【问题标题】:Aggregate data.table by one column and keep another id column in the result按一列聚合 data.table 并在结果中保留另一列 id
【发布时间】:2018-01-29 20:23:33
【问题描述】:

我在 R 中有一个 data.table,要按一列的值进行分组,并找到每组中的异常值。但我需要保留 id 列(不包含在聚合中)。比如下面的数据表a,我想按类找出Hours的异常值,并输出对应的id。

      Hours       id class
 1: 100.000 30298340     M
 2:   4.776 30310183     M
 3:   1.560 30312576     M
 4:  11.520 30336159     M
 5:   3.288 30331383     M
 6:   6.552 30364533     M
 7:   5.064 30365224     M
 8:  27.768 30365394     C
 9:   4.992 30365211     M
 10:  25.536 30365603     M
 11:   8.568 30337051     M
 12:   5.112 30337052     C
 13:   2.352 30284703     M
 14:  23.784 30325405     M
 15:  16.464 30327152     M
 16:  24.336 30351237     M
 17:   3.192 30352117     M
 18:  24.312 30324926     M
 19:  23.160 30325670     M
 20:   4.176 30324906     M

然后我使用以下代码查找异常值。

 temp<-a[,.(Hours=boxplot.stats(Hours,coef=3,do.conf=F)$out,M=boxplot.stats(Hours,do.conf=F
  )$stats[3]),by=class]

temp[Hours>M] 会给我高于中位数和中位数的异常值作为参考。

     class Hours    M
  1:     M   100 7.56

但是如何更改聚合行以包含异常行的 id?

由于我的原始表非常大,我不想将临时表与原始数据合并。另外,因为这只是现有大型程序的一小部分,所以我试图保留 temp 结果的主要结构,并添加了 id 列,以便将 temp 传递到下一个计算块中。理想情况下,是否有一种简单的方法来调整 data.table 聚合线以满足我的要求?谢谢!!!


这是相同场景中的一个附加问题。现在,如果我在原始数据中还有 3 列,即年龄、性别等。我怎样才能将它们全部保留在异常值输出中?我可以简单地重复 Eric 的代码,将 id 替换为其他变量并添加到 data.table 步骤中:

age=age[which(Hours %in% boxplot.stats(Hours, coef = 3, do.conf = FALSE)$out)],
gender=gender[which(Hours %in% boxplot.stats(Hours, coef = 3, do.conf = FALSE)$out)],

但是如果要添加更多的列,这将是一项乏味的工作。我正在考虑执行以下操作:

  keyname<-c("age", "gender","id")
  temp <- a[, .(Hours = boxplot.stats(Hours, coef = 3, do.conf = FALSE)$out,
          M = boxplot.stats(Hours, do.conf = FALSE)$stats[3],
          lapply(c(1:length(keyname)),function(x) keyname[x]=get(keyname[x])[which(Hours) %in% boxplot.stats(Hours, coef = 3, do.conf = FALSE)$out)]),
      by = class]

但是,它不起作用。有什么进一步的建议吗?谢谢!

【问题讨论】:

  • 由于 'id' 是唯一的,使用 := 创建 'Hours' 列
  • 如果你只想通过保持 Hours > median(Hours) 来对数据进行子集化,那么你可以使用这个:subset(df, df$Hours>median(df$Hours))。
  • @user108363 我猜他们想要根据class 计算的中位数(或其他任何东西),因为他们写了by=class
  • @Frank 谢谢,我错过了。然后,您可以尝试类似: library(dplyr) new_df %group_by(class) %>% summarise(median_hours_by_class= median(Hours), Hours=Hours, class=class, id=id) subset(new_df , new_df$Hours>new_df$median_hours_by_class)
  • 您好 user1083637,我需要按类别划分中位数以上的异常值,而不仅仅是中位数以上的数据点。但是您通过使用 dplyr 为我提供了一个很好的示例/可能的方式。谢谢。

标签: r data.table


【解决方案1】:

使用which 和子集来创建列。

temp <- a[, .(Hours = boxplot.stats(Hours, coef = 3, do.conf = FALSE)$out,
              M = boxplot.stats(Hours, do.conf = FALSE)$stats[3],
              id = id[which(Hours %in% boxplot.stats(Hours, coef = 3, do.conf = FALSE)$out)]),
          by = class]

> temp
   class Hours     M       id
1:     M   100  7.56 30298340
2:     C    NA 16.44       NA

> temp[Hours > M]
   class Hours    M       id
1:     M   100 7.56 30298340

【讨论】:

  • 谢谢埃里克瓦特。这正是我想要的,简单而高效。它确实在 data.table 聚合步骤中添加了想要的 id 列。欣赏!
  • 你能帮我多一点吗? @EricWatt 我在原始帖子中添加了一个附加问题。我还有 7 列要保留。我认为您的解决方案应该仍然有效,但它需要在 data.table 步骤中使用超长的重复代码。有没有一种更简单的方法(至少一种使代码看起来更干净的方法)?谢谢!
  • 如果每个 id 的列都是唯一的,像 agegender 这样的列看起来应该是,你可以使用 merge。制作完上面的temp表格后,试试merge(temp, a[, .(id, age, gender)], by = "id", all.x=TRUE)
  • 感谢您的快速回复@EricWatt。原始数据非常大,所以我犹豫合并。当其中一张表非常大时,合并是否需要更长的时间?如果是,我想我会在聚合中使用不同的变量重复代码。
  • 取决于“非常大”是什么,但我最初的回答是否定的,应该不会花很长时间。直到你尝试才知道。合并data.tables 可以非常快速且内存高效。我刚刚尝试了一百万行随机数据,不到 100 毫秒。
猜你喜欢
  • 2017-04-06
  • 2019-05-06
  • 2017-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-01
  • 2020-12-18
  • 1970-01-01
相关资源
最近更新 更多