【问题标题】:Split rows to columns in R在R中将行拆分为列
【发布时间】:2020-03-26 17:37:13
【问题描述】:

我有一个这样的文本数据文件(各个类别 [A,B,C] 有多行):

A=1,2,3,6,
7,9
10
B=3,4,5
C=5,7,8,10,11,
13,14

当我加载到 R 时,它变成了一个有 6 个 obs 的数据框。和 1 个变量

df <- read.delim("file.text",header = FALSE)

    v1
1   A=1,2,3,6,
2   7,9
3   10
4   B=3,4,5
5   C=5,7,8,10,11,
6   13,14

如何更改为这种格式?

   A  B  C
1  A
2  A
3  A  B
4     B
5     B  C
6  A
7  A     C
8        C
9  A
10 A     C
11       C
13       C
14       C

谢谢!

【问题讨论】:

  • 您不会为此找到内置函数。您必须将文件作为字符串导入,然后编写一个函数来使用正则表达式解析它
  • CHONG,让我们知道下面的答案是如何为您服务的。

标签: r reshape melt


【解决方案1】:

基本方法是将数据作为字符串读取,拆分为=,,然后找出识别每个数字所属组的最佳方法。

在以下方法中,我有意使用类型转换来创建组。由于这将涉及从字符到数字的强制转换,因为拆分值中有字符,所以会出现一些警告消息。

# Load the data.table package.
library(data.table)

# Read in the data.
x <- fread("A=1,2,3,6,
7,9
10
B=3,4,5
C=5,7,8,10,11,
13,14", sep = "\n", header = FALSE)

x[, unlist(strsplit(V1, "=|,"), use.names = FALSE, recursive = FALSE), .I][
  , list(ind = as.integer(V1), col = rep(V1[1], .N)), cumsum(is.na(as.integer(V1)))][
    , dcast(na.omit(.SD), ind ~ col, value.var = "col", fill = "")]
#     ind A B C
#  1:   1 A    
#  2:   2 A    
#  3:   3 A B  
#  4:   4   B  
#  5:   5   B C
#  6:   6 A    
#  7:   7 A   C
#  8:   8     C
#  9:   9 A    
# 10:  10 A   C
# 11:  11     C
# 12:  13     C
# 13:  14     C

这是使用我的“splitstackshape”包中的cSplit 的另一种选择。 “x”是使用fread读入的相同数据。

library(splitstackshape)
cSplit(
  cSplit(x[, toString(V1), cumsum(grepl("[A-Z]", V1))], "V1", "="), "V1_2", ",", "long")[
    , dcast(.SD, V1_2 ~ V1_1, value.var = "V1_1", fill = "")]

【讨论】:

    【解决方案2】:

    使用readLines() 的基本 R 方法。我们首先将以字符开头的单元格索引存储在向量ch 中,这有助于将paste 的序列一起查找到l2 中。 l2as.numeric 已经给出了最终数据帧d 的索引。我们从l3的维度构造NAs中的d,并根据l3的值进行填充。

    l <- readLines("delim.txt")
    ch <- c(grep("^\\D", l))
    l2 <- apply(rbind(ch, c(ch[-1] - 1, length(l))), 2, 
                function(x) Reduce(paste, l[x[1]:x[2]]))
    l3 <- lapply(sapply(strsplit(l2, "\\D"), as.numeric), na.omit)
    d <- matrix(NA, max(sapply(l3, max)), length(l3))
    let <- gsub("(.*)\\=.*", "\\1", l2)  # the col-names
    sapply(seq(length(l3)), function(n) d[l3[[n]], n] <<- let[n])
    setNames(as.data.frame(d), let)
    #      A    B    C
    # 1     A <NA> <NA>
    # 2     A <NA> <NA>
    # 3     A    B <NA>
    # 4  <NA>    B <NA>
    # 5  <NA>    B    C
    # 6     A <NA> <NA>
    # 7     A <NA>    C
    # 8  <NA> <NA>    C
    # 9     A <NA> <NA>
    # 10    A <NA>    C
    # 11 <NA> <NA>    C
    # 12 <NA> <NA> <NA>
    # 13 <NA> <NA>    C
    # 14 <NA> <NA>    C
    

    【讨论】:

      【解决方案3】:

      这是tidyverse 方法。

      library(dplyr)
      library(tidyr)
      
      df %>%
        #Remove commas at the end of the string
        mutate(V1 = sub(",$", "", V1)) %>%
        #Divide data into separate column based on "=" sign
        separate(V1, into = c("let", "num"), sep = "=", fill = "left") %>%
        #fill the NA values with it's respective group
        fill(let) %>%
        #Convert comma-separated value into different rows
        separate_rows(num, convert = TRUE) %>%
        #Convert data to wide format filling missing values with empty string
        pivot_wider(names_from = let, values_from = let, values_fill = list(let = "")) %>%
        #Arrange data according to numbers
        arrange(num)
      
      #  # A tibble: 13 x 4
      #     num A     B     C    
      #   <int> <chr> <chr> <chr>
      # 1     1 A     ""    ""   
      # 2     2 A     ""    ""   
      # 3     3 A     B     ""   
      # 4     4 ""    B     ""   
      # 5     5 ""    B     C    
      # 6     6 A     ""    ""   
      # 7     7 A     ""    C    
      # 8     8 ""    ""    C    
      # 9     9 A     ""    ""   
      #10    10 A     ""    C    
      #11    11 ""    ""    C    
      #12    13 ""    ""    C    
      #13    14 ""    ""    C  
      

      如果您想将num 列作为行名添加%&gt;% column_to_rownames('num')

      数据

      df <- read.table(text = "A=1,2,3,6,
      7,9
      10
      B=3,4,5
      C=5,7,8,10,11,
      13,14")
      

      【讨论】:

      • 我认为您应该在arrange(num) 停下来获得正确答案。
      • 好的,为了清楚起见,保留num 列。
      • 酷。 +1。 column_to_rownames('num') 也是一个合适的解决方案,但删除“num”并没有,因为它表明数据中有一个 C=12(没有)。
      【解决方案4】:

      base中,你可以paste将行合并为一行,使用strsplit获取单个数字和列名,创建一个名为matrix并使用子集填充它。

      x <- readLines(con=textConnection("A=1,2,3,6,
      7,9
      10
      B=3,4,5
      C=5,7,8,10,11,
      13,14"))
      
      x <- paste(gsub("=","",x), collapse = ",")
      y <- lapply(strsplit(unlist(strsplit(x, "[[:alpha:]]+"))[-1], ","), function(i) i[!i==""])
      names(y)  <- strsplit(x, "[^[:alpha:]]+")[[1]]
      z <- sort(unique(as.numeric(unlist(y))))
      res <- matrix("", nrow=length(z), ncol=length(y), dimnames=list(z, names(y)))
      sapply(names(y), function(i) res[y[[i]], i]  <<- i)
      res
      #   A   B   C  
      #1  "A" ""  "" 
      #2  "A" ""  "" 
      #3  "A" "B" "" 
      #4  ""  "B" "" 
      #5  ""  "B" "C"
      #6  "A" ""  "" 
      #7  "A" ""  "C"
      #8  ""  ""  "C"
      #9  "A" ""  "" 
      #10 "A" ""  "C"
      #11 ""  ""  "C"
      #13 ""  ""  "C"
      #14 ""  ""  "C"
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-02
        • 1970-01-01
        • 2014-07-28
        • 1970-01-01
        • 2016-05-17
        • 1970-01-01
        • 1970-01-01
        • 2018-05-30
        相关资源
        最近更新 更多