如何在R中无循环/Apply语句向量化kde.cv函数?
无循环向量化实现留一交叉验证核密度评分
没问题,我来帮你把这个带for循环的kde.cv函数改成完全向量化的版本——不用任何循环或apply类函数,效率还更高!
首先先理清楚你的核心需求:这个函数是做留一交叉验证的核密度评分,对每个样本点,用去掉它之后的数据集估计它的密度,最后把所有对数密度值加起来。我们可以通过矩阵运算一次性完成所有计算,完全绕开循环。
先拆解原有逻辑
你的kde函数本质是对输入的评估点,计算它和所有样本的差值,再用正态核函数转换后取均值。而kde.cv里的循环,其实就是对每个X[i],用X[-i](去掉自身的数据集)来计算这个均值。
向量化实现代码
直接看实现,我会一步步解释为什么这么写:
kde.cv.vectorized <- function(X, s) { # 1. 一次性生成所有样本两两之间的差值矩阵:X[i] - X[j] 对所有i,j diff_matrix <- outer(X, X, FUN = "-") # 2. 把对角线元素设为NA——因为留一验证里,每个点不能用自己来估计 diag(diff_matrix) <- NA # 3. 对所有差值计算正态核函数值 phi_matrix <- dnorm(diff_matrix, mean = 0, sd = s) # 4. 按行取均值,自动忽略NA(也就是跳过自身的那个样本) fhat_vector <- rowMeans(phi_matrix, na.rm = TRUE) # 5. 计算所有对数密度的和,就是CV分数 CV_score <- sum(log(fhat_vector)) return(CV_score) }
验证结果和原函数一致
用你给的示例数据测试一下,确保结果完全相同:
# 你的示例输入 X <- c(-1.1653, -0.7538, -1.3218, -2.3394, -1.9766, -1.8718, -1.5041) s <- 0.2 # 原函数输出 kde.cv(X, s) # 向量化函数输出 kde.cv.vectorized(X, s)
运行后你会发现两个函数返回的CV分数完全一样,但向量化版本没有循环,在样本量更大的时候会快很多。
为什么这个方案能替代循环?
outer(X, X, "-")直接生成了length(X)×length(X)的差值矩阵,一次性完成所有X[i]-X[j]的计算,不用逐个循环- 把对角线设为NA,正好对应留一验证里“排除自身样本”的要求
rowMeans(..., na.rm = TRUE)会自动跳过每行的NA值,计算剩下6个样本的核函数均值,和原kde(X[i], X[-i], s)的结果完全等价
这样就完美实现了你要的无循环向量化,逻辑和原函数完全一致,代码还更简洁高效!
内容的提问来源于stack exchange,提问作者Jaime Melara Sosa
相关产品推荐
相关产品推荐

