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 预测

  • 分类:预测类别标签(离散值)
    • 例子:这是猫还是狗?这封邮件是垃圾邮件吗?
  • 回归:预测连续数值
    • 例子:这套房子值多少钱?明天的温度是几度?

分类的类型

  1. 二分类:只有两个类别

    • 垃圾邮件 vs 正常邮件
    • 良性肿瘤 vs 恶性肿瘤
  2. 多分类:有多个类别

    • 手写数字识别(0-9)
    • 新闻分类(体育、科技、娱乐等)
  3. 多标签分类:一个样本可以属于多个类别

    • 电影分类(动作+科幻+冒险)
    • 图像标签(天空+云朵+建筑)

🔍 分类算法的核心思想

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()

🎯 聚类分析:找到数据中的小团体

🎉 前言:派对上的分组难题

想象一下,你是一个派对组织者,面对一群互不认识的客人,你需要把他们分成几个小组,让每个小组的人都能聊得来。这时候,你会怎么办?是根据他们的衣服颜色分组,还是根据他们的兴趣爱好?这就是聚类分析的魅力所在——它能帮你找到数据中的“小团体”,即使你对数据一无所知。

🧠 核心概念解释

什么是聚类分析?

聚类分析是一种无监督学习方法,它的目标是将数据分成几个组(称为“簇”),使得同一组内的数据相似度高,而不同组之间的相似度低。简单来说,就是“物以类聚,人以群分”。

常见的聚类算法
  1. K-means聚类:最经典的聚类算法,适合球形分布的簇。
  2. 层次聚类:构建数据的“家族树”,适合需要层次结构的场景。
  3. 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
  • 推荐书籍: 《机器学习实战》

🎬 下集预告

在下一篇文章《决策树:会问问题的智能算法》中,我们将探索如何让机器像侦探一样,通过一系列问题找到答案。敬请期待!

📝 总结与思考题

核心知识点总结

  1. 分类算法的本质:通过学习特征和标签之间的关系,对新数据进行类别预测
  2. 常见分类算法:逻辑回归、SVM、KNN、朴素贝叶斯各有特色
  3. 评估指标:准确率、精确率、召回率、F1得分,要根据具体问题选择
  4. 实际应用:从垃圾邮件过滤到医学诊断,分类算法无处不在

思考题

  1. 如果你要开发一个新闻分类系统,你会选择哪种分类算法?为什么?
  2. 在处理不平衡数据时,准确率为什么不是一个好的评估指标?
  3. 如何判断一个分类模型是否过拟合?有哪些解决方案?

实践作业

  1. 初级:使用sklearn内置数据集,比较不同分类算法的性能
  2. 中级:收集一些文本数据,构建一个文本分类器
  3. 高级:参加Kaggle上的分类竞赛,应用所学知识解决实际问题

记住,分类算法就像是一个经验丰富的分拣员,它通过学习大量的例子来掌握分类的技能。选择合适的算法,就像选择合适的工具一样重要。在实际应用中,不要害怕尝试不同的方法,因为最好的模型往往是通过不断实验和优化得到的!

下次见,我们将进入无监督学习的奇妙世界! 🚀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值