如何为观测数据批量匹配种群规模?替代大量if-else的R语言方案
高效匹配种群规模标签的R语言解决方案
我有一份观测数据列表,还有一张记录各物种不同阶段种群规模(small、medium、large)的对照表,需要给观测数据添加种群规模字段。
观测数据(实际数据更长)
observations <- data.frame("species" = c("Rana temporaria","Rana temporaria", "Bufo bufo", "Bufo bufo"), "stage" = c("adult","egg","adult","adult"), "count" = c(20,40,100,35), "population" = c(NA,NA,NA,NA))
种群规模对照表(实际数据更长)
population <- data.frame("species" = c("Rana temporaria","Bufo bufo","Bufo bufo"), "stage" = c("adult","adult", "egg"), "small" = c("1-5","1-5","0-100"), "medium" = c("6-10","6-50", "101-500"), "large" = c(">10",">50",">500"))
目前我通过逐个编写if语句来实现匹配,但效率极低,示例代码如下:
if(observations$species[1]=="Rana temporaria" & observations$stage[1] == "adult" & observations$count[1] >= 6 & observations$count[1] >= 10) { observations$population[1] = "medium" }
请问有没有更高效的替代方案?
解决方案
步骤1:预处理对照表,将区间转为数值阈值
首先需要把对照表中的区间字符串转换成可计算的数值范围,方便后续批量匹配:
# 加载dplyr和tidyr包 library(dplyr) library(tidyr) # 处理population表,拆分区间为最小值和最大值 population_processed <- population %>% pivot_longer(cols = c(small, medium, large), names_to = "size_class", values_to = "range") %>% mutate( min_val = as.numeric(sub("-.*", "", range)), max_val = as.numeric(sub(".*-", "", range)), # 处理带大于号的区间 max_val = ifelse(grepl(">", range), Inf, max_val), min_val = ifelse(grepl(">", range), as.numeric(sub(">", "", range)), min_val) ) %>% select(species, stage, size_class, min_val, max_val)
步骤2:关联数据并批量匹配规模类别
用left_join关联观测数据和预处理后的对照表,通过条件筛选匹配对应的规模标签:
# 匹配符合条件的规模类别 matched_size <- observations %>% left_join(population_processed, by = c("species", "stage")) %>% filter(count >= min_val & count <= max_val) %>% select(species, stage, count, size_class) %>% rename(population = size_class) # 合并回原始数据,保留匹配不到的NA值 final_observations <- observations %>% left_join(matched_size, by = c("species", "stage", "count")) %>% mutate(population = coalesce(population.y, population.x)) %>% select(-population.x, -population.y)
结果验证
运行后final_observations的输出结果:
| species | stage | count | population |
|---|---|---|---|
| Rana temporaria | adult | 20 | large |
| Rana temporaria | egg | 40 | NA |
| Bufo bufo | adult | 100 | large |
| Bufo bufo | adult | 35 | medium |
内容的提问来源于stack exchange,提问作者Patrick Marti
相关产品推荐
相关产品推荐

