特征工程
特征工程是什么
特征工程是将原始数据转化为更好的代表预测模型的潜在问题的特征的过程,从而提高对未知数据的预测准确性
特征工程包括特征提取、数据的预处理、特征降维
特征抽取
分类特征变量提取
对字典数据进行特征提取,语法是:
sklearn.feature_extraction.DictVectorizer(sparse=True)
将映射列表转换为Numpy矩阵或者scipy.sparse矩阵
- sparse参数是否选择为True决定是否输出为sparse矩阵,默认开启
- sparse矩阵:节约内存,方便数据读取
import sklearn
from sklearn.feature_extraction import DictVectorizer
onehot = DictVectorizer()
instances = [{'city':'北京','temperature':100},{'city':'上海','temperature':60},{'city':'深圳','temperature':89}]
data = onehot.fit_transform(instances)
# 返回类别名称
print(onehot.get_feature_names())
print('##########')
print(data)
print('----1----')
print(data.toarray())
# inverse_transform可以将列表numpy数组或者sparse矩阵转换为映射列表
print(onehot.inverse_transform(data.toarray()))
运行结果:
['city=上海', 'city=北京', 'city=深圳', 'temperature']
##########
(0, 1) 1.0
(0, 3) 100.0
(1, 0) 1.0
(1, 3) 60.0
(2, 2) 1.0
(2, 3) 89.0
----1----
[[ 0. 1. 0. 100.]
[ 1. 0. 0. 60.]
[ 0. 0. 1. 89.]]
[{'temperature': 100.0, 'city=北京': 1.0}, {'temperature': 60.0, 'city=上海': 1.0}, {'city=深圳': 1.0, 'temperature': 89.0}]
文本特征抽取
作用:对文本数据进行特征值化
from sklearn.feature_extraction.text import CountVectorizer
onehot = CountVectorizer()
data = ['life is short,i love python', 'life is to long,i love python']
result = onehot.fit_transform(data).toarray()
# 统计所有出现的词语,重复出现的当做一次处理
print(onehot.get_feature_names())
result
运行结果:
['is', 'life', 'long', 'love', 'python', 'short', 'to']
array([[1, 1, 0, 1, 1, 1, 0],
[1, 1, 1, 1, 1, 0, 1]], dtype=int64)
tf-idf算法实现文本的特征抽取:
from sklearn.feature_extraction.text import TfidfVectorizer
tf = TfidfVectorizer()
data = ['life is short,i love python', 'life is to long,i love python']
result = tf.fit_transform(data).toarray() # 返回的是对应的权重,也就是每个单词在原文本之中的重要程度
print(tf.get_feature_names())
result
运行结果:
['is', 'life', 'long', 'love', 'python', 'short', 'to']
array([[ 0.4090901 , 0.4090901 , 0. , 0.4090901 , 0.4090901 ,
0.57496187, 0. ],
[ 0.35464863, 0.35464863, 0.49844628, 0.35464863, 0.35464863,
0. , 0.49844628]])
特征预处理
数据型数据:标准缩放:
- 归一化
- 标准化
- 缺失值
类别型数据:one-hot编码
时间类型:时间的切分
归一化
通过对原始数据进行变换将数据映射到[0,1]之间
from sklearn.preprocessing import MinMaxScaler
data = np.array([[11,22,33],[44,55,66],[77,88,99]]).astype(np.float64)
# feature_range可以设定数据缩放的范围
# 这是对每一列分别进行范围缩放,即每一列在范围缩放的时候是独立计算的
mm = MinMaxScaler(feature_range=(0,1))
result = mm.fit_transform(data)
result
运行结果:
array([[ 0. , 0. , 0. ],
[ 0.5, 0.5, 0.5],
[ 1. , 1. , 1. ]])
注:注意在特定场景下最大值和最小值是变化的,另外,最大值和最小值非常容易受到异常点的影响,所以这种方法的鲁棒性比较差,只适合传统小场景数据(鲁棒性值的就是产品的稳定性),但是目前情况下小数据场景应用的非常少,所以我们在一般情况下是不会用归一化的,一般来说我们会用标准化
标准化(常用)
通过对原始数据进行变换把数据变换为均值为0,方差为1范围内
标准化:每个值减去均值然后除以标准差;作用于每一列
- 对于归一化来说,如果出现了异常点,影响了最大值和最小值,那么结果肯定会发生改变
- 对于标准化来说,由于具有一定的数据量,少量的异常点对于平均值的影响不大,从而方差改变小
from sklearn.preprocessing import StandardScaler
data = np.array([[11,22,33],[44,55,66],[77,88,99]]).astype(np.float64)
mm = StandardScaler()
result = mm.fit_transform(data)
result
运行结果:
array([[-1.22474487, -1.22474487, -1.22474487],
[ 0. , 0. , 0. ],
[ 1.22474487, 1.22474487, 1.22474487]])
缺失值处理
sklearn缺失值:sklearn.preprocessing.Imputer
- Imputer(missing_values='NaN', strategy='mean', axis=0) # 用缺失值存在的那一列的均值进行填补
- Imputer.fit_transform(X) # X是numpy array的格式的数据
- 返回值:返回形状相同的array
- 后面主要用的是pandas库进行缺失值的处理,NaN这种格式要求pandas的数据是float类型,也可以用replace函数来替换不是这只能怪格式的数据
数据降维(指的是特征的数量)
- 特征选择
- 主成分分析
特征选择
进行特征选择的原因是:
- 冗余:部分特征的相关度高,容易消耗计算性能
- 噪声:部分特征对预测结果有影响
variance Threshold
from sklearn.feature_selection import VarianceThreshold
# 删除方差为0的所有列,threshold可以根据自己的需求进行设定
var = VarianceThreshold(threshold=0.0)
data = var.fit_transform([[1,2,4,4],[3,4,5,4],[4,5,6,4],[4,7,3,4]])
print(data)
运行结果:
[[1 2 4]
[3 4 5]
[4 5 6]
[4 7 3]]
主成分分析
- 本质:PCA是一种分析、简化数据的技术
- 目的:压缩维数,尽可能减少原数据的维数(复杂度),损失少量信息,特征数量会减少,但是数据也会发生改变
- 作用:可以削减回归分析或者聚类分析中特征的数量
from sklearn.decomposition import PCA
# 如果n_components为小数,意思是降维后数据信息保存程度,也就是降维后信息至多损失10%
# 如果n_components为整数,意思是降维后特征的数量
pca = PCA(n_components=0.9)
data = pca.fit_transform([[2,1,5],[4,7,9],[5,2,7]])
data
运行结果:
array([[-3.30864763, -1.12919366],
[ 4.15275574, -0.55693769],
[-0.84410852, 1.68613088]], dtype=float32)
pca = PCA(n_components=2)
data = pca.fit_transform([[2,1,5],[4,7,9],[5,2,7]])
data
运行结果:
array([[-3.30864763, -1.12919366],
[ 4.15275574, -0.55693769],
[-0.84410852, 1.68613088]], dtype=float32)
补充:pandas的数据合并,连接
join函数可以利用行索引将两个DataFrame结构的数据进行连接,如果行数不相同的用NaN进行补全
pd.merge用来将数据进行合并,
merge(left, right, how='inner', on=None, left_on=None, right_on=None,
left_index=False, right_index=False, sort=True,
suffixes=('_x', '_y'), copy=True, indicator=False)
主要用到的参数:
- left和right表示输入的两个DataFrame结构
- 如果两个数据有重复的列名,默认就是按照重复的列名进行合并,或者通过on设置需要记性合并的参数
- 如果两边没有相同的列名,但是两边有相似的含义的列名,通过left_on和right_on进行设置
- 如果是利用行索引进行合并,可以用join进行合并
- how有四个可选参数('inner' 'outer' 'left' 'right')分别取交集,并集,各取一边
In [16]: df1=DataFrame({'key':['a','b','b'],'data1':range(3)})
In [17]: df2=DataFrame({'key':['a','b','c'],'data2':range(3)})
In [18]: pd.merge(df1,df2) #没有指定连接键,默认用重叠列名,没有指定连接方式
Out[18]:
data1 key data2
0 0 a 0
1 1 b 1
2 2 b 1
In [19]: pd.merge(df2,df1)
Out[19]:
data2 key data1
0 0 a 0
1 1 b 1
2 1 b 2 #默认内连接,可以看见c没有连接上。
In [20]: pd.merge(df2,df1,how='left') #通过how,指定连接方式
Out[20]:
data2 key data1
0 0 a 0
1 1 b 1
2 1 b 2
3 2 c NaN
In [23]: right=DataFrame({'key1':['foo','foo','bar','bar'],
...: 'key2':['one','one','one','two'],
...: 'lval':[4,5,6,7]})
In [24]: left=DataFrame({'key1':['foo','foo','bar'],
...: 'key2':['one','two','one'],
...: 'lval_x':[1,2,3]})
In [25]: right=DataFrame({'key1':['foo','foo','bar','bar'],
...: 'key2':['one','one','one','two'],
...: 'lval_y':[4,5,6,7]})
In [26]: pd.merge(left,right,on=['key1','key2'],how='outer') #传出数组
Out[26]:
key1 key2 lval_x lval_y
0 foo one 1 4
1 foo one 1 5
2 foo two 2 NaN
3 bar one 3 6
4 bar two NaN 7
In [31]: df3=DataFrame({'key3':['foo','foo','bar','bar'], #将上面的right的key 改了名字
...: 'key4':['one','one','one','two'],
...: 'lval_y':[4,5,6,7]})
In [32]: pd.merge(left,df3,left_on='key1',right_on='key3') #键名不同的连接
Out[32]:
key1 key2 lval_x key3 key4 lval_y
0 foo one 1 foo one 4
1 foo one 1 foo one 5
2 foo two 2 foo one 4
3 foo two 2 foo one 5
4 bar one 3 bar one 6
5 bar one 3 bar two 7