基于 Logistic Regression 逻辑斯蒂回归对鸢尾花分类

    1. import numpy as np
    2. import pandas as pd
    1. data = pd.read_csv(r"dataset/iris.arff.csv", header=0)
    2. # data.drop(["Id"], axis=1, inplace=True)
    3. data.drop_duplicates(inplace=True)
    4. # data["class"].drop_duplicates()
    5. # Iris-setosa Iris-versicolor Iris-virginica
    6. # 名称映射为数字
    7. data["class"] = data["class"].map({"Iris-setosa":0, "Iris-versicolor":1, "Iris-virginica":2})
    8. # 筛选数据,只选择0和1
    9. data = data[data["class"]!=2]
    1. class LogisticRegression:
    2. '''逻辑回归算法实现'''
    3. def __init__(self, learning_rate, times):
    4. '''初始化
    5. parameters
    6. -----
    7. learning_rate: float
    8. times: int
    9. '''
    10. self.learning_rate = learning_rate
    11. self.times = times
    12. def sigmoid(self, z):
    13. ''' sigmoid实现
    14. parameters:
    15. -----
    16. z: float 自变量: z=w.T*x
    17. Returns
    18. -----
    19. p: float, 属于[0,1]区间。s>=0.5(z>0)时,类别为1,否则为
    20. '''
    21. return 1.0 / ( 1.0 + np.exp(-z) )
    22. def fit(self, X, y):
    23. '''训练
    24. Parameters:
    25. X: 特征矩阵,可以是List也可以是Ndarray,形状为: [样本数量,特征数量]
    26. y: 标签数组
    27. '''
    28. X = np.asarray(X)
    29. y = np.asarray(y)
    30. # 创建权重向量,初始化为0.多出来的1是截距
    31. self.w_ = np.zeros(1 + X.shape[1]) # shape[0]为样本数量,shape[1]为特征数量
    32. # 创建损失列表,保存每次迭代后的损失值
    33. self.loss_ = []
    34. for i in range(self.times):
    35. z = np.dot(X, self.w_[1:]) + self.w_[0]
    36. # 计算概率值(判定为1的概率值)
    37. p = self.sigmoid(z)
    38. # 根据逻辑回归的代价函数(目标函数或叫损失函数)计算损失值
    39. # 逻辑回归的代价函数(目标函数或叫损失函数):
    40. # J(W) = - sum(yi * log(s(zi))+(1-yi)log(1-s(zi)))
    41. cost = - np.sum(y * np.log(p) + (1 - y) * np.log(1 - p))
    42. self.loss_.append(cost)
    43. # *****************************************************
    44. # *******************重点:权重更新********************
    45. # *****************************************************
    46. # 调整权重值,根据公式 权重(j列) = 权重(j列) + 学习率 * sum( y - s(z)) * x(j列)
    47. self.w_[0] += self.learning_rate * np.sum(y - p) * 1
    48. self.w_[1:] += self.learning_rate * np.dot(X.T, y - p)
    49. def predict_proba(self, X):
    50. '''根据参数传递的样本,对样本数据进行预测属于某一个类别的概率
    51. Parameters
    52. -----
    53. X: 类数组类型 [ 样本数量, 特征数量]
    54. Return
    55. -----
    56. result:预测(概率值)
    57. '''
    58. X = np.asarray(X)
    59. z = np.dot(X, self.w_[1:]) + self.w_[0]
    60. p = self.sigmoid(z)
    61. # 将预测结果转换为二位数组,方便后续拼接
    62. p = p.reshape(-1,1)
    63. # 将两个数组拼接,方向是横向拼接
    64. return np.concatenate([1-p, p], axis=1) #横向拼接为为1
    65. def predict(self, X):
    66. '''根据参数预测样本属于哪个类别
    67. Parameters
    68. -----
    69. X: 类数组类型: [样本数量,特征数量]. 带预测样本特征
    70. Return
    71. -----
    72. 返回属于哪个类别
    73. '''
    74. return np.argmax(self.predict_proba(X), axis=1)
    1. t1 = data[data["class"]==0]
    2. t2 = data[data["class"]==1]
    3. t1 = t1.sample(len(t1), random_state=0)
    4. t2 = t2.sample(len(t2), random_state=0)
    5. train_X = pd.concat([t1.iloc[:40,:-1], t2.iloc[:40,:-1]], axis=0)
    6. train_y = pd.concat([t1.iloc[:40,-1], t2.iloc[:40,-1]], axis=0)
    7. test_X = pd.concat([t1.iloc[40:,:-1], t2.iloc[40:,:-1]], axis=0)
    8. test_y = pd.concat([t1.iloc[40:,-1], t2.iloc[40:,-1]], axis=0)
    9. # 鸢尾花的特征列都在同一个数量级,我们可以不用标准化处理
    10. lr = LogisticRegression(learning_rate=0.01, times=20)
    11. lr.fit(train_X, train_y)
    12. # lr.predict_proba(test_X)
    13. result = lr.predict(test_X)
    14. # 计算准确性
    15. accuracy = np.sum(result==test_y) / len(test_y)
    16. display(accuracy)

    1.0

    1. import matplotlib as mpl
    2. import matplotlib.pyplot as plt
    3. mpl.rcParams['font.family'] = 'SimHei'
    4. mpl.rcParams['axes.unicode_minus'] = False
    1. # 绘制预测值
    2. plt.plot(result, 'ro',ms=15, label="预测值") # ms指定圆圈大小
    3. plt.plot(test_y.values, 'go', label="预测值") # pandas读取时serise类型,我们需要转为ndarray
    4. plt.title('逻辑回归预测')
    5. plt.xlabel('样本序号')
    6. plt.ylabel('预测值')
    7. plt.show()

    image.png

    1. # 绘制目标函数的损失值
    2. plt.plot(range(1,lr.times+1), lr.loss_, 'go-')
    3. plt.xlabel('迭代次数')
    4. plt.ylabel('损失值loss')

    Text(0, 0.5, ‘损失值loss’)

    image.png