# 机器学习入门实践:从零开始构建你的第一个预测模型

机器学习入门实践:从零开始构建你的第一个预测模型

前言

机器学习正以前所未有的速度改变着我们的世界。从智能推荐系统到自动驾驶汽车,从医疗诊断到金融风控,这项技术已经渗透到各行各业。对于初学者来说,机器学习可能看起来高深莫测,但实际上,通过正确的指导和实践,任何人都可以迈出第一步。

本文将带你从零开始,完成一个完整的机器学习项目。我们将使用经典的鸢尾花数据集,通过Python和Scikit-learn库,构建一个能够准确分类鸢尾花品种的机器学习模型。在这个过程中,你将学习到机器学习的基本流程、核心概念和实用技巧。

环境准备

在开始之前,我们需要准备好开发环境。我推荐使用Anaconda来管理Python环境,它包含了我们所需的大部分科学计算库。

安装步骤

  1. 安装Anaconda(从官网下载对应版本)
  2. 创建新的虚拟环境:
    1
    2
    conda create -n ml-beginner python=3.9
    conda activate ml-beginner
  3. 安装必要的库:
    1
    pip install numpy pandas matplotlib seaborn scikit-learn jupyter

项目概述:鸢尾花分类

鸢尾花数据集是机器学习领域最经典的数据集之一,包含150个样本,每个样本有4个特征(花萼长度、花萼宽度、花瓣长度、花瓣宽度)和1个标签(鸢尾花品种:Setosa、Versicolor、Virginica)。

我们的目标是构建一个模型,能够根据花的四个特征准确预测其品种。

🚀 完整实现步骤

第一步:导入必要的库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 基础数据处理库
import numpy as np
import pandas as pd

# 数据可视化库
import matplotlib.pyplot as plt
import seaborn as sns

# 机器学习库
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix

# 设置中文字体和图表样式
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
sns.set_style("whitegrid")

第二步:加载和探索数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 加载数据集
iris = load_iris()
print("数据集特征名称:", iris.feature_names)
print("目标类别名称:", iris.target_names)
print("数据形状:", iris.data.shape)
print("目标形状:", iris.target.shape)

# 将数据转换为DataFrame以便更好地查看
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['species'] = iris.target
df['species_name'] = df['species'].map({0: 'setosa', 1: 'versicolor', 2: 'virginica'})

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

print("\n数据基本信息:")
print(df.info())

print("\n数据统计描述:")
print(df.describe())

print("\n各类别样本数量:")
print(df['species_name'].value_counts())

第三步:数据可视化分析

理解数据是机器学习项目中至关重要的一步。可视化可以帮助我们发现数据中的模式和关系。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 创建2x2的子图布局
fig, axes = plt.subplots(2, 2, figsize=(12, 10))

# 特征分布直方图
for idx, feature in enumerate(iris.feature_names):
row, col = divmod(idx, 2)
axes[row, col].hist(df[feature], bins=20, alpha=0.7, color='skyblue', edgecolor='black')
axes[row, col].set_title(f'{feature}分布')
axes[row, col].set_xlabel(feature)
axes[row, col].set_ylabel('频数')

plt.tight_layout()
plt.show()

# 特征与目标的关系
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
colors = ['red', 'green', 'blue']

for idx, feature in enumerate(iris.feature_names):
row, col = divmod(idx, 2)
for species_idx, species in enumerate(iris.target_names):
species_data = df[df['species'] == species_idx]
axes[row, col].scatter(species_data[feature], species_data['species'],
alpha=0.6, color=colors[species_idx], label=species)
axes[row, col].set_title(f'{feature} vs 类别')
axes[row, col].set_xlabel(feature)
axes[row, col].set_ylabel('类别')
axes[row, col].legend()

plt.tight_layout()
plt.show()

# 特征间相关性热图
plt.figure(figsize=(10, 8))
correlation_matrix = df[iris.feature_names].corr()
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', center=0)
plt.title('特征间相关性热图')
plt.show()

第四步:数据预处理

数据预处理是机器学习流程中的关键步骤,直接影响模型的性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 分离特征和目标变量
X = df[iris.feature_names].values
y = df['species'].values

print("特征数据形状:", X.shape)
print("目标数据形状:", y.shape)

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)

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

# 数据标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

print("\n标准化后的数据示例(前5行):")
print(X_train_scaled[:5])

第五步:构建和训练模型

我们将尝试三种不同的分类算法,比较它们的性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 初始化模型
models = {
'K近邻': KNeighborsClassifier(n_neighbors=5),
'决策树': DecisionTreeClassifier(max_depth=3, random_state=42),
'随机森林': RandomForestClassifier(n_estimators=100, random_state=42)
}

# 训练和评估模型
results = {}

for model_name, model in models.items():
print(f"\n正在训练 {model_name} 模型...")

# 训练模型
model.fit(X_train_scaled, y_train)

# 预测
y_train_pred = model.predict(X_train_scaled)
y_test_pred = model.predict(X_test_scaled)

# 计算准确率
train_accuracy = accuracy_score(y_train, y_train_pred)
test_accuracy = accuracy_score(y_test, y_test_pred)

results[model_name] = {
'model': model,
'train_accuracy': train_accuracy,
'test_accuracy': test_accuracy,
'y_test_pred': y_test_pred
}

print(f"训练集准确率: {train_accuracy:.4f}")
print(f"测试集准确率: {test_accuracy:.4f}")

# 显示分类报告
print(f"\n{model_name} 分类报告:")
print(classification_report(y_test, y_test_pred, target_names=iris.target_names))

第六步:模型评估和比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 比较不同模型的性能
model_names = list(results.keys())
train_accuracies = [results[name]['train_accuracy'] for name in model_names]
test_accuracies = [results[name]['test_accuracy'] for name in model_names]

x = np.arange(len(model_names))
width = 0.35

fig, ax = plt.subplots(figsize=(10, 6))
rects1 = ax.bar(x - width/2, train_accuracies, width, label='训练集', color='skyblue')
rects2 = ax.bar(x + width/2, test_accuracies, width, label='测试集', color='lightcoral')

ax.set_xlabel('模型')
ax.set_ylabel('准确率')
ax.set_title('不同模型在训练集和测试集上的表现')
ax.set_xticks(x)
ax.set_xticklabels(model_names)
ax.legend()

# 在柱状图上显示准确率数值
def autolabel(rects):
for rect in rects:
height = rect.get_height()
ax.annotate(f'{height:.3f}',
xy=(rect.get_x() + rect.get_width() / 2, height),
xytext=(0, 3),
textcoords="offset points",
ha='center', va='bottom')

autolabel(rects1)
autolabel(rects2)

plt.tight_layout()
plt.show()

# 绘制混淆矩阵
fig, axes = plt.subplots(1, 3, figsize=(15, 5))

for idx, model_name in enumerate(model_names):
cm = confusion_matrix(y_test, results[model_name]['y_test_pred'])

sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=iris.target_names,
yticklabels=iris.target_names,
ax=axes[idx])
axes[idx].set_title(f'{model_name} 混淆矩阵')
axes[idx].set_xlabel('预测标签')
axes[idx].set_ylabel('真实标签')

plt.tight_layout()
plt.show()

第七步:模型优化(以K近邻为例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# 寻找K近邻算法的最优K值
k_values = range(1, 21)
train_scores = []
test_scores = []

for k in k_values:
knn = KNeighborsClassifier(n_neighbors=k)
knn.fit(X_train_scaled, y_train)

train_scores.append(knn.score(X_train_scaled, y_train))
test_scores.append(knn.score(X_test_scaled, y_test))

# 绘制K值与准确率的关系
plt.figure(figsize=(10, 6))
plt.plot(k_values, train_scores, 'o-', label='训练集准确率', color='blue')
plt.plot(k_values, test_scores, 's-', label='测试集准确率', color='red')
plt.xlabel('K值')
plt.ylabel('准确率')
plt.title('K近邻算法中K值对准确率的影响')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

# 找到最优K值
optimal_k = k_values[np.argmax(test_scores)]
print(f"最优K值: {optimal_k}")
print(f"最优K值对应的测试集准确率: {test_scores[optimal_k-1]:.4f}")

# 使用最优K值重新训练模型
optimal_knn = KNeighborsClassifier(n_neighbors=optimal_k)
optimal_knn.fit(X_train_scaled, y_train)

# 对新样本进行预测
def predict_new_sample(features):
"""
预测新样本的类别

参数:
features: 列表,包含4个特征值 [花萼长度, 花萼宽度, 花瓣长度, 花瓣宽度]
"""
# 将输入转换为数组并标准化
features_array = np.array(features).reshape(1, -1)
features_scaled = scaler.transform(features_array)

# 预测
prediction = optimal_knn.predict(features_scaled)[0]
probability = optimal_knn.predict_proba(features_scaled)[0]

# 输出结果
species_name = iris.target_names[prediction]

print(f"预测结果: {species_name}")
print("\n各类别概率:")
for i, name in enumerate(iris.target_names):
print(f" {name}: {probability[i]:.4f}")

return prediction, probability

# 示例:预测一个新样本
print("示例预测:")
sample_features = [5.1, 3.5, 1.4, 0.2] # 这是一个典型的setosa样本
predict_new_sample(sample_features)

第八步:特征重要性分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 使用随机森林分析特征重要性
best_model = results['随机森林']['model']

# 获取特征重要性
feature_importance = best_model.feature_importances_

# 创建特征重要性DataFrame
importance_df = pd.DataFrame({
'特征': iris.feature_names,
'重要性': feature_importance
}).sort_values('重要性', ascending=False)

print("特征重要性排序:")
print(importance_df)

# 可视化特征重要性
plt.figure(figsize=(10, 6))
bars = plt.barh(importance_df['特征'], importance_df['重要性'], color='teal')
plt.xlabel('重要性分数')
plt.title('随机森林特征重要性')
plt.gca().invert_yaxis() # 重要性从高到低显示

# 在条形图上显示数值
for bar in bars:
width = bar.get_width()
plt.text(width + 0.01, bar.get_y() + bar.get_height()/2,
f'{width:.3f}', ha='left', va='center')

plt.tight_layout()
plt.show()

🚀 关键概念解析

1. 监督学习 vs 无监督学习

本项目属于监督学习,因为我们有明确的标签(鸢尾花品种)来指导模型训练。

2. 过拟合与欠拟合

  • 过拟合:模型在训练集上表现很好,但在测试集上表现差
  • 欠拟合:模型在训练集和测试集上都表现不佳
  • 我们的目标:找到平衡点,使模型具有良好的泛化能力

3. 交叉验证

虽然本文使用了简单的训练集/测试集划分,但在实际项目中,推荐使用交叉验证来更可靠地评估模型性能。

4. 超参数调优

我们演示了如何通过网格搜索找到K近邻算法的最优K值。对于更复杂的模型,可以使用GridSearchCV或RandomizedSearchCV进行自动调优。

实践建议

  1. 从简单开始:不要一开始就尝试最复杂的模型,从简单的模型(如K近邻、逻辑回归)开始,建立基准性能。

  2. 理解数据:花时间探索和理解数据,这通常比盲目尝试不同算法更有效。

  3. 迭代改进:机器学习是一个迭代过程,不断尝试、评估、调整。

  4. 记录实验:记录每次实验的参数、结果和观察,这有助于你理解什么方法有效,什么无效。

  5. 关注泛化能力:最终目标是构建在未见数据上表现良好的模型,而不仅仅是在训练数据上表现好。

✨ 下一步学习方向

完成这个入门项目后,你可以尝试以下方向进一步学习:

  1. 尝试其他数据集:如手写数字识别(MNIST)、波士顿房价预测等
  2. 探索更复杂的模型:如支持向量机、神经网络等
  3. 学习深度学习:使用TensorFlow或PyTorch构建神经网络
  4. 参与Kaggle竞赛:在真实竞赛中应用所学知识
  5. 学习模型部署:将训练好的模型部署为Web服务

结语

机器学习入门并不难,关键在于动手实践。通过这个完整的项目,你已经掌握了机器学习的基本流程:数据加载、探索分析、预处理、模型训练、评估和优化。这些步骤构成了大多数机器学习项目的基础框架。

记住,每个专家都曾是初学者。持续学习、不断实践,你将在机器学习的道路上越走越远。现在,尝试修改代码中的参数,使用不同的算法,或者应用这个流程到其他数据集上,开始你的机器学习探索之旅吧!

[up主专用,视频内嵌代码贴在这]