2015-07-17 8 views
7

Próbuję zwinąć kilka wierszy na jeden dzień w jeden wiersz. Chciałbym, jeśli to możliwe, w dplyr. Wiem, że mój kod jest daleko od poprawne, ale to było jak daleko mam:R zwijanie wierszy do pojedynczego wiersza (zmienne ciągłe i czynnikowe)

data %>% 
    group_by(DAY) %>% 
    summarise_each(funs(Sum = n()), SEX, GROUP, TOTAL) 

oryginalny:

DAY SEX GROUP TOTAL  
7/1/14 FEMALE A 1  
7/1/14 FEMALE B 1  
7/1/14 FEMALE B 1  
7/1/14 FEMALE A 1  
7/1/14 MALE A 1  
7/1/14 MALE B 2  

Nowość:

DAY  FEMALE MALE GROUP_A GROUP_B TOTAL 
7/1/14 4  2  3  3  7 
+0

Cóż, na pierwszy rzut oka, najprostszym byłoby napisać go "data%>% group_by (DAY)%>% summary (FEMALE = suma (SEX ==" FEMALE "), MALE = suma (SEX ==" MALE "), GROUP_A = suma (GROUP = = "A"), GROUP_B = suma (GROUP == "B"), TOTAL = suma (TOTAL)) '. Ale myślę, że dążysz do elegancji kodu. :-) – lukeA

Odpowiedz

8

Innym sposobem z data.table, testowane na data.frame z więcej niż jeden dzień.

require(data.table) 
setDT(data)[, as.list(c(table(SEX), table(GROUP), TOTAL=sum(TOTAL))), by=DAY] 

#  DAY FEMALE MALE A B TOTAL 
#1: 7/1/14  3 0 1 2  3 
#2: 8/1/14  1 2 2 1  4 

EDIT: inny, mniej obsługi, opcja (nie trzeba wiedzieć, jakie czynniki są zmienne i które są numeryczne), dzięki jakiejś pomocy od @jangorecki i @DavidArenburg

wh_num <- sapply(data, is.numeric)[-1] 
wh_fact <-sapply(data, is.factor)[-1] 
setDT(data)[, as.list(c(lapply(.SD[, wh_fact, with = FALSE], table), 
         lapply(.SD[, wh_num, with = FALSE], sum), 
         recursive = TRUE)), by = DAY] 

#  DAY SEX.FEMALE SEX.MALE GROUP.A GROUP.B TOTAL 
#1: 7/1/14   3  0  1  2  3 
#2: 8/1/14   1  2  2  1  4 

dane

data <- structure(list(DAY = c("7/1/14", "7/1/14", "7/1/14", "8/1/14", 
"8/1/14", "8/1/14"), SEX = structure(c(1L, 1L, 1L, 1L, 2L, 2L 
), .Label = c("FEMALE", "MALE"), class = "factor"), GROUP = structure(c(1L, 
2L, 2L, 1L, 1L, 2L), .Label = c("A", "B"), class = "factor"), 
    TOTAL = c(1L, 1L, 1L, 1L, 1L, 2L)), .Names = c("DAY", "SEX", 
"GROUP", "TOTAL"), row.names = c(NA, -6L), class = "data.frame") 
3

sposób obliczyć całkowitą (suma), a pozostałe kolumny (tabela) znacznie się różnią, więc prawdopodobnie musisz wykonać te kroki oddzielnie. Obliczenie sumy jest łatwe. Na zestawianiu, sugeruję, używając tidyr następująco:

# required packages 
require(dplyr) 
require(tidyr) 

# calculations 
data %>% 
    group_by(DAY) %>%      # group by day 
    mutate(TOTAL = sum(TOTAL)) %>%  # first calculate total 
    gather(key, value, -DAY, -TOTAL) %>% # collapse 
    unite(group, key, value) %>%   # get sensible column names 
    group_by(DAY, TOTAL) %>%    # group by day and total 
    do(as.data.frame(table(.$group))) %>% # table 
    spread(Var1, Freq)     # spread out 

##  DAY TOTAL GROUP_A GROUP_B SEX_FEMALE SEX_MALE 
## 1 7/1/14  7  3  3   4  2 
+1

Jestem naprawdę zaskoczony, że wolałeś to od skomplikowanego rozwiązania 'dplyr/tidyr' zamiast prostego rozwiązania' data.table', które opublikowałeś już wiele razy. –

+0

@DavidArenburg: Zazwyczaj staram się odpowiedzieć na pakiety, które OP woli. Zgadzam się jednak, że w tym przypadku rozwiązanie data.table jest lepsze (a ja go przegłosowałem). – shadow

5

To może wydawać się trochę tajniki, ale tutaj jest krótki zaklęcie

dat %>% group_by(DAY) %>% 
    summarise_each(funs(ifelse(is.numeric(.), sum(.), list(table(.))))) -> res 

data.frame(DAY=res$DAY, t(unlist(res[, 2:ncol(res)]))) 
#  DAY SEX.FEMALE SEX.MALE GROUP.A GROUP.B TOTAL 
# 1 7/1/14   4  2  3  3  7 

Tutaj po prostu podsumować każdą kolumnę w postaci tabeli, jeżeli jest to nie numeryczne lub sumuj jeśli jest (dla całkowitej kolumny). To musi być zwrócone jako lista, ponieważ summarise_each oczekuje jednej wartości. Następnie wynik zostaje rozszerzony do zwykłego data.frame.

+1

Nie jestem pewien, czy działa poprawnie dla kilku dat. Na przykład, jeśli zmienisz 3 ostatnie daty na "8/1/14". –

+0

@DavidArenburg tak, dotyczy to specjalnego przypadku z jednego rzędu. Możesz sprawić, żeby działało więcej, coś podobnego do tego, co się z nimi wiąże. – jenesaisquoi

+0

Wątpię, aby @ user2434624 miał tylko jeden dzień w oryginalnych danych ... – Cath

3

Jednym z możliwych podejście:

library(reshape2) 
library(data.table) 

cbind(dcast(df, DAY~SEX), 
     dcast(df, DAY~GROUP)[-1], 
     setDT(df)[,.(total=sum(TOTAL)),DAY][,-1,with=F]) 

#  DAY FEMALE MALE A B total 
#1 7/1/14  4 2 3 3  7 
Powiązane problemy