前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >「R」长宽格式互换

「R」长宽格式互换

作者头像
王诗翔呀
发布2020-07-03 09:36:32
9610
发布2020-07-03 09:36:32
举报
文章被收录于专栏:优雅R

问题

你想要把数据从宽格式转换为长格式。

R中许多函数希望输入的数据是长格式而不是宽格式。然而像 SPSS 软件经常使用宽格式数据。

方案

下面有两类方法:

  • tidyr 包的 gather()spread() 函数。这 是reshape2 包的一个新接口。
  • reshape2包的 melt()dcast() 函数。

这里不包含其他一些实现的方法,因为这些方法不是很好使用:

  • reshape() 函数比较让人迷惑,因为它是 R 基础包的一部分,而不是 reshape2 包的一部分。
  • stack()unstack()

样例数据

这里使用的数据框包含同样数据的长、宽格式。它们接下来会被相互转换。

代码语言:javascript
复制
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)

tidyr

从宽格式到长格式

使用 gather():

代码语言:javascript
复制
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 指定聚集到一起。这里的意思是使用位置上在 controlconda2 之间(包括 controlconda2 )的所有列。另一种使用的方式是单独为每一列命名,如下:

代码语言:javascript
复制
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_() 函数,它会使用字符串而不是没加引号的列名。

代码语言:javascript
复制
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

可选内容:重命名变量列的因子水平并排序。

代码语言:javascript
复制
# 重命名因子水平
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

从长格式到宽格式

使用 spread():

代码语言:javascript
复制
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

可选项:一些可以使数据看起来更易读的操作。

代码语言:javascript
复制
# 重命名
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

因子水平的顺序决定了列的顺序。水平次序能够在重塑之前被改变,或者列也可以在之后重新排序。

reshape2

从宽格式到长格式

使用 melt():

代码语言:javascript
复制
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() 的一些选项可以使得输出更好处理:

代码语言:javascript
复制
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.varsmelt() 函数会自动使用除 id.vars 的所有其他变量。反之亦然。

如果你不指定 variable.name,它会把那列命名为"variable",如果你不使用 value.name 变量,它会将它命名为 "measurement"

可选项:重命名变量列的因子水平。

代码语言:javascript
复制
# 重命名因子
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

从长格式到宽格式

下面代码使用 dcast() 函数重塑数据。这个函数用于数据框,如果你处理数组或矩阵,替换使用 acast()

代码语言:javascript
复制
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

可选项:一些可以使数据看起来更易读的操作。

代码语言:javascript
复制
# 重命名
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

因子水平的顺序决定了列的顺序。水平次序能够在重塑之前被改变,或者列也可以在之后重新排序。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 优雅R 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题
  • 方案
  • 样例数据
  • tidyr
    • 从宽格式到长格式
      • 从长格式到宽格式
      • reshape2
        • 从宽格式到长格式
          • 从长格式到宽格式
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档