Tengo un marco de datos, así:
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'))
Como puede ver, algunas entradas en la director
columna son varios nombres separados por comas. Me gustaría dividir estas entradas en filas separadas mientras mantengo los valores de la otra columna. Como ejemplo, la primera fila en el marco de datos anterior debe dividirse en dos filas, con un solo nombre en la director
columna y una 'A' en la AB
columna.
Respuestas:
Esta vieja pregunta se utiliza con frecuencia como objetivo engañoso (etiquetado con
r-faq
). Hasta el día de hoy, se ha respondido tres veces ofreciendo 6 enfoques diferentes, pero carece de un punto de referencia como guía sobre cuál de los enfoques es el más rápido 1 .Las soluciones comparadas incluyen
data.table
métodos y dosdplyr
/tidyr
enfoques,splitstackshape
solución de Ananda ,data.table
métodos de Jaap .En general, se compararon 8 métodos diferentes en 6 tamaños diferentes de marcos de datos utilizando el
microbenchmark
paquete (consulte el código a continuación).Los datos de muestra proporcionados por el OP constan solo de 20 filas. Para crear marcos de datos más grandes, estas 20 filas simplemente se repiten 1, 10, 100, 1000, 10000 y 100000 veces, lo que genera problemas de hasta 2 millones de filas.
Resultados comparativos
Los resultados de la evaluación comparativa muestran que para marcos de datos suficientemente grandes, todos los
data.table
métodos son más rápidos que cualquier otro método. Para marcos de datos con más de aproximadamente 5000 filas, eldata.table
método 2 de Jaap y la varianteDT3
son los más rápidos, magnitudes más rápidas que los métodos más lentos.Sorprendentemente, los tiempos de los dos
tidyverse
métodos y lasplistackshape
solución son tan similares que es difícil distinguir las curvas en el gráfico. Son los métodos comparativos más lentos de todos los tamaños de marcos de datos.Para marcos de datos más pequeños, la solución R base de Matt y
data.table
método 4 parecen tener menos gastos generales que los otros métodos.Código
Definir función para ejecuciones de referencia de tamaño de problema
n
Ejecute un banco de pruebas para diferentes tamaños de problemas
Preparar datos para graficar
Crear gráfico
Información de la sesión y versiones del paquete (extracto)
1 Este comentario exuberante despertó mi curiosidad . ¡Brillante! Órdenes de magnitud más rápido! a una respuesta de una pregunta que se cerró como un duplicado de esta pregunta.
tidyverse
fuente
data.table
,dplyr
, etc.strsplit
fixed=TRUE
. Como el otro lo tiene y esto tendrá un impacto en los tiempos. Desde R 4.0.0 , el valor predeterminado, al crear undata.frame
, esstringsAsFactors = FALSE
, por lo queas.character
podría eliminarse.Varias alternativas:
1) dos formas con tabla de datos:
2) una dplyr / tidyr combinación:
3) con tidyrsolo: Con
tidyr 0.5.0
(y posterior), también puede usarseparate_rows
:Puede utilizar el
convert = TRUE
parámetro para convertir automáticamente números en columnas numéricas.4) con base R:
fuente
data.table(id= "X21", a = "chr1;chr1;chr1", b="123;133;134",c="234;254;268")
convirtiéndosedata.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]
es lo que funcionó para mí.Nombrando su data.frame original
v
, tenemos esto:Tenga en cuenta el uso de
rep
para construir la nueva columna AB. Aquí,sapply
devuelve el número de nombres en cada una de las filas originales.fuente
vapply
. ¿Hay algo que lo hagavapply
más apropiado aquí?sapply(s, length)
podría reemplazarse porlengths(s)
.Tarde para la fiesta, pero otra alternativa generalizada es usar
cSplit
mi paquete "splitstackshape" que tiene undirection
argumento. Establezca esto en"long"
para obtener el resultado que especifique:fuente
fuente
Actualmente, se podría recomendar otro Benchmark resultante del uso
strsplit
de base para dividir cadenas separadas por comas en una columna en filas separadas , ya que era la más rápida en una amplia gama de tamaños:Tenga en cuenta que el uso
fixed=TRUE
tiene un impacto significativo en los tiempos.Métodos comparados:
Bibliotecas:
Datos:
Resultados de cálculo y cronometraje:
Nota, métodos como
devolver un
strsplit
paraunique
director y podría ser comparable conpero a mi entender, esto no se preguntó.
fuente