r - 在data.table中设置键的目的是什么?

标签 r data.table

我正在使用 data.table 并且有很多功能需要我设置一个键(例如 X[Y] )。因此,我希望了解一个键的作用,以便在我的数据表中正确设置键。

我读到的一个来源是 ?setkey .

setkey() sorts a data.table and marks it as sorted. The sorted columns are the key. The key can be any columns in any order. The columns are sorted in ascending order always. The table is changed by reference. No copy is made at all, other than temporary working memory as large as one column.



我的结论是,一个键会对 data.table 进行“排序”,从而产生与 order() 非常相似的效果。 .但是,它并没有解释拥有 key 的目的。

data.table FAQ 3.2 和 3.3 解释了:

3.2 I don't have a key on a large table, but grouping is still really quick. Why is that?

data.table uses radix sorting. This is signicantly faster than other sort algorithms. Radix is specically for integers only, see ?base::sort.list(x,method="radix"). This is also one reason why setkey() is quick. When no key is set, or we group in a different order from that of the key, we call it an ad hoc by.

3.3 Why is grouping by columns in the key faster than an ad hoc by?

Because each group is contiguous in RAM, thereby minimising page fetches, and memory can be copied in bulk (memcpy in C) rather than looping in C.



从这里开始,我猜想以某种方式设置一个键允许 R 使用“基数排序”而不是其他算法,这就是它更快的原因。

10 分钟快速入门指南也有按键指南。

  1. Keys

Let's start by considering data.frame, specically rownames (or in English, row names). That is, the multiple names belonging to a single row. The multiple names belonging to the single row? That is not what we are used to in a data.frame. We know that each row has at most one name. A person has at least two names, a rst name and a second name. That is useful to organise a telephone directory, for example, which is sorted by surname, then rst name. However, each row in a data.frame can only have one name.

A key consists of one or more columns of rownames, which may be integer, factor, character or some other class, not simply character. Furthermore, the rows are sorted by the key. Therefore, a data.table can have at most one key, because it cannot be sorted in more than one way.

Uniqueness is not enforced, i.e., duplicate key values are allowed. Since the rows are sorted by the key, any duplicates in the key will appear consecutively



电话簿有助于理解什么是键,但与具有因子列相比,键似乎没有什么不同。此外,它没有解释为什么需要一个键(尤其是使用某些功能)以及如何选择要设置为键的列。此外,似乎在以时间为列的 data.table 中,将任何其他列设置为键也可能会弄乱时间列,这使它更加困惑,因为我不知道是否允许将任何其他列设置为键。有人可以启发我吗?

最佳答案

小更新:请引用new HTML vignettes以及。 This issue突出显示我们计划的其他小插曲。

鉴于新的 on=,我再次更新了此答案(2016 年 2 月)也允许临时连接的功能。有关较早(过时)的答案,请参阅历史记录。

究竟是做什么的setkey(DT, a, b)做什么?

它做两件事:

  • 重新排列数据的行。表DT通过引用提供的列(a,b),始终按升序排列。
  • 通过设置名为 sorted 的属性将这些列标记为键列至 DT .

  • 重新排序既快速(由于 data.table 的内部基数排序)和内存效率(只分配了一个额外的 double 类型的列)。

    什么时候setkey()需要吗?

    对于分组操作,setkey()从来都不是绝对的要求。也就是说,我们可以执行cold-by 或adhoc-by。
    ## "cold" by
    require(data.table)
    DT <- data.table(x=rep(1:5, each=2), y=1:10)
    DT[, mean(y), by=x] # no key is set, order of groups preserved in result
    

    然而,在v1.9.6之前, 形式的联接 x[i]需要 key设置在 x . 与新on=来自 v1.9.6+ 的参数 ,这不再是真的,因此设置键在这里也不是绝对的要求。
    ## joins using < v1.9.6 
    setkey(X, a) # absolutely required
    setkey(Y, a) # not absolutely required as long as 'a' is the first column
    X[Y]
    
    ## joins using v1.9.6+
    X[Y, on="a"]
    # or if the column names are x_a and y_a respectively
    X[Y, on=c("x_a" = "y_a")]
    

    请注意 on=即使对于 keyed 也可以明确指定参数也加入。

    The only operation that requires key to be absolutely set is the foverlaps() function. But we are working on some more features which when done would remove this requirement.


  • 那么实现on=的原因是什么?争论?

    原因有很多。
  • 它允许清楚地将操作区分为涉及两个 data.tables 的操作。只是做X[Y]也没有区分这一点,尽管通过适本地命名变量可以清楚地表明这一点。
  • 它还允许通过查看该代码行(而不必回溯到相应的 setkey() 行)来立即了解正在执行连接/子集的列。
  • 在通过引用添加或更新列的操作中,on=操作的性能要高得多,因为它不需要重新排序整个 data.table 只是为了添加/更新列。例如,
    ## compare 
    setkey(X, a, b) # why physically reorder X to just add/update a column?
    X[Y, col := i.val]
    
    ## to
    X[Y, col := i.val, on=c("a", "b")]
    

    在第二种情况下,我们不必重新排序。耗时的不是计算顺序,而是物理重新排序RAM中的data.table,通过避免它,我们保留了原始顺序,并且它也是高性能的。
  • 即便如此,除非您重复执行连接,否则键控连接和临时连接之间应该没有明显的性能差异。

  • 这就引出了一个问题,键控 data.table 有什么优势?
  • 键入 data.table 有优势吗?

    键入 data.table 会根据 RAM 中的那些列对其进行物理重新排序。计算顺序通常不是耗时的部分,而是重新排序本身。然而,一旦我们在 RAM 中对数据进行排序,属于同一组的行在 RAM 中都是连续的,因此缓存效率非常高。排序可以加快对键控 data.tables 的操作。

    因此,必须弄清楚重新排序整个 data.table 所花费的时间是否值得花时间进行缓存高效的连接/聚合。通常,除非在同一个键控 data.table 上执行重复的分组/连接操作,否则应该不会有明显的差异。

  • In most cases therefore, there shouldn't be a need to set keys anymore. We recommend using on= wherever possible, unless setting key has a dramatic improvement in performance that you'd like to exploit.



    问题:如果您使用 setorder(),与键控连接相比,您认为性能如何?重新排序 data.table 并使用 on= ?如果您到目前为止一直关注,您应该能够弄清楚:-)。

    关于r - 在data.table中设置键的目的是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20039335/

    相关文章:

    r - 合并具有不同列名的表

    r - 使用 `data.table` 的 DT[ i , j, by] 时,是否可以事先设置列类型?

    r - 将Dygraph中的y轴更改为不是科学计数法

    r - apply() 没有按预期工作

    r - dplyr::select - 多次使用列?

    r - 按日期加入两个数据表,表 1 中最接近的日期严格小于第二个表中的日期

    r - 使用 purrr 映射按列对迭代汇总

    删除满足条件的每个 ID 的最后一个条目

    r - data.table 中闭包的处理

    r - `spread= a - b` 用 `dplyr` 和 `data.table` 计算 tall 数据