2013-04-10 27 views
24

Chcę agregować jedną kolumnę w ramce danych według dwóch zmiennych grupujących i oddzielać poszczególne wartości przecinkiem.Zwiń/połącz/agreguj kolumnę z pojedynczym łańcuchem oddzielonym przecinkami w każdej grupie.

Oto dane:

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” i „B” są grupowania zmiennych i „C” jest zmienna, że ​​chcę, aby zwinąć się przecinkiem oddzielone character ciąg. Próbowałem:

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 

ale kiedy próbowałem konwertować kolumnę testowy do character staje się tak:

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) 

Jak mogę utrzymać się character formatu i oddzielić je przecinkiem? Na przykład wiersz 1 powinien być tylko "5,7", a nie jako c (5,7).

Odpowiedz

28

plyr Użyj toString:

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

Oto kilka dodatkowych alternatyw również wykorzystujące toString:

data.table

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

kruszywo używa żadnych pakietów:

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

sqldf

I tu jest alternatywą przy użyciu funkcji SQL group_concat pomocą sqldf package:

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

dplyrdplyr alternatywa:

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

Zmień gdzie można umieścić 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 

Należy jednak pamiętać, że każdy element jest jeszcze rzeczywiście odrębny charakter, a nie pojedynczy łańcuch znaków. Oznacza to, że nie jest to rzeczywisty ciąg znaków, który wygląda jak "5, 7", ale raczej dwa znaki, "5" i "7", które R wyświetla z przecinkiem między nimi.

porównania z:

> 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 

porównywalne rozwiązanie bazy R jest oczywiście 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"