logistic regression (逻辑回归算法)
下面的函数与图为logistic regression的核心
LR算法解决主要解决分类问题的判别概率问题。现在常用在垃圾邮件判别、推荐系统、疾病预测等场景中。一般用来判决某件 事情属于某个分类的概率来确定类别。如:一封邮件是垃圾邮件概率是90%,则判定这封邮件是垃圾邮件;某个用户可能概率最大的三类产品为:华为手机80%,iPhone75%,魅族73%,其余的都小于73%,则给这个用户推荐的产品就是华为、iPhone、魅族;一个病人,根据他的年龄、患病历史、疼痛部位、疼痛状态等特征得出他得咽喉癌的概率是79%,则判定这个病人可能是咽喉癌。
逻辑回归算法计算公式
sigmoid函数,俗称激活函数
说了这么多,下面进入正题,pyhton的代码实现
初始化线性函数参数为1
构造sigmoid函数
重复循环I次
计算数据集梯度
更新线性函数参数
确定最终的sigmoid函数
输入训练(测试)数据集
运用最终sigmoid函数求解分类
# -*- coding:utf-8 -*- import numpy as np import matplotlib.pyplot as plt import random def text2num(string): """ :param string: string :return: list """ str_list = string.replace("\n", " ").split(" ") while \'\' in str_list: str_list.remove(\'\') num_list = [float(i) for i in str_list] return num_list def sigmoid(x): """ :param x: 输入需要计算的值 :return: """ return 1.0 / (1 + np.exp(-x)) def data_plot(data_list, weight): """ :param data_list:数据点集合 :param weight: 参数集合 :return: null """ x_data = [list(i[0:2]) for i in data_list if i[2] == 0.0] y_data = [list(i[0:2]) for i in data_list if i[2] == 1.0] x_data = np.reshape(x_data, np.shape(x_data)) y_data = np.reshape(y_data, np.shape(y_data)) linear_x = np.arange(-4, 4, 1) linear_y = (-weight[0] - weight[1] * linear_x) / weight[2] print(linear_y) plt.figure(1) plt.scatter(x_data[:, 0], x_data[:, 1], c=\'r\') plt.scatter(y_data[:, 0], y_data[:, 1], c=\'g\') print(linear_x) print(linear_y.tolist()[0]) plt.plot(linear_x, linear_y.tolist()[0]) plt.show() def grad_desc(data_mat, label_mat, rate, times): """ :param data_mat: 数据特征 :param label_mat: 数据标签 :param rate: 速率 :param times: 循环次数 :return: 参数 """ data_mat = np.mat(data_mat) label_mat = np.mat(label_mat) m,n = np.shape(data_mat) weight = np.ones((n, 1)) for i in range(times): h = sigmoid(data_mat * weight) error = h - label_mat weight = weight - rate * data_mat.transpose() * error return weight def random_grad_desc(data_mat, label_mat, rate, times): """ :param data_mat: 数据特征 :param label_mat: 数据标签 :param rate: 速率 :param times: 循环次数 :return: 参数 """ data_mat = np.mat(data_mat) m,n = np.shape(data_mat) weight = np.ones((n, 1)) for i in range(times): for j in range(m): h = sigmoid(data_mat[j] * weight) error = h - label_mat[j] weight = weight - rate * data_mat[j].transpose() * error return weight def improve_random_grad_desc(data_mat, label_mat, times): """ :param data_mat: 数据特征 :param label_mat: 数据标签 :param rate: 速率 :param times: 循环次数 :return: 参数 """ data_mat = np.mat(data_mat) m,n = np.shape(data_mat) weight = np.ones((n, 1)) for i in range(times): index_data = [i for i in range(m)] for j in range(m): rate = 0.0001 + 4 / (i + j + 1) index = random.sample(index_data, 1) h = sigmoid(data_mat[index] * weight) error = h - label_mat[index] weight = weight - rate * data_mat[index].transpose() * error index_data.remove(index[0]) return weight def main(): file = open("/Users/chenzu/Documents/code-machine-learning/data/LR", "rb") file_lines = file.read().decode("UTF-8") data_list = text2num(file_lines) data_len = int(len(data_list) / 3) data_list = np.reshape(data_list, (data_len, 3)) data_mat_temp = data_list[:, 0:2] data_mat = [] for i in data_mat_temp: data_mat.append([1, i[0], i[1]]) print(data_mat) label_mat = data_list[:, 2:3] #梯度下降求参数 weight = improve_random_grad_desc(data_mat, label_mat, 500) print(weight) data_plot(data_list, weight) if __name__ == \'__main__\': main()
输出:
逻辑回归算法优缺点:
优点:计算代价不高、容易理解和实现
缺点:容易欠拟合,分类精度不高。
适用于数值型和标称型数据。
数值型:数值型目标变量则可以从无限的数值集合中取值,如0.100,42.001等 (数值型目标变量主要用于回归分析)
下面是我结合一些博主的博客,搬运过来的
from numpy import * filename=\'...\\testSet.txt\' #文件目录 def loadDataSet(): #读取数据(这里只有两个特征) dataMat = [] labelMat = [] fr = open(filename) for line in fr.readlines(): lineArr = line.strip().split() dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) #前面的1,表示方程的常量。比如两个特征X1,X2,共需要三个参数,W1+W2*X1+W3*X2 labelMat.append(int(lineArr[2])) return dataMat,labelMat def sigmoid(inX): #sigmoid函数 return 1.0/(1+exp(-inX)) def gradAscent(dataMat, labelMat): #梯度上升求最优参数 dataMatrix=mat(dataMat) #将读取的数据转换为矩阵 classLabels=mat(labelMat).transpose() #将读取的数据转换为矩阵 m,n = shape(dataMatrix) alpha = 0.001 #设置梯度的阀值,该值越大梯度上升幅度越大 maxCycles = 500 #设置迭代的次数,一般看实际数据进行设定,有些可能200次就够了 weights = ones((n,1)) #设置初始的参数,并都赋默认值为1。注意这里权重以矩阵形式表示三个参数。 for k in range(maxCycles): h = sigmoid(dataMatrix*weights) error = (classLabels - h) #求导后差值 weights = weights + alpha * dataMatrix.transpose()* error #迭代更新权重 return weights def stocGradAscent0(dataMat, labelMat): #随机梯度上升,当数据量比较大时,每次迭代都选择全量数据进行计算,计算量会非常大。所以采用每次迭代中一次只选择其中的一行数据进行更新权重。 dataMatrix=mat(dataMat) classLabels=labelMat m,n=shape(dataMatrix) alpha=0.01 maxCycles = 500 weights=ones((n,1)) for k in range(maxCycles): for i in range(m): #遍历计算每一行 h = sigmoid(sum(dataMatrix[i] * weights)) error = classLabels[i] - h weights = weights + alpha * error * dataMatrix[i].transpose() return weights def stocGradAscent1(dataMat, labelMat): #改进版随机梯度上升,在每次迭代中随机选择样本来更新权重,并且随迭代次数增加,权重变化越小。 dataMatrix=mat(dataMat) classLabels=labelMat m,n=shape(dataMatrix) weights=ones((n,1)) maxCycles=500 for j in range(maxCycles): #迭代 dataIndex=[i for i in range(m)] for i in range(m): #随机遍历每一行 alpha=4/(1+j+i)+0.0001 #随迭代次数增加,权重变化越小。 randIndex=int(random.uniform(0,len(dataIndex))) #随机抽样 h=sigmoid(sum(dataMatrix[randIndex]*weights)) error=classLabels[randIndex]-h weights=weights+alpha*error*dataMatrix[randIndex].transpose() del(dataIndex[randIndex]) #去除已经抽取的样本 return weights def plotBestFit(weights): #画出最终分类的图 import matplotlib.pyplot as plt dataMat,labelMat=loadDataSet() dataArr = array(dataMat) n = shape(dataArr)[0] xcord1 = []; ycord1 = [] xcord2 = []; ycord2 = [] for i in range(n): if int(labelMat[i])== 1: xcord1.append(dataArr[i,1]) ycord1.append(dataArr[i,2]) else: xcord2.append(dataArr[i,1]) ycord2.append(dataArr[i,2]) fig = plt.figure() ax = fig.add_subplot(111) ax.scatter(xcord1, ycord1, s=30, c=\'red\', marker=\'s\') ax.scatter(xcord2, ycord2, s=30, c=\'green\') x = arange(-3.0, 3.0, 0.1) y = (-weights[0]-weights[1]*x)/weights[2] ax.plot(x, y) plt.xlabel(\'X1\') plt.ylabel(\'X2\') plt.show() def main(): dataMat, labelMat = loadDataSet() weights=gradAscent(dataMat, labelMat).getA() plotBestFit(weights) if __name__==\'__main__\': main()
输出:
-0.017612 14.053064 0 -1.395634 4.662541 1 -0.752157 6.538620 0 -1.322371 7.152853 0 0.423363 11.054677 0 0.406704 7.067335 1 0.667394 12.741452 0 -2.460150 6.866805 1 0.569411 9.548755 0 -0.026632 10.427743 0 0.850433 6.920334 1 1.347183 13.175500 0 1.176813 3.167020 1 -1.781871 9.097953 0 -0.566606 5.749003 1 0.931635 1.589505 1 -0.024205 6.151823 1 -0.036453 2.690988 1 -0.196949 0.444165 1 1.014459 5.754399 1 1.985298 3.230619 1 -1.693453 -0.557540 1 -0.576525 11.778922 0 -0.346811 -1.678730 1 -2.124484 2.672471 1 1.217916 9.597015 0 -0.733928 9.098687 0 -3.642001 -1.618087 1 0.315985 3.523953 1 1.416614 9.619232 0 -0.386323 3.989286 1 0.556921 8.294984 1 1.224863 11.587360 0 -1.347803 -2.406051 1 1.196604 4.951851 1 0.275221 9.543647 0 0.470575 9.332488 0 -1.889567 9.542662 0 -1.527893 12.150579 0 -1.185247 11.309318 0 -0.445678 3.297303 1 1.042222 6.105155 1 -0.618787 10.320986 0 1.152083 0.548467 1 0.828534 2.676045 1 -1.237728 10.549033 0 -0.683565 -2.166125 1 0.229456 5.921938 1 -0.959885 11.555336 0 0.492911 10.993324 0 0.184992 8.721488 0 -0.355715 10.325976 0 -0.397822 8.058397 0 0.824839 13.730343 0 1.507278 5.027866 1 0.099671 6.835839 1 -0.344008 10.717485 0 1.785928 7.718645 1 -0.918801 11.560217 0 -0.364009 4.747300 1 -0.841722 4.119083 1 0.490426 1.960539 1 -0.007194 9.075792 0 0.356107 12.447863 0 0.342578 12.281162 0 -0.810823 -1.466018 1 2.530777 6.476801 1 1.296683 11.607559 0 0.475487 12.040035 0 -0.783277 11.009725 0 0.074798 11.023650 0 -1.337472 0.468339 1 -0.102781 13.763651 0 -0.147324 2.874846 1 0.518389 9.887035 0 1.015399 7.571882 0 -1.658086 -0.027255 1 1.319944 2.171228 1 2.056216 5.019981 1 -0.851633 4.375691 1 -1.510047 6.061992 0 -1.076637 -3.181888 1 1.821096 10.283990 0 3.010150 8.401766 1 -1.099458 1.688274 1 -0.834872 -1.733869 1 -0.846637 3.849075 1 1.400102 12.628781 0 1.752842 5.468166 1 0.078557 0.059736 1 0.089392 -0.715300 1 1.825662 12.693808 0 0.197445 9.744638 0 0.126117 0.922311 1 -0.679797 1.220530 1 0.677983 2.556666 1 0.761349 10.693862 0 -2.168791 0.143632 1 1.388610 9.341997 0 0.317029 14.739025 0
下面的博客是某博主利用excel和spss搞的,写的不错
https://www.cnblogs.com/nxld/p/6124235.html?utm_source=itdadao&utm_medium=referral
下面顺便介绍一下过拟合问题
过拟合问题
过拟合即是过分拟合了训练数据,使得模型的复杂度提高,繁华能力较差(对未知数据的预测能力)
下面左图即为欠拟合,中图为合适的拟合,右图为过拟合。
2)过拟合主要原因
过拟合问题往往源自过多的特征
解决方法
1)减少特征数量(减少特征会失去一些信息,即使特征选的很好)
• 可用人工选择要保留的特征;
• 模型选择算法;
2)正则化(特征较多时比较有效)
• 保留所有特征,但减少θ的大小
(3)正则化方法
正则化是结构风险最小化策略的实现,是在经验风险上加一个正则化项或惩罚项。正则化项一般是模型复杂度的单调递增函数,模型越复杂,正则化项就越大。
正则项可以取不同的形式,在回归问题中取平方损失,就是参数的L2范数,也可以取L1范数。取平方损失时,模型的损失函数变为:
lambda是正则项系数:
• 如果它的值很大,说明对模型的复杂度惩罚大,对拟合数据的损失惩罚小,这样它就不会过分拟合数据,在训练数据上的偏差较大,在未知数据上的方差较小,但是可能出现欠拟合的现象;
• 如果它的值很小,说明比较注重对训练数据的拟合,在训练数据上的偏差会小,但是可能会导致过拟合。
正则化后的梯度下降算法θ的更新变为:
在逻辑回归实战中有详细介绍及代码实现,有人看到这篇文章想要的。请加qq:761256405