特征工程学习心得

特征工程学习心得

零基础摸索中,参考零基础入门数据挖掘 - 二手车交易价格预测

本小白在初期可能更想掌握整个流程,理清楚流程脉络。知识结构图也是今后的知识点延伸扩展方向。

特征工程过程梳理结构图
特征工程
代码知识点整理

1. 数据清洗

利用箱线图去除异常值

博文:《统计基础:【27】剔除箱线图所提升的异常值》讲解简单易通
利用箱线图去除异常值
在上边缘Q1-1.5IQR之外的数据就是极大异常值,在下边缘Q3+1.5IQR之外的数据就是极小异常值。
实现利用箱线图去除异常值的代码块如下: — By: 阿泽

def outliers_proc(data, col_name, scale=3):
    def box_plot_outliers(data_ser, box_scale):
        iqr = box_scale * (data_ser.quantile(0.75) - data_ser.quantile(0.25))
        val_low = data_ser.quantile(0.25) - iqr
        val_up = data_ser.quantile(0.75) + iqr
        rule_low = (data_ser < val_low)
        rule_up = (data_ser > val_up)
        print(val_low)
        print(rule_low)
        return (rule_low, rule_up), (val_low, val_up)
    
    # 原数据复制
    data_n = data.copy()
    # 取任一列数据
    data_series = data_n[col_name]
    # 调用判断异常值的内函数(输入数据序列,箱线图尺寸;输出异常数值,是否异常)
    rule, value = box_plot_outliers(data_series, box_scale=scale)
    # 统计异常值函数返回的异常值数量
    index = np.arange(data_series.shape[0])[rule[0] | rule[1]]
    print("Delete number is: {}".format(len(index)))
    # 将原数据中的异常值删除
    data_n = data_n.drop(index)
    # 统计删除异常值后的数据集数量
    data_n.reset_index(drop=True, inplace=True)
    print("Now column number is: {}".format(data_n.shape[0]))
    # 统计小于下边界的异常值
    index_low = np.arange(data_series.shape[0])[rule[0]]
    outliers = data_series.iloc[index_low]
    print("Description of data less than the lower bound is:")
    print(pd.Series(outliers).describe())
    # 统计大于上边界的异常值
    index_up = np.arange(data_series.shape[0])[rule[1]]
    outliers = data_series.iloc[index_up]
    print("Description of data larger than the upper bound is:")
    print(pd.Series(outliers).describe())
    
    # 绘制箱图对比:原数据箱图与去除异常值后的箱图
    fig, ax = plt.subplots(1, 2, figsize=(10, 7))
    sns.boxplot(y=data[col_name], data=data, palette="Set1", ax=ax[0])
    sns.boxplot(y=data_n[col_name], data=data_n, palette="Set1", ax=ax[1])
    return data_n
- np.percentile计算箱线图上下四分点

在python中计算一个多维数组的任意百分比分位数,此处的百分位是从小到大排列,只需用np.percentile即可。

a=range(20,81)
# 计算a数列处于第80%位置的数值
np.percentile(a,80)
Out[1]:  68.0

a=range(81,20,-1)
# 倒序数列,求取第80%位的数值
np.percentile(80,a,-1)
Out[1]:  69.0

2. 特征构造

- 日期转化格式,计算时间差
# 使用时间:data['creatDate'] - data['regDate'],反应汽车使用时间,一般来说价格与使用时间成反比
# 不过要注意,数据里有时间出错的格式,所以我们需要 errors='coerce'
data['used_time'] = (pd.to_datetime(data['creatDate'], format='%Y%m%d', errors='coerce') - 
                     pd.to_datetime(data['regDate'], format='%Y%m%d', errors='coerce')).dt.days
# 此处调用的是pd.to_datetime(data['creatDate'],format='%Y%m%d',errors='coerce')

errors='coerce’将强制超出NaT的日期,返回NaT
c=(b-a).dt.days计算时间差

- groupby用法
Train_gb = Train_data.groupby("brand")
for kind, kind_data in Train_gb:
	...

groupby就是按括号内==“brand”==分组,这里我们得到了一个叫DataFrameGroupBy的东西, 但 pandas 不让我们直接看它长啥样。
这里kind表示brand列每个类别的值,类似于key;kind_data表示所有brand类的全部数据,类似于value。

- pandas中pd.cut()的用法

pd.cut()的作用是把一组数据分割成离散的区间,类似给成绩设定优良中差,比如:0-59分为差,60-70分为中,71-80分为优秀等等,在pandas中,也提供了这样一个方法来处理这些事儿。又或者是有一组年龄数据,可以使用pandas.cut将年龄数据分割成不同的年龄段并打上标签。

pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False, duplicates='raise') 

参数含义
x:被切分的类数组(array-like)数据,必须是1维的(不能用DataFrame);
bins:bins是被切割后的区间(或者叫“桶”、“箱”、“面元”),有3种形式:一个int型的标量、标量序列(数组)或者pandas.IntervalIndex 。
right:bool型参数,默认为True,表示是否包含区间右部。比如如果bins=[1,2,3],right=True,则区间为(1,2],(2,3];right=False,则区间为(1,2),(2,3)。左开右闭区间
只返回x中的数据在哪个bin,令labels=False即可。因为是左开右闭区间,左端点值不包括,属于的bin为NaN
返回值含义
out:一个pandas.Categorical, Series或者ndarray类型的值,代表分区后x中的每个值在哪个bin(区间)中,如果指定了labels,则返回对应的label。这里显示的是:对于每个值显示属于的区间。
bins:分隔后的区间,当指定retbins为True时返回。

- pandas中pd.get_dummies 的用法
data = pd.get_dummies(data, columns=['model', 'brand', 'bodyType', 'fuelType',
                                     'gearbox', 'notRepairedDamage', 'power_bin'])

特征提取之pd.get_dummies():
pandas提供对one-hot编码的函数是:pd.get_dummies()
one-hot的基本思想:将离散型特征的每一种取值都看成一种状态,若你的这一特征中有N个不相同的取值,那么我们就可以将该特征抽象成N种不同的状态,one-hot编码保证了每一个取值只会使得一种状态处于“激活态”,也就是说这N种状态中只有一个状态位值为1,其他状态位都是0。举个例子,假设我们以学历为例,我们想要研究的类别为小学、中学、大学、硕士、博士五种类别,我们使用one-hot对其编码就会得到:
one hot编码
与之相对应的是:哑变量编码直观的解释就是任意的将一个状态位去除。还是拿上面的例子来说,我们用4个状态位就足够反应上述5个类别的信息,也就是我们仅仅使用前四个状态位 [0,0,0,0] 就可以表达博士了。只是因为对于一个我们研究的样本,他已不是小学生、也不是中学生、也不是大学生、又不是研究生,那么我们就可以默认他是博士,是不是。所以,我们用哑变量编码可以将上述5类表示成:
dummy encoding

3. 特征筛选

过滤式
数值型相关性分析

print(data['power'].corr(data['price'], method='spearman'))
print(data['kilometer'].corr(data['price'], method='spearman'))
print(data['brand_amount'].corr(data['price'], method='spearman'))
print(data['brand_price_average'].corr(data['price'], method='spearman'))
print(data['brand_price_max'].corr(data['price'], method='spearman'))
print(data['brand_price_median'].corr(data['price'], method='spearman'))

图表分析

data_numeric = data[['power', 'kilometer', 'brand_amount', 'brand_price_average', 
                     'brand_price_max', 'brand_price_median']]
correlation = data_numeric.corr()
# 绘图
f , ax = plt.subplots(figsize = (7, 7))
plt.title('Correlation of Numeric Features with Price',y=1,size=16)
sns.heatmap(correlation,square = True,  vmax=0.8)

correlation

学习总结:

特征工程的主要目的还是在于将数据转换为能更好地表示潜在问题的特征,从而提高机器学习的性能。
当大家模型可能都差不多,调参带来的效果增幅是非常有限的,此时特征工程的好坏往往会决定了最终的结果。

有些比赛的特征是匿名特征,这导致我们并不清楚特征相互直接的关联性,这时我们就只有单纯基于特征进行处理,比如装箱,groupby,agg 等这样一些操作进行一些特征统计,此外还可以对特征进行进一步的 log,exp 等变换,或者对多个特征进行四则运算(如上面我们算出的使用时长),多项式组合等然后进行筛选。由于特性的匿名性其实限制了很多对于特征的处理,当然有些时候用 NN 去提取一些特征也会达到意想不到的良好效果。

对于知道特征含义(非匿名)的特征工程,特别是在工业类型比赛中,会基于信号处理,频域提取,丰度,偏度等构建更为有实际意义的特征,这就是结合背景的特征构建,在推荐系统中也是这样的,各种类型点击率统计,各时段统计,加用户属性的统计等等,这样一种特征构建往往要深入分析背后的业务逻辑或者说物理原理,从而才能更好的找到 magic。

当然特征工程其实是和模型结合在一起的,这就是为什么要为 LR NN 做分桶和特征归一化的原因,而对于特征的处理效果和特征重要性等往往要通过模型来验证。

总的来说,特征工程是一个入门简单,但想精通非常难的一件事。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值