Mam dane z ankiety internetowej, w której respondenci 1-3 razy przechodzą przez pętlę pytań. Program badania (Qualtrics) zapisuje te dane w wielu kolumnach, to znaczy Q3.2 w badaniu będą miały kolumny Q3.2.1.
, Q3.2.2.
oraz Q3.2.3.
:
df <- data.frame(
id = 1:10,
time = as.Date('2009-01-01') + 0:9,
Q3.2.1. = rnorm(10, 0, 1),
Q3.2.2. = rnorm(10, 0, 1),
Q3.2.3. = rnorm(10, 0, 1),
Q3.3.1. = rnorm(10, 0, 1),
Q3.3.2. = rnorm(10, 0, 1),
Q3.3.3. = rnorm(10, 0, 1)
)
# Sample data
id time Q3.2.1. Q3.2.2. Q3.2.3. Q3.3.1. Q3.3.2. Q3.3.3.
1 1 2009-01-01 -0.2059165 -0.29177677 -0.7107192 1.52718069 -0.4484351 -1.21550600
2 2 2009-01-02 -0.1981136 -1.19813815 1.1750200 -0.40380049 -1.8376094 1.03588482
3 3 2009-01-03 0.3514795 -0.27425539 1.1171712 -1.02641801 -2.0646661 -0.35353058
...
Chcę połączyć wszystkie kolumny QN.N * w uporządkowane oddzielne kolumny QN.N, ostatecznie kończąc na czymś takim:
id time loop_number Q3.2 Q3.3
1 1 2009-01-01 1 -0.20591649 1.52718069
2 2 2009-01-02 1 -0.19811357 -0.40380049
3 3 2009-01-03 1 0.35147949 -1.02641801
...
11 1 2009-01-01 2 -0.29177677 -0.4484351
12 2 2009-01-02 2 -1.19813815 -1.8376094
13 3 2009-01-03 2 -0.27425539 -2.0646661
...
21 1 2009-01-01 3 -0.71071921 -1.21550600
22 2 2009-01-02 3 1.17501999 1.03588482
23 3 2009-01-03 3 1.11717121 -0.35353058
...
tidyr
Biblioteka posiada gather()
funkcję, która działa świetnie na łączenie jeden zestaw kolumn:
library(dplyr)
library(tidyr)
library(stringr)
df %>% gather(loop_number, Q3.2, starts_with("Q3.2")) %>%
mutate(loop_number = str_sub(loop_number,-2,-2)) %>%
select(id, time, loop_number, Q3.2)
id time loop_number Q3.2
1 1 2009-01-01 1 -0.20591649
2 2 2009-01-02 1 -0.19811357
3 3 2009-01-03 1 0.35147949
...
29 9 2009-01-09 3 -0.58581232
30 10 2009-01-10 3 -2.33393981
Wynikowa ramka danych ma 30 wierszy, zgodnie z oczekiwaniami (10 osobników, 3 pętle każda). Jednak gromadzenie drugiego zestawu kolumn nie działa poprawnie - pomyślnie tworzy dwie połączone kolumny Q3.2
i Q3.3
, ale kończy się na 90 wierszach zamiast 30 (wszystkie kombinacje 10 osobników, 3 pętle Q3.2 i 3 pętle Q3 .3; kombinacje znacznie wzrosną dla każdej grupy kolumn w rzeczywistych danych):
df %>% gather(loop_number, Q3.2, starts_with("Q3.2")) %>%
gather(loop_number, Q3.3, starts_with("Q3.3")) %>%
mutate(loop_number = str_sub(loop_number,-2,-2))
id time loop_number Q3.2 Q3.3
1 1 2009-01-01 1 -0.20591649 1.52718069
2 2 2009-01-02 1 -0.19811357 -0.40380049
3 3 2009-01-03 1 0.35147949 -1.02641801
...
89 9 2009-01-09 3 -0.58581232 -0.13187024
90 10 2009-01-10 3 -2.33393981 -0.48502131
Czy istnieje sposób na użycie wielu wywołań w gather()
tym celu, łącząc małe podzbiory kolumn, jak to, przy jednoczesnym zachowaniu prawidłowej liczby wierszy?
df %>% gather(loop_number, Q3.2, starts_with("Q3."))
seperate()
aby podzielić wartości Q3.3 (i nie tylko) na ich własne kolumny. Ale to wciąż wydaje się być naprawdę okrężnym, hakerskim rozwiązaniem…spread
Pracuję teraz nad rozwiązaniem: pdf %>% gather(question_number, Q3.2, starts_with("Q3.")) %>% mutate(loop_number = str_sub(question_number,-2,-2), question_number = str_sub(question_number,1,4)) %>% select(id, time, loop_number, question_number, Q3.2) %>% spread(key = question_number, value = Q3.2)
spread()
. Chociaż wielokrotne połączenia i tak wydają się nieuniknione, niezależnie od tego, czy działa kilka połączeńgenerate()
, czy zagnieżdżonespread()
…Odpowiedzi:
To podejście wydaje mi się całkiem naturalne:
Najpierw zbierz wszystkie kolumny pytań, użyj ich
extract()
do rozdzielenia naquestion
iloop_number
, a następniespread()
zapytaj z powrotem do kolumn.źródło
Można to zrobić za pomocą
reshape
. Jest to jednak możliwedplyr
.Lub używając
dplyr
Aktualizacja
Za pomocą
tidyr_0.8.3.9000
możemypivot_longer
zmienić kształt wielu kolumn. (Używając zmienionych nazw kolumn zgsub
góry)UWAGA: Wartości są różne, ponieważ podczas tworzenia wejściowego zestawu danych nie było ustawionego ziarna
źródło
mutate(loop_number = as.numeric(L2))
przed upuszczeniemL2
i jest idealne.reshape
metodę ze względu na jej zwarty kod, chociażdplyr
może być szybsza w przypadku dużych zbiorów danych.reshape()
funkcji, zobacz moje rozwiązanie, które wydaje mi się całkiem czystą implementacją Tidyr.Dzięki ostatniej aktualizacji do
melt.data.table
, możemy teraz stopić wiele kolumn. Dzięki temu możemy:Możesz pobrać wersję rozwojową stąd .
źródło
Wcale nie jest to związane z "tidyr" i "dplyr", ale oto inna opcja do rozważenia:
merged.stack
z mojego pakietu "splitstackshape" , wersja 1.4.0 i nowsze.źródło
Jeśli jesteś podobny do mnie i nie możesz wymyślić, jak użyć „wyrażenia regularnego z grupami przechwytującymi” dla
extract
, następujący kod replikujeextract(...)
wiersz w odpowiedzi Hadleys:Problem polega na tym, że początkowe gromadzenie tworzy kolumnę klucza, która w rzeczywistości jest kombinacją dwóch kluczy. Zdecydowałem się użyć
mutate
w moim oryginalnym rozwiązaniu w komentarzach, aby podzielić tę kolumnę na dwie kolumny z równoważnymi informacjami,loop_number
kolumną iquestion_number
kolumną.spread
można następnie użyć do przekształcenia danych w postaci długiej, które są parami klucz-wartość(question_number, value)
w dane w szerokim formularzu.źródło