Pegar varias columnas juntas
Tengo un montón de columnas en un marco de datos que quiero pegar juntas (separadas por "-") de la siguiente manera:
data <- data.frame('a' = 1:3,
'b' = c('a','b','c'),
'c' = c('d', 'e', 'f'),
'd' = c('g', 'h', 'i'))
i.e.
a b c d
1 a d g
2 b e h
3 c f i
En lo que quiero convertirme:
a x
1 a-d-g
2 b-e-h
3 c-f-i
Normalmente podría hacer esto con:
within(data, x <- paste(b,c,d,sep='-'))
y luego eliminar las columnas antiguas, pero desafortunadamente no sé los nombres de las columnas específicamente, solo un nombre colectivo para todas las columnas, por ejemplo, sabría quecols <- c('b','c','d')
¿Alguien sabe una manera de hacer esto?
# your starting data..
data <- data.frame('a' = 1:3, 'b' = c('a','b','c'), 'c' = c('d', 'e', 'f'), 'd' = c('g', 'h', 'i'))
# columns to paste together
cols <- c( 'b' , 'c' , 'd' )
# create a new column `x` with the three columns collapsed together
data$x <- apply( data[ , cols ] , 1 , paste , collapse = "-" )
# remove the unnecessary columns
data <- data[ , !( names( data ) %in% cols ) ]
Como variante de la respuesta de Baptiste , con data
lo definido como lo tienes y las columnas que quieres armar definidas encols
cols <- c("b", "c", "d")
Puede agregar la nueva columna data
y eliminar las antiguas con
data$x <- do.call(paste, c(data[cols], sep="-"))
for (co in cols) data[co] <- NULL
lo que da
> data
a x
1 1 a-d-g
2 2 b-e-h
3 3 c-f-i
Usando tidyr
el paquete, esto se puede manejar fácilmente en 1 llamada de función.
data <- data.frame('a' = 1:3,
'b' = c('a','b','c'),
'c' = c('d', 'e', 'f'),
'd' = c('g', 'h', 'i'))
Excluye la primera columna, todo lo demás se pega.
# tidyr_0.6.3
unite(data, newCol, -a)
# or by column index unite(data, newCol, -1)
# a newCol
# 1 1 a_d_g
# 2 2 b_e_h
# 3 3 c_f_i
Construiría un nuevo data.frame:
d <- data.frame('a' = 1:3, 'b' = c('a','b','c'), 'c' = c('d', 'e', 'f'), 'd' = c('g', 'h', 'i'))
cols <- c( 'b' , 'c' , 'd' )
data.frame(a = d[, 'a'], x = do.call(paste, c(d[ , cols], list(sep = '-'))))
Solo para agregar una solución adicional Reduce
que probablemente sea más lenta do.call
pero probablemente mejor apply
porque evitará la matrix
conversión. Además, en lugar de for
eso, podríamos usar un bucle setdiff
para eliminar columnas no deseadas.
cols <- c('b','c','d')
data$x <- Reduce(function(...) paste(..., sep = "-"), data[cols])
data[setdiff(names(data), cols)]
# a x
# 1 1 a-d-g
# 2 2 b-e-h
# 3 3 c-f-i
Alternativamente, podríamos actualizar data
en el lugar usando el data.table
paquete (suponiendo que haya datos nuevos)
library(data.table)
setDT(data)[, x := Reduce(function(...) paste(..., sep = "-"), .SD[, mget(cols)])]
data[, (cols) := NULL]
data
# a x
# 1: 1 a-d-g
# 2: 2 b-e-h
# 3: 3 c-f-i
Otra opción es usar .SDcols
en lugar de mget
como en
setDT(data)[, x := Reduce(function(...) paste(..., sep = "-"), .SD), .SDcols = cols]