趋近智
正如章节引言中提到的,原始数值特征,虽然看起来简单明了,但通常无法直接向机器学习算法展现其全部能力。像线性回归这样的模型假设线性关系,而其他模型可能难以处理倾斜的分布或大范围数据。从现有数值特征生成新特征可以帮助模型更好地获取潜在模式,处理非线性,并提升整体表现。接下来我们来看一些常用且有效的技术。
有时,特征的确切数值不如其所属的范围或箱位重要。分箱,也称离散化,指的是通过将数值归入预设的箱位,将连续数值特征转换为离散分类特征。这有以下几个用处:
分箱主要有两种方法:
假设我们有一个包含 Age 列的DataFrame df。
import pandas as pd
import numpy as np
# 示例数据
data = {'Age': [22, 25, 31, 45, 58, 62, 75, 81, 19, 38]}
df = pd.DataFrame(data)
# 1. 固定宽度分箱(例如,4个箱位)
# 显式定义箱位边界
bins = [18, 30, 45, 60, 100] # 年龄 18-30, 31-45, 46-60, 61-100
labels = ['18-30', '31-45', '46-60', '61+']
df['Age_Bin_Fixed'] = pd.cut(df['Age'], bins=bins, labels=labels, right=True, include_lowest=True)
# 或者让pandas自动确定等宽箱位
# df['Age_Bin_Fixed_Auto'] = pd.cut(df['Age'], bins=4) # 创建4个等宽箱位
# 2. 基于分位数的分箱(例如,4个分位数/四分位数)
df['Age_Bin_Quantile'] = pd.qcut(df['Age'], q=4, labels=['Q1', 'Q2', 'Q3', 'Q4'])
print(df)
选择箱位数量: 箱位数量是一个超参数。箱位过少可能会过度简化数据,从而丢失有价值的信息。箱位过多可能会使特征过于细化,接近原始连续变量,并可能导致过拟合。交叉验证可以帮助确定适当的箱位数量。
“线性模型根据定义,对线性关系进行建模()。然而,关系往往是非线性的。多项式特征通过将现有特征提升到某个幂次(例如,, )以及创建特征之间的交互项(例如,)来生成新特征。”
考虑一个简单特征 。添加 允许线性模型拟合二次关系:。这仍然是一个线性模型,因为它相对于系数()是线性的,即使 与原始 之间的关系是非线性的。
Scikit-learn 的 PolynomialFeatures 转换器是生成这些特征的便捷方法。
from sklearn.preprocessing import PolynomialFeatures
import pandas as pd
# 包含两个特征的示例数据
data = {'FeatureA': [1, 2, 3, 4, 5],
'FeatureB': [2, 3, 5, 5, 7]}
df_poly = pd.DataFrame(data)
# 创建最高2次的多项式特征
# include_bias=False 避免添加全为1的列(截距)
poly = PolynomialFeatures(degree=2, include_bias=False)
poly_features = poly.fit_transform(df_poly)
# 获取特征名称以便清晰查看
feature_names = poly.get_feature_names_out(df_poly.columns)
# 使用这些特征创建新的DataFrame
df_poly_transformed = pd.DataFrame(poly_features, columns=feature_names)
print("原始特征:")
print(df_poly)
print("\n多项式特征(2次):")
print(df_poly_transformed)
# 3次示例,仅FeatureA
poly_deg3 = PolynomialFeatures(degree=3, include_bias=False)
poly_features_a = poly_deg3.fit_transform(df_poly[['FeatureA']])
feature_names_a = poly_deg3.get_feature_names_out(['FeatureA'])
df_poly_a_transformed = pd.DataFrame(poly_features_a, columns=feature_names_a)
print("\n多项式特征(3次,仅FeatureA):")
print(df_poly_a_transformed)
考量因素:
应用对数、平方根或倒数等数学函数有助于稳定方差,使分布更对称(接近正态),并处理倾斜数据。许多机器学习算法在特征分布更接近高斯(正态)分布时表现更好。
让我们使用NumPy应用对数和平方根变换。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
# 示例倾斜数据(例如,收入)
np.random.seed(42)
income_data = np.random.gamma(2, scale=2000, size=1000)
income_data = np.round(income_data, 2)
df_trans = pd.DataFrame({'Income': income_data})
# 如果可能存在零值(此处不需要),则为对数变换添加一个小的常数
# df_trans['Income_Log'] = np.log(df_trans['Income'] + 1)
# 应用对数变换
df_trans['Income_Log'] = np.log(df_trans['Income'])
# 应用平方根变换
df_trans['Income_Sqrt'] = np.sqrt(df_trans['Income'])
# 应用Box-Cox变换
# scipy.stats.boxcox 返回变换后的数据和最优 lambda 值
df_trans['Income_BoxCox'], best_lambda = stats.boxcox(df_trans['Income'])
print(f"Box-Cox 的最优 lambda: {best_lambda:.4f}")
print(df_trans[['Income', 'Income_Log', 'Income_Sqrt', 'Income_BoxCox']].head())
# --- 可视化(可选:使用Matplotlib或Plotly进行分布图) ---
# Matplotlib示例(Plotly JSON对于分布图可能很大)
fig, axes = plt.subplots(1, 4, figsize=(16, 4))
axes[0].hist(df_trans['Income'], bins=30, color='#4dabf7')
axes[0].set_title('原始收入')
axes[1].hist(df_trans['Income_Log'], bins=30, color='#9775fa')
axes[1].set_title('对数变换后')
axes[2].hist(df_trans['Income_Sqrt'], bins=30, color='#69db7c')
axes[2].set_title('平方根变换后')
axes[3].hist(df_trans['Income_BoxCox'], bins=30, color='#ff922b')
axes[3].set_title('Box-Cox变换后')
plt.tight_layout()
# 如果在网络环境中使用,您会保存此图或生成一个Plotly版本。
# plt.show() # 取消注释可在本地显示图表
直方图说明了变换如何减少偏度。原始收入数据严重右偏。对数和Box-Cox变换产生了更接近对称的分布,而平方根变换效果更温和。
何时应用变换:
从数值数据生成特征通常是一个迭代过程。您可以尝试分箱、多项式特征或变换,训练模型,评估其表现,然后根据结果调整您的特征工程策略。这里讨论的技术为机器学习模型创建更具信息量的数值特征提供了坚实支持。
这部分内容有帮助吗?
© 2026 ApX Machine Learning用心打造