【问题标题】:Spreading over a column in R在R中的列上传播
【发布时间】:2016-05-06 20:05:43
【问题描述】:

假设我有一个这样的数据框:

data.frame(x = c(1,1,1,3,3,3),y = c(12,32,43,16,32,65))

我想把它转换成这样的数据框:

data.frame(x = c(1, 3), y_1 =  c(12,16), y_2 =c(32, 32),y_3= c(43, 65))

基本上散布每个唯一 x 值的 y 值。我尝试使用 tidyr 来做到这一点,但不太清楚它是如何工作的。有什么想法吗?

谢谢。

【问题讨论】:

    标签: r tidyr


    【解决方案1】:

    这是data.table 解决方案:

    library(data.table)
    
    dat = as.data.table(df) # or setDT to convert in place
    
    dat[, obs := paste0('y_', 1:.N), by=x]
    dcast(dat, x ~ obs, value.var="y")
    
    #   x y_1 y_2 y_3
    #1: 1  12  32  43
    #2: 3  16  32  65
    

    即使所有x 的行数不同,这也可以工作。

    【讨论】:

      【解决方案2】:

      我们可以使用aggregate,然后从splitstackshape包中使用cSplit来强制数据帧,

      library(splitstackshape)
      df1 <- aggregate(y ~ x, df, paste, collapse = ',')
      df1 <- cSplit(df1, 'y', ',', direction = 'wide')
      #   x y_1 y_2 y_3
      #1: 1  12  32  43
      #2: 3  16  32  65
      

      【讨论】:

        【解决方案3】:

        Sotos 使用aggregate 给出的答案特别优雅,但以下使用reshape 的方法也可能具有启发性:

        df <- data.frame(x = c(1,1,1,3,3,3),y = c(12,32,43,16,32,65))
        df[,"time"] <- rep(1:3, 2)
        wide_df <- reshape(df, direction="wide", timevar="time", idvar="x")
        

        【讨论】:

        • 不错的一个。也可以插入transform() 调用,而不必更改原始数据reshape(transform(df, time=ave(y, x, FUN = seq_along)), direction = "wide", timevar = "time", idvar = "x", sep = "_")
        【解决方案4】:

        dplyr/tidyr 的一个选项

        library(dplyr)
        library(tidyr)
        df1 %>% 
            group_by(x) %>% 
            mutate(n = paste("y", row_number(), sep="_")) %>%
            spread(n,y)
        #     x   y_1   y_2   y_3
        #   (dbl) (dbl) (dbl) (dbl)
        #1     1    12    32    43
        #2     3    16    32    65
        

        【讨论】: