6.17 长宽格式数据互换
6.17.1 问题
你想要把数据从宽格式转换为长格式。
R中许多函数希望输入的数据是长格式而不是宽格式。然而像 SPSS 软件经常使用宽格式数据。
6.17.2 方案
下面有两类方法:
- tidyr 包的
gather()
和spread()
函数。这 是reshape2 包的一个新接口。 - reshape2包的
melt()
与dcast()
函数。
这里不包含其他一些实现的方法,因为这些方法不是很好使用:
reshape()
函数比较让人迷惑,因为它是 R 基础包的一部分,而不是 reshape2 包的一部分。stack()
和unstack()
6.17.2.1 样例数据
这里使用的数据框包含同样数据的长、宽格式。它们接下来会被相互转换。
olddata_wide <- read.table(header = TRUE, text = "
subject sex control cond1 cond2
1 M 7.9 12.3 10.7
2 F 6.3 10.6 11.1
3 F 9.5 13.1 13.8
4 M 11.5 13.4 12.9
")
# 确保 subject 列是一个因子
olddata_wide$subject <- factor(olddata_wide$subject)
olddata_long <- read.table(header = TRUE, text = "
subject sex condition measurement
1 M control 7.9
1 M cond1 12.3
1 M cond2 10.7
2 F control 6.3
2 F cond1 10.6
2 F cond2 11.1
3 F control 9.5
3 F cond1 13.1
3 F cond2 13.8
4 M control 11.5
4 M cond1 13.4
4 M cond2 12.9
")
# 确保 subject 列是一个因子
olddata_long$subject <- factor(olddata_long$subject)
6.17.2.2 tidyr
6.17.2.2.1 从宽格式到长格式
使用 gather()
:
olddata_wide
#> subject sex control cond1 cond2
#> 1 1 M 7.9 12.3 10.7
#> 2 2 F 6.3 10.6 11.1
#> 3 3 F 9.5 13.1 13.8
#> 4 4 M 11.5 13.4 12.9
library(tidyr)
# gather() 的主要参数: - data: 输入数据 - key:
# 分类key的列名 - value: 包含值的列名 - ...:
# 包换需要转换值的列名 - factor_key:
# 把新的合成列设置为因子
data_long <- gather(olddata_wide, condition, measurement,
control:cond2, factor_key = TRUE)
data_long
#> subject sex condition measurement
#> 1 1 M control 7.9
#> 2 2 F control 6.3
#> 3 3 F control 9.5
#> 4 4 M control 11.5
#> 5 1 M cond1 12.3
#> 6 2 F cond1 10.6
#> 7 3 F cond1 13.1
#> 8 4 M cond1 13.4
#> 9 1 M cond2 10.7
#> 10 2 F cond2 11.1
#> 11 3 F cond2 13.8
#> 12 4 M cond2 12.9
在这个例子中,来源列通过 control:cond2
指定聚集到一起。这里的意思是使用位置上在 control
和 conda2
之间(包括 control
与 conda2
)的所有列。另一种使用的方式是单独为每一列命名,如下:
gather(olddata_wide, condition, measurement, control, cond1,
cond2)
#> subject sex condition measurement
#> 1 1 M control 7.9
#> 2 2 F control 6.3
#> 3 3 F control 9.5
#> 4 4 M control 11.5
#> 5 1 M cond1 12.3
#> 6 2 F cond1 10.6
#> 7 3 F cond1 13.1
#> 8 4 M cond1 13.4
#> 9 1 M cond2 10.7
#> 10 2 F cond2 11.1
#> 11 3 F cond2 13.8
#> 12 4 M cond2 12.9
如果你需要编程化使用gather()
函数,可能需要使用包含列名的变量。想要实现它的话,你需要使用 gather_()
函数,它会使用字符串而不是没加引号的列名。
keycol <- "condition"
valuecol <- "measurement"
gathercols <- c("control", "cond1", "cond2")
gather_(olddata_wide, keycol, valuecol, gathercols)
#> subject sex condition measurement
#> 1 1 M control 7.9
#> 2 2 F control 6.3
#> 3 3 F control 9.5
#> 4 4 M control 11.5
#> 5 1 M cond1 12.3
#> 6 2 F cond1 10.6
#> 7 3 F cond1 13.1
#> 8 4 M cond1 13.4
#> 9 1 M cond2 10.7
#> 10 2 F cond2 11.1
#> 11 3 F cond2 13.8
#> 12 4 M cond2 12.9
可选内容:重命名变量列的因子水平并排序。
# 重命名因子水平
levels(data_long$condition)[levels(data_long$condition) ==
"cond1"] <- "first"
levels(data_long$condition)[levels(data_long$condition) ==
"cond2"] <- "second"
# 首先按照 subject 排序,然后按 condition
data_long <- data_long[order(data_long$subject, data_long$condition),
]
data_long
#> subject sex condition measurement
#> 1 1 M control 7.9
#> 5 1 M first 12.3
#> 9 1 M second 10.7
#> 2 2 F control 6.3
#> 6 2 F first 10.6
#> 10 2 F second 11.1
#> 3 3 F control 9.5
#> 7 3 F first 13.1
#> 11 3 F second 13.8
#> 4 4 M control 11.5
#> 8 4 M first 13.4
#> 12 4 M second 12.9
6.17.2.2.2 从长格式到宽格式
使用 spread()
:
olddata_long
#> subject sex condition measurement
#> 1 1 M control 7.9
#> 2 1 M cond1 12.3
#> 3 1 M cond2 10.7
#> 4 2 F control 6.3
#> 5 2 F cond1 10.6
#> 6 2 F cond2 11.1
#> 7 3 F control 9.5
#> 8 3 F cond1 13.1
#> 9 3 F cond2 13.8
#> 10 4 M control 11.5
#> 11 4 M cond1 13.4
#> 12 4 M cond2 12.9
library(tidyr)
# spread() 主要参数: - data: 数据对象 - key:
# 包含新列名的列名 - value: 包含值得列名
data_wide <- spread(olddata_long, condition, measurement)
data_wide
#> subject sex cond1 cond2 control
#> 1 1 M 12.3 10.7 7.9
#> 2 2 F 10.6 11.1 6.3
#> 3 3 F 13.1 13.8 9.5
#> 4 4 M 13.4 12.9 11.5
可选项:一些可以使数据看起来更易读的操作。
# 重命名
names(data_wide)[names(data_wide) == "cond1"] <- "first"
names(data_wide)[names(data_wide) == "cond2"] <- "second"
# 排序
data_wide <- data_wide[, c(1, 2, 5, 3, 4)]
data_wide
#> subject sex control first second
#> 1 1 M 7.9 12.3 10.7
#> 2 2 F 6.3 10.6 11.1
#> 3 3 F 9.5 13.1 13.8
#> 4 4 M 11.5 13.4 12.9
因子水平的顺序决定了列的顺序。水平次序能够在重塑之前被改变,或者列也可以在之后重新排序。
6.17.2.3 reshape2
6.17.2.3.1 从宽格式到长格式
使用 melt()
:
olddata_wide
#> subject sex control cond1 cond2
#> 1 1 M 7.9 12.3 10.7
#> 2 2 F 6.3 10.6 11.1
#> 3 3 F 9.5 13.1 13.8
#> 4 4 M 11.5 13.4 12.9
library(reshape2)
#>
#> Attaching package: 'reshape2'
#> The following object is masked from 'package:tidyr':
#>
#> smiths
# 指定id.vars:需要保持的变量名
melt(olddata_wide, id.vars = c("subject", "sex"))
#> subject sex variable value
#> 1 1 M control 7.9
#> 2 2 F control 6.3
#> 3 3 F control 9.5
#> 4 4 M control 11.5
#> 5 1 M cond1 12.3
#> 6 2 F cond1 10.6
#> 7 3 F cond1 13.1
#> 8 4 M cond1 13.4
#> 9 1 M cond2 10.7
#> 10 2 F cond2 11.1
#> 11 3 F cond2 13.8
#> 12 4 M cond2 12.9
melt()
的一些选项可以使得输出更好处理:
data_long <- melt(olddata_wide,
# 变量ID,需要保持的变量名
id.vars=c("subject", "sex"),
# 来源列(被转换的)
measure.vars=c("control", "cond1", "cond2" ),
# 目的列的名字可以确定测量列数值的来自的原始列(变量)
# 这里 measurement 是数值,condition 指定了其来源
variable.name="condition",
value.name="measurement"
)
data_long
#> subject sex condition measurement
#> 1 1 M control 7.9
#> 2 2 F control 6.3
#> 3 3 F control 9.5
#> 4 4 M control 11.5
#> 5 1 M cond1 12.3
#> 6 2 F cond1 10.6
#> 7 3 F cond1 13.1
#> 8 4 M cond1 13.4
#> 9 1 M cond2 10.7
#> 10 2 F cond2 11.1
#> 11 3 F cond2 13.8
#> 12 4 M cond2 12.9
如果你不设定 measure.vars
,melt()
函数会自动使用除 id.vars
的所有其他变量。反之亦然。
如果你不指定 variable.name
,它会把那列命名为"variable"
,如果你不使用 value.name
变量,它会将它命名为 "measurement"
。
可选项:重命名变量列的因子水平。
# 重命名因子
levels(data_long$condition)[levels(data_long$condition) ==
"cond1"] <- "first"
levels(data_long$condition)[levels(data_long$condition) ==
"cond2"] <- "second"
# 首先按 subject 排序,然后按 condition 排序
data_long <- data_long[order(data_long$subject, data_long$condition),
]
data_long
#> subject sex condition measurement
#> 1 1 M control 7.9
#> 5 1 M first 12.3
#> 9 1 M second 10.7
#> 2 2 F control 6.3
#> 6 2 F first 10.6
#> 10 2 F second 11.1
#> 3 3 F control 9.5
#> 7 3 F first 13.1
#> 11 3 F second 13.8
#> 4 4 M control 11.5
#> 8 4 M first 13.4
#> 12 4 M second 12.9
6.17.2.3.2 从长格式到宽格式
下面代码使用 dcast()
函数重塑数据。这个函数用于数据框,如果你处理数组或矩阵,替换使用 acast()
。
olddata_long
#> subject sex condition measurement
#> 1 1 M control 7.9
#> 2 1 M cond1 12.3
#> 3 1 M cond2 10.7
#> 4 2 F control 6.3
#> 5 2 F cond1 10.6
#> 6 2 F cond2 11.1
#> 7 3 F control 9.5
#> 8 3 F cond1 13.1
#> 9 3 F cond2 13.8
#> 10 4 M control 11.5
#> 11 4 M cond1 13.4
#> 12 4 M cond2 12.9
# 信息: 'subject' 和 'sex' 是我们想要保留的列
# 'condition' 是我们想要放入新列名的列 'measurement'
# 包含数值
library(reshape2)
data_wide <- dcast(olddata_long, subject + sex ~ condition,
value.var = "measurement")
data_wide
#> subject sex cond1 cond2 control
#> 1 1 M 12.3 10.7 7.9
#> 2 2 F 10.6 11.1 6.3
#> 3 3 F 13.1 13.8 9.5
#> 4 4 M 13.4 12.9 11.5
可选项:一些可以使数据看起来更易读的操作。
# 重命名
names(data_wide)[names(data_wide) == "cond1"] <- "first"
names(data_wide)[names(data_wide) == "cond2"] <- "second"
# 重排序
data_wide <- data_wide[, c(1, 2, 5, 3, 4)]
data_wide
#> subject sex control first second
#> 1 1 M 7.9 12.3 10.7
#> 2 2 F 6.3 10.6 11.1
#> 3 3 F 9.5 13.1 13.8
#> 4 4 M 11.5 13.4 12.9
因子水平的顺序决定了列的顺序。水平次序能够在重塑之前被改变,或者列也可以在之后重新排序。