前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >机器学习常用算法-k近邻算法

机器学习常用算法-k近邻算法

作者头像
吕海峰
发布2018-07-03 12:31:07
8780
发布2018-07-03 12:31:07
举报
文章被收录于专栏:Brian

概述

今天介绍一下机器学习常用算法,以及常用的数据处理技巧等。我们都知道机器学习针对特定任务从经验中学习,并且使得我们的任务效果越来越好。我们看一机器学习的workflow,如下所示:

数据采集和标记->数据清洗->特征选择->模型选择->模型训练和测试->模型性能评估和优化->模型使用即上线

我们一般通过Python来实现机器学习常用算法的程序,所以基于Python语言常用的机器学习类库及其第三方扩展库有:IPython,Jupyter,numpy,matplotlib,scipy,scikit-learn,seaborn

我们先安装这些类库即。

代码语言:javascript
复制
pip install ipython,jupyter,numpy,matplotlib,scipy,scikit-learn,seaborn

下面我们来简单的介绍一下这几个类库。

类库了解

ipython

1.ipython是一种探索性编程的类库,它可以非常方便的执行你的python代码。快捷键和魔法用法可以自己百度和google,介绍一个常用的技巧就是通过魔法函数可以直接启用魔法命令,不用每次执行魔法命令时键入%。

代码语言:javascript
复制
%automagic on
pwd
cd

2.可视化的嵌套可以通过。

代码语言:javascript
复制
%matplotlib inline

numpy

Numpy 是Python计算机科学基础库,里面有很多的数学算法。

代码语言:javascript
复制
import numpy as np

a = np.array([[1,2,4],[1,2,3]])
a.shape,a.ndim,a.dtype
#分别是多维数据的维度,轴和数据类型
(2, 3), 2, dtype('int64')

numpy是共享内存的,如果需要独立保存则需要显式的备份。可以通过np.may_share_memory(),判断两个数组是否是共享内存。

代码语言:javascript
复制
a = np.arange(10)
b = a[2:5]
np.may_share_memory(a,b)
#输出
True
b = a[2:5].copy()
np.may_share_memory(a,b)
#输出
False

关于轴的问题,numpy的多维数组是面向轴处理的。例如:

代码语言:javascript
复制
a = np.random.randint(1,5,(4,6))
print(a)
#输出
array([[2, 4, 2, 3, 4, 3],
       [2, 2, 1, 3, 4, 2],
       [1, 3, 1, 1, 3, 1],
       [1, 3, 3, 2, 3, 3]])
#面向轴处理,axis=0代表按行处理,axis=1面向列处理。
print(a.sum(axis=0),a.sum(axis=1))
#输出
(array([ 6, 12,  7,  9, 14,  9]), array([18, 14, 10, 15]))

还有一个经常使用的用法就是按照array的维度操作。比如:

代码语言:javascript
复制
a = np.arange(12)
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
b = a.reshape((3,4))
array([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])
b.ravel()
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11]))
b=a[:,np.newaxis]
array([[ 0],
       [ 1],
       [ 2],
       [ 3],
       [ 4],
       [ 5],
       [ 6],
       [ 7],
       [ 8],
       [ 9],
       [10],
       [11]])

排序,排序不仅支持按照值排序而且还通过index返回。比如

代码语言:javascript
复制
a=np.array([10,3,4,7,12])
a.argsort()
#输出
array([1, 2, 3, 0, 4])

我在Numpy 数据处理一文中介绍了一些常用的用法,或者参考它的官方文档。

pandas

关于pandas的技巧,可以参考Pandass 数据处理

matplotlib 和 sklearn

官方文档已经非常全面了,建议参考官方文档。

算法

在之前我们已经介绍了机器学习算法理论,下面我们介绍两个几个重要的关键术语。过拟合:模型能很好的拟合训练数据,但是对于新数据或者测试数据的预测准确性较差。欠拟合:模型不能很好的拟合训练样本且对新数据或者测试数据的预测准确性较差。相对应的我们一般称欠拟合为高偏差,过拟合称为高方差。我们现在常用的机器学习算法是通过模型算法成本来反馈(反推)模型参数,使得在成本函数或者代价函数最低的情况下,寻找最优的模型参数。比如:

J_{test}(\theta)=\frac 1{2m}\sum_{i=0}^m(h_\theta(x^{(i)})-y^{i})^2

我们通过模型在数据集上的最少成本来求解最优模型参数。

算法评价

我们在采用机器学习应用业务时,我们通常通过交叉验证数据集来衡量模型,即:训练数据集:交叉验证数据集:测试数据集=6:2:2

在模型选择时,使用训练数据集来训练算法参数,用交叉验证集来验证参数,选择交叉验证集的成本J最下的算法作为数据拟合模型,最后再用测试数据集来测试选择出来的模型准确性。但是在实践中,大多数直接将数据集分成训练数据集和测试数据集,而没有交叉验证数据集,主要是大多数时候并不需要横向对比不同的模型。在工程上,我们最主要的工作不是选择模型,而是获取更多的数据、分析数据以及数据挖掘。

学习曲线

学习曲线是观察模型准确率与训练数据集关系。步骤:

1.将数据集分为训练数据集和交叉验证数据集。

2.取训练数据集的20%作为训练样本,训练出模型参数。

3.使用交叉验证数据集来计算训练出来的模型的准确率。

4.以训练数据集的准确性,交叉验证的准确性作为纵坐标,训练数据集个数作为横坐标,在坐标轴画出。

5.训练数据集增加10%,跳到第三步骤继续执行,知道训练数据集大小为100%为止。

在详细的机器学习算法里面,我们会画出一个学习曲线。一般我们会通过学习曲线,来判断算法是高偏差还是高方差。

对于过拟合一般采取的方法:

1.获取更多的训练数据。

2.减少输入的特征数。

对于欠拟合一般采取的方法:

1.增加有价值的特征。

2.增加多项式特征。

查准率和召回率

除了学习曲线外,我们一般还会通过查准率和召回率来评价一个算法的好坏。比如关于一个肿瘤预测的实例中:

预测数据/实际数据 实际恶性肿瘤 实际良性肿瘤

预测恶性肿瘤 TruePositive FalsePositive

预测良性肿瘤 FalseNegative TrueNegative

Precision=\frac {TruePositive}{TruePositive+FalsePositive} Recall=\frac {TruePositive}{TruePositive+FalseNegative} F_1Score=2\frac{PR}{P+R}

K-近邻算法

k-近邻算法是针对未标记的样本类别,由距离其最近的k个邻居投票决定的。优点:准确性高,对异常值和噪声有较高的的容忍度。缺点:计算量较大,对内存的需求较大。一般而言,k值越大,模型的偏差越大,对噪声数据越不敏感,当k值很大时,可能造成欠拟合;k值越小,模型的方差越大,当k值太小时容易造成过拟合。我们通过k-近邻算法来进行糖尿病预测。数据集为diabetes.csv,我们依次来看一下。

1.加载数据

代码语言:javascript
复制
data_path="diabetes.csv"
import pandas as pd
data = pd.read_csv(data_path)
data.head()

数据的8个特征分别为

  • Pregnancies:怀孕的次数
  • Glucose:血浆葡糖糖浓度。
  • BloodPressure:舒张压(单位毫米)
  • SkinThickness:肱三头肌厚度(单位毫米)
  • Insulin:两个小时的血清胰岛素(单位毫升)
  • BMI:身体质量指数,体重除以身高的平方。
  • DiabetesPedigreeFunction:糖尿病血统指数。
  • Age 年龄
  • Outcome:结果标记值,0表示没有糖尿病,1表示有糖尿病。

我们可以看一下实例数据。

代码语言:javascript
复制
data.shape
(768,9)
ata.groupby("Outcome").size()
Outcome
0    500
1    268
dtype: int64

其中阳性有500个,阴性有268个。我们将数据集分类出来方便我们训练和衡量。

代码语言:javascript
复制
#只含有特征的数据集
x=data.iloc[:,0:8]
#标记数据
y=data.iloc[:,8]
print('shape of x {};shape of y {}'.format(x.shape,y.shape))
#输出 shape of x (768, 8);shape of y (768,)
from sklearn.model_selection import train_test_split
#将数据集划分为训练数据集和测试数据集,其中测试数据集为20%。
x_train,x_test,y_trian,y_test = train_test_split(x,y,test_size=0.2)

2.模型选择

我们使用三种算法对数据进行拟合即普通的k-均值算法,带权重的k-均值算法和指定半径的k-均值算法。

代码语言:javascript
复制
from sklearn.neighbors import KNeighborsClassifier,RadiusNeighborsClassifier
models=[]
models.append(("KNN",KNeighborsClassifier(n_neighbors=2)))
models.append(("KNN with weights",KNeighborsClassifier(n_neighbors=2,weights="distance")))
models.append(("Radius Neighbors",RadiusNeighborsClassifier(n_neighbors=2,radius=500)))
results=[]
for name,model in models:
    model.fit(x_train,y_trian)
    results.append((name,model.score(x_test,y_test)))
for i in range(len(results)):
    print("name:{};score:{}".format(results[i][0],results[i][1]))
#输出
name:KNN;score:0.7142857142857143
name:KNN with weights;score:0.6168831168831169
name:Radius Neighbors;score:0.6948051948051948

因为训练样本和测试样本是随机分配的,那么如何衡量模型呢?所以我们需要多次分配训练数据集和交叉验证数据集,然后对多次预测结果进行平均。

代码语言:javascript
复制
#kfold 将数据分成10份,其中一份作为交叉验证数据集来计算模型准确性。
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
results=[]
for name,model in models:
    kfold=KFold(n_splits=10)
    cv_result=cross_val_score(model,x,y,cv=kfold)
    results.append((name,cv_result))
for i in range(len(results)):
    print("name:{};score:{}".format(results[i][0],results[i][1].mean()))

我们采用普通的k-近邻算法。

3.模型分析

我们分别对训练集和测试集进行分析,如下:

代码语言:javascript
复制
knn = KNeighborsClassifier(n_neighbors=2)
knn.fit(X=x_train,y=y_trian)
train_score=knn.score(x_train,y_trian)
test_score=knn.score(x_test,y_test)
print("train score {};test score {}".format(train_score,test_score))
#输出
train score 0.8289902280130294;test score 0.7142857142857143

一是模型在训练样本上表现不佳,这说明算法太简单。二是在测试集的准确性欠佳。

我们下面通过学习曲线来看一下:

代码语言:javascript
复制
from sklearn.model_selection import learning_curve
import numpy as np
import matplotlib.pyplot as plt

def plot_learning_curve(plt, estimator, title, X, y, ylim=None, cv=None,n_jobs=1, train_sizes=np.linspace(.1, 1.0, 5)):
    plt.title(title)
    if ylim is not None:
        plt.ylim(*ylim)
    plt.xlabel("Training examples")
    plt.ylabel("Score")
    train_sizes, train_scores, test_scores = learning_curve(
        estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes)
    train_scores_mean = np.mean(train_scores, axis=1)
    train_scores_std = np.std(train_scores, axis=1)
    test_scores_mean = np.mean(test_scores, axis=1)
    test_scores_std = np.std(test_scores, axis=1)
    plt.grid()

    plt.fill_between(train_sizes, train_scores_mean - train_scores_std,
                     train_scores_mean + train_scores_std, alpha=0.1,
                     color="r")
    plt.fill_between(train_sizes, test_scores_mean - test_scores_std,
                     test_scores_mean + test_scores_std, alpha=0.1, color="g")
    plt.plot(train_sizes, train_scores_mean, 'o--', color="r",
             label="Training score")
    plt.plot(train_sizes, test_scores_mean, 'o-', color="g",
             label="Cross-validation score")

    plt.legend(loc="best")
    return plt

cv=ShuffleSplit(n_splits=10,test_size=0.2,random_state=0)
plt.figure(figsize=(10,6),dpi=64)
plot_learning_curve(plt,knn,"cure",x,y,ylim=(0.0,1.01),cv=cv)
plt.show()

我们能看到学习曲线,和我们的之前的模型分析的结果是一致的。如下图所示:

后面我们会介绍如何提高该算法准确率。

4.特征可视化和分析

有时候我们想通过将最相关的一个或者多个特征选择出来进行可视化分析,那么如何选择最相关的特征呢?我们一般通过如下方法:

代码语言:javascript
复制
from sklearn.feature_selection import SelectKBest
selector = SelectKBest(k=2)
x_new=selector.fit_transform(x,y)
results=[]
for name,model in models:
    kfold=KFold(n_splits=10)
    cv_result=cross_val_score(model,x_new,y,cv=kfold)
    results.append((name,cv_result))
for i in range(len(results)):
    print("name:{};score:{}".format(results[i][0],results[i][1].mean()))
#输出
name:KNN;score:0.725205058099795
name:KNN with weights;score:0.6900375939849623
name:Radius Neighbors;score:0.6510252904989747

然后可以将这两个特征和输出标记投影在坐标轴上,看一下数据分布。可以看到数据分布和重叠性很大,所以选择k-近邻算法无法达到一个很好的预测准确性。

这里的最相关的特征选择主要采用了统计学上的相关性检验,比如:卡方检验、t检验。

总结

通过一个简单的例子对机器学习的常用算法-k近邻算法有了一个整体上的了解。下面我们介绍一下另外一个常用算法:线性回归

参考

1.《scikit-learning 机器学习》

2.scikit learning

3.《机器学习导论》

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-03-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 类库了解
    • ipython
      • numpy
        • pandas
          • matplotlib 和 sklearn
            • 算法评价
            • 学习曲线
            • 查准率和召回率
        • 算法
          • K-近邻算法
            • 总结
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档