用scikit-learn估计值分类主要是为数据挖掘搭建通用的框架。有了这个框架之后,增加了算法的泛化性,减少了数据挖掘的复杂性。
用scikit-learn估计值分类有这三个方面:
1. 估计器(estimator):用于分类、聚类和回归分析。
2. 转换器(transformer):用于数据的预处理和数据的转换。
3. 流水线(pipeline):组合数据挖掘流程,便于再次使用。
近邻(kNN,k-NearestNeighbor)分类算法是标准数据挖掘分类技术中最为直观的一种。为了对新个体进行分类,它查找训练集,找到了与新个体最相似的那些个体,看看这些个体大多属于哪个类别,
就把新个体分到哪个类别。近邻算法几乎可以对任何数据进行分类,但是要计算数据集中每两个个体之间的距离,计算量很大。同时还有一个问题是在特征取离散值的数据集上表现很差。
距离是一个很关键的问题。欧式距离(两个点之间直线距离)、曼哈顿距离(两个特征在标准坐标系中绝对轴距之和)、余弦距离(特征向量夹角的余弦值)。
接下来我们利用一个叫电离层的数据集(http://archive.ics.uci.edu/ml/machine-learning-databases/ionosphere/)来分析近邻算法的运用。在这个网站里点击ionosphere.data,之后复制这个数据,保存在本地。然后,我们来进行近邻算法的实现吧!
import csv import numpy as np # 创建两个数组分别存放特征值和类别 x = np.zeros((351, 34), dtype="float") y = np.zeros((351, ), dtype="bool") ''' with open("ionosphere.data", 'r') as input_file: reader = csv.reader(input_file) ''' input_file = open('ionosphere.data', 'r') reader = csv.reader(input_file) # 遍历文件中每一行数据,每一行数据相当于一个个体,用枚举函数来获取每一行的索引值,更新数据集x。 for i, row in enumerate(reader): 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 {0} samples in training dataset".format(x_train.shape[0]) # print "There are {0} samples in testing dataset".format(x_test.shape[0]) # print "Each sample has {0} features".format(x_train.shape[1]) # 然后导入K近邻分类器这个类,并为其初始化一个实例。 from sklearn.neighbors import KNeighborsClassifier # 创建一个估计器 estimator = KNeighborsClassifier() # 创建好之后,开始用训练数据进行训练。K近邻估计器会分析训练集中的数据,通过比较待分类的新数据点和训练集中的数据,找到新数据点的近邻。 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) # The accuracy is 86.4% # 正确率很高,但是仅仅是使用默认的参数,在某些具体的情况下是不能通用的,所以,要学着根据实验的实际情况,尽可能选用合适的参数值,争取达到最佳的效果。 # 我们通常用训练集训练算法,然后在测试集上评估效果。当测试集很简单,我们就会认为算法表现很出色。反之,我们可能会认为算法很糟糕。其实,只是凭一次的测试或一次的训练,是很难真正决定一个算法的好坏。所以,此时我们就要用到交叉检验了(将数据分割成很多部分,多次测试)。 ''' 交叉检验: 1.将整个大数据集分成几个部分 2.对于每一部分执行以下操作: 将其中一部分作为当前测试集 用剩余部分去训练算法 在当前测试集上测试算法 3.记录每一次得分及平均得分 4.在上述过程中,每条数据只能在测试集中出现一次,以减少运气成分。 ''' # 导入cross_val_score交叉检验方式 from sklearn.model_selection import cross_val_score 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) # The average accuracy is 82.3% # 设置参数。参数设置对于一个算法很重要,灵活的设置参数能大大提高算法的泛化能力,所以,选取好的参数值跟数据集的特征息息相关。 # 在近邻算法中,最重要的参数(n_neighbors)是选取多少个近邻作为预测依据。它过大过小会造成不同的分类结果。 # 下面我们测试n_neighbors的值,比如1到20,可以重复进行多次实验,观察不同参数所带来的结果之间的差异。 from collections import defaultdict avg_scores = [] all_scores = defaultdict(list) for n_neighbors in xrange(1,21): estimator_ = KNeighborsClassifier(n_neighbors=n_neighbors) scores = cross_val_score(estimator_, x, y, scoring="accuracy") avg_scores.append(np.mean(scores)) all_scores[n_neighbors].append(scores) # 为了更直观的观察差异,我们可以用图来表示。 from matplotlib import pyplot as plt parameter_values = list(range(1,21)) #plt.plot(parameter_values, avg_scores, "-o") #plt.show() plt.figure(figsize=(32,20)) plt.plot(parameter_values, avg_scores, '-o', linewidth=5, markersize=24) plt.axis([0, max(parameter_values), 0, 1.0]) # plt.show() # 可以看出随着近邻数的增加,正确率不断下降。 # 对数据预处理 ''' 对于不同特征的取值范围千差万别,常见的解决方法是对不同的特征进行规范化,使它们的特征值落在相同的值域或从属于某几个确定的类别。 ''' # 选择最具区分度的特征、创建新特征等都属于预处理的范畴。 # 预处理示例 x_broken = np.array(x) # 对数据的第三个特征的值除以10 x_broken[:,::2] /= 10 # print x_broken # 再来计算正确率 original_scores = cross_val_score(estimator, x, y, scoring='accuracy') print "The original average accuracy for is {0:.1f}%".format(np.mean(original_scores) * 100) # The original average accuracy for is 82.3% broken_scores = cross_val_score(estimator, x_broken, y, scoring="accuracy") print "The broken average accuracy for is {0:.1f}%".format(np.mean(broken_scores) * 100) # The broken average accuracy for is 71.5% # 这次跌到71.5%。如果,把特征值转变到0到1之间就能解决这个问题。将特征值规范化,使用minmaxscaler类。 from sklearn.preprocessing import MinMaxScaler # 不需要单独进行训练,直接调用fit_transform()函数,即可完成训练和转换。 # x_transformed = MinMaxScaler().fit_transform(x) # 接下来将前面的broken数据拿来测试 x_transformed = MinMaxScaler().fit_transform(x_broken) transformed_scores = cross_val_score(estimator, x_transformed, y, scoring="accuracy") print "The average accuracy for is {0:.1f}%".format(np.mean(transformed_scores) * 100) # The average accuracy for is 82.3% # 正确率再次升到82.3%说明将特征值规范化有利于减少异常值对近邻算法的影响。 # 流水线 # 实现一个数据挖掘流水线,能大大提高效率。它就好比一个框架,能够有效的将转换器和估计器结合。 from sklearn.pipeline import Pipeline # 流水线的核心是元素为元组的列表。第一个元组规范特征取值范围,第二个元组实现预测功能。 scaling_pipeline = Pipeline([("scale", MinMaxScaler()), ("predict", KNeighborsClassifier())]) scores_1 = cross_val_score(scaling_pipeline, x_broken, y, scoring="accuracy") print "The pipeline scored_1 an average accuracy for is {0:.1f}%".format(np.mean(scores_1) * 100) # The pipeline scored_1 an average accuracy for is 82.3% # 运行结果与之前的一样,说明设置流水线很有用,因为它能确保代码的复杂程度不至于超出掌控范围。 # 我们再将数据规范化应用到原始数据集上,看看能不能使准确率上升,以说明数据集规范化能提升没有异常值的数据。 scores_2 = cross_val_score(scaling_pipeline, x, y, scoring="accuracy") print "The pipeline scored_2 an average accuracy for is {0:.1f}%".format(np.mean(scores_2) * 100) # The pipeline scored_2 an average accuracy for is 82.3% # 这个结果说明,数据规范化只能将含有异常值的数据集的准确率提高。