机器学习入门:核心算法与Scikit-learn

本文是AI学习系列第05篇 | 前置知识:04 第一个AI项目:手写数字识别 | 后续文章:06 深度学习初探:神经网络与PyTorch


📚 目录

  1. 什么是机器学习?
  2. Scikit-learn简介
  3. 线性回归:预测连续值
  4. 决策树:分类与回归的利器
  5. 实战案例:房价预测
  6. 模型评估方法
  7. 总结与下一步

1. 什么是机器学习?

机器学习(Machine Learning, ML)是人工智能的核心子领域,它让计算机能够从数据中自动学习规律,而无需显式编程。

🔑 核心概念

传统编程:数据 + 规则 = 结果
机器学习:数据 + 结果 = 规则(模型)

三大学习范式

类型特点典型应用
监督学习有标签数据分类、回归
无监督学习无标签数据聚类、降维
强化学习奖励机制游戏、机器人

本文重点:监督学习中的两大经典算法——线性回归和决策树 ✅


2. Scikit-learn简介

Scikit-learn 是Python最流行的机器学习库之一,提供简单高效的数据挖掘和数据分析工具。

安装

pip install scikit-learn numpy pandas matplotlib

核心模块

# 导入常用模块
from sklearn import (
    linear_model,      # 线性模型(线性回归、逻辑回归等)
    tree,              # 决策树
    model_selection,   # 模型选择(交叉验证、网格搜索)
    metrics,           # 评估指标
    preprocessing,     # 数据预处理
    datasets           # 内置数据集
)

print(f"Scikit-learn版本: {sklearn.__version__}")

Scikit-learn通用工作流

# 1️⃣ 准备数据
X, y = load_data()  # 特征矩阵X,目标向量y

# 2️⃣ 划分训练集和测试集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# 3️⃣ 创建并训练模型
model = SomeModel()        # 实例化模型
model.fit(X_train, y_train) # 训练

# 4️⃣ 预测与评估
y_pred = model.predict(X_test)
score = evaluate(y_test, y_pred)

💡 提示:几乎所有Scikit-learn的模型都遵循这个fit-predict模式!


3. 线性回归:预测连续值

线性回归(Linear Regression)是最基础的机器学习算法,用于预测连续数值(如房价、温度、销售额等)。

🎯 数学原理

一元线性回归
y = w x + b y = wx + b y=wx+b

其中:

  • y y y:预测值
  • x x x:输入特征
  • w w w:权重(weight)
  • b b b:偏置(bias)

多元线性回归
y = w 1 x 1 + w 2 x 2 + . . . + w n x n + b y = w_1x_1 + w_2x_2 + ... + w_nx_n + b y=w1x1+w2x2+...+wnxn+b

目标函数

最小化均方误差(MSE)
M S E = 1 n ∑ i = 1 n ( y i − y ^ i ) 2 MSE = \frac{1}{n}\sum_{i=1}^{n}(y_i - \hat{y}_i)^2 MSE=n1i=1n(yiy^i)2

📝 代码实现

示例1:简单线性回归
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score

# ===================
# 生成示例数据
# ===================
np.random.seed(42)
X = np.random.rand(100, 1) * 10  # 房屋面积(平方米)
y = 2 * X + 3 + np.random.randn(100, 1) * 2  # 价格(万元)+噪声

# 可视化原始数据
plt.figure(figsize=(10, 6))
plt.scatter(X, y, color='blue', alpha=0.6, label='实际数据')
plt.xlabel('房屋面积(平方米)')
plt.ylabel('价格(万元)')
plt.title('房屋面积 vs 价格')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

# ===================
# 创建并训练模型
# ===================
model = LinearRegression()
model.fit(X, y)

# 输出模型参数
print(f"权重(斜率)w: {model.coef_[0][0]:.4f}")
print(f"偏置(截距)b: {model.intercept_[0]:.4f}")
print(f"回归方程: y = {model.coef_[0][0]:.2f}x + {model.intercept_[0]:.2f}")

# ===================
# 预测与评估
# ===================
y_pred = model.predict(X)

mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)

print(f"\n均方误差(MSE): {mse:.4f}")
print(f"决定系数(R²): {r2:.4f}")

# 绘制拟合直线
plt.figure(figsize=(10, 6))
plt.scatter(X, y, color='blue', alpha=0.6, label='实际数据')
plt.plot(X, y_pred, color='red', linewidth=2, label='拟合直线')
plt.xlabel('房屋面积(平方米)')
plt.ylabel('价格(万元)')
plt.title('线性回归拟合结果')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
示例2:多元线性回归(加州房价)
import pandas as pd
from sklearn.datasets import fetch_california_housing
from sklearn.preprocessing import StandardScaler

# 加载加州房价数据集(替代已弃用的波士顿数据)
housing = fetch_california_housing()
X = housing.data
y = housing.target
feature_names = housing.feature_names

# 创建DataFrame便于查看
df = pd.DataFrame(X, columns=feature_names)
df['Price'] = y

print("数据集形状:", df.shape)
print("\n特征说明:")
for i, name in enumerate(feature_names):
    print(f"  {i+1}. {name}")

print("\n前5行数据:")
print(df.head())

# 数据标准化(重要!)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(
    X_scaled, y, test_size=0.2, random_state=42
)

# 训练多元线性回归模型
model_multi = LinearRegression()
model_multi.fit(X_train, y_train)

# 预测与评估
y_pred_multi = model_multi.predict(X_test)
mse_multi = mean_squared_error(y_test, y_pred_multi)
r2_multi = r2_score(y_test, y_pred_multi)

print(f"\n多元线性回归结果:")
print(f"  MSE: {mse_multi:.4f}")
print(f"  R²: {r2_multi:.4f}")

# 特征重要性分析
coef_df = pd.DataFrame({
    'Feature': feature_names,
    'Coefficient': model_multi.coef_
}).sort_values('Coefficient', key=abs, ascending=False)

print("\n特征系数(按绝对值排序):")
print(coef_df.to_string(index=False))

⚠️ 线性回归的假设条件

假设说明违反后果
线性关系自变量与因变量存在线性关系模型无法捕捉非线性模式
独立性残差之间相互独立出现自相关,标准误估计偏差
同方差性残差方差恒定异方差导致估计效率下降
正态性残差服从正态分布影响假设检验的有效性

4. 决策树:分类与回归的利器

决策树(Decision Tree)是一种基于树形结构进行决策的算法,既可以用于分类也可以用于回归。

🌳 算法原理

决策树通过一系列if-then规则对数据进行划分:

                    是否有房产?
                   /          \
                 Yes           No
                /               \
            收入>50K?         工龄>5年?
           /      \          /        \
         Yes      No       Yes        No
         |         |        |          |
       批准     拒绝     批准       拒绝

关键概念

  • 根节点(Root Node):树的起点,包含所有样本
  • 内部节点(Internal Node):表示一个特征测试
  • 叶节点(Leaf Node):表示最终决策结果
  • 分裂准则:信息增益(ID3)、信息增益率(C4.5)、基尼指数(CART)

📝 代码实现

示例1:分类决策树(鸢尾花数据集)
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
import seaborn as sns

# 加载鸢尾花数据集
iris = load_iris()
X_iris = iris.data
y_iris = iris.target
class_names = iris.target_names
feature_names_iris = iris.feature_names

print("鸢尾花数据集:")
print(f"  样本数: {X_iris.shape[0]}")
print(f"  特征数: {X_iris.shape[1]}")
print(f"  类别数: {len(class_names)}")
print(f"  类别名: {class_names}")

# 划分数据集
X_train_ir, X_test_ir, y_train_ir, y_test_ir = train_test_split(
    X_iris, y_iris, test_size=0.2, random_state=42, stratify=y_iris
)

# 创建决策树分类器
clf = DecisionTreeClassifier(
    criterion='gini',      # 使用基尼指数作为分裂准则
    max_depth=3,           # 最大深度为3(防止过拟合)
    min_samples_split=5,   # 内部节点再划分所需最小样本数
    min_samples_leaf=2,    # 叶节点最少样本数
    random_state=42
)

# 训练模型
clf.fit(X_train_ir, y_train_ir)

# 预测
y_pred_ir = clf.predict(X_test_ir)

# 评估
accuracy = accuracy_score(y_test_ir, y_pred_ir)
print(f"\n分类准确率: {accuracy:.4f}")

print("\n详细分类报告:")
print(classification_report(y_test_ir, y_pred_ir, target_names=class_names))

# 混淆矩阵可视化
cm = confusion_matrix(y_test_ir, y_pred_ir)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
            xticklabels=class_names, yticklabels=class_names)
plt.title('混淆矩阵')
plt.xlabel('预测标签')
plt.ylabel('真实标签')
plt.show()

# 可视化决策树结构
plt.figure(figsize=(15, 10))
plot_tree(clf, 
          feature_names=feature_names_iris,
          class_names=class_names,
          filled=True, rounded=True,
          fontsize=10)
plt.title('决策树结构可视化', fontsize=16)
plt.show()

# 特征重要性
feature_importance = pd.DataFrame({
    'Feature': feature_names_iris,
    'Importance': clf.feature_importances_
}).sort_values('Importance', ascending=False)

print("\n特征重要性排序:")
print(feature_importance.to_string(index=False))

# 特征重要性柱状图
plt.figure(figsize=(10, 6))
plt.barh(feature_importance['Feature'], feature_importance['Importance'], color='skyblue')
plt.xlabel('重要性')
plt.ylabel('特征')
plt.title('决策树特征重要性')
plt.gca().invert_yaxis()
plt.grid(axis='x', alpha=0.3)
plt.show()
示例2:回归决策树
from sklearn.tree import DecisionTreeRegressor

# 使用之前的房价数据
X_train_dt, X_test_dt, y_train_dt, y_test_dt = train_test_split(
    X_scaled, y, test_size=0.2, random_state=42
)

# 创建决策树回归器
regressor = DecisionTreeRegressor(
    criterion='squared_error',  # 使用均方误差
    max_depth=5,
    min_samples_leaf=10,
    random_state=42
)

# 训练
regressor.fit(X_train_dt, y_train_dt)

# 预测
y_pred_dt = regressor.predict(X_test_dt)

# 评估
mse_dt = mean_squared_error(y_test_dt, y_pred_dt)
r2_dt = r2_score(y_test_dt, y_pred_dt)

print(f"决策树回归结果:")
print(f"  MSE: {mse_dt:.4f}")
print(f"  R²: {r2_dt:.4f}")

# 与线性回归对比
print(f"\n对比线性回归:")
print(f"  线性回归 R²: {r2_multi:.4f}")
print(f"  决策树 R²: {r2_dt:.4f}")

🔄 线性回归 vs 决策树

对比维度线性回归决策树
适用问题回归分类 + 回归
可解释性高(系数直观)中等(规则清晰但复杂)
非线性能力❌ 弱✅ 强
异常值敏感度
过拟合风险低(简单模型)高(需剪枝/限制深度)
特征工程需求需要处理非线性自动处理
计算复杂度O(n)O(n log n) ~ O(n²)

5. 实战案例:房价预测

结合两种算法完成一个完整的端到端项目:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.linear_model import LinearRegression, Ridge, Lasso
from sklearn.tree import DecisionTreeRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error

# ===================
# 1. 数据加载与探索
# ===================
housing = fetch_california_housing()
df = pd.DataFrame(housing.data, columns=housing.feature_names)
df['MedHouseVal'] = housing.target

print("="*60)
print("房价预测项目 - 数据探索")
print("="*60)
print(f"\n数据集规模: {df.shape[0]} 条记录, {df.shape[1]} 个字段")
print("\n统计摘要:")
print(df.describe().round(2))

# 检查缺失值
print("\n缺失值检查:")
print(df.isnull().sum())

# 相关性分析
correlation = df.corr()['MedHouseVal'].sort_values(ascending=False)
print("\n与房价的相关性:")
print(correlation.round(3))

# ===================
# 2. 数据预处理
# ===================
# 分离特征和目标
X = df.drop('MedHouseVal', axis=1).values
y = df['MedHouseVal'].values

# 标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(
    X_scaled, y, test_size=0.2, random_state=42
)

print(f"\n训练集大小: {X_train.shape[0]}")
print(f"测试集大小: {X_test.shape[0]}")

# ===================
# 3. 模型训练与比较
# ===================
models = {
    '线性回归': LinearRegression(),
    'Ridge回归': Ridge(alpha=1.0),
    'Lasso回归': Lasso(alpha=0.1),
    '决策树(深度3)': DecisionTreeRegressor(max_depth=3, random_state=42),
    '决策树(深度5)': DecisionTreeRegressor(max_depth=5, random_state=42),
}

results = []

for name, model in models.items():
    # 训练
    model.fit(X_train, y_train)
    
    # 预测
    y_pred = model.predict(X_test)
    
    # 评估指标
    mse = mean_squared_error(y_test, y_pred)
    mae = mean_absolute_error(y_test, y_pred)
    r2 = r2_score(y_test, y_pred)
    
    # 交叉验证(5折)
    cv_scores = cross_val_score(model, X_train, y_train, cv=5, scoring='r2')
    
    results.append({
        '模型': name,
        'MSE': mse,
        'MAE': mae,
        'R²': r2,
        'CV_R²均值': cv_scores.mean(),
        'CV_R²标准差': cv_scores.std()
    })
    
    print(f"\n{name}:")
    print(f"  MSE: {mse:.4f}, MAE: {mae:.4f}, R²: {r2:.4f}")
    print(f"  交叉验证R²: {cv_scores.mean():.4f} (+/- {cv_scores.std()*2:.4f})")

# ===================
# 4. 结果汇总与可视化
# ===================
results_df = pd.DataFrame(results).sort_values('R²', ascending=False)
print("\n" + "="*60)
print("模型性能排名")
print("="*60)
print(results_df.to_string(index=False))

# 性能对比柱状图
fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# R²对比
axes[0].bar(results_df['模型'], results_df['R²'], color='steelblue', alpha=0.8)
axes[0].set_title('各模型R²得分对比', fontsize=12)
axes[0].set_ylabel('R² Score')
axes[0].set_ylim(0, 1)
axes[0].tick_params(axis='x', rotation=45)
for i, v in enumerate(results_df['R²']):
    axes[0].text(i, v + 0.01, f'{v:.3f}', ha='center', va='bottom')

# MSE对比
colors = ['green' if x <= min(results_df['MSE'])*1.1 else 'orange' for x in results_df['MSE']]
axes[1].bar(results_df['模型'], results_df['MSE'], color=colors, alpha=0.8)
axes[1].set_title('各模型MSE对比(越低越好)', fontsize=12)
axes[1].set_ylabel('Mean Squared Error')
axes[1].tick_params(axis='x', rotation=45)

plt.tight_layout()
plt.show()

# ===================
# 5. 最佳模型预测 vs 实际值
# ===================
best_model_name = results_df.iloc[0]['模型']
best_model = models[best_model_name]
y_best_pred = best_model.predict(X_test)

plt.figure(figsize=(8, 8))
plt.scatter(y_test, y_best_pred, alpha=0.5, edgecolors='k', s=40)
plt.plot([y.min(), y.max()], [y.min(), y.max()], 'r--', lw=2, label='完美预测线')
plt.xlabel('实际房价')
plt.ylabel('预测房价')
plt.title(f'{best_model_name} - 预测值 vs 实际值')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

# 残差图
residuals = y_test - y_best_pred
plt.figure(figsize=(10, 5))
plt.subplot(121)
plt.scatter(y_best_pred, residuals, alpha=0.5)
plt.axhline(y=0, color='r', linestyle='--')
plt.xlabel('预测值')
plt.ylabel('残差')
plt.title('残差分布')

plt.subplot(122)
plt.hist(residuals, bins=30, edgecolor='black', alpha=0.7)
plt.xlabel('残差')
plt.ylabel('频数')
plt.title('残差直方图')
plt.tight_layout()
plt.show()

6. 模型评估方法

📊 常用评估指标

回归问题
指标公式说明取值范围
MAE 1 n ∑ ∣ y i − y ^ i ∣ \frac{1}{n}\sum|y_i-\hat{y}_i| n1yiy^i平均绝对误差[0, +∞),越小越好
MSE 1 n ∑ ( y i − y ^ i ) 2 \frac{1}{n}\sum(y_i-\hat{y}_i)^2 n1(yiy^i)2均方误差[0, +∞),越小越好
RMSE M S E \sqrt{MSE} MSE 均方根误差[0, +∞),越小越好
1 − ∑ ( y i − y ^ i ) 2 ∑ ( y i − y ˉ ) 2 1-\frac{\sum(y_i-\hat{y}_i)^2}{\sum(y_i-\bar{y})^2} 1(yiyˉ)2(yiy^i)2决定系数(-∞, 1],越接近1越好
分类问题
指标说明
准确率(Accuracy)正确预测的比例
精确率(Precision)预测为正中真正为正的比例
召回率(Recall)真实为正中被正确预测的比例
F1分数精确率和召回率的调和平均

🔍 交叉验证

from sklearn.model_selection import cross_val_score, KFold

# K折交叉验证
kf = KFold(n_splits=5, shuffle=True, random_state=42)

# 对线性回归进行5折交叉验证
cv_scores = cross_val_score(
    LinearRegression(), X_scaled, y, 
    cv=kf, scoring='r2'
)

print(f"交叉验证R²得分: {cv_scores}")
print(f"平均R²: {cv_scores.mean():.4f}")
print(f"标准差: {cv_scores.std():.4f}")

# 可视化交叉验证结果
plt.figure(figsize=(8, 5))
plt.bar(range(1, 6), cv_scores, color='skyblue', edgecolor='navy')
plt.axhline(y=cv_scores.mean(), color='red', linestyle='--', label=f'平均值: {cv_scores.mean():.3f}')
plt.xlabel('Fold编号')
plt.ylabel('R² Score')
plt.title('5折交叉验证结果')
plt.xticks(range(1, 6))
plt.legend()
plt.ylim(0, 1)
plt.grid(axis='y', alpha=0.3)
plt.show()

⚠️ 过拟合与欠拟合

模型复杂度
    │
高  │      ╱╲ 过拟合区域
    │     ╱  ╲
    │    ╱    ╲
    │   ╱ 最优 ╲
    │  ╱  区域  ╲
    │ ╱          ╲
低  │╱_____________╲________ 欠拟合区域
    └───────────────────────→ 训练误差
                              测试误差

解决方案

  • 过拟合:增加数据、减少特征、正则化(Ridge/Lasso)、早停、集成学习
  • 欠拟合:增加特征、使用更复杂的模型、减小正则化强度

7. 总结与下一步

📝 本篇要点回顾

线性回归

  • 最基础的回归算法,假设特征与目标呈线性关系
  • 通过最小化MSE求解最优参数
  • 适用于可解释性要求高的场景

决策树

  • 基于规则的树形结构,可处理非线性关系
  • 既可用于分类也可用于回归
  • 易于理解和解释,但容易过拟合

Scikit-learn工作流

  • fit()predict()evaluate() 的统一接口
  • train_test_split 划分数据集
  • cross_val_score 进行交叉验证

🛠️ 实践建议

  1. 从简单开始:先用线性回归建立baseline
  2. 可视化先行:画图理解数据和模型行为
  3. 防止过拟合:使用交叉验证、正则化
  4. 特征重要:好的特征比复杂的模型更重要

🔗 下一步学习

方向内容对应文章
深度学习神经网络、CNN、PyTorch第06篇
自然语言处理Transformer、注意力机制第07篇
RAG系统LangChain + 向量数据库第08篇
模型部署FastAPI + Docker第09篇

📚 推荐资源

  • 官方文档:https://scikit-learn.org/stable/user_guide.html
  • 书籍:《Python机器学习》(Sebastian Raschka)、《机器学习实战》
  • 在线课程:Andrew Ng《Machine Learning Specialization》(Coursera)
  • 练习平台:Kaggle竞赛、天池大赛

🎯 系列进度
[✅ 01 开篇] → [✅ 02 AI全景图] → [✅ 03 环境搭建] → [✅ 04 手写数字识别] → 📍 05 机器学习入门(当前) → [06 深度学习初探] → …


作者:AI学习者
发布时间:2026年
标签:#机器学习 #Python #Scikit-learn #线性回归 #决策树 #AI入门

💡 欢迎关注本系列,持续更新中!如有疑问欢迎评论区交流~


Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐