【问题标题】:Split or separate uneven/unequal strings with no delimiter不带分隔符拆分或分隔不均匀/不相等的字符串
【发布时间】:2016-10-10 10:09:20
【问题描述】:

给定数据框df

x <- c("X1", "X2", "X3", "X4", "X5")
y <- c("00L0", "0", "00012L", "0123L0", "0D0")
df <- data.frame(x, y)

如何利用tidyr::separatey 字符串的每个字符放入单独的列(每个字符串位置一列)?

期望的输出:

x <- c("X1", "X2", "X3", "X4", "X5")
m1 <- c(0, 0, 0, 0, 0)
m2 <- c(0, NA, 0, 1, "D")
m3 <- c("L", NA, 0, 2, 0)
mN <- c(NA, NA, NA, NA, NA)
df <- data.frame(x, m1, m2, m3, mN)

其中 mN 理论上可以达到 m100(100 列)或更高。

【问题讨论】:

    标签: r tidyr


    【解决方案1】:

    这是一个基本的 R 方法。

    # split the strings
    temp <- strsplit(df$y, split="")
    # maximum length of the list items
    maxL <- max(sapply(temp, length))
    # contstruct data.frame with NAs as fills
    temp <- data.frame(do.call(rbind, lapply(temp, function(i) c(i, rep(NA, maxL-length(i))))))
    
    # add to df
    df <- cbind(x=df[, -2], temp)
    

    导致

            x X1   X2   X3   X4   X5   X6
    1       X1  0    0    L    0 <NA> <NA>
    2       X2  0 <NA> <NA> <NA> <NA> <NA>
    3       X3  0    0    0    1    2    L
    4       X4  0    1    2    3    L    0
    5       X5  0    D    0 <NA> <NA> <NA>
    

    我在创建 df 时使用了 stringsAFactors=FALSE:

    df <- data.frame(x, y, stringsAsFactors = F)
    

    但是,如果我不这样做,则此代码将导致 @m0h3n 指出的错误。如果没有这种替代的 data.frame 构造,则需要将 df$y 包装在 as.character 中以将变量从一个因子强制转换为一个字符:

    # split the strings
    temp <- strsplit(as.character(df$y), split="")
    

    感谢@m0h3n 指出这一点。

    【讨论】:

    • as.character(df$y) 应该给strsplit 函数,否则它会失败。
    • @m0h3n 鉴于上述数据,您是对的。我在data.frame 函数中使用了stringsAsFactors=FALSE,但我没有提到这一点。谢谢提醒。
    【解决方案2】:

    这是另一个base R 选项,我们使用gsub 在“y”列的每个字符之间创建分隔符,,然后使用read.csv 读取它

    cbind(df[1],read.csv(text=gsub("(?<=.)(?=.)", ",", df$y, perl=TRUE), 
                    header=FALSE,fill=TRUE, na.strings = ""))
    #   x V1   V2   V3 V4   V5   V6
    #1 X1  0    0    L  0 <NA> <NA>
    #2 X2  0 <NA> <NA> NA <NA> <NA>
    #3 X3  0    0    0  1    2    L
    #4 X4  0    1    2  3    L    0
    #5 X5  0    D    0 NA <NA> <NA>
    

    或者使用tstrsplit from data.table

    mxr = max(nchar(as.character(df$y)))
    setDT(df)[, paste0("y", seq(mxr)) := tstrsplit(y, "")]
    

    【讨论】:

      【解决方案3】:

      您可以使用 strsplit 将 y 列中的字符串拆分为单个字符:

      > strsplit("00L0",c()) 
      [[1]]
      [1] "0" "0" "L" "0"
      

      从您的数据框开始:

      > df
         x      y
      1 X1   00L0
      2 X2      0
      3 X3 00012L
      4 X4 0123L0
      5 X5    0D0
      

      我通过以下方式解决了将这些字符放入列的问题:

      首先:使用 ddply 将 y 列中的所有字符串拆分并放在单独的行中

      > ddply(df, .(x), summarise, v = 1:nchar(as.character(y)), 
              y = unlist(strsplit(as.character(y),c())))
          x v y
      1  X1 1 0
      2  X1 2 0
      3  X1 3 L
      4  X1 4 0
      5  X2 1 0
      6  X3 1 0
      7  X3 2 0
      8  X3 3 0
      9  X3 4 1
      10 X3 5 2
      11 X3 6 L
      12 X4 1 0
      13 X4 2 1
      14 X4 3 2
      15 X4 4 3
      16 X4 5 L
      17 X4 6 0
      18 X5 1 0
      19 X5 2 D
      20 X5 3 0
      

      第二种:使用reshape将x值相同的行转换成列

      > reshape(ans, idvar=c("x"), timevar="v", direction="wide")
          x y.1  y.2  y.3  y.4  y.5  y.6
      1  X1   0    0    L    0 <NA> <NA>
      5  X2   0 <NA> <NA> <NA> <NA> <NA>
      6  X3   0    0    0    1    2    L
      12 X4   0    1    2    3    L    0
      18 X5   0    D    0 <NA> <NA> <NA>
      

      这可能会使问题过于复杂,但这是我让它工作的唯一方法!

      【讨论】:

        【解决方案4】:

        这行得通。它填充空白而不是NAs,但如果您愿意,您可以更改该事后。 (fill = 'right' 仅适用于在字符向量上拆分,而不是显式位置。)

        maxchar = max(nchar(as.character(df$y)))
        tidyr::separate(df, y, into = paste0("y", 1:maxchar), sep = 1:(maxchar - 1))
        
        #    x y1 y2 y3 y4 y5 y6
        # 1 X1  0  0  L  0         
        # 2 X2  0                  
        # 3 X3  0  0  0  1  2  L   
        # 4 X4  0  1  2  3  L  0   
        # 5 X5  0  D  0      
        

        【讨论】:

          猜你喜欢
          • 2018-03-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-23
          • 1970-01-01
          • 2019-02-17
          • 2016-09-04
          相关资源
          最近更新 更多