分类算法:让机器学会分类
🎯 前言:机器界的"选择困难症"救星
想象一下,你是一个超级忙碌的邮递员,每天要处理成千上万的邮件。有些是重要的商务信函,有些是垃圾广告,有些是朋友的明信片。如果让你一封一封地看内容来分类,估计你会累得怀疑人生。
但是,如果有一个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.02
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, 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 * 5
labels = [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, probability
else:
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_score
def 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_matrix
def 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 plt
def 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_classification
X, y = 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)
# 一对多分类器
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 SVC
def 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 GaussianNB
def 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 RandomUnderSampler
def handle_imbalanced_data():
"""处理不平衡数据"""
# 创建不平衡数据
from sklearn.datasets import make_classification
X_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()
🎯 聚类分析:找到数据中的小团体
🎉 前言:派对上的分组难题
想象一下,你是一个派对组织者,面对一群互不认识的客人,你需要把他们分成几个小组,让每个小组的人都能聊得来。这时候,你会怎么办?是根据他们的衣服颜色分组,还是根据他们的兴趣爱好?这就是聚类分析的魅力所在——它能帮你找到数据中的“小团体”,即使你对数据一无所知。
🧠 核心概念解释
什么是聚类分析?
聚类分析是一种无监督学习方法,它的目标是将数据分成几个组(称为“簇”),使得同一组内的数据相似度高,而不同组之间的相似度低。简单来说,就是“物以类聚,人以群分”。
常见的聚类算法
- K-means聚类:最经典的聚类算法,适合球形分布的簇。
- 层次聚类:构建数据的“家族树”,适合需要层次结构的场景。
- DBSCAN:发现任意形状的簇,适合处理噪声数据。
💻 实战项目:客户分群
场景描述
假设你是一家电商的分析师,想要根据用户的消费行为进行分群,以便制定个性化营销策略。
数据准备
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
# 模拟用户数据
data = {
'月访问次数': [10, 20, 15, 30, 25, 5, 40, 35],
'月消费金额': [200, 400, 300, 600, 500, 100, 800, 700]
}
df = pd.DataFrame(data)
# 数据标准化
scaler = StandardScaler()
data_scaled = scaler.fit_transform(df)
K-means聚类
# K-means聚类
kmeans = KMeans(n_clusters=3, random_state=42)
clusters = kmeans.fit_predict(data_scaled)
# 添加聚类结果到数据框
df['群体'] = clusters
print(df)
可视化结果
# 可视化聚类结果
plt.scatter(df['月访问次数'], df['月消费金额'], c=df['群体'], cmap='viridis', alpha=0.6)
plt.xlabel('月访问次数')
plt.ylabel('月消费金额')
plt.title('客户分群结果')
plt.colorbar(label='群体')
plt.show()
🚀 进阶技巧
如何选择最优的聚类数量?
使用“肘部法则”来确定最优的聚类数量:
from sklearn.metrics import silhouette_score
# 计算不同簇数量的SSE
sse = []
silhouette_scores = []
for k in range(2, 10):
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans.fit(data_scaled)
sse.append(kmeans.inertia_)
silhouette_scores.append(silhouette_score(data_scaled, kmeans.labels_))
# 绘制肘部法则图
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.plot(range(2, 10), sse, marker='o')
plt.title('肘部法则')
plt.xlabel('簇数量')
plt.ylabel('SSE')
plt.subplot(1, 2, 2)
plt.plot(range(2, 10), silhouette_scores, marker='o')
plt.title('轮廓系数')
plt.xlabel('簇数量')
plt.ylabel('轮廓系数')
plt.tight_layout()
plt.show()
🔧 常见问题与解决方案
问题1:数据中有噪声怎么办?
解决方案:使用DBSCAN算法,它能自动忽略噪声点。
问题2:簇的形状不规则怎么办?
解决方案:层次聚类或DBSCAN更适合处理非球形簇。
📖 扩展阅读
- Scikit-learn官方文档: https://scikit-learn.org/stable/modules/clustering.html
- 推荐书籍: 《机器学习实战》
🎬 下集预告
在下一篇文章《决策树:会问问题的智能算法》中,我们将探索如何让机器像侦探一样,通过一系列问题找到答案。敬请期待!
📝 总结与思考题
核心知识点总结
- 分类算法的本质:通过学习特征和标签之间的关系,对新数据进行类别预测
- 常见分类算法:逻辑回归、SVM、KNN、朴素贝叶斯各有特色
- 评估指标:准确率、精确率、召回率、F1得分,要根据具体问题选择
- 实际应用:从垃圾邮件过滤到医学诊断,分类算法无处不在
思考题
- 如果你要开发一个新闻分类系统,你会选择哪种分类算法?为什么?
- 在处理不平衡数据时,准确率为什么不是一个好的评估指标?
- 如何判断一个分类模型是否过拟合?有哪些解决方案?
实践作业
- 初级:使用sklearn内置数据集,比较不同分类算法的性能
- 中级:收集一些文本数据,构建一个文本分类器
- 高级:参加Kaggle上的分类竞赛,应用所学知识解决实际问题
记住,分类算法就像是一个经验丰富的分拣员,它通过学习大量的例子来掌握分类的技能。选择合适的算法,就像选择合适的工具一样重要。在实际应用中,不要害怕尝试不同的方法,因为最好的模型往往是通过不断实验和优化得到的!
下次见,我们将进入无监督学习的奇妙世界! 🚀
2万+

被折叠的 条评论
为什么被折叠?



