机械学习——关于假设函数模型的理解
划分数据的正负样本
参数约定
样本数据
X = ( X ( 1 ) X ( 2 ) X ( 3 ) . . . X ( i ) . . . X ( m ) ) = ( 1 1 1 . . 1 . . . 1 x 1 ( 1 ) x 1 ( 2 ) x 1 ( 3 ) . . x 1 ( i ) . . . x 1 ( m ) x 2 ( 1 ) x 2 ( 2 ) x 2 ( 3 ) . . . x 2 ( i ) . . . x 2 ( m ) x 3 ( 1 ) x 3 ( 2 ) x 3 ( 3 ) . . x 3 ( i ) . . . x 3 ( m ) . . . . . . . . . . . . . . . . . . . . . . . . x j ( i ) . . . . . . . . . . . . . . . . . . . . . . . x n ( 1 ) x n ( 2 ) x n ( 3 ) . . x n ( i ) . . . x n ( m ) ) ( n + 1 ) × m (1) X = \left( \begin{matrix} X^{(1)} & X^{(2)} & X^{(3)} & ... & X^{(i)}...& X^{(m)}\\ \end{matrix} \right)= \left( \begin{matrix} 1 & 1 & 1 & .. & 1 &... & 1\\ x_{1}^{(1)} & x_{1}^{(2)} & x_{1}^{(3)} & .. & x_{1}^{(i)} &... & x_{1}^{(m)}\\ x_{2}^{(1)} & x_{2}^{(2)} & x_{2}^{(3)} & ...& x_{2}^{(i)} &...& x_{2}^{(m)}\\ x_{3}^{(1)} & x_{3}^{(2)} & x_{3}^{(3)} & ..& x_{3}^{(i)} &...& x_{3}^{(m)}\\ .. & .. & ..&..&.. &...& ...\\ .. & .. & ..&..&x_{j}^{(i)} &... & ...\\ .. & .. & ..&..&.. &...& ....\\ x_{n}^{(1)} & x_{n}^{(2)} & x_{n}^{(3)} & ..& x_{n}^{(i)} &...& x_{n}^{(m)}\\ \end{matrix} \right)_{(n+1) \times m } \tag{1}X=(X(1)X(2)X(3)...X(i)...X(m))=⎝⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎛1x1(1)x2(1)x3(1)......xn(1)1x1(2)x2(2)x3(2)......xn(2)1x1(3)x2(3)x3(3)......xn(3).................1x1(i)x2(i)x3(i)..xj(i)..xn(i)........................1x1(m)x2(m)x3(m)..........xn(m)⎠⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎞(n+1)×m(1)
Y = [ y ( 1 ) , y ( 2 ) , . . . . . . , y ( i ) , . . . , y ( m ) ] Y = [y^{(1)},y^{(2)},......,y^{(i)},...,y^{(m)}]Y=[y(1),y(2),......,y(i),...,y(m)]
y ( i ) ∈ { 0 ∣ 1 } y^{(i)} \in \{{0 | 1}\}y(i)∈{0∣1} ——0为负样本1为正样本权重
W = ( θ 1 θ 2 θ 3 . . . θ j . . . θ n ) n x × 1 (3) W = \left( \begin{matrix} \theta_{1} \\ \theta_{2} \\ \theta_{3} \\ ... \\ \theta_{j} \\ ...\\ \theta_{n}\\ \end{matrix} \right)_{n_{x} \times 1} \tag{3}W=⎝⎜⎜⎜⎜⎜⎜⎜⎜⎛θ1θ2θ3...θj...θn⎠⎟⎟⎟⎟⎟⎟⎟⎟⎞nx×1(3)偏置
b ∈ R 为 实 数 b \in R为实数b∈R为实数
算法过程
- 假设函数
Z = W T X + b = n p . d o t ( W . T , X ) + b Z = W^{T}X + b = np.dot(W.T, X) + bZ=WTX+b=np.dot(W.T,X)+b
添加激活函数
A = σ ( Z ) A = \sigma(Z)A=σ(Z) - 求dZ
d Z = A − Y dZ = A - YdZ=A−Y - 求参数偏导(正则化)
d W = 1 m ∗ X @ d Z . T + λ m ∗ W dW = \frac{1}{m} * X @dZ.T + \frac{\lambda}{m}*WdW=m1∗X@dZ.T+mλ∗W
d b = 1 m ∗ n p . s u m ( d Z ) db = \frac{1}{m}*np.sum(dZ)db=m1∗np.sum(dZ)
@——矩阵乘法运算 - 参数更新
W : = W − α ∗ d W W := W - \alpha*dWW:=W−α∗dW
b : = b − α ∗ d b b := b - \alpha*dbb:=b−α∗db
代码演示
- 导入相关库
import numpy as np
from matplotlib import pyplot as plt
from tqdm import tqdm
from tqdm.std import trange
#解决中文乱码
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
数据集加载
def load_data():
"""
加载数据集
return:
datd array 数据集
"""
data = np.loadtxt("data.txt",delimiter=",", dtype=np.float64)
return data;
数据预处理
- 数据集分割
def split_data_to_XY(data):
"""
将数据集分割X和Y集合
param:data 加载的数据集
retrun: X_p 原始数据X
Y 对应X_p的结果集
"""
data = np.array(data, dtype=np.float32)
X_p = data[:, :-1]
Y = data[:, -1].reshape((1, -1))
return [X_p, Y]
- 映射为多项式
def mapFeature(X_p):
"""
映射为多项式——在原基础训练样本特征上的特征拓展(特征数量变多了)
映射的多项式:
parameters: X_p 原始数据X 每列为一个特征值
return: X_map 映射为1多项式后的新特征样本数据, 每列仍然为一个特征
"""
#映射算法-这里没有映射
X_map = X_p
return X_map
- 特征归一化处理
def data_normal(X):
"""
采用0均值归一化,仅需要对特征X进行归一化处理
param: X list 训练样本数据 每列为一个特征
return:
X_nor list 归一化化后的数据
average list X每列计算的均值
variance list X每列计算的方差
"""
#计算均值 #axis=0 按列 axis=1 按行
average = np.mean(X, axis=0).reshape((1, -1))
#计算方差
variance = np.std(X, axis=0).reshape((1, -1))
#存储特征计算的方差和均值——第一行为均值 第二行为方差值
np.savetxt("normal.txt", np.vstack((average, variance)))
(n, m) = np.shape(X)
X_nor = np.ones((n, 1))
# print("X={0}".format(X))
for i in range(m):
tmp = (np.array(X[:, i]) - average[0, i]) / variance[0, i]
X_nor = np.hstack((X_nor, tmp.reshape((-1, 1))))
X_nor = X_nor[:, 1:]
return X_nor
- 样本向量化
def matrix(X_nor):
"""
样本向量化
"""
return np.transpose(X_nor)
- 数据预处理函数封装
#数据预处理封装函数
def data_dispose(data):
"""
数据预处理函数
parameters:
data array 原始数据集按照data.txt中格式排列样本的数据
return:
X array 数据预处理后向量化样本(每列为一个样本)
average array 对应data特征的均值为行向量
variance array 对应data特征的方差为行向量
"""
#2.数据集分割
[X_p, Y] = split_data_to_XY(data)
#4.特征归一化处理
X_nor = data_normal(X_p)
#5.样本向量化
X = matrix(X_nor)
#6.绘制数据集图像
plotData(data)
return X
假设函数
def hypothesis( X, W, b):
"""
计算假设函数
param: X array 预处理后的向量化样本数据集
W array 模型参数 列向量
b float 参数偏置 实数
return: A array 预测结果值 行向量
"""
W = np.array(W)
X = np.array(X)
#决策边界函数
Z = np.reshape(W.T @ X + b,(1, -1))
#添加激活函数
A = 1 / (1 + np.exp(-Z))
return np.reshape(A, (1, -1));
初始化模型参数
def init_param(X):
"""
初始化模型参数
param: X array 样本向量化后的数据集
return: lambd float 正则参数 常取0.01 0.1等
W array 特征权重参数 为列向量
b float 模型偏置 默认0
learn_rate float 学习率 常取0.01 0.1, 0.03, 0.3等
"""
(n, m) = np.shape(X)
#初始化W
W = np.zeros((n, 1))
#初始化b
b = 0
#初始化正则参数
lambd = 0.01
#选择学习率
learn_rate = 0.01
return [W, b, lambd, learn_rate]
辅助绘图函数
def plotData(data):
"""
绘制原始数据集图像
param:data array 数据集 按指定格式排布的
"""
#判断维数
(n, m) = np.array(data).shape
c = []
#数据标识
for i in range(n):
#负样本
if data[i, -1] == 0:
c.append("red")
elif data[i, -1] == 1:
#正样本
c.append("blue")
else:
#非法数据
c.append("green")
if m == 3:
#绘制二维图像
plt.scatter(data[:, 0], data[:, 1], c=c)
if m == 4:
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
xs = data[:, 0]
ys = data[:, 1]
zs = data[:, 2]
#绘制三维图像
ax.scatter(xs, ys, zs, c=c)
plt.title("训练样本分布图:蓝色=正样本;红色=负样本")
def plot_decision(data):
"""
绘制决策边界图:利用等高线图 + 散点图绘制决策边界
"""
#绘制决策边界的等高线图 +-.5是添加一点边缘填充
x1_min, x1_max = data[:,0].min()-.5, data[:, 0].max() + .5
x2_min, x2_max = data[:,1].min()-.5, data[:, 1].max() + .5
h = 0.01
#网格化
xx, yy = np.meshgrid(np.arange(x1_min,x1_max, h), np.arange(x2_min, x2_max, h))
#预测函数计算Z值 按列水平堆叠
X = np.c_[xx.ravel(),yy.ravel()]
Z = predict(X)
Z = Z.reshape(xx.shape)
#绘制等高线图
plt.contourf(xx, yy, Z, 1, alpha=0.15)
#绘制数据集的散点图
plotData(data)
def plotJ(cost):
"""
绘制代价函数图
"""
plt.figure(figsize=(20, 10))
plt.title("代价随迭代次数的变化图")
plt.ylabel("cost: 总代价")
plt.xlabel("epoch:迭代次数")
plt.plot(cost)
plt.figure()
模型训练
def train_LogisticRegression_model( X, Y, W, b = 0, lambd = 0.01, learn_rate = 0.01,epoch=1000):
"""
训练逻辑回归模型参数
param:
X array 向量化后的训练样本数据
Y array 对应X的结果集 为一个行向量
W array 列向量 默认为全为0
b float 模型偏置参数 默认0
lambd float 正则化参数 默认的0.01
learn_rate float 学习率 默认0.01
epoch int 迭代次数 默认1000
return:
optim_W list 最优参数
optim_b float 最优偏置参数
Cost list 迭代样本的总代价
"""
#存储所有迭代得到的参数
Parameters = []
#样本个数
m = np.size(Y)
#迭代总代价
Cost = []
#参数更新
for n in tqdm(range(epoch)):
#求解假设函数
A = hypothesis(X, W, b)
#计算总代价
L = -Y * np.log(A)-(1-Y)*np.log(1-A)
cost = 1 / m * np.sum(L) + lambd / (2*m) * np.sum(W**2)
Cost.append(cost)
#计算梯度Gradient A = [a1, a2, a3, ... ,am]
dZ = A - np.reshape(Y, (1, -1))
#正则处理
dW = 1 / m * (X @ dZ.T) + lambd / m * W
db = 1 / m * np.sum(dZ)
#模型参数更新
W = W - learn_rate * dW
b = b - learn_rate * db
Parameters.append([W,b])
#寻找最优解
k = Cost.index(min(Cost))
optim = Parameters[k]
#存储模型参数
np.savetxt("model_W.txt", optim[0])
np.savetxt("model_b.txt", [optim[1]])
return [optim, Cost]
模型预测
def predict(X):
"""
模型预测
parameters:
X array 原始数据集:每行为一个样本,每列为一个特征
return: pre_result array 预测结果
"""
#加载归一化数据集特征的均值和方差
Normal = np.loadtxt("normal.txt")
average = Normal[0, -1] #均值
variance = Normal[1, -1] #方差
# 数据归一化处理
X_nor = (X - average) / variance
#样本向量化
X = X_nor.T
#获取模型参数
W = np.loadtxt("model_W.txt")
b = np.loadtxt("model_b.txt")
W = np.reshape(W, (-1, 1))
pre_result = np.around(hypothesis(X, W, b), 7) #保留7为小数
return pre_result
- 主程序
#加载数据集
data = load_data()
#映射为多项式-----模型增强
data_map = mapFeature(data)
#数据预处理
X = data_dispose(data_map)
#初始化模型参数
[W, b, lambd, learn_rate] = init_param(X)
#迭代次数
epoch = 100000
#训练模型参数
[optim, Cost] = train_LogisticRegression_model(
X,
Y,
W,
b=0,
lambd=-0.01,
learn_rate=0.01,
epoch=epoch,
)
# #最优参数
W_optim = optim[0]
b_optim = optim[1]
#绘制代价图
plotJ(Cost)
#决策边界图像
#获取归一化的均值与方差值
normal = np.loadtxt("normal.txt")
plot_decision(data)
print("训练结果:")
print("W_optim={0}".format(W_optim))
print("b_optim={0}".format(b_optim))
print("min cost={0}".format(min(Cost)))
x = np.array([
[74.49269241843041,84.84513684930135],
[54.49269241843041,84.84513684930135],
[90, 100.2131232143],
[74.77589300092767,89.52981289513276],
[82.22666157785568,42.71987853716458],
[123.3, 123]
])
predict(x)

完整代码
在这里插入代码片
运行结果



