吴恩达机器学习作业 python 实现:Logistic Regression
1.检查加载数据,进行可视化
定义函数对数据可视化
def plotdata(path):
data1 = np.loadtxt(path, delimiter=',')
pos_index = np.where(data1[:, 2] == 1)
neg_index = np.where(data1[:, 2] == 0)
plt.scatter(data1[pos_index, 0], data1[pos_index, 1], c='b', marker='x', label='Addmited')
plt.scatter(data1[neg_index, 0], data1[neg_index, 1], c='r', marker='o', label='Unaddmited')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
加载数据
path = r'ex2data1.txt'
data1 = np.loadtxt(path, delimiter=',')
plotdata(path)
plt.show()
根据散点图显示的边界确定使用线性边界,所以不用进行特征缩放
2.定义Sigmod函数
注意传入的参数Z可以是一个矩阵(在python中为二维数组)
def sigmod(z):
ans = 1 / (1 + np.exp(-z))
return ans
3.代价函数 Cost Function
在实现代价函数的过程中,仍然使用向量化来避免for循环的使用
def computecost(theta, X, y):
hx = sigmod(np.dot(X, theta))
cost = -np.mean(np.multiply(y, np.log(hx)) + np.multiply(1-y, np.log(1-hx)))
return cost
4.梯度下降
梯度下降的实现依旧是使用向量化来避免循环
值得注意:hx 是一个一维数组,hx.shape = (100,),如果传入的y在初始化数据时就进行reshape变成(100,1),这时 err.shape = (100,100)而不是(100,1)。原因是 hx 自动扩充为(100,100)的二维数组。解决的办法是传入 y 之前不要 reshape 即可。而对 hx 进行 reshape 让 err 维度正确 却会导致返回的 grad 是二维数组(在下面自动优化函数中二维数组将会导致优化函数的传参失败)
def gradient(theta, X, y):
m = X.shape[0]
hx = sigmod(np.dot(X, theta))
err = hx - y
grad = np.dot(X.T, err) / m
计算的无正则化、theta 为0向量时的代价与得到的梯度
5. fminunc 函数在python 中的替代
result = op.minimize(fun=computecost, x0=initial_theta, args=(X, y), method='TNC', jac=gradient)
在开头引用的库
import scipy.optimize as op
minimize函数传入的参数解释:
- fun - 表示要求得最小值的函数 因此代价函数传给 fun
- x0 - 表示 fun 中的初始自变量 即对应的代价函数中的 theta 为 初始自变量
- args - 表示 fun 中除了自变量自外的固定变量
- method - 表示优化的算法
- jac - 表示 fun 函数自变量的梯度算法
注意:initial_theta 、gradient返回值 是一维数组!!!!
reshape之后变成二维数组传入自动优化函数将会bug (对应4中提到的维度问题)
确定minimiz函数的参数维度无误 :
print(X.shape, initial_theta.shape, y.shape)
print(np.shape(grad))
运行结果:
最优化函数结果 :
- x 表示最终自变量的使得fun最小的取值 ,即让costFunction最小的theta
- 如果message输出:Linear search failed 是计算代价函数使用的log里面出现了负数(在第二部分的练习才会出现)
5.预测被录取的概率
print(sigmod(np.dot(result.x, [1, 45, 85])))
6.决策边界 (类似 ax+by+c= 0,求出y即可)
xplot_points = [X[:, 1].min(), X[:, 2].max()]
yplot_points = [X[:, 1].min()*op_theta[1]+op_theta[0], X[:, 1].max()*op_theta[1]+op_theta[0]]/(-op_theta[2])
plotdata(path)
plt.plot(xplot_points, yplot_points, c='y', label='Boundary Line')
plt.legend()
plt.show()
结果:
第二部分练习:
1.代价函数和梯度下降
没有太大变化,只是加入了正则化对theta进行惩罚:
def computecost2(theta, x, y, lambda_test):
hx = sigmod(np.dot(x, theta))
cost = -np.mean(np.multiply(y, np.log(hx)) + np.multiply(1-y, np.log(1-hx))) + lambda_test * np.mean(theta[1:])
return cost
def gradient2(theta, x, y, lambda_test):
m = X.shape[0]
hx = sigmod(np.dot(X, theta))
err = hx - y
grad = np.dot(X.T, err) / m
grad[1:] = grad[1:] + (lambda_test/m) * np.array(theta[1:])
return grad
2.特征变量的映射
进行映射的原因是发现对data2进行数据可视化之后,线性的决策边界并不能将两个类别分开,因此选择更多的特征来描述边界:
映射代码:
def mapfeature(x1, x2):
#若 m = x1.shape[0]
# 当输入的不是一维的数组或者多维的矩阵时,m不存在,转换成矩阵后则为0
temp = np.mat(x1)
m = temp.shape[1]
out = np.ones(m)
# 每个Featuer的最高次数等于6
degree = 6
for i in range(1, degree+1):
for j in range(i+1):
add = np.power(x1, i-j) * np.power(x2, j)
out = np.vstack([out, add])
return out.T
3.自动寻找 cost Function 为最小值的theta
result = op.minimize(fun=computecost2, args=(X, y, lambda_test), jac=gradient2, x0=initial_theta2, method='TNC')
与上面的优化函数使用没有什么不同
结果:
fun: 0.04733255576368678
jac: array([ 4.57959287e-04, -6.00677802e-05, 5.13905638e-05, 3.16235378e-05,
-6.58358654e-05, 2.65673577e-04, -2.46359925e-05, -1.96059695e-05,
-7.00014378e-05, -8.48880946e-05, -5.47619182e-05, -1.31191872e-04,
-2.31736077e-05, 6.84331601e-06, -7.28501958e-05, 2.97037692e-05,
-2.98836862e-05, -9.32059615e-05, -6.10395839e-06, 2.51302987e-05,
-1.57621275e-04, -1.13892355e-05, -7.45965584e-05, -3.00943452e-05,
-5.94147294e-05, -1.36079733e-05, 4.72813245e-05, -1.35909497e-04])
message: 'Linear search failed'
nfev: 59
nit: 3
status: 4
success: False
x: array([ 1.27422003, 0.62478645, 1.18590385, -2.02173837, -0.9170824 ,
-1.41319104, 0.12444365, -0.36770527, -0.36458182, -0.18067802,
-1.46506508, -0.06288704, -0.61999798, -0.27174439, -1.20129288,
-0.23663762, -0.20901446, -0.05490418, -0.27804409, -0.29276915,
-0.46790817, -1.04396472, 0.02082839, -0.29638539, 0.00961552,
-0.32917183, -0.13804216, -0.93550855])
message: ‘Linear search failed’ 虽然出现了,不过已经接近最优解了
4.绘制等高图
xx = np.linspace(-1, 1.5, 30)
yy = np.linspace(-1, 1.5, 30)
z = np.zeros((xx.size, yy.size))
for i in range(0, xx.size):
for j in range(0, yy.size):
z[i][j] = np.dot(mapfeature(xx[i], yy[j]), theta_opt)
z = z.T
cs = plt.contour(xx, yy, z, [0], colors='b')
注意使用矩阵Z的转置步骤,这里yy表示原特征(没有映射之前)第二个特征的取值范围,理应是对应矩阵Z的列,但是在for中随之变化的是行向量,因此进行转置,这样才能和1中的点对应。
结果:
至此,吴恩达机器学习第二部分练习总体完成。