如何在data.table中按引用删除行?

Flo*_*ald 144 r data.table

我的问题与引用分配和复制分配有关data.table.我想知道是否可以通过引用删除行,类似于

DT[ , someCol := NULL]
Run Code Online (Sandbox Code Playgroud)

我想知道

DT[someRow := NULL, ]
Run Code Online (Sandbox Code Playgroud)

我想有一个很好的理由说明为什么这个功能不存在,所以也许你可以指出一个很好的替代通常的复制方法,如下所示.特别是,从我的例子(data.table)开始,

DT = data.table(x = rep(c("a", "b", "c"), each = 3), y = c(1, 3, 6), v = 1:9)
#      x y v
# [1,] a 1 1
# [2,] a 3 2
# [3,] a 6 3
# [4,] b 1 4
# [5,] b 3 5
# [6,] b 6 6
# [7,] c 1 7
# [8,] c 3 8
# [9,] c 6 9
Run Code Online (Sandbox Code Playgroud)

假设我想从此data.table中删除第一行.我知道我可以这样做:

DT <- DT[-1, ]
Run Code Online (Sandbox Code Playgroud)

但通常我们可能想要避免这种情况,因为我们正在复制对象(这需要大约3*N内存,如果是N object.size(DT),如此处所指出的那样.现在我发现set(DT, i, j, value).我知道如何设置特定值(如下所示:set all第1行和第2行以及第2列和第3列的值为零)

set(DT, 1:2, 2:3, 0) 
DT
#      x y v
# [1,] a 0 0
# [2,] a 0 0
# [3,] a 6 3
# [4,] b 1 4
# [5,] b 3 5
# [6,] b 6 6
# [7,] c 1 7
# [8,] c 3 8
# [9,] c 6 9
Run Code Online (Sandbox Code Playgroud)

但是,如何删除前两行呢?干

set(DT, 1:2, 1:3, NULL)
Run Code Online (Sandbox Code Playgroud)

将整个DT设置为NULL.

我的SQL知识非常有限,所以你们告诉我:给定的data.table使用SQL技术,是否有与SQL命令相同的功能

DELETE FROM table_name
WHERE some_column=some_value
Run Code Online (Sandbox Code Playgroud)

在data.table?

Mat*_*wle 119

好问题.data.table无法通过引用删除行.

data.table可以通过引用添加和删​​除,因为它会过度分配列指针的向量,如您所知.计划是为行做类似的事情,并允许快速insertdelete.行删除将memmove在C中用于在删除的行之后预订项目(在每一列中).与诸如SQL之类的行存储数据库相比,删除表中间的行仍然是非常低效的,这更适合于快速插入和删除表中这些行的任何位置.但是,它仍然比复制没有删除行的新大对象快得多.

另一方面,由于列向量将被过度分配,因此可以在末尾立即插入(和删除)行; 例如,不断增长的时间序列.


它是一个问题:通过引用删除行.

  • @statquant我想我应该修复37个bug,然后先完成`fread`.之后它非常高. (15认同)
  • @MatthewDowle肯定,再次感谢你所做的一切. (15认同)
  • 它被提交为[FR#635](https://github.com/Rdatatable/data.table/issues/635) (3认同)
  • 仍然希望这个功能;-) (3认同)
  • @Matthew Dowle 有这方面的新闻吗? (2认同)
  • @charliealpha 没有更新。欢迎投稿。我愿意指导。它需要 C 技能 - 再次,我愿意指导。 (2认同)

vc2*_*273 28

我为使内存使用而采取的方法类似于就地删除是一次对列进行子集并删除.没有正确的C memmove解决方案快,但内存使用是我在这里所关心的.这样的事情:

DT = data.table(col1 = 1:1e6)
cols = paste0('col', 2:100)
for (col in cols){ DT[, (col) := 1:1e6] }
keep.idxs = sample(1e6, 9e5, FALSE) # keep 90% of entries
DT.subset = data.table(col1 = DT[['col1']][keep.idxs]) # this is the subsetted table
for (col in cols){
  DT.subset[, (col) := DT[[col]][keep.idxs]]
  DT[, (col) := NULL] #delete
}
Run Code Online (Sandbox Code Playgroud)

  • +1尼斯记忆效率高的方法.所以理想情况下我们需要通过引用删除一组行而不是我们,我没有想到这一点.它必须是一系列"memmove",以填补空白,但没关系. (5认同)
  • 谢谢,很好的一个。为了加快一点速度(尤其是对于很多列),您可以在“set(DT, NULL, col, NULL)”中更改“DT[, col:= NULL, with = F]” (2认同)
  • 根据改变惯用语和警告"with = FALSE with with:=在2014年10月发布的v1.9.4中被弃用.请用LHS:=括号括起来;例如,DT [,(myVar):= sum(b) ,通过= a]分配给变量myVar中保存的列名.请参阅?':='作为其他示例.正如2014年警告的那样,这现在是一个警告." (2认同)

Jar*_* P. 5

这是一个基于@ vc273的答案和@Frank的反馈的工作函数.

delete <- function(DT, del.idxs) {           # pls note 'del.idxs' vs. 'keep.idxs'
  keep.idxs <- setdiff(DT[, .I], del.idxs);  # select row indexes to keep
  cols = names(DT);
  DT.subset <- data.table(DT[[1]][keep.idxs]); # this is the subsetted table
  setnames(DT.subset, cols[1]);
  for (col in cols[2:length(cols)]) {
    DT.subset[, (col) := DT[[col]][keep.idxs]];
    DT[, (col) := NULL];  # delete
  }
   return(DT.subset);
}
Run Code Online (Sandbox Code Playgroud)

其用法示例:

dat <- delete(dat,del.idxs)   ## Pls note 'del.idxs' instead of 'keep.idxs'
Run Code Online (Sandbox Code Playgroud)

其中"dat"是data.table.从我的笔记本电脑上删除1.4M行中的14k行需要0.25秒.

> dim(dat)
[1] 1419393      25
> system.time(dat <- delete(dat,del.idxs))
   user  system elapsed 
   0.23    0.02    0.25 
> dim(dat)
[1] 1404715      25
> 
Run Code Online (Sandbox Code Playgroud)

PS.由于我是SO的新手,我无法在@ vc273的帖子中添加评论:-(

  • @skan ,该分配将“dat”分配给指向修改后的 data.table,该表本身是通过对原始 data.table 进行子集化而创建的。&lt;- 分配不会复制返回数据,只是为其分配新名称。[链接](http://stackoverflow.com/questions/10225098/understanding-exactly-when-a-data-table-is-a-reference-to-vs-a-copy-of-another) (2认同)

JRR*_*JRR 5

这个话题仍然让很多人(包括我)感兴趣。

那个怎么样?我曾经assign替换过glovalenv和 前面描述的代码。捕获原始环境会更好,但至少globalenv它具有内存效率,并且就像通过引用进行更改一样。

delete <- function(DT, del.idxs) 
{ 
  varname = deparse(substitute(DT))

  keep.idxs <- setdiff(DT[, .I], del.idxs)
  cols = names(DT);
  DT.subset <- data.table(DT[[1]][keep.idxs])
  setnames(DT.subset, cols[1])

  for (col in cols[2:length(cols)]) 
  {
    DT.subset[, (col) := DT[[col]][keep.idxs]]
    DT[, (col) := NULL];  # delete
  }

  assign(varname, DT.subset, envir = globalenv())
  return(invisible())
}

DT = data.table(x = rep(c("a", "b", "c"), each = 3), y = c(1, 3, 6), v = 1:9)
delete(DT, 3)
Run Code Online (Sandbox Code Playgroud)


42-*_*42- 4

相反,或者尝试设置为 NULL,请尝试设置为 NA(匹配第一列的 NA 类型)

set(DT,1:2, 1:3 ,NA_character_)
Run Code Online (Sandbox Code Playgroud)

  • 是的,我想这可行。我的问题是我有很多数据,我想准确地删除那些带有 NA 的行,可能不需要复制 DT 来删除这些行。不管怎样,谢谢你的评论! (3认同)