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

R 在data.table中设置键的目的是什么?,r,data.table,R,Data.table,我正在使用data.table,有许多函数需要我设置一个键(例如X[Y])。因此,我希望了解为了在数据表中正确设置键,键是做什么的 我读到的一个来源是?setkey setkey()对数据表进行排序,并将其标记为已排序。已排序的列是键。键可以是任意顺序的任意列。列始终按升序排序。该表通过引用进行了更改。除了一列大小的临时工作内存外,根本不复制 我在这里的收获是,一个键将对data.table进行“排序”,从而产生与order()非常相似的效果。然而,它并没有解释拥有钥匙的目的 data.ta

我正在使用data.table,有许多函数需要我设置一个键(例如
X[Y]
)。因此,我希望了解为了在数据表中正确设置键,键是做什么的


我读到的一个来源是
?setkey

setkey()
数据表进行排序,并将其标记为已排序。已排序的列是键。键可以是任意顺序的任意列。列始终按升序排序。该表通过引用进行了更改。除了一列大小的临时工作内存外,根本不复制

我在这里的收获是,一个键将对data.table进行“排序”,从而产生与
order()
非常相似的效果。然而,它并没有解释拥有钥匙的目的


data.table FAQ 3.2和3.3解释了:

3.2我没有一个大表上的键,但是分组仍然非常快。为什么呢

data.table使用基数排序。这比其他的要快得多 排序算法。基数仅适用于整数,请参见
?base::sort.list(x,method=“基数”)
。这也是原因之一
setkey()
很快。当没有设置关键点,或者我们以不同的顺序分组时 从密钥的角度来看,我们称之为“临时用户”

3.3为什么按键中的列进行分组比按特殊列进行分组快

因为每个组在RAM中是连续的,所以最小化了页面 获取,并且可以批量复制内存(
memcpy
在C中),而不是 在C中循环


从这里开始,我猜设置一个键可以让R在某种程度上使用“基数排序”而不是其他算法,这就是为什么它更快的原因


《10分钟快速入门指南》中还提供了有关关键点的指南

  • 钥匙
  • 让我们首先考虑data.frame,特别是行名(或 英文,行名称)。也就是说,多个名称属于一个 一行属于同一行的多个名称?那不是什么 我们习惯于在data.frame中使用。我们知道每行最多有一个 名称一个人至少有两个名字,第一个名字和第二个名字。 这对于组织电话簿很有用,例如 按姓氏排序,然后按rst名称排序。但是,一行中的每一行 data.frame只能有一个名称

    钥匙由一个或多个部件组成 行名称的列,可以是整数、因子、字符或某些 其他类,而不仅仅是字符。此外,行是按 钥匙。因此,data.table最多只能有一个键,因为它 不能以多种方式排序

    不强制执行唯一性, i、 例如,允许重复的键值。因为行是按 键,键中的任何重复项都将连续出现


    电话簿有助于理解键是什么,但似乎键与“因子”列没有区别。此外,它没有解释为什么需要键(特别是使用某些函数)以及如何选择要设置为键的列。此外,在以时间为列的data.table中,将任何其他列设置为键可能也会弄乱时间列,这使得它更加混乱,因为我不知道是否允许将任何其他列设置为键。有人能告诉我吗?

    键基本上是数据集的索引,它允许非常快速有效的排序、筛选和联接操作。这些可能是使用数据表而不是数据帧的最佳理由(使用数据表的语法也更加用户友好,但这与键无关)

    如果你不理解索引,考虑一下:电话簿是按名称“索引”的。所以,如果我想查找某人的电话号码,这很简单。但假设我想按电话号码搜索(例如,查找谁有特定的电话号码)?除非我能通过电话号码“重新索引”电话簿,否则这将需要很长时间

    考虑以下示例:假设我有一个表ZIP,其中包含美国所有邮政编码(>33000)以及相关信息(城市、州、人口、收入中值等)。如果我想查找特定邮政编码的信息,如果我先
    setkey(zip,zipcode)
    ,搜索(过滤器)的速度大约会快1000倍

    另一个好处与连接有关。假设a在数据表中有一个人员列表和他们的邮政编码(称之为“PPL”),我想从邮政编码表中附加信息(例如城市、州等)。以下代码将执行此操作:

    setkey(ZIP,zipcode)
    setkey(PPL,zipcode)
    full.info <- PPL[ZIP, nomatch=F]
    
    setkey(ZIP,zipcode)
    设置键(PPL,zipcode)
    full.info次要更新:请同时参阅。重点介绍我们计划讨论的其他小插曲


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

    setkey(DT,a,b)
    ? 它做两件事:

  • 按引用提供的列(a、b)对data.table
    DT
    的行重新排序,始终按递增顺序排列
  • 通过将名为
    sorted
    的属性设置为
    DT
    ,将这些列标记为键列
  • 重新排序既快(由于data.table的内部基数排序),又节省内存(只分配了一个double类型的额外列)

    何时需要
    setkey()
    ? 对于分组操作,
    setkey()
    从来不是绝对的要求。也就是说,我们可以通过或临时通过进行感冒治疗

    请注意,
    on=
    参数也可以显式指定,即使对于键控的
    联接也是如此

    唯一需要绝对设置
    的操作是功能。但我们正在开发更多的功能,这些功能完成后将删除此要求

    • 那么实现
      o的原因是什么
      
      ## "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
      
      ## 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")]
      
      ## 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")]