R data.table symboles et opérateurs à connaître

Le code R data.table devient plus efficace - et élégant - lorsque vous tirez parti de ses symboles et fonctions spéciaux. Dans cet esprit, nous examinerons quelques moyens spéciaux de sous-ensemble, de compter et de créer de nouvelles colonnes.

Pour cette démo, je vais utiliser les données de l'enquête 2019 Stack Overflow développeurs, avec environ 90000 réponses. Si vous souhaitez suivre, vous pouvez télécharger les données à partir de Stack Overflow.

Si le package data.table n'est pas installé sur votre système, installez-le à partir de CRAN, puis chargez-le comme d'habitude avec library(data.table). Pour commencer, vous souhaiterez peut-être lire uniquement les premières lignes de l'ensemble de données pour faciliter l'examen de la structure des données. Vous pouvez le faire avec la fread()fonction de data.table et l' nrowsargument. Je vais lire en 10 lignes:

data_sample <- fread ("data / survey_results_public.csv", nrows = 10)

Comme vous le verrez, il y a 85 colonnes à examiner. (Si vous voulez savoir ce que signifient toutes les colonnes, il y a des fichiers dans le téléchargement avec le schéma de données et un PDF de l'enquête d'origine.) 

Pour lire toutes les données, j'utiliserai:

mydt <- fread ("data / survey_results_public.csv")

Ensuite, je vais créer une nouvelle table data.table avec seulement quelques colonnes pour faciliter le travail et voir les résultats. Un rappel que data.table utilise cette syntaxe de base: 

mydt [i, j, par]

L'introduction du package data.table dit de lire ceci comme "prendre dt, sous-ensemble ou réorganiser les lignes en utilisant i, calculer j, groupé par". Gardez à l'esprit que i et j sont similaires à l'ordre des crochets de base R: les lignes en premier, les colonnes en second. Donc i est pour les opérations que vous feriez sur les lignes (en choisissant les lignes en fonction des numéros de ligne ou des conditions); j est ce que vous feriez avec des colonnes (sélectionnez des colonnes ou créez de nouvelles colonnes à partir de calculs). Cependant, notez également que vous pouvez faire beaucoup plus à l'intérieur des parenthèses data.table qu'une trame de données de base R. Et la section «par» est nouvelle pour data.table.

Puisque je sélectionne des colonnes, ce code va dans le "j", ce qui signifie que les crochets ont d'abord besoin d'une virgule pour laisser le "i" vide:

mydt [, j]

Sélectionnez les colonnes data.table

Une des choses que j'aime à propos de data.table est qu'il est facile de sélectionner des colonnes avec ou sans guillemets . Non cotés est souvent plus pratique (qui est généralement le moyen de tidyverse). Mais les guillemets sont utiles si vous utilisez data.table dans vos propres fonctions, ou si vous voulez passer un vecteur que vous avez créé ailleurs dans votre code.

Vous pouvez sélectionner des colonnes data.table de la manière typique de base R, avec un vecteur conventionnel de noms de colonnes entre guillemets. Par exemple: 

dt1 <- mydt [, c ("LanguageWorkedWith", "LanguageDesireNextYear",

"OpenSourcer", "CurrencySymbol", "ConvertedComp",

«Hobbyiste»)]

Si vous voulez les utiliser sans guillemets, créez une liste au lieu d'un vecteur et vous pouvez passer les noms sans guillemets. 

dt1 <- mydt [, list (LanguageWorkedWith, LanguageDesireNextYear,

OpenSourcer, CurrencySymbol, ConvertedComp,

Amateur)]

Et maintenant nous arrivons à notre premier symbole spécial. Au lieu de taper list(), vous pouvez simplement utiliser un point:

dt1 <- mydt [,. (LanguageWorkedWith, LanguageDesireNextYear,

OpenSourcer, CurrencySymbol, ConvertedComp,

Amateur)]

C'est .()un raccourci pour les list()crochets de données internes.

Que faire si vous souhaitez utiliser un vecteur de noms de colonnes déjà existant? Mettre le nom de l'objet vectoriel dans les crochets data.table ne fonctionnera pas. Si je crée un vecteur avec des noms de colonnes entre guillemets, comme ceci: 

mycols <- c ("LanguageWorkedWith", "LanguageDesireNextYear",

"OpenSourcer", "CurrencySymbol", "ConvertedComp", "Hobbyist")

Ensuite, ce code  ne fonctionnera pas

dt1 <- mydt [, mycols]

Au lieu de cela, vous devez mettre .. (c'est deux points) devant le nom de l'objet vectoriel:

dt1 <- mydt [, ..mycols]

Pourquoi deux points? Cela me semblait un peu aléatoire jusqu'à ce que je lis l'explication. Pensez-y comme les deux points dans un terminal de ligne de commande Unix qui vous font remonter d'un répertoire. Ici, vous vous déplacez vers le haut d'un espace de noms , de l'environnement à l'intérieur des crochets data.table jusqu'à l'environnement global. (Cela m'aide vraiment à m'en souvenir!)

Compter les lignes data.table

Passons au symbole suivant. Pour compter par groupe, vous pouvez utiliser le .Nsymbole de data.table , où  .Nsignifie «nombre de lignes». Il peut s'agir du nombre total de lignes ou du nombre de lignes par groupe si vous effectuez une agrégation dans la section «par». 

Cette expression renvoie le nombre total de lignes dans la table data.table: 

mydt [, .N]

L'exemple suivant calcule le nombre de lignes regroupées par une variable: si les personnes de l'enquête codent également comme un passe-temps (la Hobbyistvariable).

mydt [, .N, amateur]

# Retour:

Amateur N 1: Oui 71257 2: Non 17626

Vous pouvez utiliser le nom de colonne simple dans les crochets data.table s'il n'y a qu'une seule variable. Si vous souhaitez regrouper par deux ou plusieurs variables, utilisez le .symbole. Par exemple:

mydt [, .N,. (Amateur, OpenSourcer)]

Pour classer les résultats du plus haut au plus bas, vous pouvez ajouter un deuxième jeu de parenthèses après le premier. Le .Nsymbole génère automatiquement une colonne nommée N (bien sûr, vous pouvez la renommer si vous le souhaitez), donc le tri par nombre de lignes peut ressembler à ceci:

mydt [, .N,. (Hobbyist, OpenSourcer)] [order (Hobbyist, -N)]

Au fur et à mesure que j'apprends le code data.table, je trouve utile de le lire étape par étape. Donc, je lisais ceci comme "Pour toutes les lignes de mydt (puisqu'il n'y a rien dans la case" I "), comptez le nombre de lignes, regroupées par Hobbyist et OpenSourcer. Ensuite, commandez d'abord par amateur, puis le nombre de lignes décroissant. " 

C'est équivalent à ce code dplyr:

mydf%>%

count (amateur, OpenSourcer)%>%

ordre (amateur, -n)

Si vous trouvez l'approche multiligne conventionnelle tidyverse plus lisible, ce code data.table fonctionne également:

mydt [, .N,

. (Amateur, OpenSourcer)] [

ordre (amateur, -N)

]

Ajouter des colonnes à un data.table

Ensuite, j'aimerais ajouter des colonnes pour voir si chaque répondant utilise R, s'il utilise Python, s'il utilise les deux ou s'il n'utilise ni l'un ni l'autre. La LanguageWorkedWithcolonne contient des informations sur les langues utilisées, et quelques lignes de ces données ressemblent à ceci:

Sharon Machlis

Chaque réponse est une chaîne de caractères unique. La plupart ont plusieurs langues séparées par un point-virgule.

Comme c'est souvent le cas, il est plus facile de rechercher Python que R, puisque vous ne pouvez pas simplement rechercher "R" dans la chaîne (Ruby et Rust contiennent également un R majuscule) comme vous pouvez rechercher "Python". C'est le code le plus simple pour créer un vecteur TRUE / FALSE qui vérifie si chaque chaîne LanguageWorkedWithcontient Python:

ifelse (LanguageWorkedWith% comme% "Python", TRUE, FALSE)

Si vous connaissez SQL, vous reconnaîtrez cette syntaxe «comme». Je, eh bien, comme %like%. c'est une belle façon simplifiée de vérifier la correspondance des motifs. La documentation de la fonction indique qu'elle est destinée à être utilisée à l'intérieur des crochets data.table, mais en fait, vous pouvez l'utiliser dans n'importe quel code, pas seulement avec data.tables. J'ai vérifié avec le créateur de data.table, Matt Dowle, qui a déclaré que le conseil de l'utiliser entre crochets était dû au fait qu'une optimisation supplémentaire des performances se produisait là-bas.

Ensuite, voici le code pour ajouter une colonne appelée PythonUser au data.table:

dt1 [, PythonUser: = ifelse (LanguageWorkedWith% like% "Python", TRUE, FALSE)]

Remarquez l' :=opérateur. Python a aussi un opérateur comme celui-là, et depuis que je l'ai entendu appelé «opérateur morse», c'est comme ça que je l'appelle. Je pense que c'est officiellement une «affectation par référence». C'est parce que le code ci-dessus a changé l'objet existant dt1 data.table en ajoutant la nouvelle colonne - sans avoir besoin de l'enregistrer dans une nouvelle variable .

Pour rechercher R, j'utiliserai l'expression régulière "\\bR\\b"qui dit: «Trouvez un modèle qui commence par une limite de mot - le \\b, puis un R, puis se termine par une autre limite de mot. (Je ne peux pas simplement rechercher "R;" car le dernier élément de chaque chaîne n'a pas de point-virgule.) 

Cela ajoute une colonne RUser à dt1:

dt1 [, RUser: = ifelse (LanguageWorkedWith% like% "\\ bR \\ b", TRUE, FALSE)]

Si vous souhaitez ajouter les deux colonnes en même temps, :=vous devez transformer cet opérateur morse en une fonction en le faisant passer, comme ceci:

dt1 [, `: =` (

PythonUser = ifelse (LanguageWorkedWith% comme% "Python", TRUE, FALSE),

RUser = ifelse (LanguageWorkedWith% comme% "\\ bR \\ b", TRUE, FALSE)

)]

Opérateurs data.table plus utiles

Il existe plusieurs autres opérateurs data.table à connaître. L'  %between% opérateur a cette syntaxe:

myvector% entre% c (valeur_inférieure, valeur_haut)

Donc, si je veux filtrer toutes les réponses pour lesquelles la compensation était comprise entre 50000 et 100000 payées en dollars américains, ce code fonctionne:

comp_50_100k <- dt1 [CurrencySymbol == "USD" &

ConvertedComp% entre% c (50000, 100000)]

La deuxième ligne ci-dessus est la condition entre. Notez que l' %between%opérateur inclut à la fois les valeurs inférieure et supérieure lorsqu'il vérifie.

Un autre opérateur utile est %chin%. Il fonctionne comme les R de base %in%mais est optimisé pour la vitesse et est uniquement destiné aux vecteurs de caractères . Donc, si je veux filtrer toutes les lignes où la colonne OpenSourcer était "Jamais" ou "Moins d'une fois par an", ce code fonctionne:

rareos <- dt1 [OpenSourcer% chin% c ("Jamais", "Moins d'une fois par an")]

C'est assez similaire à la base R, sauf que la base R doit spécifier le nom du bloc de données à l'intérieur du crochet et nécessite également une virgule après l'expression de filtre:

rareos_df <- df1 [df1 $ OpenSourcer% in% c ("Jamais", "Moins d'une fois par an"),]

La nouvelle fonction fcase ()

Pour cette démo finale, je commencerai par créer une nouvelle table data.table avec uniquement les personnes ayant déclaré une compensation en dollars américains:

usd <- dt1 [CurrencySymbol == "USD" &! is.na (ConvertedComp)]

Ensuite, je vais créer une nouvelle colonne appelée Languagepour savoir si quelqu'un utilise uniquement R, juste Python, les deux ou aucun des deux. Et j'utiliserai la nouvelle fcase()fonction. Au moment de la publication de cet article, il fcase()n'était disponible que dans la version de développement de data.table. Si data.table est déjà installé, vous pouvez mettre à jour vers la dernière version de développement avec cette commande: 

data.table :: update.dev.pkg ()

La fonction fcase () est similaire à l'instruction de SQL CASE WHENet à la case_when()fonction de dplyr . La syntaxe de base est  fcase(condition1, "value1", condition2, "value2")et ainsi de suite. Une valeur par défaut pour «tout le reste» peut être ajoutée avec default = value.

Voici le code pour créer la nouvelle colonne Langue:

usd [, Langue: = fcase (

RUser &! PythonUser, "R",

PythonUser &! RUser, "Python",

PythonUser & RUser, "Both",

! PythonUser &! RUser, "Ni l'un ni l'autre"

)]

Je mets chaque condition sur une ligne distincte parce que je la trouve plus facile à lire, mais ce n'est pas nécessaire.

Attention: si vous utilisez RStudio, la structure data.table ne se met pas automatiquement à jour dans le volet supérieur droit de RStudio après avoir créé une nouvelle colonne avec l'opérateur morse. Vous devez cliquer manuellement sur l'icône d'actualisation pour voir les modifications du nombre de colonnes.

Il y a quelques autres symboles que je ne couvrirai pas dans cet article. Vous pouvez en trouver une liste dans le fichier d'aide data.table «symboles spéciaux» en exécutant help("special-symbols"). L'un des plus utiles, le .SD, a déjà son propre article et vidéo Do More With R, "Comment utiliser .SD dans le package R data.table".

Pour plus de conseils R, rendez-vous sur la page «Faites plus avec R» ou consultez la liste de lecture YouTube «Faites plus avec R».