如何用R dplyr逐行查找11最后出现后的SOC编码变化并记录?
R中查找每行11最后出现位置并记录后续值的实现方案
首先先重现你的数据:
ID <- c(1,2,3,6) SOC_2017 <- c(22,11,11,10) SOC_2018 <- c(11,11,21,10) SOC_2019 <- c(11,11,21,20) SOC_2020 <- c(21,11,21,20) my_data<- data.frame(ID,SOC_2017,SOC_2018,SOC_2019,SOC_2020)
核心思路
不需要嵌套IF函数,用向量化操作或分组处理更高效:
- 定位每行中值为11的所有位置,取最后一个出现的索引
- 判断该索引是否为年份列的最后一列:如果是则无后续值,否则提取下一列的数值和对应年份
- 整理结果为你需要的宽格式
方法一:基础R实现
# 筛选出所有年份列的索引 soc_col_idx <- grep("SOC_", names(my_data)) # 提取年份列名称和对应的年份数字 year_cols <- names(my_data)[soc_col_idx] year_nums <- as.integer(sub("SOC_", "", year_cols)) # 逐行处理数据 row_results <- apply(my_data[soc_col_idx], 1, function(row_vals) { # 找到当前行中值为11的位置 eleven_pos <- which(row_vals == 11) # 没有11的行直接返回空 if (length(eleven_pos) == 0) return(NULL) # 取最后一个11的位置 last_eleven <- max(eleven_pos) # 如果11在最后一列,无后续值,返回空 if (last_eleven == length(row_vals)) return(NULL) # 提取后续值和对应年份列名 next_val <- row_vals[last_eleven + 1] next_year_col <- year_cols[last_eleven + 1] return(data.frame(ID = my_data$ID[which(row_vals == my_data[soc_col_idx, ])], col_name = next_year_col, value = next_val)) }) # 合并结果并转为宽格式 final_result <- do.call(rbind, row_results) %>% tidyr::pivot_wider(id_cols = ID, names_from = col_name, values_from = value) # 查看结果 print(final_result)
方法二:tidyverse框架实现(更简洁直观)
library(tidyverse) final_result <- my_data %>% # 转成长格式,便于分组处理 pivot_longer(-ID, names_to = "year_col", values_to = "soc_val") %>% mutate(year = as.integer(str_remove(year_col, "SOC_"))) %>% group_by(ID) %>% mutate( # 标记当前值是否为11 is_eleven = soc_val == 11, # 找到当前组中最后一个11的行号 last_eleven_row = max(which(is_eleven)) ) %>% # 只保留最后一个11的下一行数据 filter(row_number() == last_eleven_row + 1) %>% # 过滤掉没有11或11在最后一行的情况 filter(!is.na(last_eleven_row)) %>% # 转回宽格式 select(ID, year_col, soc_val) %>% pivot_wider(names_from = year_col, values_from = soc_val) # 查看结果 print(final_result)
两种方法运行后都会得到你需要的输出:
| ID | SOC_2018 | SOC_2020 |
|---|---|---|
| 1 | NA | 21 |
| 3 | 21 | NA |
内容的提问来源于stack exchange,提问作者S12
相关产品推荐
相关产品推荐

