【问题标题】:Can I use the R data.table join capability to select rows and perform some operation?我可以使用 R data.table 连接功能来选择行并执行一些操作吗?
【发布时间】:2016-03-11 13:05:41
【问题描述】:

我不确定如何获取由两个 data.tables 连接产生的行索引。

为了设置一个简化的例子,假设 dt 是一个 data.table,它的列 'a' 是字母表中的一个字母,'b' 是其他一些信息。

我想添加一列“c”并将其设置为“元音”或“辅音”,具体取决于“a”列。我有另一个数据表 dtv,它用作元音表。我可以使用 data.table 的连接功能来有效地执行此操作吗?

require(data.table)
dt <- data.table ( a = sample(letters, 25, replace = T), 
                   b = sample(50:100,   25, replace = F))
dtv <- data.table( vowel  = c( 'a','e','i','o','u') )
setkey(dt,a)

下一行代码给了我一个带有元音的行的 data.table

dt[dtv, nomatch=0]  

但是如何获取行索引,以便将行标记为元音或辅音?

dt[, c := 'consonant']
dt[{ `a` found in vowel list }, c := 'vowel']  
# I want to do this where column 'a' is a vowel

【问题讨论】:

    标签: r join data.table


    【解决方案1】:

    从 V 1.9.4 开始,data.table 已优化为在 %in% 上使用二元连接,以防数据集已被键入。所以@Richards 的答案应该与最新的data.table 版本具有相同的性能(顺便说一句,%in% 在使用datatable.auto.index = TRUE 时有一个错误,所以请确保你安装了data.table v 1.9.6+会用)

    下面是data.table在使用%in%函数时使用二元连接的示意图

    require(data.table)
    set.seed(123)
    dt <- data.table ( a = sample(letters, 25, replace = T), 
                       b = sample(50:100,   25, replace = F))
    dtv <- data.table( vowel  = c( 'a','e','i','o','u') )
    setkey(dt, a)
    
    options(datatable.verbose = TRUE)
    
    dt[a %in% dtv$vowel]
    # Starting bmerge ...done in 0 secs <~~~ binary join was triggered
    #    a  b
    # 1: i 87
    # 2: o 84
    # 3: o 62
    # 4: u 77
    

    无论哪种方式,您都快到了,您可以在加入时轻松修改c

    dt[, c := 'consonant']
    dt[dtv, c := 'vowel']  
    

    或者,如果您想避免从 dtv 加入不必要的列(如果它们存在),您可以只加入 dtv 中的第一列

    dt[dtv$vowel, c := 'consonant']
    

    请注意,我没有使用 .() 或 J()。如果ith 元素不是integer 或numeric 类型,data.table 将默认执行二进制连接而不是行索引。例如,如果您想对列b(类型为integer)执行二元连接,这很重要。比较

    setkey(dt, b)
    dt[80:85]
    #     a  b <~~~ binary join wan't triggered, instead an attempt to subset by rows 80:85 was made
    # 1: NA NA
    # 2: NA NA
    # 3: NA NA
    # 4: NA NA
    # 5: NA NA
    # 6: NA NA
    

    和

    dt[.(80:85)] # or dt[J(80:85)]
    # Starting bmerge ...done in 0 secs <~~~ binary join was triggered
    #     a  b
    # 1:  x 80
    # 2:  x 81
    # 3: NA 82
    # 4: NA 83
    # 5:  o 84
    # 6: NA 85
    

    这两种方法的另一个区别是%in%不会返回不匹配的实例,比较一下

    setkey(dt, a)
    dt[a %in% dtv$vowel]
    # Starting bmerge ...done in 0 secs 
    #    a  b
    # 1: i 87
    # 2: o 84
    # 3: o 62
    # 4: u 77
    

    和

    dt[dtv$vowel]
    # Starting bmerge ...done in 0 secs
    #    a  b
    # 1: a NA <~~~ unmatched values returned
    # 2: e NA <~~~ unmatched values returned
    # 3: i 87
    # 4: o 84
    # 5: o 62
    # 6: u 77
    

    对于这种特定情况,这无关紧要,因为:= 不会修改不匹配的值,但您可以在其他情况下使用nomatch = 0L

    dt[dtv$vowel, nomatch = 0L]
    # Starting bmerge ...done in 0 secs
    #    a  b
    # 1: i 87
    # 2: o 84
    # 3: o 62
    # 4: u 77
    

    如果您不希望 data.table 如此冗长,请不要忘记设置 options(datatable.verbose = FALSE)。

    【讨论】:

      【解决方案2】:

      确实没有必要使用合并/连接。我们可以使用%in%。

      dt[, c := "consonant"]
      dt[a %in% dtv$vowel, c := "vowel"]
      

      或一行中的相同内容-

      dt[, c := "consonant"][a %in% dtv$vowel, c := "vowel"]
      

      或者(并且更好),我们可以通过以下方式在一次调用中完成这两个步骤。

      dt[, c := c("consonant", "vowel")[a %in% dtv$vowel + 1L]]
      

      【讨论】:

        猜你喜欢
        • 2013-05-18
        • 2011-09-27
        • 1970-01-01
        • 2016-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多