【问题标题】:splitting a column by factor within a data frame在数据框中按因子拆分列
【发布时间】:2014-06-29 00:55:29
【问题描述】:

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

v1   v2   v3
a    1    a
a    2    b
a    6    c
b    3    a
b    4    b
b    5    c

其中 v1 是一个因子,v3 是一个字符。我想对数据框应用一些功能,例如 v2 被拆分到 v1 中,然后包含在数据框中:

v1   v2   v3   v4   v5
a    1    a    1    NA
a    2    b    2    NA
a    6    c    6    NA
b    3    a    NA   3
b    4    b    NA   4
b    5    c    NA   5

我能够制定的解决方案非常复杂。有没有一种优雅的方式来做到这一点?

(注意:v3 的存在是因为任何解决方案都需要能够处理数据框中存在的其他应该被忽略的非数字向量。)

【问题讨论】:

    标签: r split dataframe plyr


    【解决方案1】:

    1) transform / ifelse 如果v1 中有少量已知值,一个简单的方法是手动生成每个新列:

    transform(DF, a = ifelse(v1 == "a", v2, NA), 
                  b = ifelse(v1 == "b", v2, NA))
    

    2) tapply 更通用的方法是:

    cbind(DF, tapply(DF$v2, list(1:nrow(DF), DF$v1), identity))
    

    上述解决方案不需要任何插件包。

    3) 数据表。此解决方案假定 v1 是一个因素,并且 DF 的行是唯一的(就像问题中的情况一样):

    # devtools::install_github("Rdatatable/datatable")  # 1.9.3
    
    library(data.table)
    DT <- data.table(DF)
    
    DT[, split(v2, v1), by = DT]
    

    如果DT 的行可能不是唯一的,那么(基于与 Arun 的讨论)这将起作用:

    DT[, c(.SD, split(v2, v1)), by = 1:nrow(DT)][, -1, with = FALSE]
    

    更新一些改进。

    【讨论】:

      【解决方案2】:

      使用dplyr 如果dd是数据集

      # install.packages("devtools")
      devtools::install_github("hadley/tidyr")
      library(dplyr)
      library(tidyr)
      dd1 <- dd %>% 
        mutate(n = seq_len(n())) %>%
        spread(v1,v2) %>% 
        arrange(n) %>% 
        select(-n,-v3)
      
      cbind(dd, dd1)
      #    v1 v2 v3  a  b
      #1  a  1  a  1 NA
      #2  a  2  b  2 NA
      #3  a  6  c  6 NA
      #4  b  3  a NA  3
      #5  b  4  b NA  4
      #6  b  5  c NA  5
      

      【讨论】:

        【解决方案3】:

        您可以在此处使用reshape2 包。首先,你的测试数据

        dd<-data.frame(
            v1 = factor(c("a", "a", "a", "b", "b", "b")),
            v2 = c(1, 2, 6, 3, 4, 5), 
            v3 = c("a", "b", "c", "a", "b", "c"),
            stringsAsFactors=F
        )
        

        现在创建新列

        library(reshape2)
        nc<-dcast(dd, 1:nrow(dd)~v1, value.var="v2")[-1]
        

        现在合并它们

        dd<-cbind(dd, nc)
        dd
        

        得到

          v1 v2 v3  a  b
        1  a  1  a  1 NA
        2  a  2  b  2 NA
        3  a  6  c  6 NA
        4  b  3  a NA  3
        5  b  4  b NA  4
        6  b  5  c NA  5
        

        【讨论】:

          【解决方案4】:

          Gabor 的data.table 答案很好,但每一行都是splits,在更大的桌子上可能会变慢。这是使用rbindlist 的另一种方式,尽管来自1.9.3

          tmp = DT[, list(V = list(
                       setattr(list(v2), 'names', v1)
                     )), by = list(v1 = as.character(v1))]$V
          ## 1.9.3
          tmp = rbindlist(tmp, fill=TRUE)
          #     a  b
          # 1:  1 NA
          # 2:  2 NA
          # 3:  6 NA
          # 4: NA  3
          # 5: NA  4
          # 6: NA  5
          
          DT[, c(names(tmp)) := tmp]
          #    v1 v2 v3  a  b
          # 1:  a  1  a  1 NA
          # 2:  a  2  b  2 NA
          # 3:  a  6  c  6 NA
          # 4:  b  3  a NA  3
          # 5:  b  4  b NA  4
          # 6:  b  5  c NA  5
          

          PS:此解决方案假定DT 在列v1 上排序。


          这是另一个版本,它不依赖于 v1 被排序:

          for (j in unique(DT$v1)) {
              ix = which(DT$v1 == j)
              set(DT, i=ix, j=j, value=DT$v2[ix])
          }
          

          【讨论】:

            【解决方案5】:

            这是一种使用 base 的方法,它可以直接完成工作:

            n <- ncol(x)
            for (i in 1:length(levels(x$v1))) 
            {
                s <- as.numeric(x$v1)==i
                x[s,n+i] <- x$v2[s]
            }
            
            > x
              v1 v2 v3 V4 V5
            1  a  1  a  1 NA
            2  a  2  b  2 NA
            3  a  6  c  6 NA
            4  b  3  a NA  3
            5  b  4  b NA  4
            6  b  5  c NA  5
            

            这是采用因子x$v1 的数值并将其用作将数据从v2 复制到的位置。因为它正在添加列,所以可能存在其他内容并不重要。

            【讨论】:

              猜你喜欢
              • 2013-10-20
              • 1970-01-01
              • 2018-03-18
              • 1970-01-01
              • 2017-05-09
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-06-27
              相关资源
              最近更新 更多