《机器学习实战》学习笔记(4)—— Logistic 回归

1 Logistic 回归算法描述

工作原理:

为了实现 Logistic 回归分类器,可以在每个特征上都乘以一个回归系数,然后把所有结果的值相加,将这个总和带入 Sigmoid 函数中,进而得到一个范围在 0-1 之间的数值。任何大于0.5的数据被分入1类别,任何小于0.5的数据被分入0类别。Logistic 回归也可以被看成是一种概率估计。


2 梯度上升算法伪代码

(1)梯度上升算法伪代码:

每个回归系数初始化为1
重复R次:
    计算整个数据集的梯度
    使用 alpha*gradient 更新回归系数的向量
    返回回归系数

(2)随机梯度上升算法伪代码:

梯度上升算法在每次更新回归系数时,都需要遍历整个数据集,计算的复杂度太高。一种改进方法是,一次仅用一个样本点来更新回归系数,该方法称为随机梯度上升算法

由于可以在新样本到来时对分类器进行增量式更新,因而随机梯度上升算法是一个在线学习算法。一次处理所有数据被称为是“批处理”。

所有回归系数初始化为1
对数据集中的每个样本:
    计算该样本的梯度
    使用 alpha*gradient 更新回归系数值
返回回归系数

3 Wiki-最小二乘法、最大似然估计、Sigmoid函数、梯度上升法、梯度下降法、缺失值处理

(1)最小二乘法(LSE)

找到一个(组)估计值,使得实际值与估计值的距离最小。本来用两者差的绝对值汇总并使之最小是最理想的,但绝对值在数学上求最小值比较麻烦,因而替代做法是,找一个(组)估计值,使得实际值与估计值之差的平方加总之后的值最小,称为最小二乘。
“二乘”的英文为least square,其实英文的字面意思是“平方最小”。这时,将这个差的平方的和式对参数求导数,并取一阶导数为零,就是OLSE。

这里写图片描述

(2)最大似然估计(MLE)

现在已经拿到了很多个样本(数据集中所有因变量),这些样本值已经实现,最大似然估计就是去找到那个(组)参数估计值,使得前面已经实现的样本值发生概率最大。
因为你手头上的样本已经实现了,其发生概率最大才符合逻辑。这时是求样本所有观测的联合概率最大化,是个连乘积,只要取对数,就变成了线性加总。此时通过对参数求导数,并令一阶导数为零,就可以通过解方程(组),得到最大似然估计值。
利用已知的样本结果,反推最有可能(最大概率)导致这样结果的参数值。

这里写图片描述

(3)Sigmoid 函数

这里写图片描述

(4)梯度上升算法

最大化似然函数,就用梯度上升。

这里写图片描述

(5)梯度下降算法

最小化损失函数,就用梯度下降。

(6)缺失值处理

  1. 使用可用特征的均值来填补缺失值
  2. 使用特殊值来填补缺失值,例如-1
  3. 忽略有缺失值的样本
  4. 使用相似样本的均值填补缺失值
  5. 使用另外的机器学习算法预测缺失值

4 Logistic 回归的优点与缺点

(1)优点

计算代价不高,容易理解和实现

(2)缺点

容易欠拟合,分类精度可能不高


5 Python代码实现

(1)Logistic回归梯度上升优化算法

import numpy as np

def loadDataSet():
    """
    打开文本文件,并逐行读取
    :return:
    """
    # 数据
    dataMat = []

    # 标签
    labelMat = []

    # 打开测试集文本
    fr = open('testSet.txt')

    # 逐行读取
    for line in fr.readlines():
        # 去掉 去读行 首尾 空格 ,并 以 空白 进行拆分
        lineArr = line.strip().split()

        # X0 X1 X2
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])

        # 标签
        labelMat.append(int(lineArr[2]))
    return dataMat, labelMat

def sigmoid(inX):
    """
    sigmoid 函数
    :param inX:
    :return:
    """
    return 1.0/(1 + np.exp(-inX))

# gradient 梯度
# ascent 上升
def gradAscent(dataMatIn, classLabels):
    """

    :param dataMatIn:
    :param classLabels:
    :return:
    """
    # 将 数据集 转换为 numpy 中的 matrix
    dataMatrix = np.mat(dataMatIn)

    # 将 分类标签 集 转换为 numpy 矩阵,并进行 转置(从 行向量 转换为 列向量)
    labelMat = np.mat(classLabels).transpose()

    # 获得 数据矩阵 的 形状
    m, n = np.shape(dataMatrix)

    # 向 目标 移动的步长
    alpha = 0.001

    # 迭代次数
    maxCycles = 500

    # 回归系数 矩阵(列向量) n*1
    weights = np.ones((n, 1))

    for k in range(maxCycles):

        # h 为 列向量,列向量的元素个数为 样本个数
        # m*n 矩阵【点乘】 n*1 矩阵,生成 m*1 矩阵
        h = sigmoid(dataMatrix*weights)

        # 计算 真是类别 与 预测类别 的 差值
        # error 为 误差值的列向量
        error = (labelMat - h)

        # 按照 差值 方向 调整 回归系数
        # dataMatrix.transpose()*error 为 n*m 矩阵 【点乘】 m*1 矩阵 结果为 n*1 矩阵
        weights = weights + alpha*dataMatrix.transpose()*error

    return weights

# result_weight = gradAscent(loadDataSet()[0], loadDataSet()[1])
# print(result_weight)
# print(type(result_weight))

(2)随机梯度上升算法

def stocGradAscent0(dataMatrix, classLabels):
    m,n = shape(dataMatrix)
    alpha = 0.01
    # 1*n 的数组
    weights = ones(n)   #initialize to all ones
    for i in range(m):
        # dataMatrix[i]*weights 为 1*n 的数组 乘以 1*n 的数组,算术运算
        # h 为一个数值
        h = sigmoid(sum(dataMatrix[i]*weights))
        error = classLabels[i] - h
        weights = weights + alpha * error * dataMatrix[i]
    return weights

(3)优化的随机梯度上升算法

# stochastic 随机的
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
    import random

    dataMatrix = np.array(dataMatrix)

    m, n = np.shape(dataMatrix)

    # 行向量
    weights = np.ones(n)

    for j in range(numIter):
        dataIndex = list(range(m))

        for i in range(m):

            # alpha 在每次迭代的时候都会调整,缓解数据波动或者高频波动
            # 随着迭代次数不断减小,但永远不会减小到 0,以此保证新数据仍然具有一定影响
            # 如果处理的问题是动态变化的,那么可以适当加大常数项,以此来确保新的值获得更大的回归系数
            # j 是 迭代次数, i 是 样本点的下标
            alpha = 4/(1.0 + j + i) + 0.01

            # 从 数据集 中 随机选择样本
            randIndex = int(random.uniform(0, len(dataIndex)))

            # 数值
            h = sigmoid(sum(dataMatrix[dataIndex[randIndex]]*weights))

            # 数值
            error = classLabels[dataIndex[randIndex]] - h

            weights = weights + alpha * error * dataMatrix[dataIndex[randIndex]]

            del(dataIndex[randIndex])

    return weights


# result_weight = stocGradAscent1(loadDataSet()[0], loadDataSet()[1])
# print(result_weight)
# plotBestFit(result_weight)

6 示例:从疝气病症预测病马的死亡率

"""
使用 Logistic 回归估计 马伤病死亡率

1、收集数据:
    给定数据文件

2、准备数据:
    用 Python 解析文本并填充缺失值

3、分析数据:
    可视化,并观察数据

4、训练算法:
    使用优化算法,找到最佳的系数

5、测试算法:
    为了量化回归的效果,需要观察错误率。
    根据错误率决定是否回退到训练阶段,通过改变迭代的次数和步长等参数得到更好的回归系数

6、使用算法:
    实现一个简单的命令行程序来收集马的症状并输出预测结果很容易

说明:
    数据集中有 30% 的数据时缺失的

解决数据缺失的方法:

1、使用可用特征的均值来填补缺失值

2、使用特殊值来填补缺失值

3、忽略有缺失值的样本

4、使用相似样本的均值来填补缺失值

5、使用其他的机器学习算法来预测缺失值

"""
from LogisticRegres import *

def classifyVector(inX, weights):
    """

    :param inX: 特征向量
    :param weights: 回归系数
    :return: 分类结果
    """
    prob = sigmoid(sum(inX*weights))
    if prob > 0.5:
        return 1.0
    else:
        return 0.0

def colicTest():
    frTrain = open('horseColicTraining.txt')
    frTest = open('horseColicTest.txt')

    traingingSet = []
    traingingLabels = []
    for line in frTrain.readlines():
        currLine = line.strip().split()
        lineArr = []
        for i in range(21):
            lineArr.append(float(currLine[i]))
        traingingSet.append(lineArr)
        traingingLabels.append(float(currLine[21]))

    traingingWeights = stocGradAscent1(np.array(traingingSet), traingingLabels, 500)

    errorCount = 0

    numTestVec = 0.0

    for line in frTest.readlines():
        numTestVec += 1.0
        currLine = line.strip().split()
        lineArr = []
        for i in range(21):
            lineArr.append(float(currLine[i]))

        if int(classifyVector(np.array(lineArr), traingingWeights)) != int(currLine[21]):
            errorCount += 1

    errorRate = float(errorCount)/numTestVec

    print("the error rate is %f" % errorRate)

    return errorRate

def multiTest():
    numTests = 10
    errorSum = 0.0
    for k in range(numTests):
        errorSum += colicTest()
    print("after {} iterations the average error rate is : {}".format(numTests, errorSum/float(numTests)))

multiTest()

"""
Logistic 回归的目的是寻找一个非线性函数 Sigmoid 的最佳拟合参数,求解过程可以由最优化算法来完成

随机梯度上升算法 与 梯度上升算法 效果相当,但占用更少的计算资源

随机梯度上升算法是一个在线算法,可以在新数据到来时完成参数更新,而不需要重新读取整个数据集来进行运算
"""

7 使用 pandas 和 scikit-learn 实现书上的例子

In [2]:
 
import pandas as pd
import numpy as np
from pandas import Series, DataFrame
np.set_printoptions(precision=4)
×
In [11]:
 
col_names = []
for i in range(21):
    col_names.append('feature_{}'.format(i))
# print(col_list)
train_dataSet_df = pd.read_table('horseColicTraining.txt', names=col_names+['label'])
train_dataSet_df
×
Out[11]:
feature_0feature_1feature_2feature_3feature_4feature_5feature_6feature_7feature_8feature_9feature_12feature_13feature_14feature_15feature_16feature_17feature_18feature_19feature_20label
02.01.038.566.028.03.03.00.02.05.00.00.00.03.05.045.08.40.00.00.0
11.01.039.288.020.00.00.04.01.03.00.00.00.04.02.050.085.02.02.00.0
22.01.038.340.024.01.01.03.01.03.00.00.00.01.01.033.06.70.00.01.0
31.09.039.1164.084.04.01.06.02.02.01.02.05.03.00.048.07.23.05.30.0
42.01.037.3104.035.00.00.06.02.00.00.00.00.00.00.074.07.40.00.00.0
52.01.00.00.00.02.01.03.01.02.02.01.00.03.03.00.00.00.00.01.0
61.01.037.948.016.01.01.01.01.03.01.01.00.03.05.037.07.00.00.01.0
71.01.00.060.00.03.00.00.01.00.02.01.00.03.04.044.08.30.00.00.0
82.01.00.080.036.03.04.03.01.04.02.01.00.03.05.038.06.20.00.00.0
92.09.038.390.00.01.00.01.01.05.02.01.00.03.00.040.06.21.02.21.0
101.01.038.166.012.03.03.05.01.03.02.01.03.02.05.044.06.02.03.61.0
112.01.039.172.052.02.00.02.01.02.01.01.00.04.04.050.07.80.00.01.0
121.01.037.242.012.02.01.01.01.03.03.01.00.04.05.00.07.00.00.01.0
132.09.038.092.028.01.01.02.01.01.03.00.07.21.01.037.06.11.00.00.0
141.01.038.276.028.03.01.01.01.03.02.02.00.04.04.046.081.01.02.01.0
151.01.037.696.048.03.01.04.01.05.02.03.04.54.00.045.06.80.00.00.0
161.09.00.0128.036.03.03.04.02.04.03.00.00.04.05.053.07.83.04.70.0
172.01.037.548.024.00.00.00.00.00.00.00.00.00.00.00.00.00.00.01.0
181.01.037.664.021.01.01.02.01.02.01.01.00.02.05.040.07.01.00.01.0
192.01.039.4110.035.04.03.06.00.00.00.00.00.00.00.055.08.70.00.01.0
201.01.039.972.060.01.01.05.02.05.03.01.00.04.04.046.06.12.00.01.0
212.01.038.448.016.01.00.01.01.01.02.03.05.54.03.049.06.80.00.01.0
221.01.038.642.034.02.01.04.00.02.00.00.00.01.00.048.07.20.00.01.0
231.09.038.3130.060.00.03.00.01.02.00.00.00.00.00.050.070.00.00.01.0
241.01.038.160.012.03.03.03.01.00.03.02.02.00.00.051.065.00.00.01.0
252.01.037.860.042.00.00.00.01.00.00.00.00.00.00.00.00.00.00.01.0
261.01.038.372.030.04.03.03.02.03.02.01.00.03.05.043.07.02.03.91.0
271.01.037.848.012.03.01.01.01.00.01.01.00.01.03.037.05.52.01.31.0
281.01.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.0
292.01.037.748.00.02.01.01.01.01.01.01.00.00.00.045.076.00.00.01.0
2691.01.037.560.050.03.03.01.01.03.02.02.03.53.04.035.06.50.00.00.0
2701.01.037.780.00.03.03.06.01.05.02.03.00.03.01.050.055.03.02.01.0
2711.01.00.0100.030.03.03.04.02.05.03.03.00.04.04.052.06.60.00.01.0
2721.01.037.7120.028.03.03.03.01.05.01.01.00.00.00.065.07.03.00.00.0
2731.01.00.076.00.00.03.00.00.00.00.00.00.00.05.00.00.00.00.00.0
2741.09.038.8150.050.01.03.06.02.05.01.01.00.00.00.050.06.20.00.00.0
2751.01.038.036.016.03.01.01.01.04.03.03.02.03.00.037.075.02.01.00.0
2762.01.036.950.040.02.03.03.01.01.03.01.07.00.00.037.56.50.00.01.0
2772.01.037.840.016.01.01.01.01.01.00.00.00.01.01.037.06.80.00.01.0
2782.01.038.256.040.04.03.01.01.02.02.02.07.50.00.047.07.21.02.51.0
2791.01.038.648.012.00.00.01.00.01.00.00.00.00.00.036.067.00.00.01.0
2802.01.040.078.00.03.03.05.01.02.01.01.00.04.01.066.06.50.00.00.0
2811.01.00.070.016.03.04.05.02.02.02.01.00.04.05.060.07.50.00.00.0
2821.01.038.272.018.00.00.00.00.00.00.00.00.00.00.035.06.40.00.01.0
2832.01.038.554.00.01.01.01.01.03.02.01.00.01.00.040.06.82.07.01.0
2841.01.038.566.024.01.01.01.01.03.02.01.00.04.05.040.06.71.00.01.0
2852.01.037.882.012.03.01.01.02.04.01.03.00.00.00.050.07.00.00.00.0
2862.09.039.584.030.00.00.00.01.00.00.00.00.00.00.028.05.00.00.01.0
2871.01.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.01.0
2881.01.038.050.036.00.01.01.01.03.00.00.00.03.00.039.06.61.05.31.0
2892.01.038.645.016.02.01.02.01.01.00.00.00.01.01.043.058.00.00.01.0
2901.01.038.980.044.03.03.03.01.02.02.02.07.03.01.054.06.53.00.00.0
2911.01.037.066.020.01.03.02.01.04.01.00.00.01.05.035.06.92.00.00.0
2921.01.00.078.024.03.03.03.01.00.02.01.00.00.04.043.062.00.02.00.0
2932.01.038.540.016.01.01.01.01.02.00.00.00.03.02.037.067.00.00.01.0
2941.01.00.0120.070.04.00.04.02.02.00.00.00.00.05.055.065.00.00.00.0
2952.01.037.272.024.03.02.04.02.04.03.01.00.04.04.044.00.03.03.30.0
2961.01.037.572.030.04.03.04.01.04.02.01.00.03.05.060.06.80.00.00.0
2971.01.036.5100.024.03.03.03.01.03.03.01.00.04.04.050.06.03.03.41.0
2981.01.037.240.020.00.00.00.00.00.00.00.00.04.01.036.062.01.01.00.0

299 rows × 22 columns

In [12]:
x
 
test_dataSet_df = pd.read_table('horseColicTest.txt', names=col_names+['label'])
test_dataSet_df
×
Out[12]:
feature_0feature_1feature_2feature_3feature_4feature_5feature_6feature_7feature_8feature_9feature_12feature_13feature_14feature_15feature_16feature_17feature_18feature_19feature_20label
02138.5542001223225.90242.06.300.01
12137.6483600110000.00044.06.315.01
21137.7442804325110.03545.070.032.01
31137.0562431424110.00035.061.032.00
42138.0421230311000.00237.05.800.01
5110.0604030110320.00542.072.000.01
62138.4806032213220.01154.06.900.01
72137.8481221213200.02048.07.310.01
82137.9453633322210.03033.05.730.01
92139.0841231512127.00462.05.922.20
102138.2602431323330.04453.07.521.41
11110.0140000425110.00530.069.000.00
121137.91206033315227.54552.06.631.80
132138.0723611313210.03538.06.822.01
142938.0922811211307.20037.06.111.11
151138.3663023112328.54537.06.000.01
162137.5482431112110.03243.06.012.81
171137.5882023314000.00035.06.410.00
18290.01506044425000.0000.00.000.00
191139.71003000624100.04565.075.000.00
201138.380033425210.04445.07.524.61
212137.5403231313210.00532.06.411.11
221138.4843031524236.54447.07.530.00
231138.1844440425135.00460.06.805.70
242138.752011111000.0134.074.000.01
252138.1444021313000.01335.06.800.01
262138.4522021311210.03541.063.011.01
271138.260010312110.04443.06.223.91
282137.7401811103110.03336.03.500.01
291139.1601001102000.0440.00.000.01
372137.544011113000.00045.05.821.41
382138.2421611311000.01035.060.011.01
392138.0564433300210.04047.070.021.01
402138.3452033222200.0400.00.000.01
41110.0489611310210.01442.08.010.01
421137.7552821212035.0450.00.000.01
432136.01002043622110.04574.05.722.50
441137.1602020413025.03464.08.520.01
452137.11144030322000.00332.00.036.51
461138.1723033314210.03537.056.031.01
471137.0441231121000.04240.06.738.01
481138.6482031114000.03037.075.000.01
49110.0827231412030.04453.065.032.00
501938.2786044603000.01059.05.833.10
512137.8601611312120.03041.073.000.00
521138.7343020312000.00033.069.002.00
53110.0361211111110.01544.00.000.01
542138.3446000110000.0006.436.000.01
552137.4541830113220.04530.07.120.01
56110.00043022000.00054.076.032.01
571136.6481631314110.00027.056.000.00
581138.590011313232.04547.079.000.01
59110.0751211415035.80058.08.510.01
602138.242031111210.03235.05.920.01
611938.2786044603000.01059.05.833.10
622138.6603011314110.00040.06.010.01
632137.8424011111000.03336.06.200.01
641138.0601211212110.01444.065.032.00
652138.0421230311000.00137.05.800.01
662137.6883631113131.50044.06.000.00

67 rows × 22 columns

In [14]:
x
from sklearn.linear_model import LogisticRegression
logistic_reg = LogisticRegression()
×
In [16]:
x
logistic_reg.fit(train_dataSet_df.ix[:, :-1], train_dataSet_df.ix[:, -1])
×
Out[16]:
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
          intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
          penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
          verbose=0, warm_start=False)
In [17]:
xxxxxxxxxx
 
logistic_reg.predict(test_dataSet_df.ix[:, :-1])
×
Out[17]:
array([ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  0.,  1.,  0.,  0.,
        1.,  1.,  1.,  1.,  0.,  0.,  1.,  0.,  1.,  0.,  0.,  1.,  1.,
        1.,  0.,  1.,  1.,  1.,  0.,  0.,  0.,  0.,  0.,  1.,  1.,  1.,
        1.,  1.,  1.,  0.,  0.,  0.,  0.,  1.,  0.,  1.,  0.,  0.,  1.,
        1.,  0.,  1.,  1.,  1.,  1.,  1.,  0.,  1.,  0.,  1.,  1.,  1.,
        1.,  1.])
In [18]:
 
logistic_reg.predict_proba(test_dataSet_df.ix[:, :-1])
×
Out[18]:
array([[ 0.175 ,  0.825 ],
       [ 0.088 ,  0.912 ],
       [ 0.3629,  0.6371],
       [ 0.3702,  0.6298],
       [ 0.4648,  0.5352],
       [ 0.0989,  0.9011],
       [ 0.2272,  0.7728],
       [ 0.2162,  0.7838],
       [ 0.082 ,  0.918 ],
       [ 0.7505,  0.2495],
       [ 0.1831,  0.8169],
       [ 0.8869,  0.1131],
       [ 0.844 ,  0.156 ],
       [ 0.4586,  0.5414],
       [ 0.1879,  0.8121],
       [ 0.3058,  0.6942],
       [ 0.2214,  0.7786],
       [ 0.7102,  0.2898],
       [ 0.9123,  0.0877],
       [ 0.443 ,  0.557 ],
       [ 0.7109,  0.2891],
       [ 0.3688,  0.6312],
       [ 0.7929,  0.2071],
       [ 0.9282,  0.0718],
       [ 0.0656,  0.9344],
       [ 0.2568,  0.7432],
       [ 0.0797,  0.9203],
       [ 0.5667,  0.4333],
       [ 0.1443,  0.8557],
       [ 0.188 ,  0.812 ],
       [ 0.0726,  0.9274],
       [ 0.9156,  0.0844],
       [ 0.8757,  0.1243],
       [ 0.5044,  0.4956],
       [ 0.8525,  0.1475],
       [ 0.5457,  0.4543],
       [ 0.3535,  0.6465],
       [ 0.2268,  0.7732],
       [ 0.0804,  0.9196],
       [ 0.055 ,  0.945 ],
       [ 0.039 ,  0.961 ],
       [ 0.1589,  0.8411],
       [ 0.5845,  0.4155],
       [ 0.6948,  0.3052],
       [ 0.9126,  0.0874],
       [ 0.7312,  0.2688],
       [ 0.3331,  0.6669],
       [ 0.5374,  0.4626],
       [ 0.1555,  0.8445],
       [ 0.7095,  0.2905],
       [ 0.8362,  0.1638],
       [ 0.0734,  0.9266],
       [ 0.1559,  0.8441],
       [ 0.5269,  0.4731],
       [ 0.0674,  0.9326],
       [ 0.1093,  0.8907],
       [ 0.227 ,  0.773 ],
       [ 0.4529,  0.5471],
       [ 0.3762,  0.6238],
       [ 0.9505,  0.0495],
       [ 0.1314,  0.8686],
       [ 0.8362,  0.1638],
       [ 0.3192,  0.6808],
       [ 0.0816,  0.9184],
       [ 0.3924,  0.6076],
       [ 0.3461,  0.6539],
       [ 0.3246,  0.6754]])
In [20]:
 
logistic_reg.score(test_dataSet_df.ix[:, :-1], test_dataSet_df.ix[:, -1])
×
Out[20]:
0.73134328358208955
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值