diff --git a/src/python/5.Logistic/logistic.py b/src/python/5.Logistic/logistic.py index af834873..c8e85021 100644 --- a/src/python/5.Logistic/logistic.py +++ b/src/python/5.Logistic/logistic.py @@ -19,7 +19,7 @@ def loadDataSet(file_name): fr = open(file_name) for line in fr.readlines(): lineArr = line.strip().split() - # 将 X0 的值设为 1.0 + # 为了方便计算,我们将 X0 的值设为 1.0 ,也就是在每一行的开头添加一个 1.0 作为 X0 dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) labelMat.append(int(lineArr[2])) return dataMat,labelMat @@ -57,6 +57,7 @@ def gradAscent(dataMatIn, classLabels): # print 'weights====', weights # n*3 * 3*1 = n*1 h = sigmoid(dataMatrix*weights) # 矩阵乘法 + # print 'hhhhhhh====', h # labelMat是实际值 error = (labelMat - h) # 向量相减 # 0.001* (3*m)*(m*1) 表示在每一个列上的一个误差情况,最后得出 x1,x2,xn的系数的偏移量 @@ -110,6 +111,17 @@ def stocGradAscent1(dataMatrix, classLabels, numIter=150): # 可视化展示 def plotBestFit(dataArr, labelMat, weights): + ''' + Desc: + 将我们得到的数据可视化展示出来 + Args: + dataArr:样本数据的特征 + labelMat:样本数据的类别标签,即目标变量 + weights:回归系数 + Returns: + None + ''' + n = shape(dataArr)[0] xcord1 = []; ycord1 = [] xcord2 = []; ycord2 = [] @@ -146,8 +158,8 @@ def main(): # 因为数组没有是复制n份, array的乘法就是乘法 dataArr = array(dataMat) # print dataArr - # weights = gradAscent(dataArr, labelMat) - weights = stocGradAscent0(dataArr, labelMat) + weights = gradAscent(dataArr, labelMat) + # weights = stocGradAscent0(dataArr, labelMat) # weights = stocGradAscent1(dataArr, labelMat) # print '*'*30, weights diff --git a/src/python/5.Logistic/sklearn_logisticRegression_demo.py b/src/python/5.Logistic/sklearn_logisticRegression_demo.py index d56c6556..12a712e2 100644 --- a/src/python/5.Logistic/sklearn_logisticRegression_demo.py +++ b/src/python/5.Logistic/sklearn_logisticRegression_demo.py @@ -182,7 +182,6 @@ plt.show() # Logistic Regression 3-class Classifier 逻辑回归 3-类 分类器 -''' print(__doc__) import numpy as np @@ -224,11 +223,11 @@ plt.xticks(()) plt.yticks(()) plt.show() -''' # Logistic function 逻辑回归函数 # 这个类似于咱们之前讲解 logistic 回归的 Sigmoid 函数,模拟的阶跃函数 +''' print(__doc__) import numpy as np @@ -276,5 +275,7 @@ plt.xlim(-4, 10) plt.legend(('Logistic Regression Model', 'Linear Regression Model'), loc="lower right", fontsize='small') plt.show() +''' + diff --git a/src/python/8.Predictive numerical data regression/regression.py b/src/python/8.Predictive numerical data regression/regression.py index 742ee08b..59304c5a 100644 --- a/src/python/8.Predictive numerical data regression/regression.py +++ b/src/python/8.Predictive numerical data regression/regression.py @@ -48,7 +48,7 @@ def standRegres(xArr,yArr): xArr :输入的样本数据,包含每个样本数据的 feature yArr :对应于输入数据的类别标签,也就是每个样本对应的目标变量 Returns: - + ws:回归系数 ''' # mat()函数将xArr,yArr转换为矩阵 mat().T 代表的是对矩阵进行转置操作 @@ -71,67 +71,155 @@ def standRegres(xArr,yArr): def lwlr(testPoint,xArr,yArr,k=1.0): ''' Description: - 局部加权线性回归 + 局部加权线性回归,在待预测点附近的每个点赋予一定的权重,在子集上基于最小均方差来进行普通的回归。 Args: - testPoint: - xArr: - yArr: - k: + testPoint:样本点 + xArr:样本的特征数据,即 feature + yArr:每个样本对应的类别标签,即目标变量 + k:关于赋予权重矩阵的核的一个参数,与权重的衰减速率有关 Returns: - + testPoint * ws:数据点与具有权重的系数相乘得到的预测点 + Notes: + 这其中会用到计算权重的公式,w = e^((x^((i))-x) / -2k^2) + 理解:x为某个预测点,x^((i))为样本点,样本点距离预测点越近,贡献的误差越大(权值越大),越远则贡献的误差越小(权值越小)。 + 关于预测点的选取,在我的代码中取的是样本点。其中k是带宽参数,控制w(钟形函数)的宽窄程度,类似于高斯函数的标准差。 + 算法思路:假设预测点取样本点中的第i个样本点(共m个样本点),遍历1到m个样本点(含第i个),算出每一个样本点与预测点的距离, + 也就可以计算出每个样本贡献误差的权值,可以看出w是一个有m个元素的向量(写成对角阵形式)。 ''' - xMat = mat(xArr); yMat = mat(yArr).T - m = shape(xMat)[0] # 获得xMat矩阵的行数 - weights = mat(eye((m))) # eye()返回一个对角线元素为1,其他元素为0的二维数组,创建权重矩阵 - for j in range(m): # 下面两行创建权重矩阵 - diffMat = testPoint - xMat[j,:] # 遍历数据集,计算每个样本点对应的权重值 - weights[j,j] = exp(diffMat*diffMat.T/(-2.0*k**2))#k控制衰减的速度 + # mat() 函数是将array转换为矩阵的函数, mat().T 是转换为矩阵之后,再进行转置操作 + xMat = mat(xArr) + yMat = mat(yArr).T + # 获得xMat矩阵的行数 + m = shape(xMat)[0] + # eye()返回一个对角线元素为1,其他元素为0的二维数组,创建权重矩阵weights,该矩阵为每个样本点初始化了一个权重 + weights = mat(eye((m))) + for j in range(m): + # testPoint 的形式是 一个行向量的形式 + # 计算 testPoint 与输入样本点之间的距离,然后下面计算出每个样本贡献误差的权值 + diffMat = testPoint - xMat[j,:] + # k控制衰减的速度 + weights[j,j] = exp(diffMat*diffMat.T/(-2.0*k**2)) + # 根据矩阵乘法计算 xTx ,其中的 weights 矩阵是样本点对应的权重矩阵 xTx = xMat.T * (weights * xMat) if linalg.det(xTx) == 0.0: print ("This matrix is singular, cannot do inverse") return - ws = xTx.I * (xMat.T * (weights * yMat)) # 计算出回归系数的一个估计 + # 计算出回归系数的一个估计 + ws = xTx.I * (xMat.T * (weights * yMat)) return testPoint * ws -def lwlrTest(testArr,xArr,yArr,k=1.0): # 循环所有的数据点,并将lwlr运用于所有的数据点 +def lwlrTest(testArr,xArr,yArr,k=1.0): + ''' + Description: + 测试局部加权线性回归,对数据集中每个点调用 lwlr() 函数 + Args: + testArr:测试所用的所有样本点 + xArr:样本的特征数据,即 feature + yArr:每个样本对应的类别标签,即目标变量 + k:控制核函数的衰减速率 + Returns: + yHat:预测点的估计值 + ''' + # 得到样本点的总数 m = shape(testArr)[0] + # 构建一个全部都是 0 的 1 * m 的矩阵 yHat = zeros(m) + # 循环所有的数据点,并将lwlr运用于所有的数据点 for i in range(m): yHat[i] = lwlr(testArr[i],xArr,yArr,k) + # 返回估计值 return yHat -def lwlrTestPlot(xArr,yArr,k=1.0): # 首先将 X 排序,其余的都与lwlrTest相同,这样更容易绘图 - yHat = zeros(shape(yArr)) +def lwlrTestPlot(xArr,yArr,k=1.0): + ''' + Description: + 首先将 X 排序,其余的都与lwlrTest相同,这样更容易绘图 + Args: + xArr:样本的特征数据,即 feature + yArr:每个样本对应的类别标签,即目标变量,实际值 + k:控制核函数的衰减速率的有关参数,这里设定的是常量值 1 + Return: + yHat:样本点的估计值 + xCopy:xArr的复制 + ''' + # 生成一个与目标变量数目相同的 0 向量 + yHat = zeros(shape(yArr)) + # 将 xArr 转换为 矩阵形式 xCopy = mat(xArr) + # 排序 xCopy.sort(0) + # 开始循环,为每个样本点进行局部加权线性回归,得到最终的目标变量估计值 for i in range(shape(xArr)[0]): yHat[i] = lwlr(xCopy[i],xArr,yArr,k) return yHat,xCopy -def rssError(yArr,yHatArr): # yArr 和 yHatArr 两者都需要是数组 +def rssError(yArr,yHatArr): + ''' + Desc: + 计算分析预测误差的大小 + Args: + yArr:真实的目标变量 + yHatArr:预测得到的估计值 + Returns: + 计算真实值和估计值得到的值的平方和作为最后的返回值 + ''' return ((yArr-yHatArr)**2).sum() -def ridgeRegres(xMat,yMat,lam=0.2): # 岭回归 +def ridgeRegres(xMat,yMat,lam=0.2): + ''' + Desc: + 这个函数实现了给定 lambda 下的岭回归求解。 + 如果数据的特征比样本点还多,就不能再使用上面介绍的的线性回归和局部现行回归了,因为计算 (xTx)^(-1)会出现错误。 + 如果特征比样本点还多(n > m),也就是说,输入数据的矩阵x不是满秩矩阵。非满秩矩阵在求逆时会出现问题。 + 为了解决这个问题,我们下边讲一下:岭回归,这是我们要讲的第一种缩减方法。 + Args: + xMat:样本的特征数据,即 feature + yMat:每个样本对应的类别标签,即目标变量,实际值 + lam:引入的一个λ值,使得矩阵非奇异 + Returns: + 经过岭回归公式计算得到的回归系数 + ''' + xTx = xMat.T*xMat - denom = xTx + eye(shape(xMat)[1])*lam # 按照书上的公式计算计算回归系数 - if linalg.det(denom) == 0.0: # 检查行列式是否为零,即矩阵是否可逆 + # 岭回归就是在矩阵 xTx 上加一个 λI 从而使得矩阵非奇异,进而能对 xTx + λI 求逆 + denom = xTx + eye(shape(xMat)[1])*lam + # 检查行列式是否为零,即矩阵是否可逆,行列式为0的话就不可逆,不为0的话就是可逆。 + if linalg.det(denom) == 0.0: print ("This matrix is singular, cannot do inverse") return ws = denom.I * (xMat.T*yMat) return ws def ridgeTest(xArr,yArr): - xMat = mat(xArr); yMat=mat(yArr).T - yMean = mean(yMat,0) # 计算Y均值 - yMat = yMat - yMean # Y的所有的特征减去均值 - # 标准化 x - xMeans = mean(xMat,0) # X计算平均值 - xVar = var(xMat,0) # 然后计算 X的方差 + ''' + Desc: + 函数 ridgeTest() 用于在一组 λ 上测试结果 + Args: + xArr:样本数据的特征,即 feature + yArr:样本数据的类别标签,即真实数据 + Returns: + wMat:将所有的回归系数输出到一个矩阵并返回 + ''' + + xMat = mat(xArr) + yMat=mat(yArr).T + # 计算Y的均值 + yMean = mean(yMat,0) + # Y的所有的特征减去均值 + yMat = yMat - yMean + # 标准化 x,计算 xMat 平均值 + xMeans = mean(xMat,0) + # 然后计算 X的方差 + xVar = var(xMat,0) + # 所有特征都减去各自的均值并除以方差 xMat = (xMat - xMeans)/xVar + # 可以在 30 个不同的 lambda 下调用 ridgeRegres() 函数。 numTestPts = 30 - wMat = zeros((numTestPts,shape(xMat)[1]))# 创建30 * m 的全部数据为0 的矩阵 + # 创建30 * m 的全部数据为0 的矩阵 + wMat = zeros((numTestPts,shape(xMat)[1])) for i in range(numTestPts): - ws = ridgeRegres(xMat,yMat,exp(i-10))# exp返回e^x + # exp() 返回 e^x + ws = ridgeRegres(xMat,yMat,exp(i-10)) wMat[i,:]=ws.T return wMat