python机器学习-特征工程(三)

https://www.cnblogs.com/jasonfreak/p/5448385.html

三、特征提取

  • 字典加载特征:DictVectorizer
  • 文本特征提取:词频向量(CountVectorizer)TF-IDF向量(TfidfVectorizer,FfidfTransformer) 特征哈希向量(HashingVectorizer)
  • 图像特征的提取:提取像素矩阵边缘和兴趣点

3.1、字典加载特征

用python中的字典存储特征是一种常用的做法,其优点是容易理解,但是sklearn的输入特征必须是numpy或Scipy的数组。可以用DictVectorizer从字典加载特征转化成numpy,并且对分类特征会采用独热编码。

me=[
    {'city':'Dubai','temperature':33.},
    {'city':'London','temperature':12.},
    {'city':'San Francisco','temperature':18.}
]
from sklearn.feature_extraction import DictVectorizer
vec=DictVectorizer()
print(vec.fit_transform(me).toarray())
vec.get_feature_names()

[[ 1.  0.  0. 33.]
[ 0.  1.  0. 12.]
[ 0.  0.  1. 18.]]

3.2、字频向量

词库模型(Bag-of-words model)是文字模型化最常用的方法,它为每个单词设值一个特征值,依据是用类似单词的文章意思也差不多

CountVectorizer类会将文档全部转化成小写,然后把句子分割成块或有意义的字母序列,并统计他们出现的次数
可以使用stop_words选项排除一些常用的但没有意义的助词。

from sklearn.feature_extraction.text import CountVectorizer
co=[
    'UNC played Duke in basketball',
    'Duke lost the basketball game ,game over',
    'I ate a sandwich'
]
vec=CountVectorizer(stop_words='english')
print(vec.fit_transform(co).todense())
print(vec.vocabulary_)

# 三行数据
[[0 1 1 0 0 1 0 1]
[0 1 1 2 1 0 0 0]
[1 0 0 0 0 0 1 0]]
{'unc': 7, 'played': 5, 'duke': 2, 'basketball': 1, 'lost': 4, 'game': 3, 'ate': 0, 'sandwich': 6}

import jieba
from sklearn.feature_extraction.text import CountVectorizer
corpus=[
    '朋友,小红是我的',
    '小明对小红说:“小红,我们还是不是朋友”',
    '小明与小红是朋友'
]
cutcorpus=["/".join(jieba.cut(x)) for x in corpus]
vec==CountVectorizer(stop_words=['好的','是的'])
counts=vec.fit_transform(cutcorpus).todense()
print(counts)
# 查看映射字典
print(vec.vocabulary_)

可以用词频向量的欧式距离(L2范数)来衡量两个文档之间的距离(距离越小越相似)
在这里插入图片描述

from sklearn.feature_extraction.text import CountVectorizer
# 计算欧式距离
from sklearn.metrics.pairwise import euclidean_distances
vectorizer=CountVectorizer()
for x,y in [[0,1],[0,2],[1,2]]:
    dist=euclidean_distances(counts[x],counts[y])
    print('文档{}与文档{}的距离{}'.format(x,y,dist))

3.3、Tf-idf权重向量

在这里插入图片描述

from sklearn.feature_extraction.text import TfidfTransformer
transformer=TfidfTransformer(smooth_idf=False)
counts=[[3,0,1],
       [2,0,0],
       [3,0,0],
       [4,0,0],
       [3,2,0],
       [3,0,2]]
tfidf=transformer.fit_transform(counts)
tfidf.toarray()


array([[0.81940995, 0.        , 0.57320793],
       [1.        , 0.        , 0.        ],
       [1.        , 0.        , 0.        ],
       [1.        , 0.        , 0.        ],
       [0.47330339, 0.88089948, 0.        ],
       [0.58149261, 0.        , 0.81355169]])
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer=TfidfVectorizer()
vectorizer.fit_transform(cutcorpus).toarray()
vectorizer.vocabulary_ 


{'小明': 0, '小红': 1, '我们': 2, '是不是': 3, '朋友': 4}

3.4、特征哈希值

词袋模型的方法很好用,也很直接,但在有些场景下很难使用,比如分词后的词汇字典表非常大, 达到100万+,此时如果直接使用词频向量或Tf-idf权重向量的方法,将对应的样本对应特征矩阵载入内存,有可能将内存撑爆,在这种情况下我们该怎么办呢?

我们可以应用哈希技巧进行降维。

Hash函数可以将一个任意长度的字符串映射到_个固定长度的散列数字中去。Hash函数是一种典 型的多对一映射。

  • 正向快速:给定明文和hash算法,在有限时间和有限资源内能计算出hash值。
  • 逆向困难:给定(若干)hash值,在有限时间内很难(基本不可能)逆推出明文。
  • 输入敏感:原始输入信息修改一点信息,产生的hash值看起来应该都有很大不同。
  • 碰撞避免:很难找到两段内容不同的明文,使得它们的hash值一致(发生碰撞)。即对于任意两个不同的数据块,其hash值相同的可能性极小;对于一个给定的数据块,找到和它hash值相同的数据块极为困难。
    目前流行的Hash函数包括MD4,MD5,SHA等。
    在这里插入图片描述
    在这里插入图片描述
from sklearn.feature_extraction.text import HashingVectorizer
corpus=['smart boy','ate','bacon','a cat']

# HashingVectorizeras是无状态的,不需要fit

vectorizer=HashingVectorizer(n_features=6,stop_words='english')
print(vectorizer.transform(corpus).todense())

[[-0.70710678 -0.70710678  0.          0.          0.          0.        ]
 [ 0.          0.          0.          1.          0.          0.        ]
 [ 0.          0.          0.          0.         -1.          0.        ]
 [ 0.          1.          0.          0.          0.          0.        ]]
from sklearn.feature_extraction.text import HashingVectorizer

corpus=[
    'UNC played Duke in basketball',
    'Duke lost the basketball game ,game over',
    'I ate a sandwich'
    ]
vectorizer=HashingVectorizer(n_features=6)
counts=vectorizer.transform(corpus).todense()
print(counts)
counts.shape

[[ 0.          0.         -0.89442719  0.          0.         -0.4472136 ]
 [-0.37796447 -0.75592895 -0.37796447  0.          0.         -0.37796447]
 [ 0.          0.          0.70710678  0.70710678  0.          0.        ]]

Out[9]:(3, 6)

四、特征选择

https://www.cnblogs.com/jasonfreak/p/5448385.html
当数据预处理完成后,我们需要选择有意义的特征输入机器学习的算法和模型进行训练。通常来 说,从两个方面考虑来选择特征:

  • 特征是否发散:如果一个特征不发散,例如方差接近于0 ,也就是说样本在这个特征上基本上没有差异,这个特征对于样本的区分并没有什么用。
  • 特征与目标的相关性:这点比较显见,与目标相关性高的特征,应当优选选择。除方差法外,本文介绍的其他方法均从相关性考虑。

根据特征选择的形式又可以将特征选择方法分为3种:

1、Filter:过滤法,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,选择特征。
2、Wrapper:包装法,根据目标函数(通常是预测效果评分),每次选择若干特征,或者排除若干特征。
3、Embedded :嵌入法,先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征。类似于Filter方法,但是是通过训练来确定特征的优劣。

4.1、Filter过滤法

4.1.1、方差选择法

使用方差选择法,先要计算各个特征的方差,然后根据阙值,选择方差大于阙值的特征。(用的不是很多)

from sklearn.feature_selection import VarianceThreshold

**方差选择法,返回值为特征选择后的数据**
**参数thresshold为方差的阙值,方差大于3(threshold=3**

vardata=VarianceThreshold(threshold=3).fit_transform(iris.data)
vardata.shape

(150, 1)

4.1.2、相关系数法

使用相关系数,先要计算各个特征对目标值的相关系数。用feature_selection库的SelectKBest类结合相关系数来选择

from sklearn.feature_selection import SelectKBest
from scipy.stats import pearsonr
import numpy as np

**选择K个最好的特征,返回选择特征后的数据**
**第一个参数为计算评估特征是否好的函数,该函数输入特征矩阵和目标向量**
**输出二元(评分,P值)的数组,数组第i项为第i个特征的评分和P值**

f=lambda X ,Y:np.array(list(map(lambda x:pearsonr(x,Y)[0],X.T))).T
SelectKBest(f,k=2).fit_transform(iris.data,iris.target)

4.1.3、卡方检验

在这里插入图片描述

from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2

SelectKBest(chi2,k=2).fit_transform(iris.data,iris.target)

4.1.4、互信息法

经典的互信息法也是评价定性自变量对定性因变量的相关性的。相关系数,卡方检验,互信息选择原理相似,但相关系数通常只适用于连续特征选择

import numpy as np
from sklearn.feature_selection import SelectKBest
from sklearn import metrics

mic=metrics.mutual_info_score

g=lambda X ,Y:np.array(list(map(lambda x:mic(x,Y),X.T))).T

SelectKBest(g,k=2).fit_transform(iris.data,iris.target)

4.2、Wrapper

递归特征消除法(RFE)
递归消除特征法使用一个基膜型进行多伦训练,每轮训练后,消除若干权值系数的特征,再基于新的特征集进行下一轮训练

from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression

**递归特征消除法,返回特征选择后的数据**
**参数estimator为基膜型**
**n_features_to_select=2特征个数**

RFE(estimator=LogisticRegression(),n_features_to_select=2).fit_transform(iris.data,iris.target)

4.3、Embedded嵌入法

https://blog.csdn.net/jinping_shi/article/details/52433975

使用带惩罚项的基模型,除了筛选出特征外同时也进行了降维。使用feature_selection库的SelectFormModel类结合带L1惩罚项的逻辑回归模型,来选择特征的代码如下

from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression

# L1正则化的回归模型

SelectFromModel(LogisticRegression(penalty='l1',C=0.1)).fit_transform(iris.data,iris.target)

L1惩罚项降维的原理在于保留多个对目标值具有同等相关性的特征中的一个,所以没选到的特征不代表不重要。故,可结合L2惩罚项来优化。具体操作为:若一个特征在L1中的权值为1 ,选择在L2 中权值差别不大且在L1中权值为0的特征构成同类集合,将这一集合中的特征平分L1中的权值,故需要构建一个新的逻辑回归模型:


更多精彩内容