逻辑回归算法的Python实现
代码
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
# Get data as DataFrame Object
df = pd.read_csv('/Users/air/Macro/MegaChen/Study/ProgramOfStudy/MachineLearning/Data/梯度下降/data/LogiReg_data.txt', names=['Exam1', 'Exam2', 'Result'])
df.insert(0, 'Ones', 1)
matrix = df.as_matrix()
# 发现是监督学习的分类学习, 一般采用的是sigmoid函数构造最大似然函数从而得出损失函数, 为什么在这里不强调目标函数, 因为目标函数在目前
# 学到知识范围中, 就是一个t = theta0 * 1 + theta1 * x 1 + ... + thetan * xn == theta.T * x, 就是我们的theta矩阵的转置乘以
# 我们的训练集
# 此为原始的sigmoid函数, 后面的model函数仅仅是将这里的x换元成theta0 * 1 + theta1 * x 1 + ... + thetan * xn == theta.T * x
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# 对原始的sigmoid函数的换元封装, 用于为之后求似然函数作铺垫
def model(x, theta_set):
return sigmoid(np.dot(x, theta_set.T))
# x_set是一个二维矩阵, len函数是求出它的行数, 也就是一维的元素的个数
# 与数学中的函数有一些不一样, 这里作为参数的theta_set虽然是自变量, 但是在计算机中是不允许的, 所以这里的thata_set也要是一个具体的值
# 而x_set和y_set是函数的参数, 他们也是某种意义上的“自变量”, 因为他们的值也在随着我们的数据改变
def cost(x_set, y_set, theta_set):
left_side = np.multiply(-y_set, np.log(model(x_set, theta_set)))
right_side = np.multiply(1 - y_set, np.log(1 - model(x_set, theta_set)))
return sum(left_side - right_side) / len(x_set)
# 求出了cost损失函数, 接下来对该cost函数进行梯度下降求解出每一个theta的梯度, 并一一对应的保存到一个list中
def gradient(x_set, y_set, theta_set):
grad = np.zeros(theta_set.shape)
error = (model(x_set, theta_set) - y_set).ravel() # 将(100,1)的二维矩阵转为一维, 为了term = np.multiply(error, x_set[:, i])中能够计算
# error = (model(X, theta)- y).ravel()
for i in range(len(theta_set.ravel())):
term = np.multiply(error, x_set[:, i])
grad[0, i] = sum(term) / len(x_set)
return grad
# 得出了梯度, 我们只需要假定一个起始的α学习率值, 进行一个梯度下降即可
def descent(data, rate, theta_set):
np.random.shuffle(data)
x_set = data[:, 0:3]
print(x_set.shape)
y_set = data[:, 3:]
print(y_set.shape)
# 计算原始的损失函数, 这个时候的theta_set应该都全为0
costs = [cost(x_set, y_set, theta_set)]
times = 0
while True:
times += 1
grad = gradient(x_set, y_set, theta_set)
# 更新了我们的参数, 这里就是计算机的学习过程:-)
theta_set = theta_set - rate * grad
print(theta_set)
print(theta_set)
print(theta_set)
costs.append(cost(x_set, y_set, theta_set))
# 什么时候结束
if times > 5000:
return theta_set, costs
theta_set, costs = descent(matrix, 0.0001, np.zeros((1,3)))
plt.figure(figsize=(12,4))
plt.plot(range(len(costs)), costs, c='r')
plt.show()
print(theta_set)
小结
- 一般程序的开头就是调用梯度下降函数, 在该函数中调用我们之前定义好的sigmoid, model等函数, 该函数的返回结果就是我们需要的theta参数
- 对于array([1,2,3])这样矩阵, 它默认是一个列向量, 但是我们希望将他当做一个行向量来使用, 那就使用切片, 保留:, 如a[3:], 如果总共4列的话, 这样就得到了最后一列的行向量, 因为(3,)其实是一个list, 而(3,1)才是矩阵的, 矩阵最起码是二维的
- 虽然我们的数学公式中的自变量都是一个数, 但是在Python的应用中, 我们都是传入矩阵的, 也就是将我们的数据一并以矩阵的形式传入到函数中, 这样全部的数据一下子就计算出来了
- 列向量一定是二维的, 而行向量应该是一维的
- ravel()函数会降维
- 在强调一下, numpy中的zeros, ones返回的都是二维的矩阵, 不可能出现(3,), 除非a = np.array([1,2,3])
大致步骤
- 判断模型, 以逻辑回归为例
- 使用sigmoid函数
- h(x) = ...
- 用model函数表示h(x), 对sigmoid函数进行封装
- 定义cost函数, 需用推出数学公式, 在该函数中调用model函数
- 使定义gradient函数, 返回每一个参数对应的gradient的值组成的list, 注意: 该gradient函数不会调用cost函数, 因为一个是梯度(导数), 另一个是cost的函数值
- 定义主要的梯度下降函数descent, 返回的就是我们需要的theta_set, 在该函数中调用cost和gradient函数, 其中cost函数的值放在一个costs数据中, 用于画出函数图形和比较两次cost函数值的差, 如果小于我们规定的一个值, 就return退出函数, 而gradient就是为了一个这样的函数, theta = theta - alpha * gradient, 得出我们下一个theta值