目录html
更新、更全的《机器学习》的更新网站,更有python、go、数据结构与算法、爬虫、人工智能教学等着你:http://www.javashuo.com/article/p-vozphyqp-cm.htmlpython
sklearn数据预处理官方文档地址:https://scikit-learn.org/stable/modules/classes.html#module-sklearn.preprocessing算法
import numpy as np import pandas as pd import matplotlib.pyplot as plt from matplotlib.font_manager import FontProperties from sklearn import datasets %matplotlib inline font = FontProperties(fname='/Library/Fonts/Heiti.ttc')
现实生活中的数据每每是不全面的,不少样本的属性值会有缺失,例如某我的填写的我的信息不完整或者对我的隐私的保护政策致使建模时可能没法获得所须要的特征,尤为是在数据量较大时,这种缺失值的产生会对模型的性能形成很大的影响。接下来将经过鸢尾花数据讨论缺失值处理的方法。安全
# 缺失值处理示例 from io import StringIO iris_data = ''' 5.1,,1.4,0.2 4.9,3.0,1.4,0.2 4.7,3.2,,0.2 7.0,3.2,4.7,1.4 6.4,3.2,4.5,1.5 6.9,3.1,4.9, ,,, ''' iris = datasets.load_iris() df = pd.read_csv(StringIO(iris_data), header=None) df.columns = iris.feature_names df = df.iloc[:, :4] df
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | |
---|---|---|---|---|
0 | 5.1 | NaN | 1.4 | 0.2 |
1 | 4.9 | 3.0 | 1.4 | 0.2 |
2 | 4.7 | 3.2 | NaN | 0.2 |
3 | 7.0 | 3.2 | 4.7 | 1.4 |
4 | 6.4 | 3.2 | 4.5 | 1.5 |
5 | 6.9 | 3.1 | 4.9 | NaN |
6 | NaN | NaN | NaN | NaN |
# axis=0删除有NaN值的行,axis=1删除有NaN值的列 df.dropna(axis=0)
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | |
---|---|---|---|---|
1 | 4.9 | 3.0 | 1.4 | 0.2 |
3 | 7.0 | 3.2 | 4.7 | 1.4 |
4 | 6.4 | 3.2 | 4.5 | 1.5 |
# 删除全为NaN值得行或列 df.dropna(how='all')
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | |
---|---|---|---|---|
0 | 5.1 | NaN | 1.4 | 0.2 |
1 | 4.9 | 3.0 | 1.4 | 0.2 |
2 | 4.7 | 3.2 | NaN | 0.2 |
3 | 7.0 | 3.2 | 4.7 | 1.4 |
4 | 6.4 | 3.2 | 4.5 | 1.5 |
5 | 6.9 | 3.1 | 4.9 | NaN |
# 删除行不为4个值的 df.dropna(thresh=4)
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | |
---|---|---|---|---|
1 | 4.9 | 3.0 | 1.4 | 0.2 |
3 | 7.0 | 3.2 | 4.7 | 1.4 |
4 | 6.4 | 3.2 | 4.5 | 1.5 |
# 删除花萼长度中有NaN值的数据 df.dropna(subset=['sepal length (cm)'])
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | |
---|---|---|---|---|
0 | 5.1 | NaN | 1.4 | 0.2 |
1 | 4.9 | 3.0 | 1.4 | 0.2 |
2 | 4.7 | 3.2 | NaN | 0.2 |
3 | 7.0 | 3.2 | 4.7 | 1.4 |
4 | 6.4 | 3.2 | 4.5 | 1.5 |
5 | 6.9 | 3.1 | 4.9 | NaN |
# 填充缺失值示例 from sklearn.impute import SimpleImputer # 对全部缺失值填充固定值0 # imputer = SimpleImputer(missing_values=np.nan, strategy='constant', fill_value=0) # 中位数strategy=median,众数strategy=most_frequent imputer = SimpleImputer(missing_values=np.nan, strategy='mean') imputer = imputer.fit_transform(df.values) df = pd.DataFrame(imputer, columns=iris.feature_names) df
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | |
---|---|---|---|---|
0 | 5.1 | 0.0 | 1.4 | 0.2 |
1 | 4.9 | 3.0 | 1.4 | 0.2 |
2 | 4.7 | 3.2 | 0.0 | 0.2 |
3 | 7.0 | 3.2 | 4.7 | 1.4 |
4 | 6.4 | 3.2 | 4.5 | 1.5 |
5 | 6.9 | 3.1 | 4.9 | 0.0 |
6 | 0.0 | 0.0 | 0.0 | 0.0 |
异常值有时候也会被称为离群值,处理异常值的方式相似于缺失值处理,能够暴力删除,也能够填充。可是异常值每每须要手动获取,通常获取异常值的方式有如下两种:数据结构
统计分析原则app
对特征值统计后分析判断哪些值是不符合逻辑的,拿年龄举例,若是发现某我的的年龄是200,至少目前是不合理的,所以能够设定一个条件,把年龄大于200的数据都排除掉。几率分布原则dom
根据高斯分布可知距离平均值\(3\delta\)以外的几率为0.003,这在统计学中属于极小几率事件,所以能够把超过该距离的值看成异常值处理。固然,你也能够手动设定这个距离或几率,具体问题具体分析。机器学习
# 标准高斯分布曲线 fig, ax = plt.subplots() np.random.seed(1) # 建立一组平均数为0,标准差δ为1,总个数为100000的符合标准正态分布的数据 Gaussian = np.random.normal(0, 1, 100000) ax.hist(Gaussian, bins=100, histtype="stepfilled", density=True, alpha=0.5, color='r') plt.xticks(np.arange(3, 4)) plt.title('标准高斯分布曲线', fontproperties=font, fontsize=20) plt.show()
现有一个汽车样本集,经过这个汽车样本集能够判断人们是否会购买该汽车。可是这个样本集的特征值是离散型的,为了确保计算机能正确读取该离散值的特征,须要给这些特征作编码处理,即建立一个映射表。若是特征值分类较少,能够选择自定义一个字典存放特征值与自定义值的关系。接下来将直接经过scikit-learn库转换属性值类型。函数
# 汽车样本 car_data = ''' 乘坐人数,后备箱大小,安全性,是否能够接受 4,med,high,acc 2,big,low,unacc 4,big,med,acc 4,big,high,acc 6,small,low,unacc 6,small,med,unacc ''' df = pd.read_csv(StringIO(car_data), header=0) df
乘坐人数 | 后备箱大小 | 安全性 | 是否能够接受 | |
---|---|---|---|---|
0 | 4 | med | high | acc |
1 | 2 | big | low | unacc |
2 | 4 | big | med | acc |
3 | 4 | big | high | acc |
4 | 6 | small | low | unacc |
5 | 6 | small | med | unacc |
safety_mapping = { 'low': 0, 'med': 1, 'high': 2, } df['安全性'] = df['安全性'].map(safety_mapping) df
乘坐人数 | 后备箱大小 | 安全性 | 是否能够接受 | |
---|---|---|---|---|
0 | 4 | med | 2 | acc |
1 | 2 | big | 0 | unacc |
2 | 4 | big | 1 | acc |
3 | 4 | big | 2 | acc |
4 | 6 | small | 0 | unacc |
5 | 6 | small | 1 | unacc |
# 对上述字典作反向映射处理,即反向映射回原来的离散类型的特征值。 inverse_safety_mapping = {v: k for k, v in safety_mapping.items()} df['安全性'].map(inverse_safety_mapping)
0 high 1 low 2 med 3 high 4 low 5 med Name: 安全性, dtype: object
继续沿用上一个汽车样本,使用sklearn自带库对数据类型编码。性能
# scikit-learn数据类型编码示例 from sklearn.preprocessing import LabelEncoder X_label_encoder = LabelEncoder() X = df[['乘坐人数', '后备箱大小', '安全性']].values X[:, 1] = X_label_encoder.fit_transform(X[:, 1]) X
array([[4, 1, 2], [2, 0, 0], [4, 0, 1], [4, 0, 2], [6, 2, 0], [6, 2, 1]], dtype=object)
# 对标记进行编码 y_label_encoder = LabelEncoder() y = y_label_encoder.fit_transform(df['是否能够接受'].values) y
array([0, 1, 0, 0, 1, 1])
# 对标记反向映射回原始数据 y_label_encoder.inverse_transform(y)
array(['acc', 'unacc', 'acc', 'acc', 'unacc', 'unacc'], dtype=object)
假设汽车安全性只是一个衡量标准,没有特定的顺序。可是计算机颇有可能把这些\(0,1,2\)做一个特定排序或者所以区分它们的重要性,这个时候就得考虑建立一个二进制值分别表示low、med、high这三个属性值,有为1,没有为0,例如\(010\)表示为med。
# 独热编码示例 from sklearn.preprocessing import OneHotEncoder one_hot_encoder = OneHotEncoder(categories='auto') one_hot_encoder.fit_transform(X).toarray()
array([[0., 1., 0., 0., 1., 0., 0., 0., 1.], [1., 0., 0., 1., 0., 0., 1., 0., 0.], [0., 1., 0., 1., 0., 0., 0., 1., 0.], [0., 1., 0., 1., 0., 0., 0., 0., 1.], [0., 0., 1., 0., 0., 1., 1., 0., 0.], [0., 0., 1., 0., 0., 1., 0., 1., 0.]])
# 使用pandas对数据作独热编码处理,数值型数据不作编码处理 pd.get_dummies(df[['乘坐人数', '后备箱大小', '安全性']])
乘坐人数 | 安全性 | 后备箱大小_big | 后备箱大小_med | 后备箱大小_small | |
---|---|---|---|---|---|
0 | 4 | 2 | 0 | 1 | 0 |
1 | 2 | 0 | 1 | 0 | 0 |
2 | 4 | 1 | 1 | 0 | 0 |
3 | 4 | 2 | 1 | 0 | 0 |
4 | 6 | 0 | 0 | 0 | 1 |
5 | 6 | 1 | 0 | 0 | 1 |
使用独热编码在解决特征值无序性的同时也增长了特征数,这无疑会给将来的计算增长难度,所以能够适当减小没必要要的维度。例如当为后备箱进行独热编码的时候会有后备箱大小_big、后备箱大小_med、后备箱大小_small三个特征,能够减去一个特征,即后备箱大小_big与后备箱大小_med都为0则表明是后备箱大小_small。在调用pandas的get_dummies函数时,能够添加drop_first=True参数;而使用OneHotEncoder时得本身分隔。
pd.get_dummies(df[['乘坐人数', '后备箱大小', '安全性']], drop_first=True)
乘坐人数 | 安全性 | 后备箱大小_med | 后备箱大小_small | |
---|---|---|---|---|
0 | 4 | 2 | 1 | 0 |
1 | 2 | 0 | 0 | 0 |
2 | 4 | 1 | 0 | 0 |
3 | 4 | 2 | 0 | 0 |
4 | 6 | 0 | 0 | 1 |
5 | 6 | 1 | 0 | 1 |
为了解决相同权重特征不一样尺度的问题,可使用机器学习中的最小-最大标准化作处理,把他们两个值压缩在\([0-1]\)区间内。
最小-最大标准化公式:
\[ x_{norm}^{(i)}={\frac{x^{(i)}-x_{min}}{x_{max}-x_{min}}} \]
其中\(i=1,2,\cdots,m\);\(m\)为样本个数;\(x_{min},x_{max}\)分别是某个的特征最小值和最大值。
# 最小最大标准化示例 from sklearn.preprocessing import MinMaxScaler import numpy as np test_data = np.array([1, 2, 3, 4, 5]).reshape(-1, 1).astype(float) min_max_scaler = MinMaxScaler() min_max_scaler.fit_transform(test_data)
array([[0. ], [0.25], [0.5 ], [0.75], [1. ]])
Z-score标准化方法也能够对数据进行标准化,可是它的标准化并不能把数据限制在某个区间,它把数据压缩成相似高斯分布的分布方式,而且也能处理离群值对数据的影响。
在分类、聚类算法中,须要使用距离来度量类似性的时候应用很是好,尤为是数据自己呈正态分布的时候。
数据标准化公式:
\[ x_{std}^{(i)}={\frac{x^{(i)}-\mu{_x}}{\sigma{_x}}} \]
使用标准化后,能够把特征列的中心设在均值为\(0\)且标准差为\(1\)的位置,即数据处理后特征列符合标准正态分布。
# Z-score标准化 from sklearn.preprocessing import StandardScaler test_data = np.array([1, 2, 3, 4, 5]).reshape(-1, 1).astype(float) standard_scaler = StandardScaler() # fit_transform()=fit()+transform(), fit()方法估算平均值和方差,transform()方法对数据标准化 standard_scaler.fit_transform(test_data)
array([[-1.41421356], [-0.70710678], [ 0. ], [ 0.70710678], [ 1.41421356]])
二值化数据相似于独热编码,可是不一样于独热编码的是它不是0就是1,即又有点相似于二分类。直接给出数据二值化的公式:
\[ y = \begin{cases} 0,\quad if x \leq {\theta} \\ 1,\quad if x \geq {\theta} \end{cases} \]
其中\(\theta\)是手动设置的阈值,若是特征值小于阈值为0;特征值大于阈值为1。
# 数据二值化示例 from sklearn.preprocessing import Binarizer test_data = np.array([1, 2, 3, 4, 5]).reshape(-1, 1).astype(float) binarizer = Binarizer(threshold=2.5) binarizer.fit_transform(test_data)
array([[0.], [0.], [1.], [1.], [1.]])
正则化是将每一个样本缩放到单位范数,即便得每一个样本的p范数为1,对须要计算样本间类似度有很大的做用,一般有L1正则化和L2正则化两种方法。
# L1正则化示例 from sklearn.preprocessing import normalize test_data = [[1, 2, 0, 4, 5], [2, 3, 4, 5, 9]] normalize = normalize(test_data, norm='l1') normalize
array([[0.08333333, 0.16666667, 0. , 0.33333333, 0.41666667], [0.08695652, 0.13043478, 0.17391304, 0.2173913 , 0.39130435]])
# L2正则化示例 from sklearn.preprocessing import Normalizer test_data = [[1, 2, 0, 4, 5], [2, 3, 4, 5, 9]] normalize = Normalizer(norm='l2') normalize = normalize.fit_transform(test_data) normalize
array([[0.14744196, 0.29488391, 0. , 0.58976782, 0.73720978], [0.17213259, 0.25819889, 0.34426519, 0.43033148, 0.77459667]])
# 生成多项式特征图例 import matplotlib.pyplot as plt from sklearn import datasets %matplotlib inline X1, y1 = datasets.make_circles( n_samples=1000, random_state=1, factor=0.5, noise=0.1) plt.scatter(0, 0, s=23000, color='white', edgecolors='r') plt.scatter(X1[:, 0], X1[:, 1], marker='*', c=y1) plt.xlabel('$x_1$', fontsize=15) plt.ylabel('$x_2$', fontsize=15) plt.title('make_circles()', fontsize=20) plt.show()
有时候可能会遇到上图所示的数据分布状况,若是这个时候使用简单的\(x_1,x_2\)特征去拟合曲线,明显是不可能的,可是咱们可使用,可是咱们可使用\(x_1^2+x_2^2=1\)去拟合数据,可能会获得一个较好的模型,因此咱们有时候会对特征作一个多项式处理,即把特征\(x_1,x_2\)变成\(x_1^2,x_2^2\)。
test_data = [[1, 2], [3, 4], [5, 6]] test_data
[[1, 2], [3, 4], [5, 6]]
经过多项式特征,特征将会作以下变换
\[ x_1,x_2\quad\rightarrow\quad1,x_1,x_2,x_1^2,x_1x_2,x_2^2 \]
# 生成多项式特征示例 from sklearn.preprocessing import PolynomialFeatures poly = PolynomialFeatures() poly = poly.fit_transform(test_data) poly
array([[ 1., 1., 2., 1., 2., 4.], [ 1., 3., 4., 9., 12., 16.], [ 1., 5., 6., 25., 30., 36.]])