【问题标题】:strsplit by row and distribute results by column in data.frame在 data.frame 中按行拆分并按列分配结果
【发布时间】:2012-10-18 03:59:19
【问题描述】:

所以我有data.frame

dat = data.frame(x = c('Sir Lancelot the Brave', 'King Arthur',  
                       'The Black Knight', 'The Rabbit'), stringsAsFactors=F)

> dat
                       x
1 Sir Lancelot the Brave
2            King Arthur
3       The Black Knight
4             The Rabbit

我想把它转换成数据框

> dat2
                       x    1            2       3      4
1 Sir Lancelot the Brave    Sir   Lancelot     the  Brave
2            King Arthur    King    Arthur
3       The Black Knight    The      Black  Knight 
4             The Rabbit    The     Rabbit

strsplit 以列表形式返回数据

sbt <- strsplit(dat$x, " ")
> sbt
[[1]]
[1] "Sir"      "Lancelot" "the"      "Brave"   

[[2]]
[1] "King"   "Arthur"

[[3]]
[1] "The"    "Black"  "Knight"

[[4]]
[1] "The"    "Rabbit"

并且 as.data.table 不会在应该的地方创建 NULL 值,而是重复值

> t(as.data.table(sbt))
   [,1]   [,2]       [,3]     [,4]    
V1 "Sir"  "Lancelot" "the"    "Brave" 
V2 "King" "Arthur"   "King"   "Arthur"
V3 "The"  "Black"    "Knight" "The"   
V4 "The"  "Rabbit"   "The"    "Rabbit"

我想我真的很想为 as.data.table(x, repeat=FALSE) 提供一个参数,否则我该如何完成这项工作?

【问题讨论】:

  • 您使用的是data.frames 还是data.tables?
  • @mnel:只要能完成工作。当我尝试强制 sbt 时,as.data.frame 会出错,所以这就是我尝试使用 as.data.table 的原因。

标签: r data.table strsplit


【解决方案1】:

这是一个老问题,我知道,但我想我会分享两个额外的选项。

选项 1

我的“splitstackshape”包中的concat.split 正是为这种类型的东西设计的。

library(splitstackshape)
concat.split(dat, "x", " ")
#                        x  x_1      x_2    x_3   x_4
# 1 Sir Lancelot the Brave  Sir Lancelot    the Brave
# 2            King Arthur King   Arthur             
# 3       The Black Knight  The    Black Knight      
# 4             The Rabbit  The   Rabbit        

选项 2

data.table 最近(我相信从 1.8.11 版开始)对其武器库进行了一些补充,特别是在这种情况下 dcast.data.table。要使用它,unlist 拆分数据(就像在@mnel 的回答中所做的那样),使用.N(每行有多少新值)创建一个“时间”变量,然后使用dcast.data.table 将数据转换为您正在寻找的表格。

library(data.table)
library(reshape2)
packageVersion("data.table")
# [1] ‘1.8.11’

DT <- data.table(dat)
S1 <- DT[, list(X = unlist(strsplit(x, " "))), by = seq_len(nrow(DT))]
S1[, Time := sequence(.N), by = seq_len]
dcast.data.table(S1, seq_len ~ Time, value.var="X")
#    seq_len    1        2      3     4
# 1:       1  Sir Lancelot    the Brave
# 2:       2 King   Arthur     NA    NA
# 3:       3  The    Black Knight    NA
# 4:       4  The   Rabbit     NA    NA

【讨论】:

    【解决方案2】:

    这是一种选择。唯一的复杂之处是您需要首先将每个向量转换为具有一行的 data.frame,因为 data.frames 是 rbind.fill() 所期望的。

    library(plyr)
    rbind.fill(lapply(sbt, function(X) data.frame(t(X))))
    #     X1       X2     X3    X4
    # 1  Sir Lancelot    the Brave
    # 2 King   Arthur   <NA>  <NA>
    # 3  The    Black Knight  <NA>
    # 4  The   Rabbit   <NA>  <NA>
    

    不过,我自己的倾向是只使用基础 R,如下所示:

    n <- max(sapply(sbt, length))
    l <- lapply(sbt, function(X) c(X, rep(NA, n - length(X))))
    data.frame(t(do.call(cbind, l)))
    #     X1       X2     X3    X4
    # 1  Sir Lancelot    the Brave
    # 2 King   Arthur   <NA>  <NA>
    # 3  The    Black Knight  <NA>
    # 4  The   Rabbit   <NA>  <NA>
    

    【讨论】:

      【解决方案3】:
      sbt = strsplit(dat$x, " ")
      sbt
      #[[1]]
      #[1] "Sir"      "Lancelot" "the"      "Brave"   
      #[[2]]
      #[1] "King"   "Arthur"
      #[[3]]
      #[1] "The"    "Black"  "Knight"
      #[[4]]
      #[1] "The"    "Rabbit"
      
      ncol = max(sapply(sbt,length))
      ncol
      # [1] 4
      
      as.data.table(lapply(1:ncol,function(i)sapply(sbt,"[",i)))
      #      V1       V2     V3    V4
      # 1:  Sir Lancelot    the Brave
      # 2: King   Arthur     NA    NA
      # 3:  The    Black Knight    NA
      # 4:  The   Rabbit     NA    NA
      

      【讨论】:

        【解决方案4】:

        使用data.table,因为您正在尝试使用它。

        library(data.table)
        DT <- data.table(dat)
        DTB <- DT[, list(y = unlist(strsplit(x, ' '))), by = x]
        
        new <- rep(NA_character_,  DTB[,.N,by =x][which.max(N), N])
        names(new) <- paste0('V', seq_along(new))
        DTB[,{.new <- new 
              .new[seq_len(.N)] <- y 
               as.list(.new)} ,by= x]
        

        或者使用reshape2dcast重塑

        library(reshape2)
        
        dcast(DTB[,list(id = seq_len(.N),y),by= x ], x ~id, value.var = 'y')
        

        【讨论】:

          【解决方案5】:

          这是tidyr 的一个不错且简单的方法。

          library(tidyr)
          
          ncol <- max(sapply(dat, length))
          
          dat %>%
            separate(x, paste0("V", seq(1,ncol)))
          

          注意:你会得到一个警告,但是,它基本上是告诉你separate 正在用NA 填充数据。所以你可以忽略警告。

          【讨论】:

            猜你喜欢
            • 2012-07-09
            • 2011-08-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-03-07
            • 2012-08-16
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多