作者: Kevin
Scikit-Learn 可以说是Python中最出名的ML library 之一,它的特点是 干净、统一以及streamlined API,并且它网上的doc非常丰富,这样的好处是当你学会了其中一种模型的syntax和基本用法,切换到其他模型就非常的简单和容易。
Basics
大致来说 Scikit-Learn estimator API 使用步骤如下:
1. import 一个你想使用的 model class
2. 设置好class 的相应 hyperparameters
3. 将数据分成 features matrix 和 target vector
4. 使用fit()
将模型 fit到已有的数据上
5. 将 model 应用到新的数据上进行预测: 在进行supervised learning时, 我们通常用predict()
method 来预测未知数据的label;而unsupervised learning,我们则通常用transform()
或者 predict()
来推测数据的特性
现实中,数据中的很多features 不一定会用数字来表示,例如人的性别可以用“男”,“女”,因此我们在做ML时,需要把类似数据转换会机器能理解的类型——数字。
假设我们手上有以下数据
data = [
{'price': 850000, 'rooms': 4, 'city': 'Downtown Toronto'},
{'price': 700000, 'rooms': 3, 'city': 'Richmond Hill'},
{'price': 650000, 'rooms': 3, 'city': 'Waterloo'},
{'price': 600000, 'rooms': 2, 'city': 'Richmond Hill'}
]
每一条都代表了一幢房子的价格,房间数和所在城市。一开始,我们可能会想说把city 这个column 进行一个简单的 numerical mapping 不就行了,例如以下
{'Downtown Toronto': 1, 'Richmond Hill': 2, 'Waterloo': 3};
但这其实并不是一个很好的approach,因为在Scikit Learn 的模型看来,这意味着 Downtown Toronto < Richmond Hill < Waterloo, 亦或者 Downtown Toronto = Waterloo - Richmond Hill, 而这显然是不合理的。
因此我们可以使用one-hot encoding 的方式来进行mapping。在Scikit Learn 中有很多方法能达到这个目的,例如sklearn.preprocessing.OneHotEncoder
和 sklearn.feature_extraction.FeatureHasher
,以及sklearnfeature_extraction.DictVectorizer
。因为上面的数据是dict的形式,所以这里我们用DictVectorizer
来做示范:
from sklearn.feature_extraction import DictVectorizer
vec = DictVectorizer(sparse=False, dtype=int)
vec.fit_transform(data)
output:
array([[ 1, 0, 0, 850000, 4],
[ 0, 1, 0, 700000, 3],
[ 0, 0, 1, 650000, 3],
[ 0, 1, 0, 600000, 2]], dtype=int64)
vec.get_feature_names()
output:
['city=Downtown Toronto',
'city=Richmond Hill',
'city=Waterloo',
'price',
'rooms']
整个数据多出了两列,这是因为原来‘city’ column 中一共有3类categorical data,因此每一个分别对应一列,而原本的‘city’ 则被删去。每一column中的1则对应原本每一row中 city 的值。
当然这种方法有一个缺点,如果你的categorical feature 有很多可能的值(例如1000个不同的城市)那dataset size 也会变的非常大,很有可能memory就会放不下。这时候我们可以发挥sparse matrix的优势——只记录非0值的位置。
vec = DictVectorizer(sparse=True, dtype=int)
vec.fit_transform(data)
output:
<4x5 sparse matrix of type 'numpy.int64'>'
with 12 stored elements in Compressed Sparse Row format>
我们经常见到在 Dataframe 中 缺失值以 NaN 来 mask,而当我们想要使用含缺失值的dataset来做ML时,第一步就需要想办法将缺失值进行填补。
from numpy import nan
X = np.array([[ nan, 0, 3 ],
[ 3, 7, 9 ],
[ 3, 5, 2 ],
[ 4, nan, 6 ],
[ 8, 8, 1 ]])
填补的手段有很多,从最简单的使用column的mean,到更复杂的matrix completion。这个需要根据情况而定。
如果我们只想使用最基础的填补方法(mean. median, most freq value,etc.),Scikit-Learn 提供了 Imputer
class:
from sklearn.preprocessing import Imputer
imp = Imputer(strategy='mean')
X2 = imp.fit_transform(X)
X2
output:
array([[ 4.5, 0. , 3. ],
[ 3. , 7. , 9. ],
[ 3. , 5. , 2. ],
[ 4. , 5. , 6. ],
[ 8. , 8. , 1. ]])
认证模型准确度的时候,千万不能犯的错误就是训练和认证都使用同一dataset。正确的方式应该是将dataset 分割成training 和 testing,我们可以使用train_test_split
来对dataset 进行 分割:
假设 X 为 dataset,y为 X 的 label
from sklearn.cross_validation import train_test_split
# 我们可以调整 train_size 来改变分割的比例,这里0.5 就代表 各50%
X1, X2, y1, y2 = train_test_split(X, y, random_state=0,
train_size=0.5)
# 将模型应用到training set 上
model.fit(X1, y1)
# 使用 testing set 对 模型准确度进行认证
y2_model = model.predict(X2)
accuracy_score(y2, y2_model)
将dataset 分割的缺点是我们因此损失了一部分可用的训练数据,那么则很有可能失去一部分数据的特性,因此还有一种approach 就是使用 cross-validation:也就是对model进行一系列的fits,每次fit 都使用不同的分割方式,具体思路如下图
假如我们想进行更多次的cross-validation 的话,就可以用到 cross_val_score
:
cross_val_score(model, X, y, cv=5)
output:
array([ 0.96666667, 0.96666667, 0.93333333, 0.93333333, 1. ])
Python Data Science Handbook by Jake VanderPlas
https://github.com/jakevdp/PythonDataScienceHandbook
个人强烈推荐的入门数据分析的一本好书