我深知尽管平时项目做得不少,但基本是面向GitHub、CSDN、StackOverflow编程,如果把我网一断,手撸快排都有些困难。
受人安利,得知机器学习100天系列教程,说是学习机器学习知识,在其前面还是有一些关于pandas与numpy的数据处理教程,可能我的数学功底吃透后续的机器学习原理还有些障碍,不过了解一些数据处理技巧对今后的学习也是大有裨益的嘛!
限于GitHub上的翻译内容有些分散,我在学习的过程中时常也会有些批注和代码注释,也没什么地方放就拿博客当笔记本好了。
今天第一天,我们要做的似乎是预测不同国家的人的购房意愿。
第1天:数据预处理(Data Preprocessing)
第一步:导入需要的库
这两个是我们每次都需要导入的库。NumPy包含数学计算函数。Pandas用于导入和管理数据集。
import numpy as np
import pandas as pd
第二步:导入数据集
数据集通常是.csv格式。CSV文件以文本形式保存表格数据。文件的每一行是一条数据记录。我们使用Pandas的read_csv方法读取本地csv文件为一个数据帧。然后,从数据帧中制作自变量和因变量的矩阵和向量。
dataset = pd.read_csv('../datasets/Data.csv')
# 不包括最后一列的所有列
X = dataset.iloc[ : , :-1].values
#取最后一列
Y = dataset.iloc[ : , 3].values
print("Step 2: Importing dataset")
print("X")
print(X)
print("Y")
print(Y)
结果如下:
X
[['France' 44.0 72000.0]
['Spain' 27.0 48000.0]
['Germany' 30.0 54000.0]
['Spain' 38.0 61000.0]
['Germany' 40.0 nan]
['France' 35.0 58000.0]
['Spain' nan 52000.0]
['France' 48.0 79000.0]
['Germany' 50.0 83000.0]
['France' 37.0 67000.0]]
Y
['No' 'Yes' 'No' 'No' 'Yes' 'Yes' 'No' 'Yes' 'No' 'Yes']
批注:第一时间看见[ : , :-1]和[ : , 3]还是有点慌的,尽管这是pandas中的方法,但Python中也有长得类似的切片索引,来回顾一下。(Python的基础知识不是很牢固)
Python切片索引
[x:y:z]是切片索引的意思,x是左端,y是右端,z是步长,在[x,y)区间从左到右每隔z取值,默认z为1可以省略z参数,省略x参数则是从头取,省略y则是取到尾。
步长的负号就是反向,从右到左取值。例如对
a=“python”
b=a[::-1]
print (b)
'nohtyp'
常见的用法有:对a = [0,1,2,3,4,5,6,7,8,9]
a[::-1]相当于倒序列表a;a[i:j]相当于将a中第i个元素取到j-1各元素形成一个新的列表;
还有一种类型是类似[:-1],代表从位置0到位置-1,-1是指从最后算起的第二个元素。
Pandas中loc和iloc函数
上面代码中其实并非切片索引,而是pandas中的iloc函数,用于提取行数据。pandas中还有loc函数,一并介绍。参考:Pandas中loc和iloc函数用法详解(源码+实例)
已知data为:
In[1]: data
Out[1]:
A B C D
a 0 1 2 3
b 4 5 6 7
c 8 9 10 11
d 12 13 14 15
#取索引为'a'的行
In[2]: data.loc['a']
Out[2]:
A 0
B 1
C 2
D 3
#取第一行数据,索引为'a'的行就是第一行,所以结果相同
In[3]: data.iloc[0]
Out[3]:
A 0
B 1
C 2
D 3
In[4]:data.loc[:,['A']] #取'A'列所有行,多取几列格式为 data.loc[:,['A','B']]
Out[4]:
A
a 0
b 4
c 8
d 12
In[5]:data.iloc[:,[0]] #取第0列所有行,多取几列格式为 data.iloc[:,[0,1]]
Out[5]:
A
a 0
b 4
c 8
d 12
In[6]:data.loc[['a','b'],['A','B']] #提取index为'a','b',列名为'A','B'中的数据
Out[6]:
A B
a 0 1
b 4 5
In[7]:data.iloc[[0,1],[0,1]] #提取第0、1行,第0、1列中的数据
Out[7]:
A B
a 0 1
b 4 5
In[8]:data.loc[:,:] #取A,B,C,D列的所有行
Out[8]:
A B C D
a 0 1 2 3
b 4 5 6 7
c 8 9 10 11
d 12 13 14 15
In[9]:data.iloc[:,:] #取第0,1,2,3列的所有行
Out[9]:
A B C D
a 0 1 2 3
b 4 5 6 7
c 8 9 10 11
d 12 13 14 15
In[10]: data.loc[data['A']==0] #提取data数据(筛选条件: A列中数字为0所在的行数据)
Out[10]:
A B C D
a 0 1 2 3
总结:iloc是一种完全基于位置的索引,loc是基于label的索引,什么意思呢?loc只看标签,就是上述的abcd与ABCD,iloc只看索引号,就是上述的0~3。
对[x,y],x的形式类似a:b,对iloc来说a,b只能是数字,表示取从a到b行,缺省代表从头取到尾。对loc来说a,b只能是标签,尽管标签有时可能也是数字形式,如
df
Out[4]:
a b c d
0 0 1 2 3
1 4 5 6 7
2 8 9 10 11
3 12 13 14 15
df.loc[0:3,'a':'c']
Out[9]:
a b c
0 1 2
4 5 6
8 9 10
12 13 14
上面的0:3实际上并不是数字,而是行的label。
第三步:处理丢失数据
我们得到的数据很少是完整的。数据可能因为各种原因丢失,为了不降低机器学习模型的性能,需要处理数据。我们可以用整列的平均值或中间值替换丢失的数据。我们用sklearn.preprocessing库中的Imputer类完成这项任务。
批注:Anaconda的默认环境带了许多科学计算包,所以这套实验最好在Anaconda环境下进行。
from sklearn.preprocessing import Imputer
# axis=0表示按列进行
imputer = Imputer(missing_values = "NaN", strategy = "mean", axis = 0)
imputer = imputer.fit(X[ : , 1:3])
X[ : , 1:3] = imputer.transform(X[ : , 1:3])
print("---------------------")
print("Step 3: Handling the missing data")
print("step2")
print("X")
print(X)
Imputer函数主要用来填补缺失值,参数为sklearn.preprocessing.Imputer(missing_values=’NaN’, strategy=’mean’, axis=0, verbose=0, copy=True)
主要参数说明:
missing_values:缺失值,可以为整数或NaN(缺失值numpy.nan用字符串‘NaN’表示),默认为NaN
strategy:替换策略,字符串,默认用均值‘mean’替换
①若为mean时,用特征列的均值替换
②若为median时,用特征列的中位数替换
③若为most_frequent时,用特征列的众数替换
axis:指定轴数,默认axis=0代表列,axis=1代表行
copy:设置为True代表不在原数据集上修改,设置为False时,就地修改,存在如下情况时,即使设置为False时,也不会就地修改
①X不是浮点值数组
②X是稀疏且missing_values=0
③axis=0且X为CRS矩阵
④axis=1且X为CSC矩阵
statistics_属性:axis设置为0时,每个特征的填充值数组,axis=1时,报没有该属性错误statistics_属性:axis设置为0时,每个特征的填充值数组,axis=1时,报没有该属性错误
结果:
---------------------
Step 3: Handling the missing data
step2
X
[['France' 44.0 72000.0]
['Spain' 27.0 48000.0]
['Germany' 30.0 54000.0]
['Spain' 38.0 61000.0]
['Germany' 40.0 63777.77777777778]
['France' 35.0 58000.0]
['Spain' 38.77777777777778 52000.0]
['France' 48.0 79000.0]
['Germany' 50.0 83000.0]
['France' 37.0 67000.0]]
第四步:解析分类数据
分类数据指的是含有标签值而不是数字值的变量。取值范围通常是固定的。例如"Yes"和"No"不能用于模型的数学计算,所以需要解析成数字。为实现这一功能,我们从sklearn.preprocessing库导入LabelEncoder类。
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
labelencoder_X = LabelEncoder() #实例化
X[ : , 0] = labelencoder_X.fit_transform(X[ : , 0])
#Creating a dummy variable
onehotencoder = OneHotEncoder(categorical_features = [0])
X = onehotencoder.fit_transform(X).toarray()
labelencoder_Y = LabelEncoder()
Y = labelencoder_Y.fit_transform(Y)
print("---------------------")
print("Step 4: Encoding categorical data")
print("X")
print(X)
print("Y")
print(Y)
结果:
---------------------
Step 4: Encoding categorical data
X
[[1.00000000e+00 0.00000000e+00 0.00000000e+00 4.40000000e+01
7.20000000e+04]
[0.00000000e+00 0.00000000e+00 1.00000000e+00 2.70000000e+01
4.80000000e+04]
[0.00000000e+00 1.00000000e+00 0.00000000e+00 3.00000000e+01
5.40000000e+04]
[0.00000000e+00 0.00000000e+00 1.00000000e+00 3.80000000e+01
6.10000000e+04]
[0.00000000e+00 1.00000000e+00 0.00000000e+00 4.00000000e+01
6.37777778e+04]
[1.00000000e+00 0.00000000e+00 0.00000000e+00 3.50000000e+01
5.80000000e+04]
[0.00000000e+00 0.00000000e+00 1.00000000e+00 3.87777778e+01
5.20000000e+04]
[1.00000000e+00 0.00000000e+00 0.00000000e+00 4.80000000e+01
7.90000000e+04]
[0.00000000e+00 1.00000000e+00 0.00000000e+00 5.00000000e+01
8.30000000e+04]
[1.00000000e+00 0.00000000e+00 0.00000000e+00 3.70000000e+01
6.70000000e+04]]
Y
[0 1 0 0 1 1 0 1 0 1]
这一步相当于起到数据规范化的作用,毕竟无意义的字符对计算没有用处。
第五步:拆分数据集为测试集合和训练集合
把数据集拆分成两个:一个是用来训练模型的训练集合,另一个是用来验证模型的测试集合。两者比例一般是80:20。我们导入sklearn.model_selection库中的train_test_split()方法。
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split( X , Y , test_size = 0.2, random_state = 0)
print("---------------------")
print("Step 5: Splitting the datasets into training sets and Test sets")
print("X_train")
print(X_train)
print("X_test")
print(X_test)
print("Y_train")
print(Y_train)
print("Y_test")
print(Y_test)
---------------------
Step 5: Splitting the datasets into training sets and Test sets
X_train
[[ 0.00000000e+00 1.00000000e+00 0.00000000e+00 4.00000000e+01
6.37777778e+04]
[ 1.00000000e+00 0.00000000e+00 0.00000000e+00 3.70000000e+01
6.70000000e+04]
[ 0.00000000e+00 0.00000000e+00 1.00000000e+00 2.70000000e+01
4.80000000e+04]
[ 0.00000000e+00 0.00000000e+00 1.00000000e+00 3.87777778e+01
5.20000000e+04]
[ 1.00000000e+00 0.00000000e+00 0.00000000e+00 4.80000000e+01
7.90000000e+04]
[ 0.00000000e+00 0.00000000e+00 1.00000000e+00 3.80000000e+01
6.10000000e+04]
[ 1.00000000e+00 0.00000000e+00 0.00000000e+00 4.40000000e+01
7.20000000e+04]
[ 1.00000000e+00 0.00000000e+00 0.00000000e+00 3.50000000e+01
5.80000000e+04]]
X_test
[[ 0.00000000e+00 1.00000000e+00 0.00000000e+00 3.00000000e+01
5.40000000e+04]
[ 0.00000000e+00 1.00000000e+00 0.00000000e+00 5.00000000e+01
8.30000000e+04]]
Y_train
[1 1 1 0 1 0 0 1]
Y_test
[0 0]
第六步:特征量化
大部分模型算法使用两点间的欧氏距离表示,但此特征在幅度、单位和范围姿态问题上变化很大。在距离计算中,高幅度的特征比低幅度特征权重更大。可用特征标准化或Z值归一化解决。导入sklearn.preprocessing库的StandardScalar类。
from sklearn.preprocessing import StandardScaler
sc_X = StandardScaler()
X_train = sc_X.fit_transform(X_train)
X_test = sc_X.transform(X_test)
print("---------------------")
print("Step 6: Feature Scaling")
print("X_train")
print(X_train)
print("X_test")
print(X_test)
---------------------
Step 6: Feature Scaling
X_train
[[-1. 2.64575131 -0.77459667 0.26306757 0.12381479]
[ 1. -0.37796447 -0.77459667 -0.25350148 0.46175632]
[-1. -0.37796447 1.29099445 -1.97539832 -1.53093341]
[-1. -0.37796447 1.29099445 0.05261351 -1.11141978]
[ 1. -0.37796447 -0.77459667 1.64058505 1.7202972 ]
[-1. -0.37796447 1.29099445 -0.0813118 -0.16751412]
[ 1. -0.37796447 -0.77459667 0.95182631 0.98614835]
[ 1. -0.37796447 -0.77459667 -0.59788085 -0.48214934]]
X_test
[[ 0. 0. 0. -1. -1.]
[ 0. 0. 0. 1. 1.]]
数据预处理的作用是使得后续数据训练过程更快,梯度下降过程更加笔直,收敛更快性能因此也得到提升。因此,在下一步训练数据之前数据预处理是十分有必要的。