机器学习-数据预处理

数据预处理是机器学习中很基本也是很重要的一步,数据处理是否得当对训练和预测结果影响非常大。

在工程实践中,我们得到的数据会存在有缺失值、重复值等,在使用之前需要进行数据预处理。数据预处理没有标准的流程,通常针对不同的任务和数据集属性的不同而不同。数据预处理的常用流程为:处理缺失值、属性编码、数据标准化正则化、特征选择、主成分分析。

首先,我们开始进行缺失值的处理,一般在读取数据某些特征时会有缺失值,如果缺失值过多基本上可以直接去除掉这一列,在缺失值不多的情况下我们可以用一些方法处理,比如插入0、平均值、中位数值等等,根据实际情况而定。

# 第一天数据预处理
from sklearn.preprocessing import Imputer,minmax_scale,LabelEncoder,OneHotEncoder
import pandas as pd

# 数据读取
data = pd.read_csv('1day/dataSource/Data.csv', header=0)
print(data)

# 缺失值处理
#方法一
# imputer = Imputer(missing_values='NaN', strategy='mean', axis=0)
# imputer = imputer.fit(data.iloc[:,1:3])
# data.iloc[:,1:3] = imputer.transform(data.iloc[:,1:3])
# print(data)
#方法二
data['Age'].fillna(data['Age'].mean(), inplace=True)
data['Salary'].fillna(data['Salary'].mean(), inplace=True)
print(data)
   Country   Age   Salary Purchased
0   France  44.0  72000.0        No
1    Spain  27.0  48000.0       Yes
2  Germany  30.0  54000.0        No
3    Spain  38.0  61000.0        No
4  Germany  40.0      NaN       Yes
5   France  35.0  58000.0       Yes
6    Spain   NaN  52000.0        No
7   France  48.0  79000.0       Yes
8  Germany  50.0  83000.0        No
9   France  37.0  67000.0       Yes
   Country        Age        Salary Purchased
0   France  44.000000  72000.000000        No
1    Spain  27.000000  48000.000000       Yes
2  Germany  30.000000  54000.000000        No
3    Spain  38.000000  61000.000000        No
4  Germany  40.000000  63777.777778       Yes
5   France  35.000000  58000.000000       Yes
6    Spain  38.777778  52000.000000        No
7   France  48.000000  79000.000000       Yes
8  Germany  50.000000  83000.000000        No
9   France  37.000000  67000.000000       Yes

这里列出了两种插入缺失值的方法,都是用的插入特征列的均值,还可以插入中位数、最大值、最小值等等都可以。

现在我们发现Country这列和Purchased不是数字类型不能直接用于训练计算,这里要进行处理成能够训练的格式,为实现这一功能,我们从sklearn.preprocessing库导入LabelEncoder类。

# 解析分类数据
labelEncoder = LabelEncoder()
data['Purchased'] = labelEncoder.fit_transform(data['Purchased'])
print(data)
Country        Age        Salary  Purchased
0   France  44.000000  72000.000000          0
1    Spain  27.000000  48000.000000          1
2  Germany  30.000000  54000.000000          0
3    Spain  38.000000  61000.000000          0
4  Germany  40.000000  63777.777778          1
5   France  35.000000  58000.000000          1
6    Spain  38.777778  52000.000000          0
7   France  48.000000  79000.000000          1
8  Germany  50.000000  83000.000000          0
9   France  37.000000  67000.000000          1

现在Purchased已经ok了,接下来再把Country列的每个值当做一个特征列,用0,1表示是否是该值,我们用pandas中的get_dummies方法,该方法会把非数字的枚举列变成进行one-hot编码,结果如下

# 解析分类数据
labelEncoder = LabelEncoder()
data['Purchased'] = labelEncoder.fit_transform(data['Purchased'])
data = pd.get_dummies(data)
print(data)
Age        Salary  Purchased  Country_France  Country_Germany  Country_Spain
0  44.000000  72000.000000          0               1                0              0
1  27.000000  48000.000000          1               0                0              1
2  30.000000  54000.000000          0               0                1              0
3  38.000000  61000.000000          0               0                0              1
4  40.000000  63777.777778          1               0                1              0
5  35.000000  58000.000000          1               1                0              0
6  38.777778  52000.000000          0               0                0              1
7  48.000000  79000.000000          1               1                0              0
8  50.000000  83000.000000          0               0                1              0
9  37.000000  67000.000000          1               1                0              0

到这里就已经具备了训练数据的格式了,可以直接把数据和标签列放入训练模型里,但是在这里还要继续进行处理。

我们发现Age和Salary列的数字数量级差距很大,而且这两列的单位其实也是不一样的,对于数量级大的训练得到的参数权重会更大,这样会导致训练的结果仅仅与数量级越大的特征越密切,而且在训练过程中收敛的速度会比较慢,因为梯度下降可能会走不少弯路。

所以在这里我们要进行数据的归一化处理,让每个特征列的数据范围基本一致。

这里我们用到minmax_scale当然还有其它的归一化的方法,比如scale,standardscale,上代码

# 归一化处理
data_y = data['Purchased']
data_x = data.drop(['Purchased'], axis=1)
data_x = minmax_scale(data_x)
print(data_x)
[[0.73913043 0.68571429 1.         0.         0.        ]
 [0.         0.         0.         0.         1.        ]
 [0.13043478 0.17142857 0.         1.         0.        ]
 [0.47826087 0.37142857 0.         0.         1.        ]
 [0.56521739 0.45079365 0.         1.         0.        ]
 [0.34782609 0.28571429 1.         0.         0.        ]
 [0.51207729 0.11428571 0.         0.         1.        ]
 [0.91304348 0.88571429 1.         0.         0.        ]
 [1.         1.         0.         1.         0.        ]
 [0.43478261 0.54285714 1.         0.         0.        ]]

这个数据就比较标准了,最后在训练前的一步就是给数据拆分成训练集和测试集了,我们还是用sklearn里面的方法train_test_split

from sklearn.model_selection import train_test_split
#...
#中途省略上面有代码
#...
# 拆分数据
train_x, test_x, train_y, test_y = train_test_split(data_x, data_y, test_size=0.3)
print(train_x)
print(train_y)
print(test_x)
print(test_y)
[[0.56521739 0.45079365 0.         1.         0.        ]
 [0.73913043 0.68571429 1.         0.         0.        ]
 [0.51207729 0.11428571 0.         0.         1.        ]
 [1.         1.         0.         1.         0.        ]
 [0.34782609 0.28571429 1.         0.         0.        ]
 [0.43478261 0.54285714 1.         0.         0.        ]
 [0.13043478 0.17142857 0.         1.         0.        ]]
4    1
0    0
6    0
8    0
5    1
9    1
2    0
Name: Purchased, dtype: int64
[[0.91304348 0.88571429 1.         0.         0.        ]
 [0.47826087 0.37142857 0.         0.         1.        ]
 [0.         0.         0.         0.         1.        ]]
7    1
3    0
1    1
Name: Purchased, dtype: int64