10  פיית’ון מתוך R

כפי שציינתי בהקדמה לספר זה, אחד מהכלים הנפוצים ל-Data Science (ובכלל) הוא שפת פיית’ון (python). מאוד סביר שבסיטואציה כזו או אחרת תמצאו עצמכם מול בעיה שבה שילוב של פיית’ון עם R יכול להוות יתרון גדול ולחסוך זמן ומאמץ.

לדוגמה, לעיתים קרובות תמצאו ששירותים מסוימים, כגון שירותי Amazon Web Services (AWS) זמינים באופן מלא בפיית’ון (באמצעות חבילה שנקראת boto3 וזמינה בפיית’ון), אך ממומשים באופן חלקי בחבילות ב-R. בדוגמה זו, החבילה boto3 היא חבילה רשמית המתוחזקת על ידי AWS ולעומת זאת, חבילות אחרות הזמינות ישירות ב-R הן חבילות המפותחות על ידי הקהילה, ואינן נתמכות באופן “רשמי” על ידי AWS.

ישנן דוגמאות נוספות רבות, לדוגמה החבילה הרשמית של OpenAI (שנקראת openai בפיית’ון), שמתוחזקת באופן רשמי על ידי OpenAI, ומקבילה לה ל-R הנקראת גם היא באותו השם, אך מתוחזקת על ידי הקהילה באופן לא רשמי.

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

10.1 התקנת סביבה

על מנת שתוכלו לקרוא לפיית’ון מתוך R, ראשית צריך להתקין סביבת פיית’ון. פעולה זו תתבצע בפעם הראשונה בלבד (אלא אם תעברו לעבוד במחשב אחר), באמצעות פקודות של חבילת reticulate. לשם כך ישנן שתי פקודות אפשריות:

  • virtualenv_create
  • conda_create

ההבדל ביניהן הוא הכלי שבו יעשה שימוש להתקנה (Conda מול pip).

# Using Conda
library(reticulate)
conda_create(
    envname = "my_conda_env", 
    packages = c("pandas")) 
# (add libraries to `packages` argument as needed)

# Activate the environment
use_condaenv("my_conda_env")
# Using virtual environment (pip)
library(reticulate)
virtualenv_create(
    envname = "my_virtual_env", 
    packages = c("pandas")) 
# (add libraries to `packages` argument as needed)

# Activate the environment
use_virtualenv("my_virtual_env")

אם ניסיתם להשתמש בפקודה conda_create וקיבלתם הודעת שגיאה “Unable to find conda binary. Is Anaconda installed?”, נדרש קודם להתקין את miniconda על ידי שימוש בפקודה reticulate::install_miniconda, או התקנה ישירה מהאתר הרשמי של חברת Anaconda.

שימו לב שאת פקודת ההפעלה (use_*) יש להפעיל ראשונה, לפני שמפעילים פקודה אחרת של פיית’ון, אחרת reticulate עשוי לבחור בסביבה אחרת זמינה, לפי לוגיקה פנימית (והיא לאו דווקא תהיה הסביבה שאתם מתכוונים, במידה והיתה סביבה אחרת מותקנת).

במידה ופקודה זו לא עבדה כנדרש, ונטענת סביבה אחרת, ניתן גם להשתמש בהגדרת משתנה סביבה (Environment Variable), על ידי שימוש בפקודה Sys.setenv(RETICULATE_PYTHON = PATH) או על ידי הגדרה בקובץ .Renviron בתיקיית העבודה שלכם, עם השורה המתאימה RETICULATE_PYTHON = PATH .

כעת ניתן להריץ קוד פיית’ון ישירות:

py_run_string("
print('Hi, I\\'m python code, run directly from an R interpreter!')
")
Hi, I'm python code, run directly from an R interpreter!

10.2 תרגום בין אובייקטים

ב-R ובפיית’ון יש אובייקטים מסוגים שונים. כדי שנוכל למנף את השילוביות בין שתי השפות כדאי להבין כיצד אובייקטים מתורגמים מאחד לשני. הטבלה הבאה מציגה כיצד אובייקטים עוברים מאחד לשני:

טבלת המרה בין אובייקטים ב-R וב-python
R python
וקטור עם איבר יחיד el <- 5 סקלר el=5
וקטור עם מספר איברים vec <- c(1, 2, 3) רשימה vec=[1, 2, 3]

רשימה משוימת (named) עם איברים מסוגים שונים

lst <- list(a = 5, b = list(1, 2, 3))

אובייקט מסוג מילון

lst={'a' : 5, 'b' : [1, 2, 3]}

רשימה לא משוימת עם איברים מסוגים שונים

lst_unnamed <- list(1, 2, list(3, 4))

רשימה

lst_unamed=[1, 2, [3, 4]]

ניתן להשתמש בפקודה

tup <- reticulate::tuple(1, 2, 3)

בכיוון הפוך (בחזרה מפייתון) היא מומרת לרשימה לא משוימת

list(1, 2, 3)

tuple

tup=(1, 2, 3)

מטריצה

> matrix(1:10, 2, 5)
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    3    5    7    9
[2,]    2    4    6    8   10

מערך של NumPy

array([[ 1,  3,  5,  7,  9],
       [ 2,  4,  6,  8, 10]], dtype=int32)
data frame או tibble data frame של חבילת pandas

ניתן להשתמש בפקודה r_to_py ובפקודה py_to_r על מנת לעבור בין אובייקטים. לדוגמה:

r_to_py(palmerpenguins::penguins)
       species     island  bill_length_mm  ...  body_mass_g     sex  year
0       Adelie  Torgersen            39.1  ...         3750    male  2007
1       Adelie  Torgersen            39.5  ...         3800  female  2007
2       Adelie  Torgersen            40.3  ...         3250  female  2007
3       Adelie  Torgersen             NaN  ...  -2147483648     NaN  2007
4       Adelie  Torgersen            36.7  ...         3450  female  2007
..         ...        ...             ...  ...          ...     ...   ...
339  Chinstrap      Dream            55.8  ...         4000    male  2009
340  Chinstrap      Dream            43.5  ...         3400  female  2009
341  Chinstrap      Dream            49.6  ...         3775    male  2009
342  Chinstrap      Dream            50.8  ...         4100    male  2009
343  Chinstrap      Dream            50.2  ...         3775  female  2009

[344 rows x 8 columns]

10.3 שילוב קוד פיית’ון בסקריפט

לאחר שהפעלנו את סביבת הפיית’ון הרצויה, ניתן לקרוא חבילות (במידה והותקנו במסגרת בניית הסביבה הוירטואלית), באמצעות הפקודה import מתוך חבילת reticulate, ואז להשתמש בפקודות שזמינות בחבילות שקראנו.

הקריאה לפקודה מתוך חבילה מסוימת תתבצע באמצעות התו $.

נדגים זאת על ידי שימוש בפקודות מתוך pandas:

pd <- import("pandas")
species_count <- pd$value_counts(palmerpenguins::penguins$species)
species_count
   Adelie    Gentoo Chinstrap 
      152       124        68 
# And another option is to use this:
penguins_py <- r_to_py(palmerpenguins::penguins)

# Demonstrating grouping, counts, then proportions
# Group penguins by island and species
grouped <- penguins_py$groupby(list('island', 'species'))$size()$reset_index(name='counts')

# Calculate proportions for each species on each island
grouped['proportion'] <- grouped$groupby('island')['counts']$transform(function(x) x / x$sum())

# Convert the Pandas DataFrame back to an R dataframe (optional)
grouped_r <- py_to_r(grouped)

grouped_r
     island   species counts proportion
1    Biscoe    Adelie     44  0.2619048
2    Biscoe Chinstrap      0  0.0000000
3    Biscoe    Gentoo    124  0.7380952
4     Dream    Adelie     56  0.4516129
5     Dream Chinstrap     68  0.5483871
6     Dream    Gentoo      0  0.0000000
7 Torgersen    Adelie     52  1.0000000
8 Torgersen Chinstrap      0  0.0000000
9 Torgersen    Gentoo      0  0.0000000

הפקודה py_to_r מעבירה את התוצאות חזרה לאובייקטים של R, וניתן לעבוד איתם באופן רגיל. במקרה זה האובייקט grouped_r הוא מסוג data.frame.

10.4 סיכום

בפרק זה עסקנו בשילוב בין שפת פיית’ון לבין R באמצעות חבילת reticulate. שילוב זה מאפשר לנצל את היתרונות של כל אחת מהשפות. אני באופן אישי מעדיף להשתמש בעיקר ב-R, במיוחד בכל המקרים של ניתוח נתונים “קלאסי” (כל מה שמכוסה בפרקים השונים של ספר זה).

המקרים בהם יש יתרון לשימוש בפיית’ון באמצעות reticulate הם כאשר ישנה חבילה מסוימת שהיא יותר “בשלה” או מתוחזקת היטב בפיית’ון אבל המקבילה שלה ב-R אינה קיימת, או מתוחזקת באופן חלקי/לא מספק.

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

בפרק הבא נראה דוגמה פרקטית נוספת של שימוש בספריית openai של פיית’ון, להפעלת מודלי LLM של חברת OpenAI.