sort() ترتب قيم متجه
مع متجه عادي، تفعل sort() ما تتوقعه بالضبط، إذ تُرجع القيم تصاعديًا (ويبقى المتجه الأصلي دون مساس):
خياران يستحقان المعرفة. الخيار decreasing = TRUE يعكس الاتجاه. كما أن sort() تحذف قيم NA بصمت افتراضيًا، فـ sort(c(3, NA, 1)) تُرجع 1 3 فقط. وإذا وجب أن تنجو القيم المفقودة من الترتيب فحدّد مكانها: تُبقيها sort(x, na.last = TRUE) وتضعها بعد القيم المرتبة.
حتى هنا كل شيء بديهي. والجزء المثير هو سبب كون sort() الأداة الخطأ لأطر البيانات.
order() تُرجع المواضع: نقلة في التفكير
تجيب sort() عن سؤال "ما القيم مرتبةً؟" بينما تجيب order() عن سؤال مختلف: "أي المواضع أزورها لأرى القيم مرتبة؟"
اقرأ order(times) كتعليمات: أصغر قيمة تقع في الموضع 2، ثم التالية في الموضع 4، ثم 1، ثم 3. والفهرسة بهذه التعليمات، أي times[order(times)]، تُنتج sort(times) بالضبط.
ولماذا يهم ذلك؟ لأن صف data frame فريق من القيم يجب أن تتحرك معًا. فترتيب عمود time وحده بـ sort() سيعيد ترتيب عمود واحد ويترك زملاءه خلفه، فتختلط كل الصفوف. أما order() فتعطيك مواضع الصفوف، ووضع المواضع في خانة الصفوف داخل الأقواس ينقل الصفوف كاملة:
وصلت قيمة 9.8 الخاصة بـ Ben ومعها اسمه ما يزال ملتصقًا بها. هذه هي الحيلة كلها، وهي الصيغة المعتمدة لترتيب أطر البيانات في base R: df[order(df$column), ]. (أما تسميات الصفوف المطبوعة 2 4 1 3 فهي أرقام الصفوف الأصلية المرافقة، وهي غير ضارة.)
الترتيب التنازلي والترتيب بعدة أعمدة
للترتيب العددي التنازلي، انفِ العمود، فترتيب -time تصاعديًا هو ترتيب time تنازليًا. كما تقبل order() عدة أعمدة، الأولى منها أولًا واللاحقة تفض التعادل:
يرتب الاستدعاء الثاني الأقسام أبجديًا، ويرتب الرواتب داخل كل قسم من الأعلى إلى الأدنى. وحيلة النفي تصلح للأعداد فقط، فـ -df$name على عمود نصي خطأ. وللترتيب النصي التنازلي استخدم order(df$name, decreasing = TRUE) بدلًا منها (وهي تعكس كل مفاتيح الترتيب دفعة واحدة).
rank() هي الشقيقة الثالثة
على الهامش: تجيب rank(x) عن سؤال آخر، وهو "أي مرتبة تحتلها كل قيمة؟" دون تحريك أي شيء:
تعطي sort() القيم مرتبةً، وتعطي order() المواضع التي تُزار، وتعطي rank() مرتبة كل قيمة في مكانها. ويخلط الناس باستمرار بين order() وrank()، فلاحظ أنهما تبديلان متعاكسان، ولا تلجأ إلى rank() إلا حين تريد المراتب فعلًا (لوحات الصدارة، المئينات).
أسلوب dplyr: arrange()
تغلّف arrange() في dplyr رقصة order() كلها داخل فعل واحد، فالأعمدة هي مفاتيح الترتيب وdesc() تعكس أحدها (المثال ثابت، فالبيئة التجريبية تشغّل base R فقط):
library(dplyr)
runners |> arrange(time)
staff |> arrange(dept, desc(salary))
لا أقواس ولا $ ولا حيلة نفي، كما تعمل desc() على الأعمدة النصية أيضًا. وثمة فرق سلوكي يستحق المعرفة: تضع arrange() قيم NA في النهاية بغض النظر عن الاتجاه، بينما تعتمد order() في base افتراضيًا على na.last = TRUE كذلك. راجع مقدمة dplyr لمعرفة كيفية تسلسل arrange() مع filter() وأخواتها.
الترتيب النصي له حواف حادة
تحذيران عند ترتيب النصوص. أولًا، الأرقام المخزنة كنص تُرتب كنص، فالمقارنة النصية تجري رمزًا برمز:
تأتي "10" قبل "2" لأن المقارنة تتوقف عند الرمز الأول: "1" < "2". وإذا رُتِّب عمود من الأعداد ترتيبًا غريبًا فهو مخزَّن كنص على الأرجح، فحوّله بـ as.numeric() أولًا (وهي نتيجة متكررة لـ استيراد CSV فوضوي).
ثانيًا، يعتمد ترتيب النصوص على الإعدادات المحلية لنظامك، فقد تُرتب الحروف المشكّلة وحالة الأحرف والكتابات غير اللاتينية على حاسوبك بشكل مختلف عن خادم يعمل بإعداد C. لذا ينبغي للمخرجات المرتبة التي يجب أن تتطابق عبر الأجهزة أن تضبط الإعدادات المحلية صراحةً أو أن تُرتَّب وفق مفتاح مُعيَّر.
الخلاصة
- ترتب
sort(x)قيم متجه، ويعكسهاdecreasing = TRUE، وتُحذف قيمNAما لم تستخدمna.last = TRUE. - تُرجع
order(x)المواضع، وتُعدdf[order(df$x), ]الصيغة الأساسية لترتيب أطر البيانات في base. - للترتيب بعدة أعمدة:
order(df$a, -df$b)، والنفي للترتيب التنازلي يصلح للأعداد فقط. - تعطي
rank()المراتب دون إعادة ترتيب، وهي ليست بديلًا عنorder(). - الصيغة
arrange(dept, desc(salary))في dplyr هي الترتيب نفسه بعلامات ترقيم أقل. - تأتي
"10"قبل"2"في النص، فتحقق من أنواع أعمدتك.
في المستند التالي: طيّ الصفوف في ملخصات جماعية باستخدام table() وtapply() وaggregate() وgroup_by() في dplyr.
الأسئلة الشائعة
كيف أرتب data frame حسب عمود في R؟
استخدم order() داخل أقواس الصفوف: df[order(df$price), ]. تُرجع order() مواضع الصفوف بالترتيب، والفهرسة بها تعيد ترتيب data frame بأكمله. ولن تنفع sort() هنا، فهي ترتب قيم متجه واحد وتفقد ارتباطها ببقية الأعمدة.
ما الفرق بين sort() وorder() في R؟
تُرجع sort(x) قيم x بعد إعادة ترتيبها. أما order(x) فتُرجع المواضع (الفهارس) التي ترتّب x، وهو ما تحتاجه لترتيب data frame كامل حسب أحد أعمدته: df[order(df$x), ].
كيف أرتب ترتيبًا تنازليًا في R؟
للمتجه: sort(x, decreasing = TRUE). ولـ data frame: df[order(-df$x), ] (بنفي عمود عددي) أو df[order(df$x, decreasing = TRUE), ]، وهي تصلح أيضًا للأعمدة النصية التي لا يصلح فيها النفي. وفي dplyr: arrange(df, desc(x)).
كيف أرتب حسب عدة أعمدة في R؟
مرّرها كلها إلى order(): ترتب df[order(df$dept, -df$salary), ] حسب القسم، ثم حسب الراتب تنازليًا داخل كل قسم. والوسائط الأولى هي المفاتيح الأساسية، والتالية تفض التعادل. وفي dplyr: arrange(df, dept, desc(salary)).