【机器学习笔记】——逻辑回归 & 交叉熵
目 录
1.逻辑回归模型
1.1 逻辑回归模型
我们将因变量(dependant variable)可能属于的两个类分别称为负向类(negative class)和 正向类(positive class),因变量,其中0表示负向类,1表示正向类。 为了使模型的输出在0和1之间,需要引进一个新的模型,即逻辑回归模型。
模型假设:
其中是输入, 是Sigmoid函数,逻辑函数的一种,函数图像如下:
因此模型可以表示为
给出了给定输入时,结果为1的概率,,即当时预测,当时预测,参照Sigmoid函数,即当时预测,当时预测。
这时逻辑回归模型为:
于是我们只需要得到参数就可以确定我们的模型。
1.2 模型的推导1——直接使用极大似然
对于给定的训练集,其中,,可以使用极大似然估计法估计参数模型(从最优化的观点看,似然函数是光滑的凸函数,因此多种最优化的方法都适用,能保证找到全局最优解),从而得到逻辑回归模型。
设:
其中。
似然函数为:
对数似然函数为:
对似然函数求极大值,得到的估计,对求导:
假设得到的的极大似然估计值为,那么学到的逻辑回归模型就是:
求似然函数的最大值,我们可以梯度上升(梯度的解释见第2节)的方法:
其中为学习率,我们也可以用梯度下降的方法,但是需要对似然函数进行适当处理,令,于是有:
该式即为交叉熵损失函数或者交叉熵公式。
对求偏导:
这样就可以用梯度下降发逼近参数:
1.3 模型的推导2——不似然的似然
沿用前面的假设,对于第i个样本:
如果不考虑似然函数。我们可以先对概率取对数(因为 运算并不会影响函数本身的单调性):
于是是正确的对数概率为:
\begin{align}
& I(y_i = 1)\log P(\hat{y_i} = 1 | x_i, \theta) + I(y_i = 0)\log P(\hat{y_i} = 0 | x_i, \theta) \
& = y_i \log P(\hat{y_i} = 1 | x_i, \theta) + (1 - y_i) \log P(\hat{y_i} = 0 | x_i, \theta) \
& = y_i \log h_{\theta} (x_i) + (1 - y_i) \log (1 - h_{\theta} (x_i))
\end{align}
我们当然希望这个概率越大越好,那么只需取负即可,这样我们得到了单样本的代价函数:
于是总的代价函数为:
1.4 模型的推导3——使用代价函数
对于线性回归模型,我们使用误差平方和作为代价函数,因此我们先考虑也用这个函数作为逻辑回归的代价函数,于是有:
这样的是一个非凸函数,存在很多局部最小值,这会影响梯度下降算法寻找全局最小值,所以我们需要重新选择逻辑回归的代价函数。
考虑
这样当确实为1时,越接近1,代价越接近0,越接近0,代价越大;当确实为0时,越接近0,代价越接近0,越接近1,代价越大。取负号是为了让代价为正。代价函数的选择涉及到了交叉熵的知识,具体参考第5节的内容。进一步可以把整理为:
于是得到新的代价函数:
在得到这样一个代价函数以后,我们便可以用梯度下降算法来求得能使代价函数最小的参数了:
具体的推导过程参考1.2节。其实两者的不同主要在似然函数是上凸的,而代价函数是下凸的,两者也只是差了一个系数。
1.5 *思考——如果分类标签是{-1,+1}
按照极大似然的推导方法有:
似然函数为:
注意这里的上标为
对数似然函数对求导:
更新梯度:
我们也可以换一种思路,考虑到sigmoid函数的一种特殊性质,以及y取值为或,我们得到:
于是似然函数为:
对数似然函数对求导:
更新梯度:
2 梯度下降公式
梯度下降是求最优解的一种方法,因为当数据维度较高时,我们很难通过令导数为0的方法进行求解,甚至有时候根本无法求解。考虑一个下凸函数(这里如果是上凸函数,更新就会相反,参考1.2节对似然函数使用梯度上升的算法),我们要找到最小时的值。
(1).随便取一个初始值,比如
(2).现在有两个方向可以对进行更新:或者,显然是我们想要的,也就是说我们应该确定每次更新的方向。注意到当时,该点的导数,所以和我们的更新方向一致,也就是负梯度方向。因此我们对进行更新:,其中为学习率
(3).重复(1)和(2)直到收敛
再来看逻辑回归中得梯度下降算法
(1).其中N为样本总数,也就是说这里使用了全部样本对参数进行更新,这种方法称为批量梯度下降(Batch Gradient Descent, BGD),这种方法的特点是很容易求得全局最优解,但是当样本数目很多时,训练过程会很慢。当样本数量很少的时候可以使用它
(2).若只选择一个样本进行更新,即,这样的方法称为随机梯度下降(Stochastic Gradient Descent, SGD),这种方法的特点是训练速度快,但是准确度下降,容易受到单个数据的影响,如果单个样本是离群点或噪声,SGD算法也依然会得到更新,这使得SGD算法的每次更新迭代有可能不朝全局最优解方向走,也可能导致不收敛
(3).那么容易想到使用部分数据的方法,称为小批量梯度下降(Mini-batch Gradient Descent, MBGD)
2.2 高级优化
对于梯度下降算法,我们需要编写程序来计算,如果需要监控的收敛性,也可以同时计算出
除了梯度下降算法以外,还有一些常被用来令代价函数最小的算法,这些算法更加复杂和优越,而且通常不需要人工选择学习率,通常比梯度下降算法要更加快速。这些算法有:共轭梯度(Conjugate Gradient),局部优化法(Broyden fletcher goldfarb shann,BFGS)和有限内存局部优化法(LBFGS)。这些算法内部有一个线性搜索(line search)算法,可以自动选择一个好的学习率,甚至在每一次迭代时都重新选择一个学习率。因此它们往往比梯度下降收敛得更快。当然缺点也是显而易见的,复杂难懂,不过不了解内部的细节仍然不影响我们使用这些算法。
3. *多分类问题
对于多分类,我们的数据集可能是这样的:
我们可以通过一个叫做"一对多" (one-vs-all) 的分类算法来处理这样的问题。
我们先从用三角形代表的类别 1 开始,实际上我们可以创建一个,新的"伪"训练集,正方形代表的类别 2 和圆形代表的类别 3 定为负类,类别 1 定为正类,我们创建一个新的训练集,如下图所示的那样,我们要训练出一个合适的分类器。
这里红色图形为正样本,值为1,蓝色图形为负样本,值为0。于是我们可以训练一个标准的逻辑回归分类器。接着,类似地第我们选择另一个类标记(圆形样本)为正向类(y=2),再将其它类都标记为负向类,将这个模型记作 ,依此类推。最后我们得到一系列的模型简记为: ,其中:
最后,为了做出预测,我们输入一个新的 x 值,用这个做预测。我们要做的就是在我们三个分类器里面输入 x,然后我们选择一个让最大的 i,即
4. 模型的正则化
4.1 正则化
下图展示了一个分类的模型,左边的模型欠拟合(under fit),中间的模型几乎是正确的,而右边的模型发生了过拟合(overfitting)。
如果我们发现了过拟合问题,应该如何处理?
- 丢弃一些不能帮助我们正确预测的特征。可以是手工选择保留哪些特征,或者使用一些特征选择的算法来帮忙(例如 PCA)
- 正则化(regularization)。保留所有的特征,但是减少参数的大小(magnitude)。
再来看一个线性回归模型:
对于右边的过拟合模型:,可以看出,正是那些高次项导致了过拟合的产生,所以如果我们能让这些高次项的系数接近于 0 的话,我们就能很好的拟合了。所以我们要做的就是在一定程度上减小这些参数的值,这就是正则化的基本方法。
我们决定要减少 和 的大小,我们要做的便是修改代价函数,在其中对 和 设置一点惩罚。这样做的话,我们在尝试最小化代价时也需要将这个惩罚纳入考虑中,并最终导致选择较小一些的 和 。修改后的代价函数如下:
通过最小化这样的代价函数选择出的 和 对预测结果的影响就比之前要小许多。假如我们有非常多的特征,我们并不知道其中哪些特征我们要惩罚,我们将对所有的特征进行惩罚,并且让代价函数最优化的软件来选择这些惩罚的程度。这样的结果是得到了一个较为简单的能防止过拟合问题的假设:
其中 又称为正则化参数(Regularization Parameter)。 注:根据惯例,我们不对 进行惩罚。
经过正则化处理的模型与原模型的可能对比如下图所示:
如果选择的正则化参数 过大,为了使代价函数减小,则会把所有的参数都最小化甚至趋于 0 ,导致模型变成 ,也就是上图中红色直线所示的情况,造成欠拟合。所以对于正则化,我们要取一个合理的 的值,这样才能更好的应用正则化。
4.2 正则化的逻辑回归模型
对于正则化的逻辑回归模型,我们对代价函数增加惩罚项:
通过求导得出梯度下降算法为:
5. 理解交叉熵
可以参考这两篇博客:
https://blog.csdn.net/tsyccnh/article/details/79163834
https://blog.csdn.net/rtygbwwwerr/article/details/50778098
5.1 信息量
假设是一个离散型随机变量,其取值集合为,概率分布函数为, ,我们定义事件的信息量为:
可以理解为一个事件发生的概率越大,则它所携带的信息量就越小,而当时,等于0,也就是说该事件的发生不会导致任何信息量的增加。举个例子,小明平时不爱学习,考试经常不及格,而小王是个勤奋学习的好学生,经常得满分,所以我们可以做如下假设:
事件A:小明考试及格,对应的概率,信息量为
事件B:小王考试及格,对应的概率,信息量为
可以看出,结果非常符合直观:小明及格的可能性很低(十次考试只有一次及格),因此如果某次考试及格了(大家都会说:XXX竟然及格了!),必然会引入较大的信息量。而对于小王而言,考试及格是大概率事件,在事件B发生前,大家普遍认为事件B的发生几乎是确定的,因此当某次考试小王及格这个事件发生时并不会引入太多的信息量。
5.2 熵
那么什么又是熵呢?还是通过上边的例子来说明,假设小明的考试结果是一个0-1分布只有两个取值{0:不及格,1:及格},在某次考试结果公布前,小明的考试结果有多大的不确定度呢?你肯定会说:十有八九不及格!因为根据先验知识,小明及格的概率仅有0.1,90%的可能都是不及格的。怎么来度量这个不确定度?求期望!不错,我们对所有可能结果带来的额外信息量求取均值(期望),其结果不就能够衡量出小明考试成绩的不确定度了吗。
即:
对应小王的熵:
虽然小明考试结果的不确定性较低,毕竟十次有9次都不及格,但是也比不上小王(1000次考试只有一次才可能不及格,结果相当的确定)
我们再假设一个成绩相对普通的学生小东,他及格的概率是P(xC)=0.5P(xC)=0.5,即及格与否的概率是一样的,对应的熵:
其熵为1,他的不确定性比前边两位同学要高很多,在成绩公布之前,很难准确猜测出他的考试结果。
可以看出,熵其实是信息量的期望值,它是一个随机变量的确定性的度量。熵越大,变量的取值越不确定,反之就越确定。对于一个随机变量而言,它的所有可能取值的信息量的期望就称为熵。的熵定义为:
如果是连续型随机变量的pdf,则熵定义为:
为了保证有效性,这里约定当时,有
当为0-1分布时,熵与概率的关系如下图:
可以看出,当两种取值的可能性相等时,不确定度最大(此时没有任何先验知识),这个结论可以推广到多种取值的情况。在图中也可以看出,当或时,熵为0,即此时完全确定。
熵的单位随着公式中运算的底数而变化,当底数为2时,单位为“比特”(bit),底数为e时,单位为“奈特”(nat),当底数为10时,单位为“哈托特”(hat)。
5.3 *相对熵
相对熵(relative entropy)又称为KL散度(Kullback-Leibler divergence),KL距离,是两个随机分布间距离的度量。记为。它度量当真实分布为时,假设分布的无效性。
并且为了保证连续性,做如下约定:
显然,当时,两者之间的相对熵
上式最后的表示在分布下,使用进行编码需要的bit数,而表示对真实分布所需要的最小编码bit数。基于此,相对熵的意义就很明确了:表示在真实分布为的前提下,使用分布进行编码相对于使用真实分布进行编码(即最优编码)所多出来的bit数。实际上,即是我们将要讲到的交叉熵。
5.4 交叉熵
假设有两个分布,,则它们在给定样本集上的交叉熵定义如下:
可以看出,交叉熵与上一节定义的相对熵仅相差了,当已知时,可以把看做一个常数,此时交叉熵与KL距离在行为上是等价的,都反映了分布,的相似程度。交叉熵越大,相似度越小。因此,要想让预测的标签的分布与真实的标签分布最接近,就需要最小化交叉熵。最小化交叉熵等于最小化KL距离。它们都将在时取得最小值,因此有的工程文献中将最小化KL距离的方法称为Principle of Minimum Cross-Entropy (MCE)或Minxent方法。
特别的,在逻辑回归中,
:真实样本分布,服从参数为的0-1分布,即
:待估计的模型,服从参数为的0-1分布,即
两者的交叉熵为:
对所有训练样本取均值得:
这个结果与我们前面推导的逻辑回归模型相一致。
6 编程练习
6.1 练习Ⅰ
ex2data1.txt:https://github.com/fengdu78/Coursera-ML-AndrewNg-Notes/blob/master/code/ex2-logistic regression/ex2data1.txt
设想你是大学相关部分的管理者,想通过申请学生两次测试的评分,来决定他们是否被录取。现在你拥有之前申请学生的可以用于训练逻辑回归的训练样本集。对于每一个训练样本,你有他们两次测试的评分和最后是被录取的结果。为了完成这个预测任务,我们准备构建一个可以基于两次测试评分来评估录取可能性的分类模型。
准备数据
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
data = pd.read_csv('file/ex2data1.txt', header=None, names=['Exam 1', 'Exam 2', 'Admitted'])
data.head()
创建两个分数的散点图,并使用颜色编码来可视化,如果样本是正的(被接纳)或负的(未被接纳)
positive = data[data['Admitted'].isin([1])]
negative = data[data['Admitted'].isin([0])]
fig, ax = plt.subplots(figsize=(12,8))
ax.scatter(positive['Exam 1'], positive['Exam 2'], s=50, c='b', marker='o', label='Admitted')
ax.scatter(negative['Exam 1'], negative['Exam 2'], s=50, c='r', marker='x', label='Not Admitted')
ax.legend()
ax.set_xlabel('Exam 1 Score')
ax.set_ylabel('Exam 2 Score')
plt.show()
看起来在两类间,有一个清晰的决策边界。现在我们需要实现逻辑回归,那样就可以训练一个模型来预测结果
# 提取特征
def get_X(df):
theta_0 = pd.DataFrame({'Theta_0': np.ones(len(df))})
data = pd.concat([theta_0, df], axis=1) # 这两步可以用 df.insert(0, 'Ones', 1),但是这样写会修改最初的数据,可能会影响二次使用
return np.array(data.iloc[:, :-1]) # 返回一个 ndarray,也可以用data.iloc[:, :-1].values
# 提取标签
def get_y(df):
return np.array(df.iloc[:, -1])
# 特征标准化
def normalize_feature(df):
return df.apply(lambda column: (column - column.mean()) / column.std()) # 这里返回的是一个 dataframe
X = get_X(data)
y = get_y(data)
theta = np.zeros(3) # 参数初始化为(0, 0, 0)
让我们来检查矩阵的维度来确保一切良好。
X.shape, theta.shape, y.shape
((100, 3), (3,), (100,))
定义sigmoid函数
def sigmoid(z):
return 1 / (1 + np.exp(-z))
让我们做一个快速的检查,来确保它可以工作。
nums = np.arange(-10, 10, step=0.01)
fig, ax = plt.subplots(figsize=(8, 6))
ax.plot(nums, sigmoid(nums))
ax.set_ylim((-0.1,1.1))
ax.set_xlabel('z', fontsize=18)
ax.set_ylabel('g(z)', fontsize=18)
ax.set_title('sigmoid function', fontsize=18)
plt.show()
定义代价函数
def cost(theta, X, y):
return -np.mean(y * np.log(sigmoid(X.dot(theta))) + (1 - y) * np.log(1 - sigmoid(X.dot(theta))))
# X.dot(theta)等价于X @ theta, 或者X * theta.T,但是X * theta.T需要先用np.matrix()转化为矩阵
让我们计算初始化参数的代价函数( 为 )
cost(theta, X, y)
0.6931471805599453
梯度下降
-
这是批量梯度下降(batch gradient descent)
-
转化为向量化计算:
-
这里对的所有分量是同时更新的
def gradient(theta, X, y):
return (1 / len(X)) * X.T.dot((sigmoid(X.dot(theta)) - y)) # 默认学习率为1,如果是其他的学习率可以增加一个系数
注意,我们实际上没有在这个函数中执行梯度下降,我们仅仅在计算一个梯度步长。
我们看看用我们的数据和初始参数为0的梯度下降法的结果。
gradient(theta, X, y)
array([ -0.1 , -12.00921659, -11.26284221])
最优化参数
可以用SciPy’s truncated newton(TNC)实现寻找最优参数。
import scipy.optimize as opt
result1 = opt.fmin_tnc(func=cost, x0=theta, fprime=gradient, args=(X, y))
result1
(array([-25.16131854, 0.20623159, 0.20147149]), 36, 0)
我们可以利用前面定义的代价函数来查看在这个参数下的代价是多少
cost(result1[0], X, y)
0.20349770158947492
还可以使用 scipy.optimize.minimize 去寻找参数并获得更加详细的信息
result2 = opt.minimize(fun=cost, x0=theta, args=(X, y), method='Newton-CG', jac=gradient)
result2
预测和验证
当大于等于0.5时,预测 y=1
当小于0.5时,预测 y=0
def predict1(theta, X):
probability = sigmoid(X.dot(theta.T))
return [1 if x >= 0.5 else 0 for x in probability]
def cal_acc(predictions, y):
correct = [1 if a == b else 0 for (a, b) in zip(predictions, y)]
accuracy = sum(correct) % len(correct)
print('accuracy = {0}%'.format(accuracy))
final_theta = result1[0]
cal_acc(predict1(final_theta, X), y)
accuracy = 89%
还可以用 sklearn.metrics.classification_report 获得更详细的评价报告
from sklearn.metrics import classification_report
def predict2(x, theta):
prob = sigmoid(x @ theta)
return (prob >= 0.5).astype(int)
final_theta = result2.x
y_pred = predict2(X, final_theta)
print(classification_report(y, y_pred))
决策边界
首先考虑一个问题:逻辑回归可以看作是没有隐藏层的神经网络,那么为什么逻辑回归是线性分类器而神经网络是非线性分类器?首先逻辑回归的输出可以写为,说明预测是的线性函数,更确切地说,预测的对数几率(log-odds)是的线性函数,同时神经网络的输出不可能表示为的线性函数。另一方面对于逻辑回归,它的决策边界是线性的,是的解,而神经网络的决策边界不是线性的。.
coef = -(final_theta / final_theta[2])
print(coef)
x = np.arange(130, step=0.1)
y = coef[0] + coef[1]*x # 注意这里的 x 和 y 只是为了作图需要,而不是输入和输出值
[124.88803588 -1.02363461 -1. ]
fig, ax = plt.subplots(figsize=(12,8))
ax.scatter(positive['Exam 1'], positive['Exam 2'], s=50, c='b', marker='o', label='Admitted')
ax.scatter(negative['Exam 1'], negative['Exam 2'], s=50, c='r', marker='x', label='Not Admitted')
ax.legend()
ax.plot(x, y, 'grey')
ax.set_xlabel('Exam 1 Score')
ax.set_ylabel('Exam 2 Score')
ax.set_title('Decision Boundary', fontsize=18)
plt.show()
6.2 练习Ⅱ(正则化的逻辑回归)
ex2data2.txt:https://github.com/fengdu78/Coursera-ML-AndrewNg-Notes/blob/master/code/ex2-logistic regression/ex2data2.txt
设想你是工厂的生产主管,你有一些芯片在两次测试中的测试结果。对于这两次测试,你想决定是否芯片要被接受或抛弃。为了帮助你做出艰难的决定,你拥有过去芯片的测试数据集,从其中你可以构建一个逻辑回归模型。
准备数据
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
data = pd.read_csv('file/ex2data2.txt', header = None, names=['Test 1', 'Test 2', 'Accepted'])
data.head()
sns.set(context="notebook", style="ticks", font_scale=1.5)
sns.lmplot('Test 1', 'Test 2', hue='Accepted', data=data,
height=6,
fit_reg=False,
scatter_kws={"s": 100}
)
plt.title('Regularized Logistic Regression')
plt.show()
这个数据看起来可比练习Ⅰ复杂得多。特别地,注意到其没有线性决策边界来良好的分开两类数据。一个方法是用像逻辑回归这样的线性技术来构造从原始特征的多项式中得到的特征。让我们通过创建一组多项式特征入手吧。
特征映射
把映射到新特征,最高次可以任意设定
# 特征映射
def feature_mapping(x1, x2, power, as_ndarray=False):
# as_ndarray控制返回数据的类型
data = {"f{}{}".format(i - p, p): np.power(x1, i - p) * np.power(x2, p)
for i in np.arange(power + 1)
for p in np.arange(i + 1)
}
if as_ndarray:
return pd.DataFrame(data).values
else:
return pd.DataFrame(data)
power = 4
x1 = data['Test 1']
x2 = data['Test 2']
newdata = feature_mapping(x1, x2, power)
print(newdata.shape)
newdata.head()
现在,我们需要修改第1部分的代价函数和梯度函数,包括正则化项。
def sigmoid(z):
return 1 / (1 + np.exp(-z))
正则化代价函数
theta = np.zeros(newdata.shape[1])
X = newdata.values
print(X.shape)
y = np.array(data.iloc[:, -1])
print(y.shape)
(118, 15)
(118,)
# 正则化代价函数,注意不对常数项进行惩罚
def cost(theta, X, y):
return -np.mean(y * np.log(sigmoid(X.dot(theta))) + (1 - y) * np.log(1 - sigmoid(X.dot(theta))))
def regularized_cost(theta, X, y, lambda0=1):
# 默认正则化参数为1
theta_j1_to_n = theta[1:]
regularized_term = (lambda0 / (2 * len(X))) * np.power(theta_j1_to_n, 2).sum()
return cost(theta, X, y) + regularized_term
我们再来看看初始化参数下的代价
cost(theta, X, y)
0.6931471805599454
regularized_cost(theta, X, y)
0.6931471805599454
两者结果相同,因为初始化参数全为0,所以惩罚项也是0
正则化梯度
def gradient(theta, X, y):
return (1 / len(X)) * X.T.dot((sigmoid(X.dot(theta)) - y))
def regularized_gradient(theta, X, y, lambda0=1):
theta_j1_to_n = theta[1:]
regularized_theta = (lambda0 / len(X)) * theta_j1_to_n
# 注意不要忘了常数项惩罚要补0
regularized_term = np.concatenate([np.array([0]), regularized_theta])
return gradient(theta, X, y) + regularized_term
再来看看初始化参数的情况下梯度下降了多少
regularized_gradient(theta, X, y)
最优化参数
import scipy.optimize as opt
fmin_tnc方法
result1 = opt.fmin_tnc(func=regularized_cost, x0=theta, fprime=regularized_gradient, args=(X, y))
result1
minimize方法
result2 = opt.minimize(fun=regularized_cost, x0=theta, args=(X, y), method='Newton-CG', jac=regularized_gradient)
result2
预测和验证
沿用fmin_tnc方法得到的结果
def predict1(theta, X):
probability = sigmoid(X.dot(theta.T))
return [1 if x >= 0.5 else 0 for x in probability]
def cal_acc(predictions, y):
correct = [1 if a == b else 0 for (a, b) in zip(predictions, y)]
accuracy = sum(correct) % len(correct)
print('accuracy = {0}%'.format(accuracy))
final_theta = result1[0]
cal_acc(predict1(final_theta, X), y)
accuracy = 97%
沿用fmin_tnc方法得到的结果
from sklearn.metrics import classification_report
def predict2(x, theta):
prob = sigmoid(x.dot(theta))
return (prob >= 0.5).astype(int)
final_theta = result2.x
y_pred = predict2(X, final_theta)
print(classification_report(y, y_pred))
两者结果并不相同,应该和学习率有关
决策边界
def feature_mapped_logistic_regression(power, lambda0):
# 为了比较不同power和正则化参数下的结果,对前面的回归过程进行整理
# 准备数据
df = pd.read_csv('file/ex2data2.txt', names=['test1', 'test2', 'accepted'])
x1 = np.array(df.test1)
x2 = np.array(df.test2)
y = np.array(df.iloc[:, -1])
# 特征映射
X = feature_mapping(x1, x2, power, as_ndarray=True)
theta = np.zeros(X.shape[1])
# 逻辑回归
res = opt.minimize(fun=regularized_cost,
x0=theta,
args=(X, y, lambda0),
method='TNC',
jac=regularized_gradient)
final_theta = res.x
return final_theta
def find_decision_boundary(density, power, theta, threshhold):
t1 = np.linspace(-1, 1.5, density)
t2 = np.linspace(-1, 1.5, density)
cordinates = [(x, y) for x in t1 for y in t2]
x_cord, y_cord = zip(*cordinates)
mapped_cord = feature_mapping(x_cord, y_cord, power) # this is a dataframe
inner_product = mapped_cord.values.dot(theta)
decision = mapped_cord[np.abs(inner_product) < threshhold]
return decision.f10, decision.f01
def draw_boundary(power, lambda0):
density = 1000
threshhold = 2 * 10**-3
final_theta = feature_mapped_logistic_regression(power, lambda0)
x, y = find_decision_boundary(density, power, final_theta, threshhold)
df = pd.read_csv('file/ex2data2.txt', names=['Test 1', 'Test 2', 'Accepted'])
sns.lmplot('Test 1', 'Test 2', hue='Accepted', data=df, height=6, fit_reg=False, scatter_kws={"s": 100})
plt.scatter(x, y, c='red', s=10)
plt.title('Decision boundary')
plt.show()
draw_boundary(power=7, lambda0=1) # 正则化参数为1
draw_boundary(power=7, lambda0=0) # 正则化参数为0,即不进行正则化
可以看到发生了过拟合
draw_boundary(power=7, lambda0=100) # 正则化参数为100,即加重惩罚
可以看到发生了欠拟合
6.3 练习Ⅲ(使用scikit-learn)
from sklearn import linear_model
model = linear_model.LogisticRegression(penalty='l2', C=1.0)
model.fit(X, y.ravel())
model.score(X, y)
0.8220338983050848
这个准确度和result1差了好多,不过请记住这个结果是使用默认参数下计算的结果。我们可能需要做一些参数的调整来获得和我们之前结果相同的精确度。
上一篇: 微信小程序3D轮播图
下一篇: STL--deque容器