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

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

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

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

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

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

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

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

python 复制代码
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 数值特征离散化(捕捉非线性关系)

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

python 复制代码
# 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()手动映射。
python 复制代码
# 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" 的分布,可让模型公平对待每个特征:

python 复制代码
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 基于相关性的特征筛选

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

python 复制代码
# 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" 是唯一标识,无预测价值,需剔除;
  • "是否促销日" 虽与销量相关性不高,但业务上已知促销会影响销量,需保留;
  • "购买时间戳" 已提取为 "购买月份""是否周末",原字段冗余,需剔除。
python 复制代码
# 基于业务逻辑删除无用特征
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) 的拆分。

以鸢尾花分类任务为例:

python 复制代码
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 中,才能结合业务信息(如 "萼片长""花瓣宽")分析预测效果,尤其是错误样本的原因。

python 复制代码
# 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()可实现端到端流程:

python 复制代码
# 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'")
相关推荐
A尘埃2 小时前
NLP(自然语言处理, Natural Language Processing)
人工智能·自然语言处理·nlp
一碗白开水一2 小时前
【第19话:定位建图】SLAM点云配准之3D-3D ICP(Iterative Closest Point)方法详解
人工智能·算法
mit6.8242 小时前
[rStar] 策略与奖励大语言模型
人工智能·语言模型
CV-杨帆2 小时前
论文阅读:arxiv 2023 Large Language Models are Not Stable Recommender Systems
论文阅读·人工智能·语言模型
羊羊小栈3 小时前
基于「YOLO目标检测 + 多模态AI分析」的植物病害检测分析系统(vue+flask+数据集+模型训练)
人工智能·yolo·目标检测·毕业设计·创业创新·大作业
虚拟现实旅人3 小时前
【机器学习】通过tensorflow实现猫狗识别的深度学习进阶之路
深度学习·机器学习·tensorflow
胡耀超3 小时前
5、Python-NumPy科学计算基础
开发语言·人工智能·python·深度学习·numpy
茜茜西西CeCe3 小时前
数字图像处理-图像的基本运算
图像处理·人工智能·计算机视觉·matlab·图像的基本运算
武子康4 小时前
AI-调查研究-74-具身智能 机器人学习新突破:元学习与仿真到现实迁移的挑战与机遇
人工智能·程序人生·ai·职场和发展·系统架构·机器人·具身智能