R中两个相似函数向量化后一正常一报错的原因探究
问题原因分析与解决办法
这问题我之前帮人排查过,核心是你没摸透Vectorize()的工作逻辑——它天生是为接收标量参数的函数设计的,碰到pen2这种接收向量参数的函数,行为就会和你预期的不一样。
先拆解两个函数的差异
penalty是两个独立的标量参数,Vectorize()处理它时,会把传入的向量参数按元素两两配对,分别调用penalty(a_i, b_i),每次调用的参数都是合法的标量,内部计算自然顺风顺水。pen2是单个向量参数(你本来期望它接收长度≥2的向量来提取元素计算),但Vectorize()默认的逻辑是:对函数的每个参数(这里就是x)做元素级拆解——也就是说,不管你给vpen2传什么,它都会把输入的每个元素单独丢给pen2当x,而不是把整个向量作为x传入。
报错的直接诱因
举个实际的例子,假设你的pen2是这么写的:
pen2 <- function(x) { res <- x[1] - x[2] # 依赖x是长度≥2的向量 trimean <- quantile(res, c(0.25, 0.5, 0.5, 0.75)) sum(trimean * c(1,2,2,1))/6 }
当你调用vpen2(c(1,2)),Vectorize()会拆成两次调用:pen2(1)和pen2(2)。但pen2(1)里x是长度为1的向量,x[2]会返回NA,导致res变成NA。而quantile()默认不允许处理NA(na.rm=FALSE),直接就抛出了你看到的错误。
怎么解决?
你根本不需要用Vectorize()来处理pen2这种向量参数的函数,换更合适的批量处理工具就行:
- 如果输入是矩阵(每一行是一组参数向量):用
apply()直接按行处理param_matrix <- matrix(c(1,2, 3,4), ncol=2, byrow=TRUE) apply(param_matrix, 1, pen2) - 如果输入是列表(每个元素是一组参数向量):用
lapply()/sapply()param_list <- list(c(1,2), c(3,4)) sapply(param_list, pen2) - 如果一定要用
Vectorize():把pen2改成和penalty一样的双标量参数形式,再用Vectorize()就没问题了。
内容的提问来源于stack exchange,提问作者Andreï V. Kostyrka
相关产品推荐
相关产品推荐

