自定义R函数allocate_data_m运行报错求助:无法分配total_amount
问题:自定义分组处理函数在dplyr mutate中报错的原因与修复
场景与代码重现
首先是数据准备代码:
library(tidyverse) detail <- data.frame(cat = c("a","a","a","b","b","b","b","c","c"), single_amount = c(1,3,7,2,1,4,6,1,6)) total <- data.frame(cat = c("a","b","c"), total_amount = c(20,10,9)) raw_df <- detail %>% left_join(total, by = 'cat')
用户自定义了函数allocate_data_m,意图实现"当累计single_data小于total_amount时分配对应值,否则为0"的逻辑:
allocate_data_m <- function(data, single_data, total_data) { out <- cumsum_single_data <- rep('NA', nrow(data)) for (grouprow in seq_len(nrow(data))) { cumsum_single_data[grouprow] <- if_else(grouprow == 1, data[grouprow, single_data], cumsum_single_data[grouprow-1] + data[grouprow, single_data]) out[grouprow] <- if_else(cumsum_single_data[grouprow] < data[grouprow, total_data], data[grouprow, single_data], 0) } out }
但在分组调用时出现报错:self_function can't work-- Can't subset columns past the end,调用代码如下:
raw_df %>% group_by(cat) %>% mutate(amount_x_all = allocate_data_m(cur_data(), single_amount, total_amount))
用户期望的效果可通过以下代码实现:
raw_df %>% group_by(cat) %>% mutate(amount_x_all = if_else(cumsum(single_amount) < total_amount, single_amount, 0))
报错原因分析
- 参数传递类型错误:在
mutate中传递single_amount和total_amount时,实际传递的是列的数值向量,而非列名字符串。但函数里用data[grouprow, single_data]的方式试图按列名取子集,这就导致R把向量当作列索引去匹配,自然会出现"无法超出列数取子集"的错误。 - 变量类型初始化错误:
cumsum_single_data被初始化为字符型的'NA',后续做数值加法时会触发类型不兼容问题,进一步加剧报错。 - 循环逻辑冗余且错误:手动实现
cumsum完全没必要,而且循环中对累计值的类型处理混乱,导致后续比较逻辑失效。
修复方案
方案1:修正自定义函数
如果一定要保留自定义函数,需调整参数传递方式(改用列名字符串)并修正类型问题:
allocate_data_m <- function(data, single_col, total_col) { # 提取列的数值向量 single_data <- data[[single_col]] total_data <- data[[total_col]] # 计算累计值 cumsum_vals <- cumsum(single_data) # 生成结果 if_else(cumsum_vals < total_data, single_data, 0) }
调用时传递列名字符串:
raw_df %>% group_by(cat) %>% mutate(amount_x_all = allocate_data_m(cur_data(), "single_amount", "total_amount"))
方案2:直接使用原生dplyr逻辑(推荐)
用户已经写出了正确的简洁实现,完全不需要自定义函数:
raw_df %>% group_by(cat) %>% mutate(amount_x_all = if_else(cumsum(single_amount) < total_amount, single_amount, 0))
这段代码利用dplyr的分组自动处理特性,结合cumsum原生函数,直接实现需求,既简洁又避免了自定义函数的潜在问题。
内容的提问来源于stack exchange,提问作者anderwyang
相关产品推荐
相关产品推荐

