将未知列数的数据从长格式转换为宽格式

5
我很确定这个问题很简单,但我找不到如何处理它。
我有一个数据框,里面包含个体,每个个体都有若干属性,而每个属性又有许多分类方式。目前它的形式是长表格,一个记录看起来像这样(实际上更复杂一些):
IndividualID Property PropClass 
1            X         A 
1            Y         B 
2            X         A 
3            Y         B
3            W         C
3            Z         A

我希望的是每个个体ID都对应一行,第一列为个体ID,后面的列表示该个体在原始文件中拥有的每个属性和属性分类。例如,在本例中:
 IndividualID  Prop1   PropClass1 Prop2  PropClass2  Prop3  PropClass3
 1             X       A          Y      B           NA     NA
 2             X       A          NA     NA          NA     NA
 3             Y       B          W      C           Z      A

因此,必须有与原始数据集中任何individualID的最大行数一样多的Prop和PropClass变量(该数据集不大,约为5个),当一个个体在原始数据集中的行数少于该最大数量时,对于该个体没有意义的额外列中将填充NA。对于个体的Prop和PropClass变量的顺序无关紧要(尽管可以使用长格式文件的原始顺序)。

如果您为每个Prop可能的值都拥有一对Prop和propClass列,则很容易达到这个目的(例如使用reshape)。但是,由于Prop有几百个可能的值,因此文件会变得非常庞大且难以处理。我不信没有一种简单的方法可以做到我想要的,但是尽管我进行了认真的搜索,也没有找到。请告诉我我是个傻瓜,如果是,请告诉我如何纠正我的错误。

2个回答

2

可能有更高效的方法,但我现在想不到。如果有两个需要转换为宽格式的变量,我认为您可能需要分别将它们转换并将两者合并。不过,我很乐意被证明是错的。为此,我创建了两个新变量,为每个新ID生成一个列序列。这将使它们易于填充NAs。有了新列,将它们转换为正确的格式并将它们合并在一起就很容易了。

library(plyr)
library(reshape2)

#Assumes your data is read into a variable named x
x <- ddply(x, "IndividualID", transform, 
      castPropClass = paste0("PropClass", seq(length(PropClass))),
      castProp = paste0("Prop", seq(length(Property))))

#Use these two new variables to cast into wide format. Wrap in merge to join together:
merge(dcast(IndividualID ~ castPropClass, value.var = "PropClass", data = x),
      dcast(IndividualID ~ castProp,      value.var = "Property",  data = x))
#Gives you this:
  IndividualID PropClass1 PropClass2 PropClass3 Prop1 Prop2 Prop3
1            1          A          B       <NA>     X     Y  <NA>
2            2          A       <NA>       <NA>     X  <NA>  <NA>
3            3          B          C          A     Y     W     Z

显然,这个表格的“列顺序”不正确,但是数据本身是正确的。


谢谢,这个方法很有效(而且也比较容易扩展到我实际遇到的稍微复杂一些的情况)。 - Kevin McConway

1

这样的东西是否可以接受?

test.dt<-data.frame(id=(c(1,1,2,3,3,3)), property=(c("X","Y","X","Y","W","Z")), property.clss=(c("A","B","A","B","C","A")))
library(reshape)
m<-melt(data=test.dt, id.vars="id", measure.vars=c("property.clss"))
m
n<-melt(data=test.dt, id.vars="id", measure.vars=c("property"))
n
c1<-data.frame(cast(m, id~value))
colnames(c1)<-c("id", paste("property",colnames(c1)[colnames(c1)!="id"],sep=""))
c1
c2<-data.frame(cast(n,id~value))
colnames(c2)<-c("id", paste("property.clss",(colnames(c2)[colnames(c2)!="id"]),sep=""))
c2
merge(c1,c2,by="id")

这基本上就是我所概述的,只是采用了不同的步骤...很高兴看到我们或多或少在同一页上。 - Chase
嗨@Chase。我想我们实际上是同时提交的!!我认为你的答案更加简洁漂亮。 - ECII
谢谢,我很确定这对我也有用,但我选择了@Chase的版本,因为它更简洁。 - Kevin McConway

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接