机器学习(二):特征工程

目前,sklearn在应用中,主要有四类算法:聚类,分类,回归,降维

聚类:即非监督学习的方式,例如我有一堆人,这堆数据是没有男孩或者女孩这些标签的,此时我需要给这堆数据进行聚类,根据一些身体特征,分成两类,并标记为男孩,女孩。

分类/回归:监督学习的方式,还是那堆人,但是已经分好类了,男孩,女孩,此时来了一个新人,我根据这个新人的特征,给他归类。

降维:如果按照字面意思来理解,那就有问题,当数据集有很多属性的时候,我们此时需要把100个属性变成10个,并不是挑出10个,而是压缩成10个,这10个属性,就集合了100个属性特征,简单理解,就是重要的特征就拿起来,不重要的就吸收了。

1. 可用数据集

工作中,公司自己会有需要处理的数据集让我们处理,但是在我们的学习中,我们也需要数据集,那么从哪里获得这些数据集呢?
在这里插入图片描述
Kaggle网址
UCI数据集网址
scikit-learn网址

2. 特征工程介绍

2.1. 为什么要使用特征工程?

数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。

2.2. 什么是特征工程?

特征工程是使用专业背景知识和技巧处理数据,使得特征能在机器学习算法上发挥更好的作用的过程。
意义:会直接影响机器学习的效果

2.3. 特征工程的位置与数据处理的比较

pandas:一个数据读取非常方便以及基本的处理格式的工具
sklearn:对于特征的处理提供了强大的接口

特征工程包含内容

  • 特征抽取
  • 特征预处理
  • 特征降维

3.特征抽取

3.1. 什么是特征抽取?

在这里插入图片描述
当我们要分析上述文章的种类的时候,需要用到机器学习算法,那么什么是机器学习算法呢?

机器学习算法->统计学方法->数学公式

由上述关系可以发现,机器学习算法实际上就是数学公式,数学公式是没有办法处理字符串类型的文章的,它只能处理数据类型

特征提取:

  1. 将任意数据(如文本或图像)转换为可用于机器学习的数字特征

注:特征值化是为了计算机更好的去理解数据

  • 字典特征提取(特征离散化)
  • 文本特征提取
  • 图像特征提取(深度学习将介绍)
  1. 特征提取API

sklearn.feature_extraction

3.2. 字典特征提取

作用:对字典数据进行特征值化

sklearn.feature_extraction.DictVectorizer(sparse=True,…)

返回一个transform(转换器)对象,可以用改正对象来将dict转换为向量,
sparse默认True,意思是转换成一个稀疏向量,我们需要把这个参数变成
False
稀疏矩阵:将矩阵中的非0值表示出来,这样可以节约内存

DictVectorizer.fit_transform(X)

X:字典或者包含字典的迭代器返回值:返回sparse矩阵
DictVectorizer:上一步实例化之后的(transform)转换器对象

DictVectorizer.inverse_transform(X) X:

array数组或者sparse矩阵 返回值:转换之前数据格式

DictVectorizer.get_feature_names()

返回类别名称

代码演示

from sklearn import feature_extraction

data = [{'city': '北京','temperature':100},
{'city': '上海','temperature':60},
{'city': '深圳','temperature':30}]

# 1. 获取转换器对象
DictVectorizer = feature_extraction.DictVectorizer(sparse=False)

# 2. 调用fit_transform()
new_data = DictVectorizer.fit_transform(data)

# 输出
print(DictVectorizer.get_feature_names())
print(new_data)

在这里插入图片描述
我们看到了这样的一个结果,二维数组中第一个值为1的时候,那个值就表示上海,第二个值为1的时候表示北京,可以看到,从原本的两个特征变成了四个特征。

  • 适用数据集:
  1. 数据集当中,类别特征比较多,可以转换为字典类型进行提取
  2. 数据集本身就是字典类型

在这里插入图片描述
转化为:
在这里插入图片描述
将特征全部转化为二维数组,有那个值就填1,没有就填0

3.3. 文本特征提取

作用:对文本数据进行特征值化

sklearn.feature_extraction.text.CountVectorizer(stop_words=[])

返回词频矩阵
stop_words:停用词,有一些单词对分类也没有好处,在这里添加上,系统不会将它当成特征值

CountVectorizer.fit_transform(X)

X:文本或者包含文本字符串的可迭代对象 返回值:返回sparse矩阵

CountVectorizer.inverse_transform(X)

X:array数组或者sparse矩阵 返回值:转换之前数据格

CountVectorizer.get_feature_names()

返回值:单词列表

sklearn.feature_extraction.text.TfidfVectorizer

代码演示

from sklearn import feature_extraction

data = ["life is short,i like like python",
"life is too long,i dislike python"]

# 1. 获取转换器对象
CountVectorizer = feature_extraction.text.CountVectorizer()

# 2.调用fit_transform()方法
new_data = CountVectorizer.fit_transform(data)

# 输出
print(CountVectorizer.get_feature_names())
print(new_data.toarray())

在这里插入图片描述
可以看到,new_data中统计出了所有出现过的单词,并且记录了每一个单词在句子中的出现次数,第一个数组记录的第一句,第二个数组记录的第二句。
但是当我们把数据变成中文,会发生什么呢?

from sklearn import feature_extraction

text = ['人生苦短,我学python',
       'python是一门很好的编程语言']

# 1.获取转换器对象
CountVectorizer = feature_extraction.text.CountVectorizer()
new_text = CountVectorizer.fit_transform(text)
print(CountVectorizer.get_feature_names())
print(new_text.toarray())

在这里插入图片描述
为什么会得到这样的结果呢,仔细分析之后会发现英文默认是以空格分开的。其实就达到了一个分词的效果,所以我们要对中文进行分词处理。(注意:不支持单个中文)

  • 我们将原数据写几个空格,分词之后,再次尝试
from sklearn import feature_extraction

text = ['人生 苦短,我学 python',
       'python 是一门 很好的 编程语言']

# 1.获取转换器对象
CountVectorizer = feature_extraction.text.CountVectorizer()
new_text = CountVectorizer.fit_transform(text)
print(CountVectorizer.get_feature_names())
print(new_text.toarray())

在这里插入图片描述
这里就已经达到了我们想要的结果了。

  • 看到这里可能会产生疑问,要是我们对大量的中文进行特征提取,那是不是要挨个打空格呢?这个是不需要的,在这里推荐一个库,叫jieba,其中有一个方法

jieba.cut(text) # 返回一个词语组成的列表

知道这些后,我们给个案例

3.4.案例分析(jieba分词处理)

对以下三句话进行特征值化

今天很残酷,明天更残酷,后天很美好, 但绝对大部分是死在明天晚上,所以每个人不要放弃今天。

我们看到的从很远星系来的光是在几百万年之前发出的, 这样当我们看到宇宙时,我们是在看它的过去。

如果只用一种方式了解某样事物,你就不会真正了解它。 了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。

from sklearn import feature_extraction
import jieba

text = ['今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。',
        '我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。',
        '如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。']

def cut_text(text):
    
    # 获取生成器
    words_generator = jieba.cut(text)
    
    # 将生成器转化为字词列表,在以空格为分割符组装成字符串
    new_text = ' '.join(list(words_generator))
    return new_text


# 定义一个新的数组,用来存储分词后的字符串数组
new_text = []

# 将三个字符串全部分词
for i in text:
    new_text.append(cut_text(i))
    
# 1. 获取转换器
CountVectorizer = feature_extraction.text.CountVectorizer(stop_words=[])

# 2. 调用fit_transform()方法
taget = CountVectorizer.fit_transform(new_text)

print(CountVectorizer.get_feature_names())
print(taget.toarray())

在这里插入图片描述
不过接下来又引出一个问题
我们既然要对这些文章分类,文章中的一部分特有的词语,例如“经济”,“医疗”,这些在该种类文章中常有,但是别的文章中不常有的词语,这些词语对我们的分类影响比较大。但是同时还有另一部分词语,如“因为”,“但是”,之类的词语,在别的文章也会经常出现,这对我们的分类没有什么太大的影响,所以我们又引出了新的特征提取的方法

3.5.Tf-idf文本特征提取

  • TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
  • TF-IDF作用:用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。

公式

  • 词频(term frequency,tf)指的是某一个给定的词语在该文件中出现的频率
  • 逆向文档频率(inverse document frequency,idf)是一个词语普遍重要性的度量。某一特定词语的idf,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取以10为底的对数得到
    在这里插入图片描述
    最终得出结果可以理解为重要程度。
    注:假如一篇文件的总词语数是100个,而词语"非常"出现了5次,那么"非常"一词在该文件中的词频就是5/100=0.05。而计算文件频率(IDF)的方法是以文件集的文件总数,除以出现"非常"一词的文件数。所以,如果"非常"一词在1,000份文件出现过,而文件总数是10,000,000份的话,其逆向文件频率就是lg(10,000,000 / 1,0000)=3。最后"非常"对于这篇文档的tf-idf的分数为0.05 * 3=0.15

案例

from sklearn import feature_extraction
import jieba

text = ['今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。',
        '我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。',
        '如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。']

def cut_text(text):
    return ' '.join(list(jieba.cut(text)))


new_text = []

# 1. 分词
for i in text:
    new_text.append(cut_text(i))

# 2. 获取转换器对象
TfidfVectorizer = feature_extraction.text.TfidfVectorizer()

# 3. 调用fit_transform()方法
final_text = TfidfVectorizer.fit_transform(new_text)

print(TfidfVectorizer.get_feature_names())
print(final_text.toarray())

在这里插入图片描述
每个词语对应的数字就是它对于文章分类的重要程度

4. 特征预处理

什么是特征预处理?
在这里插入图片描述

4.1. 什么是特征预处理

通过一些转换函数将特征数据转换成更加适合算法模型的特征数据过程

  • 下面给一组数据集作为例子
    约会对象数据
    在这里插入图片描述
    一共有三个特征,女士会根据这三个特征对男子做出评价。这三个特征同样重要,但是在计算的时候,由于里程数的值远远大于其余两个特征值,所以其余两个特征值的价值就会显得微乎其微,因此我们要对数据进行预处理。

我们需要用到一些方法进行无量纲化,使不同规格的数据转换到同一规格

4.2. 归一化

4.2.1. 公式

在这里插入图片描述

4.2.2. 归一化所用到的API
  • sklearn.preprocessing.MinMaxScaler (feature_range=(0,1)… )
  • MinMaxScalar.fit_transform(X)
  • X:numpy array格式的数据[n_samples,n_features]
  • 返回值:转换后的形状相同的array

我们来演示一下

import pandas as pd
from sklearn import preprocessing

# 1. 获取数据
data = pd.read_csv('D:/迅雷下载/archive/summer-products-with-rating-and-performance_2020-08.csv')
data = data.loc[:,'price':'retail_price']

# 2. 获取转换器对象
MinMaxScaler = preprocessing.MinMaxScaler(feature_range=(0,1))

# 3. 调用fit_transform()
print('转换前:\n',data)
data = MinMaxScaler.fit_transform(data)
print('转换后:\n',data)

在这里插入图片描述

  • 可以发现,转换后的数值是很接近的,都在0到1之间,这样更有利于后面的数据分析

不过与此同时,也出现了一个问题,归一化是根据数据的最大值和最小值计算的,那么要是我们这个数据集的异常值比较多(异常值一般是最大值或者是最小值),那么就会严重影响我们归一化的结果

4.2.3 归一化总结

注意最大值最小值是变化的,另外,最大值与最小值非常容易受异常点影响,所以这种方法鲁棒性(健壮性,稳定性)较差,只适合传统精确小数据场景。

4.3. 标准化

标准化是比归一化更好的能达到无量纲化的效果

4.3.1 公式

在这里插入图片描述

  • 对于归一化来说:如果出现异常点,影响了最大值和最小值,那么结果显然会发生改变
  • 对于标准化来说:如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大,从而方差改变较小。
4.3.2 标准化总结

在已有样本足够多的情况下比较稳定,适合现代嘈杂大数据场景。

5. 特征降维

5.1. 什么是特征降维?

降维是指在某些限定条件下,降低随机变量(特征)个数,得到一组“不相关”主变量的过程

  • 乍一看上面的官方解释,还是不是很清楚,接下来举个例子,大家就明白了,比如现在有一个数据集。
    在这里插入图片描述
    这是鸟的数据集,有右边这些特征,但是若我们再加上几个特征,例如:是否有脚?是否有翅膀?这些特征是冗余的,因为任何鸟都有翅膀,都有脚,是没有意义的,特征降维就是要将这些冗余的特征过滤掉,留下主要特征。

5.2. 特征降维的方法

  1. Filter(过滤式):主要探究特征本身特点、特征与特征和目标值之间关联

     1. 方差选择法:低方差特征过滤
    

若这些特征的所有数据方差为0,说明这些特征在所有样本中都是相等的,没
有必要研究这个特征,这种特征就会被过滤掉

	  2. 相关系数

比较相关性,当两个特征的相关性很强,这特征完全可以值保留一个,因为
其中一个特征就能影响到另一个特征,同时处理这两个特征显得有点多余

  1. Embedded (嵌入式):算法自动选择特征(特征与目标值之间的关联)
    - 决策树:信息熵、信息增益
    - 正则化:L1、L2
    - 深度学习:卷积等

在这篇文章我们只讲过滤式的两个方法

5.3.1. 过滤式

所需模块:

sklearn.feature_selection

所需API:

sklearn.feature_selection.VarianceThreshold(threshold = 0.0) 删除所有低方差特征,threshold = 0时,表示当某个特征在所有样本中的方差为0的时候过滤掉这个特征
Variance.fit_transform(X) X:numpy array格式的数据[n_samples,n_features]
返回值:训练集差异低于threshold的特征将被删除。默认值是保留所有非零方差特征,即删除所有样本中具有相同值的特征。

from sklearn import feature_selection

# 1. 获取数据
data = pd.read_csv('E:/factor_returns.csv')

# 2. 获取转换器
VarianceThreshold = feature_selection.VarianceThreshold(threshold=1)
print('降维前特征的数量:\n',len(data.iloc[0,1:10]))

# 3. 调用fit_transform()
data = VarianceThreshold.fit_transform(data.iloc[:,1:10])
print('降维后特征的数量:\n',len(data[0,:]))

在这里插入图片描述

5.3.2. 相关系数
  • 皮尔逊相关系数(Pearson Correlation Coefficient)
    • 反映变量之间相关关系密切程度的统计指标
  1. 公式
    在这里插入图片描述

  2. 相关系数的值介于–1与+1之间,即–1≤ r ≤+1。其性质如下:

当r>0时,表示两变量正相关,r<0时,两变量为负相关 当|r|=1时,表示两变量为完全相关,当r=0时,表示两变量间无相关关系
当0<|r|<1时,表示两变量存在一定程度的相关。且|r|越接近1,两变量间线性关系越密切;|r|越接近于0,表示两变量的线性相关越弱
一般可按三级划分:|r|<0.4为低度相关;0.4≤|r|<0.7为显著性相关;0.7≤|r|<1为高度线性相关

  1. API
    from scipy.stats import pearsonr
    pearsonr(x,y)
    x:第一个特征
    y:第二个特征

演示一下

from scipy import stats

data = pd.read_csv('E:/factor_returns.csv')

r = stats.pearsonr(data['pe_ratio'],data['pb_ratio'])

print(r[0])

在这里插入图片描述
得出pe_ratio特征和pb_ratio特征的相关性

6. 主成分分析

主成分分析也是一种降维的方法

6.1. 什么是主成分分析

  • 定义:高维数据转化为低维数据的过程,在此过程中可能会舍弃原有数据、创造新的变量
  • 作用:是数据维数压缩,尽可能降低原数据的维数(复杂度),损失少量信息。
  • 应用:回归分析或者聚类分析当中

对于信息一词,在决策树中会进行介绍

那么更好的理解这个过程呢?我们来看一张图
在这里插入图片描述
我们在拍照的时候,也可以看作是吧三维的东西转换为二维,那么上面四张图片中,我们要做到的是,拍出的照片还能看出是个什么东西。
在这里插入图片描述

6.2. 所要用到的API

  • sklearn.decomposition.PCA(n_components=None)
    将数据分解为较低维数空间
  • n_components:
    小数:表示保留百分之多少的信息
    整数:减少到多少特征
  • PCA.fit_transform(X) X:numpy array格式的数据[n_samples,n_features]
  • 返回值:转换后指定维度的array

演示一下

from sklearn import decomposition

data = [[2,8,4,5], [6,3,0,8], [5,4,9,1]]

# 降维到只有两个特征
dec1 = decomposition.PCA(n_components=2)

# 保留95%的信息
dec2 = decomposition.PCA(n_components=0.95)

data1 = dec.fit_transform(data)
data2 = dec.fit_transform(data)

print('保留两个特征的结果:\n',data1)
print('保留95%信息的结果:\n',data2)

在这里插入图片描述

7. 案例:探究用户对物品类别的喜好细分降维

在这里插入图片描述
数据如下:

  • order_products__prior.csv:订单与商品信息
    字段:order_id, product_id, add_to_cart_order, reordered
  • products.csv:商品信息
    字段:product_id, product_name, aisle_id, department_id
  • orders.csv:用户的订单信息
    字段:order_id,user_id,eval_set,order_number,….
  • aisles.csv:商品所属具体物品类别
    字段: aisle_id, aisle

通过分析题意,我们要研究的是user_id和aisle的关系,所以我们必须要让这两个数据在同一个表内,之后再进行交叉表,就能找出关系

7.1. 提取数据

import pandas as pd

# 1. 读取数据
products = pd.read_csv('D:/dropbox/instacart-market-basket-analysis/products.csv')
order_products = pd.read_csv('D:/dropbox/instacart-market-basket-analysis/order_products__prior.csv')
orders = pd.read_csv('D:/dropbox/instacart-market-basket-analysis/orders.csv')
aisles = pd.read_csv('D:/dropbox/instacart-market-basket-analysis/aisles.csv')

提取出这些数据之后,我们通过观察字段就能发现,只需要经过几次合并,我们就能够将user_id和aisle合并到一个表中

7.2. 合并表

# 目的:让aisle_id和user_id在同一个表中

# 2. aisles和products合并

table1 = pd.merge(aisles,products,on=['aisle_id','aisle_id'])
table1

在这里插入图片描述

# 3. table1和order_products合并

table2 = pd.merge(table1,order_products,on=['product_id','product_id'])
table2

在这里插入图片描述

# 4. table2和orders合并

table3 = pd.merge(table2,orders,on=['order_id','order_id'])
table3

经过上面这三次合并,在table3中已经同时存在user_id和aisle了

7.3. 交叉表找出两个字段的关系

# 5. 交叉表找出user_id和aisle的关系

table4 = pd.crosstab(table3['user_id'],table3['aisle'])
table4

在这里插入图片描述
这样就能直观的显示每个用户买了哪些种类的产品,买了多少个。
依然存在一些问题,有一些产品数据全是0,这就出现了特征冗余,接下来我们通过PCA算法来降维。

7.4. PCA降维

from sklearn import decomposition

# 6. 利用PCA降维,保留95%的信息
PCA = decomposition.PCA(n_components=0.95)
result = PCA.fit_transform(table4)

print(result)

在这里插入图片描述

8. 总结

在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

若能绽放光丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值