在 data.table 中按组对特定列应用自定义函数
apply custom function to a particular column rowise by group in data.table
我有一个函数可以找到当前行号之前的最大值。
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
但是,我想根据特定的群体重复相同的说法 'gear'。我将如何修改代码。感觉跟这个有关系
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"]
我觉得我可能遗漏了一些东西..
在 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
更改为负无穷大,然后在 returning 之前将这些条目设置为 NA
(当且仅当您的数据确实 有 -Inf
值,甚至只有当它们在数据中排在第一位时)。然后,我将该函数用作尾随最大值:
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)))
return 的有限切片,与上面类似,显示:
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
一个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 的编辑。
我有一个函数可以找到当前行号之前的最大值。
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
但是,我想根据特定的群体重复相同的说法 'gear'。我将如何修改代码。感觉跟这个有关系
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"]
我觉得我可能遗漏了一些东西..
在 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
更改为负无穷大,然后在 returning 之前将这些条目设置为 NA
(当且仅当您的数据确实 有 -Inf
值,甚至只有当它们在数据中排在第一位时)。然后,我将该函数用作尾随最大值:
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)))
return 的有限切片,与上面类似,显示:
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
一个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 的编辑。