python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python Scikit-learn预测模型

Python使用Scikit-learn构建简单预测模型的完整教学

作者:小庄-Python办公

这篇文章我们将使用 Python 最流行的机器学习库 Scikit-learn,从最简单的模型开始,一步一步构建简单的预测模型,感兴趣的小伙伴可以跟随小编一起学习一下

本节学习目标

通过本节学习,你将能够:

  1. 理解机器学习的基本概念和常见类型
  2. 掌握训练集/测试集划分的原理与实现
  3. 学会使用线性回归模型进行数值预测
  4. 学会使用决策树进行分类和回归
  5. 掌握常见的模型评估指标和方法
  6. 能够独立完成一个简单的机器学习项目

为什么学这个?

在之前的所有课程中,我们做的分析都是"回头看"——发生了什么、为什么发生。但数据分析师最有价值的能力,是"向前看"——预测未来会发生什么。

这就是机器学习要解决的问题。

别被"机器学习"这个词吓到。它听起来很高深,但核心理念其实很简单:让计算机从历史数据中自动发现规律,然后用这些规律来做预测。

打个比方:

就像教小孩认苹果:你不需要告诉他"红色+圆形+有蒂=苹果",你只需要给他看很多苹果的照片,他自己就能学会。

本节我们将使用 Python 最流行的机器学习库 Scikit-learn,从最简单的模型开始,一步一步入门。

核心知识点讲解

机器学习基础概念

机器学习的类型

机器学习主要分为三类:

类型特点典型应用本节涉及
监督学习有"正确答案"(标签)预测房价、分类邮件
无监督学习没有"正确答案"用户分群、异常检测
强化学习通过奖惩学习游戏AI、机器人控制

本节聚焦监督学习,它又分为:

机器学习的工作流程

收集数据 -> 准备数据 -> 选择模型 -> 训练模型 -> 评估模型 -> 调优 -> 部署
   1         2          3          4          5          6        7

对于初学者,我们重点关注前5步:

  1. 收集数据:获取包含特征(输入)和标签(输出)的数据
  2. 准备数据:清洗、处理缺失值、特征工程等
  3. 选择模型:根据任务类型选择合适的算法
  4. 训练模型:让模型从数据中学习规律
  5. 评估模型:用未见过的数据检验模型的表现

创建示例数据集

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 设置中文字体
plt.rcParams["font.sans-serif"] = ["SimHei", "Microsoft YaHei"]
plt.rcParams["axes.unicode_minus"] = False

# 生成一个回归任务的示例数据
# 场景:根据房屋的面积和房龄预测房价
np.random.seed(42)
n_samples = 200

area = np.random.uniform(50, 200, n_samples)       # 面积: 50-200 平方米
age = np.random.uniform(0, 30, n_samples)          # 房龄: 0-30 年

# 房价公式(加入随机噪声模拟真实情况)
# 面积越大越贵,房龄越老越便宜
price = (
    1.5 * area           # 每平米1.5万
    - 2 * age            # 每年折旧2万
    + 50                 # 基础价格
    + np.random.normal(0, 15, n_samples)  # 随机噪声
)

df = pd.DataFrame({
    "面积_平米": area,
    "房龄_年": age,
    "房价_万元": price
})

print("=== 示例数据:房价预测 ===")
print(df.head(10))
print(f"\n数据规模: {len(df)} 条")
print(df.describe().round(1))

训练集/测试集划分

为什么要划分数据集?

这是机器学习中最重要也最容易理解错的概念之一。

想象你在备考:

机器学习中也是一样的道理:

如果模型在训练集上表现很好,但在测试集上表现很差,说明模型过拟合了——它只是"背下了"训练数据,没有真正学到规律。

划分数据集

from sklearn.model_selection import train_test_split

# 准备特征(X)和标签(y)
X = df[["面积_平米", "房龄_年"]]  # 特征:面积和房龄
y = df["房价_万元"]               # 标签:房价

# 划分数据集(80%训练,20%测试)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

print("=== 数据集划分 ===")
print(f"训练集: {len(X_train)} 条 ({len(X_train)/len(df)*100:.0f}%)")
print(f"测试集: {len(X_test)} 条 ({len(X_test)/len(df)*100:.0f}%)")

print("\n训练集特征前5行:")
print(X_train.head())
print("\n训练集标签前5行:")
print(y_train.head())

线性回归模型

线性回归的原理

线性回归是最简单的机器学习模型。它的核心思想:找到一条"最佳直线",让这条直线尽可能接近所有数据点。

对于只有一个特征的情况:房价 = 斜率 × 面积 + 截距

对于多个特征:房价 = w1 × 面积 + w2 × 房龄 + 截距

模型训练的过程,就是找到最好的 w1、w2 和截距,使得预测值和真实值的差距最小。

训练线性回归模型

from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score

# 创建模型
model = LinearRegression()

# 训练模型(这一步就是让模型从数据中学习)
model.fit(X_train, y_train)

# 查看学到的参数
print("=== 线性回归模型参数 ===")
print(f"系数 (w): 面积={model.coef_[0]:.2f}, 房龄={model.coef_[1]:.2f}")
print(f"截距 (b): {model.intercept_:.2f}")
print(f"\n解读:")
print(f"  - 面积每增加1平米,房价平均增加 {model.coef_[0]:.2f} 万元")
print(f"  - 房龄每增加1年,房价平均减少 {abs(model.coef_[1]):.2f} 万元")

# 用模型做预测
y_pred = model.predict(X_test)

# 对比预测值和真实值
comparison = pd.DataFrame({
    "真实房价": y_test.values,
    "预测房价": y_pred,
    "误差": y_test.values - y_pred
})
comparison["误差绝对值"] = comparison["误差"].abs()

print("\n=== 测试集预测结果对比(前10条) ===")
print(comparison.head(10).round(1))
print(f"\n平均绝对误差: {comparison['误差绝对值'].mean():.1f} 万元")

模型评估

# 计算评估指标
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)

print("=" * 50)
print("线性回归模型评估结果")
print("=" * 50)
print(f"MSE(均方误差):  {mse:.2f}")
print(f"RMSE(均方根误差): {rmse:.2f} 万元")
print(f"MAE(平均绝对误差): {mae:.2f} 万元")
print(f"R²(决定系数):    {r2:.4f}")
print("=" * 50)

# 指标解释
print("\n指标解读:")
print(f"- RMSE={rmse:.1f}万: 预测房价平均偏离真实值约 {rmse:.1f} 万元")
print(f"- R²={r2:.2%}: 模型解释了 {r2:.0%} 的房价变化原因")
print("  (R²=1.0表示完美预测,R²=0表示预测不如猜平均值)")

# 可视化:预测值 vs 真实值
fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# 左图:散点图
axes[0].scatter(y_test, y_pred, alpha=0.6, color="#3498db")
min_val = min(y_test.min(), y_pred.min())
max_val = max(y_test.max(), y_pred.max())
axes[0].plot([min_val, max_val], [min_val, max_val],
             "r--", label="完美预测线")
axes[0].set_xlabel("真实房价(万元)")
axes[0].set_ylabel("预测房价(万元)")
axes[0].set_title("预测值 vs 真实值", fontsize=13, fontweight="bold")
axes[0].legend()
axes[0].grid(True, alpha=0.3)

# 右图:残差图
residuals = y_test.values - y_pred
axes[1].scatter(y_pred, residuals, alpha=0.6, color="#e74c3c")
axes[1].axhline(y=0, color="gray", linestyle="--")
axes[1].set_xlabel("预测房价(万元)")
axes[1].set_ylabel("残差(真实-预测)")
axes[1].set_title("残差图", fontsize=13, fontweight="bold")
axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

决策树模型

决策树的原理

决策树是另一种常用的模型。它的核心思想:通过一系列"是/否"问题来做判断。

就像你去医院看病:

体温 > 37.3度?
├── 是:咳嗽吗?
│       ├── 是:可能是流感 -> 验血
│       └── 否:拍胸片
└── 否:肚子痛吗?
        ├── 是:查腹部
        └── 否:继续问诊

决策树模型会自动从数据中找到最有价值的"判断问题"和"判断顺序"。

决策树回归

from sklearn.tree import DecisionTreeRegressor, plot_tree

# 训练决策树回归模型
dt_model = DecisionTreeRegressor(
    max_depth=4,          # 最大深度(防止过拟合)
    random_state=42
)
dt_model.fit(X_train, y_train)

# 预测
dt_pred = dt_model.predict(X_test)

# 评估
dt_mae = mean_absolute_error(y_test, dt_pred)
dt_r2 = r2_score(y_test, dt_pred)

print("=== 决策树回归模型评估 ===")
print(f"MAE: {dt_mae:.2f} 万元")
print(f"R²:  {dt_r2:.4f}")

# 与线性回归对比
print("\n=== 模型对比 ===")
print(f"{'模型':<15} {'MAE':>10} {'R²':>10}")
print("-" * 35)
print(f"{'线性回归':<15} {mae:>10.2f} {r2:>10.4f}")
print(f"{'决策树':<15} {dt_mae:>10.2f} {dt_r2:>10.4f}")

# 可视化决策树结构
fig, ax = plt.subplots(figsize=(12, 6))
plot_tree(
    dt_model,
    feature_names=["面积_平米", "房龄_年"],
    filled=True,
    rounded=True,
    fontsize=10,
    ax=ax
)
ax.set_title("决策树结构", fontsize=14, fontweight="bold")
plt.tight_layout()
plt.show()

决策树分类

# 使用Iris数据集演示分类任务
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix

# 加载数据
iris = load_iris()
X_iris = iris.data
y_iris = iris.target

print("=== Iris鸢尾花数据集 ===")
print(f"特征: {iris.feature_names}")
print(f"类别: {iris.target_names}")
print(f"样本数: {len(X_iris)}")

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

# 训练决策树分类器
clf = DecisionTreeClassifier(max_depth=3, 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=== 分类模型评估 ===")
print(f"准确率: {accuracy:.2%}")
print(f"\n分类报告:")
print(classification_report(y_test_ir, y_pred_ir, target_names=iris.target_names))

# 混淆矩阵
cm = confusion_matrix(y_test_ir, y_pred_ir)
fig, ax = plt.subplots(figsize=(6, 5))
im = ax.imshow(cm, cmap="Blues")
ax.set_xticks(range(3))
ax.set_yticks(range(3))
ax.set_xticklabels(iris.target_names)
ax.set_yticklabels(iris.target_names)
ax.set_ylabel("真实标签")
ax.set_xlabel("预测标签")
ax.set_title("混淆矩阵", fontsize=13, fontweight="bold")

# 在每个格子中标注数字
for i in range(3):
    for j in range(3):
        ax.text(j, i, cm[i, j], ha="center", va="center", fontsize=14,
                color="white" if cm[i, j] > cm.max()/2 else "black")

plt.tight_layout()
plt.show()

完整机器学习项目

项目:用户购买意愿预测

# ========== 完整项目:电商用户购买预测 ==========

print("=" * 60)
print("项目:电商用户购买意愿预测模型")
print("=" * 60)

# Step 1: 创建模拟数据集
np.random.seed(42)
n_users = 1000

users = pd.DataFrame({
    "浏览时长_分钟": np.random.exponential(10, n_users),
    "浏览次数": np.random.poisson(8, n_users),
    "加入购物车": np.random.poisson(2, n_users),
    "收藏数": np.random.poisson(1, n_users),
    "历史购买次数": np.random.poisson(3, n_users),
    "距上次访问_天": np.random.exponential(7, n_users),
})

# 创建标签:是否购买(基于特征加上随机性)
buy_prob = (
    0.02 * users["浏览时长_分钟"] +
    0.05 * users["浏览次数"] +
    0.15 * users["加入购物车"] +
    0.1 * users["收藏数"] +
    0.08 * users["历史购买次数"] -
    0.03 * users["距上次访问_天"]
)
users["购买"] = (buy_prob + np.random.normal(0, 1, n_users) > 2).astype(int)

print(f"\n数据集: {len(users)} 个用户")
print(f"购买率: {users['购买'].mean():.1%}")
print(f"\n特征说明:")
for col in users.columns[:-1]:
    print(f"  - {col}: 均值={users[col].mean():.1f}")

# Step 2: 数据预处理
from sklearn.preprocessing import StandardScaler

X = users.drop("购买", axis=1)
y = users["购买"]

X_train_u, X_test_u, y_train_u, y_test_u = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 标准化(对某些模型有帮助)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train_u)
X_test_scaled = scaler.transform(X_test_u)

# Step 3: 训练多个模型并比较
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier

models = {
    "逻辑回归": LogisticRegression(random_state=42, max_iter=1000),
    "决策树": DecisionTreeClassifier(max_depth=5, random_state=42),
    "随机森林": RandomForestClassifier(n_estimators=50, random_state=42),
    "K近邻": KNeighborsClassifier(n_neighbors=5)
}

results = {}
print("\n=== 模型训练与评估 ===")
for name, model in models.items():
    model.fit(X_train_scaled, y_train_u)
    pred = model.predict(X_test_scaled)
    acc = accuracy_score(y_test_u, pred)
    results[name] = {"accuracy": acc, "model": model}
    print(f"{name:>10}: 准确率 = {acc:.2%}")

# Step 4: 选择最佳模型并详细分析
best_name = max(results, key=lambda x: results[x]["accuracy"])
best_model = results[best_name]["model"]
best_pred = best_model.predict(X_test_scaled)

print(f"\n最佳模型: {best_name}")
print(f"\n详细评估:")
print(classification_report(y_test_u, best_pred, target_names=["未购买", "已购买"]))

# 混淆矩阵
cm = confusion_matrix(y_test_u, best_pred)
fig, ax = plt.subplots(figsize=(5, 4))
im = ax.imshow(cm, cmap="Greens")
ax.set_xticks([0, 1])
ax.set_yticks([0, 1])
ax.set_xticklabels(["未购买", "已购买"])
ax.set_yticklabels(["未购买", "已购买"])
ax.set_ylabel("真实")
ax.set_xlabel("预测")
ax.set_title(f"{best_name} - 混淆矩阵", fontweight="bold")
for i in range(2):
    for j in range(2):
        ax.text(j, i, cm[i, j], ha="center", va="center", fontsize=16,
                color="white" if cm[i, j] > cm.max()/2 else "black")
plt.tight_layout()
plt.show()

# Step 5: 特征重要性分析(使用随机森林)
rf_model = results["随机森林"]["model"]
importances = pd.DataFrame({
    "特征": X.columns,
    "重要性": rf_model.feature_importances_
}).sort_values("重要性", ascending=False)

fig, ax = plt.subplots(figsize=(8, 5))
bars = ax.barh(
    importances["特征"][::-1],
    importances["重要性"][::-1],
    color="#3498db"
)
for bar, val in zip(bars, importances["重要性"][::-1]):
    ax.text(val + 0.005, bar.get_y() + bar.get_height()/2,
            f"{val:.3f}", va="center", fontsize=10)
ax.set_xlabel("特征重要性")
ax.set_title("影响购买决策的关键因素", fontsize=13, fontweight="bold")
plt.tight_layout()
plt.show()

print("\n=== 特征重要性排名 ===")
for i, (_, row) in enumerate(importances.iterrows(), 1):
    print(f"  {i}. {row['特征']}: {row['重要性']:.3f}")

# Step 6: 使用模型做新用户的预测
print("\n=== 新用户预测示例 ===")
new_users = pd.DataFrame({
    "浏览时长_分钟": [15, 5, 30],
    "浏览次数": [10, 3, 20],
    "加入购物车": [3, 0, 5],
    "收藏数": [2, 0, 3],
    "历史购买次数": [5, 1, 10],
    "距上次访问_天": [2, 15, 1]
})

new_scaled = scaler.transform(new_users)
new_pred = best_model.predict(new_scaled)
new_prob = best_model.predict_proba(new_scaled)[:, 1]

for i in range(len(new_users)):
    label = "会购买" if new_pred[i] == 1 else "不会购买"
    print(f"  用户{i+1}: 预测结果={label}, 购买概率={new_prob[i]:.1%}")

print("\n" + "=" * 60)
print("项目完成!")
print("=" * 60)

模型调优基础

交叉验证

from sklearn.model_selection import cross_val_score

# 交叉验证:把训练集分成多份,轮流用其中一份做验证
# 这能更可靠地评估模型性能
print("=== 交叉验证结果 ===")
for name, model in models.items():
    scores = cross_val_score(model, X_train_scaled, y_train_u, cv=5, scoring="accuracy")
    print(f"{name:>10}: {scores.mean():.2%} (+/- {scores.std():.2%})")

简单的参数调优

from sklearn.model_selection import GridSearchCV

# 网格搜索:尝试不同的参数组合,找到最优的
param_grid = {
    "max_depth": [3, 5, 7, 10],
    "min_samples_split": [2, 5, 10]
}

grid_search = GridSearchCV(
    DecisionTreeClassifier(random_state=42),
    param_grid,
    cv=5,
    scoring="accuracy"
)
grid_search.fit(X_train_scaled, y_train_u)

print("=== 网格搜索结果 ===")
print(f"最佳参数: {grid_search.best_params_}")
print(f"最佳准确率: {grid_search.best_score_:.2%}")

# 查看所有参数组合的结果
cv_results = pd.DataFrame(grid_search.cv_results_)
print("\n所有参数组合:")
for _, row in cv_results[["params", "mean_test_score"]].iterrows():
    print(f"  {row['params']}: {row['mean_test_score']:.4f}")

实战练习

练习1:预测学生考试成绩

题目: 根据学习时间、练习次数等特征,预测学生的考试成绩。使用线性回归和决策树回归分别建模,比较哪个模型更好。

# 参考答案
np.random.seed(100)
n = 150

students = pd.DataFrame({
    "学习时间_小时": np.random.uniform(1, 10, n),
    "练习次数": np.random.poisson(20, n),
    "出勤率": np.random.uniform(0.5, 1.0, n),
})

# 成绩公式
students["成绩"] = (
    5 * students["学习时间_小时"] +
    1.5 * students["练习次数"] +
    30 * students["出勤率"] +
    np.random.normal(0, 5, n)
)
students["成绩"] = students["成绩"].clip(0, 100)

X_s = students[["学习时间_小时", "练习次数", "出勤率"]]
y_s = students["成绩"]

X_tr, X_te, y_tr, y_te = train_test_split(X_s, y_s, test_size=0.2, random_state=42)

# 线性回归
lr = LinearRegression()
lr.fit(X_tr, y_tr)
lr_pred = lr.predict(X_te)
print(f"线性回归 R² = {r2_score(y_te, lr_pred):.4f}")

# 决策树
dt = DecisionTreeRegressor(max_depth=4, random_state=42)
dt.fit(X_tr, y_tr)
dt_pred = dt.predict(X_te)
print(f"决策树   R² = {r2_score(y_te, dt_pred):.4f}")

print("\n线性回归系数:")
for feat, coef in zip(X_s.columns, lr.coef_):
    print(f"  {feat}: {coef:.2f}")

练习2:垃圾邮件分类

题目: 使用简单的规则生成一个垃圾邮件数据集,训练分类模型判断邮件是否为垃圾邮件。

# 参考答案
np.random.seed(42)
n_emails = 500

emails = pd.DataFrame({
    "含免费字数": np.random.poisson(2, n_emails),
    "含中奖字数": np.random.poisson(1, n_emails),
    "含链接数": np.random.poisson(3, n_emails),
    "邮件长度": np.random.exponential(200, n_emails),
    "发件人是否已知": np.random.choice([0, 1], n_emails, p=[0.4, 0.6])
})

# 标签生成规则
spam_score = (
    2 * emails["含免费字数"] +
    3 * emails["含中奖字数"] +
    0.5 * emails["含链接数"] -
    0.01 * emails["邮件长度"] -
    1.5 * emails["发件人是否已知"]
)
emails["垃圾邮件"] = (spam_score + np.random.normal(0, 1, n_emails) > 3).astype(int)

X_e = emails.drop("垃圾邮件", axis=1)
y_e = emails["垃圾邮件"]
X_tr_e, X_te_e, y_tr_e, y_te_e = train_test_split(X_e, y_e, test_size=0.2, random_state=42)

clf_e = RandomForestClassifier(n_estimators=50, random_state=42)
clf_e.fit(X_tr_e, y_tr_e)
pred_e = clf_e.predict(X_te_e)
print(f"准确率: {accuracy_score(y_te_e, pred_e):.2%}")
print(f"\n分类报告:")
print(classification_report(y_te_e, pred_e, target_names=["正常邮件", "垃圾邮件"]))

本节总结

本节我们正式进入了机器学习的世界:

  1. 基本概念:理解了监督学习、训练集/测试集划分、过拟合等核心概念
  2. 线性回归:学会了最简单的数值预测模型,理解了系数的业务含义
  3. 决策树:学会了分类和回归两种决策树模型,理解决策树的可解释性
  4. 模型评估:掌握了RMSE、MAE、R²(回归)和准确率、混淆矩阵、分类报告(分类)
  5. 完整项目:从零开始完成了一个用户购买预测项目,包括数据准备、模型训练、评估和特征分析
  6. 调优基础:了解了交叉验证和网格搜索

关键收获:

以上就是Python使用Scikit-learn构建简单预测模型的完整教学的详细内容,更多关于Python Scikit-learn预测模型的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文