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 样例数据

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

  1. olddata_wide <- read.table(header = TRUE, text = "
  2. subject sex control cond1 cond2
  3. 1 M 7.9 12.3 10.7
  4. 2 F 6.3 10.6 11.1
  5. 3 F 9.5 13.1 13.8
  6. 4 M 11.5 13.4 12.9
  7. ")
  8. # 确保 subject 列是一个因子
  9. olddata_wide$subject <- factor(olddata_wide$subject)
  1. olddata_long <- read.table(header = TRUE, text = "
  2. subject sex condition measurement
  3. 1 M control 7.9
  4. 1 M cond1 12.3
  5. 1 M cond2 10.7
  6. 2 F control 6.3
  7. 2 F cond1 10.6
  8. 2 F cond2 11.1
  9. 3 F control 9.5
  10. 3 F cond1 13.1
  11. 3 F cond2 13.8
  12. 4 M control 11.5
  13. 4 M cond1 13.4
  14. 4 M cond2 12.9
  15. ")
  16. # 确保 subject 列是一个因子
  17. olddata_long$subject <- factor(olddata_long$subject)

6.17.2.2 tidyr

6.17.2.2.1 从宽格式到长格式

使用 gather():

  1. olddata_wide
  2. #> subject sex control cond1 cond2
  3. #> 1 1 M 7.9 12.3 10.7
  4. #> 2 2 F 6.3 10.6 11.1
  5. #> 3 3 F 9.5 13.1 13.8
  6. #> 4 4 M 11.5 13.4 12.9
  7. library(tidyr)
  8. # gather() 的主要参数: - data: 输入数据 - key:
  9. # 分类key的列名 - value: 包含值的列名 - ...:
  10. # 包换需要转换值的列名 - factor_key:
  11. # 把新的合成列设置为因子
  12. data_long <- gather(olddata_wide, condition, measurement,
  13. control:cond2, factor_key = TRUE)
  14. data_long
  15. #> subject sex condition measurement
  16. #> 1 1 M control 7.9
  17. #> 2 2 F control 6.3
  18. #> 3 3 F control 9.5
  19. #> 4 4 M control 11.5
  20. #> 5 1 M cond1 12.3
  21. #> 6 2 F cond1 10.6
  22. #> 7 3 F cond1 13.1
  23. #> 8 4 M cond1 13.4
  24. #> 9 1 M cond2 10.7
  25. #> 10 2 F cond2 11.1
  26. #> 11 3 F cond2 13.8
  27. #> 12 4 M cond2 12.9

在这个例子中,来源列通过 control:cond2 指定聚集到一起。这里的意思是使用位置上在 controlconda2 之间(包括 controlconda2 )的所有列。另一种使用的方式是单独为每一列命名,如下:

  1. gather(olddata_wide, condition, measurement, control, cond1,
  2. cond2)
  3. #> subject sex condition measurement
  4. #> 1 1 M control 7.9
  5. #> 2 2 F control 6.3
  6. #> 3 3 F control 9.5
  7. #> 4 4 M control 11.5
  8. #> 5 1 M cond1 12.3
  9. #> 6 2 F cond1 10.6
  10. #> 7 3 F cond1 13.1
  11. #> 8 4 M cond1 13.4
  12. #> 9 1 M cond2 10.7
  13. #> 10 2 F cond2 11.1
  14. #> 11 3 F cond2 13.8
  15. #> 12 4 M cond2 12.9

如果你需要编程化使用gather()函数,可能需要使用包含列名的变量。想要实现它的话,你需要使用 gather_() 函数,它会使用字符串而不是没加引号的列名。

  1. keycol <- "condition"
  2. valuecol <- "measurement"
  3. gathercols <- c("control", "cond1", "cond2")
  4. gather_(olddata_wide, keycol, valuecol, gathercols)
  5. #> subject sex condition measurement
  6. #> 1 1 M control 7.9
  7. #> 2 2 F control 6.3
  8. #> 3 3 F control 9.5
  9. #> 4 4 M control 11.5
  10. #> 5 1 M cond1 12.3
  11. #> 6 2 F cond1 10.6
  12. #> 7 3 F cond1 13.1
  13. #> 8 4 M cond1 13.4
  14. #> 9 1 M cond2 10.7
  15. #> 10 2 F cond2 11.1
  16. #> 11 3 F cond2 13.8
  17. #> 12 4 M cond2 12.9

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

  1. # 重命名因子水平
  2. levels(data_long$condition)[levels(data_long$condition) ==
  3. "cond1"] <- "first"
  4. levels(data_long$condition)[levels(data_long$condition) ==
  5. "cond2"] <- "second"
  6. # 首先按照 subject 排序,然后按 condition
  7. data_long <- data_long[order(data_long$subject, data_long$condition),
  8. ]
  9. data_long
  10. #> subject sex condition measurement
  11. #> 1 1 M control 7.9
  12. #> 5 1 M first 12.3
  13. #> 9 1 M second 10.7
  14. #> 2 2 F control 6.3
  15. #> 6 2 F first 10.6
  16. #> 10 2 F second 11.1
  17. #> 3 3 F control 9.5
  18. #> 7 3 F first 13.1
  19. #> 11 3 F second 13.8
  20. #> 4 4 M control 11.5
  21. #> 8 4 M first 13.4
  22. #> 12 4 M second 12.9
6.17.2.2.2 从长格式到宽格式

使用 spread():

  1. olddata_long
  2. #> subject sex condition measurement
  3. #> 1 1 M control 7.9
  4. #> 2 1 M cond1 12.3
  5. #> 3 1 M cond2 10.7
  6. #> 4 2 F control 6.3
  7. #> 5 2 F cond1 10.6
  8. #> 6 2 F cond2 11.1
  9. #> 7 3 F control 9.5
  10. #> 8 3 F cond1 13.1
  11. #> 9 3 F cond2 13.8
  12. #> 10 4 M control 11.5
  13. #> 11 4 M cond1 13.4
  14. #> 12 4 M cond2 12.9
  15. library(tidyr)
  16. # spread() 主要参数: - data: 数据对象 - key:
  17. # 包含新列名的列名 - value: 包含值得列名
  18. data_wide <- spread(olddata_long, condition, measurement)
  19. data_wide
  20. #> subject sex cond1 cond2 control
  21. #> 1 1 M 12.3 10.7 7.9
  22. #> 2 2 F 10.6 11.1 6.3
  23. #> 3 3 F 13.1 13.8 9.5
  24. #> 4 4 M 13.4 12.9 11.5

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

  1. # 重命名
  2. names(data_wide)[names(data_wide) == "cond1"] <- "first"
  3. names(data_wide)[names(data_wide) == "cond2"] <- "second"
  4. # 排序
  5. data_wide <- data_wide[, c(1, 2, 5, 3, 4)]
  6. data_wide
  7. #> subject sex control first second
  8. #> 1 1 M 7.9 12.3 10.7
  9. #> 2 2 F 6.3 10.6 11.1
  10. #> 3 3 F 9.5 13.1 13.8
  11. #> 4 4 M 11.5 13.4 12.9

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

6.17.2.3 reshape2

6.17.2.3.1 从宽格式到长格式

使用 melt():

  1. olddata_wide
  2. #> subject sex control cond1 cond2
  3. #> 1 1 M 7.9 12.3 10.7
  4. #> 2 2 F 6.3 10.6 11.1
  5. #> 3 3 F 9.5 13.1 13.8
  6. #> 4 4 M 11.5 13.4 12.9
  7. library(reshape2)
  8. #>
  9. #> Attaching package: 'reshape2'
  10. #> The following object is masked from 'package:tidyr':
  11. #>
  12. #> smiths
  13. # 指定id.vars:需要保持的变量名
  14. melt(olddata_wide, id.vars = c("subject", "sex"))
  15. #> subject sex variable value
  16. #> 1 1 M control 7.9
  17. #> 2 2 F control 6.3
  18. #> 3 3 F control 9.5
  19. #> 4 4 M control 11.5
  20. #> 5 1 M cond1 12.3
  21. #> 6 2 F cond1 10.6
  22. #> 7 3 F cond1 13.1
  23. #> 8 4 M cond1 13.4
  24. #> 9 1 M cond2 10.7
  25. #> 10 2 F cond2 11.1
  26. #> 11 3 F cond2 13.8
  27. #> 12 4 M cond2 12.9

melt() 的一些选项可以使得输出更好处理:

  1. data_long <- melt(olddata_wide,
  2. # 变量ID,需要保持的变量名
  3. id.vars=c("subject", "sex"),
  4. # 来源列(被转换的)
  5. measure.vars=c("control", "cond1", "cond2" ),
  6. # 目的列的名字可以确定测量列数值的来自的原始列(变量)
  7. # 这里 measurement 是数值,condition 指定了其来源
  8. variable.name="condition",
  9. value.name="measurement"
  10. )
  11. data_long
  12. #> subject sex condition measurement
  13. #> 1 1 M control 7.9
  14. #> 2 2 F control 6.3
  15. #> 3 3 F control 9.5
  16. #> 4 4 M control 11.5
  17. #> 5 1 M cond1 12.3
  18. #> 6 2 F cond1 10.6
  19. #> 7 3 F cond1 13.1
  20. #> 8 4 M cond1 13.4
  21. #> 9 1 M cond2 10.7
  22. #> 10 2 F cond2 11.1
  23. #> 11 3 F cond2 13.8
  24. #> 12 4 M cond2 12.9

如果你不设定 measure.varsmelt() 函数会自动使用除 id.vars 的所有其他变量。反之亦然。

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

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

  1. # 重命名因子
  2. levels(data_long$condition)[levels(data_long$condition) ==
  3. "cond1"] <- "first"
  4. levels(data_long$condition)[levels(data_long$condition) ==
  5. "cond2"] <- "second"
  6. # 首先按 subject 排序,然后按 condition 排序
  7. data_long <- data_long[order(data_long$subject, data_long$condition),
  8. ]
  9. data_long
  10. #> subject sex condition measurement
  11. #> 1 1 M control 7.9
  12. #> 5 1 M first 12.3
  13. #> 9 1 M second 10.7
  14. #> 2 2 F control 6.3
  15. #> 6 2 F first 10.6
  16. #> 10 2 F second 11.1
  17. #> 3 3 F control 9.5
  18. #> 7 3 F first 13.1
  19. #> 11 3 F second 13.8
  20. #> 4 4 M control 11.5
  21. #> 8 4 M first 13.4
  22. #> 12 4 M second 12.9
6.17.2.3.2 从长格式到宽格式

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

  1. olddata_long
  2. #> subject sex condition measurement
  3. #> 1 1 M control 7.9
  4. #> 2 1 M cond1 12.3
  5. #> 3 1 M cond2 10.7
  6. #> 4 2 F control 6.3
  7. #> 5 2 F cond1 10.6
  8. #> 6 2 F cond2 11.1
  9. #> 7 3 F control 9.5
  10. #> 8 3 F cond1 13.1
  11. #> 9 3 F cond2 13.8
  12. #> 10 4 M control 11.5
  13. #> 11 4 M cond1 13.4
  14. #> 12 4 M cond2 12.9
  15. # 信息: 'subject' 和 'sex' 是我们想要保留的列
  16. # 'condition' 是我们想要放入新列名的列 'measurement'
  17. # 包含数值
  18. library(reshape2)
  19. data_wide <- dcast(olddata_long, subject + sex ~ condition,
  20. value.var = "measurement")
  21. data_wide
  22. #> subject sex cond1 cond2 control
  23. #> 1 1 M 12.3 10.7 7.9
  24. #> 2 2 F 10.6 11.1 6.3
  25. #> 3 3 F 13.1 13.8 9.5
  26. #> 4 4 M 13.4 12.9 11.5

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

  1. # 重命名
  2. names(data_wide)[names(data_wide) == "cond1"] <- "first"
  3. names(data_wide)[names(data_wide) == "cond2"] <- "second"
  4. # 重排序
  5. data_wide <- data_wide[, c(1, 2, 5, 3, 4)]
  6. data_wide
  7. #> subject sex control first second
  8. #> 1 1 M 7.9 12.3 10.7
  9. #> 2 2 F 6.3 10.6 11.1
  10. #> 3 3 F 9.5 13.1 13.8
  11. #> 4 4 M 11.5 13.4 12.9

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