הקדמה

בשיעורים הקודמים למדנו את הבסיס של R.

מעכשיו עד סוף הקורס אנו נשתמש בספריות חיצוניות שעושות את העבודה ב R להרבה יותר קלה ומוסיפות פונקציונאליות רבה לתוכנה.

בשיעור הזה נתרכז במספר ספריות המהוות חלק מאוסף של ספריות המאוגדות תחת הכותרת ה tidyverse.

הספריות שנתמקד בהן בשיעור הזה הן:

  • dplyr - שפה נוחה לשאילתות

  • tidyr - פקודות לביצוע מנפולציות על טבלאות

  • reshape2 - פקודות לשחלוף מבנה אובייקטים


מטרות השיעור

  • להשתמש בספריות חיצוניות
  • תדעו לייבא נתונים ל R
  • לבצע שאילתות בסיסיות
  • ומורכבות יותר…
  • לחבר טבלאות ביחד
  • לשנות את הצורה של טבלה
  • ועוד

שימוש בספריות חיצוניות

ספריה חיצונית היא סוג של תוספת פקודות שמישהו כתב והנגיש לציבור הרחב.


הורדת הספריה

כדי להשתמש בספריה אנחנו צריכים להוריד אותה מהאינטרנט כאשר רוב הספריות של R נשמרות במאגר נגיש לציבור באתר CRAN

https://cran.r-project.org

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

https://cran.r-project.org/web/views


מ RSTUDIO אפשר לחפש ולהוריד ספריות לפי שם מטאב Packages וללחוץ על הכפתור Install

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

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

את רשימת הספריות האחרות שהספריה תלויה בהן ניתן לראות בקובץ ה DESCRIPTION של הספריה תחת הכותרת Imports.


תרגיל 1:

Questions
  1. הורידו את הספריה tidyverse

שימוש בספריה

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

# Install readr package:
library(readr)

לחלופין ניתן לסמן אותה ב V ב טאב של ה Packages

עכשיו כל הפקודות של הספריה זמינות לשימוש

בכתיבת script רצוי לייבא את כל הספריות הנחוצות בתחילת ה script.


התנגשויות בין ספריות

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

יש שתי דרכים לטפל בבעיה הזאת:

  1. לנתק את אחד הספריות בעזרת פקודת detach או על ידי הורדת ה V ליד שם הרשימה בטאב של ה Packages
  2. לקרוא לפקודה בשם המלא שלה, על ידי ציון שם החבילה ולאחריו :: ושם הפקודה.

הפתרון השני אפילו אין צורך להטעין את החבילה לזכרון.

לדוגמא, אם נרצה לקרוא לפקודה select מתוך החבילה dplyr נוכל לכתוב:

dplyr::select(table, column)

עזרה על הספריה

כל הפקודות של הספריה מתועדות עם עזרה שניתן לראות בדרך הרגילה (שימוש בחלונית החיפוש או ב ?)

בנוסף, בחבילות רבות יש תעוד כללי עם דוגמאות והסבר ידידותי למשתמש שנקרא Vigenette

כדי לראות אותה:

  • פתחו את הטאב Packages
    • מצאו את הספריה שלכם ולחצו על השם שלה
      • לחצו על הקישור של ה vignettes and other documentation
        • בחרו את הנושא שמעניין אותכם

תרגיל 2:

Questions
  1. הטעינו את הספריה dplyr
  2. נווטו על ה vignette של החבילה ותפתחו בנושא: introduction


ייבוא נתונים ל RSTUDIO


ייבוא נתונים מקבצים בודדים

בעבר הלא רחוק, הייתם צריכים לכתוב קוד בשביל לייבא נתונים ממקורות חיצוניים.

כיום, יש אפשרות נוחה לייבא נתונים בעזרת לחיצה על הכפתור Import Dataset ובחירת סוג הנתונים הרצוי.


ייבוא נתונים ממקורות אחרים

בעזרת ספריות חיצוניות ניתן לחבר את R למאגרי נתונים כגון SQL, ORACLE , ועוד רבים אחרים. נלמד איך לעשות את זה בשיערוים הבאים.


הטענת נתונים של R

ב R הנתונים נשמרים בתור סביבת עבודה הנקרא workspace, ונשמר כקובץ עם סיומת *.RData אותו ניתן להטעין ולשמור בעזרת האיקונים ב RSTUDIO. או בעזרת הפקודות load - לקריאת קובץ שמור; ו save לשמירת סביבת העבודה.



תרגיל 2:

Questions
  1. קראו את הקובץ Santander_sample.csv לתוך סביבת העבודה שלכם.

בפתיחת קובץ ה CSV, שימו לב לכמה דברים:

  • ה GUI מראה לכם את הקוד שאתם הייתם צריכים לבצע באופן ידני
  • הפקודה ייבא את הטבלה בתור “tbl_df” סוג של “data.frame”
  • הקודים השונים יובאו בתור “Integer”

ברוכים הבאים ל tidyverse

חבילת ה tidyverse מאגדת בתוכה מספר חבילות שמייצרות שפה חדשה לטיפול בנתונים ב R.

המשותף לכל הספריות הכללות ב tidyverse הוא המיקוד בניקוי , סידור וביצוע פעולות על טבלאות. כאשר הפילוסופיה של טבלה “מסודרת” היא ש:

  1. כל משתנה יוצר עמודה
  2. כל שורה היא תצפית
  3. כל סוג של יחידת תצפית יוצרת טבלה

ספריות ה tidyverse

בין החבילות הבולטות שנעשה בהן שימוש:

  • dplyr - שאילתות מורכבות על טבלאות נתונים
  • tidyr - מנפולציות על טבלאות נתונים
  • ggplot2 - שפה של יצירת גרפים
  • purrr - כתיבת פונקציות

למעשה, אלה החבילות הנפוצות ביותר וניתן להטעין אותן בהטענת החבילה tidyverse

נגע בקצרה או נשתמש בעקיפין במספר ספריות נוספות:

  • lubridate - פעולות על תאריכים
  • tibble - יצירת טבלאות מסוג tbl_df
  • broom - הפיכת תוצאות רגרסיה לטבלאות

לרשימה המלאה של הספריות הכללולות ראו בלינק:

https://github.com/tidyverse/tidyverse


Syntax

ברוב הפקודות של ה tidyverse ה syntax הוא בצורת:

functionName(tableName, paramters)

למשל:

summarise(Table, mean(Variable1))

select(Table, col1, col2, col3)

group_by(Table, group1)


אבל כשמתשמשים בכמה פקודות יחד זה נהיה מסורבל

אם נרצה ממוצע של המשתנה אושר לפי ענף, נכתוב:

library(dplyr)

grp_seg <- group_by(Santander_sample, segmento)

sum_table <- summarise(grp_seg, mean(renta))

#print results
sum_table %>% slice(1:10) 
## Warning: package 'bindrcpp' was built under R version 3.3.3
segmento mean(renta)
01 - TOP 146564.34
02 - PARTICULARES 117166.78
03 - UNIVERSITARIO 92802.54
  • כפי שראיתם קודם היינו צריכים ליצר טבלה חדשה זהה למקור מחולקת לפי ענף
  • ואז לבצע עליה את הסכימה

אופציה נוספת הייתה לשים את זה ישר בפנים ככה:

sum_table <- summarise(group_by(Santander_sample,segmento), mean(renta))

#print results
sum_table %>% slice(1:10) 
segmento mean(renta)
01 - TOP 146564.34
02 - PARTICULARES 117166.78
03 - UNIVERSITARIO 92802.54

אבל שני האופציות יוצרות סיבוכיות:

  • אופציה 1 משכפלת נתונים
  • אופציה 2 קשה יותר להבנה

לכן המציאו פתרון האופרטור %>%


האופרטור %>%

האופרטור %>% אומר: " שים את מה שמשמאל בתור המשתנה הראשון בפונקציה שמימין"

הפקודות נכתבות בסדר שנרצה לבצע אותם!!

כפי שתראו זה יוצר קוד נקי מובן ומונע את הבעיות דלעיל.

עכשיו נכתוב:

sum_table <- Santander_sample %>% 
          group_by(segmento) %>% 
          summarize(mean(renta))

#print results
sum_table %>% slice(1:10) 
segmento mean(renta)
01 - TOP 146564.34
02 - PARTICULARES 117166.78
03 - UNIVERSITARIO 92802.54

ניתן להשתמש באופרטור בכל הפקודות לא רק של dplyr

מעכשיו נשתדל להשתמש באופרטור הזה בכל שאילתה מורכבת.

הקיצור לאופרטור הוא Ctrl Shift M


שומר המקום .

לפעמים נרצה להשתמש באופרטור %>% שלא בתור הערך של הפרמטר הראשון בפקודה

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


שימוש ב tibble

כפי שצויין קודם, הטבלה שייבאנו לתוך ה workspace נשמרה בתור tbl_df שזה השם קיצור ל tibble.

tibble היא סוג של data frame משודרג השייכת ל tidyverse שההבדלים ביניהם הן:

  1. מראה רק 10 תצפיות ראשונות
  2. תמיד מחזיר טבלה…

שימו לב שהטבלה עדיין תהיה data frame ונוכל לבצע את כל מה שלמדנו בשיעור הקודם גם בטבלאות מסוג tibble

אם היינו רוצים להפוך טבלה ל tibble היינו יכולים לכתוב:

Santander_sample <- tbl_df(Santander_sample)


# show table properties
class(Santander_sample)
## [1] "tbl_df"     "tbl"        "data.frame"

ספרית dplyr

ספרית dplyr תהיה סוס העבודה שלנו להמשך הקורס

הפקודות בה מאשפרות:

  • לבצע שאילתות בסיסיות ומורכבות
  • לבצע חישובים ומניפולציות על המשתנים
  • לכתוב ב syntax קבוע וקל לקריאה והבנה

פקודות עיקריות לשאילתות

הפילוסופיה של הספריה היא שכל פקודה תעשה משהו אחד בלבד - בצורה הטובה ביותר

בהתאם לכך, רוב הזמן נשתמש במספר פקודות ביחד כדי לבצע משימה

הפקודות הבסיסיות הן:

  • filter - סינון נתונים לפי תנאים
  • arrange - מיון נתונים לפי שדות
  • select - בחירת שדות מסוימות
  • group_by - קיבוץ לפי קבוצות
  • summarise - סיכום עמודה לערך אחד
  • mutate - שינוי שדה ויצירת שדה חדש
  • rename - שינוי שם שדה
  • distinct - בחירת שורות ייחודיות
  • transmutate - החזרת רק שדה מחושב
  • slice - בחירת שורות לפי מיקום , למשל 10 הראשונים
  • בנוסף הפקודות הבאות מקלות מאוד על החיים:
  • mutate_at - בצע שינוי או חישוב על כל עמודה מסומנת
  • summarise_at - בצע סיכום לכל עמודה מסומנת
  • mutate_all - בצע שינוי או חישוב על כל העמודות
  • summarise_all - בצע סיכום לכל העמודות
  • mutate_if - בצע שינוי או חישוב על כל עמודה העומדת בתנאי
  • summarise_if - בצע סיכום לכל עמודה העומדת בתנאי
  • n_distinct - מחזיר מספר שורות ייחודיות
  • count - טבלת שכיחות
  • tally - ספירה או סכימת עמודה

כפי שאתם רואים יש הרבה פקודות (ואלה רק השימושיות ביותר)

בהמשך נעבור על עוד משפחה של פקודות שיעזרו לחבר נתונים

בנוסף אתם מוזמנים להשתמש ב cheat-sheet המצורף בכל עת.



count - טבלת שכיחויות

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

sum_tbl <- Santander_sample %>% 
           count(segmento)

# print results
sum_tbl %>% slice(1:10) 
segmento n
01 - TOP 7934
02 - PARTICULARES 65854
03 - UNIVERSITARIO 26212
  • וטיפה מורכב יותר: סגמנט לפי חודש
sum_tbl <- Santander_sample %>% 
           count(fecha_dato, segmento)

# print results
sum_tbl %>% slice(1:10) 
fecha_dato segmento n
2015-04-28 01 - TOP 1569
2015-04-28 02 - PARTICULARES 12448
2015-04-28 03 - UNIVERSITARIO 4507
2015-07-28 01 - TOP 1479
2015-07-28 02 - PARTICULARES 12614
2015-07-28 03 - UNIVERSITARIO 4510
2015-10-28 01 - TOP 1547
2015-10-28 02 - PARTICULARES 13316
2015-10-28 03 - UNIVERSITARIO 5361
2016-01-28 01 - TOP 1616


select - בחירת עמודות

זה די אינטואטיבי - נבחר רק את השדות: סגמנט ואינדיקטור לכרטיס אשראי (ind_cc) ותאריך

segment_cc <- Santander_sample %>% 
               select(segmento
                      , ind_cc
                      , fecha_dato
                      , age
                      , sexo)

segment_cc %>% slice(1:10) 
segmento ind_cc fecha_dato age sexo
01 - TOP 0 2015-04-28 92 H
02 - PARTICULARES 0 2016-01-28 49 V
03 - UNIVERSITARIO 0 2016-01-28 20 V
02 - PARTICULARES 0 2016-01-28 53 V
02 - PARTICULARES 0 2016-03-28 48 H
02 - PARTICULARES 0 2016-01-28 72 V
02 - PARTICULARES 0 2015-04-28 49 V
02 - PARTICULARES 0 2015-07-28 53 V
01 - TOP 0 2016-01-28 67 V
02 - PARTICULARES 0 2015-10-28 54 V

שינוי שם משתנה

  • אם נרצה לשנות שם של משתנה אפשר לעשות את זה בעזרת select , למשל:
segment_cc <- Santander_sample %>% 
               select(segmento
                      , ind_cc
                      , fecha_dato
                      , age
                      , sex = sexo)

segment_cc %>% slice(1:10) 
segmento ind_cc fecha_dato age sex
01 - TOP 0 2015-04-28 92 H
02 - PARTICULARES 0 2016-01-28 49 V
03 - UNIVERSITARIO 0 2016-01-28 20 V
02 - PARTICULARES 0 2016-01-28 53 V
02 - PARTICULARES 0 2016-03-28 48 H
02 - PARTICULARES 0 2016-01-28 72 V
02 - PARTICULARES 0 2015-04-28 49 V
02 - PARTICULARES 0 2015-07-28 53 V
01 - TOP 0 2016-01-28 67 V
02 - PARTICULARES 0 2015-10-28 54 V
  • אפשר גם להשתמש בפקודה rename באותה צורה, כאשר בניגוד ל rename,select מחזיר את כל שאר העמודות

שינוי סדר העמודות

  • ואם נרצה לשנות את הסדר של העמודות נעשה את זה פה בעזרת פונקציית העזר ()everything המסמן את כל שאר העמודות :
segment_cc <- segment_cc %>%
              select(sex, age, everything())

segment_cc %>% slice(1:10) 
sex age segmento ind_cc fecha_dato
H 92 01 - TOP 0 2015-04-28
V 49 02 - PARTICULARES 0 2016-01-28
V 20 03 - UNIVERSITARIO 0 2016-01-28
V 53 02 - PARTICULARES 0 2016-01-28
H 48 02 - PARTICULARES 0 2016-03-28
V 72 02 - PARTICULARES 0 2016-01-28
V 49 02 - PARTICULARES 0 2015-04-28
V 53 02 - PARTICULARES 0 2015-07-28
V 67 01 - TOP 0 2016-01-28
V 54 02 - PARTICULARES 0 2015-10-28


arrange - מיון

ועכשיו נמיין את הקובץ החדש לפי שתי השדות:

segment_cc <- segment_cc %>% 
              arrange(segmento, ind_cc)

#print results

segment_cc %>% slice(1:10) 
sex age segmento ind_cc fecha_dato
H 92 01 - TOP 0 2015-04-28
V 67 01 - TOP 0 2016-01-28
V 55 01 - TOP 0 2015-07-28
V 50 01 - TOP 0 2015-07-28
V 62 01 - TOP 0 2015-04-28
V 75 01 - TOP 0 2015-10-28
V 68 01 - TOP 0 2015-10-28
V 35 01 - TOP 0 2015-04-28
V 74 01 - TOP 0 2016-03-28
V 47 01 - TOP 0 2015-10-28

ואם נרצה לסדר חלק מהמשתנים בסדר יורד נשים אותם ב desc()

segment_cc <- segment_cc %>% 
              arrange(segmento, fecha_dato, desc(ind_cc))

# print results
segment_cc %>% slice(1:10) 
sex age segmento ind_cc fecha_dato
V 63 01 - TOP 1 2015-04-28
V 48 01 - TOP 1 2015-04-28
V 53 01 - TOP 1 2015-04-28
V 63 01 - TOP 1 2015-04-28
V 40 01 - TOP 1 2015-04-28
V 52 01 - TOP 1 2015-04-28
V 58 01 - TOP 1 2015-04-28
V 36 01 - TOP 1 2015-04-28
V 40 01 - TOP 1 2015-04-28
V 42 01 - TOP 1 2015-04-28


slice - חיתוך לפי מקום

עכשיו נראה את 5 השורות עם האושר הכי נמוך

segment_bottom_5 <- Santander_sample %>% 
                    select(renta, fecha_dato, segmento, ind_cc) %>% 
                    arrange(renta) %>% 
                    slice(1:5)

#print results
segment_bottom_5 %>% slice(1:5) 
renta fecha_dato segmento ind_cc
0 2016-03-28 02 - PARTICULARES 0
0 2015-07-28 02 - PARTICULARES 0
0 2015-10-28 02 - PARTICULARES 0
0 2015-07-28 03 - UNIVERSITARIO 0
0 2015-07-28 02 - PARTICULARES 0
  • שימו לב שהשתמשתי באופרטור : כדי לציין את המספרים 1 עד 5

filter - סינון

עכשיו נסנן ונראה את האושר הכי נמוך מעל 100:

# After Filter
segment_bottom_5 <- Santander_sample %>% 
                    select(renta, fecha_dato, segmento, ind_cc) %>% 
                    filter(renta>100) %>% 
                    arrange(renta) %>% 
                    slice(1:5)

#print results
segment_bottom_5 
renta fecha_dato segmento ind_cc
7376.79 2015-07-28 02 - PARTICULARES 0
7376.79 2015-10-28 02 - PARTICULARES 0
7507.32 2015-04-28 01 - TOP 0
7816.92 2016-01-28 03 - UNIVERSITARIO 0
8552.88 2015-04-28 03 - UNIVERSITARIO 0

שימו לב: את הסינון תשימו לפי סדר הפעולות שאתם רוצים לבצע


summarise - סיכום

בעזרת הפקודה הזו ניתן לחשב סיכומים שונים לאיזה עמודות שנרצה

# sum of amala, number of observations
sum_tbl <- summarise(Santander_sample
                     ,Total= sum(renta)
                     ,"Min"= min(renta)
                     ,"Max"= max(renta)
                     ,"Median"= median(renta)
                     ,"Mean"= mean(renta)
                     ,"Standard deviation"= sd(renta)
                     ,"Freq"= n()
)

#Print Results
sum_tbl 
Total Min Max Median Mean Standard deviation Freq
11311283030 0 28894396 89517.77 113112.8 248050.3 1e+05
  • שימו לב, הסוגריים לא הכרחיים, הם רק ליופי…

group_by - קיבוץ

הפקודה לא עושה שום דבר בפני עצמה.

אבל היא עושה הרבה מאוד בשילוב עם שאר הפקודות

עכשיו בוא ננסה לראות את אותו דבר לפי סגמנט בעזרת group_by

sum_tbl <- Santander_sample %>%
            group_by(segmento) %>%
            summarise("Total"=sum(renta)
                      ,"Min"=min(renta)
                      ,"Max"=max(renta)
                      ,"Median"=median(renta)
                      ,"Mean"=mean(renta)
                      ,"Standard deviation"=sd(renta)
                      ,"Freq"=n()
            )

#Print Results
sum_tbl 
segmento Total Min Max Median Mean Standard deviation Freq
01 - TOP 1162841489 0 11139896 121900.53 146564.34 236408.3 7934
02 - PARTICULARES 7715901289 0 28894396 93111.86 117166.78 255736.2 65854
03 - UNIVERSITARIO 2432540252 0 28894396 74792.31 92802.54 229607.9 26212

הערה חשובה: בטבלה שיצרתםם בעזרת group_by היא תמיד תהיה מקובצת תחת הקבוצה שיצרתם

על מנת להסיר את הקיבוץ תפעילו את הפקודה ungroup()


mutate - יצירת או שינוי עמודות

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

calc_vetek <- Santander_sample %>% 
              mutate(vetek_yrs = antiguedad/12 ) %>% 
              select(antiguedad, vetek_yrs, age, segmento)


#print results
calc_vetek %>% slice(1:10) 
antiguedad vetek_yrs age segmento
218 18.1666667 92 01 - TOP
116 9.6666667 49 02 - PARTICULARES
4 0.3333333 20 03 - UNIVERSITARIO
115 9.5833333 53 02 - PARTICULARES
33 2.7500000 48 02 - PARTICULARES
105 8.7500000 72 02 - PARTICULARES
142 11.8333333 49 02 - PARTICULARES
114 9.5000000 53 02 - PARTICULARES
20 1.6666667 67 01 - TOP
197 16.4166667 54 02 - PARTICULARES

מה שלא מובן מאליו הוא שאפשר להשתמש בשדה החדש עוד באותו פקודה!

למשל, אם בנוסף הייתי רוצה עוד עמודה המחשבת באיזה גיל התחיל כלקוח

calc_vetek <- Santander_sample %>% 
              mutate( vetek_yrs = antiguedad/12
                      ,age_lakoach_start = age - vetek_yrs ) %>% 
              select(antiguedad, vetek_yrs, age, age_lakoach_start, segmento)

calc_vetek %>% slice(1:10) 
antiguedad vetek_yrs age age_lakoach_start segmento
218 18.1666667 92 73.83333 01 - TOP
116 9.6666667 49 39.33333 02 - PARTICULARES
4 0.3333333 20 19.66667 03 - UNIVERSITARIO
115 9.5833333 53 43.41667 02 - PARTICULARES
33 2.7500000 48 45.25000 02 - PARTICULARES
105 8.7500000 72 63.25000 02 - PARTICULARES
142 11.8333333 49 37.16667 02 - PARTICULARES
114 9.5000000 53 43.50000 02 - PARTICULARES
20 1.6666667 67 65.33333 01 - TOP
197 16.4166667 54 37.58333 02 - PARTICULARES
  • אם הייתי משתמש בשם של עמודה קיימת הוא היה מחליף אותה
  • ככה אפשר גם לשנות עמודה כפי שנראה בהמשך


transmute - תחזיר רק עמודה מחושבת

לפעמים זה יהיה שימושי להחזיר רק את החישוב:

calc_vetek <- Santander_sample %>% 
                transmute( vetek_yrs = antiguedad/12
                           ,age_lakoach_start = age - vetek_yrs )

# print results
calc_vetek %>% slice(1:10) 
vetek_yrs age_lakoach_start
18.1666667 73.83333
9.6666667 39.33333
0.3333333 19.66667
9.5833333 43.41667
2.7500000 45.25000
8.7500000 63.25000
11.8333333 37.16667
9.5000000 43.50000
1.6666667 65.33333
16.4166667 37.58333

ביצוע חישבוים על מספר עמודות

לפונקציות summarise ו transform יש גרסאות שונות לביצוע אותו פעולה על מספר עמודות:

עבור פקודת mutate יש :

  • mutate_at - בצע שינוי או חישוב על כל עמודה מסומנת
  • mutate_all - בצע שינוי או חישוב על כל העמודות
  • mutate_if - בצע שינוי או חישוב על כל עמודה העומדת בתנאי

עבור פקודת summarise יש :

  • summarise_all - בצע סיכום לכל העמודות
  • summarise_at - בצע סיכום לכל עמודה מסומנת
  • summarise_if - בצע סיכום לכל עמודה העומדת בתנאי

אנו נדגים אחד מכל סוג - להרחבה ראו עזרה על summarise_all

mutate_at - חישוב על מספר עמודות

אם יש פקודה שרוצים לבצע לכמה עמודות, במקום לכתוב כל אחד בנפרד אפשר להשתמש ב mutate_each.

ה syntax של הפקודה היא:

mutate_at(.tbl, .cols, .funs, …)

כאשר :

  • .tbl - שם הטבלה
  • .cols - שמות העמודות עליהן נרצה לבצע את הפעולה מאוכלסות בתוך הפקודה ()vars
  • .funs - שמות הפונקציות לביצוע בתוך הפקודה ()funs
  • … - פרמטרים נוספים לפונקציות

למשל, לעגל את העמודות המחושבות

calc_vetek2 <- calc_vetek %>% 
                mutate_at(vars(vetek_yrs, age_lakoach_start)
                          , funs(round))


# print result
calc_vetek2  %>% slice(1:10) 
vetek_yrs age_lakoach_start
18 74
10 39
0 20
10 43
3 45
9 63
12 37
10 44
2 65
16 38
# If we want the original values we need to add names!!!

calc_vetek2 <- calc_vetek %>% 
                mutate_at(vars(vetek_yrs, age_lakoach_start)
                          , funs("new" = round))

# print result

calc_vetek2 %>% slice(1:10) 
vetek_yrs age_lakoach_start vetek_yrs_new age_lakoach_start_new
18.1666667 73.83333 18 74
9.6666667 39.33333 10 39
0.3333333 19.66667 0 20
9.5833333 43.41667 10 43
2.7500000 45.25000 3 45
8.7500000 63.25000 9 63
11.8333333 37.16667 12 37
9.5000000 43.50000 10 44
1.6666667 65.33333 2 65
16.4166667 37.58333 16 38
# to pass arithematic transfomration use `.` instead of the coloumn name

calc_vetek2 <- calc_vetek %>% 
                mutate_at(vars(vetek_yrs, age_lakoach_start)
                          ,funs("mnths" = .*12) )

# print result

calc_vetek2 %>% slice(1:10) 
vetek_yrs age_lakoach_start vetek_yrs_mnths age_lakoach_start_mnths
18.1666667 73.83333 218 886
9.6666667 39.33333 116 472
0.3333333 19.66667 4 236
9.5833333 43.41667 115 521
2.7500000 45.25000 33 543
8.7500000 63.25000 105 759
11.8333333 37.16667 142 446
9.5000000 43.50000 114 522
1.6666667 65.33333 20 784
16.4166667 37.58333 197 451

summarise_all - סיכום למספר עמודות

ובצורה דומה , אם נרצה סיכום של מספר עמודות נשתמש ב summarise_each.

ה syntax הוא:

summarise_all(.tbl, .funs, …)

כאשר :

  • .tbl - שם הטבלה
  • .funs - שמות הפונקציות לביצוע בתוך הפקודה ()funs
  • … - פרמטרים נוספים לפונקציות

למשל ערך אחוזון 5 וממוצע:

sum_tbl <- calc_vetek %>% 
            summarise_all( funs("p5" = quantile(.,0.05) , mean) )


#print results

sum_tbl 
vetek_yrs_p5 age_lakoach_start_p5 vetek_yrs_mean age_lakoach_start_mean
0.4166667 19.33333 6.97477 35.03157
  • שימו לב לשימוש ב . במקום השם של המשתנה שמשתמשים בו


פונקציות חלון - למתקדמים…

אפשר לחשב פונקציות אגרגטיביות (כמו ממוצע מקסימום ומינימום) ולחבר את התוצאה ישר לטבלה בשילוב עם mutate.

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


עם mutate

רק להדגים חלק מהפקודות:

# Show Percent and cumulative Percent
renta_stats <- Santander_sample %>% 
                select(renta) %>% 
                arrange(desc(renta)) %>% 
                mutate(sum_renta = sum(renta)
                       ,mean_renta = mean(renta)
                       ,min_renta = min(renta)
                       ,max_renta = max(renta)
                       ,meidan_renta = median(renta)
                       ,sd_renta = sd(renta)
                       
                       ,lag_renta = lag(renta)
                       ,lead_renta = lead(renta)
                       
                       ,cum_sum_renta = cumsum(renta)
                       ,cum_mean_renta = cummean(renta)
                       ,cum_min_renta = cummin(renta) 
                       ,cum_max_renta = cummax(renta)
                       
                       ,rank_renta = row_number(renta)
                       ,rank2_renta = min_rank(renta)
                       ,rank3_renta = dense_rank(renta)
                       ,rank4_renta = percent_rank(renta)
                       ,ntile_renta = ntile(renta, 3)
                       
                       ,cum_dist = cume_dist(renta)
                )

renta_stats %>% slice(1:10) 
renta sum_renta mean_renta min_renta max_renta meidan_renta sd_renta lag_renta lead_renta cum_sum_renta cum_mean_renta cum_min_renta cum_max_renta rank_renta rank2_renta rank3_renta rank4_renta ntile_renta cum_dist
28894396 11311283030 113112.8 0 28894396 89517.77 248050.3 NA 28894396 28894396 28894396 28894396 28894396 99999 99999 67773 0.99999 3 1.00000
28894396 11311283030 113112.8 0 28894396 89517.77 248050.3 28894396 22034738 57788792 28894396 28894396 28894396 100000 99999 67773 0.99999 3 1.00000
22034738 11311283030 113112.8 0 28894396 89517.77 248050.3 28894396 22034738 79823530 26607843 22034738 28894396 99997 99997 67772 0.99997 3 0.99998
22034738 11311283030 113112.8 0 28894396 89517.77 248050.3 22034738 15711716 101858268 25464567 22034738 28894396 99998 99997 67772 0.99997 3 0.99998
15711716 11311283030 113112.8 0 28894396 89517.77 248050.3 22034738 13268621 117569984 23513997 15711716 28894396 99996 99996 67771 0.99996 3 0.99996
13268621 11311283030 113112.8 0 28894396 89517.77 248050.3 15711716 11411517 130838605 21806434 13268621 28894396 99995 99995 67770 0.99995 3 0.99995
11411517 11311283030 113112.8 0 28894396 89517.77 248050.3 13268621 11202220 142250122 20321446 11411517 28894396 99994 99994 67769 0.99994 3 0.99994
11202220 11311283030 113112.8 0 28894396 89517.77 248050.3 11411517 11139896 153452342 19181543 11202220 28894396 99993 99993 67768 0.99993 3 0.99993
11139896 11311283030 113112.8 0 28894396 89517.77 248050.3 11202220 9833873 164592238 18288026 11139896 28894396 99992 99992 67767 0.99992 3 0.99992
9833873 11311283030 113112.8 0 28894396 89517.77 248050.3 11139896 9792857 174426111 17442611 9833873 28894396 99991 99991 67766 0.99991 3 0.99991

עם filter

sum_tbl <- Santander_sample %>% 
              filter( renta == max(renta))

sum_tbl2 <- Santander_sample %>% 
              filter(  renta > mean(renta))

sum_tbl2 <- Santander_sample %>% 
              filter(  renta > median(renta))

sum_tbl2 %>% select(renta, segmento) %>% slice(1:10) 
renta segmento
249323.8 02 - PARTICULARES
171329.0 03 - UNIVERSITARIO
108166.5 02 - PARTICULARES
169832.1 02 - PARTICULARES
130283.7 02 - PARTICULARES
172876.4 02 - PARTICULARES
271485.1 02 - PARTICULARES
109185.4 01 - TOP
128760.4 02 - PARTICULARES
121056.3 03 - UNIVERSITARIO

duplicates - מציאת כפילויות

יש מספר דרכים לזהות שורות לא ייחודיות:

  • unique - מצא שורות ייחודיות
  • duplicated - מוצא שורות כפולות
  • distinct - כמו ב SQL
  • filter + count - סינון שורות שמופיעות מספר פעמים
  • n_distinct - מחזיר מספר שורות ייחודיות

נגדים רק על חלק מהשיטות

בואו נשווה בין מספר שורות ייחודיות n_distinct לבין מספר שורות סך הכל n, בפקודת summarise

summarise(Santander_sample
          , "N Distinct" = n_distinct(segmento)
          , "N" = n()) 
N Distinct N
3 1e+05

עכשיו נקח רק שורות ייחודיות לפי המשתנה segmento בעזרת distinct

seg_distinct  <-  Santander_sample %>% 
                    distinct(segmento, .keep_all = TRUE) 

seg_distinct[,1:5]  
fecha_dato ncodpers ind_empleado pais_residencia sexo
2015-04-28 64154 N ES H
2016-01-28 616876 N ES V
2016-01-28 1448463 N ES V

ונסתכל על השורות הכפולות בעזרת סינון שורות שמופיעות מספר פעמים:

dups <- Santander_sample %>% 
          group_by(segmento) %>% 
          filter(row_number()>1)

dups %>% select(1:5) %>% slice(1:3) 
## Adding missing grouping variables: `segmento`
## # A tibble: 9 x 6
## # Groups:   segmento [3]
##             segmento fecha_dato ncodpers ind_empleado pais_residencia
##                <chr>     <dttm>    <int>        <chr>           <chr>
## 1           01 - TOP 2016-01-28  1258317            N              ES
## 2           01 - TOP 2015-10-28   691001            N              ES
## 3           01 - TOP 2015-07-28   217566            N              ES
## 4  02 - PARTICULARES 2016-01-28   621277            N              ES
## 5  02 - PARTICULARES 2016-03-28  1137501            N              ES
## 6  02 - PARTICULARES 2016-01-28   685293            N              ES
## 7 03 - UNIVERSITARIO 2016-01-28  1277143            N              ES
## 8 03 - UNIVERSITARIO 2016-03-28   985359            N              ES
## 9 03 - UNIVERSITARIO 2015-07-28   658233            N              ES
## # ... with 1 more variables: sexo <chr>

סיכום ביניים dplyr

עכשיו יש לכם את הכלים לבצע כמעט כל אנליזה שתרצו על הנתונים שלכם!

  • לסיכום ה syntax הכללי נראה משהו כזה:

TableName %>%

group_by(groupVariables) %>%

select(selectedColumns) %>%

mutate(calculatedColumns)

filter(filterConditions) %>%

arrange(orderByVariables)

ואם אתם מבצעים סיכום משתנה זה בדרך כלל משהו כזה:

TableName %>%

group_by(groupVariables) %>%

summarise(summaryStatistics)

כמובן שהכל לפי הצורך! ולא חייב להראות ככה בכלל !!!!

עכשיו תורכם!!!



פונקציות חיבור בין טבלאות

קבוצה אחרת של פונקציות שרצוי שנכיר הן פונקציות המקשרות בין טבלאות

רוב המשפחה של פונקציות אלה נגמרים בסיומת _join :

  • inner_join - חיבור רק מה שבשני הטבלאות
  • left_join - חיבור רק מה שבטבלה השמאלית
  • right_join - חיבור רק מה שבטבלה הימנית
  • full_join - מה שבשני הטבלאות
  • semi_join - מחזיר רק את טבלה שמאל ומשאיר רק רשומות המופיעות בטבלה ימין
  • anti_join - מחזיר רק את טבלה שמאל מסונן לפי טבלה ימין

מי שמכיר SQL ירגיש בבית.

אנו נעבור רק על left_join השאר באותו שיטה


left_join

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

ה syntax הבסיסי:

עבור שדה בעל אותו שם בשני הטבלאות:

new_table <- left_join(table1, table2, by=“keyValue”)

אם המפתח בעל שם שונה בשני הטלאות:

new_table <- left_join(table1, table2, by=c(“key1”=“key2”))

אם החיבור נעשה על ידי מספר שדות זה יצויין כך:

new_table <- left_join(table1, table2 ,by=c(“table1key1”=“table2key1” ,“table1key2”=“table2key2” ))


נושאים נוספים

זה אמור לכסות את רוב הצרכים המיידיים שלכם בשימוש ב dplyr

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

  • שימוש ב SQL ושות בעזרת dplyr
  • שימוש ב select_helpers
  • שימוש בפונקציות מסוג NSE בעזרת _
  • ועוד…

אתם מוזמנים לחפש בעזרה ובאינטרנט….



שינוי מבנה הנתונים

יש שתי חבילות מובילות לשינוי מבנה הנתונים:

  • tidyr - חבילה מה tidyverse שנועדה לסידור נתונים
  • reshape2 - חבילה יעודית לשחלוף נתונים

חבילת tidyr היא (בינתיים) קצת יותר מוגבלת בשחלוף נתונים

זאת כיוון שהיא נועדה לסדר נתונים בהתאם לפלוסופיה שהוזכרה לעיל

reshape2 נועד רק לשחלף נתונים ולכן הוא יותר גמיש

נכיר את שניהם בקצרה


tidyr - שינוי מבנה הנתונים

הפקודות בספריית tidyr נועדו לעשות מנפולציות נפוצות על נתונים:

  • שחלוף נתונים:
  • spread - שחלוף נתונים מ long ל wide
  • gather - שחלוף נתונים מ wide ל long

  • אחוד עמודות
  • seperate - חלוקת עמודה אחת למספר עומדות
  • unite - חיבור מספר עמודות לעמודה אחת

קודם נטעין את הספריה ונסתכל על הנתונים לדוגמא

library(tidyr)
## Warning: package 'tidyr' was built under R version 3.3.3
N_month_seg <- Santander_sample %>% 
  group_by(fecha_dato, segmento) %>% 
  summarise(sum_cc = sum(ind_cc),
            n_pop = n())

N_month_seg <- ungroup(N_month_seg)

N_month_seg %>% slice(1:15) 
fecha_dato segmento sum_cc n_pop
2015-04-28 01 - TOP 45 1569
2015-04-28 02 - PARTICULARES 199 12448
2015-04-28 03 - UNIVERSITARIO 15 4507
2015-07-28 01 - TOP 50 1479
2015-07-28 02 - PARTICULARES NA 12614
2015-07-28 03 - UNIVERSITARIO NA 4510
2015-10-28 01 - TOP 37 1547
2015-10-28 02 - PARTICULARES NA 13316
2015-10-28 03 - UNIVERSITARIO NA 5361
2016-01-28 01 - TOP 41 1616
2016-01-28 02 - PARTICULARES NA 13543
2016-01-28 03 - UNIVERSITARIO NA 5882
2016-03-28 01 - TOP 48 1723
2016-03-28 02 - PARTICULARES NA 13933
2016-03-28 03 - UNIVERSITARIO 11 5952



gather - מעבר מ wide ל long

ה syntax הבסיסי של הפקודה היא:

gather(data, key, value, …, na.rm = FALSE, convert = FALSE, factor_key = FALSE)

כאשר:

  • data - טבלת הנתונים
  • key - שם העמודה החדשה שנייצר שיכיל את שמות העמודות שנאסוף
  • value - שם העמודה החדשה שנייצר שיכיל את הערכים של העמודות שנאספוף
  • … - שמות העמודות שנרצה לאסוף

עכשיו נהפוך ל long בעזרת gather

N_month_seg.long <- N_month_seg %>% 
                    gather(key = new_var_col
                           , value = new_value_col 
                           , sum_cc:n_pop )

N_month_seg.long %>% slice(10:20) 
fecha_dato segmento new_var_col new_value_col
2016-01-28 01 - TOP sum_cc 41
2016-01-28 02 - PARTICULARES sum_cc NA
2016-01-28 03 - UNIVERSITARIO sum_cc NA
2016-03-28 01 - TOP sum_cc 48
2016-03-28 02 - PARTICULARES sum_cc NA
2016-03-28 03 - UNIVERSITARIO sum_cc 11
2015-04-28 01 - TOP n_pop 1569
2015-04-28 02 - PARTICULARES n_pop 12448
2015-04-28 03 - UNIVERSITARIO n_pop 4507
2015-07-28 01 - TOP n_pop 1479
2015-07-28 02 - PARTICULARES n_pop 12614

spread - מעבר מ long ל wide

ה syntax הבסיסי של הפקודה היא:

spread(data, key, value, fill = NA, convert = FALSE, drop = TRUE, sep = NULL)

כאשר:

  • data - טבלת הנתונים
  • key - שם העמודה המכילה את השמות של העמודות שנרצה לייצר
  • value - שם העמודה עם הערכים שנרצה לפרוס
  • fill - ערך לשים במקומות ריקים

ונחזיר חזרה ל wide בעזרת spread :

N_month_seg.wide <- N_month_seg.long %>% 
                    spread(key = new_var_col 
                           , value = new_value_col )

N_month_seg.wide %>% slice(10:20) 
fecha_dato segmento n_pop sum_cc
2016-01-28 01 - TOP 1616 41
2016-01-28 02 - PARTICULARES 13543 NA
2016-01-28 03 - UNIVERSITARIO 5882 NA
2016-03-28 01 - TOP 1723 48
2016-03-28 02 - PARTICULARES 13933 NA
2016-03-28 03 - UNIVERSITARIO 5952 11

unite - איחוד עמודות

ה syntax של הפקודה היא:

unite(data, col, …, sep = “_“, remove = TRUE)

כאשר:

  • data - טבלת הנתונים
  • col - שם העמודה החדשה שנייצר
  • … - שמות העמודות שנרצה לאחד
  • sep - צורת ההפרדה
  • remove - האם לשמור את העמודות המקוריות

נייצר משתנה חדש המפריד בין הרכיבים עם סימן _ כך:

N_month_seg.united <- N_month_seg %>% 
                      unite(new_col_name 
                            , fecha_dato , segmento 
                            , sep="_" 
                            , remove = TRUE)

N_month_seg.united %>% slice(20:25) 

new_col_name sum_cc n_pop ————- ——- ——

שימו לב לפקודה remove = TRUE שמוחק את המשתנים המקוריים, כמובן שאפשר גם לשמור אותם


seperate - פיצול עמודות

ה syntax של הפקודה היא:

separate(data, col, into, sep = “[^[:alnum:]]+”, remove = TRUE, convert = FALSE, extra = “warn”, fill = “warn”, …)

כאשר:

  • data - טבלת הנתונים
  • col - העמודה שנרצה לפצל
  • into - שמות העמודות החדשות שנייצר בפציול
  • sep - צורת ההפרדה
  • remove - האם לשמור את העמודות המקוריות

לחלק עמודה אחת למספר עמודות נשתמש ב seperate כך:

# Back to the original

N_month_seg.seperated <- N_month_seg.united %>% 
                         separate(  new_col_name
                                  , c("fecha_dato", "segmento") 
                                  , sep = "_" ) 

N_month_seg.seperated %>% slice(20:25) 

fecha_dato segmento sum_cc n_pop ———– ——— ——- ——



reshape2 - שינוי מבנה הנתונים

הפקודות החשובות בחבילה הן :

  • melt - מעבר מ wide ל long
  • dcast - מעבר מ long ל wide


melt - מעבר מ wide ל long

הסנטקס של הפקודה היא :

melt(data, id.vars, measure.vars, variable.name = “variable”, value.name = “value”, factorsAsStrings = TRUE)

כאשר:

  • data - טבלת הנתונים
  • id.vars - משתני מפתח שנרצה לשמר
  • measure.vars - שמות המשתנים עם ערכים שנרצה לאסוף
  • variable.name - שם המשתנה החדש המכיל את שמות העמודות שנאספו
  • value.name - שם המשתנה החדש המכיל את הערכים של העמודות שנאספו
  • factorsAsStrings - האם להפוך factor ל chr

עכשיו נהפוך ל long בעזרת melt

library(reshape2)
## 
## Attaching package: 'reshape2'
## The following object is masked from 'package:tidyr':
## 
##     smiths
N_month_seg.long <- N_month_seg %>% 
                    melt( id.vars = c("fecha_dato", "segmento")
                          , variable.name = "new_var_col"
                          , value.name = "new_value_col"
                          , factorsAsStrings = FALSE )

N_month_seg.long %>% slice(60:65) 

fecha_dato segmento new_var_col new_value_col ———– ——— ———— ————–

  • שימו לב שלא ציינתי את הפרמט measure.vars, במקרה כזה הוא לוקח את כל העמודות שלא ב `id.vars``

  • אחרת הייתי צריך לציין אותם אחד אחד מופרדים בגרשיים
  • או לפי מספר עמודות למשל 3:5


dcast - מעבר מ long ל wide

הסנטקס המקוצר של הפקודה היא :

dcast(data, formula, fun.aggregate = NULL, …, margins = NULL, value.var = guess_value(data), fill = NULL)

כאשר:

  • data - טבלת הנתונים
  • formula - נוסחא המתארת את השטחת המשתנים
  • fun.aggregate - פונקציה לאגרגציה במקרים של ריבוי ערכים
  • … - ערכים נוספים לפונקצית האגרגציה
  • value.var - שם העמודה עם הערכים להשטחה
  • fill - ערך לשים עבור מקומות ריקים

ה syntax של הפרמטר formula הוא:

key_col1 + key_col2 ~ val1 + val2

בדוגמא שלנו המפתחות הייחודיות הם: fecha_dato ו segmento

עכשיו נהפוך ל wide בעזרת dcast

N_month_seg.wide <- N_month_seg.long %>% 
                    dcast( fecha_dato + segmento ~ new_var_col
                           , value.var = "new_value_col" 
                           , fun.aggregate = mean )

N_month_seg.wide %>%  slice(10:20) 
fecha_dato segmento sum_cc n_pop
2016-01-28 01 - TOP 41 1616
2016-01-28 02 - PARTICULARES NA 13543
2016-01-28 03 - UNIVERSITARIO NA 5882
2016-03-28 01 - TOP 48 1723
2016-03-28 02 - PARTICULARES NA 13933
2016-03-28 03 - UNIVERSITARIO 11 5952
  • במקרה הזה היה מיותר לציין fun.aggregate
  • במקרים של ריבוי תצפיות לפי מפתח הוא עושה אגרגציה לפי בחירה

  • עוד אופציה נחמדה היא fill המאפשר הצבת ערכי ברירת מחדל במקום ערכים חסרים