赛题链接地址
进度安排
特征工程
特征工程指的是把原始数据转变为模型的训练数据的过程,它的目的就是获取更好的训练数据特征,使得机器学习模型逼近这个上限。一般认为包括特征构建、特征提取、特征选择三个部分。
数据预处理
数据预处理是特征工程中最为重要的一个环节,良好的数据预处理可以使模型的训练达到事半功倍的效果。数据预处理旨在通过归一化、标准化、正则化等方式改进不完整、不一致、无法直接使用的数据。
1.引入数据
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import datetime
from sklearn.preprocessing import LabelEncoder
# 训练集
train=pd.read_csv('D:/tianchi/train.csv')
# 测试集
test_A=pd.read_csv('D:/tianchi/testA.csv')
# 数值型变量
quantitative = [f for f in train.columns if train[f].dtypes != 'object']
# 类别型变量
qualitative = [f for f in train.columns if train[f].dtypes == 'object']
2.缺失值填充
缺失数据比较多的情况下,可以直接滤除,缺失数据比较少时,对数据进行填充就很有必要。在比赛中不妨尝试多种填充然后比较结果选择结果最优的一种。
# 查看缺失值情况
train.isnull().sum()
## 数值型变量填充方式
# 固定值填充(用0填充)
train[quantitative] = train[quantitative].fillna(0)
# 用每列特征的均值填充缺失数据
train[quantitative] = train[quantitative].fillna(train[quantitative].mean())
# 用每列特征的中位数填充缺失数据
train[quantitative] = train[quantitative].fillna(train[quantitative].median())
# 用相邻横向上面非缺失特征填充空值
train[quantitative] = train[quantitative].fillna(axis=0, method='ffill')
# 用相邻横向下面非缺失特征填充空值
train[quantitative] = train[quantitative].fillna(axis=0, method='bfill')
## 类别型变量填充方式
# 用每列特征的众数填充缺失数据
train[qualitative] = train[qualitative].fillna(train[qualitative].mode())
3.对象类型变量处理
[f for f in train.columns if train[f].dtypes == 'object']
#['grade', 'subGrade', 'employmentLength', 'issueDate', 'earliesCreditLine']
# 时间列issueDate转换为时间格式
train['issueDate'] = pd.to_datetime(train['issueDate'],format='%Y-%m-%d')
startdate = datetime.datetime.strptime('2007-06-01', '%Y-%m-%d')
# 构造时间特征
train['issueDateDT'] = train['issueDate'].apply(lambda x: x-startdate).dt.days
# employmentLength列对象类型特征转换为数值
train['employmentLength'].value_counts(dropna=False).sort_index()
# 处理10+ years
train['employmentLength'].replace('10+ years','10 years', inplace=True)
# 处理<1 years
train['employmentLength'].replace('< 1 years','0 years', inplace=True)
# 分离字段
train['employmentLength'] = train['employmentLength'].apply(lambda x: x.split(' ')[0] if not(pd.isnull(x)) else x)
train['employmentLength'].value_counts(dropna=False).sort_index()
# earliesCreditLine列截取年
train['earliesCreditLine'] = train['earliesCreditLine'].apply(lambda s: int(s[-4:]))
4.类别变量处理
# 部分类别特征
cate_features = ['grade', 'subGrade', 'employmentTitle', 'homeOwnership', 'verificationStatus', 'purpose', 'postCode', 'regionCode', \
'applicationType', 'initialListStatus', 'title', 'policyCode']
for f in cate_features:
print(f, '类型数:', train[f].nunique())
# 像等级这种类别特征,是有优先级的可以labelencode或者自映射
train['grade'] = train['grade'].map({'A':1,'B':2,'C':3,'D':4,'E':5,'F':6,'G':7})
# 类型数在2之上,但又不是高维稀疏的,且纯分类特征,直接label encode
train = pd.get_dummies(train, columns=['subGrade', 'homeOwnership', 'verificationStatus', 'purpose', 'regionCode'], drop_first=True)
# 高维类别特征需要进行转换
# 简单来说 LabelEncoder 是对不连续的数字或者文本进行编号
for col in tqdm(['employmentTitle', 'postCode', 'title','subGrade']):
le = LabelEncoder()
le.fit(list(train[col].astype(str).values) + list(test_A[col].astype(str).values))
train[col] = le.transform(list(train[col].astype(str).values))
test_A[col] = le.transform(list(test_A[col].astype(str).values))
print('Label Encoding 完成')
# OneHotEncoder 用于将表示分类的数据扩维
5.异常值处理
异常值检测的通用方法是数据可视化:Box-plot, Histogram, Scatter Plot
其他的常用规则:
- 超过 -1.5 x IQR ~ 1.5 x IQR 的任意值
- 覆盖方法:任何超过 小于5% 或 大于95%百分位的值都认为是异常值
- 距离均值3倍标准差的数据点
- 多变量离群点通常使用影响力、权重或者距离等指标来标识,常用的指数是Mahalanobis’ distance 以及 Cook’s D
# 区分特征数据大于(均值+3*标准差)且(小于均值-3*标准差)的个数(在样本数据大致符合正态分布的情况下,
#标准差具有方便估算的特性:66.7%的数据点落在平均值前后1个标准差的范围内、95%的数据点落在平均值前后2个标
#准差的范围内,而99%的数据点将会落在平均值前后3个标准差的范围内。)
def find_outliers_by_3segama(data,fea):
data_std = np.std(data[fea])
data_mean = np.mean(data[fea])
outliers_cut_off = data_std * 3
lower_rule = data_mean - outliers_cut_off
upper_rule = data_mean + outliers_cut_off
data[fea+'_outliers'] = data[fea].apply(lambda x:str('异常值') if x > upper_rule or x < lower_rule else '正常值')
return data
train_test = train.copy()
for fea in quantitative:
train_test = find_outliers_by_3segama(train_test,fea)
print(train_test[fea+'_outliers'].value_counts())
print(train_test.groupby(fea+'_outliers')['isDefault'].sum())
print('*'*10)
# 箱型图可以看出数据的集中程度,异常值,平均值等情况,可以将其作为异常值的一种检测手段。
def boxplot(x, y, **kwargs):
sns.boxplot(x=x, y=y)
x=plt.xticks(rotation=90)
f = pd.melt(train, value_vars=quantitative)
g = sns.FacetGrid(f, col="variable", col_wrap=2, sharex=False, sharey=False)
g = g.map(boxplot, "variable", "value")
#删除异常值
for fea in numerical_fea:
train_test = train_test[train_test[fea+'_outliers']=='正常值']
train_test = train_test.reset_index(drop=True)
# 删除包含_outliers的列
train_test = train_test[train_test.columns.drop(list(train_test.filter(regex='.+_outliers')))]
6.数据分桶
分桶是离散化的常用方法,是一种将多个连续值分组为较少数量的“桶”的方法;当数值特征跨越不同的数量级的时候,模型可能会只对大的特征值敏感,这种情况可以考虑分桶操作。
分桶的优点:
- 分桶后得到的稀疏向量,内积乘法运算速度更快,计算结果更方便存储;
- 对异常数据有很强的鲁棒性,如 age>30 为 1 否则为 0,对于年龄为 200 的也不会对模型造成很大的干扰
分桶方法分为无监督分桶和有监督分桶:
- 常用的无监督分桶方法有等频分桶、等距分桶和聚类分桶。
- 有监督分桶主要有best-ks分桶和卡方分桶。
需要注意的是:
- 要让桶内的属性取值变化对样本标签的影响基本在一个不大的范围,即不能出现单个桶内,样本标签输出变化很大的情况;
- 每个桶内都有足够的样本,如果样本太少,随机性太大,不具有统计意义上的说服力;
- 每个桶内的样本进行分布均匀;
- 箱内不能全部是好客户;
# 等距分桶,当数字跨越多个数量级时,最好用10个幂(或任何常数的幂)来分组:0-9、10-99、100-999、100-9999等
# 通过除法映射到间隔均匀的分箱中,每个分箱的取值范围都是loanAmnt/1000
data['loanAmnt_bin1'] = np.floor_divide(data['loanAmnt'], 1000)
# 通过对数函数映射到指数宽度分箱,数据之间的间隔较大的例子
data['loanAmnt_bin2'] = np.floor(np.log10(data['loanAmnt']))
#等频分桶,也叫分位数分桶,计算分位数并映射数据到分位数箱
data['loanAmnt_bin3'] = pd.qcut(data['loanAmnt'], 10, labels=False)
7.特征选择
当数据预处理完成后,我们需要选择有意义的特征输入机器学习的算法和模型进行训练。通常来说,从两个方面考虑来选择特征:
- 特征是否发散:如果一个特征不发散,例如方差接近于0,也就是说样本在这个特征上基本上没有差异,这个特征对于样本的区分并没有什么用。
- 特征与目标的相关性:这点比较显见,与目标相关性高的特征,应当优选选择。
Filter
过滤法,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,选择特征。
方差选择法
使用方差选择法,先要计算各个特征的方差,然后根据阈值,选择方差大于阈值的特征。
from sklearn.feature_selection import VarianceThreshold
#其中参数threshold为方差的阈值
VarianceThreshold(threshold=3).fit_transform(train,target_train)
相关系数法
使用相关系数法,先要计算各个特征对目标值的相关系数以及相关系数的P值。
from sklearn.feature_selection import SelectKBest
from scipy.stats import pearsonr
#选择K个最好的特征,返回选择特征后的数据
#第一个参数为计算评估特征是否好的函数,该函数输入特征矩阵和目标向量,
#输出二元组(评分,P值)的数组,数组第i项为第i个特征的评分和P值。在此定义为计算相关系数
#参数k为选择的特征个数
SelectKBest(k=5).fit_transform(train,target_train)
卡方检验
经典的卡方检验是检验定性自变量对定性因变量的相关性。假设自变量有N种取值,因变量有M种取值,考虑自变量等于i且因变量等于j的样本频数的观察值与期望的差距,构建统计量:
不难发现,这个统计量的含义简而言之就是自变量对因变量的相关性。
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
#参数k为选择的特征个数
SelectKBest(chi2, k=5).fit_transform(train,target_train)
特征选择部分为转载https://www.zhihu.com/question/29316149(城东)