一、 加载sklearn中的数据集datasets
from sklearn import datasets
iris = datasets.load_iris() # 鸢尾花卉数据
digits = datasets.load_digits() # 手写数字8x8像素信息数据
- 查看数据的信息
print iris.data[:4] # 查看数据的特征信息
print iris.data.shape # 查看数据的特征信息维度
print iris.target_names # 查看标签对应的文本
print iris.target[:4] # 查看数据的标签 setosa:0 ... [[ 5.1 3.5 1.4 0.2]
[ 4.9 3. 1.4 0.2]
[ 4.7 3.2 1.3 0.2]
[ 4.6 3.1 1.5 0.2]]
(150L, 4L)
['setosa' 'versicolor' 'virginica']
[0 0 0 0]
print digits.data[0]
print digits.data.shape
print digits.target[0]
print digits.data[0].reshape((8,8)) # 重塑成8x8的像素数组 [ 0. 0. 5. 13. 9. 1. 0. 0. 0. 0. 13. 15. 10. 15. 5.
0. 0. 3. 15. 2. 0. 11. 8. 0. 0. 4. 12. 0. 0. 8.
8. 0. 0. 5. 8. 0. 0. 9. 8. 0. 0. 4. 11. 0. 1.
12. 7. 0. 0. 2. 14. 5. 10. 12. 0. 0. 0. 0. 6. 13.
10. 0. 0. 0.]
(1797L, 64L)
0
[[ 0. 0. 5. 13. 9. 1. 0. 0.]
[ 0. 0. 13. 15. 10. 15. 5. 0.]
[ 0. 3. 15. 2. 0. 11. 8. 0.]
[ 0. 4. 12. 0. 0. 8. 8. 0.]
[ 0. 5. 8. 0. 0. 9. 8. 0.]
[ 0. 4. 11. 0. 1. 12. 7. 0.]
[ 0. 2. 14. 5. 10. 12. 0. 0.]
[ 0. 0. 6. 13. 10. 0. 0. 0.]]
二、训练集和分割集的分割
from sklearn.model_selection import train_test_split
X = digits.data # 特征矩阵
y = digits.target # 标签向量
# 随机分割训练集和测试集:
# test_size:设置测试集的比例。random_state:可理解为种子,保证随机唯一
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1/3., random_state=8) print X_train.shape
print X_test.shape (1198L, 64L)
(599L, 64L)
三、特征数值的归一化
当特征的数值范围差距较大时,需要对特征的数值进行归一化,防止某些属性的权重过大。(有时不需特征归一化)
from sklearn import preprocessing
import numpy as np
x1 = np.random.randint(0,10,1000).reshape((1000,1))
x2 = np.random.randint(0,100,1000).reshape((1000,1))
x3 = np.random.randint(0,10000,1000).reshape((1000,1))
X = np.concatenate([x1,x2,x3],axis=1)
print X[:4] [[ 0 78 3423]
[ 7 35 963]
[ 7 63 9945]
[ 3 60 6516]]
# 特征数值归一化
print preprocessing.scale(X)[:4] [[-1.59232736 0.96948157 -0.56718281]
[ 0.83236081 -0.55950092 -1.40672255]
[ 0.83236081 0.43611559 1.65862133]
[-0.55317529 0.32944239 0.48838484]
- 验证归一化的重要性
# 生成分类数据进行验证
from sklearn import datasets
import matplotlib.pyplot as plt
%matplotlib inline
# 生成分类数据:
# n_sample:样本个数、n_features:类别标签种类数
X, y = datasets.make_classification(n_samples=300, n_features=2, n_redundant=0, n_informative=2,
random_state=25, n_clusters_per_class=1, scale=100)
plt.scatter(X[:,0], X[:,1], c=y)
plt.show()

- 使用svm模型(未特征归一化时)
# 使用svm模型(未特征归一化时)
from sklearn import svm
# X = preprocessing.scale(X)
# 分割训练集合测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1/3., random_state=7)
svm_classifier = svm.SVC()
# 训练模型
svm_classifier.fit(X_train, y_train)
# 在测试集上对模型打分
svm_classifier.score(X_test, y_test) 0.52000000000000002
- 使用svm模型(特征归一化时)
# 使用svm模型(特征归一化时)
from sklearn import svm
X = preprocessing.scale(X)
# 分割训练集合测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1/3., random_state=7)
svm_classifier = svm.SVC()
svm_classifier.fit(X_train, y_train)
svm_classifier.score(X_test, y_test) 0.97999999999999998
四、模型的训练、预测与保存
- 以线性回归模型为例
iris = datasets.load_iris() # 鸢尾花卉数据
X = iris.data
y = iris.target
print X[:3]
print y[:3] [[ 5.1 3.5 1.4 0.2]
[ 4.9 3. 1.4 0.2]
[ 4.7 3.2 1.3 0.2]]
[0 0 0]
# 选择线性回归模型
from sklearn.linear_model import LinearRegression
# 新建一个模型(参数默认)
iris_model = LinearRegression()
# 分割训练集、测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1/3., random_state=7)
# 训练该模型
iris_model.fit(X_train,y_train) # 返回模型参数列表
iris_model.get_params() {'copy_X': True, 'fit_intercept': True, 'n_jobs': 1, 'normalize': False}
# 模型在训练集上的评分
iris_model.score(X_train, y_train) 0.94505820275667418
# 模型在测试集上的评分
iris_model.score(X_test, y_test) 0.89618390663189063
# 使用模型进行预测
y_pred = iris_model.predict(X_test)
print '预测标签:', y_pred[:3]
print '真实标签:', y_test[:3] 预测标签: [ 1.66080893 1.39414184 -0.02450645]
真实标签: [2 1 0]
# 使用pickle保存模型
import cPickle as pickle
with open('LR_model.pkl', 'w') as f:
pickle.dump(iris_model, f) # 重新加载模型进行预测
with open('LR_model.pkl', 'r') as f:
model = pickle.load(f)
# 使用模型进行预测
model.predict(X_test)[:3] array([ 1.66080893, 1.39414184, -0.02450645])
五、交叉验证
在分割训练集和测试集后,测试集一般用于对最后选择的模型进行评分。而在选择模型的超参数的过程中,为验证/评价模型的好坏,需要在训练集中取出一定比例的样本作为验证集来评价某个模型的好坏,训练集中的其他样本用来训练模型。
为消除所选出来的验证集中的样本的特殊性,则需要将训练集中的每一份样本作为验证集,其他样本作为训练集来训练模型。若将训练集中的样本分为N分,最后会得到N个对该模型的评分,对这些评分取均值,即得到了交叉验证的评分。
交叉验证一般用来调整模型的超参数。
-
sklearn中的交叉验证
cross_val_score函数用于交叉验证,返回各个验证集的评价得分。
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
%matplotlib inline
iris = datasets.load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1/3., random_state=5)
- 以KNN模型为例
# 使用KNN模型进行预测(K为超参数)
from sklearn.neighbors import KNeighborsClassifier
# 超参数K的范围
k_range = range(1,31)
# 交叉验证的评分集合
cv_scores = []
for k in k_range:
knn = KNeighborsClassifier(k) # 构造模型
# 将训练集均分为10份
#cv: 交叉验证迭代器
scores = cross_val_score(knn, X_train, y_train, cv=10, scoring='accuracy') # 分类问题使用
#scores = cross_val_score(knn, X_train, y_train, cv=10, scoring='neg_mean_squared_error') # 回归问题使用
cv_scores.append(scores.mean()) #
# print cv_scores
# 可视化各个k值模型的交叉验证的平均分
plt.plot(k_range,cv_scores)
plt.xlabel('k')
plt.ylabel('Accuracy')
plt.show()

# 选择最优的超参数K
best_knn = KNeighborsClassifier(15)
best_knn.fit(X_train, y_train)
print best_knn.score(X_test, y_test)
print best_knn.predict(X_test) 1.0
[1 2 2 0 2 1 0 1 0 1 1 2 2 2 0 0 2 2 0 0 1 2 0 1 1 2 1 1 1 2 0 1 1 0 1 0 0
2 0 2 2 1 0 0 1 2 1 2 2 0]
六、过拟合与欠拟合
过拟合:模型对于训练集数据拟合程度过当,以致太适合训练集数据而无法适应一般情况。即训练出来的模型在训练集上表现很好,在验证集/测试集上表现并不好。
欠拟合:模型在训练集/测试集上都表现得不是很好。
# 加载数据
from sklearn.model_selection import learning_curve
from sklearn.svm import SVC
import numpy as np
digits = datasets.load_digits()
X = digits.data
y = digits.target
- 欠拟合情况
# 绘制学习曲线(学习曲线:在不同训练数据量下对训练出来的模型进行评分)
# gamma = 0.001
train_sizes, train_scores, val_scores = learning_curve(
SVC(gamma=0.001), X, y, cv=10, scoring='accuracy',
train_sizes=[0.1, 0.25, 0.5, 0.75, 1]
)
# train_sizes: 每次模型训练的数量
# train_scores: 每次模型在训练集上的评分
# val_scores:每次模型在验证集上的交叉验证评分
# 求不同训练数据量下的评分的均值
train_scores_mean = np.mean(train_scores, axis=1) # 行均值
val_scores_mean = np.mean(val_scores, axis=1) # 绘制学习曲线
plt.plot(train_sizes, train_scores_mean, 'o-', color='r', label='training')
plt.plot(train_sizes, val_scores_mean, '*-', color='g', label='cross validation')
plt.xlabel('training sample size')
plt.ylabel('accuracy')
plt.legend(loc='best')
plt.show()

如图所示:当训练数据量较少时,模型在交叉验证中的得分较低,可看作一种欠拟合现象;随着训练数据量的增多,交叉验证的平均分也随之增加
- 过拟合
train_sizes, train_scores, val_scores = learning_curve(
SVC(gamma=0.1), X, y, cv=10, scoring='accuracy',
train_sizes=[0.1, 0.25, 0.5, 0.75, 1]
)
# 求不同训练数据量下的评分的均值
train_scores_mean = np.mean(train_scores, axis=1) # 行均值
val_scores_mean = np.mean(val_scores, axis=1)
# 绘制学习曲线
plt.plot(train_sizes, train_scores_mean, 'o-', color='r', label='training')
plt.plot(train_sizes, val_scores_mean, '*-', color='g', label='cross validation')
plt.xlabel('training sample size')
plt.ylabel('accuracy')
plt.legend(loc='best')
plt.show()

如图所示:当训练数据量较少时,模型在交叉验证中的得分较低;然而,随着训练数据量的增多,交叉验证的平均分并没增多。因此出现过拟合现象。
- 通过验证曲线来观察过拟合
# 绘制验证曲线(验证曲线:在不同超参数下对模型的评分)
from sklearn.model_selection import validation_curve
# 设置SVC模型的超参数gamma的取值范围
gamma_range = np.arange(1, 10) / 3000.
train_scores, val_scores = validation_curve(
SVC(), X, y, param_name='gamma', param_range=gamma_range,
cv=5, scoring='accuracy')
# train_scores: 每次模型在训练集上的评分
# val_scores:每次模型在验证集上的交叉验证评分
# 求每次的平均值
train_scores_mean = np.mean(train_scores, axis=1)
val_scores_mean = np.mean(val_scores, axis=1)
# 绘制验证曲线
plt.plot(gamma_range, train_scores_mean, 'o-', color='r', label='training')
plt.plot(gamma_range, val_scores_mean, '*-', color='g', label='cross validation')
plt.xlabel('gamma')
plt.ylabel('accuracy')
plt.legend(loc='best')
plt.show()

如图所示:当gamma>0.0015时,出现过拟合现象,对应模型在训练集上的评分不断增大,而在验证集上的评分反而在减小