Pytanie Funkcja tidyr spread generuje rzadką matrycę, gdy oczekiwany jest wektor kompaktowy


Uczę się dplyr, pochodzę z plyr i chcę generować (na grupę) kolumny (na interakcję) z wyjścia xtabs.

Krótkie podsumowanie: dostaję

A    B
1    NA
NA   2

kiedy chciałem

A    B
1    2

Dane xtabs wyglądają tak:

> xtabs(data=data.frame(P=c(F,T,F,T,F),A=c(F,F,T,T,T)))
       A
P       FALSE TRUE
  FALSE     1    2
  TRUE      1    1

teraz do( chce danych w ramkach danych, takich jak to:

> xtabs(data=data.frame(P=c(F,T,F,T,F),A=c(F,F,T,T,T))) %>% as.data.frame
      P     A Freq
1 FALSE FALSE    1
2  TRUE FALSE    1
3 FALSE  TRUE    2
4  TRUE  TRUE    1

Teraz chcę mieć wyjście z jednym wierszem z kolumnami będącymi interakcją poziomów. Oto czego szukam:

FALSE_FALSE TRUE_TRUE FALSE_TRUE TRUE_FALSE
          1         1          2          1

Ale zamiast tego dostaję

> xtabs(data=data.frame(P=c(F,T,F,T,F),A=c(F,F,T,T,T))) %>% 
    as.data.frame %>% 
    unite(S,A,P) %>% 
    spread(S,Freq)
  FALSE_FALSE FALSE_TRUE TRUE_FALSE TRUE_TRUE
1           1         NA         NA        NA
2          NA          1         NA        NA
3          NA         NA          2        NA
4          NA         NA         NA         1

Wyraźnie coś tu nie rozumiem. Szukam odpowiednika kodu reshape2 tutaj (przy użyciu magrittr dla spójności):

> xtabs(data=data.frame(P=c(F,T,F,T,F),A=c(F,F,T,T,T))) %>% 
    as.data.frame %>% # can be omitted. (safely??)
    melt %>% 
    mutate(S=interaction(P,A),value=value) %>% 
    dcast(NA~S)
Using P, A as id variables
  NA FALSE.FALSE TRUE.FALSE FALSE.TRUE TRUE.TRUE
1 NA           1          1          2         1

(Uwaga: tutaj jest używana, ponieważ nie mam zmiennej grupującej w tym uproszczonym przykładzie)


Aktualizacja - co ciekawe, dodanie pojedynczej kolumny grupującej zdaje się to naprawiać - dlaczego syntetyzuje (prawdopodobnie z row_name) kolumnę grupowania bez jej informowania?

> xtabs(data=data.frame(h="foo",P=c(F,T,F,T,F),A=c(F,F,T,T,T))) %>% 
  as.data.frame %>% 
  unite(S,A,P) %>% 
  spread(S,Freq)
    h FALSE_FALSE FALSE_TRUE TRUE_FALSE TRUE_TRUE
1 foo           1          1          2         1

To wydaje się częściowym rozwiązaniem.


10
2017-12-16 09:41


pochodzenie


To wygląda na to samo. - Henrik
@Henrik: rzeczywiście tak jest. - Alex Brown
To jest ten sam problem na odwrocie, z komentarzem wyjaśniającym Hadleya. Jak odkryłeś w swojej aktualizacji, oba wyjścia mają sens w odpowiednim kontekście. Gdy kontekst jest tylko niejawny, spread() musi zgadywać. - nacnudus
@nacnudus: Dziękujemy za pomocny wskaźnik. Nie zgadzam się w tej sprawie - nie odkryłem, że rozszerzony przypadek ma sens - po prostu, że istniał. Tam, gdzie nie ma ŻADNYCH argumentów / kolumn, z których można się domyślić, Spodziewam się, że założy on, że istnieje jedna globalna tożsamość. Czy możesz wyjaśnić, dlaczego to nie może być prawda? - Alex Brown
OK, zabiłem też mój obalający komentarz :-) - Carl Witthoft


Odpowiedzi:


Kluczem jest to spread nie agreguje danych.

Dlatego, jeśli jeszcze nie korzystałeś xtabs najpierw agregować, robiłbyś to:

a <- data.frame(P=c(F,T,F,T,F),A=c(F,F,T,T,T), Freq = 1) %>% 
    unite(S,A,P)
a
##             S Freq
## 1 FALSE_FALSE    1
## 2  FALSE_TRUE    1
## 3  TRUE_FALSE    1
## 4   TRUE_TRUE    1
## 5  TRUE_FALSE    1

a %>% spread(S, Freq)
##   FALSE_FALSE FALSE_TRUE TRUE_FALSE TRUE_TRUE
## 1           1         NA         NA        NA
## 2          NA          1         NA        NA
## 3          NA         NA          1        NA
## 4          NA         NA         NA         1
## 5          NA         NA          1        NA

Które nie miałoby sensu w żaden inny sposób (bez agregacji).

Jest to przewidywalne na podstawie pliku pomocy dla fill parametr:

Jeśli nie ma wartości dla każdej kombinacji innych zmiennych   i kolumna kluczowa, ta wartość zostanie zastąpiona.

W twoim przypadku nie ma żadnych innych zmiennych do połączenia z kolumną klucza. Gdyby tak było, to ...

b <- data.frame(P=c(F,T,F,T,F),A=c(F,F,T,T,T), Freq = 1
                                , h = rep(c("foo", "bar"), length.out = 5)) %>% 
    unite(S,A,P)
b
##             S Freq   h
## 1 FALSE_FALSE    1 foo
## 2  FALSE_TRUE    1 bar
## 3  TRUE_FALSE    1 foo
## 4   TRUE_TRUE    1 bar
## 5  TRUE_FALSE    1 foo

> b %>% spread(S, Freq)
## Error: Duplicate identifiers for rows (3, 5)

... może zawieść, ponieważ nie może zagregować wierszy 3 i 5 (ponieważ nie jest przeznaczony do tego).

The tidyr/dplyr sposób by to zrobić group_by i summarize zamiast xtabs, bo summarize zachowuje kolumnę grupowania, a więc spread może powiedzieć, które obserwacje należą do tego samego wiersza:

b %>%   group_by(h, S) %>%
    summarize(Freq = sum(Freq))
## Source: local data frame [4 x 3]
## Groups: h
## 
##     h           S Freq
## 1 bar  FALSE_TRUE    1
## 2 bar   TRUE_TRUE    1
## 3 foo FALSE_FALSE    1
## 4 foo  TRUE_FALSE    2

b %>%   group_by(h, S) %>%
    summarize(Freq = sum(Freq)) %>%
    spread(S, Freq)
## Source: local data frame [2 x 5]
## 
##     h FALSE_FALSE FALSE_TRUE TRUE_FALSE TRUE_TRUE
## 1 bar          NA          1         NA         1
## 2 foo           1         NA          2        NA

5
2017-12-17 00:35



Ale kiedy używamy go w połączeniu z grupami dplyr podczas grupowania maksymalnego zbioru tożsamości, mamy dorozumianą agregację: który iirc w rzeczywistości nie działa poprawnie. - Alex Brown
Co to jest maksymalny zestaw tożsamości? Nie sądzę, że istnieje jakakolwiek alternatywa do dostarczania sztucznej zmiennej grupującej. Możesz to zrobić w oryginalnej ramce danych lub możesz to zrobić group_by(1) przed spread i wtedy select(-1) potem. - nacnudus
Mam na myśli, gdy wszystkie zmienne inne niż klucz i wartość zostały skonsumowane jako "enumeratory" w operacjach group_by. Dzięki i tak - Alex Brown
@Nacnudus Chciałem tylko powiedzieć twój komentarz group_by(1) naprawdę mi pomogło. - Alex