dplyr处理storms数据集:按风暴最高等级高效拆分数据框
实现方案
核心思路是先按风暴名称分组,计算每个风暴生命周期内的最高强度,再按最高强度批量拆分数据集,不需要反复执行半连接、反连接的排除操作,代码更简洁,运行效率也更高。
基于status字段的高效实现
首先明确三类status的强度从低到高顺序为:热带低压(tropical depression)< 热带风暴(tropical storm)< 飓风(hurricane),先给每个状态匹配对应强度权重,再分组取每个风暴的最高强度状态即可。
library(dplyr) # 定义状态强度权重,数值越大强度越高,若数据集包含其他状态可按顺序补充 status_weight <- c( "tropical depression" = 1, "tropical storm" = 2, "hurricane" = 3 ) # 计算每个风暴的最高强度状态 storm_peak_status <- storms_19_20_21.df %>% mutate(score = status_weight[status]) %>% group_by(name) %>% summarise(peak_status = status[which.max(score)], .groups = "drop") # 批量拆分生成独立数据框 status_split_df <- storm_peak_status %>% left_join(storms_19_20_21.df, by = "name") %>% group_by(peak_status) %>% group_split(.keep = FALSE) # 为拆分后的数据框命名并加载到环境中 names(status_split_df) <- c("tropical_depression_data.df", "tropical_storm_data.df", "hurricane_data.df") list2env(status_split_df, envir = .GlobalEnv)
该写法相比原多步排除逻辑减少了多次表连接操作,后续如果需要新增状态分类,仅需在
status_weight中补充对应权重即可,无需调整后续拆分逻辑。
基于category字段的实现
category字段本身就是数值型强度标识:-1代表热带低压、0代表热带风暴、1-5代表不同等级的飓风,数值越高强度越大,无需手动定义权重,计算逻辑更简单。
如果需要和之前一样拆分为热带低压、热带风暴、飓风三类数据框,代码如下:
# 计算每个风暴的最高等级分类 storm_peak_cat <- storms_19_20_21.df %>% group_by(name) %>% summarise(peak_cat = max(category, na.rm = TRUE), .groups = "drop") %>% mutate( storm_type = case_when( peak_cat == -1 ~ "tropical_depression_data.df", peak_cat == 0 ~ "tropical_storm_data.df", peak_cat >= 1 ~ "hurricane_data.df" ) ) # 批量拆分生成独立数据框 cat_split_df <- storm_peak_cat %>% left_join(storms_19_20_21.df, by = "name") %>% group_by(storm_type) %>% group_split(.keep = FALSE) names(cat_split_df) <- unique(storm_peak_cat$storm_type) list2env(cat_split_df, envir = .GlobalEnv)
如果需要将飓风按1-5级拆分为更细的独立数据框,仅需调整case_when中的分类规则即可,核心逻辑无需改动。
结果校验
可运行以下代码对比新方法生成的数据集和原多步排除法的结果,三个校验语句均返回TRUE即代表结果完全一致:
# 对比飓风数据集行数 identical(nrow(hurricane_data.df), nrow(semi_join(storms_19_20_21.df, distinct(filter(storms_19_20_21.df, status=="hurricane"), name), by = "name"))) # 对比热带风暴数据集行数 identical(nrow(tropical_storm_data.df), nrow(semi_join(storms_19_20_21.df, anti_join(distinct(filter(storms_19_20_21.df, status=="tropical storm"), name), distinct(filter(storms_19_20_21.df, status=="hurricane"), name), by = "name"), by = "name"))) # 对比热带低压数据集行数 identical(nrow(tropical_depression_data.df), nrow(anti_join(anti_join(storms_19_20_21.df, distinct(filter(storms_19_20_21.df, status=="hurricane"), name), by = "name"), distinct(filter(storms_19_20_21.df, status=="tropical storm"), name), by = "name")))
内容的提问来源于stack exchange,提问作者dragonmctt
相关产品推荐
相关产品推荐

