用逻辑回归解决二分类问题
代码已经注释很详细
第一部分解决上述 能用直线搞定的决策分类问题 拟合仅为直线 不需要加入正则项
代码如下:
import pandas as pds
import matplotlib.pyplot as plt
import numpy as np
def show_data():#进行数据可视化函数 并将X与Y分别取出并返回
data = pds.read_csv("./ex2data1.txt",names=["n1","n2","result"])
data_X1 = data[data["result"]==1].values #选取结果为1数据
data_X2 = data[data["result"]==0].values #选取结果为0的数据
plt.scatter(data_X1[:,0],data_X1[:,1],c="r",marker='o')#把特征值画上去 进行可视化展示
plt.scatter(data_X2[:,0],data_X2[:,1],c='g',marker='*')
plt.xlabel("n1")
plt.ylabel("n2")#x轴为n1 y轴为n2
plt.show()
data.insert(loc=0,column="cons",value=1)#在第一列插入常数特征值1
X = data.iloc[:,0:-1].values#取出特征值
Y = data.iloc[:,[-1]].values.reshape(X.shape[0],1)#取出真实值y 并进行维度调整 变成(m,1)的二维矩阵
return data,X,Y
def sigmoid(z):#激活函数
#激活函数 y=1/(1+exp(-z))
return 1/(1+np.exp(-z))
def costfunction(X,Y,theta):#计算代价函数
m=Y.shape[0]
A = sigmoid(X@theta) #经过激活函数的m的预测值
first = Y*np.log(A) #代价函数第一项
second = (1-Y)*np.log(1-A) #代价函数第二项
return -np.sum(first+second)/m#记得求和
def grad_descent(X,Y,theta,learning_rate,num):#梯度下降算法
m = Y.shape[0]
for i in range(num):#共迭代num次
A = sigmoid(X@theta) # 得到经过激活函数的预测值
print("第{}次迭代的损失为:{}".format(i+1,costfunction(X,Y,theta)))
theta = theta - learning_rate/m*(X.T@(A-Y))#梯度下降
return theta
def show_boundary(data,theta):#展示决策界面
X1 = data[data["result"]==0].values
X2 = data[data["result"]==1].values
plt.scatter(X1[:,1],X1[:,2],c="r",marker="*")
plt.scatter(X2[:,1],X2[:,2],c="g",marker="*")
x = np.linspace(30,100,200).reshape((200,1))
xx,yy = np.meshgrid(x,x)#每个点对应的x y就是特征值
z = np.append(xx.ravel().reshape((40000,1)),yy.ravel().reshape((40000,1)),axis=1)
#xx yy将其拉伸成为一条直线 得到200*200个样本的特征值x1,x2
z = np.append(np.ones((200*200,1)),z,axis=1)#添加theta0的特征值常数1
z = z@theta#得到200*200个样本的预测值
zz = z.reshape(xx.shape)#将其还原为二维点坐标对应的z
plt.contour(xx,yy,zz,0)#绘制三维图 z为0时即为决策界面
#plt.contour函数分别传入x坐标 y坐标 以及对应的z值 绘制等高线 0表示z=0的等高线
plt.show()
def get_curancy(X,Y,theta):#得到精确度的函数
y = sigmoid(X@theta) #得到预测值
m = Y.shape[0]#样本总数
count = 0#记录正确的样本数
for i in range(m):
if y[i] >= 0.5:#大于等于0.5认为正样本 反之认为负样本
y[i] = 1
else:
y[i] = 0
if y[i] == Y[i]: # 比较 如果结果正确 则说明是预测了正确的样本
count = count + 1
print("精确度为:{}".format(float(count)/m))
def main():
data,X,Y=show_data()
learning_rate = 0.001#注意 如果设置太大会报warning 具体原因还不知道
num =200000#迭代次数
theta = np.zeros((X.shape[1],1))#初始化(n,1)的二维theta矩阵
theta = grad_descent(X,Y,theta,learning_rate,num)#通过梯度下降得到最优theta
show_boundary(data,theta)#进行决策界面展示
get_curancy(X,Y,theta)#分析准确率
if __name__ == '__main__':
main()
第二部分解决如上二分类问题 界面较为复杂 不能单纯用直线分类 需要用特征缩放得到高阶特征值 拟合出复杂曲线 故还得引入正则项
代码如下:
import numpy as np
import pandas as pds
import matplotlib.pyplot as plt
def show_data():#展示数据集并将特征值与结果y返回
data = pds.read_csv("./ex2data2.txt",names=["n1","n2","result"])
X1 = data[data["result"]==0].values#选取结果分类为0的
X2 = data[data["result"]==1].values#选取结果分类为1的
plt.scatter(X1[:,0],X1[:,1],c="r",marker="*")
plt.scatter(X2[:,0],X2[:,1],c="g",marker="*")
plt.show()
return data.values[:,[0,1]],data.values[:,[-1]],data#返回特征值与对应的结果y
def feature_mapping(X1,X2,n):#特征映射 将x1,x2特征进行组合成高阶特征值 n表示最高次项为多少
data = {}
for i in range(n+1):
for j in range(n+1):
data["n{}{}".format(i,j)]=np.power(X1,i)*np.power(X2,j)
#进行特征映射 求解所有可能组合特征 每一种得到的新的特征值放到data字典里
#上面循环是为了得到各种特征组合 例如x1*x2 x1^2*x2等等 最高到x1^n*x2^n
data = pds.DataFrame(data)#放到pds中
data = data.values#取出值 这就是特征映射得到的更多特征值
return data
def sigmoid(z):#定义sigmoid函数
return 1/(1+np.exp(-z))
def costfunction(X,Y,theta,lamda):#定义代价函数
A = sigmoid(X@theta)
m = Y.shape[0]
first = Y*np.log(A)
second = (1-Y)*np.log(1-A)
res = (lamda/(2*m))*np.sum(theta[1:,0]*theta[1:,0])#代价函数这里新加入的正则项
return -np.sum(first+second)/m + res
def grad_descent(X,Y,theta,learning_rate,num,lamda):#梯度下降
m=Y.shape[0]
for i in range(num):
A = sigmoid(X@theta)
res = theta[1:,]
res = np.insert(res,axis=0,values=0,obj=0)
theta = theta - learning_rate*(X.T@(A-Y))/m -learning_rate*res*lamda/m#因为加了更高次来进行拟合 我们需要加入正则项 所以梯度下降这也需要改变
print("第{}次迭代损失为:{}".format(i,costfunction(X,Y,theta,lamda)))
return theta
def show_border(data,theta):
X1 = data[data["result"]==0].values
X2 = data[data["result"]==1].values
plt.scatter(X1[:,0],X1[:,1],c="r",marker="*")
plt.scatter(X2[:,0],X2[:,1],c="g",marker="*")
x = np.linspace(-1.2,1.2,200)
xx,yy = np.meshgrid(x,x)#生成区间从(-1.2到1.2的200个横坐标和纵坐标组成的点)
data = feature_mapping(xx.ravel(),yy.ravel(),6)#将验证样本进行特征映射 得到新的特征集
z = data@theta#带入 得到预测值
zz = z.reshape(xx.shape)#调整维度,变为(200*200)
plt.contour(xx,yy,zz,0)#选取得到zz预测为0的即为决策界面
plt.show()
def get_curancy(X,Y,theta):#验证准确率 X是已经被特征缩放的特征集了
y = X@theta#得到预测值
count = 0
for i in range(len(y)):
if y[i]>=0.5:
y[i] = 1
else:
y[i] = 0
if y[i] == Y[i]:
count = count + 1
print("准确率为:{}".format(count/len(y)))
def main():
X,Y,data = show_data()
X = feature_mapping(X[:,0],X[:,1],6)
theta = np.zeros((X.shape[1],1))
learning_rate = 0.01
num = 500000#迭代次数
lamda = 0.01#正则项
theta = grad_descent(X,Y,theta,learning_rate,num,lamda)
show_border(data,theta)
get_curancy(X,Y,theta)
if __name__ == '__main__':
main()