线性回归与逻辑回归

一、线性回归

问题概述

线性回归要解决的问题是给一堆样本点X(m, n)和每个点对应的函数值Y(m,1)要求找到一个线性函数 y=w1x1+w2x2+...+wnxn+b y = w 1 ∗ x 1 + w 2 ∗ x 2 + . . . + w n ∗ x n + b 使得其对原样本点的拟合度最好。拟合度最好就是每个样本点到这条直线的距离和最小,转化成数学语言就是使得误差函数 J(y^,y)=1/2(y^y)2=1/2(wTx+by)2 J ( y ^ , y ) = 1 / 2 ∗ ( y ^ − y ) 2 = 1 / 2 ∗ ( w T x + b − y ) 2 最小,选平方函数消除误差的正负情况。

公式推导及实现

令误差函数对两参数的倒数分别为0,即可得出其表达式。但最后 θ(w,b)=(XTX)1XTY θ ( w , b ) = ( X T X ) − 1 X T Y 高维矩阵的逆不易算,而且存在矩阵不可逆的情况。实现上往往采用梯度下降法: θ=θαJ(w,b)θ θ = θ − α ∂ J ( w , b ) ∂ θ ,下面做个简单的示例。首先统一样本及标签矩阵的格式如下:

样本特征矩阵是 n×m 的,其中 n 是每个样本的特征数,m是样本个数。标签y为 1×m 的行向量。按此格式生成100个样本点:

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

def generate_data():
    x = np.linspace(-2, 2, 100).reshape(100, 1)
    y = -3 * x + 7 + (np.random.rand(100, 1) - 0.5)
    return x, y

x, y = generate_data()
x = x.T
y = y.T

print(x.shape,)
print(y.shape,)

((1, 100),)
((1, 100),)

拟合函数为 y=3x+7 y = − 3 ∗ x + 7 ,每个样本点加一个噪声。作图如下:

plt.figure(figsize=(12, 8))

plt.scatter(x.T, y.T, c= 'y')
plt.plot(x.T, (-3 * x + 7).T, c='b', linewidth=2)
plt.show()

接下来就用梯度下降法得到使得误差函数最小的 w,b w , b 。参数更新公式推导: J(y^,y)=1/2(y^y)2 J ( y ^ , y ) = 1 / 2 ∗ ( y ^ − y ) 2

J(w,b)w=J(w,b)y^y^w=(y^y)x ∂ J ( w , b ) ∂ w = ∂ J ( w , b ) ∂ y ^ ∗ ∂ y ^ ∂ w = ( y ^ − y ) ∗ x

J(w,b)b=(y^y) ∂ J ( w , b ) ∂ b = ( y ^ − y )

def GDparalearning (x, y,m, iterations = 1000):

    #初始化学习率a和系数w,b
    a = 0.05
    w = 1
    b = 1
    for i in range(iterations):
      #计算预测值
      z = w * x + b
      dz = z - y
      #计算误差
      loss = dz.dot(dz.T).sum()/2.0
      #更新参数
      w = w - a * 1.0/m * x.dot(dz.T) #x为向量不能用.mean(),否则变为一个数
      b = b - a * dz.mean()

    return w, b

测试与作图:

w, b = GDparalearning(x, y100)
print (w, b)
predict = w.T.dot(x) + b
#计算真实值与预测值的相关系数
print (np.corrcoef(y, predict))


plt.figure(figsize=(12, 8))
plt.scatter(x, y, c= 'y')
plt.plot(x.T, (-3 * x + 7).T, c='b', linewidth=2)
plt.plot(x.T, predict.T, c='r', linewidth=2)
plt.show()

(array([[-3.00567058]]), 6.980861739959656)
[[1. , 0.99666187]
[0.99666187 , 1. ]]

两条线基本吻合。

二、逻辑回归

问题概述

逻辑回归主要用来处理二分类问题,给样本点x,输出其标签为正或负的概率。

本来分类的是线性函数,但概率的取值范围是[0, 1]故套一层sigmod函数

同样要得到参数w,b就需要定义损失函数,此处不再用平方函数,因为这会使损失函数非凸从而存在很多局部最小值。单个样本的损失函数为: J(w,b)=(ylogy^+(1y)log(1y^)) J ( w , b ) = − ( y ∗ l o g y ^ + ( 1 − y ) ∗ l o g ( 1 − y ^ ) ) 总的代价函数即为每个样本的损失函数的和取平均。

这个损失函数也不是凭空编出来的,其背后的原理在概率论中。将概率函数p(y|x)的分段表达统一起来就是 p(y|x)=y^y(1y^)(1y) p ( y | x ) = y ^ y ∗ ( 1 − y ^ ) ( 1 − y ) 意义是:给定样本点x的条件下,其标签为y的概率是用sigmod函数计算出来的值

假定这些样本独立同分布,则所有样本的联合概率就是每个样本概率的乘积。然后对它做最大似然估计,即找到一组参数使得给定样本的观测值最大

为了去掉连乘对其取对数,算极大似然就是算代价函数最小,故定义总的代价函数时去掉前面的负号,最后对代价函数缩放加因子1/m。

公式推导及实现

样本采用同线性回归一样的格式:n为特征数,m为样本数

  • x : 训练样本特征(n,m)
  • y : 训练样本标签(1,m)
  • w: 线性参数向量(n,1)

用上面推出的代价函数 J(w,b)=(ylogy^+(1y)log(1y^)) J ( w , b ) = − ( y ∗ l o g y ^ + ( 1 − y ) ∗ l o g ( 1 − y ^ ) ) 分别对两参数求导。首先
z=wTx+b z = w T x + b
y^=σ(wTx+b)=σ(z) y ^ = σ ( w T x + b ) = σ ( z )
σ(z)=11+ez σ ( z ) = 1 1 + e − z
J(w,b)=(YlogY^+(1Y)log(1Y^)) J ( w , b ) = − ( Y ∗ l o g Y ^ + ( 1 − Y ) ∗ l o g ( 1 − Y ^ ) )
分别求导:

J(w,b)z=J(w,b)y^y^z=(yy^+1y1y^)y^(1y^)=(y^y) ∂ J ( w , b ) ∂ z = ∂ J ( w , b ) ∂ y ^ ∗ ∂ y ^ ∂ z = ( − y y ^ + 1 − y 1 − y ^ ) ∗ y ^ ( 1 − y ^ ) = ( y ^ − y )

J(w,b)w=J(w,b)zzw=(y^y)x=1/mx(y^y)T ∂ J ( w , b ) ∂ w = ∂ J ( w , b ) ∂ z ∗ ∂ z ∂ w = ( y ^ − y ) ∗ x = 1 / m ∗ x ∗ ( y ^ − y ) T

J(w,b)b=J(w,b)zzb=(y^y)=1/mnp.sum(y^y)T ∂ J ( w , b ) ∂ b = ∂ J ( w , b ) ∂ z ∗ ∂ z ∂ b = ( y ^ − y ) = 1 / m ∗ n p . s u m ( y ^ − y ) T

更新公式已经出来了,下面用梯度下降算法训练。首先构造数据集

from numpy import *  
import matplotlib.pyplot as plt  
import time  

def loadData():  
    train_x = []  
    train_y = []  
    fileIn = open('testSet.txt')  
    for line in fileIn.readlines():  
        lineArr = line.strip().split()  
        train_x.append([float(lineArr[0]), float(lineArr[1])])  
        train_y.append(float(lineArr[2]))  
    return np.array(train_x).T  , np.array(train_y)

x, y = loadData()
print x.shape, y.shape

(2, 100) (100,)
然后是sigmoid函数和梯度下降算法模型

import numpy as np  
import matplotlib.pyplot as plt  
import time  

def sigmoid(x):  
    return 1.0 / (1 + exp(-x))  

def GDlogistic(x, y, m, iterations = 50000):
    w = np.ones(2).reshape(2, 1)
    b = 1
    a = 0.05
    for i in range(iterations):
        z = sigmoid(w.T.dot(x) + b)
        dz = z - y
        w = w - a * 1.0/m * x.dot(dz.T) 
        b = b - a * 1.0/m * np.sum(dz)

    return w, b

测试

w, b = GDlogistic(x, y, 100)
print w, b
predict = sigmoid(w.T.dot(x) + b)
print (np.corrcoef(y, predict))

[[ 1.16239039]
[-1.82522712]] 13.4202362998
[[ 1. , 0.93775995]

精度达到93%,可视化

plt.figure(figsize=(12, 8))
#print y.shape
for i in xrange(100):  
        if int(y[i]) == 0:  
            plt.plot(x.T[i, 0], x.T[i, 1], 'or')  
        elif int(y[i]) == 1:  
            plt.plot(x.T[i, 0], x.T[i, 1], 'ob')

min_x = min(x.T[:, 0]) 
max_x = max(x.T[:, 0]) 

y_min_x = float(-b - w[0] * min_x) / w[1]  
y_max_x = float(-b - w[0] * max_x) / w[1]  
plt.plot([min_x, max_x], [y_min_x, y_max_x], '-g')  
plt.xlabel('X1'); plt.ylabel('X2')  
plt.show()

总结

以上是分别对线性回归与逻辑回归的数学分析和实现,两者一个用于回归一个用于分类,应属于完全不同的算法,但本质上又存在联系。实际上,逻辑回归是对样本正负概率比值的预测,也就是说它预测的是正负样本的分类面。
p=11+ewTx p = 1 1 + e − w T x
lnp1p=wTx l n p 1 − p = w T x
这两个式子可以清晰地看出两者的联系:

  • wTx<0 w T x < 0 时 p < 0.5,且值越小p越接近0
  • wTx>0 w T x > 0 时 p > 0.5,且值越大p越接近1
  • wTx=0 w T x = 0 时,恰好是非负非正,即分类面

你可能感兴趣的:(machine,learning)