学习笔记:特征工程(二)——特征增强:清洗数据

在之前的两节中,我们从特征工程基本理解讲起,逐步介绍了如何使用特征工程优化机器学习流水线,对数据集进行实际操作,以及评估和理解实际应用中出现的不同数据类型。

在分清楚数据的类型之后,我们就要着手于开始清洗和增强数据,即如何在数据集中删除和添加新的列,以及如何发现填充缺失值,所有这些操作的目标都是优化机器学习流水线。

本文主要从下面四个方面来做说明:

  • 识别数据中的缺失值;
  • 删除有害数据;
  • 输入(填充)缺失值;
  • 对数据进行归一化/标准化。

1、识别数据中的缺失值

笔者依旧是沿用了上节使用的数据集:

#我们先导入一些特征工程常用的包:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns

导入数据集:

tag = pd.read_csv('F:\\招行fintech\\test_A榜.csv')

首先进行探索性数据分析(EDA, exploration data analysis)来识别缺失的值。先使用head方法观察数据的前几行。

tag.head()

上述代码输出:

 现在我们来看看数据集中是否有数据点是空的(缺失值)。用pandas DataFrame内置的isnull()的方法:

可以很明显的看到,有四列是存在缺失值的。当然,这是非常理想的情况,我这边使用另一个数据集来说明一下一种特殊情况问题:

导入数据集:

tag = pd.read_csv('F:\\招行fintech\\附件1.csv')

我们使用head来观察数据,输入结果如下:

可以明显看到,此数据集中出现了若干如‘0’,‘?’的数据,这些数据按照惯例应该是问题数据。然而当我们再使用isnull语句时:

我们发现,系统并没有将‘0’以及‘?’识别为缺失值,但在实际情况中,这些数据明显是错误的,依旧需要进行更正!

其实这些都是我们在拿到数据集时可能会遇到的问题,如果数据集没有文档说明,缺失值常见的填充方法有如下几种:

  • 0(数值型)
  • unknown 或 Unknown (类别型)
  • ?(类别型)

当我们知道数据集中出现了这些缺失值之后,我们就可以深入研究如何去解决这些缺失值。


2、处理数据集中的缺失值

我们接下来就要讨论如何处理这些缺失值。最主要的办法就以下两种:

  • 删除缺少值的行;
  • 填充缺失值。

这两种办法都会清洗我们的数据集,让算法可以处理,但是每种办法都各有优缺点。

我们可以先用python中的None填充所有的数字‘0’和‘?’,这样pandas的fillna和fropna方法就可以正常工作,我们沿用第二个数据集做处理,操作如下:

#直接对所有列进行操作
col_0 = ['X1', 'X2', 'X3', 'X4',
         'X5', 'X6', 'X7']
for col in col_0:
    tag[col].replace(to_replace=['0'],value=[None],inplace=True)
    tag[col].replace(to_replace=['?'], value=[None], inplace=True)

现在我们使用isnull方法计算一下缺失值数量,应该可以看到正确的结果:

现在的数据前几行应该如下图所示:

现在数据就有意义多了,我们已经将缺失值正确插入了数据集,确实数据不再是原来的占位符0。

2.1、删除有害的行

在处理数据的两种办法中,我们最常用的方法大概就是直接删除掉存在缺失值的行。可以在pandas中利用dropna方法,接下来我们使用比较常见的数据集,即皮马印第安人糖尿病数据集:

删除存在缺失值的行:

tag_dropped = tag.dropna()

我们来检查一下我们丢失了多少行:

num_rows_lost = round(100*(tag.shape[0]- tag_dropped.shape[0])/float(tag.shape[0]))
print("retained {}% of rows".format(num_rows_lost))

结果显示:

 我们丢失了原始数据大约44%的行!

我们针对此数据集在做进一步的探索性数据分析:

在转换之后,二元响应并没有什么变化,那我们再来看看数据的形状:

 每列的均值(不算缺失值):

每列的均值(删除缺失值):

 

为了更好的看到这些数的变化,我们利用均值变化的百分比做可视化:

ax = ((tag_dropped.mean() - tag.mean()) / tag.mean()).plot(kind='bar', title = '%change in average column values')
ax.set_ylabel('% change')
plt.show()

 结果图如下:

 可以从上看到,times_pregnant(怀孕次数)的均值在删除缺失值后下降了14%,变化很大!如此可知,删除行对于数据的形状改变还是极大的,所以我们应该尽可能保留更多的数据。

2.2、填充缺失值

填充数据是处理缺失数据的一种更复杂的方法。最常用的便是均值填充,我们先来看看缺失总数:

我们选取Glucose来看看这些缺失值: 

我们现在就选用fillna方法,将这一列所有的None填充为该列其余值均值:

tag['Glucose'].fillna(tag['Glucose'].mean(), inplace=True)

 这样一来该列应该不存在缺失值,我们再用isnull方法来查看一下:

果然已经没有了缺失项,我们再来查看一下:

果然!缺失值已经被均值取代了!当然我们也可以用0,以及其他值来填充,我们可以使用KNN交叉验证准确率方法来验证一下用各种值取代缺失项的准确率:

knn_params = {'classify__n_neighbors':[1,2,3,4,5,6,7]}

knn = KNeighborsClassifier()

mean_impute = Pipeline([('impute', SimpleImputer(strategy='mean')),('classify', knn)])

X = tag.drop('Outcome', axis = 1)
Y = tag['Outcome']

grid = GridSearchCV(mean_impute, knn_params)
grid.fit(X,Y)

print(grid.best_score_, grid.best_params_)

最后结果统计:


3、标准化和归一化

 到目前为止,我们已经知道了如何识别数据类型,如何识别缺失值,以及如何处理缺失值。那么接下来我们将继续讨论,如何进一步优化我们的数据集,以进一步增强机器学习流水线结果,我们接下来看一看数据的分布情况:

我们可以注意到,每列的均值、最小值、最大值和标准差差值都很大,这就关系到机器学习模型中数据尺度的影响问题了,只有当所有特征的数值变化区间差别不大,才能达到机器学习算法模型的最优状态。

所以我们必须对数据做归一化,下列有三种方法:

  • z分数标准化
  • min-max标准化
  • 行归一化

3.1、z分数标准化

z分数标准化公式:

 在这个公式里:

  • z是新的值
  • x是单元格原来的值
  • μ是该列的均值
  • \sigma是列的标准差

我们继续以Glucose列为例,我们先来看看未z分数标准化前的均值和标准差:

tag['Glucose'].mean()
tag['Glucose'].std()

结果为:

可视化:

 

现在我们应用z分数标准化,代码如下:

scaler = StandardScaler()
glucose_z_score_standardized = scaler.fit_transform(tag[['Glucose']])
print(glucose_z_score_standardized.mean())
print(glucose_z_score_standardized.std())

 结果如下:

需要注意的是,在这一步我们需要先把缺失值填上。可视化:

ax = pd.Series(glucose_z_score_standardized.reshape(-1,)).hist()
ax.set_title('Distribution of plasma_glucose_concentration after Z Score Scaling')

结果如下:

我们观察到x轴更紧密了,y轴则没有变化,如此,我们就完成了z分数标准化。

3.2、min-max标准化 

接下来的两种标准化方式我就不做太多赘述了,直接上代码:

min_max = MinMaxScaler()
tag_min_max = pd.DataFrame(min_max.fit_transform(tag_imputed),
                           columns='Glucose')

3.3、行归一化

normalize = Normalizer()
tag_normalized = pd.DataFrame(normalize.fit_transform(tag_imputed),
                              columns='Glucose')

最后我们做个总结:

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
KMP算法是一种字符串匹配算法,用于在一个文本串S内查找一个模式串P的出现位置。它的时间复杂度为O(n+m),其中n为文本串的长度,m为模式串的长度。 KMP算法的核心思想是利用已知信息来避免不必要的字符比较。具体来说,它维护一个next数组,其中next[i]表示当第i个字符匹配失败时,下一次匹配应该从模式串的第next[i]个字符开始。 我们可以通过一个简单的例子来理解KMP算法的思想。假设文本串为S="ababababca",模式串为P="abababca",我们想要在S中查找P的出现位置。 首先,我们可以将P的每个前缀和后缀进行比较,得到next数组: | i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | --- | - | - | - | - | - | - | - | - | | P | a | b | a | b | a | b | c | a | | next| 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 | 接下来,我们从S的第一个字符开始匹配P。当S的第七个字符和P的第七个字符匹配失败时,我们可以利用next[6]=4,将P向右移动4个字符,使得P的第五个字符与S的第七个字符对齐。此时,我们可以发现P的前五个字符和S的前五个字符已经匹配成功了。因此,我们可以继续从S的第六个字符开始匹配P。 当S的第十个字符和P的第八个字符匹配失败时,我们可以利用next[7]=1,将P向右移动一个字符,使得P的第一个字符和S的第十个字符对齐。此时,我们可以发现P的前一个字符和S的第十个字符已经匹配成功了。因此,我们可以继续从S的第十一个字符开始匹配P。 最终,我们可以发现P出现在S的第二个位置。 下面是KMP算法的C++代码实现:

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值