【问题标题】:apply custom function to a particular column rowise by group in data.table按 data.table 中的组将自定义函数应用于特定的列
【发布时间】:2016-11-01 14:50:35
【问题描述】:

我有一个函数可以找到当前行号之前的最大值。

dt<- setDT(copy(mtcars),keep.rownames = TRUE)

apply(as.matrix(dt$rn), 1, function(x) {
 index = as.numeric(ifelse(match(x, dt$rn) == 1, 2, match(x, dt$rn)))
 max(dt[1:index-1,"mpg",with = FALSE])
 })
   # [1] 21.0 21.0 21.0 22.8 22.8 22.8 22.8 22.8 24.4 24.4 24.4 24.4 24.4 24.4 24.4 24.4 24.4 24.4 32.4 32.4 33.9 33.9 33.9 33.9 33.9 33.9 33.9 33.9 33.9 33.9 33.9
   # [32] 33.9

但是,我想根据特定组重复相同的操作,例如“齿轮”。我将如何修改代码。我觉得它与这样的事情有关。

dt[,max:=lapply(.SD,function(x){
         index = as.numeric(ifelse(match(x,dt$rn) == 1, 2, match(x, dt$rn)))
      return(max(dt[1:index-1,"mpg",with = FALSE]))
      }),by = gear,.SDcols = "rn"]

我觉得我可能错过了什么..

【问题讨论】:

  • 您的函数可以只替换为cummax(dt$mpg)
  • @DavidArenburg op 缺少1:index-1 中的括号,对吧?所以修复这让我在一个值上有所不同
  • @rawr 是的,我认为你是对的
  • dt$mpg 是否有组内的值?
  • @DavidArenburg 此外,这不仅仅是组内的最大值。但直到该组中的当前行号,因此 1:index-1

标签: r data.table apply


【解决方案1】:

在 data.table 中不确定,但在 dplyr 中相对简单。设置group_by 然后mutate 在组内运行。

res <-
  mtcars %>%
  group_by(gear) %>%
  mutate(currMax = cummax(mpg))

这是结果的一个子集,通过以下方式实现:

res %>%
  select(gear, mpg, currMax) %>%
  slice(1:3)

将结果限制为相关列和每组的前三行。

   gear   mpg currMax
  <dbl> <dbl>   <dbl>
1     3  21.4    21.4
2     3  18.7    21.4
3     3  18.1    21.4
4     4  21.0    21.0
5     4  21.0    21.0
6     4  22.8    22.8
7     5  26.0    26.0
8     5  30.4    30.4
9     5  15.8    30.4

如果您希望每一行的最大值直到当前行,但不包括当前行,则需要进行更多操作。具体来说,cummax 没有内置对NA 的处理,根据定义,您的第一个值必须是NA。所以,我写了一个小函数,临时将NA 更改为负无穷大,然后在返回之前将这些条目设置为NA(当且仅当您的数据实际上 @987654332 这将是一个问题@ 值,即使它们是数据中的第一个)。然后,我将该函数用作尾随最大值:

my_cummax <- function(x){
  x <- ifelse(is.na(x), -Inf, x)
  out <- cummax(x)
  out[out == -Inf] <- NA
  return(out)
}

mtcars %>%
  group_by(gear) %>%
  mutate(currMax = cummax(mpg)
         , trailMax = my_cummax(lag(mpg)))

返回的有限部分,与上面类似,显示:

   gear   mpg currMax trailMax
  <dbl> <dbl>   <dbl>    <dbl>
1     3  21.4    21.4       NA
2     3  18.7    21.4     21.4
3     3  18.1    21.4     21.4
4     4  21.0    21.0       NA
5     4  21.0    21.0     21.0
6     4  22.8    22.8     21.0
7     5  26.0    26.0       NA
8     5  30.4    30.4     26.0
9     5  15.8    30.4     30.4

【讨论】:

  • dt[, .(mpg, currMax = cummax(mpg)), by = gear]?这只是通常的分组操作
  • @MarkPeterson 在进行编辑之前我没有检查答案。此外,这不仅仅是组内的最大值。但直到该组中的当前行号矿石索引,因此 1:index-1
  • @DavidArenburg 当然可以——我没有提供 data.table 解决方案,因为它不是我使用的东西。如果这可行,请随时发布作为替代答案。
  • 是的,我明白了。你认为还有一个 dplyr 修改来解释行号。
  • 实心@Frank,谢谢。我相应地更新了。我想确保我可以从每个组中展示一组合理的条目,但你说得对,我以前的方法很容易导致混淆。
【解决方案2】:

data.table 解决方案

dt[, currMax := cummax(shift(mpg, fill = -Inf)), by = gear], 
head(dt)
#                      rn  mpg cyl disp  hp drat    wt  qsec vs am gear carb currMax
# 1:         Mazda RX4 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4    -Inf
# 2:     Mazda RX4 Wag 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4    21.0
# 3:        Datsun 710 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1    21.0
# 4:    Hornet 4 Drive 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1    -Inf
# 5: Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2    21.4
# 6:           Valiant 18.1   6  225 105 2.76 3.460 20.22  1  0    3    1    21.4

感谢@DavidArenburg 的编辑。

【讨论】:

  • 不,这看起来不像 data.table 解决方案,而是来自 cmets/其他答案的复制/粘贴。 data.table 没有 lag 功能。例如,一种可能的解决方案是dt[, currMax := cummax(shift(mpg, fill = -Inf)), by = gear]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-08
  • 2018-10-09
  • 2014-02-12
  • 1970-01-01
  • 1970-01-01
  • 2023-03-02
  • 2020-10-28
相关资源
最近更新 更多