使用dcast重塑数据?

时间:2013-08-07 20:43:30

标签: r reshape reshape2

我不知道使用dcast()是否正确,但我想重塑以下data.frame:

df <- data.frame(x=c("p1","p1","p2"),y=c("a","b","a"),z=c(14,14,16))
df
   x y  z
1 p1 a 14
2 p1 b 14
3 p2 a 16

所以它看起来像这样:

df2 <- data.frame(x=c("p1","p2"),a=c(1,1),b=c(1,0),z=c(14,16))
   x a b  z
1 p1 1 1 14
2 p2 1 0 16

y中的变量df应该被打破,以便其元素是新变量,每个虚拟编码。所有其他变量(在这种情况下只是z)对于每个人(p1,p2等)都是相等的。特定人员p具有不同值的唯一变量是y 我想要这个的原因是因为我需要通过变量x将此数据集与其他数据集合并。事实是,每人需要一排(p1,p2等)。

4 个答案:

答案 0 :(得分:2)

以下作品,但似乎很麻烦。

df2 <- df
df2$y <- as.numeric(y)
df$y2 <- as.numeric(df$y)

df2 <- dcast(df, x+z~y, value.var="y2")

df2
   x  z a  b
1 p1 14 1  2
2 p2 16 1 NA

答案 1 :(得分:2)

这几乎是previous question的重复,我在那里使用的基本答案也是如此。也不需要任何外部包。

aggregate(model.matrix(~ y - 1, data=df),df[c("x","z")],max)

   x  z ya yb
1 p1 14  1  1
2 p2 16  1  0

要解释这一点,因为它有点奇怪,最基本的model.matrix调用会为data.frame的每一行的每个唯一值返回一个二进制指示符变量,如下所示:

  ya yb
1  1  0
2  0  1
3  1  0

如果aggregate您的两个id变量(xz)的中间结果,那么您基本上是在初始data.frame上执行:

   x  z ya yb
1 p1 14  1  0
2 p1 14  0  1
3 p2 16  1  0

因此,如果您在maxya的每个组合中使用ybxz,那么您基本上可以这样做:

   x  z ya      yb
1 p1 14  1*max*  0
2 p1 14  0       1*max*

--collapse--

   x  z ya      yb
1 p1 14  1       1

...并对每个唯一的x / z组合重复一遍,以得出最终结果:

   x  z ya yb
1 p1 14  1  1
2 p2 16  1  0

将这一点推广到更多列时,事情变得有点疯狂,但它可以通过this question提供,例如:

df <- data.frame(x=c("p1","p1","p2"),y=c("a","b","a"),z=c("14","15","16"))
intm <- model.matrix(~ y + z - 1, data=df,
                 contrasts.arg = sapply(df[2:3], contrasts, contrasts=FALSE))
aggregate(intm,df[c("x")],max)

   x ya yb z14 z15 z16
1 p1  1  1   1   1   0
2 p2  1  0   0   0   1

答案 2 :(得分:1)

我不太清楚你必须这么做但是如果你需要一种方法来自动化它,我写了这个可能有帮助的小功能:

首先运行dcast:

new = dcast(df, x+z~y, value.var="y")

加载到R环境中:

 # args to be passed: 
 # df is your dataframe 
 # cols is a list of format c("colname1", "colname2", ... , "colnameN")
    binarizeCols = function(df, cols){
      for(i in cols){
        column = which(colnames(df) == i)
        truthRow = is.na(df[,column])
        for(j in 1:length(truthRow)){
          if(truthRow[j] == FALSE){
            df[j,column] = 1
          }else{
             df[j,column] = 0
           }
        }
      }
      return(df)
    }

然后运行:

new = binarizeCols(new, c("a", "b"))

你得到:

     x  z  a  b
   1 p1 14 1  1 
   2 p2 16 1  0

没有使用_apply()快但没有硬编码,你可以输入你想要的任何名字(也许你想跳过中间的一个?)而你不会创建你的df的新实例。 注意:我使用“=”而不是“&lt; - ”,因为我认为它正在逐步淘汰,但如果需要可以替换它们。

答案 3 :(得分:0)

df <- data.frame(x=c("p1","p1","p2","p3"),
                 y=c("a","b","a","c"),
                 z=c(14,14,16,17))  # wanted larger test case.
new <- dcast(df, x+z~y, value.var="y")
new[3:5] <- sapply(lapply(new[3:5], '%in%', unique(df$y) ), as.numeric)
new
   x  z a b c
1 p1 14 1 1 0
2 p2 16 1 0 0
3 p3 17 0 0 1

首先检查向量中的包含,该向量总结了创建逻辑值列的可能值。然后通过取这些逻辑值的as.numeric来'dummify'。