An introduction to machine learning with scikit-learn
因为有个还在读书的朋友最近拜托我帮看个作业,他不会写, 巧了, 我也不会, 但是毕竟是老基友了, 忙还是得帮的, 那就直接跟着官网的教程过一遍吧, 做个笔记一遍以后回查。
Machine learning: the problem setting
-
就是解释了机器学习就是从抽样的数据中尝试了解不知道到的数据的性质的这个个事情,这些抽样数据呢可能有很多的维度multi-dimensional, 我们说它有多个
属性或者特征(attributes or features) -
机器学习可以分成2类 监督学习和非监督学习, 监督学习里面 有分类任务和回归任务, 分类任务情况下抽样的数据一半是属于一个或者多个类的,要从标记好的数据中了解怎样去预测没标记的数据是属于哪个类别的
-
回归任务就是期望输出连续的一个数(非离散), 一半来说就是预测一个数字比如预测房价
-
非监督学习一个班就是就没有标注的数字去学习数据的分布情况,很多情况下是去估计哪些数据是相同一组的哪些数据是不同组的, 这又叫做类聚(clustering), 或者确定数据分布的特征,这又叫密度估计(density estimation)
-
一般来说数据分为训练集用来训练模型 测试集用来测试模型的性能
Loading an example dataset
- sklearn 里面提供了一些标准数据集让人玩 比如 iris, diabetes, digits 数据集.
from sklearn import datasets
import numpy as np
# 加载现成的数据集
iris = datasets.load_iris()
print(iris)
digits = datasets.load_digits()
print(digits)
# 查看抽样数据的属性
print(digits.data)
# 查看数据对应的Ground Truth真实值
print(digits.target)
# 如果数据属性是一张2D向量那么这样查看
print(digits.images)
Learning and predicting
- 按照digits数据集的例子, 那就是给我们一张写着数字的图片让我们预测上面画的是0-9数字中的哪一个, 就是说一共有10类, 给图片分个类, 那么就用有监督的分类器 比如支持向量机
- 先让分类器去学习训练集上的数据 fit(X, y), 然后再让它去预测我们要预测的图片数据 predict(T)
- 下面就是一个svm做分类器的例子 sklearn.svm.SVC, 就是 support vector classification.
from sklearn import svm
# 创建svc这么个分类器模型,输入参数 gamma, C
# 下面的参数可以通过 交叉验证cross validation 和 网格搜索grid search 去查找最好的超参值
# grid_search: https://scikit-learn.org/stable/modules/grid_search.html#grid-search
# cross_validation: https://scikit-learn.org/stable/modules/cross_validation.html#cross-validation
clf = svm.SVC(gamma=0.001, C=100.)
# 这里选择把整个数据集除了最后一个样本作为训练集, 最后一个样本做测试集
train_data = digits.data[:-1]
train_target = digits.target[:-1]
test_data = digits.data[-1:] # 虽然只有一个样本,还是要有冒号,为了保持和训练数据维度一致
test_target = digits.target[-1:]
# 分类器训练
clf.fit(train_data, train_target)
>>> SVC(C=100.0, gamma=0.001) # 分类器训练好了
# 测试(预测)
pred = clf.predict(test.data)
pred
>>> array[8]
# 对比预测结果是否和真实值一致
print(pred == test_target[0])
>>> True
模型保存和复用 Model persistence
- 用python自带的 pickle 包来保存模型
from sklearn import svm
from sklearn import datasets
clf = svm.SVC()
X, y = datasets.load_iris(return_X_y=True) # 自己把训练集的data 和 target 分两个来输出
clf.fit(X,y)
import pickle
# pickle 会把clf对象序列化成二进制乱码字符串,这样方便保存
s= pickle.dumps(clf)
print(s, type(s))
>>> b'\x80\x03csklearn.svm._classes\nSVC\nq\x00)\x81q\x01}q\x02(X\x17\x00\x00\x00decision_function_shapeq\x03X\x03\x00\x00 ...
# pickle 读取序列化后的二进制乱码字符串并还原成一个新的一样的clf对象
clf2 = pickle.loads(s)
print(clf2, type(clf2))
>>> SVC(C=1.0, break_ties=False, cache_size=200, class_weight=None, coef0=0.0, decision_function_shape='ovr', degree=3, gamma='scale', kernel='rbf', max_iter=-1, probability=False, random_state=None, shrinking=True,tol=0.001, verbose=False) <class 'sklearn.svm._classes.SVC'>
# 还原后预测结果还是对的
print(clf2.predict(X[:1]))
>>>array[0]
print(y[:1])
>>>[0]
# 可以把二进制字符串直接保存到txt文件中,下次通过读取txt文件来使用模型
with open('./svc.txt', 'wb') as f: #创建文件对象
pickle.dumps(clf, f) # 写入文件对象
with open('./svc.txt', 'rb') as f: # 创建文件对象
clf3 = pickle.loads(f) # 读取文件数据并生成分类器对象
print(clf3, type(clf3))
- 也可以用 joblib 包来保存模型, 但是这个包只能直接保存到硬盘上的文件,并不能保存成字符串留在内存里, 所以其实不吃内存适合大型数据的保存
from joblib import dump, load
dump(clf, 'filename.joblib')
clf = load('filename.joblib')
常规套路(Conventions)
类型转换 Type casting
- 除非特别声明, 不然输入数据会自动转成 float64
import numpy as np
from sklearn import random_projection
rng = np.random.RandomState(0)
X = rng.rand(10, 2000)
X = np.array(X, dtype='float32')
X.dtype
>>>dtype('float32')
transformer = random_projection.GaussianRandomProjection()
X_new = transformer.fit_transform(X)
X_new.dtype
>>>dtype('float64')
Refitting and updating parameters
就是多次训练同一个模型, 通过 set_params 来调整超参
>>> import numpy as np
>>> from sklearn.datasets import load_iris
>>> from sklearn.svm import SVC
>>> X, y = load_iris(return_X_y=True)
>>> clf = SVC()
>>> clf.set_params(kernel='linear').fit(X, y)
SVC(kernel='linear')
>>> clf.predict(X[:5])
array([0, 0, 0, 0, 0])
>>> clf.set_params(kernel='rbf').fit(X, y)
SVC()
>>> clf.predict(X[:5])
array([0, 0, 0, 0, 0])
Multiclass vs. multilabel fitting
多分类就可以用多分类器
>>> from sklearn.svm import SVC
>>> from sklearn.multiclass import OneVsRestClassifier
>>> from sklearn.preprocessing import LabelBinarizer
>>> X = [[1, 2], [2, 4], [4, 5], [3, 2], [3, 1]]
>>> y = [0, 0, 1, 1, 2]
>>> classif = OneVsRestClassifier(estimator=SVC(random_state=0))
>>> classif.fit(X, y).predict(X)
array([0, 0, 1, 1, 2])
虽然是多分类, 但是这里的target label 是1D array。我们也可以调成2Darray给它onehot编码来表达, 要用到 LabelBinarizer 单编码类中的fit_tranform()函数
>>> y = LabelBinarizer().fit_transform(y)
>>> classif.fit(X, y).predict(X)
array([[1, 0, 0],
[1, 0, 0],
[0, 1, 0],
[0, 0, 0],
[0, 0, 0]])
每一行第几个是1就代表第几类。
当然也可以用二进制编码:那就要用到 MultiLabelBinarizer 多label编码类中的 fit_transform函数
>>> from sklearn.preprocessing import MultiLabelBinarizer
>>> y = [[0, 1], [0, 2], [1, 3], [0, 2, 3], [2, 4]]
>>> y = MultiLabelBinarizer().fit_transform(y)
>>> classif.fit(X, y).predict(X)
array([[1, 1, 0, 0, 0],
[1, 0, 1, 0, 0],
[0, 1, 0, 1, 0],
[1, 0, 1, 0, 0],
[1, 0, 1, 0, 0]])