2015-09-30 5 views
6

Powiedz, że mam dane dotyczące osób, które wybierają kilka opcji. Mam jeden wiersz na osobę i chcę mieć jeden wiersz na osobę i opcję wyboru. Tak więc, jeśli mam 10 osób, które mają 3 opcje, teraz mam 10 wierszy i chcę mieć 30Jak używać tidyr do wypełniania wypełnionych wierszy w ramach każdej wartości zmiennej grupującej?

Wszystkie pozostałe zmienne powinny zostać skopiowane do każdego z nowych wierszy. Na przykład, jeśli mam zmienną dotyczącą płci, powinna ona być stała w ramach identyfikatora. (Mam ustawienie moich danych aż ten sposób analizować z mnlogit.)

To wydaje się sytuacja, że ​​dwie tidyr funkcje complete i fill, zostały zaprojektowane. Aby wykorzystać prosty przykład

library(lubridate) 
library(tidyr) 
dat <- data.frame(
    id = 1:3, 
    choice = 5:7, 
    c = c(9, NA, 11), 
    d = ymd(NA, "2015-09-30", "2015-09-29") 
    ) 

dat %>% 
    complete(id, choice) %>% 
    fill(everything()) 

# Source: local data frame [9 x 4] 
# 
#  id choice  c   d 
# (int) (int) (dbl)  (time) 
# 1  1  5  9  <NA> 
# 2  1  6  9  <NA> 
# 3  1  7  9  <NA> 
# 4  2  5  9  <NA> 
# 5  2  6  9 2015-09-30 
# 6  2  7  9 2015-09-30 
# 7  3  5  9 2015-09-30 
# 8  3  6  9 2015-09-30 
# 9  3  7 11 2015-09-29 

to jednak pewne problemy - wartości D przeniesiono poprawnie, ale wartości C identyfikatora 1 otrzymuje (poprawne) brak wartości dla ID 2.

Mogę wypróbować obejście, na przykład zastąpienie wszystkich brakujących wartości 999, uruchamianie complete i fill, a następnie zastąpienie 999 NA. (Myślę, że musiałbym przekonwertować zmienne daty na zmienne znakowe, a następnie przekonwertować je ponownie, jeśli pójdę tą drogą.) Ale może ktoś tutaj zna czysty sposób na zrobienie tego z tidyr?

Edit: sygnał wyjściowy jest tutaj:

# Source: local data frame [9 x 4] 
# 
#  id  c   d choice 
# (int) (dbl)  (time) (int) 
# 1  1  9  <NA>  5 
# 2  1  9  <NA>  6 
# 3  1  9  <NA>  7 
# 4  2 NA 2015-09-30  5 
# 5  2 NA 2015-09-30  6 
# 6  2 NA 2015-09-30  7 
# 7  3 11 2015-09-29  5 
# 8  3 11 2015-09-29  6 
# 9  3 11 2015-09-29  7 
+1

Niestety, 'time' ma być' wyborem'. Naprawię to. –

+0

Jako aktualizacja, 'mlogit' zawiera funkcję,' mlogit.data', która rozwiązuje ten problem. 'mlogit.data (dat, choice =" choice ", shape =" wide ")' również daje pożądane wyniki. Wiem, że poprosiłem o rozwiązanie 'tidyr', ale dla przyszłych czytelników pomyślałem, że pomocne może być również włączenie tego rozwiązania. –

Odpowiedz

8

Można użyć sztuczki rzeczy „Grupowanie”, aby zakończyć w ciągu zakończyć korzystanie c(). Powoduje to, że jest on zakończony tylko przy użyciu wcześniej istniejących kombinacji zgrupowanych zmiennych.

library(tidyr) 
dat %>% complete(c(id, c, d), choice) 
    id  c   d choice 
    (int) (dbl)  (time) (int) 
1  1  9  <NA>  5 
2  1  9  <NA>  6 
3  1  9  <NA>  7 
4  2 NA 2015-09-30  5 
5  2 NA 2015-09-30  6 
6  2 NA 2015-09-30  7 
7  3 11 2015-09-29  5 
8  3 11 2015-09-29  6 
9  3 11 2015-09-29  7 
+2

Hm, okay. Tak więc wygląda na to, że rozwiązaniem jest tutaj 'complete (c (id, c, d, [wszystkie inne zmienne, które się nie zmieniają]), wybór)' i po prostu całkowicie zaprzestań 'fill'. Dobrze? –

+1

Dodam go, ale pożądane dane wyjściowe są tworzone przez 'complete (dat, c (id, c, d), choice)'. –

+0

Używanie 'tidyr' version' 0.5.1' to już nie działa. Zobacz moją odpowiedź poniżej. –

2

myślę, że jesteś lepiej zachowując dane oddzielić podczas przygotowania go, a następnie łączenie przed musisz zrobić regresji.

subjectdata <- dat[,c("id", "c", "d")] 
questiondata <- dat[,c("id", "choice")] %>% complete(id, choice) 

A potem

> merge(questiondata, subjectdata) 
    id choice c   d 
1 1  5 9  <NA> 
2 1  6 9  <NA> 
3 1  7 9  <NA> 
4 2  5 NA 2015-09-30 
5 2  6 NA 2015-09-30 
6 2  7 NA 2015-09-30 
7 3  5 11 2015-09-29 
8 3  6 11 2015-09-29 
9 3  7 11 2015-09-29 

jak to konieczne. W ten sposób otrzymasz również poprawną kolumnę d dla użytkownika 2, bez polegania na kolejności pytań w ramce danych.

+0

Masz prawdopodobnie rację, to prawdopodobnie będzie najczystszym sposobem, aby to zrobić, w końcu. –

0

Wygląda na to, że innym sposobem jest użycie spread i gather. spread tworzy jedną kolumnę na każdą możliwą odpowiedź, a gather pobiera oddzielne kolumny i przekształca je w wiersze. Z tych danych:

dat %>% 
    spread(choice, choice) %>% 
    gather(choice, drop_me, `5`:`7`) %>% # Drop me is a redundant column 
    select(-drop_me) %>% 
    arrange(id, choice) # reorders so that the answer matches 

# id c   d choice 
# 1 1 9  <NA>  5 
# 2 1 9  <NA>  6 
# 3 1 9  <NA>  7 
# 4 2 NA 2015-09-30  5 
# 5 2 NA 2015-09-30  6 
# 6 2 NA 2015-09-30  7 
# 7 3 11 2015-09-29  5 
# 8 3 11 2015-09-29  6 
# 9 3 11 2015-09-29  7 

nie robiłem żadnych badań, aby zobaczyć jak to porównać z wydajnością.

7

Jako aktualizację odpowiedzi @jeremycg. Od tidyr 0.5.1 (a może nawet wersja 0.4.0) dalej c() już nie działa. Użyj nesting() zamiast:

dat %>% 
complete(nesting(id, c, d), choice) 

Uwaga starałem się zmieniać odpowiedź @jeremycg, ponieważ odpowiedź była poprawna w momencie został napisany (i stąd nowa odpowiedź nie jest to konieczne), ale niestety dostał edit odrzucony.

Powiązane problemy