将apply转换为purrr的pmap:求每行最新得分年份的替代实现
把apply逻辑转成purrr实现的方案
嘿,我来帮你把这段apply代码转换成更符合tidyverse风格的purrr实现~先理清楚原代码的核心逻辑:逐行找出值为1的SCORE列中最新的年份,没有匹配项就返回0,下面是两种等价的purrr写法,都能实现相同功能:
方案一:贴近原apply逻辑的pmap写法
这种写法和你原代码的思路几乎一致,只是用pmap替代了apply,更符合函数式编程的风格:
library(purrr) library(stringr) # 原数据 dat = data.frame('SCORE_2010'=c(0,0,1,0), 'SCORE_2011'=c(1,0,1,0), 'SCORE_2012'=c(0,0,1,0), 'SCORE_2013'=c(1,0,0,1)) # 先单独提取所有SCORE年份列,避免后续索引混乱 score_cols = dat |> dplyr::select(matches('^SCORE_[0-9]+')) # 用pmap_chr逐行处理,返回字符型结果 dat$L_YEAR = pmap_chr(score_cols, function(...) { # 把当前行的所有值拼成向量,对应原apply里的x row_values = c(...) # 找出值为1的元素索引 ones_positions = which(row_values == 1) if (length(ones_positions) > 0) { # 取最大索引(对应最新年份的列),提取列名中的年份 latest_col = names(score_cols)[max(ones_positions)] str_extract(latest_col, '[0-9]+') } else { # 没有1的情况返回'0' '0' } }) # 可选:把结果转成数值型 dat$L_YEAR = as.integer(dat$L_YEAR)
方案二:结合dplyr的更直观写法
如果习惯tidyverse的管道风格,这种写法可读性更强,不用手动处理索引,直接通过列名筛选和排序:
library(purrr) library(stringr) library(dplyr) dat = data.frame('SCORE_2010'=c(0,0,1,0), 'SCORE_2011'=c(1,0,1,0), 'SCORE_2012'=c(0,0,1,0), 'SCORE_2013'=c(1,0,0,1)) score_cols = dat |> select(matches('^SCORE_[0-9]+')) dat$L_YEAR = score_cols |> pmap(function(...) { # 把当前行的列名和对应值做成临时表格 current_row = tibble(col_name = names(score_cols), value = c(...)) # 筛选值为1的行,提取列名,取最大的(年份最新的),默认返回SCORE_0 current_row |> filter(value == 1) |> pull(col_name) |> max(default = 'SCORE_0') |> str_extract('[0-9]+') }) |> unlist() |> as.integer()
小提示
原代码里有个潜在的小问题:names(dat)[max(which(x==1))]依赖于SCORE列在整个data.frame中的位置,如果后续dat新增了其他列在SCORE列前面,索引就会出错。上面的两种purrr方案都先单独提取了score_cols,避免了这个问题,更健壮。
内容的提问来源于stack exchange,提问作者spazznolo
相关产品推荐
相关产品推荐

