Python使用Scikit-learn构建简单预测模型的完整教学
本节学习目标
通过本节学习,你将能够:
- 理解机器学习的基本概念和常见类型
- 掌握训练集/测试集划分的原理与实现
- 学会使用线性回归模型进行数值预测
- 学会使用决策树进行分类和回归
- 掌握常见的模型评估指标和方法
- 能够独立完成一个简单的机器学习项目
为什么学这个?
在之前的所有课程中,我们做的分析都是"回头看"——发生了什么、为什么发生。但数据分析师最有价值的能力,是"向前看"——预测未来会发生什么。
- 预测下个月的销售额是多少?
- 预测这个用户会不会流失?
- 预测这支股票明天是涨还是跌?
这就是机器学习要解决的问题。
别被"机器学习"这个词吓到。它听起来很高深,但核心理念其实很简单:让计算机从历史数据中自动发现规律,然后用这些规律来做预测。
打个比方:
- 传统的编程方式是:你告诉计算机规则(if 温度 > 30 then 开空调)
- 机器学习的方式是:你给计算机一堆"温度-是否开空调"的历史数据,让它自己总结出规则
就像教小孩认苹果:你不需要告诉他"红色+圆形+有蒂=苹果",你只需要给他看很多苹果的照片,他自己就能学会。
本节我们将使用 Python 最流行的机器学习库 Scikit-learn,从最简单的模型开始,一步一步入门。
核心知识点讲解
机器学习基础概念
机器学习的类型
机器学习主要分为三类:
| 类型 | 特点 | 典型应用 | 本节涉及 |
|---|---|---|---|
| 监督学习 | 有"正确答案"(标签) | 预测房价、分类邮件 | 是 |
| 无监督学习 | 没有"正确答案" | 用户分群、异常检测 | 否 |
| 强化学习 | 通过奖惩学习 | 游戏AI、机器人控制 | 否 |
本节聚焦监督学习,它又分为:
- 回归(Regression):预测一个连续数值(如房价、销量)
- 分类(Classification):预测一个离散类别(如会/不会购买、好/坏评价)
机器学习的工作流程
收集数据 -> 准备数据 -> 选择模型 -> 训练模型 -> 评估模型 -> 调优 -> 部署
1 2 3 4 5 6 7
对于初学者,我们重点关注前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=["正常邮件", "垃圾邮件"]))
本节总结
本节我们正式进入了机器学习的世界:
- 基本概念:理解了监督学习、训练集/测试集划分、过拟合等核心概念
- 线性回归:学会了最简单的数值预测模型,理解了系数的业务含义
- 决策树:学会了分类和回归两种决策树模型,理解决策树的可解释性
- 模型评估:掌握了RMSE、MAE、R²(回归)和准确率、混淆矩阵、分类报告(分类)
- 完整项目:从零开始完成了一个用户购买预测项目,包括数据准备、模型训练、评估和特征分析
- 调优基础:了解了交叉验证和网格搜索
关键收获:
- 机器学习的本质:从历史数据中找规律,用规律做预测
- 训练集/测试集划分是防止"死记硬背"的关键
- 没有最好的模型,只有最适合当前数据和任务的模型
- R²告诉你模型"解释了多少",准确率告诉你"猜对了多少"
以上就是Python使用Scikit-learn构建简单预测模型的完整教学的详细内容,更多关于Python Scikit-learn预测模型的资料请关注脚本之家其它相关文章!
相关文章
python 中 关于reverse() 和 reversed()的用法详解
这篇文章主要介绍了python 中 关于reverse() 和 reversed()的用法介绍,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2023-01-01
django自带serializers序列化返回指定字段的方法
今天小编就为大家分享一篇django自带serializers序列化返回指定字段的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2019-08-08


最新评论