sklearn
sklearn
介绍
采集到的样本中的特征数据往往很多时候为字符串或者其他类型的数据,电脑只可以识别二进制数值型的数据,如果把字符串给电脑,电脑不能识别【如果不是数值型数据,识别不了】
效果演示【将字符串转换为数字】
from sklearn.feature_extraction.text import CountVectorizer
vector=CountVectorizer()
res=vector.fit_transform(['lift is short,I love python','lift is too long,I hate python'])
print(res.toarray())
# [[0 1 1 0 1 1 1 0]
# [1 1 1 1 0 1 0 1]]
结论
from sklearn.feature_extraction import DictVectorizer
fit_transform(X) #X为字典或者包含字典的迭代器,返回值为sparse矩阵
inverse_transform(X) #X为sparse矩阵或者array数组,返回值为转换之前的数据格式
transform(X) #按照原先的标准转换
get_feature_names() #返回类别名称
from sklearn.feature_extraction import DictVectorizer
alist=[
{"city":'AHui','temp':33},
{'city':'GZ','temp':42},
{'city':'SH','temp':40}
]
d=DictVectorizer() #实例化一个工具类对象
feature=d.fit_transform(alist) #返回一个sparse矩阵(存储的就是特征值化之后的结果)
print(feature)
# (0, 0) 1.0
# (0, 3) 33.0
# (1, 1) 1.0
# (1, 3) 42.0
# (2, 2) 1.0
# (2, 3) 40.0
print(d.get_feature_names())
# ['city=AHui', 'city=GZ', 'city=SH', 'temp']
print(feature.toarray())
# [[ 1. 0. 0. 33.]
# [ 0. 1. 0. 42.]
# [ 0. 0. 1. 40.]]
补充,sparse矩阵的理解
DictVectorizer
类的构造方法中设定sparse=False,则返回的就不是sparse矩阵,而是一个数组示例代码
from sklearn.feature_extraction import DictVectorizer
alist=[
{"city":'AHui','temp':33},
{'city':'GZ','temp':42},
{'city':'SH','temp':40}
]
d=DictVectorizer(sparse=False)
#返回一个二维列表
fature=d.fit_transform(alist)
print(d.get_feature_names()) # ['city=AHui', 'city=GZ', 'city=SH', 'temp']
print(feature)
#输出结果:1为是,0为不是
# [[ 1. 0. 0. 33.]
# [ 0. 1. 0. 42.]
# [ 0. 0. 1. 40.]]
作用:对文本数据进行特征值化
from sklearn.feature_extraction.text import CountVectorizer
fit_transform(X) #X为文本或者包含文本字符串的可迭代对象,返回sparse矩阵
inverse_transform(X) #X为sparse矩阵或者array数组,返回值为转换之前的数据格式
toarray() #将sparse矩阵转化为数组
示例代码
from sklearn.feature_extraction.text import CountVectorizer
vector=CountVectorizer()
res=vector.fit_transform(['lift is is short,I love python','lift is too long,I hate python'])
print(res)#sparse矩阵
# (0, 2) 1
# (0, 1) 2
# (0, 6) 1
# (0, 4) 1
# (0, 5) 1
# (1, 2) 1
# (1, 1) 1
# (1, 5) 1
# (1, 7) 1
# (1, 3) 1
# (1, 0) 1
print(vector.get_feature_names())
#['hate', 'is', 'lift', 'long', 'love', 'python', 'short', 'too']
print(res.toarray())#将sparse矩阵转换成数组
# [[0 2 1 0 1 1 1 0]
# [1 1 1 1 0 1 0 1]]
#注意:单字母不统计(因为单个字母代表不了实际含义),然后每个数字表示的是单词出现的次数
中文文本特征提取【对有标点符号的中文文本进行特征提取】
from sklearn.feature_extraction.text import CountVectorizer
vector=CountVectorizer()
res=vector.fit_transform(['人生苦短 我用python','人生满长,不用python'])
print(res)
# (0, 2) 1
# (0, 3) 1
# (1, 1) 1
# (1, 0) 1
print(vector.get_feature_names())
['不用python', '人生满长', '人生苦短', '我用python']
print(res.toarray())
# [[0 0 1 1]
# [1 1 0 0]]
中文文本特征提取【对有标点符合且有空格分隔的中文文本进行特征提取】【注意:单个汉字不统计】
from sklearn.feature_extraction.text import CountVectorizer
vector=CountVectorizer()
res=vector.fit_transform(['人生 苦短, 我 用python','人生 漫长, 不用 python'])
print(res)
# (0, 2) 1
# (0, 5) 1
# (0, 4) 1
# (1, 2) 1
# (1, 3) 1
# (1, 1) 1
# (1, 0) 1
print(vector.get_feature_names())
# ['python', '不用', '人生', '漫长', '用python', '苦短']
print(res.toarray())
# [[0 0 1 0 1 1]
# [1 1 1 1 0 0]]
目前CountVectorizer
只可以对有标点符号和用分隔符对应的文本进行特征提取,满足不了需求【在自然语言处理中,我们是需要将一段中文文本中相关的词语,成语,形容词…都要进行提取的】
对中文文章进行分词处理
使用
#基本使用:对文章进行分词
import jieba
jb = jieba.cut('我是一个好人')
content = list(jb)
ct = ' '.join(content)
print(ct) #返回空格区分的词语
import jieba
from sklearn.feature_extraction.text import CountVectorizer
jb1=jieba.cut('人生苦短,我用python,你觉得我说的对吗?')
ct1=" ".join(list(jb1))
print(ct1)
# 人生 苦短 , 我用 python , 你 觉得 我 说 的 对 吗 ?
jb2=jieba.cut('人生满长,不用python,你说我说的对不对?')
ct2=" ".join(list(jb2))
print(ct2)
# 人生 满长 , 不用 python , 你 说 我 说 的 对 不 对 ?
vector=CountVectorizer()
res=vector.fit_transform([ct1,ct2])
print(res)
# (0, 2) 1
# (0, 5) 1
# (0, 3) 1
# (0, 0) 1
# (0, 6) 1
# (1, 2) 1
# (1, 0) 1
# (1, 4) 1
# (1, 1) 1
print(vector.get_feature_names())
# ['python', '不用', '人生', '我用', '满长', '苦短', '觉得']
print(res.toarray())
# [[1 0 1 1 0 1 1]
# [1 1 1 0 1 0 0]]
为什么需要onehot
编码
特征抽取主要目的就是对非数值型的数据进行特征值化!如果现在需要对下图中的human和alien进行手动特征值化Alien为4,human为1。则1和4有没有优先级或者权重大小之分呢?
就需要用onehot
编码
基于pandas
实现onehot
编码【pd.get_dummies(df['col']
】
import pandas as pd
df=pd.DataFrame([
['green','M',20,'class1'],
['red','L',21,"class2"],
['blue','XL',30,'class3']
])
df.columns=['color','size','weight','class label']
#将color这一列变成one-hot编码
pd.get_dummies(df['color'])
# blue green red
# 0 0 1 0
# 1 0 0 1
# 2 1 0 0
对数值型数据进行处理
预处理就是用来实现无量钢化的方式
无量钢化:
含义:特征抽取后我们就可以获取对应的数值型的样本数据,然后进行数据处理
概念:通过特定的统计方式(数学方法),将算法转换成算法要求的数据
方式
from sklearn.preprocessing import MinMaxScaler
参数:feature_range表示缩放范围,通常使用(0,1)
作用:使得某一个特征对最终结果不会造成很大的影响
from sklearn.preprocessing import MinMaxScaler
mm=MinMaxScaler(feature_range=(0,1)) #每个特征缩放的范围
data=[[90,2,10,40],[60,5,15,45],[73,3,13,45]]
data=mm.fit_transform(data)#data需要归一化的特征
print(data)
# [[1. 0. 0. 0. ]
# [0. 1. 1. 1. ]
# [0.43333333 0.33333333 0.6 1. ]]
问题:如果数据中存在的异常值比较多,会有什么影响?
归一化总结:
当数据按均值中心化后,再按标准差缩放,数据就会服从为均值为0,方差为1的正态分布(即标准正态分布),而这个过程,就叫做数据标准化(Standardization,又称Z-score normalization),公式如下
从公式可以看出,异常值对均值和标准差的影响不大
API
处理后,每列所有的数据都聚集在均值为0,标准差为1范围附近
标准化API:
from sklearn.preprocessing import StandardScaler
fit_transform(X) #对X标准化
mean_#均值
var_ #方差
示例
from sklearn.preprocessing import StandardScaler
ss=StandardScaler()
data=[[90,2,10,40],[60,5,15,45],[73,3,13,45]]
ss.fit_transform(data)
# array([[ 1.27540458, -1.06904497, -1.29777137, -1.41421356],
# [-1.16685951, 1.33630621, 1.13554995, 0.70710678],
# [-0.10854507, -0.26726124, 0.16222142, 0.70710678]])
ss.mean_ #array([74.33333333, 3.33333333, 12.66666667, 43.33333333])
ss.var_ #array([150.88888889, 1.55555556, 4.22222222, 5.55555556])
StandardScaler
和MinMaxSclaer
选哪个?StandardSclaer
来进行特征缩放,因为MinMaxSclaer
对异常值非常敏感。在CPA,聚类,逻辑回归,支持向量机,神经网络这些算法中,StandardSclaer
往往是最好的选择。MinMaxScaler
在不涉及距离度量,梯度,协方差计算以及数据需要被压缩到特定区间时,使用广泛,比如数字图像处理中量化像素强度时,都会使用MinMaxScaler
将数据压缩于[0,1]区间之中StandardScaler
,效果不好换MinMaxScaler
从特征中选择出有意义对模型有帮助的特征作为最终的机器学习输入的数据
注意
人为对不相关的特征进行主关舍弃
在真正的数据应用领域,比如:金融,医疗,电商,我们得数据特征非常多,这样明显,如果遇见极端的情况,我们无法依赖对业务的理解来选则特征怎么办?
原理:这是通过特征本身的方差来筛选特征的类,比如:一个特征本身的方差很小,就表示样本在这个特征上基本没有差异,可能特征中的大多数值都一样,甚至整个特征的取值都相同,那这个特征对于样本区分没有作用,所以无论接下来特征工程要做什么,都要优先消除方差为0或方差较低的特征
API
from sklearn.feature_selection import VarianceThreshold
VarianceThreshold(threshold=x) #threshold为方差的值,删除所有方差低于x的特征,默认为0表示保留所有方差为非0的特征
fit_transform(X) #X为特征
示例
from sklearn.feature_selection import VarianceThreshold
#threshold方差的值,threshold=1,删除所有方差低于1的特征,默认为0,宝石保留所有方差为非0的特征
v=VarianceThreshold(threshold=1)
v.fit_transform([[0,2,4,3],[0,3,7,3],[0,9,6,3]])#X为特征【数据为特征】
如果将方差为0或方差极低的特征取出后,剩余特征还有很多且模型的效果没有显著提升,则可以用方差将特征选择【一步到位】。留下一半的特征,那可以设定一个让特征总数减半的方差阈值,即找到特征方差的中位数,将中位数作为参数threshold的值即可
from sklearn.feature_selection import VarianceThreshold
#threshold方差的值,threshold=1,删除所有方差低于1的特征,默认为0,宝石保留所有方差为非0的特征
v=VarianceThreshold(threshold=np.median(X.var().values))
v.fit_transform(X)## X为样本数据中的特征列
方差过滤对模型的影响
定义
降维的维度值就是特征的种类
思想:如何跟好的对一个立体的物体用二维表示
当然,第四张二维图片可以比较好的标识一个立体三维的水壶。但是也要清楚,用一个低纬度去表示高纬度的物体时,一定会造成一些信息的差异。可以让低纬度也可以能正确的表示高纬度的事物,或者信息差异最小。
目的:特征数量达到上百,上千的时候,考虑数据的优化。使数据维度压缩,尽可能降低源数据的维度(复杂度),损失少量信息。
作用:可以削减回归分析或者聚类分析中特征的数量
PCA大致原理
红色为原始的样本特征,为二维的特征,如果降为一维,则可以将5个红色的原始特征,映射到一维的线段上就变成了4个特征。
PCA语法
from sklearn.decomposition import PCA
pca=PCA(n_components=None)
# n_components可以为小数(保留特征的百分比),整数(减少到的特征数量)
pca.fit_transform(X)
示例
from sklearn.decomposition import PCA
#将数据分解为较低维度的空间
#n_components可以为小数(保留特征的百分比),整数(减少到的特征数量)【保留几个特征值】
pca=PCA(n_components=2)
pca.fit_transform([[0,2,4,3],[0,3,7,3],[0,9,6,3]])
概述:IV
和WOE
通常是用在对模型的特征筛选中,在模型刚建立时,变量往往很多,IV
和WOE
可以帮助我们衡量什么变量应该进入模型什么变量应该舍弃。用IV
和WOE
值来进行判断,值越大表示该特征的预测能力越强,则该特征应该加入到模型的训练中
WOE(Weight Of Evidence)
用来衡量特征的预测强度,要是用WOE
,首先要对特征进行分箱(分组:将一种特征的组成元素进行分组),分享之后,对于其中第i组的WOE
值公式如下:py_i
表示该组中的正例占负例样本的比例,pn_i
表示整体的正例占负例样本的比例
例子
假设现在某个公司举行一个活动,在举行这个活动之前,先在小范围的客户中进行了一次试点,收集了一些用户对这次活动的一些响应,然后希望通过这些数据,去构造一个模型,预测如果举行这次的活动,是否能够得到很好的响应或者得到客户的响应概率之类。
假设我们已经从公司客户列表中随机抽取了100000个客户进行了营销活动测试,收集了这些客户的响应结果,作为我们的建模数据集,其中响应的客户有10000个。另外假设我们也已经提取到了这些客户的一些变量,作为我们模型的候选变量集,这些变量包括以下这些:
假设,我们已经对这些变量进行了离散化,统计的结果如下面几张表所示。
根据结果,对结果的正负值分析,根据ln函数的特性,当这个组中响应样本的比例比总体的响应比例小时为负数,相等时为0,大于时为整数
把这个变量的所有分组的WOE
值的绝对值加起来,这个可以在一定程度上表示这个变量的预测能力,但是一般不会这么做,因为对于分组中的样本数量相差悬殊的场景,WOE
值可能不能很好的表示出这个变量的预测能力,一边会用到另一个值:IV值。IV在计算的时候,比WOE
值多考虑了一层该变量下该分组占该变量下所有样本的比例
py_i-pn_i
),py_i
表示该组中的正例占负例样本的比例,pn_i
表示整体的正例占负例样本的比例数据分箱(也称为离散分箱或分段)是一种数据预处理技术,用于减少次要观察误差的影响,是一种将多个连续值分组为较少数量的"分箱"的方法,就是将连续型特征进行离散化
分箱的作用和意义
注意:对特征进行分箱后,需要对分箱后的每组(箱)进行woe编码,然后才能放进模型训练
例如我们有一组关于人年龄的数据,如下图所示
注意
pd.cut()
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
score_list=np.random.randint(30,100,size=20)
# [92 73 73 49 62 35 56 90 81 84 84 89 96 94 54 51 91 43 54 98]
#设置分箱:方式一
bins=[0,59,70,80,100]
score_cat=pd.cut(score_list,bins)#指定分箱数据的范围
print(pd.value_counts(score_cat))
# Categories (4, interval[int64]): [(0, 59] < (59, 70] < (70, 80] < (80, 100]]
# (0, 59] 9
# (80, 100] 4
# (70, 80] 4
# (59, 70] 3
# dtype: int64
#设置分箱:方式2
bins = 3#指定分箱数据的范围的个数
score_cat = pd.cut(score_list, bins,labels=range(3))#labels设置分箱的每一个范围标识
print(score_cat)
print(pd.value_counts(score_cat))
# [0, 2, 0, 1, 1, ..., 0, 0, 2, 2, 0]
# Length: 20
# Categories (3, int64): [0 < 1 < 2]
# 0 9
# 2 7
# 1 4
# dtype: int64
import sklearn.datasets as ds
bc=ds.load_breast_cancer()
feature=bc.data
target=bc.target
#查看第一列数据范围,判定是连续数据
feature[:,1].min(),feature[:,1].max()#(9.71, 39.28)
#对其进行分箱处理,将其离散化
fea_bins=pd.cut(feature[:,1],bins=5,labels=range(5))
fea_bins.value_counts()
#0 113
# 1 299
# 2 129
# 3 25
# 4 3
# dtype: int64
#对分箱后的特征进行woe编码
gi=pd.crosstab(fea_bins,target)
gb=pd.Series(data=target).value_counts()
bgi=(gi[1]/gi[0])/(gb[1]/gb[0])
# row_0
# 0 7.794118
# 1 1.164157
# 2 0.257330
# 3 0.755793
# 4 0.296919
# dtype: float64
woe=np.log(bgi)
# row_0
# 0 2.053369
# 1 0.151997
# 2 -1.357398
# 3 -0.279987
# 4 -1.214297
# dtype: float64
#进行映射操作
dict=woe.to_dict()
woe_bins=fea_bins.map(dict)
woe_bins.tolist()
from imblearn.over_sampling import SMOTE
通过增加分类中少数类样本的数量来实现样本均衡,比较好的方法有SMOTE
算法
SMOTE
算法原理
smote
算法的思想是合成新的少数类样本,合成的策略是对每个少数类样本a,从他的最近邻中随机选一个样本b,然后再a,b之间连线上随机选一点作为新合成的少数类样本示例
import pandas as pd
import numpy as np
from imblearn.over_sampling import SMOTE
#数据源生成
x=np.random.randint(0,100,size=(100,3))
y=pd.Series(data=np.random.randint(0,1,size=(95,)))
y=y.append(pd.Series(data=[1,1,1,1,1]),ignore_index=False).values
y=y.reshape((-1,1))
all_data_up=np.concatenate((x,y),axis=1)
np.random.shuffle(all_data_up)
df=pd.DataFrame(all_data_up)
#提取样本数据
feature=df[[0,1,2]]
target=df[3]
target.value_counts()
# 0 95
# 1 5
# Name: 3, dtype: int64
target.shape #(190,)
s=SMOTE(k_neighbors=3) #实例化算法对象
s_feature,s_target=s.fit_resample(feature,target)#合成新的样本数据
s_target.shape #(190,)
s_target.value_counts()
#1 95
# 0 95
# Name: 3, dtype: int64
欠抽样:通过减少分类中多数类样本的数量来实现样本均衡
from imblearn.under_sampling import RandomUnderSampler
import pandas as pd
import numpy as np
from imblearn.under_sampling import RandomUnderSampler
#数据源生成
x=np.random.randint(0,100,size=(100,3))
y=pd.Series(data=np.random.randint(0,1,size=(95,)))
y=y.append(pd.Series(data=[1,1,1,1,1]),ignore_index=False).values
y=y.reshape((-1,1))
all_data_up=np.concatenate((x,y),axis=1)
np.random.shuffle(all_data_up)
df=pd.DataFrame(all_data_up)
#提取样本数据
feature=df[[0,1,2]]
target=df[3]
target.value_counts()
# 0 95
# 1 5
# Name: 3, dtype: int64
r=RandomUnderSampler()
r_feature,r_target=r.fit_resample(feature,target)
r_target.shape #(10,)
r_target.value_counts()
# 1 5
# 0 5
# Name: 3, dtype: int64
r_feature.shape #(10, 3)
https://www.luffycity.com/