使用多个度量变量重塑数据框
Posted
技术标签:
【中文标题】使用多个度量变量重塑数据框【英文标题】:Reshaping a data frame with more than one measure variable 【发布时间】:2012-10-02 00:03:34 【问题描述】:我正在使用与此类似的数据框:
df<-data.frame(student=c(rep(1,5),rep(2,5)), month=c(1:5,1:5),
quiz1p1=seq(20,20.9,0.1),quiz1p2=seq(30,30.9,0.1),
quiz2p1=seq(80,80.9,0.1),quiz2p2=seq(90,90.9,0.1))
print(df)
student month quiz1p1 quiz1p2 quiz2p1 quiz2p2
1 1 1 20.0 30.0 80.0 90.0
2 1 2 20.1 30.1 80.1 90.1
3 1 3 20.2 30.2 80.2 90.2
4 1 4 20.3 30.3 80.3 90.3
5 1 5 20.4 30.4 80.4 90.4
6 2 1 20.5 30.5 80.5 90.5
7 2 2 20.6 30.6 80.6 90.6
8 2 3 20.7 30.7 80.7 90.7
9 2 4 20.8 30.8 80.8 90.8
10 2 5 20.9 30.9 80.9 90.9
描述学生在五个月内获得的成绩 - 在两个测验中,每个测验分为两个部分。
我需要将两个测验分成不同的行——这样每个月的每个学生都会有两行,每个测验一个,两列——测验的每个部分。 当我融化桌子时:
melt.data.frame(df, c("student", "month"))
我也将测验的两个部分放在不同的行中。
dcast(dfL,student+month~variable)
当然可以让我回到开始的位置,但我找不到将表格重新转换为所需形式的方法。 有没有办法使熔化命令功能类似于:
melt.data.frame(df, measure.var1=c("quiz1p1","quiz2p1"),
measure.var2=c("quiz1p2","quiz2p2"))
【问题讨论】:
样本数据,明确问题。 +1。对于提出第一个问题的人来说,这是一件好事。欢迎来到 SO。 相关问题:***.com/questions/27247078/… 【参考方案1】:大约半年前有一个很相似的question问,我在里面写了如下函数:
melt.wide = function(data, id.vars, new.names)
require(reshape2)
require(stringr)
data.melt = melt(data, id.vars=id.vars)
new.vars = data.frame(do.call(
rbind, str_extract_all(data.melt$variable, "[0-9]+")))
names(new.vars) = new.names
cbind(data.melt, new.vars)
您可以使用该功能“融化”您的数据,如下所示:
dfL <-melt.wide(df, id.vars=1:2, new.names=c("Quiz", "Part"))
head(dfL)
# student month variable value Quiz Part
# 1 1 1 quiz1p1 20.0 1 1
# 2 1 2 quiz1p1 20.1 1 1
# 3 1 3 quiz1p1 20.2 1 1
# 4 1 4 quiz1p1 20.3 1 1
# 5 1 5 quiz1p1 20.4 1 1
# 6 2 1 quiz1p1 20.5 1 1
tail(dfL)
# student month variable value Quiz Part
# 35 1 5 quiz2p2 90.4 2 2
# 36 2 1 quiz2p2 90.5 2 2
# 37 2 2 quiz2p2 90.6 2 2
# 38 2 3 quiz2p2 90.7 2 2
# 39 2 4 quiz2p2 90.8 2 2
# 40 2 5 quiz2p2 90.9 2 2
一旦数据采用这种形式,您就可以更轻松地使用dcast()
来获得您想要的任何形式。例如
head(dcast(dfL, student + month + Quiz ~ Part))
# student month Quiz 1 2
# 1 1 1 1 20.0 30.0
# 2 1 1 2 80.0 90.0
# 3 1 2 1 20.1 30.1
# 4 1 2 2 80.1 90.1
# 5 1 3 1 20.2 30.2
# 6 1 3 2 80.2 90.2
【讨论】:
感谢@mrdwab 提出此解决方案。我花了一段时间才理解它应该如何工作,但现在我明白了,我可以看到你的功能和你解决问题的一般方法在这种情况和其他情况下是如何有用的。 @eli-k,不要忘记对于大多数函数,您可以简单地在控制台写函数名(例如> reshape
)以查看为它们提供动力的代码。然后,您可以运行函数的不同部分,查看每一步都做了什么。这可能是学习一些有趣的编码技巧的有用方法。【参考方案2】:
下面是你如何使用reshape()
来做到这一点,来自基础 R:
df2 <- reshape(df, direction="long",
idvar = 1:2, varying = list(c(3,5), c(4,6)),
v.names = c("p1", "p2"), times = c("quiz1", "quiz2"))
## Checking the output
rbind(head(df2, 3), tail(df2, 3))
# student month time p1 p2
# 1.1.quiz1 1 1 quiz1 20.0 30.0
# 1.2.quiz1 1 2 quiz1 20.1 30.1
# 1.3.quiz1 1 3 quiz1 20.2 30.2
# 2.3.quiz2 2 3 quiz2 80.7 90.7
# 2.4.quiz2 2 4 quiz2 80.8 90.8
# 2.5.quiz2 2 5 quiz2 80.9 90.9
您还可以为idvar
和varying
使用列名(而不是列号)。它更冗长,但对我来说似乎是更好的做法:
## The same operation as above, using just column *names*
df2 <- reshape(df, direction="long", idvar=c("student", "month"),
varying = list(c("quiz1p1", "quiz2p1"),
c("quiz1p2", "quiz2p2")),
v.names = c("p1", "p2"), times = c("quiz1", "quiz2"))
【讨论】:
感谢您的回答。很好地说明了“v.names”和“times”的使用。 @DWin -- 没问题。我认为你和我是围绕这些部分的普通旧reshape()
的主要支持者。 (我想不出任何 R 函数具有更不透明的手册页(或不太有用的示例),因此学习使用它需要一个非常陡峭的学习曲线。)
没错。我认为这个问题和答案将是帮助页面的示例部分的一个很好的补充。
我之前考虑过为reshape()
建立一个替代示例部分。是否有任何现实的途径可以将类似的东西纳入基础包?
@eli-k -- 最好将 Hadley 的包视为对用户更友好而不是更高级。 R 核心团队包括一些令人印象深刻且经验丰富的程序员,而像 reshape()
这样的函数已经存在了足够长的时间,以至于它已经变得非常坚固。因此,在许多重要的方面,核心 R 包含了 R 世界中许多最“先进”的代码。 (顺便说一句,很高兴您喜欢这个替代解决方案。)【参考方案3】:
我认为这是你想要的:
#Break variable into two columns, one for the quiz and one for the part of the quiz
dfL <- transform(dfL, quiz = substr(variable, 1,5),
part = substr(variable, 6,7))
#Adjust your dcast call:
dcast(dfL, student + month + quiz ~ part)
#-----
student month quiz p1 p2
1 1 1 quiz1 20.0 30.0
2 1 1 quiz2 80.0 90.0
3 1 2 quiz1 20.1 30.1
...
18 2 4 quiz2 80.8 90.8
19 2 5 quiz1 20.9 30.9
20 2 5 quiz2 80.9 90.9
【讨论】:
感谢@Chase 这个伟大的解决方案。虽然我通常更喜欢内置解决方案,但您的解决方案看起来在更复杂的 df 中需要更少的代码。例如,如果每个测验分为六个部分,我就不必在代码中添加任何内容,而我必须在 reshape 函数中编写六对列名。以上是关于使用多个度量变量重塑数据框的主要内容,如果未能解决你的问题,请参考以下文章