Pegar varias columnas juntas

Resuelto user1165199 asked hace 54 años • 11 respuestas

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?

user1165199 avatar Jan 01 '70 08:01 user1165199
Aceptado
# 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 ) ]
Anthony Damico avatar Jan 28 '2013 18:01 Anthony Damico

Como variante de la respuesta de Baptiste , con datalo definido como lo tienes y las columnas que quieres armar definidas encols

cols <- c("b", "c", "d")

Puede agregar la nueva columna datay 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
Brian Diggs avatar Jan 28 '2013 19:01 Brian Diggs

Usando tidyrel 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
data_steve avatar Oct 07 '2015 19:10 data_steve

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 = '-'))))
baptiste avatar Jan 28 '2013 18:01 baptiste

Solo para agregar una solución adicional Reduceque probablemente sea más lenta do.callpero probablemente mejor applyporque evitará la matrixconversión. Además, en lugar de foreso, podríamos usar un bucle setdiffpara 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 dataen el lugar usando el data.tablepaquete (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 .SDcolsen lugar de mgetcomo en

setDT(data)[, x := Reduce(function(...) paste(..., sep = "-"), .SD), .SDcols = cols]
David Arenburg avatar Oct 08 '2015 12:10 David Arenburg