逻辑斯谛回归(LR)是经典的分类方法

1.逻辑斯谛回归模型是由以下条件概率分布表示的分类模型。逻辑斯谛回归模型可以用于二类多类分类
逻辑斯谛回归 - 图1

逻辑斯谛回归 - 图2

这里,x为输入特征,w为特征的权值。

逻辑斯谛回归模型源自逻辑斯谛分布,其分布函数F(x)是S形函数。逻辑斯谛回归模型是由输入的线性函数表示的输出的对数几率模型。
image.png

2.最大熵模型是由以下条件概率分布表示的分类模型。最大熵模型也可以用于二类或多类分类。

逻辑斯谛回归 - 图4

逻辑斯谛回归 - 图5

其中,逻辑斯谛回归 - 图6是规范化因子,逻辑斯谛回归 - 图7为特征函数,逻辑斯谛回归 - 图8为特征的权值。

3.最大熵模型可以由最大熵原理推导得出。最大熵原理是概率模型学习或估计的一个准则。最大熵原理认为在所有可能的概率模型(分布)的集合中,熵最大的模型是最好的模型。
最大熵原理应用到分类模型的学习中,有以下约束最优化问题:

逻辑斯谛回归 - 图9
逻辑斯谛回归 - 图10

逻辑斯谛回归 - 图11
求解此最优化问题的对偶问题得到最大熵模型。

4.逻辑斯谛回归模型与最大熵模型都属于对数线性模型

5.逻辑斯谛回归模型及最大熵模型学习一般采用极大似然估计,或正则化的极大似然估计。逻辑斯谛回归模型及最大熵模型学习可以形式化为无约束最优化问题。求解该最优化问题的算法有改进的迭代尺度法梯度下降法拟牛顿法

回归模型:逻辑斯谛回归 - 图12
其中wx线性函数:逻辑斯谛回归 - 图13

  1. from math import exp
  2. import numpy as np
  3. import pandas as pd
  4. import matplotlib.pyplot as plt
  5. %matplotlib inline
  6. from sklearn.datasets import load_iris
  7. from sklearn.model_selection import train_test_split
  8. # data
  9. def create_data():
  10. iris = load_iris()
  11. df = pd.DataFrame(iris.data, columns=iris.feature_names)
  12. df['label'] = iris.target
  13. df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']
  14. data = np.array(df.iloc[:100, [0,1,-1]])
  15. # print(data)
  16. return data[:,:2], data[:,-1]
  17. X, y = create_data()
  18. X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
  19. class LogisticReressionClassifier:
  20. def __init__(self, max_iter=200, learning_rate=0.01):
  21. self.max_iter = max_iter
  22. self.learning_rate = learning_rate
  23. def sigmoid(self, x):
  24. return 1 / (1 + exp(-x))
  25. def data_matrix(self, X):
  26. data_mat = []
  27. for d in X:
  28. data_mat.append([1.0, *d])
  29. return data_mat
  30. def fit(self, X, y):
  31. # label = np.mat(y)
  32. data_mat = self.data_matrix(X) # m*n
  33. self.weights = np.zeros((len(data_mat[0]), 1), dtype=np.float32)
  34. for iter_ in range(self.max_iter):
  35. for i in range(len(X)):
  36. result = self.sigmoid(np.dot(data_mat[i], self.weights))
  37. error = y[i] - result
  38. self.weights += self.learning_rate * error * np.transpose([data_mat[i]])
  39. print('LogisticRegression Model(learning_rate={},max_iter={})'.format(
  40. self.learning_rate, self.max_iter))
  41. # def f(self, x):
  42. # return -(self.weights[0] + self.weights[1] * x) / self.weights[2]
  43. def score(self, X_test, y_test):
  44. right = 0
  45. X_test = self.data_matrix(X_test)
  46. for x, y in zip(X_test, y_test):
  47. result = np.dot(x, self.weights)
  48. if (result > 0 and y == 1) or (result < 0 and y == 0):
  49. right += 1
  50. return right / len(X_test)
  51. lr_clf = LogisticReressionClassifier()
  52. lr_clf.fit(X_train, y_train)
  53. LogisticRegression Model(learning_rate=0.01,max_iter=200)
  54. lr_clf.score(X_test, y_test)
  55. Out[6]:
  56. 0.9666666666666667
  57. x_ponits = np.arange(4, 8)
  58. y_ = -(lr_clf.weights[1]*x_ponits + lr_clf.weights[0])/lr_clf.weights[2] # 绘制直线
  59. plt.plot(x_ponits, y_)
  60. #lr_clf.show_graph()
  61. plt.scatter(X[:50,0],X[:50,1], label='0') # 绘制离散点
  62. plt.scatter(X[50:,0],X[50:,1], label='1')
  63. plt.legend()


image.png

scikit-learn实例

sklearn.linear_model.LogisticRegression

solver参数决定了我们对逻辑回归损失函数的优化方法,有四种算法可以选择,分别是:

  • a) liblinear:使用了开源的liblinear库实现,内部使用了坐标轴下降法来迭代优化损失函数。
  • b) lbfgs:拟牛顿法的一种,利用损失函数二阶导数矩阵即海森矩阵来迭代优化损失函数。
  • c) newton-cg:也是牛顿法家族的一种,利用损失函数二阶导数矩阵即海森矩阵来迭代优化损失函数。
  • d) sag:即随机平均梯度下降,是梯度下降法的变种,和普通梯度下降法的区别是每次迭代仅仅用一部分的样本来计算梯度,适合于样本数据多的时候。
  1. from sklearn.linear_model import LogisticRegression
  2. clf = LogisticRegression(max_iter=200)
  3. clf.fit(X_train, y_train)
  4. Out[10]:
  5. LogisticRegression(max_iter=200)
  6. clf.score(X_test, y_test)
  7. Out[11]:
  8. 0.9666666666666667
  9. print(clf.coef_, clf.intercept_)
  10. [[ 2.59546005 -2.81261232]] [-5.08164524]
  11. x_ponits = np.arange(4, 8)
  12. y_ = -(clf.coef_[0][0]*x_ponits + clf.intercept_)/clf.coef_[0][1]
  13. plt.plot(x_ponits, y_)
  14. plt.plot(X[:50, 0], X[:50, 1], 'bo', color='blue', label='0')
  15. plt.plot(X[50:, 0], X[50:, 1], 'bo', color='orange', label='1')
  16. plt.xlabel('sepal length')
  17. plt.ylabel('sepal width')
  18. plt.legend()


image.png

最大熵模型

  1. import math
  2. from copy import deepcopy
  3. class MaxEntropy:
  4. def __init__(self, EPS=0.005):
  5. self._samples = []
  6. self._Y = set() # 标签集合,相当去去重后的y
  7. self._numXY = {} # key为(x,y),value为出现次数
  8. self._N = 0 # 样本数
  9. self._Ep_ = [] # 样本分布的特征期望值
  10. self._xyID = {} # key记录(x,y),value记录id号
  11. self._n = 0 # 特征键值(x,y)的个数
  12. self._C = 0 # 最大特征数
  13. self._IDxy = {} # key为(x,y),value为对应的id号
  14. self._w = []
  15. self._EPS = EPS # 收敛条件
  16. self._lastw = [] # 上一次w参数值
  17. def loadData(self, dataset):
  18. self._samples = deepcopy(dataset)
  19. for items in self._samples:
  20. y = items[0]
  21. X = items[1:]
  22. self._Y.add(y) # 集合中y若已存在则会自动忽略
  23. for x in X:
  24. if (x, y) in self._numXY:
  25. self._numXY[(x, y)] += 1
  26. else:
  27. self._numXY[(x, y)] = 1
  28. self._N = len(self._samples) # 样本数
  29. self._n = len(self._numXY) # 特征键值(x,y)的个数
  30. self._C = max([len(sample) - 1 for sample in self._samples]) # 最大特征数
  31. self._w = [0] * self._n
  32. self._lastw = self._w[:] # 上一次w参数值
  33. self._Ep_ = [0] * self._n # 样本分布的特征期望值
  34. for i, xy in enumerate(self._numXY): # 计算特征函数fi关于经验分布的期望
  35. self._Ep_[i] = self._numXY[xy] / self._N
  36. self._xyID[xy] = i
  37. self._IDxy[i] = xy
  38. def _Zx(self, X): # 计算每个Z(x)值
  39. zx = 0
  40. for y in self._Y:
  41. ss = 0
  42. for x in X:
  43. if (x, y) in self._numXY:
  44. ss += self._w[self._xyID[(x, y)]]
  45. zx += math.exp(ss)
  46. return zx
  47. def _model_pyx(self, y, X): # 计算每个P(y|x)
  48. zx = self._Zx(X)
  49. ss = 0
  50. for x in X:
  51. if (x, y) in self._numXY:
  52. ss += self._w[self._xyID[(x, y)]]
  53. pyx = math.exp(ss) / zx
  54. return pyx
  55. def _model_ep(self, index): # 计算特征函数fi关于模型的期望
  56. x, y = self._IDxy[index]
  57. ep = 0
  58. for sample in self._samples:
  59. if x not in sample:
  60. continue
  61. pyx = self._model_pyx(y, sample)
  62. ep += pyx / self._N
  63. return ep
  64. def _convergence(self): # 判断是否全部收敛
  65. for last, now in zip(self._lastw, self._w):
  66. if abs(last - now) >= self._EPS:
  67. return False
  68. return True
  69. def predict(self, X): # 计算预测概率
  70. Z = self._Zx(X)
  71. result = {}
  72. for y in self._Y:
  73. ss = 0
  74. for x in X:
  75. if (x, y) in self._numXY:
  76. ss += self._w[self._xyID[(x, y)]]
  77. pyx = math.exp(ss) / Z
  78. result[y] = pyx
  79. return result
  80. def train(self, maxiter=1000): # 训练数据
  81. for loop in range(maxiter): # 最大训练次数
  82. print("iter:%d" % loop)
  83. self._lastw = self._w[:]
  84. for i in range(self._n):
  85. ep = self._model_ep(i) # 计算第i个特征的模型期望
  86. self._w[i] += math.log(self._Ep_[i] / ep) / self._C # 更新参数
  87. print("w:", self._w)
  88. if self._convergence(): # 判断是否收敛
  89. break
  90. dataset = [['no', 'sunny', 'hot', 'high', 'FALSE'],
  91. ['no', 'sunny', 'hot', 'high', 'TRUE'],
  92. ['yes', 'overcast', 'hot', 'high', 'FALSE'],
  93. ['yes', 'rainy', 'mild', 'high', 'FALSE'],
  94. ['yes', 'rainy', 'cool', 'normal', 'FALSE'],
  95. ['no', 'rainy', 'cool', 'normal', 'TRUE'],
  96. ['yes', 'overcast', 'cool', 'normal', 'TRUE'],
  97. ['no', 'sunny', 'mild', 'high', 'FALSE'],
  98. ['yes', 'sunny', 'cool', 'normal', 'FALSE'],
  99. ['yes', 'rainy', 'mild', 'normal', 'FALSE'],
  100. ['yes', 'sunny', 'mild', 'normal', 'TRUE'],
  101. ['yes', 'overcast', 'mild', 'high', 'TRUE'],
  102. ['yes', 'overcast', 'hot', 'normal', 'FALSE'],
  103. ['no', 'rainy', 'mild', 'high', 'TRUE']]
  104. maxent = MaxEntropy()
  105. x = ['overcast', 'mild', 'high', 'FALSE']
  106. maxent.loadData(dataset)
  107. maxent.train()
  108. print('predict:', maxent.predict(x))
  109. predict: {'yes': 0.9999971802186581, 'no': 2.819781341881656e-06}