在 R 中将凌乱的宽数据转换为长数据
transforming messy wide data to long in R
我是 R 的新手,我在尝试将我的 df 从宽转换为长时遇到了一些问题。目前看起来如下:
ppt_num
w.1.rt
w.1.vrt
w.2.rt
w.2.vrt
n.1.rt
n.1.vrt
n.2.rt
n.2.vrt
1
0.90
2.00
1.25
2.05
1.01
1.85
2.06
1.76
2
1.02
2.04
3.02
2.45
1.07
1.95
2.54
1.60
有两个实验条件和两个难度级别。对于实验条件,“w”代表 want 启动,“n”代表 need 启动。对于难度级别,1 表示困难的试验,2 表示简单的试验。最后,rt(反应时间)和 vrt(反应时间方差)是我感兴趣的测量值。我正在尝试重塑我的数据,使其如下所示:
ppt_num
type
difficulty
rt
vrt
1
w
1
0.90
2.00
1
w
2
1.25
2.05
1
n
1
1.01
1.85
2
n
2
2.06
1.76
2
w
1
1.02
2.04
2
w
2
3.02
2.45
2
n
1
1.07
1.95
2
n
2
2.54
1.60
到目前为止,我已经尝试使用 melt() 但这并没有产生预期的结果。
new_df <- melt(df, id.vars = c("ppt_num"))
如有任何关于此处采用的方法的建议,我们将不胜感激。
这里有一个带有 pivot_longer
的选项,我们指定 names_sep
来匹配列名中数字后的 .
,然后 separate
'grp' 列变成 'type' 和 'difficulty'
library(dplyr)
library(tidyr)
df %>%
pivot_longer(cols = -ppt_num, names_to = c('grp', '.value'),
names_sep = '(?<=\d)\.') %>%
separate(grp, into = c('type', 'difficulty'))
-输出
# A tibble: 8 x 5
# ppt_num type difficulty rt vrt
# <int> <chr> <chr> <dbl> <dbl>
#1 1 w 1 0.9 2
#2 1 w 2 1.25 2.05
#3 1 n 1 1.01 1.85
#4 1 n 2 2.06 1.76
#5 2 w 1 1.02 2.04
#6 2 w 2 3.02 2.45
#7 2 n 1 1.07 1.95
#8 2 n 2 2.54 1.6
names_sep
中使用的模式匹配.
(.
是正则表达式中的一个元字符,可以匹配任何字符,所以我们转义得到字面值),后面是一个数字((?<=\d)
- 匹配数字的正则表达式查找)在列名称
数据
df <- structure(list(ppt_num = 1:2, w.1.rt = c(0.9, 1.02), w.1.vrt = c(2,
2.04), w.2.rt = c(1.25, 3.02), w.2.vrt = c(2.05, 2.45), n.1.rt = c(1.01,
1.07), n.1.vrt = c(1.85, 1.95), n.2.rt = c(2.06, 2.54), n.2.vrt = c(1.76,
1.6)), class = "data.frame", row.names = c(NA, -2L))
这是一个基本的 R 选项
reshape(
reshape(
setNames(df, sub("(.*)\.(.*)", "\2-\1", names(df))),
direction = "long",
idvar = "ppt_num",
varying = -1,
timevar = "type"
),
direction = "long",
idvar = c("ppt_num", "type"),
varying = -(1:2),
timevar = "difficulty",
sep = "-"
)
这给出了
ppt_num type difficulty rt vrt
1.1.w 1 1 w 0.90 2.00
2.1.w 2 1 w 1.02 2.04
1.2.w 1 2 w 1.25 2.05
2.2.w 2 2 w 3.02 2.45
1.1.n 1 1 n 1.01 1.85
2.1.n 2 1 n 1.07 1.95
1.2.n 1 2 n 2.06 1.76
2.2.n 2 2 n 2.54 1.60
这里我的版本使用data.table
library(data.table)
dt <- read.table(header = TRUE, text ="ppt_num w.1.rt w.1.vrt w.2.rt w.2.vrt n.1.rt n.1.vrt n.2.rt n.2.vrt
1 0.90 2.00 1.25 2.05 1.01 1.85 2.06 1.76
2 1.02 2.04 3.02 2.45 1.07 1.95 2.54 1.60")
setDT(dt)
dt2 <- melt(dt,id.vars = "ppt_num") #First melt your initial data frame
dt2[,c("type","difficult", "varbl" ):= tstrsplit(variable, "\.")] #Split the new column "variable" containing your ex-column names
dt2$variable<-NULL # I don't need column variable anymore
dcast(dt2,ppt_num+type+difficult~varbl,value.var = "value") #casting your result fixing ppt_num, type, and difficult but sending varbl to columns
ppt_num type difficult rt vrt
1: 1 n 1 1.01 1.85
2: 1 n 2 2.06 1.76
3: 1 w 1 0.90 2.00
4: 1 w 2 1.25 2.05
5: 2 n 1 1.07 1.95
6: 2 n 2 2.54 1.60
7: 2 w 1 1.02 2.04
8: 2 w 2 3.02 2.45
您只能使用 pivot_longer
作为 :
tidyr::pivot_longer(df, cols = -ppt_num,
names_to = c('type', 'difficulty', '.value'),
names_sep = '\.')
# ppt_num type difficulty rt vrt
# <int> <chr> <chr> <dbl> <dbl>
#1 1 w 1 0.9 2
#2 1 w 2 1.25 2.05
#3 1 n 1 1.01 1.85
#4 1 n 2 2.06 1.76
#5 2 w 1 1.02 2.04
#6 2 w 2 3.02 2.45
#7 2 n 1 1.07 1.95
#8 2 n 2 2.54 1.6
我是 R 的新手,我在尝试将我的 df 从宽转换为长时遇到了一些问题。目前看起来如下:
ppt_num | w.1.rt | w.1.vrt | w.2.rt | w.2.vrt | n.1.rt | n.1.vrt | n.2.rt | n.2.vrt |
---|---|---|---|---|---|---|---|---|
1 | 0.90 | 2.00 | 1.25 | 2.05 | 1.01 | 1.85 | 2.06 | 1.76 |
2 | 1.02 | 2.04 | 3.02 | 2.45 | 1.07 | 1.95 | 2.54 | 1.60 |
有两个实验条件和两个难度级别。对于实验条件,“w”代表 want 启动,“n”代表 need 启动。对于难度级别,1 表示困难的试验,2 表示简单的试验。最后,rt(反应时间)和 vrt(反应时间方差)是我感兴趣的测量值。我正在尝试重塑我的数据,使其如下所示:
ppt_num | type | difficulty | rt | vrt |
---|---|---|---|---|
1 | w | 1 | 0.90 | 2.00 |
1 | w | 2 | 1.25 | 2.05 |
1 | n | 1 | 1.01 | 1.85 |
2 | n | 2 | 2.06 | 1.76 |
2 | w | 1 | 1.02 | 2.04 |
2 | w | 2 | 3.02 | 2.45 |
2 | n | 1 | 1.07 | 1.95 |
2 | n | 2 | 2.54 | 1.60 |
到目前为止,我已经尝试使用 melt() 但这并没有产生预期的结果。
new_df <- melt(df, id.vars = c("ppt_num"))
如有任何关于此处采用的方法的建议,我们将不胜感激。
这里有一个带有 pivot_longer
的选项,我们指定 names_sep
来匹配列名中数字后的 .
,然后 separate
'grp' 列变成 'type' 和 'difficulty'
library(dplyr)
library(tidyr)
df %>%
pivot_longer(cols = -ppt_num, names_to = c('grp', '.value'),
names_sep = '(?<=\d)\.') %>%
separate(grp, into = c('type', 'difficulty'))
-输出
# A tibble: 8 x 5
# ppt_num type difficulty rt vrt
# <int> <chr> <chr> <dbl> <dbl>
#1 1 w 1 0.9 2
#2 1 w 2 1.25 2.05
#3 1 n 1 1.01 1.85
#4 1 n 2 2.06 1.76
#5 2 w 1 1.02 2.04
#6 2 w 2 3.02 2.45
#7 2 n 1 1.07 1.95
#8 2 n 2 2.54 1.6
names_sep
中使用的模式匹配.
(.
是正则表达式中的一个元字符,可以匹配任何字符,所以我们转义得到字面值),后面是一个数字((?<=\d)
- 匹配数字的正则表达式查找)在列名称
数据
df <- structure(list(ppt_num = 1:2, w.1.rt = c(0.9, 1.02), w.1.vrt = c(2,
2.04), w.2.rt = c(1.25, 3.02), w.2.vrt = c(2.05, 2.45), n.1.rt = c(1.01,
1.07), n.1.vrt = c(1.85, 1.95), n.2.rt = c(2.06, 2.54), n.2.vrt = c(1.76,
1.6)), class = "data.frame", row.names = c(NA, -2L))
这是一个基本的 R 选项
reshape(
reshape(
setNames(df, sub("(.*)\.(.*)", "\2-\1", names(df))),
direction = "long",
idvar = "ppt_num",
varying = -1,
timevar = "type"
),
direction = "long",
idvar = c("ppt_num", "type"),
varying = -(1:2),
timevar = "difficulty",
sep = "-"
)
这给出了
ppt_num type difficulty rt vrt
1.1.w 1 1 w 0.90 2.00
2.1.w 2 1 w 1.02 2.04
1.2.w 1 2 w 1.25 2.05
2.2.w 2 2 w 3.02 2.45
1.1.n 1 1 n 1.01 1.85
2.1.n 2 1 n 1.07 1.95
1.2.n 1 2 n 2.06 1.76
2.2.n 2 2 n 2.54 1.60
这里我的版本使用data.table
library(data.table)
dt <- read.table(header = TRUE, text ="ppt_num w.1.rt w.1.vrt w.2.rt w.2.vrt n.1.rt n.1.vrt n.2.rt n.2.vrt
1 0.90 2.00 1.25 2.05 1.01 1.85 2.06 1.76
2 1.02 2.04 3.02 2.45 1.07 1.95 2.54 1.60")
setDT(dt)
dt2 <- melt(dt,id.vars = "ppt_num") #First melt your initial data frame
dt2[,c("type","difficult", "varbl" ):= tstrsplit(variable, "\.")] #Split the new column "variable" containing your ex-column names
dt2$variable<-NULL # I don't need column variable anymore
dcast(dt2,ppt_num+type+difficult~varbl,value.var = "value") #casting your result fixing ppt_num, type, and difficult but sending varbl to columns
ppt_num type difficult rt vrt
1: 1 n 1 1.01 1.85
2: 1 n 2 2.06 1.76
3: 1 w 1 0.90 2.00
4: 1 w 2 1.25 2.05
5: 2 n 1 1.07 1.95
6: 2 n 2 2.54 1.60
7: 2 w 1 1.02 2.04
8: 2 w 2 3.02 2.45
您只能使用 pivot_longer
作为 :
tidyr::pivot_longer(df, cols = -ppt_num,
names_to = c('type', 'difficulty', '.value'),
names_sep = '\.')
# ppt_num type difficulty rt vrt
# <int> <chr> <chr> <dbl> <dbl>
#1 1 w 1 0.9 2
#2 1 w 2 1.25 2.05
#3 1 n 1 1.01 1.85
#4 1 n 2 2.06 1.76
#5 2 w 1 1.02 2.04
#6 2 w 2 3.02 2.45
#7 2 n 1 1.07 1.95
#8 2 n 2 2.54 1.6