当前位置:   article > 正文

手撕机器学习02-逻辑回归_手撕逻辑回归

手撕逻辑回归

上一讲:手撕机器学习01-线性回归

逻辑回归原理

逻辑回归虽然被称为回归,但其实际上是分类模型,并常用于二分类。可以认为逻辑回归 = 线性回归 + sigmoid激活函数。之所以逻辑回归被称为回归是因为sigmoid的输出为连续的概率值,所以叫回归,但其实得到概率后进行了分类处理,所以逻辑回归其实是一个分类器。

原理更多可以参考:https://zhuanlan.zhihu.com/p/74874291,总结的非常详细,这里不再赘述

逻辑回归 =  线性回归 + sigmoid激活函数

在上一讲线性回归中,目标函数为y = wx + b, 在逻辑回归中变成了 sigmoid( wx + b),所以可以理解为逻辑回归 = sigmoid(线性回归)。sigmoid输出概率大于0.5被认为属于正类,反之属于负类。

 

手撕实现

1、生成数据集

随机生成数据,同时为数据分类。

  1. import numpy as np
  2. num_inputs = 2 # 样本维度
  3. num_examples = 1000 # 样本数量
  4. true_w = [4, -2.4] # 设置真实w = [4, -2.4]⊤和偏差b = 3.2
  5. true_b = 3.2
  6. features = np.random.normal(scale=5, size=(num_examples, num_inputs))
  7. true_y = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b # x 在 wx+b上的实际应该值
  8. labels = true_y > 0 # >= wx + b 对应标签为1 < wx+b 对应标签为0
  9. labels = np.array(list(map(lambda x: 1 if x else 0, labels)))

展示数据机真实的分割线

  1. from IPython import display
  2. from matplotlib import pyplot as plt
  3. def use_svg_display():
  4. # 用矢量图显示
  5. display.set_matplotlib_formats('svg')
  6. def set_figsize(figsize=(5, 4)):
  7. use_svg_display()
  8. # 设置图的尺寸
  9. plt.rcParams['figure.figsize'] = figsize
  10. set_figsize()
  11. colors = ['g','r', 'b']
  12. Label_Com = ['0','1', 'line']
  13. x1_0, x2_0, x1_1, x2_1 = [], [], [], []
  14. for i in range(len(labels)):
  15. if labels[i] == 0:
  16. x1_0.append(features[i,0])
  17. x2_0.append(features[i,1])
  18. else:
  19. x1_1.append(features[i,0])
  20. x2_1.append(features[i,1])
  21. line_x1 = np.arange(-10, 10, 0.1)
  22. line_x2 = (true_w[0] * line_x1 + true_b) / -true_w[1]
  23. plt.scatter(x1_0, x2_0, c=colors[0], cmap='brg', s=5, marker='8', linewidth=0)
  24. plt.scatter(x1_1, x2_1, c=colors[1], cmap='brg', s=5, marker='8', linewidth=0)
  25. plt.scatter(line_x1, line_x2, c=colors[2], cmap='brg', s=3, marker='8', linewidth=0)
  26. plt.legend(labels = Label_Com, loc='upper right')
  27. plt.show()

将数据分批

  1. batch_size = 100 # 批大小
  2. indices = np.array(range(num_examples))
  3. np.random.shuffle(indices) # 随机打乱顺序
  4. X = np.array([features.take(indices[i:i+batch_size], 0) for i in range(0, num_examples, batch_size)])
  5. Y = np.array([labels.take(indices[i:i+batch_size], 0) for i in range(0, num_examples, batch_size)])
  6. print(X.shape, Y.shape)

2、定义模型

  1. class LogisticsRegression:
  2. def __init__(self, num_inputs):
  3. # 初始化参数
  4. self.w = np.random.normal(scale=1, size=(num_inputs, 1))
  5. self.b = np.random.normal(scale=0.01, size=(1))
  6. def __str__(self):
  7. # 输出参数
  8. return 'w:' + str(self.w) + '\nb:' + str(self.b)
  9. def forward(self, input):
  10. # 前向计算
  11. return np.dot(input, self.w) + self.b
  12. def sigmoid(self, input):
  13. return 1.0/(1+np.exp(-input))
  14. def cross_entropy(self, p, label):
  15. # 损失函数-交叉熵函数
  16. return - np.dot(label.T,np.log(p)) - np.dot((1-label).T, np.log(1.0000000001-p)) # 防止溢出
  17. def accuracy(self, p, label):
  18. # 计算分类的准确率
  19. pre = (p > 0.5)
  20. pre = np.array(list(map(lambda x: 1 if x else 0, pre))).reshape(label.shape)
  21. return np.sum(pre == label)/len(label)
  22. def sgd(self, lr, input, p, label):
  23. # batch梯度下降,反向传播
  24. batch_size = len(label)
  25. off = p - label # 求导损失函数公式得到 (p(x) - y)* x , 先求p(x) - y, 方便后面计算
  26. for i in range(len(self.w)):
  27. error = np.dot(input[:,i].T, off) / batch_size # 这里求导得到的公式 w[i] -= lr* (p(x) - y)*xi
  28. error = error.reshape(1,)
  29. self.w[i] -= lr*error
  30. self.b -= lr * sum(off) / batch_size # b = lr*off
  31. def train(self, lr, inputs, labels, epoch):
  32. for i in range(epoch):
  33. loss, acc = [], []
  34. for input, label in zip(inputs, labels):
  35. output = self.forward(input) # wx + b
  36. p = self.sigmoid(output) # sigmoid(wx + b)
  37. label = label.reshape(output.shape)
  38. loss.append(self.cross_entropy(p, label))
  39. self.sgd(lr, input, p, label)
  40. acc.append(self.accuracy(p, label))
  41. print('epoch %d, loss %f, accuracy %f' % (i+1, np.mean(loss), np.mean(acc)))

3、迭代训练

  1. model = LogisticsRegression(num_inputs)
  2. print(model)
  3. model.train(1, X, Y, 40)
  4. print(model)

训练过程:

训练出来的分割线:

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/72122
推荐阅读
相关标签
  

闽ICP备14008679号