按组和列查找最小值
Finding minimum by groups and among columns
我试图在不同的列和组中找到最小值。
我的一小部分数据样本如下所示:
group cut group_score_1 group_score_2
1 a 1 3 5.0
2 b 2 2 4.0
3 a 0 2 2.5
4 b 3 5 4.0
5 a 2 3 6.0
6 b 1 5 1.0
我想按组分组,对于每个组,在两个组分数中找到包含最小组分数的行,然后还得到包含最小值的列的名称(group_score_1 或group_score_2),
所以基本上我的结果应该是这样的:
group cut group_score_1 group_score_2
1 a 0 2 2.5
2 b 1 5 1.0
我尝试了一些想法,最终想出将其分成几个新的数据框,按组过滤并选择相关列,然后使用 which.min()
,但我确信还有更多有效的方法来做到这一点。不确定我错过了什么。
对于每个 group
,您可以计算 min
值和 select 列之一中存在该值的行。
library(dplyr)
df %>%
group_by(group) %>%
filter({tmp = min(group_score_1, group_score_2);
group_score_1 == tmp | group_score_2 == tmp})
# group cut group_score_1 group_score_2
# <chr> <int> <int> <dbl>
#1 a 0 2 2.5
#2 b 1 5 1
当您只有两个 group_score
列时,上面的方法很有效。如果您有很多这样的列,则不可能用 group_score_1 == tmp | group_score_2 == tmp
等列出每个列。在这种情况下,以长格式获取数据并获取对应的 cut
最小值的值和加入数据。假设 cut
在每个组中都是唯一的。
df %>%
tidyr::pivot_longer(cols = starts_with('group_score')) %>%
group_by(group) %>%
summarise(cut = cut[which.min(value)]) %>%
left_join(df, by = c("group", "cut"))
这是使用 pmin
+ ave
+ subset
的基础 R 选项
subset(
df,
as.logical(ave(
do.call(pmin, df[grep("group_score_\d+", names(df))]),
group,
FUN = function(x) x == min(x)
))
)
这给出了
group cut group_score_1 group_score_2
3 a 0 2 2.5
6 b 1 5 1.0
数据
> dput(df)
structure(list(group = c("a", "b", "a", "b", "a", "b"), cut = c(1L,
2L, 0L, 3L, 2L, 1L), group_score_1 = c(3L, 2L, 2L, 5L, 3L, 5L
), group_score_2 = c(5, 4, 2.5, 4, 6, 1)), class = "data.frame", row.names = c("1",
"2", "3", "4", "5", "6"))
我们可以使用data.table
方法
library(data.table)
setDT(df)[df[, .I[which.min(do.call(pmin, .SD))],
group, .SDcols = patterns('^group_score')]$V1]
# group cut group_score_1 group_score_2
#1: a 0 2 2.5
#2: b 1 5 1.0
我试图在不同的列和组中找到最小值。 我的一小部分数据样本如下所示:
group cut group_score_1 group_score_2
1 a 1 3 5.0
2 b 2 2 4.0
3 a 0 2 2.5
4 b 3 5 4.0
5 a 2 3 6.0
6 b 1 5 1.0
我想按组分组,对于每个组,在两个组分数中找到包含最小组分数的行,然后还得到包含最小值的列的名称(group_score_1 或group_score_2), 所以基本上我的结果应该是这样的:
group cut group_score_1 group_score_2
1 a 0 2 2.5
2 b 1 5 1.0
我尝试了一些想法,最终想出将其分成几个新的数据框,按组过滤并选择相关列,然后使用 which.min()
,但我确信还有更多有效的方法来做到这一点。不确定我错过了什么。
对于每个 group
,您可以计算 min
值和 select 列之一中存在该值的行。
library(dplyr)
df %>%
group_by(group) %>%
filter({tmp = min(group_score_1, group_score_2);
group_score_1 == tmp | group_score_2 == tmp})
# group cut group_score_1 group_score_2
# <chr> <int> <int> <dbl>
#1 a 0 2 2.5
#2 b 1 5 1
当您只有两个 group_score
列时,上面的方法很有效。如果您有很多这样的列,则不可能用 group_score_1 == tmp | group_score_2 == tmp
等列出每个列。在这种情况下,以长格式获取数据并获取对应的 cut
最小值的值和加入数据。假设 cut
在每个组中都是唯一的。
df %>%
tidyr::pivot_longer(cols = starts_with('group_score')) %>%
group_by(group) %>%
summarise(cut = cut[which.min(value)]) %>%
left_join(df, by = c("group", "cut"))
这是使用 pmin
+ ave
+ subset
subset(
df,
as.logical(ave(
do.call(pmin, df[grep("group_score_\d+", names(df))]),
group,
FUN = function(x) x == min(x)
))
)
这给出了
group cut group_score_1 group_score_2
3 a 0 2 2.5
6 b 1 5 1.0
数据
> dput(df)
structure(list(group = c("a", "b", "a", "b", "a", "b"), cut = c(1L,
2L, 0L, 3L, 2L, 1L), group_score_1 = c(3L, 2L, 2L, 5L, 3L, 5L
), group_score_2 = c(5, 4, 2.5, 4, 6, 1)), class = "data.frame", row.names = c("1",
"2", "3", "4", "5", "6"))
我们可以使用data.table
方法
library(data.table)
setDT(df)[df[, .I[which.min(do.call(pmin, .SD))],
group, .SDcols = patterns('^group_score')]$V1]
# group cut group_score_1 group_score_2
#1: a 0 2 2.5
#2: b 1 5 1.0