【问题标题】:Melt a dataframe by pattern in colnames通过 colnames 中的模式融化数据框
【发布时间】:2014-08-10 23:26:27
【问题描述】:

我有几个数据框,每个都有超过 250 个变量。第一个数据帧的部分dput

df <- structure(list(id = structure(1:6, .Label = c("00", "01", "02", "03", "04", "05", "06", "08", "09", "10", "11", "12", "13", "14", "15", "All Recordings"), class = "factor"), Geslacht = structure(c(2L, 2L, 3L, 2L, 2L, 3L), .Label = c("-", "Man", "Vrouw"), class = "factor"), Leeftijd = structure(c(2L, 3L, 3L, 4L, 4L, 4L), .Label = c("-", "13", "14", "15", "17"), class = "factor"), FD.1.01 = c(13.96, 3.46, 2.45, 4.65, 1.18, 0.76), FD.1.02 = c(2.79, 4.32, 5.28, 0.78, 4.03, 0.74), FD.1.03 = c(2.09, 2.96, 5.78, 0.52, 1.12, 0), FD.1.04 = c(0, 2.79, 1.65, 0, 2.11, 2.11), FD.1.05 = c(1.26, 0.96, 8.67, 0.34, 1.77, 2.25), FD.1.06 = c(7.27, 0.58, 12.04, 0, 0.84, 3.39), FD.1.07 = c(3.97, 0.16, 8.37, 0.92, 0, 4.05), FD.1.08 = c(4.45, 0, 4.23, 0, 0, 1.63), FD.1.09 = c(0, 0, 2.07, 0, 0, 0.46), FD.1.10 = c(0, 0, 1.87, 0, 0, 0.42), FD.1.11 = c(0, 0, 9.05, 0, 0, 0), FD.1.12 = c(0, 0, 0, 0, 0, 0), FD.1.13 = c(0, 0, 0, 0, 0, 0), FD.1.14 = c(0, 0, 0, 0, 0, 0), FD.1.15 = c(0, 0, 0, 0, 0, 0), FD.1.16 = c(0, 0, 0, 0, 0, 0), FD.1.17 = c(0, 0, 0, 0, 0, 0), FD.1.18 = c(0, 0, 0, 0, 0, 0), FD.1.19 = c(0, 0, 0, 0, 0, 0), FD.1.20 = c(0, 0, 0, 0, 0, 0), FD.1.21 = c(0, 0, 0, 0, 0, 0), FD.1.22 = c(0, 0, 0, 0, 0, 0)), .Names = c("id", "Geslacht", "Leeftijd", "FD.1.01", "FD.1.02", "FD.1.03", "FD.1.04", "FD.1.05", "FD.1.06", "FD.1.07", "FD.1.08", "FD.1.09", "FD.1.10", "FD.1.11", "FD.1.12", "FD.1.13", "FD.1.14", "FD.1.15", "FD.1.16", "FD.1.17", "FD.1.18", "FD.1.19", "FD.1.20", "FD.1.21", "FD.1.22"), row.names = c(1L, 2L, 3L, 4L, 5L, 7L), class = "data.frame")

我想通过以下方式将我的数据框从宽改成长:

library(reshape2)
melted.df <- melt(df, id=c("id","Geslacht","Leeftijd"), measure.vars=c("all variables starting with FD"))

但是,我不知道哪些列名以FD 开头。此外,这个数字因几个数据帧而异,我也必须对以其他字母组合开头的变量执行此操作。

当然,我可以手动执行此操作,但这需要更多时间并且容易出错。因此,程序化解决方案是非常可取的。

有什么建议可以解决这个问题吗?


为了能够检查@akrun 的dplyr 解决方案出现问题的位置,前6 行和所有列的dput

df <- structure(list(id = structure(1:6, .Label = c("00", "01", "02", "03", "04", "05", "06", "08", "09", "10", "11", "12", "13", "14", "15", "All Recordings"), class = "factor"), Geslacht = structure(c(2L, 2L, 3L, 2L, 2L, 3L), .Label = c("-", "Man", "Vrouw"), class = "factor"), Leeftijd = structure(c(2L, 3L, 3L, 4L, 4L, 4L), .Label = c("-", "13", "14", "15", "17"), class = "factor"), FD.1.01 = c(13.96, 3.46, 2.45, 4.65, 1.18, 0.76), FD.1.02 = c(2.79, 4.32, 5.28, 0.78, 4.03, 0.74), FD.1.03 = c(2.09, 2.96, 5.78, 0.52, 1.12, 0), FD.1.04 = c(0, 2.79, 1.65, 0, 2.11, 2.11), FD.1.05 = c(1.26, 0.96, 8.67, 0.34, 1.77, 2.25), FD.1.06 = c(7.27, 0.58, 12.04, 0, 0.84, 3.39), FD.1.07 = c(3.97, 0.16, 8.37, 0.92, 0, 4.05), FD.1.08 = c(4.45, 0, 4.23, 0, 0, 1.63), FD.1.09 = c(0, 0, 2.07, 0, 0, 0.46), FD.1.10 = c(0, 0, 1.87, 0, 0, 0.42), FD.1.11 = c(0, 0, 9.05, 0, 0, 0), FD.1.12 = c(0, 0, 0, 0,   0, 0), FD.1.13 = c(0, 0, 0, 0, 0, 0), FD.1.14 = c(0, 0, 0, 0, 0, 0), FD.1.15 = c(0, 0, 0, 0, 0, 0), FD.1.16 = c(0, 0, 0, 0, 0, 0), FD.1.17 = c(0, 0, 0, 0, 0, 0), FD.1.18 = c(0, 0, 0, 0, 0, 0), FD.1.19 = c(0, 0, 0, 0, 0, 0), FD.1.20 = c(0, 0, 0, 0, 0, 0), FD.1.21 = c(0, 0, 0, 0, 0, 0), FD.1.22 = c(0, 0, 0, 0, 0, 0), Click.5.18 = c(0, 0, 0, 0, 0, 0), Click.5.19 = c(0, 0, 0, 0, 0, 0), Click.5.20 = c(0, 0, 0, 0, 0, 0), Click.5.21 = c(0, 0, 0, 0, 0, 0), Click.6.01 = c(0, 0, 0, 0, 0, 0), Click.6.02 = c(0, 0, 0, 0, 0, 0), Click.6.03 = c(0, 0, 0, 0, 0, 0), Click.6.04 = c(0, 0, 0, 0, 0, 0), Click.6.05 = c(0, 0, 0, 0, 0, 0), Click.6.06 = c(0, 0, 0, 0, 0, 0), Click.6.07 = c(0, 0, 0, 0, 0, 0), Click.6.08 = c(0, 0, 0, 0, 0, 0), Click.6.12 = c(0, 0, 0, 0, 0, 0), Click.6.13 = c(0, 0, 0, 0, 0, 0), Click.6.14 = c(0, 0, 0, 0, 0, 0), Click.6.15 = c(0, 0, 0, 0, 0, 0), Click.6.16 = c(0, 0, 0, 0, 0, 0), Click.6.17 = c(0, 0, 0, 0, 0, 0), Click.6.18 = c(0, 0, 0, 0, 0, 0), Click.6.19 = c(0, 0, 0, 0, 0, 0), Click.6.20 = c(0, 0, 0, 0, 0, 0), Click.6.21 = c(0, 0, 0, 0, 0, 0), Click.7.01 = c(0, 0, 0, 0, 0, 0), Click.7.02 = c(0, 0, 0, 0, 0, 0), Click.7.03 = c(0, 0, 0, 0, 1, 0), Click.7.04 = c(0, 0, 0, 0, 0, 0)), .Names = c("id", "Geslacht", "Leeftijd", "FD.1.01", "FD.1.02", "FD.1.03", "FD.1.04", "FD.1.05", "FD.1.06", "FD.1.07", "FD.1.08", "FD.1.09", "FD.1.10", "FD.1.11", "FD.1.12", "FD.1.13", "FD.1.14", "FD.1.15", "FD.1.16", "FD.1.17", "FD.1.18", "FD.1.19", "FD.1.20", "FD.1.21", "FD.1.22", "Click.5.18", "Click.5.19",  "Click.5.20", "Click.5.21", "Click.6.01", "Click.6.02", "Click.6.03", "Click.6.04", "Click.6.05", "Click.6.06", "Click.6.07", "Click.6.08", "Click.6.12", "Click.6.13", "Click.6.14", "Click.6.15", "Click.6.16", "Click.6.17", "Click.6.18", "Click.6.19", "Click.6.20", "Click.6.21", "Click.7.01", "Click.7.02", "Click.7.03", "Click.7.04"), row.names = c(1L, 2L, 3L, 4L, 5L, 7L), class = "data.frame")

【问题讨论】:

  • 在colnames中grep FD? melt(df,id=c("id","Geslacht","Leeftijd"), measure.vars=colnames(df)[grepl("^FD",colnames(df))])
  • @agstudy 从 Jaap 的代表点来看,我没想到答案会这么简单,所以认为我们还缺少其他东西......
  • @zx8754 你是对的:)
  • @zx8754 代表点不要说一切,我通过回答ggplot2 问题获得了大部分;-) regex 相关的东西是我使用 R 的主要弱点之一

标签: r dataframe dplyr reshape2 tidyr


【解决方案1】:

试试:

melt(df, id=c("id","Geslacht", "Leeftijd"), 
         measure.vars=grep("^FD", colnames(df)))

library(dplyr)
library(tidyr)

df %>% gather(FD, Score, FD.1.01:FD.1.22)

这也适用于您提供的示例:

df %>% 
gather(FD, Score, grep("^FD", colnames(df))) %>%
head()
  id Geslacht Leeftijd      FD Score
1 00      Man       13 FD.1.01 13.96
2 01      Man       14 FD.1.01  3.46
3 02    Vrouw       14 FD.1.01  2.45
4 03      Man       15 FD.1.01  4.65
5 04      Man       15 FD.1.01  1.18
6 05    Vrouw       15 FD.1.01  0.76

在更大的数据集上,

newCols <- simplify2array(replicate(100,df[,-(1:3)]))
colnames(newCols) <- paste0("FD.1.", 23:2222)
df1 <- cbind(df, newCols)
df2 <- df1 %>% 
gather(FD, Score, grep("^FD", colnames(df1)))
dim(df2)
#[1] 13332     5

使用具有不同列名的新示例数据集。

res1 <- df %>% 
select(id, Geslacht, Leeftijd, grep("^FD",names(df))) %>% 
gather(FD, Score, grep("^FD",names(df))) 

用 ?melt() 比较结果

res2 <-  melt(df, id=c("id","Geslacht", "Leeftijd"), 
      measure.vars=grep("^FD", colnames(df)))
colnames(res2) <- colnames(res1)
identical(res1,res2)
 #[1] TRUE

【讨论】:

  • 不幸的是,我收到以下错误消息:Error in measure.attributes[[1]] : subscript out of bounds 在尝试您的第一个代码时将其应用于整个数据帧。您的dplyr 解决方案的缺点是我必须指定FD.1.01:FD.1.22,这不是我想要的,因为以FD 开头的列数可能会有所不同(正如我在问题中所解释的那样)
  • 嗨,Jaap,感谢 cmets。您能否提供一个 ?melt() 失败的最小 ?dput() 示例。我更新了 dplyr() 代码。不确定 ?dplyr 在原始数据集中是否有效。
  • 我必须先将我的 R 版本更新到 3.1.0 才能测试您的 dplyr 解决方案。但是,它不起作用:所有带有FD 的列都被删除了。
  • Jaap,很抱歉听到这个消息。您的意思是它不适用于示例数据或原始数据集中吗?我没有注意到任何问题。 sessionInfo() R 版本 3.1.0 (2014-04-10) 平台:x86_64-unknown-linux-gnu (64-bit) 其他附加软件包:[1] tidyr_0.1 dplyr_0.2 gsubfn_0.6-5 proto_0.3 -10 gtools_3.4.0 [6] stringr_0.6.2 reshape2_1.4 通过命名空间加载(未附加):[1] assertthat_0.1 magrittr_1.0.1 parallel_3.1.0 plyr_1.8.1 Rcpp_0.11.1 [6] tcltk_3.1.0 tools_3。 1.0
  • 它不适用于原始数据集。您的grep 解决方案返回正确的结果(一个具有 5 列和 1860 行的数据框),其中您的第二个解决方案返回一个只有 6 行和 129 列的数据框(在原始数据集中有 251 列)
【解决方案2】:

grep FD in colnames:

melted.df <- melt(df, id=c("id","Geslacht","Leeftijd"),
                  measure.vars=colnames(df)[grepl("^FD",colnames(df))])

【讨论】:

  • 不幸的是,我收到以下错误消息:Error in measure.attributes[[1]] : subscript out of bounds 当我将其应用于整个数据框时
  • 你的包是最新的吗?此代码适用于帖子中提供的示例数据,也许您可​​以显示更多示例数据?
  • 我希望你不介意我接受了另一个答案。它更适合我的需求(尤其是dplyr 解决方案)。作为补偿,我还对您的其他答案之一投了赞成票;-)
【解决方案3】:

dplyrtidyr 的另一个非常直接的解决方案是:

melted.df <- df %>% 
  select(id, Geslacht, Leeftijd, starts_with("FD")) %>% 
  gather(FD, Score, starts_with("FD"))

data.table:

melted.df <- melt(df, id = c("id","Geslacht","Leeftijd"),
                  measure.vars = patterns("^FD"))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-22
    • 2016-07-26
    • 1970-01-01
    • 2021-01-26
    相关资源
    最近更新 更多