28.分类算法:让机器学会分类
分类算法:让机器学会分类
🎯 前言:机器界的"选择困难症"救星
想象一下,你是一个超级忙碌的邮递员,每天要处理成千上万的邮件。有些是重要的商务信函,有些是垃圾广告,有些是朋友的明信片。如果让你一封一封地看内容来分类,估计你会累得怀疑人生。
但是,如果有一个AI助手能够看一眼邮件就知道该放进哪个箱子,那该多好啊!这就是分类算法的魔力——它能让机器像经验丰富的老师傅一样,快速准确地把东西归类。
今天我们就来探索这个让机器学会"分门别类"的神奇技术。从垃圾邮件过滤到医学诊断,从图像识别到推荐系统,分类算法无处不在,就像是AI世界的"万能分拣机"。
📚 目录
- 什么是分类算法
- 分类算法的核心思想
- 常见的分类算法
- 实战项目:垃圾邮件分类器
- 分类算法的评估指标
- 多分类问题的处理
- 实战项目:鸢尾花分类
- 进阶技巧与优化
- 常见问题与解决方案
🧠 什么是分类算法
分类算法的本质
分类算法就像是一个超级挑剔的管家,它的工作就是把东西放到正确的位置。给它一个新的物品,它会根据以往的经验判断:“这个应该放在A柜子里,那个应该放在B柜子里。”
# 分类算法的基本逻辑
def classify_email(email_content):if "恭喜中奖" in email_content:return "垃圾邮件"elif "会议通知" in email_content:return "工作邮件"elif "生日快乐" in email_content:return "个人邮件"else:return "其他"
分类 vs 预测
- 分类:预测类别标签(离散值)
- 例子:这是猫还是狗?这封邮件是垃圾邮件吗?
- 回归:预测连续数值
- 例子:这套房子值多少钱?明天的温度是几度?
分类的类型
-
二分类:只有两个类别
- 垃圾邮件 vs 正常邮件
- 良性肿瘤 vs 恶性肿瘤
-
多分类:有多个类别
- 手写数字识别(0-9)
- 新闻分类(体育、科技、娱乐等)
-
多标签分类:一个样本可以属于多个类别
- 电影分类(动作+科幻+冒险)
- 图像标签(天空+云朵+建筑)
🔍 分类算法的核心思想
1. 特征提取:教机器"看门道"
就像医生看病要检查症状一样,分类算法需要提取特征来做判断。
# 邮件分类的特征提取示例
def extract_email_features(email):features = {'word_count': len(email.split()),'has_urgent': '紧急' in email,'has_money': any(word in email for word in ['钱', '中奖', '优惠']),'exclamation_count': email.count('!'),'uppercase_ratio': sum(1 for c in email if c.isupper()) / len(email)}return features
2. 训练过程:机器的"学习经历"
分类算法的训练就像是给机器上课,用大量的例子来教它如何区分不同的类别。
# 训练数据示例
training_data = [("恭喜您中奖1000万!!!", "垃圾邮件"),("明天开会,请准时参加", "工作邮件"),("生日快乐,祝你开心", "个人邮件"),("点击链接领取奖品", "垃圾邮件"),("项目报告已完成", "工作邮件")
]
3. 决策边界:机器的"判断标准"
分类算法会在特征空间中画出一条"分界线",就像是在地图上划分不同的区域。
🤖 常见的分类算法
1. 逻辑回归:概率判断专家
逻辑回归不是做回归,而是做分类的!它的名字确实有点让人困惑,就像"热狗"里没有狗一样。
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import numpy as np# 创建示例数据
X = np.array([[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7]])
y = np.array([0, 0, 0, 1, 1, 1])# 训练逻辑回归模型
model = LogisticRegression()
model.fit(X, y)# 预测
predictions = model.predict([[3.5, 4.5]])
probabilities = model.predict_proba([[3.5, 4.5]])print(f"预测类别: {predictions[0]}")
print(f"属于各类别的概率: {probabilities[0]}")
2. 支持向量机(SVM):最优分界线寻找者
SVM就像是一个完美主义者,它要找到最优的分界线,确保两个类别之间的"安全距离"最大。
from sklearn.svm import SVC
from sklearn.datasets import make_classification
import matplotlib.pyplot as plt# 创建示例数据
X, y = make_classification(n_samples=100, n_features=2, n_redundant=0, n_informative=2, random_state=42)# 训练SVM模型
svm_model = SVC(kernel='rbf', random_state=42)
svm_model.fit(X, y)# 可视化决策边界
def plot_decision_boundary(X, y, model, title):plt.figure(figsize=(10, 8))# 创建网格h = 0.02x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1xx, yy = np.meshgrid(np.arange(x_min, x_max, h),np.arange(y_min, y_max, h))# 预测网格点Z = model.predict(np.c_[xx.ravel(), yy.ravel()])Z = Z.reshape(xx.shape)# 绘制决策边界plt.contourf(xx, yy, Z, alpha=0.8, cmap=plt.cm.RdYlBu)# 绘制数据点scatter = plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.RdYlBu, edgecolors='black')plt.colorbar(scatter)plt.title(title)plt.xlabel('特征1')plt.ylabel('特征2')plt.show()plot_decision_boundary(X, y, svm_model, 'SVM分类边界')
3. K近邻(KNN):邻居投票法
KNN就像是一个爱打听邻居意见的人,它会看看新来的数据点周围都是什么类别,然后让邻居们投票决定。
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import make_blobs# 创建聚类数据
X, y = make_blobs(n_samples=100, centers=3, n_features=2, random_state=42)# 训练KNN模型
knn_model = KNeighborsClassifier(n_neighbors=5)
knn_model.fit(X, y)# 预测新数据点
new_point = [[0, 0]]
prediction = knn_model.predict(new_point)
neighbors = knn_model.kneighbors(new_point, return_distance=True)print(f"新数据点的预测类别: {prediction[0]}")
print(f"最近的5个邻居距离: {neighbors[0][0]}")
print(f"最近的5个邻居索引: {neighbors[1][0]}")
4. 朴素贝叶斯:概率推理大师
朴素贝叶斯就像是一个数学老师,它会根据概率论来计算每个类别的可能性。
from sklearn.naive_bayes import GaussianNB
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB# 文本分类示例
emails = ["恭喜您中奖了!立即领取奖品!","明天的会议改到下午3点","生日快乐!祝你幸福!","点击链接获得免费礼品","项目报告请在周五前提交","限时优惠!不要错过!"
]labels = [1, 0, 0, 1, 0, 1] # 1为垃圾邮件,0为正常邮件# 文本向量化
vectorizer = TfidfVectorizer()
X_text = vectorizer.fit_transform(emails)# 训练朴素贝叶斯模型
nb_model = MultinomialNB()
nb_model.fit(X_text, labels)# 预测新邮件
new_email = ["免费获得iPhone!"]
new_email_vec = vectorizer.transform(new_email)
prediction = nb_model.predict(new_email_vec)
probability = nb_model.predict_proba(new_email_vec)print(f"邮件分类结果: {'垃圾邮件' if prediction[0] == 1 else '正常邮件'}")
print(f"是垃圾邮件的概率: {probability[0][1]:.2f}")
💻 实战项目:垃圾邮件分类器
让我们来构建一个完整的垃圾邮件分类系统,就像是给你的邮箱配备一个聪明的门卫。
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import MultinomialNB
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns# 创建模拟数据集
def create_spam_dataset():"""创建垃圾邮件数据集"""spam_emails = ["恭喜您中奖1000万!立即点击领取!","限时优惠!买一送一!不要错过!","免费获得iPhone!点击链接!","您的账户存在风险,请立即验证!","神秘礼品等您领取!机会难得!","投资理财,月收益20%!","减肥神器,一周瘦10斤!","点击即可获得免费课程!","紧急通知:您的银行卡被冻结!","恭喜成为我们的VIP用户!"]normal_emails = ["明天的会议改到下午3点举行","生日快乐!祝你工作顺利!","项目报告请在周五前提交","今天天气不错,适合出门","感谢您参加我们的活动","会议纪要已发送,请查收","周末有空一起吃饭吗?","文档已更新,请及时查看","新产品发布会定于下周举行","祝您新年快乐,身体健康!"]# 扩展数据集emails = spam_emails * 5 + normal_emails * 5labels = [1] * 50 + [0] * 50 # 1为垃圾邮件,0为正常邮件return pd.DataFrame({'email': emails,'label': labels})# 创建数据集
df = create_spam_dataset()
print(f"数据集大小: {len(df)}")
print(f"垃圾邮件数量: {sum(df['label'])}")
print(f"正常邮件数量: {len(df) - sum(df['label'])}")# 特征提取
def extract_email_features(email):"""提取邮件特征"""features = {'length': len(email),'word_count': len(email.split()),'exclamation_count': email.count('!'),'question_count': email.count('?'),'uppercase_ratio': sum(1 for c in email if c.isupper()) / len(email) if email else 0,'digit_count': sum(1 for c in email if c.isdigit()),'has_money_words': any(word in email for word in ['钱', '中奖', '优惠', '免费', '赚', '收益']),'has_urgent_words': any(word in email for word in ['紧急', '立即', '马上', '赶快', '限时']),'has_click_words': any(word in email for word in ['点击', '链接', '登录', '验证'])}return features# 应用特征提取
feature_data = df['email'].apply(extract_email_features)
feature_df = pd.DataFrame(feature_data.tolist())print("\n特征统计:")
print(feature_df.describe())# 文本向量化
vectorizer = TfidfVectorizer(max_features=100, stop_words=None)
X_text = vectorizer.fit_transform(df['email'])# 合并特征
X_combined = np.hstack([X_text.toarray(), feature_df.values])
y = df['label'].values# 分割数据
X_train, X_test, y_train, y_test = train_test_split(X_combined, y, test_size=0.3, random_state=42, stratify=y
)# 训练多个模型
models = {'Logistic Regression': LogisticRegression(random_state=42),'Naive Bayes': MultinomialNB(),'SVM': SVC(kernel='rbf', random_state=42)
}results = {}for name, model in models.items():print(f"\n训练 {name}...")model.fit(X_train, y_train)# 预测y_pred = model.predict(X_test)accuracy = accuracy_score(y_test, y_pred)results[name] = {'model': model,'accuracy': accuracy,'predictions': y_pred}print(f"{name} 准确率: {accuracy:.3f}")print(f"分类报告:")print(classification_report(y_test, y_pred, target_names=['正常邮件', '垃圾邮件']))# 可视化结果
plt.figure(figsize=(12, 8))# 准确率对比
plt.subplot(2, 2, 1)
accuracies = [results[name]['accuracy'] for name in models.keys()]
plt.bar(models.keys(), accuracies)
plt.title('模型准确率对比')
plt.ylabel('准确率')
plt.xticks(rotation=45)# 混淆矩阵
for i, (name, result) in enumerate(results.items()):plt.subplot(2, 2, i+2)cm = confusion_matrix(y_test, result['predictions'])sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')plt.title(f'{name} 混淆矩阵')plt.ylabel('真实标签')plt.xlabel('预测标签')plt.tight_layout()
plt.show()# 实时预测函数
def predict_spam(email_text, model_name='Logistic Regression'):"""预测邮件是否为垃圾邮件"""# 提取特征features = extract_email_features(email_text)# 文本向量化text_vec = vectorizer.transform([email_text])# 合并特征combined_features = np.hstack([text_vec.toarray(), [list(features.values())]])# 预测model = results[model_name]['model']prediction = model.predict(combined_features)[0]if hasattr(model, 'predict_proba'):probability = model.predict_proba(combined_features)[0][1]return prediction, probabilityelse:return prediction, None# 测试实时预测
test_emails = ["恭喜您中奖100万!点击链接立即领取!","明天下午2点开会,请准时参加","免费送iPhone!机会难得!","项目进展报告已完成,请查收"
]print("\n实时预测测试:")
for email in test_emails:prediction, prob = predict_spam(email)result = "垃圾邮件" if prediction == 1 else "正常邮件"prob_str = f"(概率: {prob:.2f})" if prob is not None else ""print(f"邮件: {email}")print(f"预测: {result} {prob_str}")print("-" * 50)
📊 分类算法的评估指标
评估分类算法的效果不能只看准确率,就像评价一个学生不能只看总分一样。
1. 准确率(Accuracy)
准确率是最直观的指标,就像是考试的正确率。
from sklearn.metrics import accuracy_score# 计算准确率
def calculate_accuracy(y_true, y_pred):return accuracy_score(y_true, y_pred)# 示例
y_true = [0, 1, 0, 1, 1, 0]
y_pred = [0, 1, 0, 0, 1, 0]
accuracy = calculate_accuracy(y_true, y_pred)
print(f"准确率: {accuracy:.3f}")
2. 精确率(Precision)和召回率(Recall)
- 精确率:在所有预测为正类的样本中,真正是正类的比例
- 召回率:在所有真正是正类的样本中,被正确预测的比例
from sklearn.metrics import precision_score, recall_score, f1_scoredef evaluate_classification(y_true, y_pred):"""计算分类评估指标"""precision = precision_score(y_true, y_pred)recall = recall_score(y_true, y_pred)f1 = f1_score(y_true, y_pred)print(f"精确率: {precision:.3f}")print(f"召回率: {recall:.3f}")print(f"F1得分: {f1:.3f}")return precision, recall, f1# 示例
evaluate_classification(y_true, y_pred)
3. 混淆矩阵:一目了然的错误分析
混淆矩阵就像是一个考试成绩单,告诉你哪些题目答对了,哪些答错了。
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrixdef plot_confusion_matrix(y_true, y_pred, labels=None):"""绘制混淆矩阵"""cm = confusion_matrix(y_true, y_pred)plt.figure(figsize=(8, 6))sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=labels, yticklabels=labels)plt.title('混淆矩阵')plt.ylabel('真实标签')plt.xlabel('预测标签')plt.show()return cm# 绘制混淆矩阵
cm = plot_confusion_matrix(y_true, y_pred, labels=['正常', '垃圾'])
print(f"混淆矩阵:\n{cm}")
4. ROC曲线:性能全景图
ROC曲线就像是一个全景相机,能够展示分类器在不同阈值下的性能。
from sklearn.metrics import roc_curve, auc
import matplotlib.pyplot as pltdef plot_roc_curve(y_true, y_proba):"""绘制ROC曲线"""fpr, tpr, thresholds = roc_curve(y_true, y_proba)roc_auc = auc(fpr, tpr)plt.figure(figsize=(8, 6))plt.plot(fpr, tpr, color='darkorange', lw=2, label=f'ROC曲线 (AUC = {roc_auc:.2f})')plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')plt.xlim([0.0, 1.0])plt.ylim([0.0, 1.05])plt.xlabel('假正率')plt.ylabel('真正率')plt.title('ROC曲线')plt.legend(loc="lower right")plt.show()return roc_auc# 示例(需要概率预测)
# roc_auc = plot_roc_curve(y_test, model.predict_proba(X_test)[:, 1])
🎯 多分类问题的处理
当我们面对多个类别时,就像是要把邮件分成工作、个人、垃圾邮件、促销等多个类别。
1. 一对多(One-vs-Rest)策略
from sklearn.multiclass import OneVsRestClassifier
from sklearn.linear_model import LogisticRegression# 创建多分类数据
from sklearn.datasets import make_classificationX, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=0, n_classes=4, random_state=42)# 一对多分类器
ovr_classifier = OneVsRestClassifier(LogisticRegression(random_state=42))
ovr_classifier.fit(X, y)# 预测
predictions = ovr_classifier.predict(X[:5])
probabilities = ovr_classifier.predict_proba(X[:5])print(f"预测类别: {predictions}")
print(f"各类别概率: {probabilities}")
2. 一对一(One-vs-One)策略
from sklearn.multiclass import OneVsOneClassifier# 一对一分类器
ovo_classifier = OneVsOneClassifier(LogisticRegression(random_state=42))
ovo_classifier.fit(X, y)# 预测
predictions = ovo_classifier.predict(X[:5])
print(f"一对一预测: {predictions}")
🌸 实战项目:鸢尾花分类
让我们用经典的鸢尾花数据集来实践多分类算法,这个数据集就像是机器学习界的"Hello World"。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, accuracy_score
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd# 加载鸢尾花数据集
iris = load_iris()
X, y = iris.data, iris.target# 创建数据框
df = pd.DataFrame(X, columns=iris.feature_names)
df['species'] = y
df['species_name'] = df['species'].map({0: 'setosa', 1: 'versicolor', 2: 'virginica'})print("鸢尾花数据集概述:")
print(df.head())
print(f"\n数据集形状: {df.shape}")
print(f"特征列: {list(iris.feature_names)}")
print(f"目标类别: {list(iris.target_names)}")# 数据可视化
plt.figure(figsize=(15, 10))# 特征分布
for i, feature in enumerate(iris.feature_names):plt.subplot(2, 3, i+1)for species in iris.target_names:data = df[df['species_name'] == species][feature]plt.hist(data, alpha=0.7, label=species, bins=20)plt.xlabel(feature)plt.ylabel('频率')plt.title(f'{feature} 分布')plt.legend()# 特征相关性热力图
plt.subplot(2, 3, 5)
correlation_matrix = df[iris.feature_names].corr()
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', center=0)
plt.title('特征相关性')# 散点图矩阵
plt.subplot(2, 3, 6)
for i, species in enumerate(iris.target_names):species_data = df[df['species_name'] == species]plt.scatter(species_data['sepal length (cm)'], species_data['sepal width (cm)'], label=species, alpha=0.7)
plt.xlabel('花萼长度')
plt.ylabel('花萼宽度')
plt.title('花萼长度 vs 宽度')
plt.legend()plt.tight_layout()
plt.show()# 数据预处理
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y
)# 标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)# 训练多个分类器
classifiers = {'Logistic Regression': LogisticRegression(random_state=42, max_iter=1000),'Decision Tree': DecisionTreeClassifier(random_state=42),'Random Forest': RandomForestClassifier(random_state=42)
}results = {}print("\n模型训练和评估:")
for name, clf in classifiers.items():print(f"\n{'='*50}")print(f"训练 {name}")print(f"{'='*50}")# 训练if name == 'Logistic Regression':clf.fit(X_train_scaled, y_train)y_pred = clf.predict(X_test_scaled)y_proba = clf.predict_proba(X_test_scaled)else:clf.fit(X_train, y_train)y_pred = clf.predict(X_test)y_proba = clf.predict_proba(X_test)# 评估accuracy = accuracy_score(y_test, y_pred)results[name] = {'model': clf,'accuracy': accuracy,'predictions': y_pred,'probabilities': y_proba}print(f"准确率: {accuracy:.3f}")print(f"详细报告:")print(classification_report(y_test, y_pred, target_names=iris.target_names))# 可视化结果
plt.figure(figsize=(15, 10))# 准确率对比
plt.subplot(2, 3, 1)
accuracies = [results[name]['accuracy'] for name in classifiers.keys()]
bars = plt.bar(classifiers.keys(), accuracies)
plt.title('模型准确率对比')
plt.ylabel('准确率')
plt.xticks(rotation=45)# 为每个柱子添加数值标签
for bar, acc in zip(bars, accuracies):plt.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.01, f'{acc:.3f}', ha='center', va='bottom')# 混淆矩阵
for i, (name, result) in enumerate(results.items()):plt.subplot(2, 3, i+2)cm = confusion_matrix(y_test, result['predictions'])sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=iris.target_names, yticklabels=iris.target_names)plt.title(f'{name} 混淆矩阵')plt.ylabel('真实标签')plt.xlabel('预测标签')plt.tight_layout()
plt.show()# 特征重要性(对于树模型)
plt.figure(figsize=(12, 8))for i, name in enumerate(['Decision Tree', 'Random Forest']):plt.subplot(1, 2, i+1)importance = results[name]['model'].feature_importances_feature_names = iris.feature_names# 排序indices = np.argsort(importance)[::-1]plt.bar(range(len(importance)), importance[indices])plt.xticks(range(len(importance)), [feature_names[i] for i in indices], rotation=45)plt.title(f'{name} 特征重要性')plt.ylabel('重要性')plt.tight_layout()
plt.show()# 预测新样本
def predict_iris_species(sepal_length, sepal_width, petal_length, petal_width):"""预测鸢尾花品种"""# 创建新样本new_sample = np.array([[sepal_length, sepal_width, petal_length, petal_width]])print(f"新样本特征: 花萼长度={sepal_length}, 花萼宽度={sepal_width}, "f"花瓣长度={petal_length}, 花瓣宽度={petal_width}")print("-" * 60)for name, result in results.items():model = result['model']# 预处理if name == 'Logistic Regression':sample_scaled = scaler.transform(new_sample)prediction = model.predict(sample_scaled)[0]probabilities = model.predict_proba(sample_scaled)[0]else:prediction = model.predict(new_sample)[0]probabilities = model.predict_proba(new_sample)[0]species_name = iris.target_names[prediction]print(f"{name}:")print(f" 预测品种: {species_name}")print(f" 各品种概率:")for i, prob in enumerate(probabilities):print(f" {iris.target_names[i]}: {prob:.3f}")print()# 测试预测
print("预测示例:")
predict_iris_species(5.0, 3.5, 1.5, 0.2) # 应该是 setosa
predict_iris_species(6.0, 3.0, 4.5, 1.5) # 应该是 versicolor
predict_iris_species(7.0, 3.2, 6.0, 2.0) # 应该是 virginica
🚀 进阶技巧与优化
1. 特征选择:去除冗余特征
就像整理衣柜一样,我们要把不必要的特征去掉,只留下真正有用的。
from sklearn.feature_selection import SelectKBest, f_classif, RFE
from sklearn.linear_model import LogisticRegression# 单变量特征选择
def univariate_feature_selection(X, y, k=5):"""单变量特征选择"""selector = SelectKBest(f_classif, k=k)X_selected = selector.fit_transform(X, y)# 获取选中的特征selected_features = selector.get_support(indices=True)scores = selector.scores_print(f"选中的特征索引: {selected_features}")print(f"特征得分: {scores}")return X_selected, selected_features# 递归特征消除
def recursive_feature_elimination(X, y, n_features=3):"""递归特征消除"""estimator = LogisticRegression(random_state=42)selector = RFE(estimator, n_features_to_select=n_features)X_selected = selector.fit_transform(X, y)selected_features = selector.get_support(indices=True)ranking = selector.ranking_print(f"选中的特征索引: {selected_features}")print(f"特征排名: {ranking}")return X_selected, selected_features# 示例
X_uni, features_uni = univariate_feature_selection(X, y, k=3)
X_rfe, features_rfe = recursive_feature_elimination(X, y, n_features=3)
2. 超参数调优:找到最佳配置
超参数调优就像是调收音机,要找到最清晰的频道。
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
from sklearn.svm import SVCdef hyperparameter_tuning():"""超参数调优示例"""# 定义参数网格param_grid = {'C': [0.1, 1, 10, 100],'gamma': [0.001, 0.01, 0.1, 1],'kernel': ['rbf', 'linear']}# 网格搜索svm = SVC(random_state=42)grid_search = GridSearchCV(svm, param_grid, cv=5, scoring='accuracy')grid_search.fit(X_train, y_train)print(f"最佳参数: {grid_search.best_params_}")print(f"最佳得分: {grid_search.best_score_:.3f}")# 使用最佳模型预测best_model = grid_search.best_estimator_y_pred = best_model.predict(X_test)accuracy = accuracy_score(y_test, y_pred)print(f"测试集准确率: {accuracy:.3f}")return best_model# 执行调优
best_svm = hyperparameter_tuning()
3. 集成学习:团队作战
集成学习就像是组建一个专家团队,每个人都有自己的专长,最后投票决定。
from sklearn.ensemble import VotingClassifier, BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import GaussianNBdef ensemble_learning():"""集成学习示例"""# 创建基础分类器clf1 = LogisticRegression(random_state=42)clf2 = DecisionTreeClassifier(random_state=42)clf3 = GaussianNB()# 硬投票voting_hard = VotingClassifier(estimators=[('lr', clf1), ('dt', clf2), ('nb', clf3)],voting='hard')# 软投票voting_soft = VotingClassifier(estimators=[('lr', clf1), ('dt', clf2), ('nb', clf3)],voting='soft')# 训练和评估models = {'Hard Voting': voting_hard,'Soft Voting': voting_soft}for name, model in models.items():model.fit(X_train, y_train)y_pred = model.predict(X_test)accuracy = accuracy_score(y_test, y_pred)print(f"{name} 准确率: {accuracy:.3f}")return voting_soft# 执行集成学习
ensemble_model = ensemble_learning()
4. 处理不平衡数据:公平竞争
当数据不平衡时,就像是一场不公平的比赛,我们需要采取措施来平衡。
from sklearn.utils.class_weight import compute_class_weight
from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSamplerdef handle_imbalanced_data():"""处理不平衡数据"""# 创建不平衡数据from sklearn.datasets import make_classificationX_imb, y_imb = make_classification(n_samples=1000, n_features=10, n_informative=5,n_redundant=0, n_clusters_per_class=1,weights=[0.9, 0.1], random_state=42)print(f"原始数据类别分布: {np.bincount(y_imb)}")# 方法1: 类权重平衡class_weights = compute_class_weight('balanced', classes=np.unique(y_imb), y=y_imb)print(f"类权重: {class_weights}")clf_weighted = LogisticRegression(class_weight='balanced', random_state=42)clf_weighted.fit(X_imb, y_imb)# 方法2: SMOTE过采样smote = SMOTE(random_state=42)X_smote, y_smote = smote.fit_resample(X_imb, y_imb)print(f"SMOTE后类别分布: {np.bincount(y_smote)}")clf_smote = LogisticRegression(random_state=42)clf_smote.fit(X_smote, y_smote)# 方法3: 随机欠采样undersampler = RandomUnderSampler(random_state=42)X_under, y_under = undersampler.fit_resample(X_imb, y_imb)print(f"欠采样后类别分布: {np.bincount(y_under)}")clf_under = LogisticRegression(random_state=42)clf_under.fit(X_under, y_under)return clf_weighted, clf_smote, clf_under# 处理不平衡数据
clf_weighted, clf_smote, clf_under = handle_imbalanced_data()
🔧 常见问题与解决方案
问题1:过拟合怎么办?
症状:训练准确率很高,但测试准确率很低
解决方案:
- 增加训练数据
- 使用正则化
- 减少特征数量
- 使用交叉验证
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression# 使用交叉验证评估模型
def cross_validation_evaluation():"""交叉验证评估"""# 不同正则化强度的模型C_values = [0.01, 0.1, 1, 10, 100]for C in C_values:clf = LogisticRegression(C=C, random_state=42)scores = cross_val_score(clf, X_train, y_train, cv=5)print(f"C={C}: CV平均得分={scores.mean():.3f} (+/- {scores.std() * 2:.3f})")cross_validation_evaluation()
问题2:特征太多怎么办?
解决方案:特征选择和降维
from sklearn.decomposition import PCA
from sklearn.feature_selection import SelectFromModeldef feature_reduction():"""特征降维"""# PCA降维pca = PCA(n_components=2)X_pca = pca.fit_transform(X)print(f"PCA解释方差比例: {pca.explained_variance_ratio_}")print(f"累积解释方差: {np.cumsum(pca.explained_variance_ratio_)}")# 基于模型的特征选择clf = RandomForestClassifier(n_estimators=100, random_state=42)clf.fit(X, y)selector = SelectFromModel(clf, prefit=True)X_selected = selector.transform(X)print(f"原始特征数: {X.shape[1]}")print(f"选择后特征数: {X_selected.shape[1]}")return X_pca, X_selectedX_pca, X_selected = feature_reduction()
问题3:模型选择困难症?
解决方案:系统化的模型比较
from sklearn.model_selection import cross_validate
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNBdef comprehensive_model_comparison():"""全面的模型比较"""models = {'Logistic Regression': LogisticRegression(random_state=42),'Random Forest': RandomForestClassifier(random_state=42),'SVM': SVC(random_state=42),'Naive Bayes': GaussianNB(),'Decision Tree': DecisionTreeClassifier(random_state=42)}scoring = ['accuracy', 'precision', 'recall', 'f1']results = {}for name, model in models.items():cv_results = cross_validate(model, X, y, cv=5, scoring=scoring)results[name] = {'accuracy': cv_results['test_accuracy'].mean(),'precision': cv_results['test_precision'].mean(),'recall': cv_results['test_recall'].mean(),'f1': cv_results['test_f1'].mean()}# 创建结果DataFrameresults_df = pd.DataFrame(results).Tprint("模型比较结果:")print(results_df.round(3))# 可视化plt.figure(figsize=(12, 8))results_df.plot(kind='bar')plt.title('模型性能比较')plt.ylabel('得分')plt.xticks(rotation=45)plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')plt.tight_layout()plt.show()return results_df# 执行全面比较
comparison_results = comprehensive_model_comparison()
📖 扩展阅读
推荐书籍
- 《机器学习实战》 - Peter Harrington
- 《统计学习方法》 - 李航
- 《模式识别与机器学习》 - Christopher Bishop
在线资源
- Scikit-learn官方文档: https://scikit-learn.org/
- Kaggle竞赛: https://www.kaggle.com/
- Google Colab: https://colab.research.google.com/
实践项目建议
- 垃圾邮件分类器:使用真实邮件数据
- 图像分类:使用CIFAR-10数据集
- 文本分类:新闻分类或情感分析
- 医学诊断:基于症状的疾病预测
🎬 下集预告
在下一篇文章《聚类分析:找到数据中的小团体》中,我们将探索无监督学习的神奇世界。想象一下,如果你是一个派对组织者,需要把客人分成几个小组,让每个小组的人都能聊得来,但你事先不知道应该怎么分组——这就是聚类算法要解决的问题!
我们将学习:
- K-means聚类:最经典的聚类算法
- 层次聚类:构建数据的家族树
- DBSCAN:发现任意形状的聚类
- 如何确定最优的聚类数量
- 聚类结果的可视化和解释
📝 总结与思考题
核心知识点总结
- 分类算法的本质:通过学习特征和标签之间的关系,对新数据进行类别预测
- 常见分类算法:逻辑回归、SVM、KNN、朴素贝叶斯各有特色
- 评估指标:准确率、精确率、召回率、F1得分,要根据具体问题选择
- 实际应用:从垃圾邮件过滤到医学诊断,分类算法无处不在
思考题
- 如果你要开发一个新闻分类系统,你会选择哪种分类算法?为什么?
- 在处理不平衡数据时,准确率为什么不是一个好的评估指标?
- 如何判断一个分类模型是否过拟合?有哪些解决方案?
实践作业
- 初级:使用sklearn内置数据集,比较不同分类算法的性能
- 中级:收集一些文本数据,构建一个文本分类器
- 高级:参加Kaggle上的分类竞赛,应用所学知识解决实际问题
记住,分类算法就像是一个经验丰富的分拣员,它通过学习大量的例子来掌握分类的技能。选择合适的算法,就像选择合适的工具一样重要。在实际应用中,不要害怕尝试不同的方法,因为最好的模型往往是通过不断实验和优化得到的!
下次见,我们将进入无监督学习的奇妙世界! 🚀