איך הדפסה עובדת ב-R
ל-R יש הרגל שאין לאף שפה נפוצה אחרת: בקונסולה לא צריך בכלל פקודת הדפסה. הקלידו שם של משתנה, לחצו Enter, ו-R מדפיס את הערך שלו. זו הדפסה אוטומטית (auto-printing), ובגללה מדריכי R מלאים בביטויים חשופים.
אבל להדפסה האוטומטית יש גבול נוקשה: היא פועלת רק לביטויים ברמה העליונה. בתוך לולאת for או בתוך גוף של פונקציה, ערך חשוף מוערך ונזרק בשקט:
ה-x הבודד מודפס (הוא ברמה העליונה), הלולאה הראשונה לא מדפיסה כלום, והשנייה מדפיסה 1, 2, 3 כי היא מבקשת זאת במפורש. "הלולאה שלי רצה אבל לא מראה כלום" היא אחת השאלות הנפוצות ביותר על R, וזו כל התשובה: בתוך לולאות ופונקציות, ההדפסה היא תמיד האחריות שלכם. (אותו הדבר נכון כשמריצים סקריפט עם Rscript: מה שעבד שורה אחר שורה בקונסולה יכול להשתתק בתוך לולאה.)
print(): הרשמית
print() מציגה ערך כפי ש-R רואה אותו, ולכן היא הכלי הנכון לבדיקת נתונים, והכלי הלא נכון לפלט מלוטש:
שני דברים בולטים. מחרוזות שומרות על המרכאות שלהן: print() מראה לכם ייצוג נאמן, והמרכאות אומרות שזה ערך תווי. וכל שורה מתחילה במספר בסוגריים מרובעים כמו [1]: זה האינדקס של האיבר הראשון באותה שורה, כך שכשווקטור ארוך נשבר לכמה שורות, הסוגריים בכל שורה אומרים מאיזה איבר היא ממשיכה. זה עזר קריאה לווקטורים, לא רעש.
אם אתם רוצים פלט בסגנון print() בלי המרכאות, גם print(x, quote = FALSE) וגם noquote(x) עושים את זה, אבל בדרך כלל מה שבאמת רוצים בשלב הזה הוא cat().
cat(): פלט לבני אדם
cat() (קיצור של concatenate-and-print) כותבת טקסט גולמי: בלי מרכאות, בלי קידומות אינדקס, והארגומנטים שלה מחוברים ברווחים. המחיר של השליטה הזו הוא ששום דבר לא מתווסף בשבילכם, כולל ירידת השורה:
לשכוח את ה-"\n" הוא טקס החניכה האוניברסלי של cat(): בלעדיו, הפלט הבא נדבק לאותה שורה. הפכו את סיום קריאות cat() ב-"\n" לרפלקס.
ההבדל במרכאות בין שתי הפונקציות הוא בעצם הבדל במה שהן מראות. print() מציגה רצפי escape כפי שהקלדתם אותם; cat() מעבדת אותם:
print() מראה את ה-\t וה-\n מילולית בתוך מרכאות, שימושי כשמדבגים בדיוק מה מחרוזת מכילה. cat() הופכת אותם לטאב אמיתי ולירידת שורה אמיתית, שימושי כשמפיקים פלט. בחרו לפי הכוונה: print() כדי לבדוק, cat() כדי להציג.
דוחות מעוצבים: sprintf() + cat()
הארגומנטים המופרדים ברווחים של cat() מגיעים רק עד גבול מסוים. לפלט מיושר ומעוצב, מספר ספרות אחרי הנקודה קבוע ומונים מרופדים, בנו את המחרוזת עם sprintf() ומסרו אותה ל-cat():
%-8s מרפד כל שם ל-8 תווים ו-%6.2f נותן לכל ציון אותו רוחב ושתי ספרות אחרי הנקודה, כך שהעמודות מתיישרות. הזוג הזה הוא סוס העבודה של R הבסיסי להודעות התקדמות ולדוחות טקסט קטנים (קודי העיצוב מוסברים במחרוזות).
message() ו-warning(): הערוץ השני
cat() ו-print() כותבות לפלט הסטנדרטי (standard output), הזרם שמכיל את התוצאות של התוכנית. message() ו-warning() כותבות לשגיאה הסטנדרטית (standard error), הזרם להערות על הריצה:
על המסך שתיהן נראות דומה, אבל ההפרדה חשובה ברגע שהפלט מנותב: הפנו את ה-stdout של הסקריפט לקובץ, וה-42 נוחת בקובץ בזמן שהערת הסטטוס נשארת בטרמינל. זה כלל האצבע: תוצאות ל-stdout עם cat(), הערות ל-stderr עם message(). זו גם הסיבה ש-message() (ולא cat()) היא הדרך המנומסת של פונקציות וחבילות לדבר עם המשתמשים שלהן: מי שקורא להן יכול להשתיק אותה עם suppressMessages() בלי לאבד פלט אמיתי.
warning() חזקה יותר, "משהו לא בסדר, אבל המשכתי", וכשסקריפט רץ תחת Rscript, האזהרות נאספות ומוצגות יחד בסוף ולא במקום (ראו דיבאג של שגיאות כדי ללמוד לקרוא אותן).
קריאת קלט מהמשתמש: readline() ו-readLines()
כדי לשאול את המשתמש שאלה בסשן אינטראקטיבי (הקונסולה של R או RStudio), השתמשו ב-readline(). אי אפשר להריץ את הדוגמאות האלה בעורך המוטמע, כי למריץ שבעמוד אין חלונית קלט, אז נסו אותן בקונסולה מקומית:
# Interactive sessions only:
name <- readline("What is your name? ")
cat("Hello,", name, "\n")
age <- as.numeric(readline("Your age? "))
cat("Next year you'll be", age + 1, "\n")
שני דברים לזכור. readline() תמיד מחזירה מחרוזת: המירו עם as.numeric() לפני חישובים, ובדקו אם התוצאה היא NA למקרה שהמשתמש הקליד משהו שאינו מספר. ובסקריפט לא אינטראקטיבי, readline() בכלל לא מחכה לקלט; היא מחזירה מיד "".
לסקריפט שמורץ עם Rscript וצריך לקרוא קלט מנותב או מוקלד, קראו מהקלט הסטנדרטי במקום:
# In a script run as: echo "Ada" | Rscript greet.R
line <- readLines(con = "stdin", n = 1)
cat("Hello,", line, "\n")
readLines(con = "stdin") בלי n קוראת כל שורה עד שהקלט נגמר, הצורה הסטנדרטית לסקריפטים בסגנון מסנן. קריאת קובצי נתונים היא משימה אחרת עם כלים טובים יותר; התחילו ב-read-csv כשהקלט שלכם הוא מאגר נתונים ולא מקלדת.
מה לקחת מכאן
- הדפסה אוטומטית קורית רק ברמה העליונה: בתוך לולאות ופונקציות, קראו בעצמכם ל-
print()או ל-cat(). print()בודקת: מרכאות על מחרוזות, קידומות אינדקס[1], רצפי escape מוצגים מילולית.cat()מציגה: טקסט גולמי, ארגומנטים מחוברים ברווחים, ואתם מספקים את ה-"\n".sprintf()+cat()הוא הדפוס של R הבסיסי לפלט מעוצב ומיושר.- תוצאות הולכות ל-stdout (
cat), הערות ל-stderr (message,warning). readline()לקלט אינטראקטיבי (תמיד מחרוזת!);readLines(con = "stdin")ל-Rscript.
בהמשך: אופרטורים, חשבון, השוואה והאופרטורים הלוגיים שמניעים כל תנאי שתכתבו.
שאלות נפוצות
מה ההבדל בין print() ל-cat() ב-R?
print() מציג ערך כפי ש-R מייצג אותו: מחרוזות שומרות על המרכאות שלהן וכל שורה מקבלת קידומת אינדקס בסגנון [1]. cat() כותב טקסט גולמי בלי מרכאות, בלי אינדקסים ובלי ירידת שורה אוטומטית (אתם מוסיפים "\n" בעצמכם). השתמשו ב-print() כדי לבדוק אובייקטים, וב-cat() כדי להפיק פלט לבני אדם.
למה הלולאה שלי ב-R לא מדפיסה כלום?
הדפסה אוטומטית קורית רק לביטויים ברמה העליונה. בתוך לולאת for או בתוך גוף של פונקציה, x חשוף מוערך ונזרק בשקט. עטפו אותו במפורש: print(x) או cat(x, "\n").
איך קוראים קלט מהמשתמש ב-R?
בסשן אינטראקטיבי, readline("prompt: ") קורא שורה אחת של קלט מוקלד כמחרוזת (המירו עם as.numeric() אם אתם צריכים מספר). בסקריפט שמורץ עם Rscript, readline() לא מחכה, ולכן קראו מהקלט הסטנדרטי עם readLines(con = "stdin", n = 1) במקום.
איך מדפיסים בלי מרכאות ב-R?
השתמשו ב-cat("hello\n"), שלעולם לא מוסיף מרכאות. אם אתם רוצים דווקא את ההתנהגות של print() בלי מרכאות, גם print("hello", quote = FALSE) או noquote("hello") עובדים.