Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/75.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 有效地检查data.table中其他行的值_R_Data.table - Fatal编程技术网

R 有效地检查data.table中其他行的值

R 有效地检查data.table中其他行的值,r,data.table,R,Data.table,注意:这是我最初发布到data.table帮助组的一个问题。马特·道尔(Matt Dowle)要求提供一个更详细的示例,我发布了这个示例,但我在电子邮件格式方面遇到了问题。我已经知道如何在SO上格式化,所以我想我会把它贴在这里 基本上,我要做的是根据data.table中的值以及前一行或后一行中的值对该行进行子集。现在,我正在为将来和过去的行创建新列,然后在这些列上键入data.table,但这是资源密集型的,而且非常繁重 下面的示例说明了我现在使用的方法。该示例使用文档中的单词(我使用数字索引

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

基本上,我要做的是根据data.table中的值以及前一行或后一行中的值对该行进行子集。现在,我正在为将来和过去的行创建新列,然后在这些列上键入data.table,但这是资源密集型的,而且非常繁重

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

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

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
库(data.table)
种子集(1000)

DT听起来你只是想:

DT[, sum(wordindex == 1 & c(tail(wordindex, -1), 2) != 2), by = docindex]
我看不出通过连接使它复杂化的意义

顺便说一句,在某些情况下,你会得到与你不同的答案,这要么是因为我不明白你想要什么,要么是因为你的方法在某些边缘情况下失败。例如,两种方法都可以尝试

DT = data.table(wordindex = c(1,1,2,1,1,2), docindex = c(1,1,2,2,3,3))

只需创建一个
lead
函数,并在
j表达式中使用它即可:

lead <- function(x, n)
    if (n == 0) x else c(tail(x, -n), rep.int(NA, n))
如果您想在
i
处获得
wordindex
为1L、
i+1
为2L、
i+2
为3L的计数,则:

DT[, sum(wordindex == 1L & lead(wordindex, 1L) == 2L & 
          lead(wordindex, 2L) == 3L, na.rm=TRUE), by=docindex]
#     docindex   V1
#  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
请注意,此处不需要设置键
adhoc by
应该很有效


针对该评论:

此解决方案在
j
中使用矢量扫描,而不是二进制搜索方法。但这里有不同的权衡。与二进制搜索版本相比,该代码相对优雅,易于阅读,可以扩展到多个滞后和条件,并且可以维护(因为我想不出一种不创建额外列的方法)。这需要更少的内存,这也是您的情况中的一个限制因素

你说的是“大数据”,但别再说了。是的,对整个数据(比如2000万行或2亿行)进行矢量扫描的成本很高。但是,对每个组进行操作,即使不能提供二进制搜索的性能,也不会慢很多。当然,这同样取决于你所观察到的群体数量和每个群体的观察数量。但最好对这些东西进行基准测试并找出答案


我让你去做吧。祝你好运:)。

我突然想到另一个主意。它只需要再创建一列,并对子集使用二进制搜索

在根据数据生成的
DT
上,首先我们将添加额外的列:

# the extra column:
DT[, I := .I]
我们需要这个,因为我们将在
docindex
wordindex
上设置
setkey
。这是我们在不创建额外列的情况下创建子集的唯一方法(至少是我能想到的)。因此,我们以后需要一种方法来提取“原始”位置,以检查您的状况(因此是
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])]
}

第二种情况如何?在这里,我们希望
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

system.time(ans2)这是一个既适用于你的答案又适用于eddi的问题。我曾想过类似的事情(虽然不是那么优雅),但我避免了它,因为(我想)这是一个向量扫描。这是正确的方法吗?重新更新:也许你可以尝试一种混合策略,将它过滤到你感兴趣的单词集(如果你已经有了一个键集,也许可以使用一个简单的连接),然后在上面运行向量扫描(你需要保存位置并区分它们)谢谢eddi,我也可以试一试。另外,对于字符向量,
%chin%
要比%
中的
%快得多。谢谢你,Arun,我今天和明天都会玩这个,看看我能想出什么。这真的很好,也很快。我仍然有一些游戏要做,以使它在我的设置中正常工作,但我非常肯定不会他解决了我的问题。非常感谢!
DT[, sum(wordindex == 1L & lead(wordindex, 1L) == 2L & 
          lead(wordindex, 2L) == 3L, na.rm=TRUE), by=docindex]
#     docindex   V1
#  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
# the extra column:
DT[, I := .I]
setkey(DT, docindex, wordindex)
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])]
}
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
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