我想了解R语言的kknn包是如何计算权重、距离和类别概率的,特别是在二元分类问题中。以下是R语言代码,其中训练样本中有三个观测值,保留样本中有一个观测值。两个预测变量是身高和体重。使用欧几里得距离,训练样本中每个观测值的距离计算如下:
sqrt((6-8)^2 + (4-5)^2) = 2.24
sqrt((6-3)^2 + (4-7)^2) = 4.24
sqrt((6-7)^2 + (4-3)^2) = 1.41.
当k=3且权重相等时,我得到保留样本的概率为:
(1/3 * 1) + (1/3 * 0) + (1/3 * 1) = 0.67.
当k=2且权重相等时,我得到保留样本的概率为:
(1/2 * 1) + (1/2 * 1) = 1.00.
我想了解R语言的kknn包是如何使用“三角形”、“高斯”和“逆”权重(以及更一般的情况)进行这些相同计算的。
library(kknn)training <- data.frame(class = c(1, 0, 1), height = c(8, 3, 7), weight = c(5, 7, 3))holdouts <- data.frame(class = 1, height = 6, weight = 4)triangular_kernel <- kknn(class ~., training, holdouts, distance = 2, kernel = "triangular", k = 3)triangular_kernel[["fitted.values"]]triangular_kernel[["W"]]triangular_kernel[["D"]]gaussian_kernel <- kknn(class ~., training, holdouts, distance = 2, kernel = "gaussian", k = 3)gaussian_kernel[["fitted.values"]]gaussian_kernel[["W"]]gaussian_kernel[["D"]]inverse_kernel <- kknn(class ~., training, holdouts, distance = 2, kernel = "inv", k = 3)inverse_kernel[["fitted.values"]]inverse_kernel[["W"]]inverse_kernel[["D"]]
回答:
调用kknn::kknn
会在控制台打印出kknn函数的源代码。通过逐行查看函数,可以了解它的工作原理。
距离
kknn
调用了编译后的C代码dmEuclid
。要获取其源代码,我们按照这个指南,在R中编写以下代码:
untar(download.packages(pkgs = "kknn", destdir = ".", type = "source")[,2])
然后在工作目录(getwd()
)中打开kknn_1.3.1.tar的src目录,找到并使用任何文本编辑器打开dm.C。向下滚动大约一半可以找到dmEuclid。要测试dmEuclid
的具体输出,可以安装构建工具,并在Rstudio中打开一个C++文件,通过下拉菜单选择它,然后使用不同的输入运行代码。
根据函数输出,在你的情况下,dmtmp$dm
的结果是
3.779645e-01 1.133893e+00 1.000000e+150 3.685210e-156
根据你的指定k
,前3个值被选为距离D
。包作者手动将其转换为maxdist = 1e-06
,因为在你的情况下最大距离小于该值。
权重
kknn
函数使用以下部分来分配权重方案,根据你定义的核函数。
W <- D/maxdist W <- pmin(W, 1 - (1e-06)) W <- pmax(W, 1e-06)
在这一点上,你的W值大于1,因此W被强制转换为大约1。
if (kernel == "inv" W <- 1/Wif (kernel == "triangular") W <- 1 - Wif (kernel == "gaussian") { alpha = 1/(2 * (k + 1)) qua = abs(qnorm(alpha)) W = W * qua W = dnorm(W, sd = 1) }
其解释可以在gowerc链接的论文中找到。W随后被转换为矩阵W <- matrix(W, p, k)
,有1行(p=1),3列(k=3)。
拟合值
在你的情况下p = 1
是1,k=3
,cl = c(1,0,1)
。
C <- matrix(dmtmp$cl, nrow = p, ncol = k + 1)C <- C[, 1:k] + 1CL <- matrix(cl[C], nrow = p, ncol = k)W <- matrix(W, p, k)fit <- rowSums(W * CL)/pmax(rowSums(W), 1e-06)