اطّلع على الأسماء أولًا: names() وcolnames()
توجد أسماء الأعمدة في سمة يمكنك قراءتها كأي متجه. وتُرجعها كل من names() وcolnames() عند التعامل مع data frame:
النتيجة نفسها. والفارق الحقيقي الوحيد أن colnames() تعمل أيضًا على المصفوفات، بخلاف names()، لذا تستخدم الشيفرة العامة colnames(). أما في أطر البيانات اليومية فهما متكافئتان.
والفكرة المحورية لكل ما يلي: إعادة تسمية عمود هي إسناد داخل هذا المتجه. فلا توجد دالة مخصصة في base، بل تعدّل names(df) بالفهرسة نفسها التي تستخدمها مع أي متجه.
إعادة التسمية بالموضع (تعمل لكنها هشة)
افهرس متجه الأسماء بالموضع ثم أسنِد:
صار العمود الثاني اسمه price. لا بأس بذلك كإصلاح تفاعلي سريع، لكنه مصيدة داخل سكربت. فالمواضع وعد بشأن ترتيب الأعمدة، وترتيب الأعمدة هو أقل ما يمكن الاعتماد على ثباته في البيانات المستوردة: ففي اليوم الذي يكتسب فيه ملف CSV الذي تقرأه عمودًا إضافيًا، ستعيد names(df)[2] تسمية العمود الخطأ بصمت. وإذا كان السكربت يعيد التسمية بالموضع فإن أي تغيير في البنية يكسره دون أي رسالة خطأ.
إعادة التسمية بالاسم (الصيغة المتينة في base)
طابِق الاسم القديم بدل الوثوق بموضع:
اقرأ الجزء الداخلي أولًا: تُنتج names(sales) == "prc" القيم FALSE TRUE FALSE، وهي قناع منطقي فوق متجه الأسماء. والفهرسة به تختار المدخل المطابق، ويستبدله الإسناد. وإذا لم يكن "prc" موجودًا فلن يطابق شيء ولن يتغير شيء (بلا خطأ، لذا تحقق من النتيجة). تصمد هذه الصيغة أمام إعادة الترتيب والأعمدة المضافة والنسخ إلى سكربتات أخرى. احفظها، فهي جواب base R على سؤال "كيف أعيد تسمية عمود".
عدة أعمدة دفعة واحدة
استبدل المتجه بالكامل حين تسمي كل الأعمدة (وهو أمر شائع مباشرة بعد الاستيراد)، أو استخدم match() لإعادة تسمية مجموعة جزئية مختارة:
تُرجع match(old, names(df)) مواضع الأسماء القديمة، فتحل الأسماء الجديدة تمامًا حيث كانت القديمة، وهو أسلوب آمن تجاه الترتيب مثل صيغة الاسم المفرد. وإذا كان أي اسم قديم مفقودًا أرجعت match() القيمة NA وأطلق الإسناد خطأ، وهو نمط الفشل المرغوب: صريح ومسموع.
setNames() لسلاسل المعالجة
كل الصيغ السابقة تعدّل متغيرًا على خطوتين. أما setNames(object, names) فتُرجع نسخة معاد تسميتها في تعبير واحد، وهو ما تحتاجه سلسلة المعالجة:
مفيدة حين تُرجع دالة إطارًا بلا أسماء أو بأسماء سيئة وتريد إصلاحه ضمن السطر نفسه، مثل read_something() |> setNames(c("id", "value"))، دون متغير مؤقت.
أسلوب dplyr: rename() وrename_with()
تأخذ rename() في dplyr أزواج new = old، أي الاسم الجديد أولًا، وهو ما يعكسه الجميع مرة واحدة على الأقل (المثال ثابت، فالبيئة التجريبية تشغّل base R فقط):
library(dplyr)
sales |> rename(price = prc, qty = q)
تبقى الأسماء القديمة التي لم يمسسها الاستدعاء كما هي، ويؤدي اسم قديم مكتوب خطأً إلى خطأ صريح بدل عملية صامتة بلا أثر، وهو تحسّن حقيقي على صيغة base. ولإعادة التسمية وفق قاعدة بدل الأزواج، تطبّق rename_with() دالة على الأسماء:
sales |> rename_with(toupper) # every column
sales |> rename_with(toupper, starts_with("p")) # just some
راجع مقدمة dplyr لمعرفة موقع هاتين الدالتين ضمن عائلة الأفعال.
تنظيف الترويسات المستوردة الفوضوية
تصل ترويسات CSV الحقيقية بصيغ مثل "Order ID" و"unit.price ($)" و"2024 Total"، أي أسماء تحوي مسافات ورموزًا تفرض استخدام العلامات المائلة الخلفية في كل مكان. وتحوّل make.names() في base R أي متجه نصي إلى أسماء صالحة في R:
صالحة، لكنها قبيحة بطريقتها الخاصة (X2024.Total). ولهذا توحّد فرق كثيرة عملها حول دالة clean_names() من حزمة janitor، التي تُنتج أسماء snake_case مرتبة (order_id وunit_price وx2024_total) في استدعاء واحد: df |> janitor::clean_names(). وإذا كنت تستورد ملفات فوضوية أسبوعيًا فستوفر عليك الجهد فورًا.
الخلاصة
- أسماء الأعمدة مجرد متجه: اقرأها بـ
names()/colnames()، وأعِد التسمية بالإسناد إليه. - الصيغة
names(df)[2] <- "new"هشة، والصيغةnames(df)[names(df) == "old"] <- "new"هي التي ينبغي حفظها. - تعيد
match()تسمية عدة أعمدة بالاسم، وتعيدsetNames()التسمية ضمن سلسلة المعالجة مباشرة. - تُطلق
rename(new = old)في dplyr خطأ عند الأسماء المفقودة (وهذا جيد)، وتعيدrename_with()التسمية وفق قاعدة. - للترويسات المستوردة الفوضوية:
make.names()في base، وjanitor::clean_names()لنتائج أنيقة.
في المستند التالي: الترتيب عبر sort() للمتجهات، وحيلة order() لأطر البيانات، وarrange().
الأسئلة الشائعة
كيف أعيد تسمية عمود في R؟
الصيغة المتينة في base هي المطابقة بالاسم: names(df)[names(df) == "old"] <- "new". فهي تجد العمود المسمى old أينما وقع وتعيد تسميته. وفي dplyr تكون rename(df, new = old)، وانتبه إلى الترتيب: الاسم الجديد أولًا.
ما الفرق بين names() وcolnames()؟
على data frame لا فرق عمليًا، فكلتاهما تقرأ أسماء الأعمدة وتضبطها. لكن colnames() تعمل أيضًا على المصفوفات (حيث لا تعمل names())، لذا تميل الشيفرة التي تتعامل مع النوعين إلى استخدام colnames(). أما على أطر البيانات العادية فاستخدم ما تشاء.
كيف أعيد تسمية عمود بالموضع في R؟
أسنِد إلى متجه الأسماء عند ذلك الموضع: تعيد names(df)[2] <- "price" تسمية العمود الثاني. تعمل هذه الطريقة لكنها هشة، ففي اليوم الذي يُضاف فيه عمود أو يتغير ترتيب أعمدة ملف CSV يصبح الموضع 2 عمودًا مختلفًا. والأفضل إعادة التسمية بالاسم.
كيف أعيد تسمية عدة أعمدة دفعة واحدة في R؟
أسنِد متجهًا كاملًا: تستبدل names(df) <- c("id", "name", "price") كل الأسماء بالترتيب. ولإعادة تسمية بضعة أعمدة مختارة بالاسم، استخدم match(): names(df)[match(c("old1", "old2"), names(df))] <- c("new1", "new2"). وفي dplyr: rename(df, new1 = old1, new2 = old2).