2016-12-28 31 views
4

我有data.frame列表,需要應用非常具體的重複刪除方法。我有理由對此data.frame列表使用特定的條件重複刪除。但是,每個單獨的data.frame的重複刪除條件是不同的。我想爲第一個列表元素完成重複刪除;對於第二個列表元素,我需要搜索出現兩次以上(freq> 2)的行,並且只保留一行;對於第三個列表元素,搜索出現三次以上(freq> 3)的行,並在該data.frame中保留兩行。我正在嘗試爲此數據處理任務獲得更多編程式動態解決方案。我試過我的鏡頭來獲得很好的解決方案,但無法獲得我想要的輸出。我如何輕鬆地做到這一點?任何方式更有效地完成這項任務,尊重我的具體產出?請任何想法嗎?如何將條件重複刪除應用於data.frame列表?

重複性data.frame:

myList <- list(
    bar= data.frame(start.pos=c(9,19,34,54,70,82,136,9,34,70,136,9,82,136), 
        end.pos=c(14,21,39,61,73,87,153,14,39,73,153,14,87,153), 
        pos.score=c(48,6,9,8,4,15,38,48,9,4,38,48,15,38)), 
    cat = data.frame(start.pos=c(7,21,21,72,142,7,16,21,45,72,100,114,142,16,72,114), 
        end.pos=c(10,34,34,78,147,10,17,34,51,78,103,124,147,17,78,124), 
        pos.score=c(53,14,14,20,4,53,20,14,11,20,7,32,4,20,20,32)), 
    foo= data.frame(start.pos=c(12,12,12,58,58,58,118,12,12,44,58,102,118,12,58,118), 
        end.pos=c(36,36,36,92,92,92,139,36,36,49,92,109,139,36,92,139), 
        pos.score=c(48,48,48,12,12,12,5,48,48,12,12,11,5,48,12,5)) 
) 

因爲myList是自定義函數的結果,data.frame無法分離。我正在尋求更多的程序化解決方案來爲我的數據做出特定的重複刪除。如果輸入是data.frame列表,我怎樣才能做出特定的重複刪除?

我的期望輸出如下:

expectedList <- list(
    bar= data.frame(start.pos=c(9,19,34,54,70,82,136), 
        end.pos=c(14,21,39,61,73,87,153), 
        pos.score=c(48,6,9,8,4,15,38)), 
    cat= data.frame(start.pos=c(7,21,72,142,7,16,45,100,114,142,16,114), 
        end.pos=c(10,34,78,147,10,17,51,103,124,147,17,124), 
        pos.score=c(53,14,20,4,53,20,11,7,32,4,20,32)), 
    foo= data.frame(start.pos=c(12,12,44,58,58,118,102,118,118), 
        end.pos=c(36,36,49,92,92,139,109,139,139), 
        pos.score=c(48,48,12,12,12,5,11,5,5)) 
) 

編輯

在第二data.frame cat

,我要查找出現三次行,並保持只有行一旦;如果行出現兩次,我不會做重複的刪除。

for third data.frame foo,我將檢查出現三次以上的行,並保留兩個相同的行。這是我想要爲每個data.frame進行非常具體的重複刪除。我怎樣才能得到我的輸出?

如何獲取我想要的data.frame列表?我如何輕鬆地做到這一點?非常感謝 !

+0

這是肯定要做,能但可能會有一些限制,這是多麼的方案,除非有一個在邏輯明確的模式。我認爲,對於每個列表項目,您總是希望將允許的重複項數增加1,對吧? –

+1

您預期的'foo'輸出看起來不正確。 '(118,139,5)'出現三次。 – bouncyball

+2

不確定預期的輸出是否正確。也許'library(data.table); Map(函數(x,y)setDT(x)[x [,.I [(1:.N)<= y],。(start.pos,end.pos,pos .score)] $ V1],myList,1:3)' – akrun

回答

6

我們可以這樣做Map子集行list個元素基於用向量中指定的相應編號創建的邏輯索引(1:3)。將list中的data.frame元素轉換爲data.tablesetDT(x)),按列('start.pos','end.pos','pos.score')進行分組,得到行數(.N),創建一個邏輯索引與if/else並獲得滿足在OP的帖子中指定的條件的行的序列,使用.I獲得行索引,提取該索引列($V1)並使用它來對數據集進行子集化。

library(data.table) 
res <- Map(function(x,y) setDT(x)[x[, .I[if(.N > y) seq_len(pmax(y-1, 1)) 
     else seq_len(.N)] , .(start.pos, end.pos, pos.score)]$V1], myList, 1:3) 
sapply(res, nrow) 
#bar cat foo 
# 7 12 9 

sapply(expectedList, nrow) 
#bar cat foo 
#7 12 9 
+0

我可以多解釋一下這個data.table解決方案嗎?使用'.N','。()$ V1'來達到這個目的?我對data.table包非常熟悉。瞭解您的解決方案對了解您的想法非常有幫助。謝謝:) – Dan

+1

@丹更新了一些描述。希望能幫助到你 – akrun

1

應用下面的函數列表指定每行的最大頻率的每個數據幀

removeDuplicate = function(df, freq=1) { 

    # back up the dataframe and add a row id 
    tmp = df; 
    tmp$cnt = 1:NROW(df); 
    # get each row frequency 
    cnt = aggregate(cnt~., tmp, length); 

    # merge the original data-frame and the row-frequency data-frame 
    tmp = merge(df, cnt, by=names(df)); 
    tmp = rbind(
       tmp[tmp$cnt<=freq, names(df)], # keep all the rows which frequency is not greater than the max allowed 
       cnt[, names(df)] # add all the other rows just once 
      ); 

    return(tmp); 

} 

要應用功能,每個數據幀我會做:

expectedList = myList 
maxFreq = c(1, 2, 3) 
for(i in 1:length(expectedList)) { 

    expectedList[[i]] = removeDuplicate(expectedList[[i]], maxFreq[i]) 

} 

但我認爲使用lapply可以找到一個更優雅的解決方案...

1
# Separate individual dataframes 
bar = myList$bar 
cat = myList$cat 
foo = myList$foo 

# We will need ddply command of plyr package 
library(plyr) 

#Count how many times the rows have repeated and put the value in the fourth column (V1) 
bar = ddply(bar,.(start.pos,end.pos,pos.score),nrow) 
cat = ddply(cat,.(start.pos,end.pos,pos.score),nrow) 
foo = ddply(foo,.(start.pos,end.pos,pos.score),nrow) 

# For each data.frame, change the number of repetions to appropriate number of times 
# if the rows have repeated for more than the desired number of times 
# i.e 1 for bar, 2 for cat, and 3 for foo 
for (i in 1:nrow(bar)){ 
if (bar$V1[i] > 1){ 
bar$V1[i] = 1 
}} 
for (i in 1:nrow(cat)){ 
if (cat$V1[i] > 2){ 
cat$V1[i] = 1 
}} 
for (i in 1:nrow(foo)){ 
if (foo$V1[i] > 2){ 
foo$V1[i] = 2 
}} 

# Repeat each row for the number of times indicated in the fourth column. 
# This will be 1 for bar, up to 2 for cat, and up to 3 for foo 
bar = bar[rep(row.names(bar), bar[,4]), 1:3] 
cat = cat[rep(row.names(cat), cat[,4]), 1:3] 
foo = foo[rep(row.names(foo), foo[,4]), 1:3] 

# Set the rownames to NULL if desired 
rownames(cat) = NULL 
rownames(bar) = NULL 
rownames(foo) = NULL 

# Combine the indivudal data.frames into a new list 
expectedList = list(bar = bar,cat = cat,foo = foo)