本文主要实现非线性可分数据的逻辑回归,包括特征映射,正则化等

  • 原数据

原数据是关于是由2个特征和一个标签字段组成的资料,如果需要数据可以来“三行科创”微信公众号交流群索要。

机器学习——逻辑回归正则_机器学习

  • 数据可视化

看看原数据有什么特点

import numpy as np 
import pandas as pd
import matplotlib.pyplot as plt
data = pd.read_csv("CourseraML/ex2/data/ex2data2.txt", header = None, names = ["x1", "x2", "label"]) #读取数据
X = np.array(data[["x1", "x2"]]) #特征
y = np.array(data["label"]) #标签
X = np.insert(X, 0, 1, axis =1) #多插入虚拟列
m = len(X) #样本数
pos = np.array([X[i,:] for i in range(len(X)) if y[i]==1] ) #postive 特征
neg = np.array([X[i,:] for i in range(len(X)) if y[i] ==0]) #negative 特征

def dataPlot(): #定义数据可视化函数
#plt.figure(figsize = (6,4))
plt.plot(pos[:,1], pos[:,2], "+", color = "orange", label = "positive")
plt.plot(neg[:, 1], neg[:,2], "x", color = "red", label = "negative")
plt.xlabel("x1")
plt.ylabel("x2")
plt.title("Scatter plot")
plt.legend()

dataPlot()

机器学习——逻辑回归正则_机器学习_02

从数据散点分布图可以看到正性样本主要分布在中间,负性样本主要分布在周边,没办法用一条直线来分离,故需要做特征映射

  • 特征映射

原始特征只有 x 1 , x 2 x_1,x_2 x1​,x2​可以用多项式创建更多的特征 x 1 、 x 2 、 x 1 x 2 、 x 1 2 、 x 2 2 、 x 1 2 x 2 、 . . . 、 x 1 n x 2 n x_1、x_2、x_1x_2、x_1^2、x_2^2、x_1^2x_2、... 、x_1^nx_2^n x1​、x2​、x1​x2​、x12​、x22​、x12​x2​、...、x1n​x2n​来刻画,因为更多的特征进行逻辑回归时,得到的分割线可以是任意高阶函数的形状

def featureMap(x1col, x2col): #定义特征映射函数 非线性变换,变成线性可分的
power = 6
out = np.ones((x1col.shape[0], 1))
for i in range(1, power+1):
for j in range(0, i+1):
term1 = x1col **(i-j)
term2 = x2col**(j)
term = (term1*term2).reshape(term1.shape[0], 1)
out = np.hstack((out, term))
return out
X_mapped = featureMap(X[:,1], X[:,2])

  • 损失函数和最优化

定义损失函数,并最优化参数theta

from scipy.special import expit #导入logistic函数
from scipy import optimize

def h(mytheta, myX): #定义假设函数
return expit(np.dot(myX, mytheta))

def costFunction(start_theta, msX, msy, mylambda = 0): #定义损失函数
term1 = np.dot(-np.array(y).T, np.log(h(start_theta, msX)))
term2 = -np.dot(1-np.array(y).T, np.log(1-h(start_theta, msX)))
regterm = (mylambda/2)*(np.sum(np.dot(start_theta.T, start_theta)))
return float((1./m)*(term1 + term2 + regterm))

initial_theta = np.zeros((X_mapped.shape[1], 1))
print(costFunction(initial_theta, X_mapped, y))

def optimizeRegularizedTheta(mytheta, myX, myy,mylambda = 0): #最优化函数
result = optimize.minimize(costFunction, mytheta, args = (myX, myy, mylambda), method = "BFGS", options = {"maxiter":500, "disp":False})
return np.array([result.x]), result.fun

theta, mincost = optimizeRegularizedTheta(initial_theta, X_mapped, y)
print(theta, mincost)

此时的输出

[[   19.4138306     31.3285252     16.12163907  -189.01000144
-82.69573059 -98.31203217 -230.13312921 -193.14282274
-123.96034243 -40.47214451 647.53238059 493.01458645
803.48109078 328.58433644 178.55338966 391.62472251
512.68088072 610.14918783 356.83374407 122.25968739
34.66926026 -755.58675051 -882.12281602 -1486.20826842
-1024.42073137 -1002.80938001 -367.67179237 -120.41821974]]

0.24862169044212865

前面一个矩阵是theta值,此时的theta是特征映射后的theta,0.2486……是最小损失函数值

  • 决策边界

需要定义出决策边界并可视化,此时的决策函数

f ( x 1 , x 2 ) = f ( x 1 、 x 2 、 x 1 x 2 、 x 1 2 、 x 2 2 、 . . . x 1 n x 2 n ) f(x_1,x_2)= f(x_1、x_2、x_1x_2、x_1^2、x_2^2、... x_1^nx_2^n) f(x1​,x2​)=f(x1​、x2​、x1​x2​、x12​、x22​、...x1n​x2n​)

是一个关于 x 1 , x 2 x_1, x_2 x1​,x2​的高程函数,故可以用等值线来刻画决策边界,可以认为lambda是一个超参,取不同的正则化参数lambda来观看分割效果。

def boundaryPlot(mytheta, myX, myy, mylambda =0): #定义绘制决策边界函数
theta, mincost = optimizeRegularizedTheta(mytheta, myX, myy, mylambda)
xvals = np.linspace(-1, 1.5, 50)
yvals = np.linspace(-1, 1.5, 50)
zvals = np.zeros((len(xvals), len(yvals)))
for i in range(len(xvals)):
for j in range(len(yvals)):
myfeatureij = featureMap(np.array([xvals[i]]), np.array([yvals[j]]))
zvals[i][j] = np.dot(theta, myfeatureij.T)
zvals = zvals.transpose()

u, v = np.meshgrid(xvals, yvals)
mycontour = plt.contour(xvals, yvals, zvals, [0])
myfmt = {0:"Lambda = %d"%mylambda}
plt.clabel(mycontour, inline =1 ,fontsize = 15, fmt = myfmt)
plt.title("Decision boundary")

plt.figure(figsize = (9,9))
plt.subplot(221)
dataPlot()
boundaryPlot(theta, X_mapped, y, 0)

plt.subplot(222)
dataPlot()
boundaryPlot(theta, X_mapped, y, 1)

plt.subplot(223)
dataPlot()
boundaryPlot(theta, X_mapped, y ,10)

plt.subplot(224)
dataPlot()
boundaryPlot(theta, X_mapped, y, 100)

延伸阅读

​https://blog.51cto.com/u_13580904/3726659​​​

​https://blog.51cto.com/u_15255081/2857901​​​

​https://blog.51cto.com/u_15255081/2857902​​​

机器学习——逻辑回归正则_机器学习_03