第5章 Logistic回归

1 引言

Logistic 是在回归的基础上进行分类(二分类),试想在二维平面上,是不是可以用一条直线把数据点分开呢(如果这条直线存在的话)?假如直线存在,在这条直线上的点为0,这条直线两侧的点,对于这条直线一侧大于0,一侧小于0,这就是进行了分类,现在呢,我们引入 sigmoid 函数,用来进一步转化为概率问题,sigmoid 函数如下所示


sigmoid函数

2 Sample Code

2.1 部分数据集如下,共计 100行3列,前两列为feature,最后一列为label
import numpy as np

# 从文本中读取数据集
def loadDataSet():
    x = []
    y = []
    fr = open(r'E:\tensorflow\Ch05\testSet.txt')
    for line in fr.readlines():
        # line.strip() 截取掉所有回车字符(即每行最后一个字符)
        # split(str="")  str - 分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等分隔
        line_x = line.strip().split()
        # 此处第一列的 1,即为biases
        x.append([1.0, float(line_x[0]), float(line_x[1])])
        y.append([int(line_x[2])])
    return np.mat(x),np.mat(y)
# 测试 loadDataSet
x,y = loadDataSet()
print(x.shape)   # (100,3)
print(y.shape)   # (100,1)
# 读进数据集之后,现在让我们来以图像化显示一下数据集
def plotFigure():
    x, y = loadDataSet()
    xarr = np.array(x)
    n = np.shape(x)[0]
    x1 = []; y1 = []
    x2 = []; y2 = []
    for i in np.arange(n):
        if int(y[i]) == 1:
            x1.append(xarr[i,1]); y1.append(xarr[i,2])
        else:
            x2.append(xarr[i,1]); y2.append(xarr[i,2])
    
    fig = plt.figure()
    ax = fig.add_subplot(1,1,1)
    # scatter 画出散点图
    ax.scatter(x1, y1, s = 30, c = 'r', marker = 's')
    ax.scatter(x2, y2, s = 30, c = 'g')
    plt.show()

# 画图
plotFigure()
  • 数据集以图像化显示如上所示,现在我们就要来对它进行分类了(二分类问题)。也就是找到一条直线来使不同类别数据分开。
2.2 辅助函数
# 定义 sigmoid 函数
def sigmoid(x):
    return 1.0 / (1 + np.exp(- x))
print(sigmoid(0)) #  输出 0.5 验证通过
# 画出决策边界
# 用此函数来画出三种梯度上升算法的分类直线
import matplotlib.pyplot as plt

def plotBestFit(weights):
    x, y = loadDataSet()
    xarr = np.array(x)
    n = np.shape(x)[0]
    x1 = []; y1 = []
    x2 = []; y2 = []
    for i in np.arange(n):
        if int(y[i]) == 1:
            x1.append(xarr[i,1]); y1.append(xarr[i,2])
        else:
            x2.append(xarr[i,1]); y2.append(xarr[i,2])
    
    fig = plt.figure()
    ax = fig.add_subplot(1,1,1)
    # scatter 画出散点图
    ax.scatter(x1, y1, s = 30, c = 'r', marker = 's')
    ax.scatter(x2, y2, s = 30, c = 'g')
    
    # 画出Logistic 分类直线
    a = np.arange(-3.0, 3.0, 0.1) # (60,)
    # 由分类直线 weights[0] + weights[1] * a + weights[2] * b = 0 易得下式
    b = (-weights[0] - weights[1] * a) / weights[2]
    # print(b.shape)   # (1, 60)
    # print(b.T.shape) # (60, 1)
    ax.plot(a, b.T)
    plt.title('BestFit')
    plt.xlabel('x1')
    plt.ylabel('x2')
    plt.show()
2.3 梯度上升算法

本文所使用的优化方法为 梯度上升算法,又逐步优化实现了 批量梯度上升算法,随机梯度上升算法,改进的随机梯度上升算法,并比较了三种优化方法的优越性。

2.3.1 批量梯度上升算法
# 批量梯度上升优化算法
def gradAscent(x, y):
    m, n = np.shape(x) # 100 3
    alpha = 0.001
    maxCycle = 500
    weights = np.ones((n, 1))  # 3行1列
    for k in np.arange(maxCycle):
        h = sigmoid(x * weights)
        error = y - h
        weights = weights + alpha * x.T * error  # 详细推导过程见参考      
    return weights # (3, 1)
x,y = loadDataSet()
weights = gradAscent(x, y)
print(weights)
    # [[ 4.12414349]
    #  [ 0.48007329]
    #  [-0.6168482 ]]
plotBestFit(weights)
2.3.2 随机梯度上升算法
# 随机梯度上升算法
def randgradAscent(x, y):
    m, n = np.shape(x) # 100 3
    alpha = 0.01
    weights = np.ones(n) #(3,)  [1. 1. 1.]
    for i in np.arange(m):
        h = sigmoid(np.sum(x[i] * weights))
        error = y[i] - h
        weights = weights + alpha * error * x[i]
    return (np.mat(weights)).T
x,y = loadDataSet()
weights = randgradAscent(np.array(x), np.array(y))
print(weights)
        # [[ 1.01702007]
        #  [ 0.85914348]
        #  [-0.36579921]]
# 画出决策边界
plotBestFit(weights)
2.3.3 改进的随机梯度上升算法
# 改进的随机梯度上升算法
def randgradAscent1(x, y, cycle = 150):
    m, n = np.shape(x) # 100 3
    weights = np.ones(n) # (3,) [1. 1. 1.]
    # 循环 150 次
    for j in np.arange(cycle):
        dataindex = np.arange(m) # 100
        # 在 150 次之内,每一次又循环 100 次
        for i in np.arange(m):
            # 定义学习率,随着 i,j 的增大,学习率越来越小,0.01保证学习率永远不为0
            alpha = 4 / (1.0 + j + i) + 0.01
            # 从 0 - len(dataindex) 中随机取出一个数
            randindex = int(np.random.uniform(0, len(dataindex)))
            # 预测类别的概率
            h = sigmoid(np.sum(x[randindex] * weights))
            # 误差
            error = y[randindex] - h
            # 梯度上升更新权重
            weights = weights + alpha * error * x[randindex]
            # dataindex 原来为 array ,转化为 list
            dataindex = dataindex.tolist()
            # 删除已取出的数
            del(dataindex[randindex])
            # dataindex 再次转化为 array
            dataindex = np.array(dataindex)
    # 注意,此处开始创建 weights 的shape为 (3,) ,现在把weight转化为matrix类型,再者转置,化为 (3, 1)
    return np.mat(weights).T
x,y = loadDataSet()
weights = randgradAscent1(np.array(x), np.array(y))
print(weights)
        # [[14.7744613 ]
        #  [ 0.93062723]
        #  [-2.03935598]]
# 画出决策边界
plotBestFit(weights)

3 实战: 从疝气病症预测病马的死亡率

# 预测类别
def classifyVector(x, weights):
    prob = sigmoid(np.sum(x * weights))
    if prob > 0.5:
        return 1.0
    else:
        return 0.0
# 读取文件
def colicTest():
    # 读取训练集
    frTrain = open(r'E:\tensorflow\Ch05\horseColicTraining.txt')
    # 读取测试集
    frTest = open(r'E:\tensorflow\Ch05\horseColicTest.txt')
    
    # 定义存放 feature 和 label 的容器
    trainingSet = []; trainingLabels = []
    # 一次取文本中的一行
    # 一行共计 22 列,前 21 列为 feature, 最后一列为 label
    for line in frTrain.readlines():
        currLine = line.strip().split('\t')
        lineArr = []
        for i in np.arange(21):
            lineArr.append(float(currLine[i]))
        trainingSet.append(lineArr)
        trainingLabels.append(float(currLine[21]))
    
    # 调用改进的随机梯度上升算法计算权重
    trainWeights = randgradAscent1(np.array(trainingSet), np.array(trainingLabels), 500)
    
    # 测试
    # 一行共计 22 列,前 21 列为 feature, 最后一列为 label
    # 测试错误计数
    errorCount = 0
    # 测试集总共样本数
    numTestVec = 0.0
    # 一次取出一行
    for line in frTest.readlines():
        # 测试集样本计数
        numTestVec += 1.0
        currLine = line.strip().split('\t')
        lineArr = []
        for i in np.arange(21):
            lineArr.append(float(currLine[i]))
        # 若预测和真实类别不符合,则错误计数加 1
        if int(classifyVector(np.array(lineArr), trainWeights) != int(currLine[21])):
            errorCount += 1
    
    # 计数这一次的错误率
    errorRate = (float(errorCount) / numTestVec)
    print("the error rate of this test is: %f" % errorRate )
    return errorRate
# 主函数
def multiTest():
    # 共计测试 10 次,即测试集读取10次,每次算出错误率,最后算出平均错误率
    numTests = 10
    # 10 次中,每一次的错误率
    errorSum = 0.0
    for k in np.arange(numTests):
        errorSum += colicTest()
    print("after %d iterations the average error rate is: %f" %(numTests, errorSum / float(numTests)))
# 开始运行,进行分类
multiTest()

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容