Menu

Lists ב-R: יצירה, גישה ([[ מול $ מול [) ושינוי

רשימות הן המכל של R שמקבל הכול: טיפוסים מעורבים, מבנים מקוננים, data frames שלמים. המיומנות המרכזית היא לדעת מתי [ מחזיר רשימה קטנה יותר ומתי [[ מחזיר את האיבר עצמו.

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

רשימה מחזיקה כל דבר

לוקטור יש כלל נוקשה אחד: כל האיברים חייבים להיות מאותו טיפוס. לרשימה אין כלל כזה. כל איבר ברשימה יכול להיות מטיפוס שונה, באורך שונה, ואפילו רשימה אחרת. זה המכל הכללי של R:

length() מדווח 4: ארבעה איברים, אף שאחד מהם (scores) מכיל בעצמו שלושה מספרים. רשימה סופרת את התאים שלה, לא את מה שבתוכם. str() (structure) הוא הדרך המהירה ביותר לראות מה רשימה מחזיקה בפועל: שורה אחת לכל איבר עם השם, הטיפוס ותצוגה מקדימה. הפכו את str() לרפלקס: בכל פעם שפונקציה מחזירה לכם משהו ואתם לא בטוחים מה הוא, הפעילו עליו str().

שמות הם אופציונליים (list(1, "a", TRUE) חוקי) אבל כמעט תמיד כדאי שיהיו: רשימה עם שמות מתעדת את עצמה.

שלוש דרכי הכניסה: [, [[ ו-$

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

  • [ מחזיר רשימה קטנה יותר: מכל מאותו סוג, שמחזיק את מה שבחרתם.
  • [[ מחזיר את האיבר עצמו: הערך בפועל שבתוך התא.
  • $ הוא קיצור של [[ עם שם מילולי: person$age הוא person[["age"]].

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

ל-person["scores"] יש class "list": רשימה באורך 1 עם וקטור הציונים בתוכה. ל-person[["scores"]] יש class "numeric": הווקטור עצמו, מוכן ל-mean(). קראו ל-mean() על הגרסה עם הסוגריים הבודדים ותקבלו שגיאה שהארגומנט אינו מספרי; הודעת השגיאה הזו היא כמעט תמיד סימן שהשתמשתם ב-[ כשהתכוונתם ל-[[.

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

אז מתי [ הוא הכלי הנכון? כשרוצים כמה איברים ורוצים לשמור אותם ארוזים:

אי אפשר לשלוף שני איברים "עצמם" בבת אחת, כי שני ערכים צריכים מכל, ולכן בחירה של כמה איברים היא תמיד עם סוגריים בודדים, ותמיד מניבה רשימה.

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

הוספה, שינוי, הסרה

רשימות גדלות ומתכווצות בהשמה פשוטה, בלי צורך במתודת הוספה מיוחדת:

  • השמה לשם שעדיין לא קיים מוסיפה את האיבר.
  • השמה לשם קיים מחליפה אותו.
  • השמה למיקום length(x) + 1 מוסיפה בסוף איבר ללא שם.
  • הצבת NULL מסירה את האיבר לגמרי, והרשימה מתקצרת. (זה המקום היחיד שבו NULL מתנהג כפקודת מחיקה; אם אתם באמת צריכים לאחסן "כלום" בתא, השתמשו ב-x["k"] <- list(NULL).)

כדי להדביק שתי רשימות זו אחרי זו, c() עובד על רשימות בדיוק כמו על וקטורים: c(list_a, list_b) מחזיר רשימה אחת ארוכה יותר.

רשימות מקוננות

מכיוון שאיבר ברשימה יכול להיות רשימה אחרת, רשימות מתקננות לכל עומק, וזה הופך אותן לצורה הטבעית של R לנתונים מובנים כמו JSON מפוענח או תוצאות מקובצות:

הירידה פנימה היא פשוט שרשור של אופרטורי גישה: כל $ או [[ יורד רמה אחת לעומק. כשמבנה מקונן נעשה מבלבל, str(company) מראה את כל העץ בבת אחת, ו-str(company, max.level = 1) מראה רק את השכבה העליונה.

שיטוח עם unlist()

unlist() מכווץ רשימה, מקוננת לעומק ככל שתהיה, לווקטור יחיד:

שני דברים לשים לב אליהם. ראשית, unlist() בונה בשבילכם שמות (math1, math2, art) כך שעדיין אפשר לדעת מאיפה הגיע כל ערך. שנית, וזו המלכודת, וקטור מחזיק טיפוס אחד בלבד, ולכן שיטוח של רשימה מעורבת ממיר הכול לטיפוס הגמיש ביותר שקיים. המספר 1 חזר כמחרוזת "1". אם שיטחתם והמספרים שלכם הפכו לטקסט, הרשימה לא הייתה אחידה כמו שחשבתם.

למה רשימות חשובות

רשימות יכולות להיראות כמו נושא למתחילים שתתגברו עליו. זה ההפך: הן נושאות משקל בכל השפה:

  • פונקציות שמחזירות כמה דברים מחזירות רשימה. פונקציות ב-R מחזירות אובייקט אחד; רשימה מאפשרת לאובייקט האחד הזה לשאת ערך מותאם כאן וטבלת מקדמים שם. כשמריצים רגרסיה, אובייקט המודל שמקבלים בחזרה הוא רשימה (גדולה, עם class), ו-str() עליו מוכיח זאת.
  • data frame הוא רשימה של עמודות: וקטורים באורך שווה עם התנהגות נוספת מעליהם. כל מה שלמדתם עכשיו ($, [[, הצבת NULL כדי להסיר איבר) חל מילה במילה על עמודות של data frame.
  • משפחת apply, lapply() וחבריה, מקבלת רשימה, מפעילה פונקציה על כל איבר ומחזירה רשימה. רשימות נכנסות, רשימות יוצאות: זו הצורה הסטנדרטית של חישוב חוזר ב-R.

מה לקחת מכאן

  • רשימות מחזיקות כל דבר: טיפוסים מעורבים, אורכים שונים, רשימות אחרות, data frames שלמים.
  • [ מחזיר רשימה קטנה יותר; [[ מחזיר את האיבר עצמו; $ הוא [[ עם שם מילולי. רוצים לחשב? אתם צריכים [[ או $.
  • מוסיפים בהשמה לשם חדש, מסירים בהצבת NULL, משלבים עם c().
  • unlist() משטח לווקטור וממיר טיפוסים מעורבים בדרך: בדקו את ה-class של התוצאה.
  • data frames הם רשימות של עמודות, כך שהידע הזה עובר ישירות.

בהמשך: מטריצות, המקבילה של הרשימה עם טיפוס אחד בלבד, שורות ועמודות.

שאלות נפוצות

מה ההבדל בין [ ל-[[ ב-R?

סוגריים מרובעים בודדים [ תמיד מחזירים רשימה שמכילה את האיברים שנבחרו, מכל קטן יותר מאותו סוג. סוגריים כפולים [[ נכנסים פנימה ומחזירים את האיבר עצמו. אם x$scores מכיל וקטור מספרי, x["scores"] הוא רשימה באורך 1 ו-x[["scores"]] הוא הווקטור המספרי. השתמשו ב-[[ (או ב-$) כשאתם רוצים לעבוד בפועל עם הערך.

איך מוסיפים איבר לרשימה ב-R?

בצעו השמה לשם שעדיין לא קיים: x$email <- "rosa@example.com" או x[["email"]] <- .... הרשימה גדלה אוטומטית. כדי להוסיף בסוף בלי שם, בצעו השמה למיקום הבא: x[[length(x) + 1]] <- value. כדי להסיר איבר, הציבו בו NULL: x$email <- NULL.

איך ממירים רשימה לווקטור ב-R?

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

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

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

להתחיל