R中的递归函数,用于查找数据表列表的唯一行

时间:2013-06-22 17:47:42

标签: r data.table

我正在开发一个函数,该函数将具有相同列名的数据表列表作为输入,并返回单个数据表,该表具有使用连续rbind组合的每个数据帧中的唯一行,如下所示。

该函数将应用于“非常”大的data.table(数百万行),这就是我必须将其拆分为几个较小的数据表并将它们分配到列表以使用递归的原因。在每一步,取决于数据表列表的长度(奇数或偶数),我找到该列表索引的data.table和列表索引x - 1的数据表的唯一,然后连续rbind 2并分配列出索引x - 1,以及更多列表索引x。

我必须遗漏一些明显的东西,因为虽然我可以在打印时产生最终的unique-d data.table(例如,print(listelement [[1]]),但当我返回时(listelement [[1] ])我得到NULL。如果有人能发现我所遗漏的内容会有所帮助......或者建议是否有其他更有效的方法来执行此操作。

此外,我可以将它们添加为列表中的“引用”,而不必将每个data.table添加到列表中吗?我相信像list(datatable1,datatable2 ......)这样的东西实际上会复制它们吗?

## CODE
returnUnique2 <- function (alist) {

if (length(alist) == 1) {
  z <- (alist[[1]])
  print (class(z))
  print (z)   ### This is the issue, if I change to return (z), I get NULL (?)
}

if (length(alist) %% 2 == 0) {
  alist[[length(alist) - 1]] <- unique(rbind(unique(alist[[length(alist)]]), unique(alist[[length(alist) - 1]])))
  alist[[length(alist)]] <- NULL
  returnUnique2(alist)
}

if (length(alist) %% 2 == 1 && length(alist) > 2) {
  alist[[length(alist) - 1]] <- unique(rbind(unique(alist[[length(alist)]]), unique(alist[[length(alist) - 1]])))
  alist[[length(alist)]] <- NULL
  returnUnique2(alist)
}  
}


## OUTPUT with print statement
t1 <- data.table(col1=rep("a",10), col2=round(runif(10,1,10)))
t2 <- data.table(col1=rep("a",10), col2=round(runif(10,1,10)))
t3 <- data.table(col1=rep("a",10), col2=round(runif(10,1,10)))
tempList <- list(t1, t2, t3)

returnUnique2(tempList)

[1] "list"
[[1]]
col1 col2
 1:    a    3
 2:    a    2
 3:    a    5
 4:    a    9
 5:    a   10
 6:    a    7
 7:    a    1
 8:    a    8
 9:    a    4
10:    a    6

更改以下内容,

print (z)   ### This is the issue, if I change to return (z), I get NULL (?)

阅读

return(z)

返回NULL

提前致谢。

3 个答案:

答案 0 :(得分:1)

似乎这可能是for循环的一个很好的用例。对于许多行,与计算时间相比,使用for循环的开销应该相对较小。我会尝试将我的data.table组合到一个列表中(在我的示例中称为ll),然后为每个删除重复的行,然后rbind添加到上一个data.table唯一行,然后再次按唯一行子集。

如果你在每个块中有很多重复的行,那么这可能会节省一些时间,总的来说我不确定它会有多么有效,但值得一试?

#  Create empty data.table for results (I have columns x and y in this case)
res <- data.table( x= numeric(0),y=numeric(0))

#   loop over all data.tables in a list called 'll'
for( i in 1:length(ll) ){
    #  rbind the unique rows from the current list element to the results from all previous iterations
    res <- rbind( res , ll[[i]][ ! duplicated(ll[[i]]) , ] )
    #  Keep only unique records at each iteration
    res <- res[ ! duplicated(res) , ]
}

另一方面,你看过data.table的文档了吗?它明确指出,

  

因为data.tables通常按键排序,所以重复测试   特别快。

所以你可能最好还是运行整个data.table?

DT[ ! duplicated(DT) , ]

答案 1 :(得分:1)

如果我误解了你正在做的事情,请纠正我,但听起来你有一个大的data.table,并且正试图将其分开以对其运行某些功能,然后将所有内容组合起来并运行一个独一无二的。 data.table这样做的方法是使用by,例如

fn = function(d) {
  # do whatever to the subset and return the resulting data.table
  # in this case, do nothing
  d
}

N = 10  # number of pieces you like
dt[, fn(.SD), by = (seq_len(nrow(dt)) - 1) %/% (nrow(dt)/N)][, seq_len := NULL]
dt = dt[!duplicated(dt)]

答案 2 :(得分:0)

为每个data.table

添加一个id列
t1$id=1
t2$id=2
t3$id=3

然后将它们全部组合在一起并使用by=执行唯一操作。 如果data.tables很大,你可以使用setkey(...)在id之前创建一个索引,然后再调用unique。

tall=rbind(t1,t2,t3)
tall[,unique(col1,col2),by=id]