scikit-learn库,实现了一系列数据挖掘算法,提供通用编程接口、标准化的测试和调参工具,便于用户尝试不同算法对其进行充分测试和查找最优参数值。
本节目标:讲解数据挖掘通用框架的搭建方法。
本节核心概念:
估计器(Estimator):用于分类、聚类和回归分析。
转换器(Transformer):用于数据预处理和数据转换。
流水线(Pipeline):组合数据挖掘流程,便于再次使用。
scikit-learn估计器:为实现分类算法,把相关功能封装估计器。
估计器包括以下两个函数:
1、fit():训练算法,设置内部参数。接受训练集及其类别两个参数。
2、predict():参数为测试集。预测测试集类别。
scikit-learn估计器的接受和输出的数据格式均为numpy数组或类似格式。
scikit-learn提供大量估计器,包括支持向量机、随机森林、神经网络等。
近邻算法:为了对新个体进行分类,查找训练集,找到与新个体最相似的那些个体,看看这些个体大多属于哪个类别,就把新个体分到哪个类别。
优缺点:几乎可对任何数据集进行分类。但要计算数据集中每个个体之间的距离,计算量很大。
欧式距离:是真实距离。但某些特征比其他特征取值大很多,精确度就会比较差。如果很多特征值为0,也就是稀疏矩阵,结果也不准确。
曼哈顿距离:两个特征在标准坐标系中绝对轴距之和。该距离在某些情况下具有更高的稳定性,但如果数据集中某些特征值很大,这些特征会掩盖其他特征间的邻近关系。
余弦距离:更适合解决异常值和数据稀疏问题。余弦距离指的是特征向量夹角的余弦值。适用于特征向量很多的情况,但它丢弃了向量长度所包含的在某些场景下可能有用的一些信息。
电离层数据集(Ionosphere):这些数据是由高频天线收集的。这些天线的目的是侦测在电离层和高层大气中,存不存在由自由电子组成的特殊结构。如果一条数据能给出特殊结构存在的证据,就属于好的一类(g),否则为坏的一类(b)。
下载:
http://archive.ics.uci.edu/ml/datasets/Ionosphere
点击Data Folder,下载ionosphere.data和iono.names文件
保存至用户主目录的Data文件夹下
import os
home_folder = os.path.expanduser("~")
print(home_folder)
data_folder = os.path.join(home_folder, "Data", "Ionosphere")
data_filename = os.path.join(data_folder, "ionosphere.data")
print(data_filename)
import numpy as np
import csv
# 数据集大小已知,共有351行34列
X = np.zeros((351, 34), dtype='float')
y = np.zeros((351,), dtype='bool')
with open(data_filename, 'r') as input_file:
reader = csv.reader(input_file) # 创建csv阅读器对象
for i, row in enumerate(reader): # 用枚举函数来获得每行的索引号
# 获取每个个体的前34个值,将其强制转化为浮点型,保存到X中
data = [float(datum) for datum in row[:-1]]
X[i] = data
# 获取每个个体最后一个表示类别的值,把字母转化为数字
y[i] = row[-1] == 'g'
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=14)
print("There are {} samples in the training dataset".format(X_train.shape[0]))
print("There are {} samples in the testing dataset".format(X_test.shape[0]))
print("Each sample has {} features".format(X_train.shape[1]))
from sklearn.neighbors import KNeighborsClassifier
# 默认选择5个近邻作为分类依据
estimator = KNeighborsClassifier()
# 分析训练集中的数据,比较待分类的新数据点和训练集中的数据,找到新数据点的近邻
estimator.fit(X_train, y_train)
# 用测试集测试算法,评估它在测试集上的表现
y_predicted = estimator.predict(X_test)
accuracy = np.mean(y_test == y_predicted) * 100
print("The accuracy is {0:.1f}%".format(accuracy))
# 交叉检验能够解决一次性测试所带来的问题。
# 算法描述:
# (1)将整个大数据集分为几个部分(fold)
# (2)对于每一部分执行如下操作:
# a.将其中一部分作为当前测试集
# b.用剩余部分训练算法
# c.在当前测试集上测试算法
# (3)记录每次得分及平均得分。
# (4)上述过程,每条数据只能在测试集中出现一次。
from sklearn.model_selection import cross_val_score
# 默认使用Stratified K Fold方法切分数据集
# 它大体上保证切分后得到的数据集中类别分布相同
scores = cross_val_score(estimator, X, y, scoring='accuracy')
average_accuracy = np.mean(scores) * 100
print("The average accuracy is {0:.1f}%".format(average_accuracy))
# 允许用户设置参数的好处是,增强算法的泛化能力
avg_scores = []
all_scores = []
# 测试一系列n_neighbors的值
parameter_values = list(range(1, 21)) # Including 20
for n_neighbors in parameter_values:
estimator = KNeighborsClassifier(n_neighbors=n_neighbors)
scores = cross_val_score(estimator, X, y, scoring='accuracy')
avg_scores.append(np.mean(scores))
all_scores.append(scores)
# %matplotlib inline 告诉IPython notebook,要作图
from matplotlib import pyplot as plt
plt.figure(figsize=(32, 20))
# 参数为近邻数和平均正确率
plt.plot(parameter_values, avg_scores, '-o', linewidth=5, markersize=24)
流水线在预处理中的应用:
1、特征值大小实际上与该特征的分类效果没有任何关系。 2、解决方法是,对不同的特征进行规范化,使特征值落在相同的值域或从属于某几个确定的类别。 3、选择最具区分度的特征、创建新特征等都属于预处理范畴。scikit-learn的预处理工具叫作转换器
标准预处理:
from sklearn.preprocessing import MinMaxScaler #对训练集X进行预处理,最小值用0代替,最大值用1代替,其余值介于两者之间 X_transformed = MinMaxScaler().fit_transform(X)
常用规范化方法:
sklearn.preprocessing.Normalizer:使每条数据各特征值的和为1 sklearn.preprocessing.StandardScaler:使各特征值的均值为0,方差为1 sklearn.preprocessing.Binarizer:将数值型特征二值化,即大于阈值的为1,反之为0
简单总结:异常值会影响近邻算法,不同算法对值域大小的敏感度不同。
流水线:
解决了跟踪记录操作不容易、代码具有先后顺序等问题。流水线把一些步骤保存到数据挖掘的工作流中,之后就可以用它们读入数据,做各种必要的预处理,然后给出预测结果。
创建流水线:输入为一连串的数据挖掘步骤,其中最后一步必须使估计器。
from sklearn.preprocessing import MinMaxScaler
from sklearn.pipeline import Pipeline
X_broken = np.array(X)
X_broken[:, ::2] /= 10
scaling_pipeline = Pipeline([('scale', MinMaxScaler()), ('predict', KNeighborsClassifier())])
scores = cross_val_score(scaling_pipeline, X_broken, y, scoring='accuracy')
print("The pipeline scored an average accuracy for is {0:.1f}%".format(np.mean(scores) * 100))