J'ai un bloc de données, comme ceci:
data.frame(director = c("Aaron Blaise,Bob Walker", "Akira Kurosawa",
"Alan J. Pakula", "Alan Parker", "Alejandro Amenabar", "Alejandro Gonzalez Inarritu",
"Alejandro Gonzalez Inarritu,Benicio Del Toro", "Alejandro González Iñárritu",
"Alex Proyas", "Alexander Hall", "Alfonso Cuaron", "Alfred Hitchcock",
"Anatole Litvak", "Andrew Adamson,Marilyn Fox", "Andrew Dominik",
"Andrew Stanton", "Andrew Stanton,Lee Unkrich", "Angelina Jolie,John Stevenson",
"Anne Fontaine", "Anthony Harvey"), AB = c('A', 'B', 'A', 'A', 'B', 'B', 'B', 'A', 'B', 'A', 'B', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'A'))
Comme vous pouvez le voir, certaines entrées de la director
colonne sont des noms multiples séparés par des virgules. Je voudrais diviser ces entrées en lignes séparées tout en conservant les valeurs de l'autre colonne. Par exemple, la première ligne du bloc de données ci-dessus doit être divisée en deux lignes, avec un seul nom chacune dans la director
colonne et «A» dans la AB
colonne.
Réponses:
Cette vieille question est fréquemment utilisée comme cible de dupe (taguée avec
r-faq
). À ce jour, il a été répondu trois fois en proposant 6 approches différentes, mais il manque un point de référence pour déterminer laquelle des approches est la plus rapide 1 .Les solutions de référence comprennent
data.table
méthodes et deuxdplyr
/tidyr
approches de Jaap ,splitstackshape
solution d'Ananda ,data.table
méthodes de Jaap .Dans l'ensemble, 8 méthodes différentes ont été comparées sur 6 tailles différentes de trames de données à l'aide du
microbenchmark
package (voir le code ci-dessous).Les exemples de données fournis par l'OP ne comportent que 20 lignes. Pour créer des blocs de données plus volumineux, ces 20 lignes sont simplement répétées 1, 10, 100, 1000, 10000 et 100000 fois, ce qui donne des tailles de problème allant jusqu'à 2 millions de lignes.
Résultats de référence
Les résultats de référence montrent que pour des bases de données suffisamment grandes, toutes les
data.table
méthodes sont plus rapides que toute autre méthode. Pour les trames de données de plus de 5000 lignes environ, ladata.table
méthode 2 de Jaap et la varianteDT3
sont les plus rapides et les magnitudes plus rapides que les méthodes les plus lentes.Remarquablement, les horaires des deux
tidyverse
méthodes et lasplistackshape
solution sont si similaires qu'il est difficile de distinguer les courbes dans le graphique. Il s'agit de la plus lente des méthodes de référence pour toutes les tailles de trame de données.Pour les trames de données plus petites, la solution de base R et la
data.table
méthode 4 de Matt semblent avoir moins de frais généraux que les autres méthodes.Code
Définir la fonction pour les exécutions de référence de taille de problème
n
Exécutez un benchmark pour différentes tailles de problème
Préparer les données pour le traçage
Créer un graphique
Informations sur la session et versions du package (extrait)
1 Ma curiosité a été piquée par ce commentaire exubérant Brillant! Des ordres de grandeur plus rapides! à une
tidyverse
réponse à une question qui a été fermée comme un double de cette question.la source
data.table
,dplyr
etc.strsplit
fixed=TRUE
. Comme les autres l'ont et cela aura un impact sur les horaires. Depuis R 4.0.0 , la valeur par défaut, lors de la création d'undata.frame
, eststringsAsFactors = FALSE
, doncas.character
pourrait être supprimé.Plusieurs alternatives:
1) deux façons avec data.table:
2) un déplyr / tidyr combinaison:
3) avec tidyruniquement: Avec
tidyr 0.5.0
(et versions ultérieures), vous pouvez également simplement utiliserseparate_rows
:Vous pouvez utiliser le
convert = TRUE
paramètre pour convertir automatiquement des nombres en colonnes numériques.4) avec base R:
la source
data.table(id= "X21", a = "chr1;chr1;chr1", b="123;133;134",c="234;254;268")
devenirdata.table(id = c("X21","X21",X21"), a=c("chr1","chr1","chr1"), b=c("123","133","134"), c=c("234","254","268"))
?setDT(dt)[,lapply(.SD, function(x) unlist(tstrsplit(x, ";",fixed=TRUE))), by = ID]
est ce qui a fonctionné pour moi.En nommant votre data.frame d'origine
v
, nous avons ceci:Notez l'utilisation de
rep
pour créer la nouvelle colonne AB. Ici,sapply
renvoie le nombre de noms dans chacune des lignes d'origine.la source
vapply
? Y a-t-il quelque chose qui rendvapply
plus approprié ici?sapply(s, length)
pourrait être remplacé parlengths(s)
.En retard à la fête, mais une autre alternative généralisée est d'utiliser à
cSplit
partir de mon package "splitstackshape" qui a undirection
argument. Définissez ceci sur"long"
pour obtenir le résultat que vous spécifiez:la source
la source
Un autre Benchmark résultant de l'utilisation
strsplit
de base pourrait actuellement être recommandé pour diviser une chaîne séparée par des virgules dans une colonne en lignes séparées , car c'était le plus rapide sur une large gamme de tailles:Notez que l'utilisation
fixed=TRUE
a un impact significatif sur les horaires.Méthodes comparées:
Bibliothèques:
Les données:
Résultats de calcul et de chronométrage:
Remarque, des méthodes comme
retourner un
strsplit
pourunique
directeur et pourrait être comparable àmais à ma connaissance, cela n'a pas été demandé.
la source