当前位置: 首页 > news >正文

机器学习实战(二):Pandas 特征工程与模型协同进阶

在上一篇中,我们通过 Pandas 完成了机器学习的 “数据清洗” 环节 —— 从加载数据到处理缺失值、去重筛选,得到了 “干净” 的原始数据。但 “干净数据” 不等于 “可用特征”,机器学习模型真正需要的是结构化、有预测价值的特征。本文作为系列第二篇,将聚焦 Pandas 在特征工程模型协同中的核心应用,从特征提取、转换、选择,到与 Scikit-learn 模型对接、预测结果分析,帮你打通从 “数据” 到 “模型” 的关键链路。

一、Pandas 特征工程:从原始数据到高价值特征

特征工程是机器学习的 “灵魂”—— 好的特征能让简单模型达到复杂模型的效果,而差的特征会让复杂模型失效。Pandas 凭借灵活的列操作能力,可完成特征提取、转换、选择三大核心任务,为模型注入 “预测能力”。

1.1 特征提取:挖掘隐藏在原始数据中的信息

原始数据中的信息往往是 “零散” 的(如日期、连续数值),需通过 Pandas 提取成可建模的特征。常见场景包括时间特征提取、数值特征离散化等。

1.1.1 时间特征提取(时间序列数据必备)

若数据包含时间列(如 “购买时间”“浏览时间”),提取年、月、星期等特征,能有效捕捉时间维度的规律(如周末销量更高、旺季价格上涨):

import pandas as pd
df = pd.read_csv("商品销售数据.csv", encoding='gbk')# 1. 先将字符串格式的时间转换为Pandas时间类型(关键步骤!)
df['购买时间'] = pd.to_datetime(df['购买时间'], format='%Y-%m-%d %H:%M:%S')# 2. 提取核心时间特征
df['购买年份'] = df['购买时间'].dt.year          # 年份(如2024)
df['购买月份'] = df['购买时间'].dt.month        # 月份(1-12)
df['购买星期'] = df['购买时间'].dt.dayofweek    # 星期(0=周一,6=周日)
df['是否周末'] = df['购买星期'].apply(lambda x: 1 if x in [5,6] else 0)  # 周末标记(1=是,0=否)
df['是否促销日'] = df['购买时间'].dt.day.apply(lambda x: 1 if x in [1,11,12] else 0)  # 特殊日期标记# 查看提取结果
print("时间特征提取结果:")
print(df[['购买时间', '购买月份', '购买星期', '是否周末', '是否促销日']].head(10))
1.1.2 数值特征离散化(捕捉非线性关系)

连续数值特征(如 “价格”“好评数”)直接输入模型可能无法捕捉非线性规律(如 “低价商品销量骤增,高价商品销量稳定”),通过离散化将其划分为区间,可转化为更有价值的分类特征:

# 1. 手动指定区间:将“价格”划分为4个区间(适合业务明确的场景)
price_bins = [0, 3000, 6000, 10000, float('inf')]  # 区间边界:0-3k、3k-6k、6k-1w、1w+
price_labels = ['低价', '中价', '高价', '超高价']    # 区间标签(便于理解)
df['价格区间'] = pd.cut(df['价格'], bins=price_bins, labels=price_labels, right=False)  # right=False:左闭右开# 2. 自动等频划分:将“好评数”按样本数量平均分为4段(适合业务不明确的场景)
df['好评数等级'] = pd.qcut(df['好评数'], q=4, labels=['极低', '较低', '较高', '极高'])  # q=4:分4段# 统计各区间样本数量(验证离散化效果)
print("\n各价格区间商品数量:")
print(df['价格区间'].value_counts())
print("\n各好评数等级商品数量:")
print(df['好评数等级'].value_counts())

1.2 特征转换:让特征适配模型输入要求

机器学习模型无法直接处理两类数据:字符串类型的分类特征(如 “品牌 = 苹果”)和尺度差异大的数值特征(如 “收入 = 100000” 与 “年龄 = 30”)。Pandas 可结合 Scikit-learn 完成编码和标准化,解决这两个问题。

1.2.1 分类特征编码(字符串→数值)
  • One-Hot 编码:适用于无顺序的分类特征(如 “品牌”“颜色”),通过pd.get_dummies()实现,避免模型误解类别顺序;
  • 标签编码:适用于有顺序的分类特征(如 “好评等级 = 低 / 中 / 高”),通过map()手动映射。
# 1. One-Hot编码:处理“品牌”特征(无顺序)
df_onehot = pd.get_dummies(df, columns=['品牌'], prefix='品牌')  # prefix:新列名前缀(避免列名重复)
print("\nOne-Hot编码后新增列:")
print([col for col in df_onehot.columns if col.startswith('品牌_')])  # 查看新增的品牌列# 2. 标签编码:处理“好评数等级”特征(有顺序:极低<较低<较高<极高)
grade_map = {'极低': 0, '较低': 1, '较高': 2, '极高': 3}
df['好评数等级_编码'] = df['好评数等级'].map(grade_map)
print("\n标签编码结果:")
print(df[['好评数等级', '好评数等级_编码']].head())
1.2.2 数值特征标准化(消除尺度影响)

KNN、SVM、线性回归等模型对特征尺度敏感(如 “收入” 的数值范围远大于 “年龄”,会主导模型计算)。通过标准化将特征转换为 “均值 = 0、标准差 = 1” 的分布,可让模型公平对待每个特征:

from sklearn.preprocessing import StandardScaler# 1. 选择需要标准化的数值特征(如“价格”“好评数”“总评价数”)
numeric_features = ['价格', '好评数', '总评价数']
X_numeric = df[numeric_features]# 2. 初始化标准化器并拟合数据(计算均值和标准差)
scaler = StandardScaler()
X_numeric_scaled = scaler.fit_transform(X_numeric)  # 返回NumPy数组# 3. 将标准化结果转换回DataFrame(便于后续查看和合并)
X_numeric_scaled_df = pd.DataFrame(X_numeric_scaled, columns=[f'{col}_标准化' for col in numeric_features],  # 新列名index=df.index  # 保持索引一致,便于合并
)# 4. 合并标准化特征到原数据
df_final = pd.concat([df, X_numeric_scaled_df], axis=1)  # axis=1:按列拼接# 验证标准化效果(均值接近0,标准差接近1)
print("\n标准化后特征统计:")
print(X_numeric_scaled_df.describe().round(2))

1.3 特征选择:剔除冗余特征,降低模型复杂度

并非所有特征都对预测有用 —— 冗余特征(如 “购买时间戳” 与 “购买年份” 高度相关)会增加模型计算量,甚至导致过拟合。Pandas 可通过相关性分析业务逻辑筛选核心特征。

1.3.1 基于相关性的特征筛选

通过计算特征与目标变量(如 “销量”)的相关系数,保留相关性高的特征;同时剔除特征间高度相关的冗余特征:

# 1. 计算所有数值特征与目标变量(“销量”)的相关系数
corr_with_target = df_final.corr()['销量'].sort_values(ascending=False)
print("各特征与销量的相关系数:")
print(corr_with_target.round(2))# 2. 筛选:保留与销量相关系数绝对值>0.3的特征(认为有较强预测价值)
useful_features = corr_with_target[abs(corr_with_target) > 0.3].index.tolist()
df_useful = df_final[useful_features]# 3. 剔除特征间高度相关的冗余特征(相关系数>0.8)
corr_matrix = df_useful.corr()  # 计算有用特征的相关性矩阵
high_corr_pairs = []
for i in range(len(corr_matrix.columns)):for j in range(i+1, len(corr_matrix.columns)):if abs(corr_matrix.iloc[i, j]) > 0.8:high_corr_pairs.append((corr_matrix.columns[i], corr_matrix.columns[j]))# 手动剔除冗余特征(保留业务意义更明确的)
redundant_features = [pair[1] for pair in high_corr_pairs]
df_selected = df_useful.drop(columns=redundant_features)print(f"\n剔除的冗余特征:{redundant_features}")
print(f"最终筛选的特征:{df_selected.columns.tolist()}")
1.3.2 基于业务逻辑的特征筛选

除了统计方法,业务逻辑是特征选择的 “最后一道防线”。例如:

  • “商品 ID” 是唯一标识,无预测价值,需剔除;
  • “是否促销日” 虽与销量相关性不高,但业务上已知促销会影响销量,需保留;
  • “购买时间戳” 已提取为 “购买月份”“是否周末”,原字段冗余,需剔除。
# 基于业务逻辑删除无用特征
df_selected = df_selected.drop(columns=['商品ID', '购买时间戳'])
print(f"业务筛选后最终特征:{df_selected.columns.tolist()}")

二、Pandas 与机器学习模型协同:从特征到预测的闭环

完成特征工程后,需将 Pandas 的 DataFrame 转换为模型可接受的格式(NumPy 数组),并与 Scikit-learn 等库协同完成模型训练、预测及结果分析。这一环节的核心是 “格式兼容” 与 “结果回写”。

2.1 数据格式转换:DataFrame → NumPy 数组

大多数机器学习库(如 Scikit-learn、XGBoost)仅接受 NumPy 数组作为输入。Pandas 的values属性或to_numpy()方法可实现无缝转换,需注意特征(X) 与标签(y) 的拆分。

以鸢尾花分类任务为例:

import pandas as pd
from sklearn.neighbors import KNeighborsClassifier# 1. 加载并拆分特征与标签(假设已完成特征工程)
train_df = pd.read_excel("鸢尾花训练数据.xlsx")
test_df = pd.read_excel("鸢尾花测试数据.xlsx")# 2. 拆分特征(X)和标签(y)
# 特征:萼片长、萼片宽、花瓣长、花瓣宽(DataFrame→NumPy数组)
train_X = train_df[["萼片长(cm)", "萼片宽(cm)", "花瓣长(cm)", "花瓣宽(cm)"]].values
# 标签:花的类型(需展平为一维数组,避免模型报错)
train_y = train_df["类型_num"].values.ravel()# 测试集同理
test_X = test_df[["萼片长(cm)", "萼片宽(cm)", "花瓣长(cm)", "花瓣宽(cm)"]].values
test_y = test_df["类型_num"].values.ravel()# 3. 训练KNN模型
knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(train_X, train_y)  # 模型接受NumPy数组输入# 4. 模型预测
train_pred = knn.predict(train_X)
test_pred = knn.predict(test_X)
test_score = knn.score(test_X, test_y)
print(f"测试集准确率:{test_score:.2f}")

2.2 预测结果回写:将模型输出融入 DataFrame

模型预测的结果是 NumPy 数组,需回写到原始测试数据的 DataFrame 中,才能结合业务信息(如 “萼片长”“花瓣宽”)分析预测效果,尤其是错误样本的原因。

# 1. 将测试集预测结果回写到test_df
test_df["预测类型_num"] = test_pred# 2. 将数值标签转换为中文名称(更易理解业务含义)
type_map = {1: "山鸢尾", 2: "变色鸢尾", 3: "维吉尼亚鸢尾"}
test_df["预测类型名称"] = test_df["预测类型_num"].map(type_map)
test_df["实际类型名称"] = test_df["类型_num"].map(type_map)# 3. 查看预测结果详情(对比实际与预测类型)
result_detail = test_df[["萼片长(cm)", "花瓣宽(cm)", "实际类型名称", "预测类型名称"]]
print("\n预测结果详情(前10条):")
print(result_detail.head(10))# 4. 筛选错误预测样本,分析原因(关键!优化模型的基础)
error_samples = test_df[test_df["实际类型名称"] != test_df["预测类型名称"]]
print(f"\n错误预测样本数量:{len(error_samples)}")
if len(error_samples) > 0:print("\n错误预测样本特征:")print(error_samples[["萼片长(cm)", "花瓣宽(cm)", "实际类型名称", "预测类型名称"]])

2.3 批量预测与结果导出:对接业务应用

在实际业务中,常需对批量新数据(无标签)进行预测,并将结果导出为 Excel/CSV 文件供业务部门使用(如 “鸢尾花分类结果表”“商品销量预测表”)。Pandas 的read_excel()to_excel()可实现端到端流程:

# 1. 加载批量新数据(无标签,仅含特征)
new_data = pd.read_excel("待预测鸢尾花数据.xlsx")
new_X = new_data[["萼片长(cm)", "萼片宽(cm)", "花瓣长(cm)", "花瓣宽(cm)"]].values# 2. 批量预测
new_data["预测类型_num"] = knn.predict(new_X)
new_data["预测类型名称"] = new_data["预测类型_num"].map(type_map)# 3. 导出预测结果到Excel(设置index=False,避免导出多余的行索引)
new_data.to_excel("鸢尾花预测结果.xlsx", index=False, sheet_name="预测结果")
print("\n批量预测完成!结果已导出至'鸢尾花预测结果.xlsx'")

文章转载自:

http://wH97vx0F.njpny.cn
http://x5jXq9kZ.njpny.cn
http://2zmELqOz.njpny.cn
http://mkO7O0zw.njpny.cn
http://ejuNx8NG.njpny.cn
http://OlAP33iB.njpny.cn
http://BzZNksQo.njpny.cn
http://7EWgMAik.njpny.cn
http://DRX3SYpf.njpny.cn
http://wsoRPKtB.njpny.cn
http://WKbVDJgi.njpny.cn
http://UoKs7dz2.njpny.cn
http://IHYdmDgn.njpny.cn
http://1Ph0Ifw3.njpny.cn
http://1IrAYdUQ.njpny.cn
http://cIm6QJ4m.njpny.cn
http://sSh0L3GY.njpny.cn
http://oIOYaaUr.njpny.cn
http://aYJR3Ddj.njpny.cn
http://LNaHkssS.njpny.cn
http://QZLlvBBl.njpny.cn
http://bOrIz3sr.njpny.cn
http://LVsBHCoK.njpny.cn
http://krp9f40X.njpny.cn
http://Ug9DmOxY.njpny.cn
http://7pdtrVTR.njpny.cn
http://oLlzhzAW.njpny.cn
http://Iw6Debj8.njpny.cn
http://FrWOLflI.njpny.cn
http://ZZfUxXtM.njpny.cn
http://www.dtcms.com/a/377479.html

相关文章:

  • Flutter 朦胧效果布局大全:5种方法实现优雅视觉层次
  • 【CVPR2023】奔跑而非行走:追求更高FLOPS以实现更快神经网络
  • PHP学习(第三天)
  • 数仓简要笔记-1
  • 机器人商业化落地需要突破的关键性技术
  • AI 技术体系核心概念
  • STM32H750 I2C介绍及应用
  • 计算机网络---物理层
  • 【freemarker】创建html页面
  • 【华为OD】区块链文件转储系统
  • sprintf不是像printf一样的打印函数吗
  • Js 图片加载完成 与 图片缓存加载的区别
  • 汽车动力电池管理系统(BMS):电动汽车的“智能大脑”
  • n8n add npm module 發生 Module ‘ioredis‘ is disallowed,getaddrinfo EAI_AGAIN
  • 性能——day3
  • 安卓学习 之 SeekBar(音视频播放进度条)
  • CRMEB标准版PHP订单列表功能详解与优化技巧
  • Linux基础知识(五)
  • [数据结构——lesson7.队列]
  • 在算法竞赛中怎样正确的分析一个程序的时间复杂度
  • ES6笔记4
  • 实现一个动态顺序表(C++)
  • 10 分钟上手 ECharts:从“能跑”到“生产级”的完整踩坑之旅
  • Decode Global新官网上线披露核心数据
  • 【Redis】Scan 命令使用教程:高效遍历海量数据
  • 深度解析:抗辐射电源芯片 ASP4644S2B 在空间环境中的单粒子效应表现
  • 多链冷换仓攻略:如何在 Solana、BSC 与 Base 隐身管理资产
  • 【博弈论和SG函数 | 那忘算10】巴什博奕 尼姆博弈及其变种 威佐夫博弈(附例题)
  • Cubemx+Fatfs(解决挂载Fatfs失败的问题)
  • UVa1063/LA3807 Marble Game