2015-10-03 40 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")