gpt4 book ai didi

r - 有效检查data.table中其他行的值

转载 作者:行者123 更新时间:2023-12-04 11:28:59 24 4
gpt4 key购买 nike

注:这是我最初发布到 data.table 帮助组的问题。 Matt Dowle 要求提供一个更详细的示例,我发布了这个示例,但是我在电子邮件中格式化时遇到了问题。我已经知道如何在 SO 上格式化,所以我想我会在这里发布它。

我基本上想要做的是基于该行中的值从 data.table 中子集行 以及 前一行或后一行中的值。现在,我正在为 future 和过去的行创建新列,然后在这些列上键入 data.table,但这是资源密集型和繁重的。

下面的例子说明了我现在使用的方法。该示例使用文档中的单词(我对两者都使用数字索引)。我想对特定单词进行子集化,但前提是它前面或后面是另一个单词或一组单词:

我首先创建了一个虚拟数据集,其中包含 10 个包含 100 万个单词的文档。该集合中有三个独特的词。

library(data.table)
set.seed(1000)
DT<-data.table(wordindex=sample(1:3,1000000,replace=T),docindex=sample(1:10,1000000,replace=T))
setkey(DT,docindex)
DT[,position:=seq.int(1:.N),by=docindex]


wordindex docindex position
1: 1 1 1
2: 1 1 2
3: 3 1 3
4: 3 1 4
5: 1 1 5
---
999996: 2 10 99811
999997: 2 10 99812
999998: 3 10 99813
999999: 1 10 99814
1000000: 3 10 99815

请注意,简单地计算所有文档中第一个唯一单词的出现次数既简单又美观。
setkey(DT,wordindex)
count<-DT[J(1),list(count.1=.N),by=docindex]
count

docindex count.1
1: 1 33533
2: 2 33067
3: 3 33538
4: 4 33053
5: 5 33231
6: 6 33002
7: 7 33369
8: 8 33353
9: 9 33485
10: 10 33225

考虑到前面的位置时,情况会变得更加困惑。这是一个查询,用于计算所有文档中第一个唯一单词的出现次数 除非 紧随其后的是第二个唯一词。首先,我创建一个新列,其中包含前面一个位置的单词,然后键入两个单词。
setkey(DT,docindex,position)
DT[,lead_wordindex:=DT[list(docindex,position+1)][,wordindex]]

wordindex docindex position lead_wordindex
1: 1 1 1 1
2: 1 1 2 3
3: 3 1 3 3
4: 3 1 4 1
5: 1 1 5 2
---
999996: 2 10 99811 2
999997: 2 10 99812 3
999998: 3 10 99813 1
999999: 1 10 99814 3
1000000: 3 10 99815 NA

setkey(DT,wordindex,lead_wordindex)
countr2<-DT[J(c(1,1),c(1,3)),list(count.1=.N),by=docindex]
countr2

docindex count.1
1: 1 22301
2: 2 21835
3: 3 22490
4: 4 21830
5: 5 22218
6: 6 21914
7: 7 22370
8: 8 22265
9: 9 22211
10: 10 22190

我有一个非常大的数据集,上面的查询无法分配内存。作为替代方案,我们可以通过过滤原始数据集然后将其连接回所需位置,仅为相关数据子集创建此新列:
setkey(DT,wordindex)
filter<-DT[J(1),list(wordindex,docindex,position)]
filter[,lead_position:=position+1]

wordindex wordindex docindex position lead_position
1: 1 1 2 99717 99718
2: 1 1 3 99807 99808
3: 1 1 4 100243 100244
4: 1 1 1 1 2
5: 1 1 1 42 43
---
332852: 1 1 10 99785 99786
332853: 1 1 10 99787 99788
332854: 1 1 10 99798 99799
332855: 1 1 10 99804 99805
332856: 1 1 10 99814 99815

setkey(DT,docindex,position)
filter[,lead_wordindex:=DT[J(filter[,list(docindex,lead_position)])][,wordindex]]

wordindex wordindex docindex position lead_position lead_wordindex
1: 1 1 2 99717 99718 NA
2: 1 1 3 99807 99808 NA
3: 1 1 4 100243 100244 NA
4: 1 1 1 1 2 1
5: 1 1 1 42 43 1
---
332852: 1 1 10 99785 99786 3
332853: 1 1 10 99787 99788 3
332854: 1 1 10 99798 99799 3
332855: 1 1 10 99804 99805 3
332856: 1 1 10 99814 99815 3

setkey(filter,wordindex,lead_wordindex)
countr2.1<-filter[J(c(1,1),c(1,3)),list(count.1=.N),by=docindex]
countr2.1

docindex count.1
1: 1 22301
2: 2 21835
3: 3 22490
4: 4 21830
5: 5 22218
6: 6 21914
7: 7 22370
8: 8 22265
9: 9 22211
10: 10 22190

太丑了,我觉得。此外,我可能要向前看不止一个词,因此需要创建另一列。简单但昂贵的方法是:
setkey(DT,docindex,position)
DT[,lead_lead_wordindex:=DT[list(docindex,position+2)][,wordindex]]

wordindex docindex position lead_wordindex lead_lead_wordindex
1: 1 1 1 1 3
2: 1 1 2 3 3
3: 3 1 3 3 1
4: 3 1 4 1 2
5: 1 1 5 2 3
---
999996: 2 10 99811 2 3
999997: 2 10 99812 3 1
999998: 3 10 99813 1 3
999999: 1 10 99814 3 NA
1000000: 3 10 99815 NA NA

setkey(DT,wordindex,lead_wordindex,lead_lead_wordindex)
countr23<-DT[J(1,2,3),list(count.1=.N),by=docindex]
countr23

docindex count.1
1: 1 3684
2: 2 3746
3: 3 3717
4: 4 3727
5: 5 3700
6: 6 3779
7: 7 3702
8: 8 3756
9: 9 3702
10: 10 3744

但是,由于尺寸的原因,我目前必须使用丑陋的过滤器和连接方式。

那么问题来了,有没有更简单、更美观的方法呢?

更新 :

感谢 Arun 和 eddi 提供了解决问题的简洁代码。在我的 ~200M 行数据上,这个解决方案在大约 10 秒内对单词的简单组合起作用,这非常好!

然而,我确实有一个额外的问题,这使得矢量扫描方法不是最佳的。尽管在示例中我只查找一个单词组合,但实际上我可能在每个位置都有一个单词向量要查找。当我为此目的将“==”语句更改为“%in%”(100 个字或更多字的向量)时,查询需要更长的时间来运行。因此,如果存在二进制搜索解决方案,我仍然会对它感兴趣。但是,如果 Arun 不知道,也可能不知道,我很乐意接受他的回答。

最佳答案

这是我脑海中浮现的另一个想法。它只需要再创建一列并对子集使用二分搜索。

关于 DT您已根据数据生成,首先我们将添加额外的列:

# the extra column:
DT[, I := .I]

我们需要这个,因为我们会 setkeydocindex wordindex .这是我们可以在不创建额外列的情况下进行子集化的唯一方法(至少我能想到的)。因此,我们稍后需要一种方法来提取“原始”位置以检查您的情况(因此是 I )。

添加额外的列后,让我们在上面提到的两列上设置键:
setkey(DT, docindex, wordindex)

伟大的!这里的想法是提取您想要的单词匹配的位置 - 这里的值是 1L .然后,在正确的位置提取您可能(或可能不)希望出现在该词之后的所有其他词。然后,我们简单地保留(或删除)那些满足条件的索引。

这是一个可以解决这个问题的函数。它绝不是完整的,但应该给你一个想法。
foo <- function(DT, doc_key, word_key, rest_key=NULL, match=FALSE) {
## note that I'm using 1.9.3, where this results in a vector
## if you're using 1.9.2, you'll have to change the joins accordingly
idx1 = DT[J(doc_key, word_key), I]
for (i in seq_along(rest_key)) {
this_key = rest_key[i]
idx2 = DT[J(doc_key, this_key), I]
if (match) idx1 = idx1[which((idx1+i) %in% idx2)]
else idx1 = idx1[which(!(idx1+i) %in% idx2)]
}
DT[idx1, .N, by=c(key(DT)[1L])]
}

在这里, DTdata.table到哪个 I已添加列, 然后 setkey已经在前面提到的两列上调用了。
doc_key基本上包含 docindex 中的所有唯一值- 这里 1:10。 word_key这里基本上是1L。 rest_key您要检查的值是否出现在 i word_key 位置之后的第 th 个位置.

首先我们提取 I对于 1L 的所有匹配项在 idx1 (直截了当)。接下来,我们循环遍历 rest_key 的每个值并将该位置添加到 idx1 = idx1+i并检查该值是否出现在 idx2 中.如果是这样,根据您是想提取匹配条目还是不匹配条目,我们将保留(或删除它们)。

在这个循环结束时, idx1应该只有所需的条目。希望这可以帮助。下面显示的是其他答案中已经讨论过的案例的演示。

让我们考虑您的第一个场景。所有条目的计数,对于 docindex 中的每个组第 i 个位置是 1Li+1这不是2L。这基本上是:
system.time(ans1 <- foo(DT, 1:10, 1L, 2L, FALSE))

# user system elapsed
# 0.066 0.019 0.085

# old method took 0.12 seconds

# docindex N
# 1: 1 22301
# 2: 2 21836
# 3: 3 22491
# 4: 4 21831
# 5: 5 22218
# 6: 6 21914
# 7: 7 22370
# 8: 8 22265
# 9: 9 22211
# 10: 10 22190

第二种情况呢?在这里,我们想要 i+1 th 和 i+2 th 位置是 2L 和 3L,这与前面案例中的不相等场景相反。所以,我们设置 match=TRUE这里。
system.time(ans2 <- foo(DT, 1:10, 1L, 2:3,TRUE))
# user system elapsed
# 0.080 0.011 0.090

# old method took 0.22 seconds

# docindex N
# 1: 1 3684
# 2: 2 3746
# 3: 3 3717
# 4: 4 3727
# 5: 5 3700
# 6: 6 3779
# 7: 7 3702
# 8: 8 3756
# 9: 9 3702
# 10: 10 3744

扩展这个功能很容易。例如:如果您想拥有 i+1 th 等于 2L但是 i+2 th 不等于 3L然后,您可以更改 match成为向量 = length(rest_key)指定相应的逻辑值。

我希望这对于您的实际情况来说很快 - 至少比其他版本快。

HTH

关于r - 有效检查data.table中其他行的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24556928/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com