前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MLK | 特征工程系统化干货笔记+代码了解一下(上)

MLK | 特征工程系统化干货笔记+代码了解一下(上)

作者头像
Sam Gor
发布2019-08-28 15:06:23
6480
发布2019-08-28 15:06:23
举报
文章被收录于专栏:SAMshareSAMshare

? 目录

  • ? 特征理解
  • ? 特征增强
  • ? 特征构建(待更新)
  • ✅ 特征选择(待更新)
  • ? 特征转换(待更新)
  • ? 特征学习(待更新)

大家可以先看下思维导图:

? 01 特征理解

在拿到数据的时候,我们第一步需要做的是理解它,一般我们可以从下面几个角度入手:

(注:本节用到了两个数据集,分别是Salary_Ranges_by_Job_Classification 和 GlobalLandTemperaturesByCity)

1. 区分结构化数据与非结构化数据

如一些以表格形式进行存储的数据,都是结构化数据;而非结构化数据就是一堆数据,类似于文本、报文、日志之类的。

2. 区分定量和定性数据

定量数据:指的是一些数值,用于衡量某件东西的数量; 定性数据:指的是一些类别,用于描述某件东西的性质。

其实区分了定量和定性数据,还可以继续细分下去,分为定类(nominal)、定序(ordinal)、定距(interval)、定比数据(ratio),下面我们分别对这4类数据进行举例说明,加深大家对它们的印象。

1)定类(nominal)

也就是分类,比如:血型(A/B/O/AB型)、性别(男/女)、货币(人民币/美元/日元),而且值得注意的是这些分类之间没有大小可比性。一般画图的话就只能看下分布占比,可以用条形图、饼图来表示。

2)定序(ordinal)

定序相比于定类,也就是多了一个“可排序”的属性,也就是说虽然它们是类别变量,但是它们的变量值之间是存在“大小”之分的。比如:期末绩点(A、B、C、D、E、F)、问卷答案(非常满意、满意、一般、不满意)。可视化方面,和定类一样,不过就是多了一个 箱体图 可以用(因为定序变量可以有中位数)。

3)定距(interval)

定距的话,就是变量值之间可以做加减法计算,也就是可以引入均值、方差之类的名词了,而且能够画的图也多了,包括先前的那些,还包括了直方图。

4)定比(ratio)

定比相比于定距更加严格,不仅仅有定距的所有属性,同时,有一个 绝对零点 的概念,可以做加减乘除运算,比如说某个商品的价格是另一个的2倍。值得注意的是,温度一般不归入定比,而是定距,没有说20度是10度的两倍这种说法。

最后把上面的内容总结一下:

3. 关键代码汇集

以下的代码只是核心片段,完整代码可在公众号(SAMshare)后台输入关键字 特征工程 获取。

1)常见简易画图

代码语言:javascript
复制
# 绘制条形图
salary_ranges['Grade'].value_counts().sort_values(ascending=False).head(10).plot(kind='bar')

# 绘制饼图
salary_ranges['Grade'].value_counts().sort_values(ascending=False).head(5).plot(kind='pie')

# 绘制箱体图
salary_ranges['Union Code'].value_counts().sort_values(ascending=False).head(5).plot(kind='box')

# 绘制直方图
climate['AverageTemperature'].hist()

# 为每个世纪(Century)绘制平均温度的直方图
climate_sub_china['AverageTemperature'].hist(by=climate_sub_china['Century'],
                                            sharex=True,
                                            sharey=True,
                                            figsize=(10, 10),
                                            bins=20)

# 绘制散点图
x = climate_sub_china['year']
y = climate_sub_china['AverageTemperature']

fig, ax = plt.subplots(figsize=(10,5))
ax.scatter(x, y)
plt.show()

2)检查缺失情况

代码语言:javascript
复制
# 移除缺失值
climate.dropna(axis=0, inplace=True)

# 检查缺失个数
climate.isnull().sum()

3)变量类别转换

代码语言:javascript
复制
# 日期转换, 将dt 转换为日期,取年份, 注意map的用法
climate['dt'] = pd.to_datetime(climate['dt'])
climate['year'] = climate['dt'].map(lambda value: value.year)

# 只看中国
climate_sub_china = climate.loc[climate['Country'] == 'China']
climate_sub_china['Century'] = climate_sub_china['year'].map(lambda x:int(x/100 +1))
climate_sub_china.head()

? 02 特征增强

这一步其实就是数据清洗了,虽然上一步中也有涉及到部分清洗工作(比如清除空值、日期转换之类的),但却是分散的,这节重点讲讲数据清洗的一些技巧和实践代码,供大家在实际项目中去使用。

Step1: 进行EDA(Exploratory Data Analysis),思路如下:

(1)首先看看目标占比情况(针对二分类问题,也就是0和1的占比情况),直接 value_counts()就可以解决,看看样本是否失衡。

(2)接着看看有没有空值,直接统计 isnull().sum() 的个数,不过需要注意的是,可能统计出来没有缺失,并不是因为真的没有缺失,而且缺失被人用某个特殊值填充了,一般会用 -9、blank、unknown、0之类的,需要注意⚠️识别,后面需要对缺失进行合理填充。

(2.1)怎么识别缺失值呢?一般可以通过 data.describe() 获取基本的描述性统计,根据均值、标准差、极大极小值等指标,结合变量含义来判断。

(3)再接着看不同类别之间的特征值分布情况,可通过画直方图(数值型变量)和计算变量值占比分布(类别变量)来观察。

(4)观察不同变量之间的相关性情况,可以通过绘制 相关矩阵的热力图 来观察大体情况。

Step2: 处理数据缺失问题

缺失处理的办法有好多种,但最为常用的作者讲到有两种:填充和删除。

而在处理缺失前,我们在上面的小节中识别出来了部分被人工填充的缺失,

需要还原一下:

代码语言:javascript
复制
# 处理被错误填充的缺失值0,还原为 空(单独处理)
pima['serum_insulin'] = pima['serum_insulin'].map(lambda x:x if x !=0 else None)
# 检查变量缺失情况
pima['serum_insulin'].isnull().sum()


# 批量操作 还原缺失值
columns = ['serum_insulin','bmi','plasma_glucose_concentration','diastolic_blood_pressure','triceps_thickness']

for col in columns:
    pima[col].replace([0], [None], inplace=True)

# 检查变量缺失情况
pima.isnull().sum()

1) 删除含有缺失值的行

这里的话比较简单,就是使用 dropna() 来处理即可,同时我们还可以检查下我们到底删除了多少数据量:round(data.shape[0]-data_dropped.shape[0])/float(data.shape[0]) 就可以统计出来了。当然,删除之后,我们还需要看看数据的分布,对比目标占比、特征分布与先前的是否存在明显差异,如果是的话,建议不要使用这种办法。

2) 缺失值合理填充

缺失填充,这里介绍的有均值填充、-9填充、中位数填充。这里会比较简单,我们可以通常都是通过 sklearn的 Pipeline以及 Imputer来实现,下面是一个简单的完整

Demo:

代码语言:javascript
复制
# 使用sklearn的 Pipeline以及 Imputer来实现缺失值填充
from sklearn.pipeline import Pipeline
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import Imputer

# 调参候选
knn_params = {'classify__n_neighbors':[1,2,3,4,5,6]}

# 实例化KNN模型
knn = KNeighborsClassifier()

# 管道设计
mean_impute = Pipeline([('imputer', Imputer(strategy='mean')),
                        ('classify',knn)
                       ])

x = pima.drop('onset_disbetes', axis=1) # 丢弃y
y = pima['onset_disbetes']

# 网格搜索
grid = GridSearchCV(mean_impute, knn_params)
grid.fit(x, y)

# 打印模型效果
print(grid.best_score_, grid.best_params_)
# 0.73177
Step3: 标准化和归一化

经过上面的处理,模型的精度可以达到0.73177,但我们可以继续优化吗?那是肯定的。

我们可以先看看所有特征的分布(特征少的时候可以这么看):

代码语言:javascript
复制
pima_imputed_mean.hist(figsize=(15,15))

从上图中我们可以看出一个问题,那就是每个特征之间的量纲都是不一样的,这对于knn这种基于距离的模型来说是“致命”的bug,因此我们需要进行标准化和归一化处理。

我们重点关注3种方法:

1)Z分数标准化

最为常用的标准化技术,利用了统计学中的z分数思想,也就是将数据转换为均值为0,标准差为1的分布,其在python中的调用方法:

代码语言:javascript
复制
# z分数标准化(单一特征)
from sklearn.preprocessing import StandardScaler
# 实例化方法
scaler = StandardScaler()
glucose_z_score_standarScaler = scaler.fit_transform(pima[['plasma_glucose_concentration']].fillna(-9))
# 可以看看转换之后的均值和标准差是否为0和1
glucose_z_score_standarScaler.mean(), glucose_z_score_standarScaler.std()


# z分数标准化(全部特征)
from sklearn.preprocessing import StandardScaler
# 实例化方法
scaler = StandardScaler()
pima_imputed_mean_scaled = pd.DataFrame(scaler.fit_transform(pima_imputed_mean), columns=pima_columns)
# 看下标准化之后的分布
pima_imputed_mean_scaled.hist(figsize=(15,15), sharex=True)


# 在Pipeline中使用
model = Pipeline([
    ('imputer', Imputer()),
    ('standardize', StandarScaler())
])

2)min-max标准化

min-max标准化和z-score类似,其公式为:(X - Xmin)/(Xmax - Xmin)

在python中的调用方法:

代码语言:javascript
复制
# min-max标准化
from sklearn.preprocessing import MinMaxScaler
# 实例化方法
min_max = MinMaxScaler()
# 使用min-max标准化
pima_min_maxed = pd.DataFrame(min_max.fit_transform(pima.fillna(-9)), columns=pima_columns)

3)行归一化

行归一化针对的是每一行数据,不同于上面的两种方法(针对列),对行进行处理是为了保证每行的向量长度一样(也就是单位范围,unit norm),有L1、L2范数。

在python中的调用方法:

代码语言:javascript
复制
# 行归一化
from sklearn.preprocessing import Normalizer
# 实例化方法
normalize = Normalizer()
# 使用行归一化
pima_normalized = pd.DataFrame(normalize.fit_transform(pima.fillna(-9)), columns=pima_columns)
# 查看矩阵的平均范数(1)
np.sqrt((pima_normalized**2).sum(axis=1)).mean()

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 SAMshare 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ? 目录
  • ? 01 特征理解
    • 1. 区分结构化数据与非结构化数据
      • 2. 区分定量和定性数据
        • 3. 关键代码汇集
        • ? 02 特征增强
          • Step1: 进行EDA(Exploratory Data Analysis),思路如下:
            • Step2: 处理数据缺失问题
              • Step3: 标准化和归一化
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档