R语言使用自定义函数为DataFrame新增列时apply报错解决
报错根因
两个核心错误直接触发了你看到的警告和报错:
apply()的第三个参数要求传入函数对象本身,你写的fun(dt$value)是提前把整个value列(长度为数据表行数的向量)直接传入了自定义函数。R原生的if/else结构、你代码里用的&&运算符都只能处理单值逻辑判断,传入长度大于1的向量时,只会取第一个元素做判断,对应你看到的the condition has length > 1 and only the first element will be used警告;如果向量里存在缺失值NA,判断逻辑无法返回TRUE/FALSE布尔值,就会抛出missing value where TRUE/FALSE needed的错误。- 你的需求仅需要对
value单列做值映射,用apply(,1,)逐行遍历整个数据框是非常低效的写法,数据量稍大就会有明显的性能问题,完全没有必要。
可直接运行的解决方案
按推荐优先级从高到低排列:
方法1:用原生向量化函数cut实现(首选)
这是R语言针对区间分箱场景的原生实现,没有逐行循环的性能损耗,万行以上数据运行速度比apply快几十到上百倍,不需要写自定义函数,直接匹配你的判断规则即可:
dt$newcolumn <- cut( dt$value, breaks = c(-Inf, 10, 30, 50, Inf), labels = c("white", "yellow", "red", "black"), right = FALSE # 匹配左闭右开的判断规则:x<10、10≤x<30、30≤x<50、x≥50 )
方法2:改造自定义函数为向量化版本
如果要保留自定义判断逻辑的可读性,可以把函数改造成支持向量输入的版本,直接传入整列赋值即可,不需要调用apply:
如果可以调用dplyr包,用case_when写判断逻辑可读性最高:
library(dplyr) fun <- function(x) { case_when( x < 10 ~ "white", x >= 10 & x < 30 ~ "yellow", x >= 30 & x < 50 ~ "red", TRUE ~ "black" ) } # 直接传入整列赋值 dt$newcolumn <- fun(dt$value)
不想加载第三方包的话,用基础R的ifelse嵌套也可以实现同样的向量化效果:
fun <- function(x) { ifelse(x < 10, "white", ifelse(x < 30, "yellow", ifelse(x < 50, "red", "black"))) } dt$newcolumn <- fun(dt$value)
方法3:修正apply的错误写法(不推荐)
仅作为错误写法的修正参考,这种逐行遍历全表的写法性能极差,非必要不要用:
# 注意:apply遍历数据框时会强制把所有值转为字符型,取value列后要先转回数值 dt$newcolumn <- apply(dt, 1, function(row) { val <- as.numeric(row["value"]) if(val < 10) {return ("white") } else if (val >= 10 && val < 30) { return ("yellow") } else if (val >= 30 && val < 50) { return ("red") } else { return ("black") } })
注意事项
如果你的value列本身存在NA值,上述所有方法返回的新列对应位置默认会是NA,不会触发报错。如果需要给缺失值单独指定填充值,在判断逻辑最前面加一层is.na(x)的分支判断即可。
内容的提问来源于stack exchange,提问作者Geek_Nerdy93
相关产品推荐
相关产品推荐

