2013-04-10 15 views
24

Voglio aggregare una colonna in un frame di dati in base a due variabili di raggruppamento e separare i singoli valori con una virgola.Comprimi/concateni/aggrega una colonna in una singola stringa separata da virgola all'interno di ciascun gruppo

Ecco alcuni dati:

data <- data.frame(A = c(rep(111, 3), rep(222, 3)), B = rep(1:2, 3), C = c(5:10)) 
data 
#  A B C 
# 1 111 1 5 
# 2 111 2 6 
# 3 111 1 7 
# 4 222 2 8 
# 5 222 1 9 
# 6 222 2 10  

"A" e "B" sono variabili di raggruppamento, e "C" è la variabile che voglio crollare in un separato da virgole character stringa. Ho provato:

library(plyr) 
ddply(data, .(A,B), summarise, test = list(C)) 

    A B test 
1 111 1 5, 7 
2 111 2  6 
3 222 1  9 
4 222 2 8, 10 

ma quando ho provato per convertire colonna di prova per character diventa in questo modo:

ddply(data, .(A,B), summarise, test = as.character(list(C))) 
#  A B  test 
# 1 111 1 c(5, 7) 
# 2 111 2  6 
# 3 222 1  9 
# 4 222 2 c(8, 10) 

Come posso mantenere il formato character e separarli da una virgola? Ad esempio, la riga 1 deve essere solo "5,7" e non come c (5,7).

risposta

28

plyr Prova utilizzando toString:

# plyr 
library(plyr) 
ddply(data, .(A,B), summarize, C = toString(C)) 

Ecco alcuni ulteriori alternative anche utilizzando toString:

data.table

# alternative using data.table 
library(data.table) 
as.data.table(data)[, toString(C), by = list(A, B)] 

aggregato Questa non utilizza pacchetti:

# alternative using aggregate from the stats package in the core of R 
aggregate(C ~., data, toString) 

sqldf

E qui è un'alternativa utilizzando la funzione SQL group_concat utilizzando il sqldf package:

library(sqldf) 
sqldf("select A, B, group_concat(C) C from data group by A, B", method = "raw") 

dplyr A dplyr alternativa:

library(dplyr) 
data %>% 
    group_by(A, B) %>% 
    summarise(test = toString(C)) %>% 
    ungroup() 
9

Change dove si mettono as.character:

> out <- ddply(data, .(A, B), summarise, test = list(as.character(C))) 
> str(out) 
'data.frame': 4 obs. of 3 variables: 
$ A : num 111 111 222 222 
$ B : int 1 2 1 2 
$ test:List of 4 
    ..$ : chr "5" "7" 
    ..$ : chr "6" 
    ..$ : chr "9" 
    ..$ : chr "8" "10" 
> out 
    A B test 
1 111 1 5, 7 
2 111 2  6 
3 222 1  9 
4 222 2 8, 10 

Si noti, tuttavia, che ogni articolo è ancora in realtà un personaggio a parte, non è una stringa di caratteri singolo. Cioè, questa non è una stringa vera e propria che assomiglia a "5, 7", ma piuttosto due caratteri, "5" e "7", che R visualizza con una virgola tra di loro.

Paragonare con il seguente:

> out2 <- ddply(data, .(A, B), summarise, test = paste(C, collapse = ", ")) 
> str(out2) 
'data.frame': 4 obs. of 3 variables: 
$ A : num 111 111 222 222 
$ B : int 1 2 1 2 
$ test: chr "5, 7" "6" "9" "8, 10" 
> out 
    A B test 
1 111 1 5, 7 
2 111 2  6 
3 222 1  9 
4 222 2 8, 10 

La soluzione analoga a base di R è, naturalmente, aggregate:

> A1 <- aggregate(C ~ A + B, data, function(x) c(as.character(x))) 
> str(A1) 
'data.frame': 4 obs. of 3 variables: 
$ A: num 111 222 111 222 
$ B: int 1 1 2 2 
$ C:List of 4 
    ..$ 0: chr "5" "7" 
    ..$ 1: chr "9" 
    ..$ 2: chr "6" 
    ..$ 3: chr "8" "10" 
> A2 <- aggregate(C ~ A + B, data, paste, collapse = ", ") 
> str(A2) 
'data.frame': 4 obs. of 3 variables: 
$ A: num 111 222 111 222 
$ B: int 1 1 2 2 
$ C: chr "5, 7" "9" "6" "8, 10" 
Problemi correlati