2016-12-28 73 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)