【问题标题】:data.table aggregations that return vectors, such as scale()返回向量的 data.table 聚合,例如 scale()
【发布时间】:2013-03-28 00:25:13
【问题描述】:

我最近一直在处理更大的数据集,并开始学习并迁移到 data.table 以提高聚合/分组的性能​​。我无法按预期对某些表达式或函数进行分组。这是我遇到问题的基本分组操作示例。

library(data.table)
category <- rep(1:10, 10)
value <- rnorm(100)
df <- data.frame(category, value)
dt <- data.table(df)

如果我想简单地按类别计算每个组的平均值。这很容易工作。

dt[,mean(value),by="category"]

    category          V1
 1:        1 -0.67555478
 2:        2 -0.50438413
 3:        3  0.29093723
 4:        4 -0.41684790
 5:        5  0.33921764
 6:        6  0.01970997
 7:        7 -0.23684245
 8:        8 -0.04280998
 9:        9  0.01838804
10:       10  0.44295978

如果我尝试使用 scale 函数,甚至是从自身减去值的简单表达式,我会遇到问题。分组被忽略,我将函数/表达式应用于每一行。以下按类别返回所有 100 行而不是 10 行。

dt[,scale(value),by="category"]


dt[,value-mean(value),by="category"]

我认为将比例重新创建为返回数值向量而不是矩阵的函数可能会有所帮助。

zScore <- function(x) {
  z=(x-mean(x,na.rm=TRUE))/sd(x,na.rm = TRUE)
  return(z) 
}

dt[,zScore(value),by="category"]

  category          V1
  1:        1 -1.45114132
  2:        1 -0.35304528
  3:        1 -0.94075418
  4:        1  1.44454416
  5:        1  1.39448268
  6:        1  0.55366652
  ....
 97:       10 -0.43190602
 98:       10 -0.25409244
 99:       10  0.35496694
100:       10  0.57323480
     category          V1

这还会返回应用于所有行 (N=100) 并忽略分组的 zScore 函数。为了让 scale() 或自定义函数像上面使用 mean() 时那样使用分组,我缺少什么?

【问题讨论】:

  • mean 返回 1 个值。 scale 函数为每个输入返回一个缩放值。也就是说,scale(1:5) 给出了 5 个值。 mean(1:5) 给出 1 个值。这有助于理解您的问题吗?
  • 你在grouped变量上应用的函数应该返回1个值而不是向量。
  • 这正是问题所在。我试图以使用 ddply 的方式使用 data.table。我将如何使用 data.table 等效地实现以下目标。在ddply? ddply(df,"category",transform, zscorebycategory=zScore(value))
  • @Aaron dt[,zscorebycategory:=zScore(value),by=category]我不明白你在哪里看到问题?
  • @Roland 你是对的。我没有完全意识到 := 的行为有点不同并直接更新表。当我在期望手动将其分配给 dt 之前运行它时。它现在正在工作。非常感谢您帮我解决这个问题。

标签: r data.table


【解决方案1】:

您已在 cmets 中阐明您希望与以下相同的行为:

ddply(df,"category",transform, zscorebycategory=zScore(value))

给出:

    category       value zscorebycategory
1          1  0.28860691       0.31565682
2          1  1.17473759       1.33282374
3          1  0.06395503       0.05778463
4          1  1.37825487       1.56643607
etc

您给出的数据表选项:

     category          V1
  1:        1  0.31565682
  2:        1  1.33282374
  3:        1  0.05778463
  4:        1  1.56643607
  etc

这是完全相同的数据。但是,您还想在结果中重复 value 列,并使用更具描述性的名称重命名 V1 变量。 data.table 为您提供结果中的分组变量,以及您提供的表达式的结果。因此,让我们修改它以提供您想要的行:

你的

dt[,zScore(value),by="category"]

变成:

dt[,list(value=value, zscorebycategory=zScore(value)),by="category"]

列表中的命名项成为结果中的列。

plyr = data.table(ddply(df,"category",transform, zscorebycategory=zScore(value)))
dt   = dt[,list(value=value, zscorebycategory=zScore(value)),by="category"]
identical(plyr, dt)
> TRUE

(请注意,我将您的 ddply data.frame 结果转换为 data.table,以允许 identical 命令工作)。

【讨论】:

  • 这很好用。谢谢彼得。我遇到了其他不相关的数据问题,这些问题缓和了我对 data.table 已经有限的理解。使用我生成的基本数据集配对每个人的帮助已经澄清了一些事情。
  • 干杯,@Aaron。虽然我认为@Roland 在问题 cmets:dt[,zscorebycategory:=zScore(value),by=category] 中的回答可能会更有效率,因为:= 会更新现有表,而我的回答会创建一个新表。
【解决方案2】:

您声称 data.table 没有分组是错误的:

library(data.table)
category <- rep(1:2, each=4)
value <- c(rep(c(1:2),each=2),rep(c(4,10),each=2))
dt <- data.table(category, value)

   category value
1:        1     1
2:        1     1
3:        1     2
4:        1     2
5:        2     4
6:        2     4
7:        2    10
8:        2    10

dt[,value-mean(value),by=category]
   category   V1
1:        1 -0.5
2:        1 -0.5
3:        1  0.5
4:        1  0.5
5:        2 -3.0
6:        2 -3.0
7:        2  3.0
8:        2  3.0

如果您想缩放/转换,这正是您想要的行为,因为这些操作根据定义返回与输入大小相同的对象。

【讨论】:

    猜你喜欢
    • 2013-06-15
    • 2018-07-23
    • 1970-01-01
    • 2019-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-15
    • 1970-01-01
    相关资源
    最近更新 更多