Python kontra R: Syntactic Sugar Magic
Opublikowany: 2022-07-22Moje podniebienie rozwojowe rozszerzyło się, odkąd nauczyłem się doceniać słodycz znalezioną w Pythonie i R. Data science to sztuka, do której można podejść z wielu stron, ale wymaga starannej równowagi języka, bibliotek i wiedzy. Rozbudowane możliwości Pythona i R zapewniają cukier składniowy: składnię, która ułatwia nam pracę i pozwala nam rozwiązywać złożone problemy za pomocą krótkich, eleganckich rozwiązań.
Te języki zapewniają nam unikalne sposoby eksploracji naszej przestrzeni rozwiązań. Każdy język ma swoje mocne i słabe strony. Sztuczka do efektywnego wykorzystania każdego z nich polega na rozpoznaniu, jakie typy problemów odnoszą korzyści z każdego narzędzia i decydowaniu, w jaki sposób chcemy przekazać nasze odkrycia. Cukier składniowy w każdym języku pozwala nam pracować wydajniej.
R i Python działają jako interaktywne interfejsy na wierzchu kodu niższego poziomu, umożliwiając analitykom danych używanie wybranego języka do eksploracji, wizualizacji i modelowania danych. Ta interaktywność pozwala nam uniknąć nieustannej pętli edycji i kompilacji kodu, która niepotrzebnie komplikuje naszą pracę.
Te języki wysokiego poziomu pozwalają nam pracować z minimalnymi trudnościami i robić więcej przy mniejszej ilości kodu. Cukier składniowy każdego języka pozwala nam szybko przetestować nasze pomysły w REPL (pętla odczytu-oceny-drukowania), interaktywnym interfejsie, w którym kod może być wykonywany w czasie rzeczywistym. To iteracyjne podejście jest kluczowym elementem w nowoczesnym cyklu przetwarzania danych.
R vs. Python: ekspresyjny i wyspecjalizowany
Siła R i Pythona tkwi w ich ekspresji i elastyczności. Każdy język ma określone przypadki użycia, w których jest potężniejszy od drugiego. Dodatkowo każdy język rozwiązuje problemy za pomocą różnych wektorów i bardzo różnych typów danych wyjściowych. Te style mają zwykle różne społeczności programistów, w których preferowany jest jeden język. Ponieważ każda społeczność rozwija się organicznie, ich preferowany język i zestaw funkcji dążą do unikalnych stylów cukru składniowego, które zmniejszają objętość kodu wymaganą do rozwiązywania problemów. A gdy społeczność i język dojrzewają, cukier składniowy języka często staje się jeszcze słodszy.
Chociaż każdy język oferuje potężny zestaw narzędzi do rozwiązywania problemów z danymi, musimy podejść do tych problemów w sposób wykorzystujący poszczególne mocne strony narzędzi. R narodził się jako język obliczeń statystycznych i ma szeroki zestaw narzędzi do przeprowadzania analiz statystycznych i wyjaśniania danych. Python i jego podejścia do uczenia maszynowego rozwiązują podobne problemy, ale tylko te, które pasują do modelu uczenia maszynowego. Pomyśl o obliczeniach statystycznych i uczeniu maszynowym jako o dwóch szkołach modelowania danych: chociaż szkoły te są ze sobą ściśle powiązane, ich pochodzenie i paradygmaty modelowania danych są różne.
R uwielbia statystyki
R przekształcił się w bogatą ofertę pakietów do analizy statystycznej, modelowania liniowego i wizualizacji. Ponieważ te pakiety są częścią ekosystemu R od dziesięcioleci, są dojrzałe, wydajne i dobrze udokumentowane. Gdy problem wymaga podejścia do obliczeń statystycznych, R jest właściwym narzędziem do pracy.
Główne powody, dla których społeczność R jest kochana, sprowadza się do:
- Dyskretna manipulacja danymi, metody obliczania i filtrowania.
- Operatory elastycznego łączenia w łańcuchy do łączenia tych metod.
- Zwięzły cukier składniowy, który pozwala programistom rozwiązywać złożone problemy przy użyciu wygodnych metod statystycznych i wizualizacyjnych.
Prosty model liniowy z R
Aby zobaczyć, jak zwięzłe może być R, stwórzmy przykład, który przewiduje ceny diamentów. Po pierwsze potrzebujemy danych. Użyjemy domyślnego zestawu danych diamonds
, który jest instalowany wraz z R i zawiera atrybuty, takie jak kolor i cięcie.
Zademonstrujemy również operator potoku R ( %>%
), odpowiednik uniksowego operatora potoku ( |
). Ten popularny element funkcji cukru składniowego R jest udostępniany przez pakiet pakietów tidyverse. Ten operator i wynikający z niego styl kodu zmienia zasady gry w języku R, ponieważ umożliwia łączenie czasowników R (tj. funkcji R) w celu dzielenia i opanowania szerokiego zakresu problemów.
Poniższy kod ładuje wymagane biblioteki, przetwarza nasze dane i generuje model liniowy:
library(tidyverse) library(ggplot2) mode <- function(data) { freq <- unique(data) freq[which.max(tabulate(match(data, freq)))] } data <- diamonds %>% mutate(across(where(is.numeric), ~ replace_na(., median(., na.rm = TRUE)))) %>% mutate(across(where(is.numeric), scale)) %>% mutate(across(where(negate(is.numeric)), ~ replace_na(.x, mode(.x)))) model <- lm(price~., data=data) model <- step(model) summary(model)
Call: lm(formula = price ~ carat + cut + color + clarity + depth + table + x + z, data = data) Residuals: Min 1Q Median 3Q Max -5.3588 -0.1485 -0.0460 0.0943 2.6806 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) -0.140019 0.002461 -56.892 < 2e-16 *** carat 1.337607 0.005775 231.630 < 2e-16 *** cut.L 0.146537 0.005634 26.010 < 2e-16 *** cut.Q -0.075753 0.004508 -16.805 < 2e-16 *** cut.C 0.037210 0.003876 9.601 < 2e-16 *** cut^4 -0.005168 0.003101 -1.667 0.09559 . color.L -0.489337 0.004347 -112.572 < 2e-16 *** color.Q -0.168463 0.003955 -42.599 < 2e-16 *** color.C -0.041429 0.003691 -11.224 < 2e-16 *** color^4 0.009574 0.003391 2.824 0.00475 ** color^5 -0.024008 0.003202 -7.497 6.64e-14 *** color^6 -0.012145 0.002911 -4.172 3.02e-05 *** clarity.L 1.027115 0.007584 135.431 < 2e-16 *** clarity.Q -0.482557 0.007075 -68.205 < 2e-16 *** clarity.C 0.246230 0.006054 40.676 < 2e-16 *** clarity^4 -0.091485 0.004834 -18.926 < 2e-16 *** clarity^5 0.058563 0.003948 14.833 < 2e-16 *** clarity^6 0.001722 0.003438 0.501 0.61640 clarity^7 0.022716 0.003034 7.487 7.13e-14 *** depth -0.022984 0.001622 -14.168 < 2e-16 *** table -0.014843 0.001631 -9.103 < 2e-16 *** x -0.281282 0.008097 -34.740 < 2e-16 *** z -0.008478 0.005872 -1.444 0.14880 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 Residual standard error: 0.2833 on 53917 degrees of freedom Multiple R-squared: 0.9198, Adjusted R-squared: 0.9198 F-statistic: 2.81e+04 on 22 and 53917 DF, p-value: < 2.2e-16
R sprawia, że to równanie liniowe jest proste do zaprogramowania i zrozumienia dzięki jego cukrem składniowym. Przejdźmy teraz naszą uwagę na to, gdzie króluje Python.
Python jest najlepszy do uczenia maszynowego
Python to potężny język ogólnego przeznaczenia, którego jedna z głównych społeczności użytkowników koncentruje się na uczeniu maszynowym, wykorzystując popularne biblioteki, takie jak scikit-learn, imbalanced-learn i Optuna. Wiele z najbardziej wpływowych zestawów narzędzi do uczenia maszynowego, takich jak TensorFlow, PyTorch i Jax, jest napisanych głównie dla Pythona.
Cukier składniowy Pythona to magia, którą uwielbiają eksperci od uczenia maszynowego, w tym zwięzła składnia potoku danych, a także wzorzec fit-transform-predict scikit-learn:
- Przekształć dane, aby przygotować je do modelu.
- Skonstruuj model (niejawny lub jawny).
- Dopasuj model.
- Przewiduj nowe dane (nadzorowany model) lub przekształć dane (bez nadzoru).
- W przypadku modeli nadzorowanych oblicz metrykę błędu dla nowych punktów danych.
Biblioteka scikit-learn zawiera funkcjonalność pasującą do tego wzorca, jednocześnie upraszczając programowanie do eksploracji i wizualizacji. Istnieje również wiele funkcji odpowiadających każdemu etapowi cyklu uczenia maszynowego, zapewniając walidację krzyżową, dostrajanie hiperparametrów i potoki.
Model diamentowego uczenia maszynowego
Skoncentrujemy się teraz na prostym przykładzie uczenia maszynowego przy użyciu Pythona, który nie ma bezpośredniego porównania w języku R. Użyjemy tego samego zestawu danych i wyróżnimy wzorzec fit-transform-predict w bardzo napiętym fragmencie kodu.
Zgodnie z podejściem uczenia maszynowego podzielimy dane na partycje szkoleniowe i testowe. Zastosujemy te same przekształcenia na każdej partycji i połączymy zawarte operacje za pomocą potoku. Metody (dopasowanie i ocena) są kluczowymi przykładami potężnych metod uczenia maszynowego zawartych w scikit-learn:
import numpy as np import pandas as pd from sklearn.linear_model LinearRegression from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.preprocessing import OneHotEncoder from sklearn.impute import SimpleImputer from sklearn.pipeline import Pipeline from sklearn.compose import ColumnTransformer from pandas.api.types import is_numeric_dtype diamonds = sns.load_dataset('diamonds') diamonds = diamonds.dropna() x_train,x_test,y_train,y_test = train_test_split(diamonds.drop("price", axis=1), diamonds["price"], test_size=0.2, random_state=0) num_idx = x_train.apply(lambda x: is_numeric_dtype(x)).values num_cols = x_train.columns[num_idx].values cat_cols = x_train.columns[~num_idx].values num_pipeline = Pipeline(steps=[("imputer", SimpleImputer(strategy="median")), ("scaler", StandardScaler())]) cat_steps = Pipeline(steps=[("imputer", SimpleImputer(strategy="constant", fill_value="missing")), ("onehot", OneHotEncoder(drop="first", sparse=False))]) # data transformation and model constructor preprocessor = ColumnTransformer(transformers=[("num", num_pipeline, num_cols), ("cat", cat_steps, cat_cols)]) mod = Pipeline(steps=[("preprocessor", preprocessor), ("linear", LinearRegression())]) # .fit() calls .fit_transform() in turn mod.fit(x_train, y_train) # .predict() calls .transform() in turn mod.predict(x_test) print(f"R squared score: {mod.score(x_test, y_test):.3f}")
Widzimy, jak usprawniony jest proces uczenia maszynowego w Pythonie. Ponadto klasy sklearn
Pythona pomagają programistom uniknąć wycieków i problemów związanych z przekazywaniem danych przez nasz model, jednocześnie generując kod strukturalny i na poziomie produkcyjnym.
Co jeszcze potrafią R i Python?
Oprócz rozwiązywania aplikacji statystycznych i tworzenia modeli uczenia maszynowego, R i Python przodują w raportowaniu, interfejsach API, interaktywnych pulpitach nawigacyjnych i prostym dołączaniu zewnętrznych bibliotek kodu niskiego poziomu.
Deweloperzy mogą generować interaktywne raporty zarówno w R, jak i Pythonie, ale znacznie prościej jest je tworzyć w R. R obsługuje również eksportowanie tych raportów do formatu PDF i HTML.
Oba języki umożliwiają analitykom danych tworzenie interaktywnych aplikacji danych. R i Python używają odpowiednio bibliotek Shiny i Streamlit do tworzenia tych aplikacji.
Wreszcie, R i Python obsługują zewnętrzne wiązania do kodu niskopoziomowego. Jest to zwykle używane do wstrzykiwania wysoce wydajnych operacji do biblioteki, a następnie wywoływania tych funkcji z wybranego języka. R używa pakietu Rcpp, podczas gdy Python używa do tego pakietu pybind11.
Python i R: coraz słodsze każdego dnia
W mojej pracy jako data scientist regularnie używam zarówno R, jak i Pythona. Kluczem jest zrozumienie, gdzie każdy język jest najsilniejszy, a następnie dostosowanie problemu do elegancko zakodowanego rozwiązania.
Podczas komunikowania się z klientami naukowcy zajmujący się danymi chcą to robić w języku, który jest najłatwiejszy do zrozumienia. Dlatego musimy rozważyć, czy prezentacja statystyczna czy ucząca się maszynowo jest bardziej efektywna, a następnie użyć najbardziej odpowiedniego języka programowania.
Zarówno Python, jak i R zapewniają stale rosnącą kolekcję cukru składniowego, który zarówno upraszcza naszą pracę jako analityków danych, jak i ułatwia jej zrozumiałość dla innych. Im bardziej dopracowana jest nasza składnia, tym łatwiej jest zautomatyzować i współdziałać z naszymi preferowanymi językami. Podoba mi się mój słodki język data science, a eleganckie rozwiązania, które wynikają, są jeszcze słodsze.
Dalsza lektura na blogu Toptal Engineering:
- Wprowadzenie do teorii uczenia maszynowego i jej zastosowań: wizualny samouczek z przykładami
- Wzorce projektowe Pythona: dla eleganckiego i modnego kodu
- Analiza sieci społecznościowych w R i Gephi: kopanie na Twitterze
- Poznawanie nadzorowanych algorytmów uczenia maszynowego
- Zapewnienie czystego kodu: spojrzenie na Pythona, sparametryzowane