Przekształcanie szerokości do długości z wieloma kolumnami wartości [duplikat]
To pytanie ma już odpowiedź tutaj:
- przekształcanie wielu zestawów kolumn pomiarowych (szeroki format) w pojedyncze kolumny (długi format) 6 odpowiedzi
Muszę przekształcić moją szeroką tabelę w długi format, ale zachowując wiele pól dla każdego rekordu, na przykład:
dw <- read.table(header=T, text='
sbj f1.avg f1.sd f2.avg f2.sd blabla
A 10 6 50 10 bA
B 12 5 70 11 bB
C 20 7 20 8 bC
D 22 8 22 9 bD
')
# Now I want to melt this table, keeping both AVG and SD as separate fields for each measurement, to get something like this:
# sbj var avg sd blabla
# A f1 10 6 bA
# A f2 50 10 bA
# B f1 12 5 bB
# B f2 70 11 bB
# C f1 20 7 bC
# C f2 20 8 bC
# D f1 22 8 bD
# D f2 22 9 bD
Mam podstawową wiedzę na temat używania melt
i reshape
, ale nie jest to dla mnie oczywiste, jak zastosować takie przekształcenie w moim przypadku.
Byłbym wdzięczny za wszelkie podpowiedzi lub wskazać inny tak post, jeśli coś podobnego zostały już poproszone.
5 answers
reshape
robi to z odpowiednimi argumentami.
varying
wyświetla listę kolumn, które istnieją w szerokim formacie, ale są podzielone na wiele wierszy w długim formacie. v.names
jest odpowiednikiem długiego formatu. Pomiędzy nimi tworzy się mapowanie.
From ?reshape
:
Również, zgadywanie nie jest próbowane, jeśli V. names jest podane jawnie. Zauważ, że kolejność zmiennych w różnych Jest Jak x. 1, y. 1, x. 2, y. 2.
Biorąc pod uwagę argumenty varying
i v.names
, reshape
jest wystarczająco inteligentny, aby zobaczyć, że podałem, że indeks jest przed kropką tutaj (tj.x, 1.y, 2.x, 2.y). Zauważ, że oryginalne dane mają kolumny w tej kolejności, więc możemy podać varying=2:5
dla tych przykładowych danych, ale ogólnie nie jest to bezpieczne.
Biorąc pod uwagę wartości times
i v.names
, reshape
dzieli kolumny varying
na znak .
(domyślny argument sep
), aby utworzyć kolumny na wyjściu.
times
określa wartości, które mają być użyte w utworzone kolumny var
i v.names
są wklejane do tych wartości, aby uzyskać nazwy kolumn w szerokim formacie do mapowania do wyniku.
Wreszcie, idvar
jest określona jako kolumna sbj
, która identyfikuje poszczególne rekordy w szerokim formacie (dzięki @thelatemail).
reshape(dw, direction='long',
varying=c('f1.avg', 'f1.sd', 'f2.avg', 'f2.sd'),
timevar='var',
times=c('f1', 'f2'),
v.names=c('avg', 'sd'),
idvar='sbj')
## sbj blabla var avg sd
## A.f1 A bA f1 10 6
## B.f1 B bB f1 12 5
## C.f1 C bC f1 20 7
## D.f1 D bD f1 22 8
## A.f2 A bA f2 50 10
## B.f2 B bB f2 70 11
## C.f2 C bC f2 20 8
## D.f2 D bD f2 22 9
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-24 23:42:45
Kolejna opcja wykorzystująca Nowy Pakiet tidyr
Hadleya.
library(tidyr)
library(dplyr)
dw <- read.table(header=T, text='
sbj f1.avg f1.sd f2.avg f2.sd blabla
A 10 6 50 10 bA
B 12 5 70 11 bB
C 20 7 20 8 bC
D 22 8 22 9 bD
')
dw %>%
gather(v, value, f1.avg:f2.sd) %>%
separate(v, c("var", "col")) %>%
arrange(sbj) %>%
spread(col, value)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-11 12:56:03
Wygląda na to, że robi to, co chcesz, z wyjątkiem tego, że {[1] } jest usuwany z elementów w time
.
reshape(dw, idvar = "sbj", varying = list(c(2,4),c(3,5)), v.names = c("ave", "sd"), direction = "long")
sbj blabla time ave sd
A.1 A bA 1 10 6
B.1 B bB 1 12 5
C.1 C bC 1 20 7
D.1 D bD 1 22 8
A.2 A bA 2 50 10
B.2 B bB 2 70 11
C.2 C bC 2 20 8
D.2 D bD 2 22 9
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-30 01:18:38
Aby dodać do dostępnych tutaj opcji, możesz również rozważyć merged.stack
z mojego pakietu "splitstackshape":
library(splitstackshape)
merged.stack(dw, var.stubs = c("avg", "sd"), sep = "var.stubs", atStart = FALSE)
# sbj blabla .time_1 avg sd
# 1: A bA f1. 10 6
# 2: A bA f2. 50 10
# 3: B bB f1. 12 5
# 4: B bB f2. 70 11
# 5: C bC f1. 20 7
# 6: C bC f2. 20 8
# 7: D bD f1. 22 8
# 8: D bD f2. 22 9
Możesz również zrobić trochę więcej czyszczenia na zmiennej ".time_1"
, Jak to.
merged.stack(dw, var.stubs = c("avg", "sd"),
sep = "var.stubs", atStart = FALSE)[, .time_1 := sub(
".", "", .time_1, fixed = TRUE)][]
# sbj blabla .time_1 avg sd
# 1: A bA f1 10 6
# 2: A bA f2 50 10
# 3: B bB f1 12 5
# 4: B bB f2 70 11
# 5: C bC f1 20 7
# 6: C bC f2 20 8
# 7: D bD f1 22 8
# 8: D bD f2 22 9
Zwróć uwagę na użycie argumentu atStart = FALSE
. Dzieje się tak dlatego, że wasze imiona są w nieco innej kolejności niż funkcje związane z przekształceniem. W tym samym roku, w 2010 roku, w Polsce, w 2014 roku, w Polsce i na świecie, w 2015 roku, w Polsce i na świecie.]}
dw2 <- dw
setnames(dw2, gsub("(.*)\\.(.*)", "\\2.\\1", names(dw2)))
names(dw2)
# [1] "sbj" "avg.f1" "sd.f1" "avg.f2" "sd.f2" "blabla"
Gdyby nazwy były w tym formacie zarówno reshape
, jak i merged.stack
korzystają z bardziej bezpośredniej składni:
merged.stack(dw2, var.stubs = c("avg", "sd"), sep = ".")
reshape(dw2, idvar = c("sbj", "blabla"), varying = 2:5,
sep = ".", direction = "long")
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-02 11:35:11
melt
od wersji >=1.9.6 data.table
, robi to poprzez podanie indeksu kolumny w measure.vars
jako list
.
melt(setDT(dw), measure.vars=list(c(2,4), c(3,5)),
variable.name='var', value.name=c('avg', 'sd'))[,
var:= paste0('f',var)][order(sbj)]
# sbj blabla var avg sd
#1: A bA f1 10 6
#2: A bA f2 50 10
#3: B bB f1 12 5
#4: B bB f2 70 11
#5: C bC f1 20 7
#6: C bC f2 20 8
#7: D bD f1 22 8
#8: D bD f2 22 9
Lub możesz użyć nowej funkcji patterns
:
melt(setDT(dw),
measure = patterns("avg", "sd"),
variable.name = 'var', value.name = c('avg', 'sd'))
# sbj blabla var avg sd
# 1: A bA 1 10 6
# 2: B bB 1 12 5
# 3: C bC 1 20 7
# 4: D bD 1 22 8
# 5: A bA 2 50 10
# 6: B bB 2 70 11
# 7: C bC 2 20 8
# 8: D bD 2 22 9
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-26 07:35:57