Функция распределения tidyr генерирует разреженную матрицу при ожидаемом компактном векторе

Я изучаю dplyr, выйдя из plyr, и я хочу генерировать (для каждой группы) столбцы (за взаимодействие) из вывода xtabs.

Краткое описание: Я получаю

A    B
1    NA
NA   2

когда я хотел

A    B
1    2

Данные xtabs выглядят следующим образом:

> 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

теперь do( запрашивает данные в кадрах данных, например:

> 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

Теперь мне нужен вывод с одной строкой, где столбцы представляют собой взаимодействие уровней. Вот что я ищу:

FALSE_FALSE TRUE_TRUE FALSE_TRUE TRUE_FALSE
          1         1          2          1

Но вместо этого я получаю

> 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

Я явно что-то недопонимаю. Я ищу эквивалент кода reshape2 здесь (используя конвейеры magrittr для согласованности):

> 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

(примечание NA используется здесь, потому что в этом упрощенном примере у меня нет переменной группировки)


Обновление - интересно, добавление одного столбца группировки, по-видимому, исправить это - почему он синтезирует (предположительно из row_name) столбцы группировки, не говоря мне об этом?

> 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

Это похоже на частичное решение.

Ответ 1

Ключ здесь состоит в том, что spread не агрегирует данные.

Следовательно, если вы ранее не использовали xtabs для агрегирования, вы бы это сделали:

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

Это не имело бы смысла каким-либо другим способом (без агрегации).

Это предсказуемо на основе файла справки для параметра fill:

Если для каждой комбинации других переменных нет значения и ключевой столбец, это значение будет заменено.

В вашем случае нет никаких других переменных для объединения с ключевым столбцом. Если бы было, то...

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)

... он не сработает, потому что он не может агрегировать строки 3 и 5 (потому что он не предназначен для).

Для этого tidyr/dplyr будет group_by и summarize вместо xtabs, потому что summarize сохраняет столбец группировки, поэтому spread может определить, какие наблюдения принадлежат в та же строка:

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