用scikit-learn估计值分类——近邻算法(KNN)

来源:互联网 发布:服务器开放端口查询 编辑:程序博客网 时间:2024/05/16 08:33
用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 csvimport 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_splitx_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) * 100print "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_scorescores = cross_val_score(estimator, x, y, scoring="accuracy")average_accuracy = np.mean(scores) * 100print "The average accuracy is {0:.1f}%".format(average_accuracy)# The average accuracy is 82.3%# 设置参数。参数设置对于一个算法很重要,灵活的设置参数能大大提高算法的泛化能力,所以,选取好的参数值跟数据集的特征息息相关。# 在近邻算法中,最重要的参数(n_neighbors)是选取多少个近邻作为预测依据。它过大过小会造成不同的分类结果。# 下面我们测试n_neighbors的值,比如1到20,可以重复进行多次实验,观察不同参数所带来的结果之间的差异。from collections import defaultdictavg_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 pltparameter_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)# 对数据的第三个特征的值除以10x_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%# 这个结果说明,数据规范化只能将含有异常值的数据集的准确率提高。

 

原创粉丝点击