2025/10/24日 每日总结 机器学习入门实践:数据准备与模型评估(Iris数据集实战)

机器学习入门实践:数据准备与模型评估(Iris数据集实战)

作为机器学习入门的基础实验,数据准备和模型评估是构建可靠模型的核心步骤。这次我以经典的Iris鸢尾花数据集为对象,实操了数据集加载、五折交叉验证和多指标评估的完整流程,整理了一份详细的实践笔记,适合刚入门的小伙伴参考~

一、实验核心目标

  1. 熟悉Python数据处理和机器学习库的基本操作(pandas、scikit-learn)

  2. 掌握数据集的多种加载方式(本地文件、库内置数据)

  3. 理解训练集/测试集划分、五折交叉验证的原理与实现

  4. 学会计算模型的准确率、精度、召回率和F1值等核心评估指标

二、实验核心内容

本次实验围绕Iris数据集展开,主要完成4件事:

  1. 用pandas读取本地存储的Iris数据集(CSV格式、UCI标准格式)

  2. 直接从scikit-learn库加载内置Iris数据集

  3. 基于随机森林模型实现五折交叉验证训练

  4. 计算并对比不同加载方式下的模型评估指标

三、算法设计思路

1. 核心逻辑

通过五折交叉验证充分利用有限数据,避免单一划分带来的结果偶然性,同时通过多指标全面评估模型泛化能力。

2. 算法伪代码

def EvaluateRF-CV(X, y, target_names, model, random_state=42):
# 1. 定义5折交叉验证(打乱数据,固定随机种子保证可重复)
kf = KFold(n_splits=5, shuffle=True, random_state=random_state)

2. 计算每折准确率

acc_scores = cross_val_score(model, X, y, cv=kf, scoring='accuracy')

3. 得到交叉验证的预测标签

y_pred = cross_val_predict(model, X, y, cv=kf)

4. 计算多维度评估指标(加权平均处理多分类)

avg_acc = mean(acc_scores)
std_acc = std(acc_scores)
precision = precision_score(y, y_pred, average='weighted', zero_division=0)
recall = recall_score(y, y_pred, average='weighted', zero_division=0)
f1 = f1_score(y, y_pred, average='weighted', zero_division=0)

5. 输出结果

print(f"五折交叉验证准确率: {avg_acc:.4f} (±{std_acc:.4f})")
print(f"Precision: {precision:.4f} Recall: {recall:.4f} F1: {f1:.4f}")
print(classification_report(y, y_pred, target_names=target_names))

return avg_acc, precision, recall, f1

### 3. 关键参数说明
| 参数 | 含义 | 作用 |
|------|------|------|
| n_estimators=100 | 随机森林中决策树数量 | 平衡模型性能与计算成本 |
| random_state=42 | 随机种子 | 保证实验结果可重复 |
| max_depth=3 | 单棵决策树最大深度 | 防止模型过拟合 |
| cv=5 | 交叉验证折数 | 充分利用数据,提升评估可靠性 |
| average='weighted' | 多分类指标平均方式 | 处理类别平衡问题 |
## 四、完整代码实现
```python
"""
机器学习入门:数据准备与模型评估(Iris数据集)
"""
import pandas as pd
import numpy as np
import os
import warnings
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score, cross_val_predict, KFold
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, classification_report
from sklearn.preprocessing import LabelEncoder
warnings.filterwarnings("ignore")
# ---------------------- 数据加载函数 ----------------------
def load_iris_local():
 """加载本地CSV格式Iris数据集(UTF-8-sig编码)"""
 try:
 df = pd.read_csv("iris.csv", encoding="utf-8-sig")
 X = df.drop("species", axis=1).values
 y = df["species"].values
 le = LabelEncoder()
 y_encoded = le.fit_transform(y)
 print("✅ 成功从本地 iris.csv 加载数据")
 return X, y_encoded, le.classes_
 except FileNotFoundError:
 print("❌ 本地 iris.csv 未找到")
 return None, None, None
def load_iris_data_file():
 """加载UCI标准格式 iris.data"""
 try:
 cols = ["sepal_length", "sepal_width", "petal_length", "petal_width", "class"]
 df = pd.read_csv("iris.data", header=None, names=cols)
 X, y = df.iloc[:, :-1].values, df.iloc[:, -1].values
 le = LabelEncoder()
 y_encoded = le.fit_transform(y)
 print("✅ 成功从 iris.data 加载数据")
 return X, y_encoded, le.classes_
 except Exception as e:
 print(f"❌ 读取 iris.data 失败: {e}")
 return None, None, None
def load_bezdek_iris_data():
 """加载Iris数据集变体 bezdekIris.data"""
 try:
 cols = ["sepal_length", "sepal_width", "petal_length", "petal_width", "class"]
 df = pd.read_csv("bezdekIris.data", header=None, names=cols)
 X, y = df.iloc[:, :-1].values, df.iloc[:, -1].values
 le = LabelEncoder()
 y_encoded = le.fit_transform(y)
 print("✅ 成功从 bezdekIris.data 加载数据")
 return X, y_encoded, le.classes_
 except Exception as e:
 print(f"❌ 读取 bezdekIris.data 失败: {e}")
 return None, None, None
def load_iris_sklearn():
 """直接从scikit-learn加载内置数据集"""
 iris = load_iris()
 print("✅ 成功从 scikit-learn 加载数据")
 return iris.data, iris.target, iris.target_names
# ---------------------- 工具函数 ----------------------
def list_available_files():
 """列出本地可加载的数据集文件"""
 files = []
 desc = {
 "iris.data": "UCI标准Iris数据集",
 "bezdekIris.data": "Iris数据集变体",
 "iris.csv": "CSV格式Iris数据集",
 }
 print("\n📂 本地可用数据集文件:")
 for f in desc:
 if os.path.exists(f):
 size = os.path.getsize(f)
 files.append(f)
 print(f" {f:<20} {size:>6} B {desc[f]}")
 return files
def create_local_iris_file():
 """自动生成CSV格式Iris数据集(方便本地使用)"""
 try:
 iris = load_iris()
 df = pd.DataFrame(iris.data, columns=iris.feature_names)
 df["species"] = [iris.target_names[i] for i in iris.target]
 df.to_csv("iris.csv", index=False, encoding="utf-8-sig")
 print("✅ 已自动创建 iris.csv 文件")
 return True
 except Exception as e:
 print(f"❌ 创建 iris.csv 失败: {e}")
 return False
def display_dataset_info(X, y, target_names, source):
 """展示数据集基本信息"""
 print(f"\n📊 {source} 数据集信息:")
 print(f" 数据形状: {X.shape} 类别数: {len(target_names)}")
 unique, counts = np.unique(y, return_counts=True)
 for cls, cnt in zip(unique, counts):
 print(f" {target_names[cls]:<15} {cnt:>3} 条样本")
 feature_names = ["花萼长度", "花萼宽度", "花瓣长度", "花瓣宽度"]
 for i, name in enumerate(feature_names):
 print(f" {name}: 均值={X[:, i].mean():.2f} 标准差={X[:, i].std():.2f}")
def evaluate_model(X, y, target_names, model, model_name="模型"):
 """五折交叉验证 + 多指标评估"""
 kf = KFold(n_splits=5, shuffle=True, random_state=42)
 acc_scores = cross_val_score(model, X, y, cv=kf, scoring="accuracy")
 y_pred = cross_val_predict(model, X, y, cv=kf)
 avg_acc, std_acc = acc_scores.mean(), acc_scores.std()
 prec = precision_score(y, y_pred, average="weighted", zero_division=0)
 rec = recall_score(y, y_pred, average="weighted", zero_division=0)
 f1 = f1_score(y, y_pred, average="weighted", zero_division=0)
 print(f"\n🏆 {model_name} 评估结果:")
 print(f" 五折交叉验证准确率: {avg_acc:.4f} (±{std_acc:.4f})")
 print(f" Precision: {prec:.4f} Recall: {rec:.4f} F1: {f1:.4f}")
 print("\n详细分类报告:")
 print(classification_report(y, y_pred, target_names=target_names, digits=4))
 return avg_acc, prec, rec, f1
# ---------------------- 主程序 ----------------------
def main():
 # 初始化随机森林模型(固定参数保证可重复)
 rf = RandomForestClassifier(n_estimators=100, random_state=42, max_depth=3)
 print("=" * 60)
 print("机器学习实践:数据准备与模型评估(Iris数据集)")
 print("=" * 60)
 # 列出本地可用文件
 available_files = list_available_files()
 # 构建加载方式菜单
 loader_map = {
 "1": (load_iris_sklearn, "scikit-learn内置"),
 "2": (load_iris_local, "本地iris.csv"),
 "3": (load_iris_data_file, "iris.data"),
 "4": (load_bezdek_iris_data, "bezdekIris.data"),
 }
 menu = {"1": "从 scikit-learn 库直接加载"}
 if "iris.csv" in available_files:
 menu["2"] = "从本地CSV文件加载"
 if "iris.data" in available_files:
 menu["3"] = "从 iris.data 加载"
 if "bezdekIris.data" in available_files:
 menu["4"] = "从 bezdekIris.data 加载"
 if not any(f in available_files for f in ["iris.csv", "iris.data", "bezdekIris.data"]):
 menu["5"] = "创建本地 iris.csv 文件"
 menu["0"] = "退出程序"
 # 交互选择加载方式
 while True:
 print("\n🔧 请选择数据加载方式:")
 for k, v in menu.items():
 print(f"{k}. {v}")
 choice = input(">>> ").strip()

if choice == "0":
 print("👋 程序已退出")
 break

# 自动创建本地文件
 if choice == "5" and "5" in menu:
 if create_local_iris_file():
 X, y, names = load_iris_local()
 if X is not None:
 display_dataset_info(X, y, names, "新建本地CSV")
 evaluate_model(X, y, names, rf, "新建本地CSV数据集")
 continue

# 加载选中的数据集
 if choice not in loader_map or choice not in menu:
 print("❌ 无效选择,请重新输入")
 continue
 loader, desc = loader_map[choice]
 X, y, names = loader()
 if X is None:
 continue

# 展示信息并评估模型
 display_dataset_info(X, y, names, desc)
 evaluate_model(X, y, names, rf, desc)
 # 是否继续尝试其他加载方式
 if input("\n🔄 是否继续尝试其他加载方式? (y/n) ").lower() != "y":
 print("🎉 实验完成!")
 break
 print("=" * 60)
if __name__ == "__main__":
 main()

五、实验运行结果

1. 不同加载方式的性能对比

数据加载方式 五折交叉验证准确率 精度 召回率 F1值
scikit-learn内置 0.9600 (±0.0249) 0.9600 0.9600 0.9600
本地iris.data 0.9600 (±0.0249) 0.9600 0.9600 0.9600
本地bezdekIris.data 0.9600 (±0.0249) 0.9600 0.9600 0.9600
本地CSV文件 0.9600 (±0.0249) 0.9600 0.9600 0.9600

2. 关键结论

  • 不同加载方式下,模型性能基本一致,说明数据加载逻辑可靠

  • 随机森林在Iris数据集上表现优异,平均准确率达96%

  • 三类鸢尾花中,Iris-setosa的识别准确率达100%,另外两类准确率约94%

    六、实验心得与收获

  1. 数据准备是基础:实际项目中数据格式多样(CSV、原始文本等),需要掌握灵活的加载和预处理方法。这次实现了多种格式的兼容加载,还添加了自动创建文件的容错机制,深刻体会到"数据干净,模型才靠谱"。
  2. 交叉验证的重要性:五折交叉验证比单一训练测试分割更能反映模型真实性能,避免了数据划分的偶然性。通过标准差可以看到,模型性能波动很小(±0.0249),说明模型稳定性较好。
  3. 多指标评估更全面:单一准确率在类别不平衡时会误导判断,而精度、召回率、F1值能从不同角度评估模型。比如这次实验中,虽然整体准确率很高,但通过分类报告能看到具体类别的表现差异。
  4. 工程细节不能忽视:随机种子的固定、标签编码的一致性、异常处理(文件不存在等情况),这些细节决定了实验的可重复性和代码的健壮性。
    作为机器学习入门的第一个实验,这次实践不仅巩固了Python和scikit-learn的使用,更建立了"数据-模型-评估"的完整思维框架。后续可以尝试调整模型超参数(比如决策树数量、深度),或者更换其他模型(如逻辑回归、SVM)进行对比,进一步深化理解~
posted @ 2025-12-29 14:44  Moonbeamsc  阅读(3)  评论(0)    收藏  举报
返回顶端