كيف تقرأ مخطط الصندوق
يضغط مخطط الصندوق توزيعًا كاملًا في خمسة أرقام ويرسمها رمزًا واحدًا مضغوطًا. وتعلّم قراءته يستغرق ثلاثين ثانية، فلنفعل ذلك أولًا، إذ لكل جزء معنى دقيق:
- الخط الغليظ داخل الصندوق هو الوسيط: نصف البيانات تحته ونصفها فوقه.
- الصندوق نفسه يمتد على المدى الربيعي (IQR)، من الربيع الأول (25% من البيانات تحته) إلى الربيع الثالث (75% تحته). فالنصف الأوسط من بياناتك يعيش داخل الصندوق.
- الشاربان هما الخطان الممتدان من الصندوق. ويصل كل منهما إلى أبعد نقطة بيانات لا تزال ضمن 1.5 × المدى الربيعي من حافة الصندوق، فهما يغطيان "المدى الاعتيادي" للبيانات لا المدى الكامل.
- النقاط المفردة خارج الشوارب قيم تبعد أكثر من 1.5 × المدى الربيعي عن الصندوق، وتُوسم قيمًا شاذة مشتبهًا بها، وتُرسم واحدة تلو الأخرى لتستطيع عدّها.
فالصندوق الطويل يعني بيانات مبعثرة، وخط الوسيط غير المتمركز داخل الصندوق يعني التواءً، وسلسلة نقاط بعد أحد الشاربين تعني ذيلًا ثقيلًا في تلك الجهة. ويعرض المدرج التكراري التوزيع نفسه بتفصيل أكبر، لكن قوة مخطط الصندوق الخارقة أن اثني عشر منها تتسع جنبًا إلى جنب، ما يجعله الرسم الأمثل لمقارنة المجموعات.
مخطط صندوق لمتغير واحد
الدالة هي boxplot()، وهي استدعاء واحد لمتجه عددي مفرد:
scores <- c(52, 55, 58, 60, 61, 63, 64, 66, 68, 70, 72, 95)
boxplot(scores,
main = "Test scores",
ylab = "Score")
والصورة التي يرسمها هذا: صندوق من 59 إلى 69 وخط الوسيط عند 63.5، وشاربان يمتدان نزولًا إلى 52 وصعودًا إلى 72، ونقطة وحيدة تسبح عند 95، وهي القيمة الشاذة التي كان ملخص المتوسط والانحراف المعياري ليبتلعها بهدوء. وذلك الإدراك الفوري بأن "قيمة واحدة تختلف عن البقية" هو ما وُجدت مخططات الصندوق من أجله.
(وكما في كل صفحة من هذا الفصل، استدعاءات الرسم مقتطفات ثابتة، فالمشغّل أدناه يعرض المخرجات النصية فقط. شغّلها محليًا لترى الرسم.)
مقارنة المجموعات: واجهة الصيغة
الاستخدام اليومي الحقيقي هو صندوق لكل مجموعة، ولذلك تقبل boxplot() صيغة: y ~ group، وتُقرأ "y مفصّلًا حسب المجموعة". ومجموعة البيانات المدمجة ToothGrowth في R، أي طول الأسنان لدى 60 خنزير غينيا أُعطي فيتامين C عبر عصير البرتقال (OJ) أو حمض الأسكوربيك (VC)، هي العرض الكلاسيكي:
boxplot(len ~ supp,
data = ToothGrowth,
main = "Tooth growth by supplement",
xlab = "Supplement",
ylab = "Tooth length")
يظهر صندوقان على مقياس رأسي مشترك: يقع صندوق OJ أعلى بوضوح من صندوق VC، ووسيطه حول 22 مقابل نحو 19. ولأن الصندوقين يتشاركان محورًا واحدًا فإن المقارنة صادقة بحكم البناء، فلا فرصة لرسمين بمقياسين مختلفين يجمّلان إحدى المجموعتين. وينبغي أن يكون عمود التجميع عاملًا (أو متجهًا نصيًا)، ويصبح كل مستوى صندوقًا واحدًا.
وتتداخل الصيغ أيضًا: ترسم boxplot(len ~ supp * dose, data = ToothGrowth) ستة صناديق، واحدًا لكل تركيبة من المكمّل والجرعة. وحين يبدو الفرق بين المجموعات حقيقيًا في الصناديق، فإن السؤال الطبيعي التالي، أي هل يتجاوز مجرد الضوضاء، هو ما يجيب عنه اختبار t.
التسميات والألوان ومخططات الصندوق الأفقية
تتبع وسائط التنسيق أعراف الرسم في base. فـ names يسمّي الصناديق، وcol يملؤها، ومرّر متجهًا لتلوين كل مجموعة على حدة:
boxplot(len ~ supp,
data = ToothGrowth,
names = c("Orange juice", "Ascorbic acid"),
col = c("orange", "lightblue"),
main = "Tooth growth by supplement",
ylab = "Tooth length")
ومفتاحان آخران يستحقان مكانهما:
- يدير
horizontal = TRUEالرسم كله بحيث تمتد الصناديق على المحور الأفقي. افعل ذلك كلما كانت أسماء المجموعات طويلة، فالتسميات الأفقية تبقى مقروءة حيث تتصادم الرأسية. - ينحت
notch = TRUEثلمة حول كل وسيط، وحين لا تتداخل ثلمتا مجموعتين فمن المرجّح أن وسيطيهما مختلفان. وعامله تلميحًا بصريًا لا اختبارًا.
الأرقام خلف الصندوق
كل ما يرسمه المخطط يأتي من أرقام تستطيع طباعتها. تعطي quantile() الملخص الخماسي، وتعطيك boxplot.stats() بالضبط ما يستخدمه المخطط، بما في ذلك القيم الشاذة. وهذه الكتلة تستطيع تشغيلها هنا مباشرة:
ولاحظ أنهما قريبتان لا توأمان: فـ quantile() تُبلغ عن القيمة الصغرى والكبرى الحقيقيتين، بينما تنتهي s$stats عند الشاربين، أي أبعد النقاط داخل سياج 1.5 × المدى الربيعي. والفجوة بينهما هي بالضبط s$out، وهي هنا القيمة الوحيدة 95. وحين يسأل أحدهم "أي الصفوف هي تلك النقاط الشاذة؟"، تجيب الصيغة x[x %in% boxplot.stats(x)$out] أو مرشّح على قيم السياج.
مخططات الصندوق بـ ggplot2
في ggplot2 يذهب التجميع إلى الربط الجمالي بدل الصيغة:
library(ggplot2)
ggplot(ToothGrowth, aes(x = supp, y = len, fill = supp)) +
geom_boxplot() +
labs(title = "Tooth growth by supplement",
x = "Supplement", y = "Tooth length")
الصندوقان نفساهما، مع مفتاح إيضاح وسمة مجانًا. وتتوسع نسخة ggplot2 بشكل أفضل حين يكبر الرسم، فقسّمه حسب dose، وراكِب النقاط الخام بـ geom_jitter(width = 0.1)، وتبقى الشيفرة تصريحية. أما لمقارنة عابرة أثناء التحليل فتبقى boxplot(y ~ g, data = df) أسرع ما يمكنك كتابته.
الخلاصة
- تشريح الصندوق: خط الوسيط، والصندوق = المدى الربيعي، والشاربان = أبعد النقاط ضمن 1.5 × المدى الربيعي، والنقاط بعدهما = قيم شاذة مشتبهًا بها.
-
boxplot(x)لمتغير واحد، وboxplot(y ~ group, data = df)لمقارنة المجموعات جنبًا إلى جنب على مقياس واحد مشترك وصادق. - نسّق بـ
namesوبمتجهcolلكل مجموعة، وبـhorizontal = TRUEحين تطول التسميات. -
boxplot.stats(x)$statsو$outهما المخطط على هيئة أرقام، فاستخدمهما لاستخراج القيم الشاذة التي يشير إليها المخطط. - في ggplot2:
geom_boxplot()مع ربط المجموعة بـxأوfill.
في المستند التالي: مخطط الانتشار، أي الانتقال من توزيع متغير واحد إلى العلاقة بين متغيرين.
الأسئلة الشائعة
كيف تنشئ مخطط صندوق في R؟
استدعِ boxplot(x) على متجه عددي للحصول على صندوق واحد، أو استخدم واجهة الصيغة boxplot(y ~ group, data = df) للحصول على صندوق لكل مجموعة جنبًا إلى جنب. وكلتاهما تأتيان مع base R بلا حاجة إلى حزم.
ماذا تعني أجزاء مخطط الصندوق؟
الخط الغليظ داخل الصندوق هو الوسيط. ويمتد الصندوق على المدى الربيعي، من الربيع الأول إلى الربيع الثالث. وتمتد الشوارب إلى أبعد نقاط البيانات الواقعة ضمن 1.5 ضعف المدى الربيعي من الصندوق، وكل ما يتجاوز الشوارب يُرسم نقطة مفردة، أي قيمة شاذة مشتبهًا بها.
كيف تنشئ مخطط صندوق حسب المجموعة في R؟
استخدم صيغة: ترسم boxplot(len ~ supp, data = ToothGrowth) صندوقًا لكل مستوى من supp. وينبغي أن يكون متغير التجميع عمود factor أو عمودًا نصيًا، ويصبح كل مستوى صندوقًا واحدًا على مقياس مشترك.
كيف تجد القيم الشاذة التي يعرضها مخطط الصندوق؟
تُرجع boxplot.stats(x)$out تحديدًا القيم التي سيرسمها المخطط نقاطًا خارج الشوارب، وتعطي boxplot.stats(x)$stats الأرقام الخمسة خلف الصندوق: طرفَي الشاربين والمفصلين والوسيط.