在R语言中使用dplyr包实现分组最值对应日期匹配是否有更高效方法?
问题描述
我有如下格式的tibble数据框:
library(tidyverse) date = seq(as.Date("2022/1/1"), by = "day", length.out = 16) value = c(1.1,1.2,1.3,1.4,1.7,1.4,1.9,1.89,2,2.1,2.2,2.15,3,3.1,3.09,2.08) variable = c(rep("a",4),rep("b",4),rep("c",4),rep("d",4)) df = tibble(date,value,variable);df
数据框结构如下:
# A tibble: 16 × 3 date value variable <date> <dbl> <chr> 1 2022-01-01 1.1 a 2 2022-01-02 1.2 a 3 2022-01-03 1.3 a 4 2022-01-04 1.4 a 5 2022-01-05 1.7 b 6 2022-01-06 1.4 b 7 2022-01-07 1.9 b 8 2022-01-08 1.89 b 9 2022-01-09 2 c 10 2022-01-10 2.1 c 11 2022-01-11 2.2 c 12 2022-01-12 2.15 c 13 2022-01-13 3 d 14 2022-01-14 3.1 d 15 2022-01-15 3.09 d 16 2022-01-16 2.08 d
我的需求是按variable列分组,统计value列的最大值和最小值,并匹配这些统计值对应的date列。
我自己用tidyverse实现的代码如下:
df%>%group_by(variable)%>% summarise(MAX = max(value),MIN=min(value))%>% pivot_longer(!variable, names_to = "stats", values_to = "value")%>% left_join(.,df,by=c("value","variable"))
运行结果:
# A tibble: 8 × 4 variable stats value date <chr> <chr> <dbl> <date> 1 a MAX 1.4 2022-01-04 2 a MIN 1.1 2022-01-01 3 b MAX 1.9 2022-01-07 4 b MIN 1.4 2022-01-06 5 c MAX 2.2 2022-01-11 6 c MIN 2 2022-01-09 7 d MAX 3.1 2022-01-14 8 d MIN 2.08 2022-01-16
想请教有没有更高效的方法实现这种统计值与对应日期的匹配?
更高效的实现方法
你的方法需要经过summarise→pivot_longer→left_join三个步骤,其实可以通过直接在分组后提取最值对应的行来简化流程,避免额外的join操作,效率更高:
方法1:用slice_max+slice_min结合bind_rows
直接筛选出每组最大/最小值对应的行,再添加标记列区分类型,逻辑直观且省去中间转换步骤:
df %>% group_by(variable) %>% slice_max(value, n = 1) %>% mutate(stats = "MAX") %>% bind_rows( df %>% group_by(variable) %>% slice_min(value, n = 1) %>% mutate(stats = "MIN") ) %>% select(variable, stats, value, date) %>% arrange(variable, desc(stats))
方法2:在summarise中直接提取对应日期
利用which.max/which.min定位最值位置,直接提取对应日期,再通过pivot_longer整理格式:
df %>% group_by(variable) %>% summarise( max_value = max(value), max_date = date[which.max(value)], min_value = min(value), min_date = date[which.min(value)] ) %>% pivot_longer( cols = -variable, names_to = c(".value", "stats"), names_sep = "_" ) %>% select(variable, stats, value, date)
这个方法只需要一次分组聚合,通过names_sep参数直接拆分列名,代码更紧凑。
方法3:用data.table处理大数据集
如果是超大数据集,data.table的性能优势更明显,写法也更简洁:
library(data.table) setDT(df) df[, .( stats = c("MAX", "MIN"), value = c(max(value), min(value)), date = c(date[which.max(value)], date[which.min(value)]) ), by = variable]
内容的提问来源于stack exchange,提问作者Homer Jay Simpson
相关产品推荐
相关产品推荐

