Boostez vos données avec R

Publié: 2022-03-11

Le langage R est souvent perçu comme un langage pour les statisticiens et les data scientists. Il y a assez longtemps, c'était surtout vrai. Cependant, au fil des ans, la flexibilité offerte par R via les packages a fait de R un langage plus général. R était open source en 1995, et depuis lors, les référentiels de packages R ne cessent de croître. Pourtant, comparé à des langages comme Python, R est fortement basé sur les données.

En parlant de données, les données tabulaires méritent une attention particulière, car c'est l'un des types de données les plus couramment utilisés. C'est un type de données qui correspond à une structure de table connue dans les bases de données, où chaque colonne peut être d'un type différent, et les performances de traitement de ce type de données particulier sont le facteur crucial pour de nombreuses applications.

R peut être utilisé pour un stockage très efficace des données tabulaires

R peut être utilisé pour un stockage très efficace des données tabulaires
Tweeter

Dans cet article, nous allons présenter comment réaliser une transformation de données tabulaires de manière efficace. De nombreuses personnes qui utilisent déjà R pour l'apprentissage automatique ne savent pas que la gestion des données peut être effectuée plus rapidement dans R et qu'elles n'ont pas besoin d'utiliser un autre outil pour cela.

Solution haute performance en R

Base R a introduit la classe data.frame en 1997, qui était basée sur S-PLUS avant elle. Contrairement aux bases de données couramment utilisées qui stockent les données ligne par ligne, R data.frame stocke les données en mémoire sous la forme d'une structure orientée colonne, ce qui la rend plus efficace en termes de cache pour les opérations de colonne courantes dans les analyses. De plus, même si R est un langage de programmation fonctionnel, il ne l'impose pas au développeur. Les deux opportunités ont été bien traitées par le package R data.table , qui est disponible dans le référentiel CRAN. Il s'exécute assez rapidement lors du regroupement d'opérations et est particulièrement économe en mémoire en faisant attention à la matérialisation des sous-ensembles de données intermédiaires, comme la matérialisation uniquement des colonnes nécessaires à une certaine tâche. Il évite également les copies inutiles grâce à sa sémantique de référence lors de l'ajout ou de la mise à jour de colonnes. La première version du package a été publiée en avril 2006, améliorant considérablement les performances de data.frame à cette époque. La description initiale du package était :

Ce paquet fait très peu. La seule raison de son existence est que le livre blanc spécifie que data.frame doit avoir des noms de ligne. Ce package définit une nouvelle classe data.table qui fonctionne exactement comme un data.frame, mais utilise jusqu'à 10 fois moins de mémoire et peut être jusqu'à 10 fois plus rapide à créer (et à copier). Il en profite également pour autoriser subset() et with() comme des expressions à l'intérieur du []. La plupart du code est copié à partir des fonctions de base avec le code manipulant row.names supprimé.

Depuis lors, les implémentations de data.frame et data.table ont été améliorées, mais data.table reste incroyablement plus rapide que la base R. En fait, data.table n'est pas seulement plus rapide que la base R, mais il semble en être un. de l'outil de gestion de données open source le plus rapide disponible, en concurrence avec des outils tels que Python Pandas et des bases de données de stockage en colonnes ou des applications de données volumineuses telles que Spark. Ses performances sur une infrastructure partagée distribuée n'ont pas encore été évaluées, mais être capable d'avoir jusqu'à deux milliards de lignes sur une seule instance offre des perspectives prometteuses. Des performances exceptionnelles vont de pair avec les fonctionnalités. De plus, avec les efforts récents pour paralléliser les pièces chronophages pour des gains de performances supplémentaires, une direction pour repousser la limite de performances semble assez claire.

Exemples de transformation de données

Apprendre R devient un peu plus facile en raison du fait qu'il fonctionne de manière interactive, nous pouvons donc suivre les exemples étape par étape et regarder les résultats de chaque étape à tout moment. Avant de commencer, installons le package data.table à partir du référentiel CRAN.

 install.packages("data.table")

Conseil utile : nous pouvons ouvrir le manuel de n'importe quelle fonction en tapant simplement son nom avec un point d'interrogation en tête, c'est-à-dire ?install.packages .

Chargement de données dans R

Il existe des tonnes de packages pour extraire des données à partir d'un large éventail de formats et de bases de données, qui incluent souvent des pilotes natifs. Nous allons charger les données du fichier CSV , le format le plus courant pour les données tabulaires brutes. Le fichier utilisé dans les exemples suivants peut être trouvé ici. Nous n'avons pas à nous soucier des performances de lecture CSV car la fonction fread est hautement optimisée à cet égard.

Pour utiliser n'importe quelle fonction d'un package, nous devons la charger avec l'appel de la library .

 library(data.table) DT <- fread("flights14.csv") print(DT)
 ## year month day dep_delay arr_delay carrier origin dest air_time ## 1: 2014 1 1 14 13 AA JFK LAX 359 ## 2: 2014 1 1 -3 13 AA JFK LAX 363 ## 3: 2014 1 1 2 9 AA JFK LAX 351 ## 4: 2014 1 1 -8 -26 AA LGA PBI 157 ## 5: 2014 1 1 2 1 AA JFK LAX 350 ## --- ## 253312: 2014 10 31 1 -30 UA LGA IAH 201 ## 253313: 2014 10 31 -5 -14 UA EWR IAH 189 ## 253314: 2014 10 31 -8 16 MQ LGA RDU 83 ## 253315: 2014 10 31 -4 15 MQ LGA DTW 75 ## 253316: 2014 10 31 -5 1 MQ LGA SDF 110 ## distance hour ## 1: 2475 9 ## 2: 2475 11 ## 3: 2475 19 ## 4: 1035 7 ## 5: 2475 13 ## --- ## 253312: 1416 14 ## 253313: 1400 8 ## 253314: 431 11 ## 253315: 502 11 ## 253316: 659 8

Si nos données ne sont pas bien modélisées pour un traitement ultérieur, car elles doivent être remodelées du format long à large ou large à long (également connu sous le nom de pivot et unpivot ), nous pouvons examiner les ?dcast et ?melt , connu du paquet reshape2. Cependant, data.table implémente des méthodes plus rapides et économes en mémoire pour la classe data.table/data.frame.

Interrogation avec la syntaxe data.table

Si vous êtes familier avec data.frame

La requête data.table est très similaire à la requête data.frame . Lors du filtrage dans i argument, nous pouvons utiliser les noms de colonne directement sans avoir besoin d'y accéder avec le signe $ , comme df[df$col > 1, ] . Lors de la fourniture de l'argument suivant j , nous fournissons une expression à évaluer dans le cadre de notre data.table . Pour passer un argument non-expression j , utilisez with=FALSE . Le troisième argument, non présent dans la méthode data.frame , définit les groupes, faisant en sorte que l'expression en j soit évaluée par des groupes.

 # data.frame DF[DF$col1 > 1L, c("col2", "col3")] # data.table DT[col1 > 1L, .(col2, col3), ...] # by group using: `by = col4`

Si vous êtes familier avec les bases de données

La requête data.table correspond à bien des égards aux requêtes SQL que davantage de personnes connaissent peut-être. DT ci-dessous représente l'objet data.table et correspond à la clause SQLs FROM .

 DT[ i = where, j = select | update, by = group by] [ having, ... ] [ order by, ... ] [ ... ] ... [ ... ] 

Démêler les données tabulaires

Tri des lignes et réorganisation des colonnes

Le tri des données est une transformation cruciale pour les séries chronologiques, et c'est également important pour l'extraction et la présentation des données. Le tri peut être réalisé en fournissant le vecteur entier de l'ordre des lignes à i argument, de la même manière que data.frame . Le premier argument dans l' order(carrier, -dep_delay) sélectionnera les données dans l'ordre croissant sur le champ de carrier et dans l'ordre décroissant sur la mesure dep_delay . Le deuxième argument j , comme décrit dans la section précédente, définit les colonnes (ou expressions) à renvoyer et leur ordre.

 ans <- DT[order(carrier, -dep_delay), .(carrier, origin, dest, dep_delay)] head(ans)
 ## carrier origin dest dep_delay ## 1: AA EWR DFW 1498 ## 2: AA JFK BOS 1241 ## 3: AA EWR DFW 1071 ## 4: AA EWR DFW 1056 ## 5: AA EWR DFW 1022 ## 6: AA EWR DFW 989

Pour réorganiser les données par référence, au lieu d'interroger les données dans un ordre spécifique, nous utilisons les fonctions set* .

 setorder(DT, carrier, -dep_delay) leading.cols <- c("carrier","dep_delay") setcolorder(DT, c(leading.cols, setdiff(names(DT), leading.cols))) print(DT)
 ## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1241 2014 4 15 1223 JFK BOS 39 ## 3: AA 1071 2014 6 13 1064 EWR DFW 175 ## 4: AA 1056 2014 9 12 1115 EWR DFW 198 ## 5: AA 1022 2014 6 16 1073 EWR DFW 178 ## --- ## 253312: WN -12 2014 3 9 -21 LGA BNA 115 ## 253313: WN -13 2014 3 10 -18 EWR MDW 112 ## 253314: WN -13 2014 5 17 -30 LGA HOU 202 ## 253315: WN -13 2014 6 15 10 LGA MKE 101 ## 253316: WN -13 2014 8 19 -30 LGA CAK 63 ## distance hour ## 1: 1372 7 ## 2: 187 13 ## 3: 1372 10 ## 4: 1372 6 ## 5: 1372 7 ## --- ## 253312: 764 16 ## 253313: 711 20 ## 253314: 1428 17 ## 253315: 738 20 ## 253316: 397 16

Le plus souvent, nous n'avons pas besoin à la fois de l'ensemble de données d'origine et de l'ensemble de données ordonné/trié. Par défaut, le langage R, similaire aux autres langages de programmation fonctionnels, renverra les données triées en tant que nouvel objet, et nécessitera donc deux fois plus de mémoire que le tri par référence.

Requêtes de sous-ensemble

Créons un sous-ensemble de données pour l'origine du vol "JFK" et le mois de 6 à 9. Dans le deuxième argument, nous sous-ensembles les résultats dans les colonnes répertoriées, en ajoutant une variable calculée sum_delay .

 ans <- DT[origin == "JFK" & month %in% 6:9, .(origin, month, arr_delay, dep_delay, sum_delay = arr_delay + dep_delay)] head(ans)
 ## origin month arr_delay dep_delay sum_delay ## 1: JFK 7 925 926 1851 ## 2: JFK 8 727 772 1499 ## 3: JFK 6 466 451 917 ## 4: JFK 7 414 450 864 ## 5: JFK 6 411 442 853 ## 6: JFK 6 333 343 676

Par défaut, lors du sous-ensemble de données sur une seule colonne, data.table crée automatiquement un index pour cette colonne. Cela se traduit par des réponses en temps réel à tout autre appel de filtrage sur cette colonne.

Mettre à jour l'ensemble de données

L'ajout d'une nouvelle colonne par référence est effectué à l'aide de l'opérateur := , il affecte une variable dans l'ensemble de données en place. Cela évite la copie en mémoire de l'ensemble de données, nous n'avons donc pas besoin d'attribuer des résultats à chaque nouvelle variable.

 DT[, sum_delay := arr_delay + dep_delay] head(DT)
 ## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1241 2014 4 15 1223 JFK BOS 39 ## 3: AA 1071 2014 6 13 1064 EWR DFW 175 ## 4: AA 1056 2014 9 12 1115 EWR DFW 198 ## 5: AA 1022 2014 6 16 1073 EWR DFW 178 ## 6: AA 989 2014 6 11 991 EWR DFW 194 ## distance hour sum_delay ## 1: 1372 7 2992 ## 2: 187 13 2464 ## 3: 1372 10 2135 ## 4: 1372 6 2171 ## 5: 1372 7 2095 ## 6: 1372 11 1980

Pour ajouter plus de variables à la fois, nous pouvons utiliser la syntaxe DT[, := (sum_delay = arr_delay + dep_delay)] , similaire à .(sum_delay = arr_delay + dep_delay) lors de l'interrogation de l'ensemble de données.

Il est possible de sous-affecter par référence, en ne mettant à jour que des lignes particulières en place, simplement en combinant avec i argument.

 DT[origin=="JFK", distance := NA] head(DT)
 ## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1241 2014 4 15 1223 JFK BOS 39 ## 3: AA 1071 2014 6 13 1064 EWR DFW 175 ## 4: AA 1056 2014 9 12 1115 EWR DFW 198 ## 5: AA 1022 2014 6 16 1073 EWR DFW 178 ## 6: AA 989 2014 6 11 991 EWR DFW 194 ## distance hour sum_delay ## 1: 1372 7 2992 ## 2: NA 13 2464 ## 3: 1372 10 2135 ## 4: 1372 6 2171 ## 5: 1372 7 2095 ## 6: 1372 11 1980

Données agrégées

Pour agréger les données, nous fournissons le troisième argument by le crochet. Ensuite, dans j , nous devons fournir des appels de fonction d'agrégation, afin que les données puissent être réellement agrégées. Le symbole .N utilisé dans l'argument j correspond au nombre de toutes les observations dans chaque groupe. Comme mentionné précédemment, les agrégats peuvent être combinés avec des sous-ensembles sur des lignes et des colonnes de sélection.

 ans <- DT[, .(m_arr_delay = mean(arr_delay), m_dep_delay = mean(dep_delay), count = .N), .(carrier, month)] head(ans)
 ## carrier month m_arr_delay m_dep_delay count ## 1: AA 10 5.541959 7.591497 2705 ## 2: AA 4 1.903324 3.987008 2617 ## 3: AA 6 8.690067 11.476475 2678 ## 4: AA 9 -1.235160 3.307078 2628 ## 5: AA 8 4.027474 8.914054 2839 ## 6: AA 7 9.159886 11.665953 2802

Souvent, nous pouvons avoir besoin de comparer une valeur d'une ligne à son agrégat sur un groupe. En SQL, on applique des agrégats sur partition by : AVG(arr_delay) OVER (PARTITION BY carrier, month) .

 ans <- DT[, .(arr_delay, carrierm_mean_arr = mean(arr_delay), dep_delay, carrierm_mean_dep = mean(dep_delay)), .(carrier, month)] head(ans)
 ## carrier month arr_delay carrierm_mean_arr dep_delay carrierm_mean_dep ## 1: AA 10 1494 5.541959 1498 7.591497 ## 2: AA 10 840 5.541959 848 7.591497 ## 3: AA 10 317 5.541959 338 7.591497 ## 4: AA 10 292 5.541959 331 7.591497 ## 5: AA 10 322 5.541959 304 7.591497 ## 6: AA 10 306 5.541959 299 7.591497

Si nous ne voulons pas interroger les données avec ces agrégats, et les mettre à la place dans la mise à jour réelle de la table par référence, nous pouvons le faire avec l'opérateur := . Cela évite la copie en mémoire de l'ensemble de données, nous n'avons donc pas besoin d'affecter des résultats à la nouvelle variable.

 DT[, `:=`(carrierm_mean_arr = mean(arr_delay), carrierm_mean_dep = mean(dep_delay)), .(carrier, month)] head(DT)
 ## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1241 2014 4 15 1223 JFK BOS 39 ## 3: AA 1071 2014 6 13 1064 EWR DFW 175 ## 4: AA 1056 2014 9 12 1115 EWR DFW 198 ## 5: AA 1022 2014 6 16 1073 EWR DFW 178 ## 6: AA 989 2014 6 11 991 EWR DFW 194 ## distance hour sum_delay carrierm_mean_arr carrierm_mean_dep ## 1: 1372 7 2992 5.541959 7.591497 ## 2: NA 13 2464 1.903324 3.987008 ## 3: 1372 10 2135 8.690067 11.476475 ## 4: 1372 6 2171 -1.235160 3.307078 ## 5: 1372 7 2095 8.690067 11.476475 ## 6: 1372 11 1980 8.690067 11.476475

Joindre des ensembles de données

La jonction et la fusion d'ensembles de données en base R sont considérées comme un type spécial d'opération de sous- ensemble . Nous fournissons un ensemble de données auquel nous voulons nous joindre dans le premier argument entre crochets i . Pour chaque ligne de l'ensemble de données fourni à i , nous faisons correspondre les lignes de l'ensemble de données dans lequel nous utilisons [ . Si nous voulons conserver uniquement les lignes correspondantes ( jointure interne ), nous passons un argument supplémentaire nomatch = 0L . Nous utilisons on argument pour spécifier les colonnes sur lesquelles nous voulons joindre les deux ensembles de données.

 # create reference subset carrierdest <- DT[, .(count=.N), .(carrier, dest) # count by carrier and dest ][1:10 # just 10 first groups ] # chaining `[...][...]` as subqueries print(carrierdest)
 ## carrier dest count ## 1: AA DFW 5877 ## 2: AA BOS 1173 ## 3: AA ORD 4798 ## 4: AA SEA 298 ## 5: AA EGE 85 ## 6: AA LAX 3449 ## 7: AA MIA 6058 ## 8: AA SFO 1312 ## 9: AA AUS 297 ## 10: AA DCA 172
 # outer join ans <- carrierdest[DT, on = c("carrier","dest")] print(ans)
 ## carrier dest count dep_delay year month day arr_delay origin ## 1: AA DFW 5877 1498 2014 10 4 1494 EWR ## 2: AA BOS 1173 1241 2014 4 15 1223 JFK ## 3: AA DFW 5877 1071 2014 6 13 1064 EWR ## 4: AA DFW 5877 1056 2014 9 12 1115 EWR ## 5: AA DFW 5877 1022 2014 6 16 1073 EWR ## --- ## 253312: WN BNA NA -12 2014 3 9 -21 LGA ## 253313: WN MDW NA -13 2014 3 10 -18 EWR ## 253314: WN HOU NA -13 2014 5 17 -30 LGA ## 253315: WN MKE NA -13 2014 6 15 10 LGA ## 253316: WN CAK NA -13 2014 8 19 -30 LGA ## air_time distance hour sum_delay carrierm_mean_arr ## 1: 200 1372 7 2992 5.541959 ## 2: 39 NA 13 2464 1.903324 ## 3: 175 1372 10 2135 8.690067 ## 4: 198 1372 6 2171 -1.235160 ## 5: 178 1372 7 2095 8.690067 ## --- ## 253312: 115 764 16 -33 6.921642 ## 253313: 112 711 20 -31 6.921642 ## 253314: 202 1428 17 -43 22.875845 ## 253315: 101 738 20 -3 14.888889 ## 253316: 63 397 16 -43 7.219670 ## carrierm_mean_dep ## 1: 7.591497 ## 2: 3.987008 ## 3: 11.476475 ## 4: 3.307078 ## 5: 11.476475 ## --- ## 253312: 11.295709 ## 253313: 11.295709 ## 253314: 30.546453 ## 253315: 24.217560 ## 253316: 17.038047
 # inner join ans <- DT[carrierdest, # for each row in carrierdest nomatch = 0L, # return only matching rows from both tables on = c("carrier","dest")] # joining on columns carrier and dest print(ans)
 ## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1071 2014 6 13 1064 EWR DFW 175 ## 3: AA 1056 2014 9 12 1115 EWR DFW 198 ## 4: AA 1022 2014 6 16 1073 EWR DFW 178 ## 5: AA 989 2014 6 11 991 EWR DFW 194 ## --- ## 23515: AA -8 2014 10 11 -13 JFK DCA 53 ## 23516: AA -9 2014 5 21 -12 JFK DCA 52 ## 23517: AA -9 2014 6 5 -6 JFK DCA 53 ## 23518: AA -9 2014 10 2 -21 JFK DCA 51 ## 23519: AA -11 2014 5 27 10 JFK DCA 55 ## distance hour sum_delay carrierm_mean_arr carrierm_mean_dep count ## 1: 1372 7 2992 5.541959 7.591497 5877 ## 2: 1372 10 2135 8.690067 11.476475 5877 ## 3: 1372 6 2171 -1.235160 3.307078 5877 ## 4: 1372 7 2095 8.690067 11.476475 5877 ## 5: 1372 11 1980 8.690067 11.476475 5877 ## --- ## 23515: NA 15 -21 5.541959 7.591497 172 ## 23516: NA 15 -21 4.150172 8.733665 172 ## 23517: NA 15 -15 8.690067 11.476475 172 ## 23518: NA 15 -30 5.541959 7.591497 172 ## 23519: NA 15 -1 4.150172 8.733665 172

Sachez qu'en raison de la cohérence avec le sous-ensemble R de base, la jointure externe est par défaut RIGHT OUTER . Si nous recherchons LEFT OUTER , nous devons échanger les tables, comme dans l'exemple ci-dessus. Le comportement exact peut également être facilement contrôlé dans la méthode merge data.table , en utilisant la même API que la base R merge data.frame .

Si nous voulons simplement rechercher la ou les colonnes dans notre ensemble de données, nous pouvons le faire efficacement avec l'opérateur := dans l'argument j lors de la jointure. De la même manière que nous sous-attribuons par référence, comme décrit dans la section Mettre à jour le jeu de données , nous ajoutons maintenant une colonne par référence à partir du jeu de données auquel nous nous joignons. Cela évite la copie en mémoire des données, nous n'avons donc pas besoin d'affecter les résultats à de nouvelles variables.

 DT[carrierdest, # data.table to join with lkp.count := count, # lookup `count` column from `carrierdest` on = c("carrier","dest")] # join by columns head(DT)
 ## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1241 2014 4 15 1223 JFK BOS 39 ## 3: AA 1071 2014 6 13 1064 EWR DFW 175 ## 4: AA 1056 2014 9 12 1115 EWR DFW 198 ## 5: AA 1022 2014 6 16 1073 EWR DFW 178 ## 6: AA 989 2014 6 11 991 EWR DFW 194 ## distance hour sum_delay carrierm_mean_arr carrierm_mean_dep lkp.count ## 1: 1372 7 2992 5.541959 7.591497 5877 ## 2: NA 13 2464 1.903324 3.987008 1173 ## 3: 1372 10 2135 8.690067 11.476475 5877 ## 4: 1372 6 2171 -1.235160 3.307078 5877 ## 5: 1372 7 2095 8.690067 11.476475 5877 ## 6: 1372 11 1980 8.690067 11.476475 5877

Pour l'agrégat while join , utilisez by = .EACHI . Il effectue une jointure qui ne matérialise pas les résultats de jointure intermédiaires et applique des agrégats à la volée, ce qui le rend efficace en termes de mémoire.

La jointure roulante est une fonctionnalité peu courante, conçue pour traiter des données ordonnées. Il convient parfaitement au traitement des données temporelles et des séries chronologiques en général. Il roule essentiellement les correspondances dans la condition de jointure vers la prochaine valeur correspondante. Utilisez-le en fournissant l'argument roll lors de la jointure.

La jointure de chevauchement rapide joint des ensembles de données en fonction de périodes et de sa gestion du chevauchement à l'aide de divers opérateurs de chevauchement : any , within , start , end .

Une fonctionnalité de jointure non-équi pour joindre des ensembles de données en utilisant une condition non-égale est actuellement en cours de développement.

Données de profilage

Lors de l'exploration de notre jeu de données, nous pouvons parfois souhaiter collecter des informations techniques sur le sujet, afin de mieux appréhender la qualité des données.

Statistiques descriptives

 summary(DT)
 ## carrier dep_delay year month ## Length:253316 Min. :-112.00 Min. :2014 Min. : 1.000 ## Class :character 1st Qu.: -5.00 1st Qu.:2014 1st Qu.: 3.000 ## Mode :character Median : -1.00 Median :2014 Median : 6.000 ## Mean : 12.47 Mean :2014 Mean : 5.639 ## 3rd Qu.: 11.00 3rd Qu.:2014 3rd Qu.: 8.000 ## Max. :1498.00 Max. :2014 Max. :10.000 ## ## day arr_delay origin dest ## Min. : 1.00 Min. :-112.000 Length:253316 Length:253316 ## 1st Qu.: 8.00 1st Qu.: -15.000 Class :character Class :character ## Median :16.00 Median : -4.000 Mode :character Mode :character ## Mean :15.89 Mean : 8.147 ## 3rd Qu.:23.00 3rd Qu.: 15.000 ## Max. :31.00 Max. :1494.000 ## ## air_time distance hour sum_delay ## Min. : 20.0 Min. : 80.0 Min. : 0.00 Min. :-224.00 ## 1st Qu.: 86.0 1st Qu.: 529.0 1st Qu.: 9.00 1st Qu.: -19.00 ## Median :134.0 Median : 762.0 Median :13.00 Median : -5.00 ## Mean :156.7 Mean : 950.4 Mean :13.06 Mean : 20.61 ## 3rd Qu.:199.0 3rd Qu.:1096.0 3rd Qu.:17.00 3rd Qu.: 23.00 ## Max. :706.0 Max. :4963.0 Max. :24.00 Max. :2992.00 ## NA's :81483 ## carrierm_mean_arr carrierm_mean_dep lkp.count ## Min. :-22.403 Min. :-4.500 Min. : 85 ## 1st Qu.: 2.676 1st Qu.: 7.815 1st Qu.:3449 ## Median : 6.404 Median :11.354 Median :5877 ## Mean : 8.147 Mean :12.465 Mean :4654 ## 3rd Qu.: 11.554 3rd Qu.:17.564 3rd Qu.:6058 ## Max. : 86.182 Max. :52.864 Max. :6058 ## NA's :229797

Cardinalité

Nous pouvons vérifier l'unicité des données en utilisant la fonction uniqueN et l'appliquer sur chaque colonne. L'objet .SD dans la requête ci-dessous correspond au S ubset de la Data.table :

 DT[, lapply(.SD, uniqueN)]
 ## carrier dep_delay year month day arr_delay origin dest air_time ## 1: 14 570 1 10 31 616 3 109 509 ## distance hour sum_delay carrierm_mean_arr carrierm_mean_dep lkp.count ## 1: 152 25 1021 134 134 11

Rapport NA

Pour calculer le rapport des valeurs inconnues ( NA en R et NULL en SQL) pour chaque colonne, nous fournissons la fonction souhaitée à appliquer sur chaque colonne.

 DT[, lapply(.SD, function(x) sum(is.na(x))/.N)]
 ## carrier dep_delay year month day arr_delay origin dest air_time ## 1: 0 0 0 0 0 0 0 0 0 ## distance hour sum_delay carrierm_mean_arr carrierm_mean_dep lkp.count ## 1: 0.3216654 0 0 0 0 0.9071555

Exportation de données

L'exportation rapide des données tabulaires au format CSV est également fournie par le package data.table .

 tmp.csv <- tempfile(fileext=".csv") fwrite(DT, tmp.csv) # preview exported data cat(system(paste("head -3",tmp.csv), intern=TRUE), sep="\n")
 ## carrier,dep_delay,year,month,day,arr_delay,origin,dest,air_time,distance,hour,sum_delay,carrierm_mean_arr,carrierm_mean_dep,lkp.count ## AA,1498,2014,10,4,1494,EWR,DFW,200,1372,7,2992,5.54195933456561,7.59149722735674,5877 ## AA,1241,2014,4,15,1223,JFK,BOS,39,,13,2464,1.90332441727168,3.98700802445548,1173

Au moment d'écrire ces lignes, la fonction fwrite n'a pas encore été publiée dans le référentiel CRAN. Pour l'utiliser, nous devons installer la version de développement data.table , sinon nous pouvons utiliser la fonction base R write.csv , mais ne vous attendez pas à ce qu'elle soit rapide.

Ressources

De nombreuses ressources sont disponibles. Outre les manuels disponibles pour chaque fonction, il existe également des vignettes de package, qui sont des didacticiels axés sur le sujet particulier. Ceux-ci peuvent être trouvés sur la page Mise en route. De plus, la page Présentations répertorie plus de 30 documents (diapositives, vidéo, etc.) issus de présentations data.table du monde entier. De plus, le soutien de la communauté a augmenté au fil des ans, atteignant récemment la 4000ème question sur la balise Stack Overflow data.table , avec toujours un taux élevé (91,9%) de questions répondues. Le graphique ci-dessous présente le nombre de questions étiquetées data.table sur Stack Overflow au fil du temps.

SO questions mensuelles pour data.table - Seules les questions étiquetées data.table, pas celles avec des réponses data.table (acceptées)

SO questions mensuelles pour data.table - Seules les questions étiquetées data.table, pas celles avec des réponses data.table (acceptées)

Sommaire

Cet article fournit des exemples choisis pour une transformation efficace des données tabulaires dans R à l'aide du package data.table . Les chiffres réels sur la performance peuvent être examinés en recherchant des repères reproductibles. J'ai publié un article de blog résumé sur les solutions data.table pour les 50 questions StackOverflow les mieux notées pour le langage R appelé Résoudre efficacement les problèmes R courants avec data.table, où vous pouvez trouver beaucoup de chiffres et de code reproductible. Le package data.table utilise l'implémentation native de l'ordre de base rapide pour ses opérations de regroupement et la recherche binaire des sous-ensembles/jointures rapides. Cet ordre par base a été intégré dans la base R à partir de la version 3.3.0. De plus, l'algorithme a été récemment implémenté dans la plate-forme d'apprentissage automatique H2O et parallélisé sur le cluster H2O, permettant de grandes jointures efficaces sur des lignes 10B x 10B.

En relation : Manipulation ultime de la collecte de données en mémoire avec Supergroup.js