【问题标题】:R Cleaning and reordering names/serial numbers in data frameR清理和重新排序数据框中的名称/序列号
【发布时间】:2015-10-12 06:07:24
【问题描述】:

假设我在 R 中有如下数据框:

 Data <- data.frame("SerialNum" = character(), "Year" = integer(), "Name" = character(), stringsAsFactors = F)
 Data[1,] <- c("983\n837\n424\n ", 2015, "Michael\nLewis\nPaul\n ")
 Data[2,] <- c("123\n456\n789\n136", 2014, "Elaine\nJerry\nGeorge\nKramer")
 Data[3,] <- c("987\n654\n321\n975\n ", 2010, "John\nPaul\nGeorge\nRingo\nNA")
 Data[4,] <- c("424\n983\n837", 2015, "Paul\nMichael\nLewis")
 Data[5,] <- c("456\n789\n123\n136", 2014, "Jerry\nGeorge\nElaine\nKramer")

我想做的是:

  1. 拆分每个名称字符串和每个序列号字符串,使它们成为自己的向量(或字符串向量列表)。
  2. 删除向量集中的任何字符"NA""...\n " 表示的任何空格。
  3. 按字母顺序重新排列每个名称列表,并按照相同的排列重新排列相应的序列号。
  4. 以与最初相同的方式连接每个向量(我通常使用paste(., collapse = "\n") 这样做)。

我的问题是如何在不使用 for 循环的情况下做到这一点。什么是面向对象的方法来做到这一点?作为这个方向的第一次尝试,我最初通过命令LIST &lt;- strsplit(Data$Name, split = "\n") 列出了一个列表,从这里我需要一个 for 循环来查找名称的排列,这似乎是一个不会根据我的实际扩展的过程数据。此外,一旦我列出LIST,我不确定如何删除NA 符号或空格。任何帮助表示赞赏!

【问题讨论】:

    标签: r text-processing string-parsing


    【解决方案1】:

    使用lapply,我将数据框的每一行转换为一个新的数据框,每行一个名称。这将创建一个包含 5 个数据帧的列表,每个数据帧对应原始数据帧的每一行。

     seinfeld = lapply(1:nrow(Data), function(i) {
    
       # Turn strings into data frame with one name per row
       dat = data.frame(SerialNum=unlist(strsplit(Data[i,"SerialNum"], split="\n")), 
                  Year=Data[i,"Year"],
                  Name=unlist(strsplit(Data[i,"Name"], split="\n")))
    
       # Get rid of empty strings and NA values
       dat = dat[!(dat$Name %in% c(""," ","NA")), ]
    
       # Order alphabetically
       dat = dat[order(dat$Name), ]
     })
    

    更新:根据您的评论,让我知道这是否是您想要达到的结果:

    seinfeld = lapply(1:nrow(Data), function(i) {
    
      # Turn strings into data frame with one name per row
      dat = data.frame(SerialNum=unlist(strsplit(Data[i,"SerialNum"], split="\n")), 
                       Name=unlist(strsplit(Data[i,"Name"], split="\n")))
    
      # Get rid of empty strings and NA values
      dat = dat[!(dat$Name %in% c(""," ","NA")), ]
    
      # Order alphabetically
      dat = dat[order(dat$Name), ]
    
      # Collapse back into a single row with the new sort order
      dat = data.frame(SerialNum=paste(dat[, "SerialNum"], collapse="\n"),
                       Year=Data[i, "Year"],
                       Name=paste(dat[, "Name"], collapse="\n"))
    
    })
    
    do.call(rbind, seinfeld)
    
               SerialNum Year                          Name
    1      837\n983\n424 2015          Lewis\nMichael\nPaul
    2 123\n789\n456\n136 2014 Elaine\nGeorge\nJerry\nKramer
    3 321\n987\n654\n975 2010     George\nJohn\nPaul\nRingo
    4      837\n983\n424 2015          Lewis\nMichael\nPaul
    5 123\n789\n456\n136 2014 Elaine\nGeorge\nJerry\nKramer
    

    【讨论】:

    • 感谢您的回答,很抱歉这么久才回复。我正在寻找的最终结果看起来像原始数据框,除了按字母顺序排列和清理。如果我提供的样本数据集实际上只是一个较大数据帧的摘录,但我想在较大的数据帧上执行此操作,同时保持所有其他字段不变,您会怎么做?
    【解决方案2】:

    eipi10 提供了一个很好的答案。除此之外,我想将主要尝试的内容留在 data.table 中。首先,我用cSplit() 拆分两列(即SerialNum and Name),用add_rownames() 添加一个索引,然后按索引拆分数据。在第一个lapply() 中,我使用了splitstackshape 包中的Stacked()。我堆叠了 SerialNum 和 Name;如您在temp2 的一部分中所见,分隔的 SeriaNum 和 Name 成为两列。在第二个lapply() 中,我使用了data.table 包中的合并。然后,我删除了带有 NA 的行(lapply(na.omit)),合并了所有数据表(rbindlist),并通过rowname(原始数据的行号)和Namesetorder(rowname, Name))更改了行的顺序)

    library(data.table)
    library(splitstackshape)
    library(dplyr)
    
    cSplit(mydf, c("SerialNum", "Name"), direction = "wide",
           type.convert = FALSE, sep = "\n") %>%
    add_rownames %>%
    split(f = .$rowname) -> temp
    
    #a part of temp
    #$`1`
    #Source: local data frame [1 x 12]
    #
    #rowname  Year SerialNum_1 SerialNum_2 SerialNum_3 SerialNum_4 SerialNum_5  Name_1 Name_2
    #(chr) (dbl)       (chr)       (chr)       (chr)       (chr)       (chr)   (chr)  (chr)
    #1       1  2015         983         837         424          NA          NA Michael  Lewis
    #Variables not shown: Name_3 (chr), Name_4 (chr), Name_5 (chr)
    
    
    lapply(temp, function(x){
    
        Stacked(x, var.stubs = c("SerialNum", "Name"), sep = "_")
    
    }) -> temp2
    
    # A part of temp2
    #$`1`
    #$`1`$SerialNum
    #   rowname Year .time_1 SerialNum
    #1:       1 2015       1       983
    #2:       1 2015       2       837
    #3:       1 2015       3       424
    #4:       1 2015       4        NA
    #5:       1 2015       5        NA
    #
    #$`1`$Name
    #   rowname Year .time_1    Name
    #1:       1 2015       1 Michael
    #2:       1 2015       2   Lewis
    #3:       1 2015       3    Paul
    #4:       1 2015       4      NA
    #5:       1 2015       5      NA
    
    lapply(1:nrow(mydf), function(x){
    
        merge(temp2[[x]]$SerialNum, temp2[[x]]$Name, by = c("rowname", "Year", ".time_1"))
    
    }) %>%
    
    lapply(na.omit) %>%
    rbindlist %>%
    setorder(rowname, Name) -> out
    
    print(out)
    
     #    rowname Year .time_1 SerialNum    Name
     # 1:       1 2015       2       837   Lewis
     # 2:       1 2015       1       983 Michael
     # 3:       1 2015       3       424    Paul
     # 4:       2 2014       1       123  Elaine
     # 5:       2 2014       3       789  George
     # 6:       2 2014       2       456   Jerry
     # 7:       2 2014       4       136  Kramer
     # 8:       3 2010       3       321  George
     # 9:       3 2010       1       987    John
     #10:       3 2010       2       654    Paul
     #11:       3 2010       4       975   Ringo
     #12:       4 2015       3       837   Lewis
     #13:       4 2015       2       983 Michael
     #14:       4 2015       1       424    Paul
     #15:       5 2014       3       123  Elaine
     #16:       5 2014       2       789  George
     #17:       5 2014       1       456   Jerry
     #18:       5 2014       4       136  Kramer
    

    数据

    mydf <- structure(list(SerialNum = c("983\n837\n424\n ", "123\n456\n789\n136", 
    "987\n654\n321\n975\n ", "424\n983\n837", "456\n789\n123\n136"
    ), Year = c(2015, 2014, 2010, 2015, 2014), Name = c("Michael\nLewis\nPaul\n ", 
    "Elaine\nJerry\nGeorge\nKramer", "John\nPaul\nGeorge\nRingo\nNA", 
    "Paul\nMichael\nLewis", "Jerry\nGeorge\nElaine\nKramer")), .Names = c("SerialNum", 
    "Year", "Name"), row.names = c(NA, -5L), class = "data.frame")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多