Menu
flag Ar iconالعربيةdown icon

العوامل في R: البيانات الفئوية والمستويات والفخاخ الشائعة

العوامل هي طريقة R في تخزين البيانات الفئوية: شيفرات صحيحة ترتدي تسميات نصية. كيف تنشئها، وترتّبها، وتضبط المستوى المرجعي - وتتفادى فخ تحويل العامل إلى عدد.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

ما هو العامل فعلًا

العامل هو جواب R عن البيانات الفئوية - أي القيم القادمة من قائمة ثابتة من الاحتمالات: مجموعات المعالجة، وإجابات الاستبيانات، ومقاسات القمصان. وهو يبدو متجهًا نصيًا عند الطباعة، لكنه ليس كذلك. فهو داخليًا متجه من الشيفرات الصحيحة إضافة إلى جدول بحث للتسميات تُسمى المستويات:

تعرض المخرجات التسميات، ثم سطر Levels: الذي يسرد القائمة. وتكشف as.integer() عن الآلية: إذ تعود الشيفرات بالقيم 3 1 3 2، لأن كل قيمة هي في الحقيقة فهرس في جدول المستويات - وتُرتَّب المستويات أبجديًا افتراضيًا (large ثم medium ثم small) لا بترتيب وصول البيانات. لذا فإن small شيفرته 3 وlarge شيفرته 1، وهو ما لا يتوافق مع حدس أحد. تذكر هذا الترتيب الأبجدي الافتراضي؛ فهو يقود فخين من الفخاخ التي سنتناولها.

ولماذا نتكبد هذا التصميم ذا الطبقتين بدل السلاسل النصية العادية؟ لأن الإحصاء يحتاج إليه. فالنموذج لا يستطيع ضرب "small" في معامل - لكنه يستطيع ترميز ثلاثة مستويات معروفة ترميزًا صوريًا إلى أعمدة من الأصفار والآحاد. ودوال مثل lm() وglm() وtable() والآلية التي يقوم عليها تحليل التباين تعتمد كلها على العوامل لتعرف أن متغيرًا ما فئوي، وما هي المجموعة الكاملة للفئات (بما فيها الغائبة عن البيانات)، وأي فئة هي خط الأساس. والمتجهات النصية العادية لا تحمل شيئًا من ذلك.

إنشاء العوامل: ‏levels وlabels وtable()

تأخذ factor() افتراضيًا القيم المميزة التي تجدها وترتبها أبجديًا في مستويات. وكثيرًا ما تريد التحكم في المجموعة والترتيب معًا - فمرر الوسيط levels =:

والآن تسير المستويات بترتيب المقاس الطبيعي، وتُبلغ table() - وهي عدّ التكرارات ذو السطر الواحد الذي ستستخدمه باستمرار مع العوامل - عن الأعداد بذلك الترتيب أيضًا. وتحسب nlevels() عدد الفئات.

ويمنحك الوسيط levels = أمرين إضافيين. فالقيم الموجودة في البيانات وغير المدرجة في قائمة مستوياتك تصبح NA (وهذا جيد: إذ تطفو الأخطاء المطبعية إلى السطح بدل أن تصير فئة مستقلة). والمستويات ذات التكرار الصفري تظل موجودة، فيعرض ملخص إجابات الاستبيان "أعارض بشدة: 0" بدل التظاهر بأن الخيار لم يوجد أصلًا.

ويعيد الوسيط labels = تسمية المستويات لحظة الإنشاء، وهو مفيد حين تستخدم البيانات الخام شيفرات:

والدالة as.factor(x) هي المحوّل السريع لمتجه قائم حين تكون الإعدادات الافتراضية مناسبة.

العوامل المرتبة للبيانات الترتيبية

تعامل العوامل العادية الفئات على أنها غير مرتبة - فـ "أحمر" ليس أقل من "أزرق". لكن بعض المقاييس الفئوية لها ترتيب حقيقي: منخفض/متوسط/مرتفع، أو أعارض/محايد/أوافق. صرّح بذلك عبر ordered = TRUE:

تعرض المخرجات الآن Levels: low < medium < high، وتعمل معاملات المقارنة: إذ يمكنك أن تسأل هل يتجاوز تقييم آخر، أو ترشّح كل ما يبلغ "medium" أو يفوقه - وكلا الأمرين يعطي خطأ (أو بالأحرى تحذيرات وقيم NA) مع عامل غير مرتب. كما تغيّر العوامل المرتبة طريقة ترميز النماذج للمتغير (تباينات كثيرة الحدود بدل المتغيرات الصورية)، وهو ما تريده عادة للمتنبئات الترتيبية.

ولا تستخدم ordered = TRUE إلا حين يكون الترتيب حقيقيًا. فترميز المجموعات العادية بوصفها مرتبة يغيّر مخرجات النموذج بطرق يسهل إساءة قراءتها.

المستوى المرجعي والدالة relevel()

المستوى الأول في العامل مميز: إذ تعامله دوال النمذجة بوصفه الفئة المرجعية، أي خط الأساس الذي يُقاس عليه معامل كل مستوى آخر. ولأن ترتيب المستويات الافتراضي أبجدي، فإن الأبجدية هي من تختار خط أساسك ما لم تتدخل - وخسارة "control" أمام "aspirin" أبجديًا ليست قرارًا علميًا.

وترقّي relevel() مستوى إلى الموضع الأول:

قبل ذلك: صادف أن جاء control أولًا بحظ أبجدي فقط. وبعد relevel(..., ref = "control") صار أولًا عن قصد. وفي انحدار خطي بهذا المتنبئ، صار معامل treatment يجيب عن سؤال "كيف تختلف المعالجة عن الضبط؟" - وهو السؤال الذي طرحته فعلًا. وكلما بدت معاملات النموذج الفئوية محيرة، فافحص المستوى المرجعي أولًا.

(وللترتيب الكامل - لا الموضع الأول وحده - مرر متجه levels = كاملًا إلى factor() مجددًا.)

الفخ الكلاسيكي: تحويل عامل إلى عدد

أحيانًا تصل الأرقام على هيئة عوامل - وهو ما يحدث نمطيًا مع عمود CSV احتوى قيمة شاردة غير عددية. ويبدو التحويل العكسي بديهيًا لكنه يخطئ خطأً لا يُنسى:

يعيد as.numeric(f) القيم 2 1 3. لا 20 و10 و30 - بل شيفرات المستويات. فالمستويات تُرتَّب أبجديًا إلى "10" و"20" و"30"، فتكون "20" هي المستوى 2 وتتحول إلى... 2. لا خطأ، ولا تحذير، بل أعداد صحيحة صغيرة تبدو معقولة تحل محل بياناتك بهدوء. وقد سُحبت تحليلات منشورة بسبب هذا وحده.

والمسار الصحيح يمر عبر النص: فالتعبير as.numeric(as.character(f)) يستعيد أولًا التسميات نصًا، ثم يحلل النص أرقامًا - فيعطي 20 10 30. رسّخ هذه الصيغة: تحويل العامل إلى عدد يمر دائمًا عبر as.character().

الدالة droplevels() وقصة stringsAsFactors

استخراج مجموعة جزئية من عامل يبقي مجموعة المستويات كاملة، حتى بالنسبة إلى الفئات التي لم تعد تظهر:

فبعد ترشيح large خارجًا، ما تزال table() تبلغ عنه - بعدّ يساوي 0. وأحيانًا يكون ذلك صحيحًا تمامًا (فأنت تريد رؤية الفئة الفارغة). وحين لا يكون كذلك - إذ تزحم المجموعات ذات العدّ الصفري المخططات وقد تعطّل التحليلات المطبقة - تتخلص droplevels() من المستويات التي لا مشاهدات لها.

وثمة ملاحظة تاريخية ستحتاجها عند قراءة الشيفرة الأقدم أو إجابات Stack Overflow: فقبل الإصدار R 4.0 (عام 2020)، كانت data.frame() وread.csv() تحوّلان كل عمود نصي إلى عامل تلقائيًا - إذ كان stringsAsFactors = TRUE هو الافتراضي. وعقد كامل من الدروس مليء بحلول التفافية لعوامل لم يطلبها أحد. ومنذ الإصدار R 4.0 صار الافتراضي FALSE: فالنصوص تبقى نصوصًا، وتنشئ العوامل عن قصد حيث يكون متغير في إطار بياناتك فئويًا فعلًا. وتلك هي العادة الصحيحة - عوامل صريحة، عن قصد، بمستويات اخترتها بنفسك.

ما تخرج به

  • العامل = شيفرات صحيحة + تسميات مستويات؛ وهو ما يخبر الدوال الإحصائية بأن المتغير فئوي.
  • تحكم في مجموعة الفئات وترتيبها بالوسيط levels =، وأعد التسمية بالوسيط labels =، وعُدّ بـ table().
  • يفعّل ordered = TRUE المقارنات للمقاييس الترتيبية الحقيقية.
  • المستوى الأول هو خط أساس النموذج - فاضبطه عن قصد بـ relevel(f, ref = ...).
  • لا تستخدم as.numeric(f) مباشرة أبدًا - بل as.numeric(as.character(f)) دائمًا.
  • تنظف droplevels() المستويات غير المستخدمة بعد الاستخراج؛ ومنذ الإصدار R 4.0، تبقى النصوص نصوصًا ما لم تنشئ العوامل بنفسك.

التالي: إطارات البيانات - حيث تعيش العوامل والأرقام والنصوص معًا بوصفها أعمدة في جدول واحد.

الأسئلة الشائعة

ما هو العامل في R؟

العامل هو النوع الذي تمثل به R البيانات الفئوية - أي القيم المسحوبة من مجموعة ثابتة من الاحتمالات تسمى المستويات. وهو داخليًا متجه من الشيفرات الصحيحة إضافة إلى جدول لتسميات المستويات، وهذا ما يتيح للدوال الإحصائية معاملة الفئات معاملة صحيحة (بعدّها، وترميزها ترميزًا صوريًا في النماذج) بدل معاملتها نصًا حرًا.

كيف تحوّل عاملًا إلى عدد في R؟

مر عبر النص: ‏as.numeric(as.character(f)). فاستدعاء as.numeric(f) مباشرة يعيد شيفرات المستويات الداخلية (1 و2 و3 وهكذا) لا القيم التي تعرضها التسميات - فقد يعود عامل يعرض "20" بالقيمة 2. وهذه من أشيع العلل الصامتة في R.

ماذا تفعل الدالة relevel() في R؟

تنقل مستوى مختارًا إلى الموضع الأول: ‏relevel(group, ref = "control"). والمستوى الأول هو الفئة المرجعية (خط الأساس) التي تقارن بها دوال النمذجة مثل lm() وglm() كل مستوى آخر، لذا فإن اختياره عن قصد يجعل معاملات الانحدار تعني ما تريده.

لماذا ما زال عاملي يعرض مستويات حذفتها؟

استخراج مجموعة جزئية من عامل يبقي مجموعة المستويات كاملة حتى حين لا تعود بعض المستويات موجودة، لذا تعرض table() فئات بعدّ صفري وتظل النماذج تحجز لها مساحة. نفّذ droplevels() على المجموعة الجزئية للتخلص من المستويات غير المستخدمة.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن