目录
1、逻辑回归(Logistic Regression)—— 最简单的分类 “基准线”
1.1、通俗理解
1.2、核心原理
1.3、关键公式解析
1.4、实战技巧
1.5、案列
1.5.1、完整代码
1.5.2、实验结果
2、决策树(Decision Tree)—— 像 “问路” 一样做判断
2.1、通俗理解
2.2、核心原理
2.3、关键公式解析
2.4、实战技巧
2.5、案例
2.5.1、完整代码
2.5.2、实验结果
3、随机森林(Random Forest)——“众人拾柴火焰高”
3.1、通俗理解
3.2、核心原理
3.3、关键优势
3.4、实战技巧
3.5、示例
3.5.1、完整代码
3.5.2、实验结果
4、支持向量机(SVM)—— 找 “最宽的分隔带”
4.1、通俗理解
4.2、核心原理
4.3、关键公式解析
4.4、实战技巧
4.5、示例
4.5.1、完整代码
4.5.2、实验结果
5、K 近邻(KNN)——“跟着邻居学样”
5.1、通俗理解
5.2、核心原理
5.3、关键参数
5.4、实战技巧
5.5、示例
5.5.1、完整代码
5.5.2、实验结果
下文:
区别:十大算法全景对比表(新增维度)
总结:如何选对算法?
分类算法是机器学习中最核心的技术之一,它能让计算机从已知数据中学习规律,对新数据的类别做出判断。本文将用通俗的语言拆解十大分类算法,帮你真正吃透每种算法的本质。
1、逻辑回归(Logistic Regression)—— 最简单的分类 “基准线”
1.1、通俗理解
逻辑回归就像一个 “概率计算器”,它先通过线性公式算出一个 “分数”,再把这个分数转换成 0-1 之间的概率(比如 “用户点击广告的概率是 80%”),最后用 0.5 作为阈值判断类别(>0.5 为 “会点击”,否则为 “不会”)。
1.2、核心原理
线性得分:先用线性模型计算样本的得分(w是权重,x是特征,b是偏置)。概率转换:通过 Sigmoid 函数把得分z压缩到 [0,1],得到属于正类的概率:(当z=0时,;z越大,概率越接近 1;z越小,越接近 0)分类判断:若,预测为正类(1);否则为负类(0)。
1.3、关键公式解析
Sigmoid 函数的魔力:它能把无限范围的z“挤” 进 0-1,正好对应概率的取值范围。损失函数(交叉熵损失):用来衡量预测概率与真实标签的差距,公式为: (y是真实标签 0/1,是预测概率)
1.4、实战技巧
必须做特征缩放(如标准化),否则权重会受特征单位影响(比如 “身高” 以米为单位和以厘米为单位,权重差异很大)。对不平衡数据,可调整阈值(比如少数类重要时,用 0.3 作为阈值提高召回率)。
1.5、案列
用逻辑回归预测 “贷款违约”:特征包括收入、负债、信用分,模型算出某用户违约概率 0.7,超过 0.5,预测为 “会违约”。
1.5.1、完整代码
"""
文件名: Loan_Default_Prediction
作者: 墨尘
日期: 2025/7/28
项目名: llm_finetune
备注: 本代码使用逻辑回归模型预测贷款违约,特征包括收入、负债、信用分
"""
# 导入必要的库
import numpy as np # 用于数值计算和数组操作
import matplotlib.pyplot as plt # 用于数据可视化
import pandas as pd # 用于数据处理
from sklearn.datasets import make_classification # 用于生成虚拟分类数据集
from sklearn.linear_model import LogisticRegression # 导入逻辑回归模型
from sklearn.model_selection import train_test_split, cross_val_score, learning_curve # 数据分割、交叉验证、学习曲线工具
from sklearn.metrics import confusion_matrix, roc_curve, auc, accuracy_score, precision_score, recall_score, f1_score # 模型评估指标
from sklearn.preprocessing import StandardScaler # 特征标准化(贷款数据通常需要标准化)
# 设置中文显示,避免可视化时中文乱码
plt.rcParams["font.family"] = ["SimHei"] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示为方块的问题
if __name__ == '__main__': # 主程序入口
# 生成贷款违约相关的虚拟数据集(3个特征:收入、负债、信用分)
# 生成基础数据(1000个样本,3个特征,二分类)
X, y = make_classification(
n_samples=1000, # 样本数量:1000个贷款申请人
n_features=3, # 特征数量:3个(收入、负债、信用分)
n_classes=2, # 类别:0=不违约,1=违约
n_informative=3, # 3个特征均对违约有影响
n_redundant=0, # 无冗余特征
random_state=42 # 随机种子,保证结果可复现
)
# 将特征转换为实际业务含义(调整数值范围使其符合现实意义)
# 收入:缩放为3-15万元/年
X[:, 0] = X[:, 0] * 2 + 9 # 均值9,范围约3-15
# 负债:缩放为0-5万元
X[:, 1] = (X[:, 1] + 2) * 1.25 # 范围约0-5
# 信用分:缩放为300-850分(常见信用分范围)
X[:, 2] = (X[:, 2] + 2) * 137.5 + 300 # 范围300-850
# 转换为DataFrame便于处理
df = pd.DataFrame(X, columns=['收入(万元/年)', '负债(万元)', '信用分'])
df['是否违约'] = y
X = df[['收入(万元/年)', '负债(万元)', '信用分']].values # 特征矩阵
y = df['是否违约'].values # 标签(0=不违约,1=违约)
# 数据探索性分析(EDA):了解贷款数据分布
plt.figure(figsize=(15, 5)) # 创建画布
# 子图1:三个特征的分布(箱线图)
plt.subplot(1, 2, 1)
plt.boxplot(X)
plt.title('贷款申请人特征分布')
plt.xticks(range(1, X.shape[1] + 1), ['收入(万元/年)', '负债(万元)', '信用分'])
plt.ylabel('数值')
# 子图2:违约与不违约的样本数量
plt.subplot(1, 2, 2)
# 修正变量名,使用英文或拼音避免中文变量名
default_count = len(y[y == 1]) # 违约数量(标签为1的样本数)
non_default_count = len(y[y == 0]) # 不违约数量(标签为0的样本数)
plt.bar(['不违约', '违约'], [non_default_count, default_count], color=['green', 'red'])
plt.title('贷款违约情况分布')
plt.ylabel('申请人数量')
# 在柱状图上标注具体数量
plt.text(0, non_default_count + 10, f'{non_default_count}人', ha='center')
plt.text(1, default_count + 10, f'{default_count}人', ha='center')
plt.tight_layout() # 自动调整布局
plt.savefig('贷款数据探索.png') # 保存图片
plt.close() # 关闭画布
# 数据预处理:特征标准化(逻辑回归对特征尺度敏感,标准化后性能更稳定)
scaler = StandardScaler() # 初始化标准化器
X_scaled = scaler.fit_transform(X) # 对特征进行标准化(均值为0,标准差为1)
# 数据集分割:70%训练,30%测试
X_train, X_test, y_train, y_test = train_test_split(
X_scaled, y,
test_size=0.3, # 测试集占30%
random_state=42 # 随机种子,保证分割结果可复现
)
# 创建并训练逻辑回归模型(贷款违约预测模型)
# class_weight='balanced':自动平衡类别权重,应对可能的样本不平衡问题
model = LogisticRegression(class_weight='balanced')
model.fit(X_train, y_train) # 用训练数据训练模型,学习特征与违约的关系
# 模型预测
y_pred = model.predict(X_test) # 预测类别:0=不违约,1=违约
y_prob = model.predict_proba(X_test)[:, 1] # 预测为违约的概率(0-1之间)
# 计算评估指标(针对贷款违约场景的业务指标)
accuracy = accuracy_score(y_test, y_pred) # 准确率:整体预测正确的比例
precision = precision_score(y_test, y_pred) # 精确率:预测为违约的客户中实际违约的比例(降低误拒优质客户的风险)
recall = recall_score(y_test, y_pred) # 召回率:实际违约客户中被正确识别的比例(降低坏账风险)
f1 = f1_score(y_test, y_pred) # F1分数:综合精确率和召回率的指标
# 打印评估结果(结合业务解读)
print(f"贷款违约预测模型评估:")
print(f"准确率: {accuracy:.4f} (整体预测正确的比例)")
print(f"精确率: {precision:.4f} (预测为违约的客户中,实际违约的比例)")
print(f"召回率: {recall:.4f} (实际违约的客户中,被正确识别的比例)")
print(f"F1分数: {f1:.4f} (综合精确率和召回率的指标)")
# 10折交叉验证(评估模型稳定性,减少数据分割带来的随机性影响)
cv_scores = cross_val_score(
LogisticRegression(class_weight='balanced'), # 待验证的模型
X_scaled, y, # 整个数据集
cv=10, # 10折交叉验证
scoring='accuracy' # 评估指标为准确率
)
# 输出交叉验证结果:均值±标准差(反映模型的平均性能和稳定性)
print(f"交叉验证准确率: {np.mean(cv_scores):.4f} ± {np.std(cv_scores):.4f}")
# 可视化评估结果(针对贷款场景调整标签,更贴合业务理解)
plt.figure(figsize=(16, 12)) # 创建大画布
# 子图1:特征重要性(展示收入、负债、信用分对违约的影响程度)
plt.subplot(2, 2, 1)
coef = model.coef_[0] # 模型系数(系数越大,该特征对违约的影响越显著)
# 正值表示该特征越高,违约概率越大;负值表示该特征越高,违约概率越小
plt.bar(['收入', '负债', '信用分'], coef, color=['blue', 'orange', 'green'])
plt.title('特征对贷款违约的影响')
plt.ylabel('系数值(正值促进违约,负值抑制违约)')
plt.axhline(y=0, color='r', linestyle='-') # 绘制y=0参考线
# 在柱状图上标注系数值
for i, v in enumerate(coef):
plt.text(i, v + 0.05, f'{v:.2f}', ha='center')
# 子图2:混淆矩阵(详细展示预测结果的分布)
plt.subplot(2, 2, 2)
cm = confusion_matrix(y_test, y_pred) # 计算混淆矩阵
# 混淆矩阵含义:
# cm[0,0]:实际不违约且预测不违约(正确)
# cm[0,1]:实际不违约但预测违约(误判,可能错失优质客户)
# cm[1,0]:实际违约但预测不违约(漏判,可能产生坏账)
# cm[1,1]:实际违约且预测违约(正确)
plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Greens) # 绘制热力图
plt.title('贷款违约预测混淆矩阵')
plt.colorbar() # 颜色条,指示数值与颜色的对应关系
plt.xticks([0, 1], ['预测不违约', '预测违约'], rotation=45)
plt.yticks([0, 1], ['实际不违约', '实际违约'])
plt.ylabel('实际情况')
plt.xlabel('预测结果')
# 在混淆矩阵上标注具体数值
thresh = cm.max() / 2 # 阈值,用于区分文字颜色(确保清晰可见)
for i, j in np.ndindex(cm.shape):
plt.text(j, i, format(cm[i, j], 'd'),
ha="center", va="center",
color="white" if cm[i, j] > thresh else "black")
# 子图3:ROC曲线(评估模型区分违约与不违约的能力)
plt.subplot(2, 2, 3)
fpr, tpr, _ = roc_curve(y_test, y_prob) # 计算假阳性率和真阳性率
roc_auc = auc(fpr, tpr) # 计算AUC值(ROC曲线下面积,越大模型性能越好)
plt.plot(fpr, tpr, color='darkorange', lw=2,
label=f'ROC曲线 (面积 = {roc_auc:.2f})')
plt.plot([0, 1], [0, 1], color='red', lw=2, linestyle='--') # 随机猜测的基准线(AUC=0.5)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('假阳性率 (错误预测为违约的比例)')
plt.ylabel('真阳性率 (正确预测为违约的比例)')
plt.title('贷款违约预测ROC曲线')
plt.legend(loc="lower right")
# 子图4:不同阈值对贷款违约预测的影响(帮助业务决策确定最佳阈值)
plt.subplot(2, 2, 4)
thresholds = [0.3, 0.4, 0.5, 0.6, 0.7] # 不同的违约概率阈值
recall_list = [] # 存储不同阈值下的召回率
precision_list = [] # 存储不同阈值下的精确率
for threshold in thresholds:
# 当预测概率大于等于阈值时,判定为违约
y_pred_threshold = (y_prob >= threshold).astype(int)
recall_list.append(recall_score(y_test, y_pred_threshold))
precision_list.append(precision_score(y_test, y_pred_threshold))
plt.plot(thresholds, recall_list, marker='o', label='召回率(识别违约的能力)')
plt.plot(thresholds, precision_list, marker='s', label='精确率(预测违约的准确性)')
plt.title('不同阈值对贷款违约预测的影响')
plt.xlabel('违约概率阈值(超过此值则预测为违约)')
plt.ylabel('指标值')
plt.legend()
plt.grid()
plt.tight_layout()
plt.savefig('贷款违约模型评估.png')
plt.close()
# 学习曲线(分析模型在不同样本量下的表现,判断是否需要更多数据)
train_sizes, train_scores, test_scores = learning_curve(
LogisticRegression(class_weight='balanced'),
X_scaled, y,
train_sizes=np.linspace(0.1, 1.0, 10), # 训练样本比例:10%到100%
cv=5, # 5折交叉验证
scoring='accuracy', # 评估指标为准确率
n_jobs=-1 # 并行计算,使用所有可用CPU核心
)
# 计算均值和标准差
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# 绘制学习曲线
plt.figure(figsize=(10, 6))
plt.plot(train_sizes, train_mean, color='blue', marker='o', label='训练集准确率')
# 填充标准差区间,展示数据波动
plt.fill_between(train_sizes, train_mean + train_std, train_mean - train_std, alpha=0.15, color='blue')
plt.plot(train_sizes, test_mean, color='green', marker='s', label='测试集准确率')
plt.fill_between(train_sizes, test_mean + test_std, test_mean - test_std, alpha=0.15, color='green')
plt.title('贷款违约预测模型学习曲线')
plt.xlabel('训练样本数量(贷款申请人数量)')
plt.ylabel('准确率')
plt.legend()
plt.grid()
plt.savefig('贷款模型学习曲线.png')
plt.close()
# 模拟实际预测场景:预测一个新用户的违约概率
# 示例用户数据:收入8万,负债2万,信用分650
new_user = np.array([[8, 2, 650]])
# 标准化(使用训练好的scaler,保证与训练数据处理方式一致)
new_user_scaled = scaler.transform(new_user)
# 预测违约概率
default_prob = model.predict_proba(new_user_scaled)[0, 1]
print(f"\n示例用户违约预测:")
print(f"收入:{new_user[0,0]}万元/年,负债:{new_user[0,1]}万元,信用分:{new_user[0,2]}分")
print(f"预测违约概率:{default_prob:.2%}") # 以百分比形式展示
# 根据阈值0.5判断结果
print(f"预测结果:{'会违约' if default_prob > 0.5 else '不会违约'}(阈值0.5)")
print("\n贷款违约预测模型训练和评估完成,结果已保存为图片文件")
1.5.2、实验结果
贷款数据探索
贷款模型学习曲线
贷款违约模型评估
贷款违约示例
2、决策树(Decision Tree)—— 像 “问路” 一样做判断
2.1、通俗理解
决策树就像我们问路时的 “分支选择”:比如 “收入是否大于 50 万?是→看工作是否稳定;否→看负债是否小于 10 万”,通过一层层提问,最终确定类别。
2.2、核心原理
特征选择:每次从特征中选一个 “最好” 的特征做分裂(比如 “收入” 比 “性别” 更能区分违约与否)。分裂标准:
信息熵(Entropy):衡量数据混乱程度,值越小越纯,是第 k 类样本占比)。信息增益:分裂后信息熵的减少量(),增益越大,特征越好。 停止条件:当子节点样本全为同一类,或树深达到上限时停止。
2.3、关键公式解析
信息熵:比如 “全是违约样本” 的熵为 0(纯),“一半违约一半不违约” 的熵为 1(最混乱)。基尼指数(CART 树用):另一种衡量纯度的指标(),计算更快,效果与熵类似。
2.4、实战技巧
剪枝是关键!预剪枝(限制树深≤5)或后剪枝(删除无用分支)可避免过拟合(比如 “收入 = 50.1 万且星座 = 水瓶→不违约” 这种极端规则)。对类别特征友好,无需编码;对连续特征,会自动找最佳分裂点(如 “收入> 50 万”)。
2.5、案例
用决策树预测 “是否购买产品”:先按 “是否浏览过详情页” 分裂,浏览过的再按 “是否加购” 分裂,最终快速锁定高概率购买用户。
2.5.1、完整代码
"""
文件名: Decision_Tree
作者: 墨尘
日期: 2025/7/28
项目名: llm_finetune
备注: 基于决策树的用户购买行为预测模型
通过用户浏览、加购等行为特征预测购买概率
特别优化了决策边界可视化的特征匹配问题
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.inspection import DecisionBoundaryDisplay
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
# 设置中文显示
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False # 确保负号正确显示
if __name__ == '__main__':
# ========================= 数据生成模块 =========================
# 设置随机种子,确保实验可复现
np.random.seed(42)
n_samples = 1000 # 生成1000个用户样本
# 核心用户行为特征1:是否浏览过详情页(0=未浏览, 1=浏览过)
viewed_detail = np.random.randint(0, 2, n_samples)
# 核心用户行为特征2:是否加入购物车(与浏览行为强相关)
added_cart = np.zeros(n_samples, dtype=int)
for i in range(n_samples):
if viewed_detail[i] == 1:
# 浏览过详情页的用户有60%概率加购
added_cart[i] = np.random.choice([0, 1], p=[0.4, 0.6])
else:
# 未浏览详情页的用户仅有10%概率加购
added_cart[i] = np.random.choice([0, 1], p=[0.9, 0.1])
# 辅助行为特征:是否收藏商品(与加购行为强相关)
favorited = np.zeros(n_samples, dtype=int)
for i in range(n_samples):
if added_cart[i] == 1:
# 已加购用户有70%概率收藏
favorited[i] = np.random.choice([0, 1], p=[0.3, 0.7])
else:
# 未加购用户仅有20%概率收藏
favorited[i] = np.random.choice([0, 1], p=[0.8, 0.2])
# 连续型特征:浏览时长(与是否浏览详情页强相关)
view_time = np.zeros(n_samples)
for i in range(n_samples):
if viewed_detail[i] == 1:
# 浏览过详情页的用户平均浏览60秒,标准差20秒
view_time[i] = np.random.normal(60, 20)
else:
# 未浏览详情页的用户平均浏览10秒,标准差5秒
view_time[i] = np.random.normal(10, 5)
# 用户属性特征:是否新用户
is_new_user = np.random.randint(0, 2, n_samples)
# 生成目标标签:是否购买(0=未购买, 1=购买)
# 基于多特征加权计算购买概率
y = np.zeros(n_samples, dtype=int)
for i in range(n_samples):
# 基础购买概率10%
base_prob = 0.1
# 核心行为特征:浏览详情页增加30%购买概率
if viewed_detail[i] == 1:
base_prob += 0.3
# 核心行为特征:加购增加40%购买概率
if added_cart[i] == 1:
base_prob += 0.4
# 辅助行为特征:收藏增加20%购买概率
if favorited[i] == 1:
base_prob += 0.2
# 用户属性特征:新用户减少10%购买概率
if is_new_user[i] == 1:
base_prob -= 0.1
# 连续型特征:浏览时长每10秒增加5%购买概率,最多增加30%
base_prob += min(view_time[i] / 10 * 0.05, 0.3)
# 确保概率在合理范围内
base_prob = np.clip(base_prob, 0, 1)
# 基于最终概率随机生成购买标签
y[i] = 1 if np.random.random() < base_prob else 0
# ========================= 数据预处理模块 =========================
# 构建特征矩阵和标签
X = np.column_stack((viewed_detail, added_cart, favorited, view_time, is_new_user))
feature_names = ['是否浏览过详情页', '是否加入购物车', '是否收藏商品', '浏览时长(秒)', '是否新用户']
class_names = ['未购买', '购买']
# 划分训练集(70%)和测试集(30%)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42
)
# ========================= 模型训练与评估模块 =========================
# 创建完整特征的决策树模型(用于最终预测)
# max_depth=3: 限制树的最大深度为3层,防止过拟合
# 优先分裂最重要的特征(浏览详情页和加购)
clf = DecisionTreeClassifier(max_depth=3, random_state=42)
clf.fit(X_train, y_train)
# 在测试集上进行预测并评估
y_pred = clf.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"模型准确率: {accuracy:.2f}")
# 输出详细分类报告(精确率、召回率、F1分数)
print("\n分类报告:")
print(classification_report(y_test, y_pred, target_names=class_names))
# 计算混淆矩阵
cm = confusion_matrix(y_test, y_pred)
print("\n混淆矩阵:")
print(cm)
# ========================= 可视化模块 =========================
# 1. 特征重要性可视化
importances = clf.feature_importances_ # 获取特征重要性分数
indices = np.argsort(importances)[::-1] # 按重要性降序排列
plt.figure(figsize=(10, 6))
plt.bar(range(X.shape[1]), importances[indices], color='teal')
plt.xticks(range(X.shape[1]), [feature_names[i] for i in indices], rotation=45)
plt.title('特征重要性')
plt.ylabel('重要性得分')
plt.tight_layout()
plt.savefig('feature_importance.png')
plt.close()
# 2. 决策边界可视化(关键修改部分)
# 提取前2个特征(仅用于绘制决策边界)
X_2d = X[:, :2] # 所有样本的前2个特征
X_train_2d = X_train[:, :2] # 训练集的前2个特征
# 训练仅使用前2个特征的决策树模型
# 这是解决特征数量不匹配问题的关键
clf_2d = DecisionTreeClassifier(max_depth=3, random_state=42)
clf_2d.fit(X_train_2d, y_train)
# 绘制决策边界(使用仅含2个特征的模型)
plt.figure(figsize=(10, 8))
DecisionBoundaryDisplay.from_estimator(
clf_2d, # 使用仅含2个特征的模型
X_2d, # 仅传入前2个特征
cmap='RdBu',
alpha=0.5,
ax=plt.gca(),
response_method='predict'
)
# 叠加散点图(显示实际数据分布)
scatter = plt.scatter(
X_2d[:, 0], # x轴: 是否浏览过详情页
X_2d[:, 1], # y轴: 是否加入购物车
c=y, # 颜色: 实际购买状态
cmap='RdBu',
edgecolor='k',
s=50
)
plt.title('决策树分类边界(是否浏览过详情页 vs 是否加购)')
plt.xlabel('是否浏览过详情页')
plt.xticks([0, 1], ['未浏览', '浏览过'])
plt.ylabel('是否加入购物车')
plt.yticks([0, 1], ['未加购', '已加购'])
plt.legend(handles=scatter.legend_elements()[0], labels=class_names)
plt.tight_layout()
plt.savefig('decision_boundary.png')
plt.close()
# 3. 完整决策树结构可视化
plt.figure(figsize=(20, 12))
plot_tree(
clf, # 使用完整特征的模型
feature_names=feature_names,
class_names=class_names,
filled=True, # 按类别填充颜色
rounded=True, # 圆角矩形
fontsize=10, # 字体大小
proportion=True # 显示样本比例而非数量
)
plt.title('产品购买预测决策树')
plt.tight_layout()
plt.savefig('decision_tree.png')
plt.close()
# ========================= 业务应用模块 =========================
# 模拟实际预测场景: 对新用户进行购买概率预测
print("\n模拟实际预测场景:")
# 创建4个典型用户案例
sample_users = np.array([
[1, 1, 1, 80, 0], # 用户1: 浏览过详情页、加购、收藏、浏览时间长、老用户(高概率购买)
[1, 0, 0, 40, 1], # 用户2: 浏览过详情页、未加购、未收藏、浏览时间中等、新用户(中低概率)
[0, 0, 0, 10, 0], # 用户3: 未浏览详情页、未加购、未收藏、浏览时间短、老用户(低概率)
[1, 1, 0, 90, 0], # 用户4: 浏览过详情页、加购、未收藏、浏览时间长、老用户(高概率)
])
# 使用完整特征模型进行预测
predictions = clf.predict(sample_users) # 预测类别(0/1)
probabilities = clf.predict_proba(sample_users)[:, 1] # 预测购买概率
# 输出预测结果
print("\n示例用户预测结果:")
for i, user in enumerate(sample_users):
print(f"\n用户{i + 1}:")
print(f" 是否浏览过详情页: {'是' if user[0] else '否'}")
print(f" 是否加入购物车: {'是' if user[1] else '否'}")
print(f" 是否收藏商品: {'是' if user[2] else '否'}")
print(f" 浏览时长: {user[3]:.1f}秒")
print(f" 是否新用户: {'是' if user[4] else '否'}")
print(f" 预测购买概率: {probabilities[i]:.2%}")
print(f" 预测结果: {'购买' if predictions[i] else '不购买'}")
2.5.2、实验结果
特征重要性分布
决策树分类边界
产品购买预测决策树
模型准确率: 0.81
分类报告: precision recall f1-score support
未购买 0.81 0.79 0.80 144 购买 0.81 0.83 0.82 156
accuracy 0.81 300 macro avg 0.81 0.81 0.81 300 weighted avg 0.81 0.81 0.81 300
混淆矩阵: [[114 30] [ 26 130]]
模拟实际预测场景:
示例用户预测结果:
用户1: 是否浏览过详情页: 是 是否加入购物车: 是 是否收藏商品: 是 浏览时长: 80.0秒 是否新用户: 否 预测购买概率: 100.00% 预测结果: 购买
用户2: 是否浏览过详情页: 是 是否加入购物车: 否 是否收藏商品: 否 浏览时长: 40.0秒 是否新用户: 是 预测购买概率: 72.27% 预测结果: 购买
用户3: 是否浏览过详情页: 否 是否加入购物车: 否 是否收藏商品: 否 浏览时长: 10.0秒 是否新用户: 否 预测购买概率: 24.84% 预测结果: 不购买
用户4: 是否浏览过详情页: 是 是否加入购物车: 是 是否收藏商品: 否 浏览时长: 90.0秒 是否新用户: 否 预测购买概率: 100.00% 预测结果: 购买
3、随机森林(Random Forest)——“众人拾柴火焰高”
3.1、通俗理解
随机森林是多棵决策树的 “投票委员会”:每棵树独立投票(预测类别),最终按多数票决定结果。通过 “随机” 让每棵树不同,避免单棵树的偏见。
3.2、核心原理
样本随机:用 Bootstrap 抽样(有放回)从训练集抽多个样本集,每个样本集训练一棵决策树(比如 100 棵树需要 100 个样本集)。特征随机:每棵树分裂时,只从随机选的部分特征中挑 “最好” 的(比如总特征 10 个,每次随机选 3 个)。投票机制:分类任务取多数票,回归任务取平均值。
3.3、关键优势
抗过拟合:单棵树可能过拟合,但多棵树投票会抵消极端规则。并行性:树之间独立,可同时训练,速度快。
3.4、实战技巧
(树的数量):越多效果越好,但超过 100 后提升有限,建议 50-200。用查看特征重要性(比如 “收入” 在 80% 的树中被选中,重要性高)。
3.5、示例
在医疗诊断中,随机森林结合 “年龄、血压、血糖” 等特征,多棵树共同判断是否患病,比单棵决策树更稳健。
3.5.1、完整代码
"""
文件名: Random_Forest
作者: 墨尘
日期: 2025/7/28
项目名: llm_finetune
备注: 基于随机森林的医疗疾病诊断模型,使用年龄、血压、血糖等10项医疗特征预测健康状态(健康/轻度疾病/重度疾病)。
核心优化点:1. 采用分层抽样确保训练集与测试集类别比例一致;2. 动态匹配实际存在的类别标签,避免评估和可视化时的标签不匹配错误;
3. 优化疾病风险计算逻辑,保证三类样本分布均衡;4. 纯matplotlib实现特征重要性可视化,不依赖seaborn;
5. 通过zero_division参数处理无预测样本类别的评估警告,提高模型稳健性。
"""
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay, classification_report
# 设置中文显示,确保图表中中文正常显示
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示为方块的问题
if __name__ == '__main__':
# 1. 生成医疗诊断虚拟数据集(模拟疾病诊断场景,优化类别均衡性)
np.random.seed(42) # 设置随机种子,保证结果可复现
n_samples = 1000 # 生成1000个患者样本
# 核心医疗特征(符合医学常识的数值范围)
age = np.random.randint(18, 90, n_samples) # 年龄:18-90岁的整数
blood_pressure = np.random.normal(120, 15, n_samples) # 血压:均值120,标准差15的正态分布
blood_sugar = np.random.normal(5.5, 1.2, n_samples) # 血糖:均值5.5mmol/L,标准差1.2
cholesterol = np.random.normal(5.2, 1.0, n_samples) # 胆固醇:均值5.2mmol/L,标准差1.0
heart_rate = np.random.normal(70, 10, n_samples) # 心率:均值70次/分,标准差10
# 辅助医疗特征(其他医学检查指标)
hemoglobin = np.random.normal(145, 15, n_samples) # 血红蛋白:均值145g/L
white_blood_cell = np.random.normal(7.5, 2.0, n_samples) # 白细胞计数:均值7.5×10^9/L
platelet = np.random.normal(300, 50, n_samples) # 血小板:均值300×10^9/L
creatinine = np.random.normal(80, 15, n_samples) # 肌酐(肾功能指标):均值80μmol/L
bilirubin = np.random.normal(15, 5, n_samples) # 胆红素(肝功能指标):均值15μmol/L
# 构建特征矩阵(组合所有特征)
X = np.column_stack((age, blood_pressure, blood_sugar, cholesterol, heart_rate,
hemoglobin, white_blood_cell, platelet, creatinine, bilirubin))
# 特征名称列表(与特征矩阵顺序对应)
feature_names = ['年龄', '血压', '血糖', '胆固醇', '心率',
'血红蛋白', '白细胞计数', '血小板', '肌酐', '胆红素']
# 生成疾病标签(0=健康,1=轻度疾病,2=重度疾病),优化计算确保类别均衡
y = np.zeros(n_samples, dtype=int) # 初始化标签为0(健康)
for i in range(n_samples):
# 计算疾病风险值(综合多个特征的影响)
risk = 0
risk += (age[i] - 50) * 0.03 # 年龄越大,风险越高(基准年龄50岁)
risk += (blood_pressure[i] - 120) * 0.04 # 血压越高,风险越高(基准120)
risk += (blood_sugar[i] - 5.5) * 0.05 # 血糖越高,风险越高(基准5.5)
risk += (cholesterol[i] - 5.2) * 0.03 # 胆固醇越高,风险越高(基准5.2)
# 加入随机扰动,增加数据多样性,避免类别过于集中
risk += np.random.normal(0, 1.5) # 均值0,标准差1.5的随机值
# 根据风险值划分疾病等级(调整阈值使三类比例均衡)
if risk > 4:
y[i] = 2 # 风险值>4:重度疾病
elif risk > 1:
y[i] = 1 # 风险值1-4:轻度疾病
else:
y[i] = 0 # 风险值≤1:健康
# 检查并打印类别分布(验证是否三类样本数量均衡)
print(f"类别分布:健康{np.sum(y==0)},轻度{np.sum(y==1)},重度{np.sum(y==2)}")
# 2. 划分训练集(70%)和测试集(30%)
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=0.3, # 测试集占比30%
random_state=42, # 固定随机种子,确保划分结果可复现
stratify=y # 分层抽样:保持训练集和测试集中各类别的比例与原数据一致
)
# 3. 创建随机森林分类器并训练
# n_estimators=100:由100棵决策树组成森林,提高模型稳定性
# random_state=42:确保训练结果可复现
clf = RandomForestClassifier(n_estimators=100, random_state=42)
clf.fit(X_train, y_train) # 用训练集数据训练模型
# 4. 模型预测
y_pred = clf.predict(X_test) # 预测测试集样本的疾病类别(0/1/2)
y_pred_proba = clf.predict_proba(X_test) # 预测每个样本属于各类别的概率(返回n×3的矩阵)
# 5. 模型评估(动态匹配实际存在的类别标签,避免标签不匹配错误)
print("\n疾病诊断模型分类报告:")
class_names = ['健康', '轻度疾病', '重度疾病'] # 所有可能的类别名称
# 提取测试集和预测结果中实际存在的所有类别(合并去重)
unique_classes = np.unique(np.concatenate([y_test, y_pred]))
# 实际存在的类别对应的名称列表
actual_class_names = [class_names[i] for i in unique_classes]
# 生成分类报告(包含精确率、召回率、F1分数等指标)
print(classification_report(y_test, y_pred,
labels=unique_classes, # 指定评估的类别(实际存在的类别)
target_names=actual_class_names, # 类别名称
zero_division=1 # 当某类别无预测样本时,精确率设为1.0(避免警告)
))
# 6. 可视化:混淆矩阵 + 特征重要性(1行2列的子图)
fig, ax = plt.subplots(1, 2, figsize=(16, 6)) # 创建画布,大小16×6英寸
# 6.1 绘制混淆矩阵(展示预测结果与实际结果的匹配情况)
# 计算混淆矩阵(仅包含实际存在的类别)
cm = confusion_matrix(y_test, y_pred, labels=unique_classes)
# 创建混淆矩阵显示对象(指定混淆矩阵和类别标签)
disp = ConfusionMatrixDisplay(
confusion_matrix=cm,
display_labels=actual_class_names
)
disp.plot(ax=ax[0], cmap='Blues') # 在第1个子图绘制,使用蓝色系颜色
ax[0].set_title('疾病诊断混淆矩阵', fontsize=14) # 设置子图标题
ax[0].set_xlabel('预测类别', fontsize=12) # x轴标签
ax[0].set_ylabel('实际类别', fontsize=12) # y轴标签
# 6.2 绘制特征重要性(展示各医疗指标对诊断的影响程度)
importances = clf.feature_importances_ # 获取每个特征的重要性得分(总和为1)
indices = np.argsort(importances)[::-1] # 特征索引按重要性从高到低排序
# 生成渐变色(从cool到warm,与特征重要性顺序对应)
colors = plt.cm.coolwarm(np.linspace(0, 1, len(indices)))
# 绘制水平条形图(y轴为特征,x轴为重要性得分)
ax[1].barh(range(len(indices)), importances[indices], color=colors, align='center')
ax[1].set_yticks(range(len(indices))) # 设置y轴刻度位置
# 设置y轴刻度标签(特征名称,按重要性排序)
ax[1].set_yticklabels([feature_names[i] for i in indices])
ax[1].set_title('医疗特征对诊断的重要性', fontsize=14) # 子图标题
ax[1].set_xlabel('重要性得分', fontsize=12) # x轴标签
ax[1].invert_yaxis() # 反转y轴,使最重要的特征显示在顶部
plt.tight_layout() # 自动调整子图间距,避免标签重叠
plt.savefig('医疗诊断模型评估.png', dpi=300) # 保存图像为PNG文件,分辨率300dpi
plt.show() # 显示图像
# 7. 模拟实际诊断场景:预测新患者的疾病情况
# 新患者的特征数据(3个示例)
new_patients = np.array([
[65, 140, 7.2, 6.1, 85, 130, 6.2, 280, 90, 18], # 患者1特征
[35, 110, 5.0, 4.8, 65, 155, 7.8, 320, 75, 12], # 患者2特征
[70, 160, 9.5, 7.0, 90, 120, 4.5, 220, 110, 25] # 患者3特征
])
# 预测新患者的疾病类别和概率
new_pred = clf.predict(new_patients) # 预测类别(0/1/2)
new_pred_proba = clf.predict_proba(new_patients) # 预测各类别的概率
# 输出新患者的诊断结果
print("\n新患者诊断结果:")
for i in range(len(new_patients)):
print(f"\n患者{i + 1}特征:")
# 打印关键特征值(年龄、血压、血糖)
print(f"年龄:{new_patients[i, 0]}岁,血压:{new_patients[i, 1]},血糖:{new_patients[i, 2]}")
# 打印预测结果和概率分布
print(f"预测结果:{class_names[new_pred[i]]}")
print(f"概率分布:健康{new_pred_proba[i, 0]:.1%},轻度{new_pred_proba[i, 1]:.1%},重度{new_pred_proba[i, 2]:.1%}")
3.5.2、实验结果
疾病诊断混淆矩阵(左图) 医疗特征对诊断的重要性(右图)
类别分布:健康685,轻度299,重度16
疾病诊断模型分类报告: precision recall f1-score support
健康 0.71 0.91 0.80 205 轻度疾病 0.47 0.19 0.27 90 重度疾病 1.00 0.00 0.00 5
accuracy 0.68 300 macro avg 0.73 0.37 0.36 300 weighted avg 0.64 0.68 0.63 300
新患者诊断结果:
患者1特征: 年龄:65.0岁,血压:140.0,血糖:7.2 预测结果:健康 概率分布:健康66.0%,轻度30.0%,重度4.0%
患者2特征: 年龄:35.0岁,血压:110.0,血糖:5.0 预测结果:健康 概率分布:健康91.0%,轻度9.0%,重度0.0%
患者3特征: 年龄:70.0岁,血压:160.0,血糖:9.5 预测结果:健康 概率分布:健康53.0%,轻度43.0%,重度4.0%
4、支持向量机(SVM)—— 找 “最宽的分隔带”
4.1、通俗理解
SVM 的目标是在两类样本间画一条线(或平面),让线到两边最近样本的距离(间隔)最大。就像在两群人中找一条路,路越宽,行人越不容易撞到人。
4.2、核心原理
线性可分:当两类样本能被直线分开时,找 “最大间隔超平面”(),满足(是 ±1,代表两类)。核函数:对非线性数据(比如 “月亮形” 分布),用核函数(如 RBF)把数据映射到高维空间,使其线性可分(比如二维不可分→三维可分)。软间隔:允许少数样本在间隔内(通过参数C控制,C越小,容忍度越高)。
4.3、关键公式解析
间隔公式:超平面到样本的距离为,最大间隔为,目标是最小化(即最大化间隔)。RBF 核:,越大,对局部样本越敏感(易过拟合)。
4.4、实战技巧
必须做特征缩放!SVM 对特征尺度敏感(比如 “收入” 以万为单位和以元为单位,间隔会差 10000 倍)。小样本高维数据(如文本分类,词袋特征维度高)效果最好,大样本数据训练慢。
4.5、示例
用 SVM 做文本分类(垃圾邮件识别):把邮件转换成词向量,SVM 找到最优分隔面,高效区分垃圾邮件和正常邮件。
4.5.1、完整代码
"""
文件名: SVM_Spam_Detection
作者: 墨尘
日期: 2025/7/29
项目名: llm_finetune
备注: 优化垃圾邮件识别模型,解决预测错误问题
"""
import numpy as np
import matplotlib.pyplot as plt
import jieba # 中文分词库(需安装:pip install jieba)
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics import accuracy_score, classification_report
# 设置中文显示
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False
# 自定义中文分词函数(使用jieba提高分词准确性)
def chinese_tokenizer(text):
return jieba.lcut(text) # 精确分词
if __name__ == '__main__':
# 1. 扩充样本量(各20封邮件,增加特征多样性)
# 垃圾邮件(包含更多典型关键词)
spam_emails = [
"免费获取会员资格,点击链接立即领取",
"限时优惠!全场商品五折,不买后悔",
"恭喜您中了一等奖,请填写银行卡信息领奖",
"无需信用检查,快速贷款,立即审批",
"兼职赚钱,日入上千,轻松在家工作",
"您的账户存在异常,请点击链接验证",
"特价促销,最后机会,错过再等一年",
"免费赠送礼品,只需支付运费即可",
"提升信用卡额度,立即联系我们",
"中奖通知:您获得了一台新款手机",
"低息贷款,无抵押,当天到账",
"点击此处,领取您的专属福利",
"免费抽奖,100%中奖,快来参与",
"您有一份未领取的奖品,点击查看",
"兼职刷单,高额佣金,立即可做",
"您的快递异常,点击链接处理",
"限时免费领取,仅限今天",
"恭喜成为幸运用户,获得万元大奖",
"无门槛优惠券,点击领取",
"您的账号已冻结,点击解封"
]
# 正常邮件
normal_emails = [
"关于下周会议的安排,请查收附件",
"您的订单已发货,快递单号是123456",
"请问这个项目的截止日期是哪天?",
"明天上午10点的会议,别忘了参加",
"您的论文修改意见已上传至系统",
"周末一起聚餐,地点在老地方",
"关于产品的使用说明,请参考文档",
"麻烦确认一下这份报表的数据",
"下周三的培训取消,另行通知",
"您的会员积分已到账,可登录查看",
"项目进度更新,请查阅最新文档",
"下周的工作计划已发送至您的邮箱",
"关于合作细节,我们再沟通一下",
"您的申请已通过,请注意查收通知",
"明天的研讨会,需要准备什么材料?",
"季度总结会议定在周五下午3点",
"请提供一下您的银行账户信息,用于转账",
"产品测试反馈已收到,正在处理",
"假期安排已公布,请注意查看",
"关于报销流程,有几点需要说明"
]
# 合并数据并创建标签(0=正常邮件,1=垃圾邮件)
emails = spam_emails + normal_emails
labels = [1] * len(spam_emails) + [0] * len(normal_emails)
y = np.array(labels)
# 2. 文本向量化:使用jieba分词,提取有效特征
# 自定义分词器,处理中文文本
vectorizer = CountVectorizer(
tokenizer=chinese_tokenizer, # 使用jieba分词
max_features=200 # 保留前200个最常见的特征词
)
X = vectorizer.fit_transform(emails)
feature_names = vectorizer.get_feature_names_out()
# 3. 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y
)
# 4. 训练SVM模型(调整参数,增强拟合能力)
svm = SVC(
kernel='linear',
C=10.0, # 增大C值(正则化参数),减少正则化强度,增强对训练数据的拟合
random_state=42,
probability=True # 开启概率预测
)
svm.fit(X_train, y_train)
# 5. 模型评估
y_pred = svm.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"模型准确率: {accuracy:.2f}")
print("\n分类报告:")
print(classification_report(y_test, y_pred, target_names=['正常邮件', '垃圾邮件'], zero_division=1))
# 6. 可视化关键特征词
coef = svm.coef_[0].toarray().flatten()
n_words = min(8, len(feature_names))
top_spam_words = np.argsort(coef)[-n_words:]
top_normal_words = np.argsort(coef)[:n_words]
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.barh(feature_names[top_spam_words], coef[top_spam_words], color='red')
plt.title('与垃圾邮件强相关的关键词')
plt.xlabel('SVM权重')
plt.subplot(1, 2, 2)
plt.barh(feature_names[top_normal_words], coef[top_normal_words], color='blue')
plt.title('与正常邮件强相关的关键词')
plt.xlabel('SVM权重')
plt.tight_layout()
plt.show()
# 7. 重新测试示例邮件
test_emails = [
"恭喜您获得免费礼品,点击领取", # 垃圾邮件
"关于项目的进度汇报,请查收" # 正常邮件
]
test_X = vectorizer.transform(test_emails)
test_pred = svm.predict(test_X)
test_prob = svm.predict_proba(test_X)
print("\n修正后的预测示例:")
for i in range(len(test_emails)):
print(f"\n邮件内容: {test_emails[i]}")
print(f"预测结果: {'垃圾邮件' if test_pred[i] == 1 else '正常邮件'}")
print(f"概率分布: 正常邮件{test_prob[i, 0]:.2%}, 垃圾邮件{test_prob[i, 1]:.2%}")
4.5.2、实验结果
模型准确率: 1.00
分类报告: precision recall f1-score support
正常邮件 1.00 1.00 1.00 6 垃圾邮件 1.00 1.00 1.00 6
accuracy 1.00 12 macro avg 1.00 1.00 1.00 12 weighted avg 1.00 1.00 1.00 12
修正后的预测示例:
邮件内容: 恭喜您获得免费礼品,点击领取 预测结果: 垃圾邮件 概率分布: 正常邮件0.32%, 垃圾邮件99.68%
邮件内容: 关于项目的进度汇报,请查收 预测结果: 正常邮件 概率分布: 正常邮件92.71%, 垃圾邮件7.29%
5、K 近邻(KNN)——“跟着邻居学样”
5.1、通俗理解
KNN 是 “看邻居猜类别”:想知道一个样本属于哪类,就看它周围最近的 K 个样本(邻居),多数邻居属于哪类,它就属于哪类。
5.2、核心原理
计算距离:用欧氏距离(或曼哈顿距离)计算样本与所有训练样本的距离()。找邻居:选距离最近的 K 个样本。投票:K 个邻居中占比最高的类别就是预测结果。
5.3、关键参数
K值:K太小易受噪声影响(比如邻居是异常点);K太大易模糊边界(比如 K = 样本总数,结果永远是多数类)。通常选奇数(避免平票),如 3、5、7。距离度量:文本数据常用余弦距离(衡量方向相似性),地理数据常用曼哈顿距离(街区距离)。
5.4、实战技巧
对高维数据效果差(“维度灾难”:高维空间中所有样本距离都差不多),需降维(如 PCA)。可给近邻加权(距离越近权重越大),比简单投票更合理。
5.5、示例
推荐系统中,KNN 找与你兴趣相似的 K 个用户,他们喜欢的商品就推荐给你。
5.5.1、完整代码
"""
文件名: KNN
作者: 墨尘
日期: 2025/7/28
项目名: llm_finetune
备注: 基于KNN的推荐系统实现
"""
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import confusion_matrix, accuracy_score
from matplotlib.colors import ListedColormap
# 设置中文显示
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False
if __name__ == '__main__':
# ========================= 1. 数据准备:模拟用户商品偏好数据 =========================
np.random.seed(42)
n_users = 1000
X, y = make_classification(
n_samples=n_users,
n_features=2,
n_informative=2,
n_redundant=0,
n_clusters_per_class=1,
n_classes=3,
random_state=42
)
X = (X - X.min()) / (X.max() - X.min()) * 10 # 归一化到0-10分
# ========================= 2. 数据集划分 =========================
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y
)
# ========================= 3. KNN模型训练 =========================
k_values = range(1, 20)
accuracies = []
for k in k_values:
knn = KNeighborsClassifier(n_neighbors=k)
knn.fit(X_train, y_train)
y_pred = knn.predict(X_test)
accuracies.append(accuracy_score(y_test, y_pred))
best_k = k_values[np.argmax(accuracies)]
knn_best = KNeighborsClassifier(n_neighbors=best_k)
knn_best.fit(X_train, y_train)
y_pred_best = knn_best.predict(X_test)
# ========================= 4. 可视化分析(修复决策边界变量问题) =========================
# -------------------------- 图1:用户偏好分布与兴趣群体边界 --------------------------
plt.figure(figsize=(8, 6))
ax = plt.gca()
cmap = plt.colormaps['Set1'].resampled(3)
# 绘制散点图
scatter = ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=cmap, edgecolor='k', s=50)
# 【修复】手动定义图例标签
legend_labels = [f"兴趣群体{i}" for i in range(3)]
legend1 = ax.legend(
handles=scatter.legend_elements()[0],
labels=legend_labels,
title="兴趣群体",
loc="upper right",
frameon=True,
framealpha=0.8,
edgecolor='black'
)
ax.add_artist(legend1)
# 添加标题和坐标轴标签
ax.set_title('新用户商品偏好分布(真实兴趣群体)', fontsize=14)
ax.set_xlabel('对数码产品的偏好度(0-10分)', fontsize=12)
ax.set_ylabel('对服装的偏好度(0-10分)', fontsize=12)
# 【关键修复】定义 x_min, x_max, y_min, y_max(基于全部数据范围)
x_min, x_max = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5
y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5
ax.set_xlim(x_min, x_max)
ax.set_ylim(y_min, y_max)
ax.grid(True, linestyle='--', alpha=0.6)
# 绘制决策边界(使用修复后的变量)
xx, yy = np.meshgrid(
np.arange(x_min, x_max, 0.05), # x轴网格范围
np.arange(y_min, y_max, 0.05) # y轴网格范围
)
Z = knn_best.predict(np.c_[xx.ravel(), yy.ravel()]) # 预测网格点类别
Z = Z.reshape(xx.shape) # 重塑为网格形状
ax.contourf(xx, yy, Z, alpha=0.3, cmap=cmap) # 绘制填充轮廓
# 保存并显示图表
plt.tight_layout()
plt.savefig('用户偏好分布与兴趣群体边界.png', dpi=300)
plt.show()
# -------------------------- 图2:K值与推荐准确率的关系 --------------------------
plt.figure(figsize=(8, 6))
ax = plt.gca()
ax.plot(k_values, accuracies, marker='o', color='orange', linewidth=2)
ax.set_title('推荐准确率与相似用户数量(K值)的关系', fontsize=14)
ax.set_xlabel('相似用户数量(K值)', fontsize=12)
ax.set_ylabel('准确率', fontsize=12)
ax.axvline(x=best_k, color='red', linestyle='--', linewidth=1.5)
ax.text(best_k, max(accuracies), f'最优K={best_k}', color='red', fontsize=12)
ax.grid(True, linestyle='--', alpha=0.6)
plt.tight_layout()
plt.savefig('K值与准确率的关系.png', dpi=300)
plt.show()
# -------------------------- 图3:兴趣群体预测混淆矩阵 --------------------------
plt.figure(figsize=(8, 6))
ax = plt.gca()
cm = confusion_matrix(y_test, y_pred_best)
im = ax.imshow(cm, interpolation='nearest', cmap='Blues')
cbar = plt.colorbar(im, ax=ax)
cbar.set_label('样本数量', fontsize=12)
# 添加标题和坐标轴标签
ax.set_title(f'兴趣群体预测混淆矩阵(最优K值={best_k})', fontsize=14)
ax.set_xlabel('预测的兴趣群体', fontsize=12)
ax.set_ylabel('真实的兴趣群体', fontsize=12)
# 设置刻度和标签
ax.set_xticks(range(3))
ax.set_yticks(range(3))
ax.set_xticklabels([f'群体{i}' for i in range(3)], fontsize=10)
ax.set_yticklabels([f'群体{i}' for i in range(3)], fontsize=10)
# 在每个格子中添加数值
thresh = cm.max() / 2.
for i in range(cm.shape[0]):
for j in range(cm.shape[1]):
ax.text(j, i, format(cm[i, j], 'd'),
ha="center", va="center",
color="white" if cm[i, j] > thresh else "black",
fontsize=12)
plt.tight_layout()
plt.savefig('兴趣群体预测混淆矩阵.png', dpi=300)
plt.show()
# -------------------------- 图4:新用户与相似老用户的偏好对比 --------------------------
plt.figure(figsize=(8, 6))
ax = plt.gca()
sample_idx = 0
new_user = X_test[sample_idx].reshape(1, -1)
distances, indices = knn_best.kneighbors(new_user)
similar_users = X_train[indices[0]]
# 绘制相似老用户
ax.scatter(similar_users[:, 0], similar_users[:, 1],
c='lightblue', marker='o', label=f'相似的{best_k}个老用户', alpha=0.6, s=80)
# 绘制待推荐新用户(用更大的星形标记)
ax.scatter(new_user[0, 0], new_user[0, 1],
c='red', marker='*', s=200, label='待推荐新用户', edgecolor='black')
# 添加标题、坐标轴标签和图例
ax.set_title('新用户与相似老用户的商品偏好对比', fontsize=14)
ax.set_xlabel('对数码产品的偏好度(0-10分)', fontsize=12)
ax.set_ylabel('对服装的偏好度(0-10分)', fontsize=12)
ax.legend(fontsize=10, loc='upper left')
ax.grid(True, linestyle='--', alpha=0.6)
plt.tight_layout()
plt.savefig('新用户与相似老用户的偏好对比.png', dpi=300)
plt.show()
# ========================= 5. 模拟推荐场景 =========================
group_favorite = {
0: [101, 103, 105], # 数码类商品
1: [202, 204, 206], # 服装类商品
2: [301, 307, 308] # 综合类商品
}
new_user_group = y_pred_best[sample_idx]
recommended_products = group_favorite[new_user_group]
print("\n推荐系统结果:")
print(f"1. 为新用户找到的最优相似用户数量:{best_k}个")
print(f"2. 预测该新用户属于兴趣群体{new_user_group}")
print(f"3. 推荐商品ID:{recommended_products}(基于相似用户的喜好)")
5.5.2、实验结果
推荐系统结果: 1. 为新用户找到的最优相似用户数量:1个 2. 预测该新用户属于兴趣群体1 3. 推荐商品ID:[202, 204, 206](基于相似用户的喜好)
下文:
别再死磕理论!十大分类算法:公式讲透 + 场景踩坑指南(附可复用代码)(2)-CSDN博客https://blog.csdn.net/wh1236666/article/details/149715383?spm=1001.2014.3001.5502
区别:十大算法全景对比表(新增维度)
算法核心思想核心公式 / 机制对噪声敏感特征缩放小样本表现大样本表现调参难度逻辑回归概率转换Sigmoid 函数 + 交叉熵损失低需中中低决策树分支判断信息熵 / 基尼指数高无需中低(过拟合)中随机森林多树投票Bootstrap 抽样 + 特征随机低无需高高低SVM最大间隔间隔公式 + 核函数中需高低(慢)中KNN近邻投票距离公式(欧氏 / 曼哈顿)高需中低(慢)低朴素贝叶斯逆向概率贝叶斯定理 + 特征独立假设低无需高高低梯度提升串行纠错损失函数 + 梯度下降中需中高高XGBoost优化梯度提升正则化 + 二阶泰勒展开低需高高高神经网络多层非线性变换激活函数 + 反向传播高需低(过拟合)极高高LightGBM高效梯度提升Histogram+Leaf-wise 生长低需高极高中
总结:如何选对算法?
快速上手:先用逻辑回归 / 朴素贝叶斯做基准,再试随机森林(效果好且稳定)。小样本 / 高维:选 SVM(文本)或朴素贝叶斯(文本)。大数据 / 高精度:XGBoost(结构化数据)或 LightGBM(超大数据)。需解释性:逻辑回归(系数)或决策树(规则),避免神经网络 / XGBoost。实时预测:朴素贝叶斯(快)或 LightGBM(兼顾速度和精度)。
每种算法都有其 “擅长领域”,没有 “最好” 只有 “最合适”。理解原理 + 多实战,才能灵活运用十大算法解决实际问题。