我正在尝试实现一个用于分类的感知机算法,但我觉得似乎缺少了一些东西。这是使用逻辑回归得到的决策边界:
红色点表示在测试1和测试2中表现更好后进入了大学。
这是数据,这是R中逻辑回归的代码:
dat = read.csv("perceptron.txt", header=F)colnames(dat) = c("test1","test2","y")plot(test2 ~ test1, col = as.factor(y), pch = 20, data=dat)fit = glm(y ~ test1 + test2, family = "binomial", data = dat)coefs = coef(fit)(x = c(min(dat[,1])-2, max(dat[,1])+2))(y = c((-1/coefs[3]) * (coefs[2] * x + coefs[1])))lines(x, y)
以下是“手动”实现感知机的代码:
# 数据预处理:dat = read.csv("perceptron.txt", header=F)dat[,1:2] = apply(dat[,1:2], MARGIN = 2, FUN = function(x) scale(x)) # 对数据进行缩放data = data.frame(rep(1,nrow(dat)), dat) # 引入“偏置”列colnames(data) = c("bias","test1","test2","y")data$y[data$y==0] = -1 # 将0/1的因变量转换为-1/1.data = as.matrix(data) # 将数据框转换为矩阵以避免矩阵乘法问题。# 感知机:set.seed(62416)no.iter = 1000 # 循环次数theta = rnorm(ncol(data) - 1) # 开始一个随机系数向量。theta = theta/sqrt(sum(theta^2)) # 归一化向量。h = theta %*% t(data[,1:3]) # 执行第一次f(theta^T X)for (i in 1:no.iter){ # 我们将重新计算1000次 for (j in 1:nrow(data)){ # 每次我们遍历每个示例。 if(h[j] * data[j, 4] < 0){ # 如果假设与y的符号不一致, theta = theta + (sign(data[j,4]) * data[j, 1:3]) # 我们对theta进行加或减示例。 } else theta = theta # 否则保持不变。 } h = theta %*% t(data[,1:3]) # 在迭代后计算h()。}theta # 最终系数mean(sign(h) == data[,4]) # 准确率
使用这个,我得到了以下系数:
bias test1 test2 9.131054 19.095881 20.736352
以及88%
的准确率,这与使用glm()
逻辑回归函数计算的结果一致:mean(sign(predict(fit))==data[,4])
为89%
– 显然,从上面的图表可以看出,不可能线性分类所有点。实际上,仅迭代10次并绘制准确率,在第一次迭代后即可达到~90%
的准确率:
由于与逻辑回归的训练分类性能一致,代码在概念上应该没有问题。
问题:得到与逻辑回归如此不同的系数是否可以接受:
(Intercept) test1 test2 1.718449 4.012903 3.743903
回答:
这其实更适合在CrossValidated上提问而不是StackOverflow,但我还是会回答这个问题。
是的,得到非常不同的系数是正常且预期的,因为你不能直接比较这两种技术的系数大小。
在逻辑(logit)模型中,你使用的是基于Sigmoid成本函数的二项分布和logit链接。系数只有在这种情况下才有意义。你在logit中还包含了一个截距项。
感知机模型则不具备这些特征。因此,系数的解释完全不同。
现在,这并不是说哪个模型更好。你的问题中没有可比较的性能指标来判断这一点。要判断这一点,你应该进行交叉验证或者至少使用一个保留样本进行测试。