组填充最大值很慢,缺少值
Group-filling maximum is slow with missing values
我正在尝试在 R 中对 ~50k 行进行 groupby 最大操作。我的数据如下所示:
> head(df, 10)
group val
1 2 0.9891907
2 2 0.8965835
3 2 NA
4 2 NA
5 3 NA
6 4 0.8681051
7 4 0.7861292
8 5 0.9110303
9 7 NA
10 7 NA
我想根据 group
中的组创建一个新列 maxval
,它的组最大值为 val
。当一个组有任何非缺失值时,我想忽略缺失值,当该组有所有缺失值时,我想 return NA
。因此,前几行的预期结果为:
group val maxval
1 2 0.989 0.989 # 0.989 is the max value for all of group == 2
2 2 0.897 0.989
3 2 NA 0.989
4 2 NA 0.989
5 3 NA NA # for group == 3, val is always missing, so return NA
6 4 0.868 0.868
7 4 0.786 0.868
8 5 0.911 0.911
9 7 NA NA # for group == 7, val is always missing, so return NA
10 7 NA NA
我尝试使用 dplyr
工具来做到这一点:
df %>% group_by(group) %>% mutate(maxval=max(val, na.rm=T)) %>% ungroup()
这有效*,但速度非常慢(将近 30 秒):
> system.time(df %>% group_by(group) %>% mutate(maxval=max(val, na.rm=T)) %>% ungroup())
user system elapsed
27.021 0.093 27.171
* 请注意,因为它 return 是 -Inf
而不是 NA
,但这可以很快解决。
如果我在对 max
的调用中省略 na.rm = T
,则操作是即时的(0.06 秒)。但是输出不正确,因为 maxval
列中只有部分缺失值 return NA
的组。
我认为速度缓慢可能是由于在空序列上使用 max
产生的警告,但使用 suppressWarnings
并没有改善时间:
# following here:
suppressWarnings(df %>% group_by(group) %>% mutate(maxval=max(val, na.rm=T)) %>% ungroup())
我找到了一个解决方案,我会 post,但我不太明白它为什么有效,我也想知道是否有更好的解决方案。我对 R 不是很熟悉,所以让我知道你会怎么做(或者如果我遗漏了一些明显的东西)。我愿意使用其他非基础包。谢谢!
数据构造代码:
set.seed(13)
# create data
n <- 50000
df <- data.frame(group = sample(1:n, size=n, replace=T),
val = runif(n))
# sort
df <- df[order(df$group), ]
rownames(df) <- NULL
# sparsify
df$val <- ifelse(df$val < .75, NA, df$val)
我从 this post 中获取了这个自定义最大值函数。根据需要,当组的所有值都是 NA
:
时,它将 return NA
> my.max <- function(x) ifelse( !all(is.na(x)), max(x, na.rm=T), NA)
> df %>% group_by(group) %>% mutate(maxval=my.max(val)) %>% ungroup()
# A tibble: 50,000 x 3
group val maxval
<int> <dbl> <dbl>
1 2 0.989 0.989
2 2 0.897 0.989
3 2 NA 0.989
4 2 NA 0.989
5 3 NA NA
6 4 0.868 0.868
7 4 0.786 0.868
8 5 0.911 0.911
9 7 NA NA
10 7 NA NA
# ... with 49,990 more rows
> system.time(df %>% group_by(group) %>% mutate(maxval=my.max(val)) %>% ungroup())
user system elapsed
0.14 0.00 0.14
这比 na.rm = F
的常规 max
慢 2-3 倍,但仍然比 na.rm = T
快很多倍(并给出正确的输出)。
如果整个向量是NA
,我们可以使用if(){}
绕过max
计算。这是一个巨大的加速:
fmax = function(x, na.rm = TRUE) {
if(all(is.na(x))) return(x[1])
return(max(x, na.rm = na.rm))
}
system.time(df %>%
group_by(group) %>%
mutate(maxval = fmax(val)))
# user system elapsed
# 0.20 0.01 0.22
我正在尝试在 R 中对 ~50k 行进行 groupby 最大操作。我的数据如下所示:
> head(df, 10)
group val
1 2 0.9891907
2 2 0.8965835
3 2 NA
4 2 NA
5 3 NA
6 4 0.8681051
7 4 0.7861292
8 5 0.9110303
9 7 NA
10 7 NA
我想根据 group
中的组创建一个新列 maxval
,它的组最大值为 val
。当一个组有任何非缺失值时,我想忽略缺失值,当该组有所有缺失值时,我想 return NA
。因此,前几行的预期结果为:
group val maxval
1 2 0.989 0.989 # 0.989 is the max value for all of group == 2
2 2 0.897 0.989
3 2 NA 0.989
4 2 NA 0.989
5 3 NA NA # for group == 3, val is always missing, so return NA
6 4 0.868 0.868
7 4 0.786 0.868
8 5 0.911 0.911
9 7 NA NA # for group == 7, val is always missing, so return NA
10 7 NA NA
我尝试使用 dplyr
工具来做到这一点:
df %>% group_by(group) %>% mutate(maxval=max(val, na.rm=T)) %>% ungroup()
这有效*,但速度非常慢(将近 30 秒):
> system.time(df %>% group_by(group) %>% mutate(maxval=max(val, na.rm=T)) %>% ungroup())
user system elapsed
27.021 0.093 27.171
* 请注意,因为它 return 是 -Inf
而不是 NA
,但这可以很快解决。
如果我在对 max
的调用中省略 na.rm = T
,则操作是即时的(0.06 秒)。但是输出不正确,因为 maxval
列中只有部分缺失值 return NA
的组。
我认为速度缓慢可能是由于在空序列上使用 max
产生的警告,但使用 suppressWarnings
并没有改善时间:
# following here:
suppressWarnings(df %>% group_by(group) %>% mutate(maxval=max(val, na.rm=T)) %>% ungroup())
我找到了一个解决方案,我会 post,但我不太明白它为什么有效,我也想知道是否有更好的解决方案。我对 R 不是很熟悉,所以让我知道你会怎么做(或者如果我遗漏了一些明显的东西)。我愿意使用其他非基础包。谢谢!
数据构造代码:
set.seed(13)
# create data
n <- 50000
df <- data.frame(group = sample(1:n, size=n, replace=T),
val = runif(n))
# sort
df <- df[order(df$group), ]
rownames(df) <- NULL
# sparsify
df$val <- ifelse(df$val < .75, NA, df$val)
我从 this post 中获取了这个自定义最大值函数。根据需要,当组的所有值都是 NA
:
NA
> my.max <- function(x) ifelse( !all(is.na(x)), max(x, na.rm=T), NA)
> df %>% group_by(group) %>% mutate(maxval=my.max(val)) %>% ungroup()
# A tibble: 50,000 x 3
group val maxval
<int> <dbl> <dbl>
1 2 0.989 0.989
2 2 0.897 0.989
3 2 NA 0.989
4 2 NA 0.989
5 3 NA NA
6 4 0.868 0.868
7 4 0.786 0.868
8 5 0.911 0.911
9 7 NA NA
10 7 NA NA
# ... with 49,990 more rows
> system.time(df %>% group_by(group) %>% mutate(maxval=my.max(val)) %>% ungroup())
user system elapsed
0.14 0.00 0.14
这比 na.rm = F
的常规 max
慢 2-3 倍,但仍然比 na.rm = T
快很多倍(并给出正确的输出)。
如果整个向量是NA
,我们可以使用if(){}
绕过max
计算。这是一个巨大的加速:
fmax = function(x, na.rm = TRUE) {
if(all(is.na(x))) return(x[1])
return(max(x, na.rm = na.rm))
}
system.time(df %>%
group_by(group) %>%
mutate(maxval = fmax(val)))
# user system elapsed
# 0.20 0.01 0.22