2015-10-03 38 views
0

比方说,我有一个数据帧中的R如下:[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 <- strsplit(Data$Name, split = "\n")创建了一个列表,并且从这里我需要一个for循环来查找名称的排列,这看起来像一个不会根据我的实际数据进行缩放的进程。此外,一旦我列出名单LIST我不知道我如何去除NA符号或空格。任何帮助表示赞赏!

回答

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), ] 
}) 

UPDATE:基于您的评论,让我知道,如果这是你想达到的效果:

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 
+0

谢谢您的回答,和对不起它采取了这么长时间才做出反应。我正在寻找的最终结果是看起来像原始数据框,除了按字母顺序排列和清理。如果我给出的样本数据集实际上只是一个较大数据框的摘录,那么您会如何做到这一点,但是我想在更大的数据框上执行此操作,同时保持所有其他字段不变? – Mnifldz

1

eipi10提供了一个伟大的答案。除此之外,我想离开我主要使用data.table尝试的东西。首先,我将两列(即SerialNum and Name)与cSplit()分开,添加一个索引add_rownames(),并将索引拆分为数据。在第一个lapply()中,我使用了splitstackshape包中的Stacked()。我堆叠了SerialNum和Name;分离的SeriaNum和Name将成为两列,如您在temp2的一部分中看到的那样。在第二个lapply()中,我使用data.table包进行合并。然后,我删除行与NAS(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 

DATA

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")