机器学习入门:核心算法与Scikit-learn
机器学习入门:核心算法与Scikit-learn
本文是AI学习系列第05篇 | 前置知识:04 第一个AI项目:手写数字识别 | 后续文章:06 深度学习初探:神经网络与PyTorch
📚 目录
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=1∑n(yi−y^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| n1∑∣yi−y^i∣ | 平均绝对误差 | [0, +∞),越小越好 |
| MSE | 1 n ∑ ( y i − y ^ i ) 2 \frac{1}{n}\sum(y_i-\hat{y}_i)^2 n1∑(yi−y^i)2 | 均方误差 | [0, +∞),越小越好 |
| RMSE | M S E \sqrt{MSE} MSE | 均方根误差 | [0, +∞),越小越好 |
| R² | 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−∑(yi−yˉ)2∑(yi−y^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进行交叉验证
🛠️ 实践建议
- 从简单开始:先用线性回归建立baseline
- 可视化先行:画图理解数据和模型行为
- 防止过拟合:使用交叉验证、正则化
- 特征重要:好的特征比复杂的模型更重要
🔗 下一步学习
| 方向 | 内容 | 对应文章 |
|---|---|---|
| 深度学习 | 神经网络、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入门
💡 欢迎关注本系列,持续更新中!如有疑问欢迎评论区交流~
更多推荐


所有评论(0)