HY-MT1.5-1.8B移动端集成实战教程
2026/1/10 16:38:22
1.不需要训练,仅仅获取样本的异常因子
实现代码:
# !/usr/bin/python # -*- coding:utf-8 -*- import numpy as np import matplotlib import matplotlib.pyplot as plt from sklearn.neighbors import LocalOutlierFactor print(__doc__) # 设置中文字体以避免显示为方框 plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans'] plt.rcParams['axes.unicode_minus'] = False # 解决负号显示为方框的问题 ############################################################ # 生成数据 # 设置随机种子以确保结果可重现 np.random.seed(42) # 生成正常(非异常)观测数据 X = 0.3 * np.random.randn(100, 2) # 生成标准正态分布数据,乘以0.3缩小范围 X_normal = np.r_[X + 2, X - 2] # 将数据分为两部分,分别向右上和左下移动 # 生成一些异常的新观测数据 X_outliers = np.random.uniform(low=-4, high=4, size=(20, 2)) # 在[-4,4]范围内随机生成异常点 # 合并所有数据,用于异常检测 X_all = np.r_[X_normal, X_outliers] # 使用异常检测模式计算每个样本的LOF值(novelty=False是默认值) # 这样可以获取数据集中每个样本的异常分数 lof = LocalOutlierFactor(n_neighbors=10, contamination=0.1) y_pred = lof.fit_predict(X_all) # 计算所有样本的预测结果(1为正常,-1为异常) lof_scores = -lof.negative_outlier_factor_ # 获取每个样本的负LOF分数 # 打印LOF分数的统计信息 print("LOF分数统计:") print(f"最小LOF分数: {min(lof_scores):.3f} (最正常)") print(f"最大LOF分数: {max(lof_scores):.3f} (最异常)") print(f"平均LOF分数: {np.mean(lof_scores):.3f}") # 找到最可能的异常样本(LOF分数最大的样本) n_top_outliers = 10 # 显示前10个最可能的异常样本 top_outlier_indices = np.argsort(lof_scores)[::-1][:n_top_outliers] # 降序排列的索引 print(f"\n前{n_top_outliers}个最可能的异常样本:") for i, idx in enumerate(top_outlier_indices): print(f"{i+1}. 样本索引: {idx}, LOF分数: {lof_scores[idx]:.3f}, 位置: ({X_all[idx,0]:.2f}, {X_all[idx,1]:.2f})") # 统计异常样本数量 n_outliers = len(y_pred[y_pred == -1]) print(f"\nLOF算法检测到 {n_outliers} 个异常样本") # 可视化结果 plt.figure(figsize=(12, 10)) plt.title("使用LOF检测异常点 - LOF分数可视化 (分数越高越异常)") # 分离正常点和异常点 normal_points = X_all[y_pred == 1] anomaly_points = X_all[y_pred == -1] # 绘制正常点(LOF分数越低越正常) sc1 = None if len(normal_points) > 0: sc1 = plt.scatter(normal_points[:, 0], normal_points[:, 1], c=lof_scores[y_pred == 1], cmap='viridis_r', s=50, edgecolors='k', alpha=0.7, label=f'正常点 ({len(normal_points)})', vmin=min(lof_scores), vmax=max(lof_scores)) # 绘制算法检测出的异常点(红色圆圈) sc2 = None if len(anomaly_points) > 0: sc2 = plt.scatter(anomaly_points[:, 0], anomaly_points[:, 1], c=lof_scores[y_pred == -1], cmap='viridis_r', s=100, edgecolors='red', marker='o', linewidth=2, label=f'LOF检测的异常点 ({len(anomaly_points)})', vmin=min(lof_scores), vmax=max(lof_scores)) # 标记前n_top_outliers个最可能的异常样本(用黑色X标记) for idx in top_outlier_indices: plt.scatter(X_all[idx, 0], X_all[idx, 1], c='black', s=150, marker='x', linewidth=3, label=f'最异常样本 (LOF={lof_scores[idx]:.2f})' if idx == top_outlier_indices[0] else "") # 添加颜色条显示LOF分数 # 我们使用其中一个scatter plot对象来创建colorbar scatter_to_use = sc1 if sc1 is not None else sc2 if scatter_to_use is not None: # cbar = plt.colorbar(scatter_to_use, label='LOF分数 (越高越异常)') cbar = plt.colorbar(scatter_to_use, label='LOF分数 (越高越异常)', pad=0.03) # 添加pad参数微调位置 # 将colorbar位置设置在左侧 cbar.ax.yaxis.set_ticks_position('left') # cbar.ax.yaxis.set_label_position('left') plt.xlabel('特征 1') plt.ylabel('特征 2') plt.legend(loc='upper left', bbox_to_anchor=(1.10, 1)) plt.grid(True, alpha=0.3) # 根据项目规范,以300 DPI保存图片 plt.savefig('lof_anomaly_detection.png', dpi=300, bbox_inches='tight') plt.show() # 额外的可视化:LOF分数直方图 plt.figure(figsize=(10, 6)) plt.hist(lof_scores, bins=50, edgecolor='black', alpha=0.7) plt.title('LOF分数分布直方图') plt.xlabel('LOF分数') plt.ylabel('样本数量') plt.grid(True, alpha=0.3) # 标记LOF算法检测的异常点的LOF分数阈值 threshold = min(lof_scores[y_pred == -1]) if len(anomaly_points) > 0 else np.percentile(lof_scores, 90) plt.axvline(x=threshold, color='red', linestyle='--', label=f'异常阈值: {threshold:.2f}') plt.legend() # 根据项目规范,以300 DPI保存图片 plt.savefig('lof_score_histogram.png', dpi=300, bbox_inches='tight') plt.show()2.需要训练的方式(新奇检测)、分为训练集和测试集
实现代码:
# !/usr/bin/python # -*- coding:utf-8 -*- import numpy as np import matplotlib import matplotlib.pyplot as plt from sklearn.neighbors import LocalOutlierFactor print(__doc__) # 设置中文字体以避免显示为方框 plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans'] plt.rcParams['axes.unicode_minus'] = False # 解决负号显示为方框的问题 # 设置随机种子以确保结果可重现 np.random.seed(42) # 创建网格用于可视化决策边界 xx, yy = np.meshgrid(np.linspace(-5, 5, 500), np.linspace(-5, 5, 500)) # 生成正常(非异常)训练观测数据 X = 0.3 * np.random.randn(100, 2) # 生成标准正态分布数据,乘以0.3缩小范围 X_train = np.r_[X + 2, X - 2] # 将数据分为两部分,分别向右上和左下移动 # 生成新的正常(非异常)观测数据 X = 0.3 * np.random.randn(20, 2) # 生成较小的测试集 X_test = np.r_[X + 2, X - 2] # 同样分为两部分 # 生成一些异常的新观测数据 X_outliers = np.random.uniform(low=-4, high=4, size=(20, 2)) # 在[-4,4]范围内随机生成异常点 # 使用新奇性检测模型拟合数据 (novelty=True) # LocalOutlierFactor通常用于异常检测,但设置novelty=True后可用于新奇检测 clf = LocalOutlierFactor(n_neighbors=20, novelty=True, contamination=0.1) clf.fit(X_train) # 在训练数据上拟合模型 # 注意:不要在X_train上使用predict、decision_function和score_samples方法 # 这会给出错误的结果,只应在新的未见数据上使用,如X_test、X_outliers或网格数据 y_pred_test = clf.predict(X_test) # 预测测试数据 y_pred_outliers = clf.predict(X_outliers) # 预测异常数据 n_error_test = y_pred_test[y_pred_test == -1].size # 计算测试数据中被误分类的数量 n_error_outliers = y_pred_outliers[y_pred_outliers == 1].size # 计算异常数据中被误分类的数量 # 绘制学习到的边界、数据点和边界上的最近向量 # 计算网格点上的决策函数值 Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) # 将决策函数值重塑为网格形状 # 绘制图形 plt.title("使用LOF进行新奇检测") # 设置图形标题 plt.contourf(xx, yy, Z, levels=np.linspace(Z.min(), 0, 7), cmap=plt.cm.PuBu) # 填充等高线图(负值区域) a = plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors='darkred') # 绘制决策边界(0值等高线) plt.contourf(xx, yy, Z, levels=[0, Z.max()], colors='palevioletred') # 填充等高线图(正值区域) # 设置散点大小 s = 40 # 绘制训练数据点(白色圆点,黑色边框) b1 = plt.scatter(X_train[:, 0], X_train[:, 1], c='white', s=s, edgecolors='k') # 绘制测试数据点(紫罗兰色圆点,黑色边框) b2 = plt.scatter(X_test[:, 0], X_test[:, 1], c='blueviolet', s=s, edgecolors='k') # 绘制异常数据点(金色圆点,黑色边框) c = plt.scatter(X_outliers[:, 0], X_outliers[:, 1], c='gold', s=s, edgecolors='k') # 设置坐标轴 plt.axis('tight') plt.xlim((-5, 5)) # x轴范围 plt.ylim((-5, 5)) # y轴范围 # 修复collections属性错误 - 处理不同matplotlib版本的兼容性问题 try: # 尝试获取contour的collection contour_collection = a.collections[0] except AttributeError: # 如果失败,使用contour对象本身 contour_collection = a # 添加图例 plt.legend([contour_collection, b1, b2, c], ["学习到的边界", "训练观测", "新的正常观测", "新的异常观测"], loc="upper left", prop=matplotlib.font_manager.FontProperties(size=11)) # 添加x轴标签,显示错误统计信息 plt.xlabel( "新正常观测错误: %d/40 ; 新异常观测错误: %d/40" % (n_error_test, n_error_outliers)) # 根据项目规范,以300 DPI保存图片 plt.savefig('lof_novelty_detection.png', dpi=300, bbox_inches='tight') plt.show()