Menu

מיון ב-R: sort(), order() ו-arrange()

איך מיון באמת עובד ב-R: sort() לווקטורים, למה data frames צריכים את טריק האינדקסים של order(), מיון יורד ומיון לפי כמה עמודות, ו-arrange() של dplyr.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

sort() ממיינת את הערכים של וקטור

לווקטור רגיל, sort() עושה בדיוק מה שמצפים: מחזירה את הערכים בסדר עולה (המקור לא משתנה):

שתי אפשרויות שכדאי להכיר. decreasing = TRUE הופך את הכיוון. ו-sort() משמיטה בשקט ערכי NA כברירת מחדל: sort(c(3, NA, 1)) מחזירה רק 1 3. אם ערכים חסרים חייבים לשרוד את המיון, אמרו לאן הם הולכים: sort(x, na.last = TRUE) שומר אותם, אחרי הערכים הממוינים.

עד כאן, מובן מאליו. החלק המעניין הוא למה sort() היא הכלי הלא נכון ל-data frames.

order() מחזירה מיקומים: השינוי בחשיבה

sort() עונה על "מהם הערכים, לפי הסדר?". order() עונה על שאלה אחרת: "באילו מיקומים צריך לבקר כדי לראות את הערכים לפי הסדר?"

קראו את order(times) כהוראות: הערך הקטן ביותר נמצא במיקום 2, הבא במיקום 4, אחר כך 1, ואז 3. בחירה לפי ההוראות האלה, times[order(times)], משחזרת בדיוק את sort(times).

למה זה חשוב? כי שורה ב-data frame היא צוות של ערכים שחייבים לזוז יחד. מיון של העמודה time לבדה עם sort() היה מסדר מחדש עמודה אחת ומשאיר את חברי הצוות שלה מאחור: כל השורות מבולגנות. order() נותנת במקום זה מיקומי שורות, והצבת מיקומים בחלק של השורות בתוך הסוגריים מזיזה שורות שלמות:

ה-9.8 של Ben מגיע כשהשם של Ben עדיין צמוד אליו. זה כל הטריק, וזו הדרך המקובלת למיין data frames ב-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() הופכת אחת מהן (קוד סטטי; סביבת ההרצה כאן מריצה רק R בסיסית):

library(dplyr)

runners |> arrange(time)
staff   |> arrange(dept, desc(salary))

בלי סוגריים, בלי $, בלי טריק הפיכת סימן: desc() עובדת גם על עמודות תווים. הבדל התנהגותי אחד שכדאי להכיר: arrange() שמה ערכי NA בסוף בלי קשר לכיוון, בעוד שגם order() הבסיסית מוגדרת כברירת מחדל ל-na.last = TRUE. ראו את המבוא ל-dplyr כדי להבין איך arrange() משתלבת בשרשרת עם filter() וחברותיה.

למיון תווים יש קצוות חדים

שתי הסתייגויות כשממיינים טקסט. ראשית, ספרות שנשמרו כטקסט ממוינות כטקסט: השוואת תווים עוברת סמל אחר סמל:

"10" ממוין לפני "2" כי ההשוואה נעצרת בסמל הראשון: "1" < "2". אם עמודה של מספרים ממוינת בצורה מוזרה, היא כמעט בוודאות שמורה כ-character: המירו עם as.numeric() קודם (תוצאה נפוצה של ייבוא CSV מבולגן).

שנית, סדר הטקסט תלוי בהגדרות האזוריות (locale) של המערכת: אותיות עם סימנים, אותיות גדולות וקטנות וכתבים שאינם לטיניים יכולים להתמיין אחרת במחשב הנייד שלכם מאשר בשרת עם locale של C. פלט ממוין שחייב להיות זהה בכל המחשבים צריך להגדיר את ה-locale במפורש או למיין לפי מפתח מנורמל.

מה לקחת מכאן

  • sort(x) מסדרת את הערכים של וקטור; decreasing = TRUE הופך אותה; ערכי NA מושמטים אלא אם na.last = TRUE.
  • order(x) מחזירה מיקומים, ו-df[order(df$x), ] היא הדרך הבסיסית המקובלת למיין data frames.
  • כמה עמודות: 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)).

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל