上一篇:机器学习知识整理一:数据加载、数据整理、数值型数据处理
提示:参考资料《Python机器学习手册-从数据预处理到深度学习》以及从网上查找的其他资料
主要内容:处理分类数据、处理文本
这里的分类是针对某一个特征来说的,一个特征可能会被分成几类。比如有一列特征是颜色,颜色可以分为很多类:赤、橙、黄、绿、青、蓝、紫。
什么是nominal型分类特征?
本身没有内在顺序的类别称为nominal。比如颜色:蓝色、红色、橙色,这种特征分类没有内在顺序。
处理nominal型分类特征,需要对特征进行one-hot编码(独热编码),one-hot编码是什么?资料中是这样解释的:
为原特征中的每一个分类都创建一个二元特征,这个方法被称为One-hot编码。
举个例子解释下,假设有一个特征为水果,如下:
水果 | 价格 |
---|---|
苹果 | 5 |
梨 | 6 |
橘子 | 7 |
在对其进行one-hot编码之后,会对水果特征进行分类,分成苹果、梨、橘子三个特征,就变为下表中的样子:
苹果 | 梨 | 橘子 | 价格 |
---|---|---|---|
1 | 0 | 0 | 5 |
0 | 1 | 0 | 6 |
0 | 0 | 1 | 7 |
从上面的例子可以看出one-hot编码把一个特征分成了n个特征(二元特征),这些特征的值是0或1。至此对one-hot编码有了一个基本认识。
书中有这样一句话值得思考:值得注意的是,在one-hot编码之后,最好从结果矩阵中删除一个one-hot编码的特征,以避免线性依赖
[P86]。这里为什么要删掉一个one-hot编码特征呢?线性依赖又有着什么含义?这里需要探索一下。
代码参考:nominal处理-demo_5_1
本身存在内在顺序的类别称为ordinal。比如:高、中、低,这种分类天然就有内在的顺序。
这种特征的解决方法是对其进行替换映射。
举个例子来说:假设有一个特征为成绩,如下:
成绩 |
---|
High |
High |
Medium |
Low |
从上面的表格中可以看出,成绩其实是有内在顺序的:高、中、低,我们可以对高中低进行数字映射,高-3, 中-2,低-1。进行特征映射之后,变为下表中的样子:
成绩 |
---|
3 |
3 |
2 |
1 |
这儿要注意的一点是,针对以上的高、中、低,还比较方便映射数字,如果成绩还有一类是位于高和中之间
,这种分类之间的间隔不相等的情况怎么映射数据?设置位于高和中之间-2.5
还是映射成其他值,这个就需要留意了。
代码参考:ordinal处理-demo_5_2
对特征字典编码做的工作就是将一个字典转换成一个特征矩阵,有助于节省内存。
机器学习算法要求数据是矩阵的形式。
这里有两个概念需要了解下:稀疏矩阵和稠密矩阵。
稀疏矩阵:就是数值为0的元素远多于非0元素的矩阵是系数矩阵。
稠密矩阵:相对稀疏矩阵,非0元素个数远多于数值为0元素的个数的矩阵是稠密矩阵。
怎么界定为0元素和非0元素的多与少,暂时还没有了解。
代码参考:对特征字典编码-demo_5_3
如果分类特征中包含缺失值,需要用预测值来填充。
有两种方法来填充缺失值:
方法一:利用机器学习算法预测缺失值,将带缺失值的特征作为目标向量,将其他特征作为特征矩阵,实现完成预测。常用的是KNN分类器。
方法二:就是把这个特征中出现次数最多的分类来填充缺失值。
两种方法都最好再创建一个二元特征来标识观察值中是否包含填充值。
代码参考:填充缺失的分类值-demo_5_4
处理极度不均衡分类的目的是什么呢?书中给出了一个例子:假设有一个样本是关于罕见癌症的,正常样本和癌症样本比例差别很大,就当作10000:1,根据这个样本数据训练出的模型预测没有人会得这个癌症的准确率能达到99.5%,但这不是我们想要的结果。就是说样本分类比例对模型训练会有很大影响。
处理不均衡分类常用的方法:
收集更多的观察值
尤其是占少数的分类的观察值,但是通常情况下这是很难做到的。
选择有分类权重参数的模型
比如随机森林分类器,带有一个权重参数class_weight
假设有一个样本特征分类情况为0占了0.1,1占了0.9,那么在随机森林分类器中可以通过加权weights = {0: 0.9, 1: 0.1},让类别为0的权重加上0.9到达1,让类别为1的权重加上0.1到达1,以此抵消分类数据不均衡带来的影响。
下采样
原理:从占多数的分类中随机抽取观察值,使得抽出来的观察值数量等于占少数的分类的观察值的数量。
上采样
原理:从占少数的分类中随机抽取观察值,重复采样,使得抽出来的观察值数量等于占多数的分类的观察值的数量。
代码参考:处理不均衡分类-demo_5_5
大部分文本数据在被用于特征生成之前都需要进行清洗,比如去除空格、字符串替换、删除特定字符等等。这些清洗操作一般使用python的字符串操作就可以搞定,有时可能需要根据自己的需求对文本进行特定的操作,需要自己写自定义的清洗函数。
代码参考:清洗文本-demo_6_1
做过爬虫的话,应该都知道python有一个处理HTML文档的库BeautifulSoup
,专门用于解析html。功能还是很强大的。这儿给出简单的代码
参考样例:解析并清洗HTML-demo_6_2,后续再对BeautifulSoup的详细使用做下总结。
在创建特征的时候难免要删除标点,删除标点的方法不止一种,书中给出的例子是使用translate
函数将标点转换为None达到移除标点的目的。
代码参考:移除标点-demo_6_3
将文本分离成独立的单词。用到了python的自然语言工具集NLTK, Natural Language Toolkit。
代码参考:文本分词-demo_6_4
如果使用NLTK报错:Resource punkt not found.
,可以参考:Resource punkt not found
停止词指的是非常常见但包含的信息又很少的单词。
代码参考:删除停止词-demo_6_5
词干提取能识别出一个单词的词缀并将其删除,例如ing, ional等,提取词干后,单词的可读性会变差,不过更接近它的基本意思,因此更适合用于做比较。
代码参考:提取词干-demo_6_6
将单词的词性标注出来,比如名词、副词、过去式的动词等。使用NLTK中的Penn Treebank的词性标签进行标注。部分标签例子如下:
标签 | 词性 |
---|---|
NNP | 单数专有名词 |
NN | 单数或复数的名词 |
RB | 副词 |
VBD | 过去式的动词 |
VBG | 动名词或动词的现在分词形式 |
JJ | 形容词 |
PRP | 人称代词 |
代码参考:标注词性-demo_6_7
词袋可以理解为有一个特征表,每个特征都是一个单词,记录了每个单词在观察值中的出现次数。
代码参考:将文本编码成词袋-demo_6_8
理解几个概念:
词频(term frequency, tf):单词在文档中出现的次数。一个词在文档中出现的次数越多,它对这个文档就越重要。
文档频率(document frequency, df):单词出现在多少个文档中。
逆向文档频率(inverse of document frequency, idf):用于计算TF-IDF。
TF-IDF(term frequency-inverse document frequency): 将一个词在某个文档中出现次数和这个词在所有文档中的出现次数进行对比,用于衡量单词对文档的重要性。
将tf和df结合起来,为每个单词确定一个分数,来表示它在某个文档中的重要程度。计算公式如下:
t表示单词,d表示文档。
在scikit-learn中,idf计算公式如下:
n d n_d nd是文档的数量, d f ( d , t ) df(d,t) df(d,t)是单词 t t t的文档频率(也就是单词在多少份文档中出现过)。
默认情况下,scikit-learn会使用欧式范数将TF-IDF向量归一化,得到的结果值越大,这个单词对一个文档来说就越重要。
代码参考:按单词的重要性加权-demo_6_9
python中有许多工具能将字符串转换成datetime类型,代码例子中使用的是pandas的to_datetime执行转换。
pd.to_datetime(datestr, format='%d-%m-%Y %I:%M %p')
其中format指定了字符串的具体格式,常用的日期和时间的格式化代码:
代码 | 描述 | 例子 |
---|---|---|
%Y | 完整的年份 | 2022 |
%m | 月,首位空缺时需用0填充 | 01 |
%d | 日,首位空缺时需用0填充 | 01 |
%I | 小时,首位空缺时需用0填充 | 01 |
%p | AM-上午或PM-下午 | AM |
%M | 分,首位空缺时需用0填充 | 01 |
%S | 秒,首位空缺时需用0填充 | 01 |
代码参考:把字符串转换成日期-demo_7_1
代码参考:处理时区-demo_7_2
代码参考:选择日期和时间-demo_7_3
代码参考:将日期数据切分成多个特征-demo_7_4
计算时间间隔也是常有的情况,所以直接看例子,用到的时候直接借鉴。
代码参考:计算两个日期之间的时间差-demo_7_5
代码参考:对一周内的各天进行编码-demo_7_6
代码参考:创建一个之后的特征-demo_7_7
滚动时间窗口:窗口宽度是固定的,假设窗口宽度是3天,窗口每往前滚动1天,就对窗口内的数据做一次处理。所有窗口移动后处理的数据是很有用的。
下图设置的时间滚动窗口为2:
代码参考:使用滚动时间窗口-demo_7_8
方法一:插值法
插值法的原理,就是利用缺口前后的数据画一条直线或者曲线
,利用这条线预测应该插入什么值比较合理。举个例子:缺口的前一个值是2,缺口的后一个值是5,画一条从2到5的线,缺口处的合理值就是3和4。
方法二:向前填充
向前填充就是把缺口前面的值拿过来填充上。
方法二:向后填充
向后填充就是把缺口后面的值拿来填充上。
代码参考:处理时间序列中的缺失值-demo_7_9
1、了解了如何处理数据分类。刚开始还很疑惑:为什么要把特征分类给转换为数字,比如nominal型分类拆成多个0/1二元特征,ordinal分类要映射成具体的数字,后来看到书中有这么一句话:分类信息常常用一个字符串型的向量或列表示(例如:高、中、低),但大部分机器学习算法都要求其输入是数值型的数据。
才恍然大悟原来是这样。
2、了解了处理文本的方法。
3、了解了机器学习中对时间的处理方法。