橘智橘智
FakeOrange
预计阅读时间:7分钟19秒

数据分析2.5 —— 特征工程入门!

垃圾进,垃圾出。数据的质量永远是第一准则

0
0

特征工程的介绍


特征工程是机器学习中非常关键的一步,它通过提取、构建、选择和处理模型输入数据的特征,使得模型能够更有效地从数据中学习并提高预测性能。对于泰坦尼克(Titanic)数据集,特征工程的主要任务是将原始数据中的各种信息(如乘客年龄、船票等级、登船地点等)处理成适合模型训练的格式,并构建新的有用特征。

下面我们将通过Titanic数据集演示常见的特征工程操作,并解释其重要性。


1. 数据加载和初步处理


首先,我们加载Titanic数据集并查看其结构。

import pandas as pd

# 加载数据
df = pd.read_csv('titanic.csv')

# 查看数据结构
print(df.info())
print(df.head())

我们可以看到数据集中存在诸如Age(年龄)、Sex(性别)、Embarked(登船地点)、Cabin(舱位)等特征。这些特征在模型训练前需要进行预处理。


2. 处理缺失值


在任何实际数据集中,缺失值都是常见的现象。特征工程中,处理缺失值是非常重要的一步,因为机器学习模型通常无法处理包含缺失值的数据。

# 查看数据中的缺失值
print(df.isnull().sum())

结果显示AgeEmbarkedCabin特征中存在缺失值:

  • Age(年龄):通常通过填充缺失值来处理,例如使用中位数或平均值。
  • Embarked(登船地点):使用众数(最常见值)进行填充。
  • Cabin(舱位):缺失值过多,直接删除该列或将其转换为是否有舱位的信息。

处理代码:

# 填充年龄的缺失值
df['Age'].fillna(df['Age'].median(), inplace=True)

# 填充登船地点的缺失值
df['Embarked'].fillna(df['Embarked'].mode()[0], inplace=True)

# 将舱位信息是否缺失转换为二值特征
df['Cabin_null'] = df['Cabin'].isnull().astype(int)

# 删除原始的Cabin列
df.drop(columns=['Cabin'], inplace=True)

# 再次检查缺失值
print(df.isnull().sum())

重要性:

  • 处理缺失值可以防止模型训练时出错,并最大限度地保留有用信息,确保数据的完整性。
  • 对于像Cabin这样缺失率过高的列,转换为二进制特征是一个有效的做法,因为是否有舱位可能与生存率相关。


注意!,中值插补仅用出现频次最高的或者平均数代替缺失数据,看似不影响结果的插补方式,实际会改变数据的结构分布。高级的方式会在以后介绍,也可使用一些对于缺失数据不敏感的算法如XGBoost


3. 类别型特征编码


机器学习模型无法直接处理类别型特征(如SexEmbarked),因此需要将它们转换为数值形式。这通常通过独热编码(One-Hot Encoding)或标签编码(Label Encoding)来实现。

# 独热编码(将类别变量转换为0/1的二进制变量)
df = pd.get_dummies(df, columns=['Sex', 'Embarked'], drop_first=True)

# 查看编码后的数据
print(df.head())
  • Sex 被转换为 Sex_male(1表示男性,0表示女性)。
  • Embarked 被转换为 Embarked_QEmbarked_S 两列,分别表示是否从不同地点登船。

重要性:

  • 类别特征编码让模型能够理解类别信息,并避免类别间的隐含顺序假设(如简单的数值编码可能会让模型误解类别间有顺序性)。


4. 构建新特征


构建新特征是提升模型性能的关键技巧之一。基于领域知识和已有特征,我们可以创建更具信息量的特征。例如:

  • 家庭规模(FamilySize):通过SibSp(兄弟姐妹/配偶)和Parch(父母/子女)的信息构造家庭规模特征。
  • 是否为孤身一人(IsAlone):根据FamilySize判断乘客是否是独自乘船。
# 构造家庭规模特征
df['FamilySize'] = df['SibSp'] + df['Parch'] + 1  # 自身也算作家庭成员

# 构造是否独自一人的特征
df['IsAlone'] = (df['FamilySize'] == 1).astype(int)

# 查看新特征
print(df[['FamilySize', 'IsAlone']].head())

重要性:

  • 家庭规模是否独自一人可能与乘客的生存率密切相关,因为有些研究表明,大家庭可能在混乱中不易生存,而独自一人可能更有灵活性。
  • 通过构建与任务相关的特征,模型可以获得更多有助于分类的信息,从而提升预测效果。


5. 特征缩放


对于某些机器学习模型(如线性回归、支持向量机、K近邻等),特征缩放非常重要,避免因特征取值范围不同而导致模型性能下降。我们可以使用标准化(Standardization)或归一化(Normalization)来进行特征缩放。

from sklearn.preprocessing import StandardScaler

# 定义需要缩放的特征
features_to_scale = ['Age', 'Fare', 'FamilySize']

# 进行标准化
scaler = StandardScaler()
df[features_to_scale] = scaler.fit_transform(df[features_to_scale])

# 查看缩放后的特征
print(df[features_to_scale].head())

重要性:

  • 特征缩放确保所有特征在同一数量级上,使得模型的训练过程更加稳定,尤其对于梯度下降法、KNN等依赖距离度量的模型,缩放至关重要。


6. 特征选择


在处理高维数据时,特征选择能够帮助我们减少数据的复杂度,并且有助于消除噪声特征。常用的特征选择方法有:

  • 基于统计方法:例如chi2检验、互信息、方差阈值等。
  • 基于模型的方法:使用L1正则化(Lasso)、随机森林等模型自动选择重要特征。
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import SelectFromModel

# 使用随机森林进行特征选择
rf = RandomForestClassifier(random_state=42)
rf.fit(df.drop(columns=['Survived']), df['Survived'])

# 选择重要性高于某个阈值的特征
selector = SelectFromModel(rf, threshold=0.01, prefit=True)
selected_features = df.drop(columns=['Survived']).columns[selector.get_support()]

# 查看选择的特征
print("选择的重要特征:", selected_features)

重要性:

  • 特征选择能够去除冗余或噪声特征,减少模型的复杂度,从而提升模型的泛化能力,并减少过拟合风险。


7. 树模型特征选择可视化


首先,确保已经加载并预处理数据集,例如处理缺失值和进行特征编码。

import pandas as pd
from sklearn.model_selection import train_test_split

# 加载数据集
df = pd.read_csv('titanic.csv')

# 处理缺失值
df['Age'].fillna(df['Age'].median(), inplace=True)
df['Embarked'].fillna(df['Embarked'].mode()[0], inplace=True)
df['Cabin_null'] = df['Cabin'].isnull().astype(int)
df.drop(columns=['Cabin'], inplace=True)

# 类别型特征编码
df = pd.get_dummies(df, columns=['Sex', 'Embarked'], drop_first=True)

# 划分特征和标签
X = df.drop(columns=['Survived'])
y = df['Survived']

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

训练随机森林模型


使用RandomForestClassifier来训练模型。

from sklearn.ensemble import RandomForestClassifier

# 创建随机森林模型
rf_model = RandomForestClassifier(random_state=42)
rf_model.fit(X_train, y_train)

查看特征重要性


随机森林模型可以通过feature_importances_属性来访问特征重要性。

# 获取特征重要性
importances = rf_model.feature_importances_

# 将特征重要性与特征名称组合成DataFrame
feature_importance_df = pd.DataFrame({'Feature': X.columns, 'Importance': importances})

# 按重要性排序
feature_importance_df = feature_importance_df.sort_values(by='Importance', ascending=False)

print(feature_importance_df)

可视化特征重要性


为了更好地理解特征重要性,可以使用可视化工具(如matplotlib)来绘制条形图。

import matplotlib.pyplot as plt

# 绘制特征重要性图
plt.figure(figsize=(10, 6))
plt.barh(feature_importance_df['Feature'], feature_importance_df['Importance'], color='skyblue')
plt.xlabel('Importance')
plt.title('Feature Importance using Random Forest')
plt.gca().invert_yaxis()  # 反转y轴,使得最重要的特征在上方
plt.show()


8. 完整代码总结

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import SelectFromModel

# 加载数据
df = pd.read_csv('titanic.csv')

# 处理缺失值
df['Age'].fillna(df['Age'].median(), inplace=True)
df['Embarked'].fillna(df['Embarked'].mode()[0], inplace=True)
df['Cabin_null'] = df['Cabin'].isnull().astype(int)
df.drop(columns=['Cabin'], inplace=True)

# 类别型特征编码
df = pd.get_dummies(df, columns=['Sex', 'Embarked'], drop_first=True)

# 构造新特征
df['FamilySize'] = df['SibSp'] + df['Parch'] + 1
df['IsAlone'] = (df['FamilySize'] == 1).astype(int)

# 特征缩放
features_to_scale = ['Age', 'Fare', 'FamilySize']
scaler = StandardScaler()
df[features_to_scale] = scaler.fit_transform(df[features_to_scale])

# 特征选择
X = df.drop(columns=['Survived'])
y = df['Survived']
rf = RandomForestClassifier(random_state=42)
rf.fit(X, y)
selector = SelectFromModel(rf, threshold=0.01, prefit=True)
selected_features = X.columns[selector.get_support()]

print("最终选择的重要特征:", selected_features)

总结

特征工程是机器学习流程中不可忽视的一步,它能够帮助模型更好地理解数据,提高预测性能。通过处理缺失值、类别特征编码、构建新特征、特征缩放和特


评论