数据预处理与特征工程
概念: 数据预处理与特征工程泛指对训练数据集进行特征增加、删除、变换的方法
目标: 通过对训练数据的处理变换,提高模型的训练表现和泛化能力。
类别:
- 特征变化:预处理、标准化、纠偏
- 特征增加与删减:特征降维与变量扩展
模型评价体系:
- 模型:规律和经验
- 学习:从数据中总结规律的过程
- 误差:衡量模型准确性的指标
- 训练集:训练模型的数据集
- 验证集:测试机器学习模型繁华能力的数据集
- 应用数据:模型实际应用场景中的特征集
数据预处理
缺失值:样本的部分特征信息缺失
处理方式:
- 删除:缺失样本量非常大,删除整个变量,如果缺失了较少,且难以填充,则删除缺失值
- 填充:缺失量小于10%,根据缺失变量的数据分布采取均值或中位数进行填充
- 模拟或预测缺失样本:根据样本的数据分布,生成随机值填充;使用与缺失值相比相关性非常高的特征,建立模型,预测缺失值
数据预处理演示
用到的数据集:https://download.csdn.net/download/d1240673769/20910882
import pandas as pd
import matplotlib.pyplot as plt
# 样例数据读取
df = pd.read_excel('realestate_sample.xlsx')
# 数据集基本情况查看
print(df.shape)
print(df.dtypes)
df.head()
查看数据样本中的缺失情况
# 缺失值处理
# 查看数据样本中的缺失情况
print(df.isnull().sum())
查看房价分布
# 逐一查看特征,进行缺失值填充
df['average_price'].hist()
plt.show()
类似正态分布,选择均值填充
# 选择均值填充
price_mean = df['average_price'].mean()
print(price_mean)
# 使用均值进行缺失值填充
df.loc[df['average_price'].isna(),'average_price'] = price_mean
print(df.isnull().sum())
查看面积数据分布情况
df['area'].hist()
plt.show()
偏态分布,适合中位数填充
# 选择中位数填充
area_median = df['area'].median()
print(area_median)
# 使用均值进行缺失值填充
df.loc[df['area'].isna(),'area'] = area_median
print(df.isnull().sum())
查看’daypop’,‘nightpop’,'night20-39’三个特征的相关性系数
# 查看相关性系数
print(df[['daypop','nightpop','night20-39']].corr())
日间人口和夜间人口相关性较高,因此选择用日间人口数据来预测夜间人口
# 训练线性回归模型对夜间人口进行填补
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, r2_score
train = df.copy().loc[~df['nightpop'].isna(),['daypop','nightpop']].reset_index(drop=True)
x = train[['daypop']]
y = train[['nightpop']]
model = LinearRegression()
model.fit(x,y)
print(f'R squared is: {r2_score(y, x)}')
# 填充夜间人口缺失数据
df.loc[df['nightpop'].isna(),['nightpop']] = model.predict(df.loc[df['nightpop'].isna(),['daypop']])
print(df.isnull().sum())
特殊类型的缺失值
# 特殊类型的缺失值
print(df.complete_year.value_counts()) # 房屋建成年代字段中存在未知
# 做切片删除缺失房龄的样本
df = df[df.complete_year!='未知'].reset_index(drop=True)
离群值:远离数据主要部分的样本(极大值或极小值)
处理方式:
- 删除:直接删除离群样本
- 填充样本:使用 box-plot 定义变量的数值上下界,以上界填充极大值,以下界填充最小值
查看房价的离群情况
# 查看房价的离群情况
df['average_price'].hist()
plt.show()
df[['average_price']].boxplot()
plt.show()
根据箱线图的上下限进行异常值的填充
# 根据箱线图的上下限进行异常值的填充
def boxplot_fill(col):
# 计算iqr:数据四分之三分位值与四分之一分位值的差
iqr = col.quantile(0.75)-col.quantile(0.25)
# 根据iqr计算异常值判断阈值
u_th = col.quantile(0.75) + 1.5*iqr # 上界
l_th = col.quantile(0.25) - 1.5*iqr # 下界
# 定义转换函数:如果数字大于上界则用上界值填充,小于下界则用下界值填充。
def box_trans(x):
if x > u_th:
return u_th
elif x < l_th:
return l_th
else:
return x
return col.map(box_trans)
# 填充效果查看
boxplot_fill(df['average_price']).hist()
# 进行赋值
df['average_price'] = boxplot_fill(df['average_price'])
plt.show()
标准化
标准化目的:
- 去除数据量纲的影响
- 提高模型的解释性
- 加快模型收敛速度
标准化的方法:
- 中心化:减去均值再除以标准差
- 0-1标准化:减去最小值再除以最大值与最小值的差
sklearn 中标准化的方法
# sklearn 中标准化的方法
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
# 以中心化为例讲解sklearn中标准化的使用方法
scaler = StandardScaler()
df['daypop'].hist()
plt.show()
trans_data = df.copy()[['daypop']]
scaler.fit(trans_data)
trans_data['daypop'] = scaler.transform(trans_data)
trans_data['daypop'].hist()
plt.show()
使用pipeline整合数据标准化与模型
# 使用pipeline整合数据标准化与模型
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# 构建模型工作流
pipe_lm = Pipeline([
('sc',StandardScaler()),
('lm_regr',LinearRegression())
])
print(pipe_lm)
纠偏
- 正态分布:数据呈现对称的钟型分布
- 右偏态:样本大量集中在均值左边(均值偏到了右边)
- 左偏态:样本大量集中在均值右边(均值偏到了左边)
处理方法:
- 右偏态:常用对数函数处理
- 左偏态:常用指数函数处理
通用变换方法:以降低数据的偏态系数为目标,使得数据分布更加接近正态分布的变换方法
- yeo-johnson 变换:可以处理包含正数、负数和零的变量
- box-cox 变换:只能处理数值皆为正数的变量
sklearn 中纠偏的方法
# sklearn 中纠偏的方法
from sklearn.preprocessing import PowerTransformer
# 参数讲解
# method = 'yeo-johnson' or 'box-cox’
# 使用pipeline进行纠偏过程的整合
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline
# 构建模型工作流
pipe_lm = Pipeline([
('sc',StandardScaler()),
('pow_trans',PowerTransformer(method='yeo-johnson')),
('lm_regr',LinearRegression())
])
print(pipe_lm)
特征工程
共线性
特征间共线性:
- 两个或多个特征包含了相似的信息,其间存在强烈的相关关系
常用判断标准:
- 两个或两个以上的特征间的相关性系数高于0.8
共线性的影响:
- 降低运算效率
- 降低一些模型的稳定性
- 弱化一些模型的预测能力
处理方式:
- 删除:一组相互共线的特征中只保留与y相关性最高的一个
- 变换:对共线的两列特征进行求比值、求差值等计算
特征工程的演示
# 特征工程的演示
import pandas as pd
import matplotlib.pyplot as plt
# 样例数据读取
df = pd.read_excel('realestate_sample_preprocessed.xlsx')
# 数据集基本情况查看
print(df.shape)
print(df.dtypes)
print(df.isnull().sum())
df.head()
变量相关性矩阵
# 变量相关性矩阵
correlation_table = df.drop(columns='id').corr()
print(correlation_table)
对相关性矩阵进行可视化
# 对相关性矩阵进行可视化
import seaborn as sns
# 绘制相关性矩阵热力图
sns.heatmap(correlation_table)
plt.show()
查看共线的日间、夜间、夜间20-39岁人口与房价的关系
# 查看共线的日间、夜间、夜间20-39岁人口与房价的关系
print(df[['average_price','daypop','nightpop','night20-39']].corr())
根据共线性矩阵,保留与房价相关性最高的日间人口,将夜间人口和20-39岁夜间人口进行比例处理
# 根据共线性矩阵,保留与房价相关性最高的日间人口,将夜间人口和20-39岁夜间人口进行比例处理
def age_percent(row):
if row['nightpop'] == 0:
return 0
else:
return row['night20-39']/row['nightpop']
df['per_a20_39'] = df.apply(age_percent,axis=1)
df = df.drop(columns=['nightpop','night20-39'])
# 再次查看相关性矩阵的热力图
correlation_table = df.corr()
sns.heatmap(correlation_table)
数据降维与特征提取
处理目的:
- 降低不相关特征对于模型准确性的干扰
- 降低模型复杂度,提高模型泛化能力
- 减少模型特征,提高模型训练与预测速度
处理方法:
- 基于数据理解,直接删除
- 使用主成分分析(PCA)对特征进行变换
- 使用机器学习模型对特征进行筛选
查看样例数据特征表
# 查看样例数据特征表
df.columns
查看主成分对于数据的解释方差百分比
# 载入sklearn里的pca模块
from sklearn.decomposition import PCA
pca = PCA(n_components=5) # 降维到5个特征
x = df[['complete_year','area', 'daypop', 'sub_kde',
'bus_kde', 'kind_kde', 'per_a20_39']]
# 使用x进行pca模型训练同时对x进行转换
x_transform = pca.fit_transform(x)
# 查看主成分对于数据的解释方差百分比
print(pca.explained_variance_ratio_.sum())
# 查看保留主成分数量与方差解释百分比
for i in range(1,8):
pca = PCA(n_components=i)
x_transform = pca.fit_transform(x)
print(f'components={i},explanined_variance={pca.explained_variance_ratio_.sum()}')
常用判断标准:保留数据的解释方差累计百分比达到95%的所有特征
使用pipeline整合数据标准化、主成分分析与模型
# 使用pipeline整合数据标准化、主成分分析与模型
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.pipeline import Pipeline
# 构建模型工作流
pipe_lm = Pipeline([
('sc',StandardScaler()),
('pca',PCA(n_components=1)),
('lm_regr',LinearRegression())
])
print(pipe_lm)
使用模型进行特征筛选
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import Lasso
# 准备筛选数据
x = df[['complete_year','area', 'daypop', 'sub_kde',
'bus_kde', 'kind_kde', 'per_a20_39']]
print(x.shape[1])
y = df[['average_price']]
# 定义筛选模型
lasso_lm = Lasso(alpha = 500)
# 定义特征筛选器
select_m = SelectFromModel(lasso_lm)
# 训练筛选器
select_m.fit(x,y)
# 运行筛选结果
print(select_m.transform(x).shape[1])
构建模型工作流
# 构建模型工作流
pipe_lm = Pipeline([
('sc',StandardScaler()),
('lasso_select',SelectFromModel(lasso_lm)),
('lm_regr',LinearRegression())
])
print(pipe_lm)
特征扩展
处理目的:
- 解决模型欠拟合
- 捕捉自变量与因变量之间的非线性关系
常见处理方法:多项式拓展
- 假设数据集中包含自变量a、b
- 如果对自变量做二项式扩展
- 自变量集从两个变量扩展为5个变量(a、b、axa、bxb、axb)
from sklearn.preprocessing import PolynomialFeatures
# 准备筛选数据
x = df[['complete_year','area', 'daypop', 'sub_kde',
'bus_kde', 'kind_kde', 'per_a20_39']]
print(x.shape[1])
# 定义特征扩展模型并扩展特征
polynomy = PolynomialFeatures(degree=2) #进行2级扩展
# 训练筛选器
new_x = polynomy.fit_transform(x)
print(new_x.shape[1]) # 处理之后的特征个数
构建模型工作流
# 构建模型工作流
pipe_lm = Pipeline([
('sc',StandardScaler()),
('poly_trans',PolynomialFeatures(degree=2)),
('lm_regr',LinearRegression())
])
print(pipe_lm)