Python Vs R

Quel est le meilleur langage pour l’analyse de données? (Python vs R)

Dans cet article, je vais comparer Python vs R de façon objective. Pour ce faire, j’analyserai des données avec ces 2 langages pour obtenir les mêmes résultats. Cela nous permettra de comprendre les forces et faiblesses de chacun. Même si j’enseigne pour le moment seulement Python, je pense que Python et R ont tous les 2 leur place dans la boîte à outils des compétences d’un data scientist.

Nous analyserons ici un ensemble de données sur les joueurs de la NBA et leur performance au cours de la saison 2013-2014. Vous pouvez télécharger le fichier ici. Pour chaque étape de l’analyse, nous montrerons le code Python et R ainsi que les résultats (depuis l’interface Jupyter Notebook pour Python et à partir de R Studio pour R). On en profitera pour ajouter quelques explications et remarques sur les différentes approches.

Sans plus tarder, que le match commence !

Python vs R : Importer un fichier CSV

Python :

import pandas as pd
nba = pd.read_csv("nba_2013.csv")

R :

nba <- read.csv("nba_2013.csv")

Ce code lit le fichier csv nba_2013.csv, qui contient des données sur les joueurs NBA de la saison 2013-2014, dans une variable qu’on nomme nba. La seule vraie différence est qu’en Python, nous devons importer la bibliothèque Pandas pour avoir accès aux Dataframes. Les Dataframes en R ou Python sont des tableaux bidimensionnels (matrices) où chaque colonne peut être d’un type de données différent.
À la fin de cette étape, le fichier csv a été chargé dans un tableau pour les 2 langages.

Python vs R : Trouver le nombre de lignes

Python :

nba.shape
(481, 31)

R :

dim(nba)
481   31

Cela retourne le nombre de joueurs et le nombre de colonnes du DataFrame.
Nous avons 481 lignes (ou joueurs) et 31 colonnes contenant des données sur les joueurs.

Python vs R : Observations de la première ligne du DataFrame

Python :

nba.head(1)

R :

head(nba, 1)

Les deux codes ci-dessus affichent la première ligne du tableau. On remarque que la syntaxe est très similaire. Python est plus orienté objet avec l’application de la méthode head sur l’objet dataframe.
R quant à lui utilise la fonction head. C’est assez fréquent, Python est orienté objet alors que R est plus fonctionnel.

Python vs R : Trouver la moyenne pour chaque colonne

Nous allons maintenant trouver la valeur moyenne pour chaque statistique. Les colonnes, comme vous pouvez le voir, ont des noms comme fg (field goals made) et ast (assists). Ce sont les statistiques de la saison pour le joueur correspondant.
Si vous voulez une explication plus complète de toutes les statistiques de basketball, regardez ici.

Python :

nba.mean()

R :

sapply(nba, mean, na.rm=TRUE)

On note quelques différences majeures dans notre approche. Dans les deux cas, nous appliquons une fonction dans les colonnes du tableau.

En python, la méthode .mean() sur les DataFrames trouvera par défaut la moyenne de chaque colonne.En R, prendre la moyenne des valeurs de chaîne se traduira par NA – Not Available. Nous devons donc ignorer les valeurs NA lorsque nous prenons la moyenne (nous obligeant à ajouter na.rm = TRUE dans les paramètres de la fonction mean). Si nous ne le faisons pas, nous nous retrouvons avec NA pour la moyenne des colonnes comme x3p (cette colonne est un pourcentage de trois points). Certains joueurs n’ont pris aucun 3 points donc leur pourcentage est manquant.

Si nous essayons la fonction mean dans R, nous obtenons NA comme réponse, sauf si nous spécifions na.rm = TRUE, qui ignore les valeurs NA pour le calcul de la moyenne. La méthode .mean() en Python ignore déjà ces valeurs par défaut. 

Python vs R : Diagrammes de corrélation

Un moyen courant d’explorer un ensemble de données consiste à voir comment les différentes colonnes sont corrélées entre elles. Ici nous allons comparer les colonnes ast, fg et trb.

Python :

import seaborn as sns
import matplotlib.pyplot as plt

sns.pairplot(nba[["ast", "fg", "trb"]])
plt.show()

R :

library(GGally)

ggpairs(nba[,c("ast", "fg", "trb")])

Résultat: nous obtenons des tracés très similaires. Cela montre aussi que l’écosystème R en Data Science a beaucoup de petites librairies (GGally est une librairie d’aide pour ggplot2 qui est la librairie la plus utilisée sur R) et beaucoup plus de librairies de visualisation en général.
En python, Matplotlib est la principale librairie pour tracer des courbes et Seaborn est une couche très utilisée sur Matplotlib. Avec la visualisation en Python, il y a généralement une seule façon de faire, alors que pour R, il y a de nombreuses méthodes rendues possible grâce aux nombreuses librairies différentes.

Python vs R : Regrouper les joueurs en clusters

Un bon moyen d’explorer ce type de données est de générer des graphiques regroupant les données (on appelle ça des clusters). Ceux-ci montreront quels joueurs ont le plus de similarités.

Python :

from sklearn.cluster import KMeans

kmeans_model = KMeans(n_clusters=5, random_state=1)
good_columns = nba._get_numeric_data().dropna(axis=1)

kmeans_model.fit(good_columns)
labels = kmeans_model.labels_

R :

library(cluster)
set.seed(1)

isGoodCol <- function(col){
    sum(is.na(col)) == 0 && is.numeric(col)
}

goodCols <- sapply(nba, isGoodCol)
clusters <- kmeans(nba[,goodCols], centers=5)
labels <- clusters$cluster

Pour regrouper correctement, nous supprimons toutes les colonnes non numériques. C’est à dire les colonnes avec des valeurs manquantes (NA, NaN, etc.).

En R, nous faisons cela en appliquant une fonction à travers chaque colonne et en la supprimant si elle a des valeurs manquantes ou n’est pas numérique. Nous utilisons ensuite le package cluster pour effectuer k-means et trouver 5 clusters dans nos données. Nous avons défini un seed aléatoire en utilisant set.seed pour pouvoir reproduire les mêmes résultats de votre côté.

En Python, nous utilisons le principal module de Machine Learning, Scikit-learn, pour adapter un modèle de regroupement k-means (clustering k-means) et obtenir nos labels de clusters. Nous effectuons des méthodes très similaires pour préparer les données que nous avons utilisées en R, sauf que nous utilisons les méthodes get_numeric_data et dropna pour supprimer les colonnes non-numériques et les colonnes avec des valeurs manquantes.

Python vs R : Tracer les joueurs par cluster

Nous pouvons maintenant identifier les joueurs par groupe pour découvrir des tendances. Une façon d’y parvenir est d’utiliser d’abord la méthode PCA (Principal Analysis Component) pour rendre nos données bi-dimensionnelles, puis de les tracer et de donner à chaque point une icône en fonction de son groupe (ou cluster).

Python :

from sklearn.decomposition import PCA

pca_2 = PCA(2)
plot_columns = pca_2.fit_transform(good_columns)
plt.scatter(x=plot_columns[:,0], y=plot_columns[:,1], c=labels)
plt.show()

R :

nba2d <- prcomp(nba[,goodCols], center=TRUE)
twoColumns <- nba2d$x[,1:2]
clusplot(twoColumns, labels)

Nous avons donc fait un nuage de points de nos données et adapté l’icône du point (ou la couleur) selon le cluster. R, la fonction clusplot a été utilisée, qui fait partie de la librairie spécialisée pour les clusters. Nous avons effectué le PCA via la fonction pccomp intégrée à R.

Avec Python, nous avons utilisé la classe PCA dans la librairie Scikit-learn. Enfin nous avons utilisé Matplotlib pour créer le graphique.

Python vs R : Partager notre dataset en 2 (Entrainement et Test)

Si nous voulons faire du Machine Learning supervisé, c’est une bonne idée de diviser les données en 2 ensembles: un ensemble d’entraînement et un autre de test.

Python :

train = nba.sample(frac=0.8, random_state=1)
test = nba.loc[~nba.index.isin(train.index)]

R :

trainRowCount <- floor(0.8 * nrow(nba))
set.seed(1)

trainIndex <- sample(1:nrow(nba), trainRowCount)

train <- nba[trainIndex,]
test <- nba[-trainIndex,]

Vous remarquerez que R a beaucoup plus de fonctions ‘built-in’ axés sur l’analyse de données, comme floor, sample et set.seed. Alors que ces mêmes fonctions sont appelés via des librairies en Python (math.floor, random.sample, random.seed).
En Python, la dernière version de Pandas est livrée avec une méthode d’échantillonnage qui retourne un certain nombre de lignes échantillonnées aléatoirement à partir d’une base de données source – ce qui rend le code beaucoup plus concis.
Avec R, il existe des packages pour simplifier l’échantillonnage, mais ils ne sont pas beaucoup plus concis que l’utilisation de la fonction sample intégrée. Dans les deux cas, j’ai défini un seed aléatoire pour rendre les résultats reproductibles chez vous.

Python vs R : Régression linéaire

Disons que nous voulons prédire le nombre de passes décisives (assist) par joueur à partir des lancers francs et paniers à 2 points (field goal) par joueur.

Python :

from sklearn.linear_model import LinearRegression

lr = LinearRegression()
lr.fit(train[["fg"]], train["ast"])
predictions = lr.predict(test[["fg"]])

R :

fit <- lm(ast ~ fg, data=train)
predictions <- predict(fit, test)

Scikit-learn a un modèle de régression linéaire que nous pouvons adapter pour générer des prédictions.
R s’appuie sur les fonctions intégrées de lm et predict. predict se comportera différemment selon le type de modèle qui lui est transmis – il peut être utilisé avec une variété de modèles.

Python vs R : Calculer des statistiques récapitulatives pour le modèle retenu

Python :

import statsmodels.formula.api as sm

model = sm.ols(formula='ast ~ fga', data=train)
fitted = model.fit()
fitted.summary()

R :

summary(fit)

Si nous voulons obtenir des statistiques récapitulatives sur le modèle, comme la valeur du coefficient de détermination (r-squared), nous aurons besoin de faire un peu plus en Python qu’en R.
Avec R, nous pouvons utiliser la fonction ‘built-in’ summary pour obtenir des informations sur le modèle.
Avec Python, nous devons utiliser le package statsmodels, qui permet d’utiliser de nombreuses méthodes statistiques en Python. Nous obtenons des résultats similaires, bien qu’il soit généralement un peu plus difficile de faire une analyse statistique en Python, et certaines méthodes statistiques qui existent dans R n’existent pas en Python.

Python vs R : Ajuster un modèle de forêt aléatoire (ou forêt d’arbre décisionnel – random forest)

Notre régression linéaire a bien fonctionné dans le cas de la variable unique. Mais nous soupçonnons qu’il peut y avoir des non-linéarités dans les données. Ainsi, nous voulons adapter un modèle de forêt aléatoire (Random Forest.

Python :

from sklearn.ensemble import RandomForestRegressor

predictor_columns = ["age", "mp", "fg", "trb", "stl", "blk"]
rf = RandomForestRegressor(n_estimators=100, min_samples_leaf=3)
rf.fit(train[predictor_columns], train["ast"])
predictions = rf.predict(test[predictor_columns])

R :

library(randomForest)

predictorColumns <- c("age", "mp", "fg", "trb", "stl", "blk")
rf <- randomForest(train[predictorColumns], train$ast, ntree=100)
predictions <- predict(rf, test[predictorColumns])

La principale différence ici est que nous avons besoin d’utiliser la librairie randomForest dans R pour utiliser l’algorithme alors qu’elle est intégrée à Scikit-learn en Python. Scikit-learn dispose d’une interface unifiée pour travailler avec de nombreux algorithmes de Machine Learning en Python et il n’y a généralement qu’une seule implémentation principale pour chaque algorithme en Python.
Avec R, il existe de nombreux petits packages contenant des algorithmes individuels, souvent avec des moyens peu cohérents pour y accéder. Cela se traduit par une plus grande diversité d’algorithmes mais ils sont légèrement plus compliqués à utiliser.

Python vs R : Calculer l’erreur

Maintenant que nous avons ajusté deux modèles, calculons l’erreur moyenne. Nous allons utiliser la méthode MSE (Mean Square Error).

Python :

from sklearn.metrics import mean_squared_error

mean_squared_error(test["ast"], predictions)
4166.9202475632374

R :

mean((test["ast"] - predictions)^2)
4573.86778567462

En Python, la bibliothèque scikit-learn dispose de diverses mesures d’erreur que nous pouvons utiliser.
En R, il y a probablement quelques bibliothèques plus petites qui calculent le MSE, mais le faire manuellement est assez facile dans les deux langages. Il y a une petite différence dans les erreurs qui est presque certainement due au réglage des paramètres – rien de bien méchant.

Python vs R : Télécharger une page Web (Web Scraping)

Maintenant que nous avons des données sur les joueurs de la NBA entre 2013 et 2014, nous allons ajouter quelques données supplémentaires pour le compléter. Nous allons juste regarder le score de la finale de NBA 2015 (Cleveland – Golden States).

Python :

import requests

url = "https://www.basketball-reference.com/boxscores/201506140GSW.html"
data = requests.get(url).content

R :

library(RCurl)

url <- "https://www.basketball-reference.com/boxscores/201506140GSW.html"
data <- readLines(url)

En Python, la librairie requests facilite le téléchargement de pages Web, avec une API cohérente pour tous les types de requêtes.
Avec R, RCurl fournit un outil similaire aussi simple. Les deux téléchargent la page Web dans un type de données string.

Python vs R : Extraire les scores des joueurs

Maintenant que nous avons la page Web, nous devrons l’analyser pour extraire les scores des joueurs.

Python :

from bs4 import BeautifulSoup
import re

soup = BeautifulSoup(data, 'html.parser')
box_scores = []
for tag in soup.find_all(id=re.compile("[A-Z]{3,}_basic")):
   rows = []
   for i, row in enumerate(tag.find_all("tr")):
       if i == 0:
       continue
   elif i == 1:
       tag = "th"
   else:
       tag = "td"
   row_data = [item.get_text() for item in row.find_all(tag)]
   rows.append(row_data)
   box_scores.append(rows)

R :

library(rvest)

age <- read_html(url)
table <- html_nodes(page, ".stats_table")[3]
rows <- html_nodes(table, "tr")
cells <- html_nodes(rows, "td a")
teams <- html_text(cells)

extractRow <- function(rows, i){
    if(i == 1){
       return
    }
    row <- rows[i]
    tag <- "td"
    if(i == 2){
    tag <- "th"
 }
    items <- html_nodes(row, tag)
    html_text(items)
}
scrapeData <- function(team){
    teamData <- html_nodes(page, paste("#",team,"_basic", sep=""))
    rows <- html_nodes(teamData, "tr")
    lapply(seq_along(rows), extractRow, rows=rows)
}

data <- lapply(teams, scrapeData)

Cela va créer une liste contenant deux listes: la première avec le score pour CLE (équipe de Clerverland) et la seconde avec le score pour GSW (Golden State Warriors). Les deux contiennent les en-têtes, ainsi que pour chaque joueur ses statistiques dans le jeu. Nous ne transformerons pas ces données en données d’entrainement (training). Il serait facile de les transformer pour les ajouter à notre variable nba.

Le code en R est plus complexe que le code en Python car il n’existe pas de moyen pratique d’utiliser des expressions régulières pour sélectionner des éléments. Nous devons donc effectuer une analyse supplémentaire pour obtenir les noms d’équipe à partir du code HTML. R déconseille également d’utiliser des boucles for en faveur de l’application de fonctions avec des vecteurs. Nous utilisons la méthode lapply pour le faire, mais comme nous devons traiter chaque ligne différemment selon qu’il s’agit d’un en-tête ou non, nous transmettons l’index de l’élément que nous voulons et la liste des lignes entières dans la fonction.

Nous utilisons rvest – un nouveau package de Web Scraping en R très utilisé pour extraire les données dont nous avons besoin. Notez que nous pouvons passer une url directement dans rvest, donc la dernière étape n’était pas nécessaire en R.

En Python, nous utilisons BeautifulSoup, la librairie de Web Scraping la plus utilisée. Cela nous permet de parcourir les tags du code HTML et de construire une liste de listes de manière simple.

Python vs R : le verdict

Nous avons examiné comment analyser un ensemble de données avec R et Python. Il y a de nombreuses tâches que nous n’avons pas approfondies, telles que la fiabilité des résultats de notre analyse, le partage de ces résultats (avec d’autres), le test et la préparation de la production et la création d’un plus grand nombre de visualisations. Nous le ferons plus tard, ce qui nous permettra de tirer des conclusions plus définitives.

Pour l’instant, voici ce que nous pouvons dire :

R est plus fonctionnel, Python est plus orienté objet.

Comme nous l’avons vu à partir de fonctions telles que lm, predict et d’autres, R permet de faire la plupart du travail. Cela contraste avec la classe LinearRegression de Python et à la méthode sample sur les DataFrames.

R a plus de fonction ‘built-in’ pour analyser des données, Python s’appuie sur des librairies.

En ce qui concerne les statistiques, nous pouvons utiliser la fonction ‘built-in’ summary de R. Mais nous devions importer la librairie statsmodels en Python. 
De même la structure de DataFrame (tableau) est intégrée dans R alors qu’elle doit être importée via la librairie Pandas en Python.

Python a des packages « principaux » pour les tâches d’analyse de données, R a un plus grand écosystème de petits packages.

Avec Python, nous pouvons faire une régression linéaire, des forêts aléatoires, et plus encore avec la librairie Scikit-learn. Il offre une API stable et maintenue à jour. En R, nous avons une plus grande diversité de packages, mais aussi une plus grande fragmentation et moins de cohérence (la régression linéaire est une fonction ‘built-in’: lm, et randomForest est un package séparé, etc…).

R est meilleur pour les statistiques de façon générale.

R a été construit comme un langage statistique et cela se voit. statsmodels dans Python et d’autres librairies offrent une couverture satisfaisante pour les méthodes statistiques, mais l’écosystème R est beaucoup plus large.

Il est généralement plus simple de faire des tâches non statistiques en Python.

Avec des bibliothèques bien maintenues à jour comme BeautifulSoup et requests, le web scraping en Python est beaucoup plus facile qu’en R. Ceci s’applique aux autres tâches que nous n’avons pas examinées de près, comme sauvegarder des données dans des bases de données, déployer des serveurs web ou exécuter des workflows complexes.

Il existe de tout de même de nombreux parallèles dans le workflow d’analyse de données des 2 langages.

Il y a des points d’inspiration clairs entre R et Python (les données pandas ont été inspirées par les données R, le package rvest a été inspiré par BeautifulSoup). De plus les deux écosystèmes continuent de se renforcer. Il est remarquable de constater à quel point la syntaxe et les approches sont similaires pour de nombreuses tâches courantes dans les deux langages.

Même si je pense que Python s’en sort mieux dans un plus grand nombre de domaines, R est un langage efficace. Il peut être utilisé soit comme complément de Python dans des domaines tels que l’exploration de données et dans les statistiques, soit même comme votre seul outil d’analyse de données.
Comme le montre la démarche de comparaison que l’on vient de faire dans cette article, les deux langages ont beaucoup de similitudes dans la syntaxe et l’approche. Gardez en tête que vous ne pouvez pas vous tromper en apprenant l’un ou l’autre (ou les deux).

Publications similaires

1 Commentaire
Le plus récent
Le plus ancien Le plus populaire
Commentaires en ligne
Afficher tous les commentaires