Lösungen mit angegeben
Paket von Hadley Wickham. Teil von tidyverse
Ziel sind tidy data
tidyr documentation
Befehle:
tidyr::gather() # wide -> long
tidyr::spread() # long -> wide
tidyr::separate() # seperate one column in multiple columns (generating adequate factors)
tidyr::extract() #
tidyr::unite() # Unite multiple columns into one, complement to separate()
vignette("tidy-data")
demo(package = "tidyr")
subj: Versuchsperson gender: ‘f’, ‘m’ t1: AV Zeitpunkt 1 t2: AV Zeitpunkt 2
# wide format
df <- data.frame(
subj = c(1,2,3,4),
gender = c('f', 'f', 'm', 'm'),
t1 = c(4, 5, 7, 6),
t2 = c(6, 5, 9, 8)
)
require(tidyr)
## Loading required package: tidyr
df.t <- df %>% tidyr::gather(key=time, value=dv, t1, t2)
# or even shorter: key and value can be used as positional parameters too
df.t <- df %>% tidyr::gather(time, dv, t1, t2)
# we want to have all repeated measures for each person in consecutive lines
df.t %>% dplyr::arrange(subj, time) -> df.t
# we notice that variables subj and gender are kept and adequately repeated
df.t
## subj gender time dv
## 1 1 f t1 4
## 2 1 f t2 6
## 3 2 f t1 5
## 4 2 f t2 5
## 5 3 m t1 7
## 6 3 m t2 9
## 7 4 m t1 6
## 8 4 m t2 8
AV Zahl reproduzierter Silben subj: Versuchsperson gender: ‘f’, ‘m’ mnemotechnik: ‘m’, ‘c’ t1: AV Zeitpunkt 1 t2: AV Zeitpunkt 2 t3: AV Zeitpunkt 3
Die Idee hinter dem Umbau von wide nach long ist hier: - wandle im ersten Schritt alle Messwiederholungswerte in eine Spalte um. - Die Information, aus welcher Spalte die Werte stammen, stehen dann in der neu generierten Spalte mit Namen des Paramter ‘key’ bzw. des zweiten Parameters des gather-Befehls. - in einem weiteren Befehl werden die Infos aus der neu generierten key-Spalte in neue Spalten aufgesplittet, die die jeweils relevanten Informationen für den Messwiederholungsfaktor enthalten. Die Key-Spalte wird quasi entschlüsselt.
# we generate data frame in wide format
df <- data.frame(
subj = c(1,2,3,4),
gender = c('f', 'f', 'm', 'm'),
t1c = c( 4, 5, 7, 6),
t2c = c( 6, 5, 9, 8),
t3c = c( 7, 6, 12, 10),
t1m = c( 8, 6, 15, 10),
t2m = c(12, 7, 19, 13),
t3m = c(13, 7, 22, 14)
)
# take a look at it
df
## subj gender t1c t2c t3c t1m t2m t3m
## 1 1 f 4 6 7 8 12 13
## 2 2 f 5 5 6 6 7 7
## 3 3 m 7 9 12 15 19 22
## 4 4 m 6 8 10 10 13 14
# we gather all repeated measure variables at once
require(tidyr)
df.t <- df %>% tidyr::gather(key=m_t, value=dv, t1c:t3m)
# now we have all information mixed in column m_t
head(df.t)
## subj gender m_t dv
## 1 1 f t1c 4
## 2 2 f t1c 5
## 3 3 m t1c 7
## 4 4 m t1c 6
## 5 1 f t2c 6
## 6 2 f t2c 5
# we make new columns to specify the repeated measure factors using the position in source column name and preserving source column to control what's happening
df.t %>% tidyr::separate(m_t, c("time", "cond"), 2, 1, remove=F) -> df.t # 2, 1 refer to the number of letters in value strings
df.t %>% tidyr::separate(m_t, c("time", "cond"), 2, -1, remove=F) -> df.t # -1 refers to the last letter in value string
# more separation techniques are possible
head(df.t)
## subj gender m_t time cond dv
## 1 1 f t1c t1 c 4
## 2 2 f t1c t1 c 5
## 3 3 m t1c t1 c 7
## 4 4 m t1c t1 c 6
## 5 1 f t2c t2 c 6
## 6 2 f t2c t2 c 5
# we want to have all repeated measures for each person in consecutive lines and reorder the data frame
head(df.t)
## subj gender m_t time cond dv
## 1 1 f t1c t1 c 4
## 2 2 f t1c t1 c 5
## 3 3 m t1c t1 c 7
## 4 4 m t1c t1 c 6
## 5 1 f t2c t2 c 6
## 6 2 f t2c t2 c 5
Befehle in diesem Kontext
stack()
und unstack()
library(reshape2)
melt()
wide -> long format cast()
long -> wide (und noch mehr)
library(reshape2)
und library(reshape)
haben namespace Probleme, beispielsweise bei ‘variable.name’, ‘value.name’ und ‘variable_name’. Um reshape2 sauber zu verwenden, muss reshape entladen sein detach(package:reshape)
.
subj: Versuchsperson gender: ‘f’, ‘m’ t1: AV Zeitpunkt 1 t2: AV Zeitpunkt 2
# wide format
dd <- data.frame(
subj = c(1,2,3,4),
gender = c('f', 'f', 'm', 'm'),
t1 = c(4, 5, 7, 6),
t2 = c(6, 5, 9, 8)
)
# we could also have used reshape2
require("reshape2")
## Loading required package: reshape2
##
## Attaching package: 'reshape2'
## The following object is masked from 'package:tidyr':
##
## smiths
## subj gender variable value
## 1 1 f t1 4
## 2 2 f t1 5
## 3 3 m t1 7
## 4 4 m t1 6
## 5 1 f t2 6
## 6 2 f t2 5
## 7 3 m t2 9
## 8 4 m t2 8
# more verbatim
dd.t <- reshape2::melt(dd, id=c('subj', 'gender'), variable.name="time", value.name="dv", measured=c('t1', 't2'))
dd.t
## subj gender time dv
## 1 1 f t1 4
## 2 2 f t1 5
## 3 3 m t1 7
## 4 4 m t1 6
## 5 1 f t2 6
## 6 2 f t2 5
## 7 3 m t2 9
## 8 4 m t2 8
# the same using tidyr of tidyverse
# cf vignette("tidy-data")
require(tidyr)
# the values of the two columns t1 and t2 are gathered in one column called dv
# a new column "time" is created, where t1 and t2 are coded (factor levels)
dd %>% tidyr::gather(time, dv, t1, t2) -> dd.l
dd.l
## subj gender time dv
## 1 1 f t1 4
## 2 2 f t1 5
## 3 3 m t1 7
## 4 4 m t1 6
## 5 1 f t2 6
## 6 2 f t2 5
## 7 3 m t2 9
## 8 4 m t2 8
# change to wide format
# factor levels of column time become column names
# dv values are put to columns, which names are equal to factor levels of column time
dd.l %>% tidyr::spread(time, dv)
## subj gender t1 t2
## 1 1 f 4 6
## 2 2 f 5 5
## 3 3 m 7 9
## 4 4 m 6 8
Grundidee: Datentabelle in Teiltabellen aufteilen, Info-Spalte hinzufügen und Teiltabellen wieder zusammenfügen.
# wide format
dd <- data.frame(
subj = c(1,2,3,4),
gender = c('f', 'f', 'm', 'm'),
t1 = c(4, 5, 7, 6),
t2 = c(6, 5, 9, 8)
)
# we create a dataframe of t1 data
# dd.t1 <- dd[1:3] # or more verbose
dd.t1 <- dd[, c('subj', 'gender', 't1')]
# we rename column t1
dd.t1['y'] <- dd.t1$t1
dd.t1$t1 <- NULL
# and add t1 info
dd.t1['time'] <- 't1'
# the same wit t2 data
dd.t2 <- dd[, c('subj', 'gender', 't2')]
# and add t1 info
dd.t2['time'] <- 't2'
# we rename column t2
dd.t2['y'] <- dd.t2$t2
dd.t2$t2 <- NULL
# we now merge the two parts
dd.t <- rbind(dd.t1, dd.t2)
Stai State sei erhoben worden von männlichen und weiblichen Studierenden.
Erhoben wurde in 3 Situationen:
Die Studierenden hatten in ihrem Abitur eine niedrige (lo), eine durchschnittliche (av) oder eine gute (hi) Note in Mathematik.
## Loading required package: psych
# minimal example
ddf <- read.delim("http://md.psych.bio.uni-goettingen.de/data/virt/v_stait_exam_wide.txt")
# what is in there
head(ddf)
## subj gender group neutr exam1 exam2
## 1 1 f av 42 52 48
## 2 2 f av 59 68 65
## 3 3 f av 49 59 55
## 4 4 f av 20 31 27
## 5 5 f av 45 55 51
## 6 6 f av 39 49 45
## vars n mean sd median trimmed mad min max range skew
## subj 1 180 90.50 52.11 90.5 90.50 66.72 1 180 179 0.00
## gender* 2 180 1.50 0.50 1.5 1.50 0.74 1 2 1 0.00
## group* 3 180 2.00 0.82 2.0 2.00 1.48 1 3 2 0.00
## neutr 4 180 43.84 14.97 42.0 43.44 15.57 5 89 84 0.25
## exam1 5 180 50.19 15.62 48.5 49.47 15.57 16 98 82 0.44
## exam2 6 180 50.43 14.96 49.0 50.08 16.31 12 95 83 0.21
## kurtosis se
## subj -1.22 3.88
## gender* -2.01 0.04
## group* -1.52 0.06
## neutr -0.06 1.12
## exam1 -0.13 1.16
## exam2 -0.13 1.11
Die Daten spiegeln eine Struktur, wie sie von vielen Statistikpaketen verlangt wird. Pro Zeile eine Versuchsperson (Beobachtungseinheit). Alle Daten dieser Zeile sind Daten dieser Beobachtungseinheit. Hieraus folgt, dass ‘neutral’, ‘exam1’ und ‘exam2’ Messwiederholungsdaten sein müssen.
R verlangt bei Messwiederholungen das ‘long format’. Eine Beobachtung im gegebenen Beispiel ist eine Kombination aus Zeitpunkt und Versuchsperson. Hier werden auch die Messwiederholungsvariablen im Data-Frame so angeordnet, als seien es Beobachtungen (im klassischen Sinn). Die Unterscheidung von unabhängigen und abhängigen Variablen (between subjects und within subjects) erfolgt über die Formulae beim Aufruf der entsprechenden Auswertungsmethoden. Im Long-Format werden auch die Messwiederholungsdaten über eigene Variablen kodiert, nicht nur die Zugehörigkeit der Beobachtungen zu bestimmten (Sub-)Gruppen. Die zu einer Beobachtung gehörenden ‘Gruppierungsvariablen’ werden im Long-Format entsprechend wiederholt.
ddf <- read.delim("http://md.psych.bio.uni-goettingen.de/data/virt/v_stait_exam_wide.txt")
require("tidyr")
# convert it to long format
ddf.r <- ddf %>% tidyr::gather(key=situation, value=dv, neutr, exam1, exam2)
# show it
head(ddf.r)
## subj gender group situation dv
## 1 1 f av neutr 42
## 2 2 f av neutr 59
## 3 3 f av neutr 49
## 4 4 f av neutr 20
## 5 5 f av neutr 45
## 6 6 f av neutr 39
require("reshape2")
ddf <- read.delim("http://md.psych.bio.uni-goettingen.de/data/virt/v_stait_exam_wide.txt")
# convert it to long format
ddf.r <- melt(ddf, id=c('subj','gender', 'group'), variable.name="sit", value.name="anx", measured=c('neutr', 'exam1', 'exam2'))
# show it
head(ddf.r)
## subj gender group sit anx
## 1 1 f av neutr 42
## 2 2 f av neutr 59
## 3 3 f av neutr 49
## 4 4 f av neutr 20
## 5 5 f av neutr 45
## 6 6 f av neutr 39
# sequence of id variables matters for the sequence of columns in the newly created data frame
head(melt(ddf, id=c('subj', 'group', 'gender'), variable.name="sit", value.name="anx", measured=c('exam1', 'exam2', 'neutr')))
## subj group gender sit anx
## 1 1 av f neutr 42
## 2 2 av f neutr 59
## 3 3 av f neutr 49
## 4 4 av f neutr 20
## 5 5 av f neutr 45
## 6 6 av f neutr 39
Sollte es notwendig sein, die Daten aus dem Long-Format in das Wide-Format zurückzuwandeln, kann der Befehl dcast()
(für Data-Frames) aus der library(reshape2)
verwendet werden.
require("reshape2")
ddf <- read.delim("http://md.psych.bio.uni-goettingen.de/data/virt/v_stait_exam_wide.txt")
# convert it to long format
ddf.r <- melt(ddf, id=c('subj','gender', 'group'), measured=c('neutr', 'exam1', 'exam2'))
# convert long format back to wide format
head(dcast(ddf.r, subj + gender + group ~ variable, value ="value"))
## subj gender group neutr exam1 exam2
## 1 1 f av 42 52 48
## 2 2 f av 59 68 65
## 3 3 f av 49 59 55
## 4 4 f av 20 31 27
## 5 5 f av 45 55 51
## 6 6 f av 39 49 45
## subj gender group neutr exam1 exam2
## 1 1 f av 42 52 48
## 2 2 f av 59 68 65
## 3 3 f av 49 59 55
## 4 4 f av 20 31 27
## 5 5 f av 45 55 51
## 6 6 f av 39 49 45
Erstellen Sie ein Dataframe im Long-Format, mit dem Sie die Messzeitpunkte 1 und 2 hinsichtlich der STAI-Skalen vergleichen können. Daten
Lösung
require(tidyverse)
dd <- read_delim("http://md.psych.bio.uni-goettingen.de/data/div/stud_stai_scales_utf8.txt", delim='\t')
## Parsed with column specification:
## cols(
## .default = col_double(),
## code = col_character(),
## ageschl = col_character(),
## haar = col_character(),
## auge = col_character(),
## raucher = col_character(),
## geschw = col_character(),
## code2 = col_character(),
## ageschl2 = col_character(),
## haar2 = col_character(),
## augen2 = col_character(),
## raucher2 = col_character()
## )
## See spec(...) for full column specifications.
Reshaping Your Data with tidyr
Tidyr reference
Reorganizing the data for within subject analyses in Link
Sean C. Anderson (2013) An Introduction to reshape2
https://stackoverflow.com/questions/5890584/how-to-reshape-data-from-long-to-wide-format
https://stackoverflow.com/questions/9341865/alternatives-to-statsreshape