找回密码
 立即注册
首页 业界区 业界 彩笔运维勇闯机器学习--KNN算法

彩笔运维勇闯机器学习--KNN算法

仟仞 9 小时前
前言

彩笔运维勇闯机器学习:KNN算法,它也是分类中的一种
开始探索

scikit-learn
  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. from sklearn.model_selection import train_test_split
  4. from sklearn.preprocessing import StandardScaler
  5. from sklearn.neighbors import KNeighborsClassifier
  6. from sklearn.metrics import classification_report, confusion_matrix
  7. np.random.seed(0)
  8. x0 = np.random.randn(60, 2) * 0.6 + np.array([1, 2])
  9. x1 = np.random.randn(30, 2) * 0.6 + np.array([3, 4])
  10. x2 = np.random.randn(10, 2) * 0.6 + np.array([1, 5])
  11. X = np.vstack((x0, x1, x2))
  12. y = np.array([0]*60 + [1]*30 + [2]*10)
  13. X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
  14. scaler = StandardScaler()
  15. X_train_std = scaler.fit_transform(X_train)
  16. X_test_std = scaler.transform(X_test)
  17. k = 5
  18. knn = KNeighborsClassifier(n_neighbors=k)
  19. knn.fit(X_train_std, y_train)
  20. y_pred = knn.predict(X_test_std)
  21. def plot_knn_decision(X, y, model):
  22.     h = 0.02
  23.     x_min, x_max = X[:, 0].min()-1, X[:, 0].max()+1
  24.     y_min, y_max = X[:, 1].min()-1, X[:, 1].max()+1
  25.     xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
  26.                          np.arange(y_min, y_max, h))
  27.     Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
  28.     Z = Z.reshape(xx.shape)
  29.     plt.figure(figsize=(8,6))
  30.     plt.contourf(xx, yy, Z, cmap=plt.cm.Pastel2)
  31.     plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k', cmap=plt.cm.Set1)
  32.     plt.grid(True)
  33.     plt.show()
  34. plot_knn_decision(X_train_std, y_train, knn)
复制代码
这是一个三分类的数据,分类0有60个,分类1有30个,分类2有10个
脚本!启动:
1.png

深入理解KNN

KNN算法属于惰性学习,没有所谓的数据训练的过程。它把训练数据暂时保存,当有新的数据需要进行分类时,再使用训练数据进行对应的计算,而这个计算算法常见的是欧氏距离

\[d(A, B) = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}\]
下面用一个例子来加深一下算法的过程
举例说明

假设有以下训练数据
x1x2类别A120B230C331D651E7211)由于是惰性学习,训练数据就先放着备用
2)假设有一个测试数据,T(3,4),需要对他进行分类
对每一个点分别计算:

  • A点,(1,2),\(D_A=\sqrt{(3-1)^2+(4-2)^2} \approx 2.83\)
  • B点,(2,3),\(D_A=\sqrt{(3-2)^2+(4-3)^2} \approx 1.41\)
  • C点,(3,3),\(D_A=\sqrt{(3-3)^2+(4-3)^2} = 1\)
  • D点,(6,5),\(D_A=\sqrt{(3-6)^2+(4-5)^2} \approx 3.16\)
  • E点,(7,8),\(D_A=\sqrt{(3-7)^2+(4-8)^2} \approx 5.66\)
3)设置超参数K=3,选择3个距离最小作为邻居
邻居距离类别C11B1.410A2.8304)投票,少数服从多数,T(3,4)的类别是0
小结

KNN算法的优点是简单直接,非常容易理解。缺点也很明显,由于是惰性计算,面对高维的、数据量非常大的数据,往往需要大量的计算才能进行分类,并且对于每一个测试数据都需要“遍历所有训练数据”来计算距离,这在大规模 数据集上会变得非常慢。
异常检测

在之前讨论分类问题的时候,遇到了所谓的“类别不平衡”问题,就是多数类占据样本的大量,而少数类只占用非常少的样本,导致分类算法对于少数类不能正确分类,需要做额外的处理
在实际工作中,“类别不平衡”问题有着非常重要的实践,比如有100w的日志,怎么精准识别出10条异常日志,除了10条日常,其余999990条日志都属于正常日志。对于这种问题又叫做“异常检测”,对于“异常检测”问题,有一些算法是比较擅长处理的,比如KNN算法
举例说明

在下列数据中,找出异常点
x1x2A12B23C33D65E721)算法没变,还是使用欧式距离公式
A(1,2)B(2,3)C(3,3)D(6,5)E(7,8)A(1,2)-1.412.835.838.49B(2,3)1.41-14.246.71C(3,3)2.831-3.615.83D(6,5)5.834.243.61-3.16E(7,8)8.496.715.833.16-2)设置超参数K=2,找到最近的2个邻居计算平均距离

  • A最近的邻居:(1.41 2.83),\(D_A=2.12\)
  • B最近的邻居:(1 1.41),\(D_B=1.21\)
  • C最近的邻居:(1 2.83),\(D_C=1.91\)
  • D最近的邻居:(3.16 3.61),\(D_D=3.39\)
  • E最近的邻居:(3.16 5.83),\(D_E=4.5\)
3)找出异常点

  • 如果要找出最异常的,那就是E点
  • 如果要找出2个的异常点,那就是D与E
scikit-learn
  1. import numpy as np
  2. from sklearn.neighbors import NearestNeighbors
  3. np.random.seed(42)
  4. X_normal = np.random.randn(100, 2)
  5. X_outliers = np.array([[5, 5], [-5, -5], [6, -6]])
  6. X = np.vstack((X_normal, X_outliers))
  7. k = 3
  8. nbrs = NearestNeighbors(n_neighbors=k)
  9. nbrs.fit(X)
  10. distances, _ = nbrs.kneighbors(X)
  11. k_dist = distances[:, -1]
  12. n_outliers = 3
  13. threshold = np.partition(k_dist, -n_outliers)[-n_outliers]
  14. outlier_mask = k_dist >= threshold
  15. outliers = X[outlier_mask]
  16. print("异常点坐标:")
  17. print(outliers)
复制代码
脚本!启动:
2.png

画图分析
  1. import matplotlib.pyplot as plt
  2. plt.figure(figsize=(8,6))
  3. plt.scatter(X[:, 0], X[:, 1], c='blue')
  4. plt.scatter(outliers[:, 0], outliers[:, 1], c='red', edgecolors='black', s=100)
  5. plt.legend()
  6. plt.grid(True)
  7. plt.show()
复制代码
3.png

KNN增强版本LOF

局部离群因子(LOF)算法,专门用于异常检测
  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. from sklearn.neighbors import LocalOutlierFactor
  4. X = np.array([
  5.     [1, 2],
  6.     [2, 3],
  7.     [3, 3],
  8.     [6, 5],
  9.     [7, 9],
  10.     [20, 20],
  11. ])
  12. k = 2
  13. lof = LocalOutlierFactor(n_neighbors=k, contamination=0.3)
  14. y_pred = lof.fit_predict(X)
  15. anomaly_scores = lof.negative_outlier_factor_
  16. for i, (point, label, score) in enumerate(zip(X, y_pred, anomaly_scores)):
  17.     status = "异常" if label == -1 else "正常"
  18.     print(f"点 {i}: 坐标={point}, 状态={status}, LOF分数={score:.3f}")
复制代码

  • n_neighbors=2,就是超参数k,用来选择邻居数
  • contamination=0.3,表示有30%的数据为异常
脚本!启动:
4.png

两种算法的对比

KNNLOF功能查找最近邻居检测局部异常输出每个点最近的 k 个邻居及其距离每个点的异常标签(1 或 -1)和 LOF 分数适用任务查找最近的用户/商品/样本检测数据中的异常点是否计算异常否是(negative_outlier_factor_)参数n_neighbors 只是最近邻个数n_neighbors, contamination 控制邻居数和异常比例小结


  • 联系我,做深入的交流
    5.bmp

至此,本文结束
在下才疏学浅,有撒汤漏水的,请各位不吝赐教...

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册