机器学习【KNN案例、API、总结】

发布于:2022-08-02 ⋅ 阅读:(388) ⋅ 点赞:(0)

一 案例数据集介绍

主要介绍使用Python进行机器学习的一些基本概念。 在此案例中,将使用K-Nearest Neighbor(KNN)算法对鸢尾花的种类进行分类,并测量花的特征。

1 案例:鸢尾花种类预测

Iris数据集是常用的分类实验数据集,由Fisher, 1936收集整理。Iris也称鸢尾花卉数据集,是一类多重变量分析的数据集。关于数据集的具体介绍:
在这里插入图片描述
在这里插入图片描述

2 scikit-learn中数据集介绍

2.1 scikit-learn数据集API介绍

sklearn.datasets:加载获取流行数据集
	datasets.load_*()
		获取小规模数据集,数据包含在datasets里
	datasets.fetch_*(data_home=None)
		获取大规模数据集,需要从网络上下载,函数的第一个参数是data_home,表示数据集下载的目录,默认是 ~/scikit_learn_data/

2.1.1 sklearn小数据集

sklearn.datasets.load_iris() 加载并返回鸢尾花数据集

from sklearn.datasets import load_iris

# 小数据集获取
iris = load_iris()
print(iris)

2.1.2 sklearn大数据集

sklearn.datasets.fetch_20newsgroups(data_home=None,subset=‘train’)

​ subset:‘train’或者’test’,‘all’,可选,选择要加载的数据集。

​ 训练集的“训练”,测试集的“测试”,两者的“全部”

from sklearn.datasets import fetch_20newsgroups
# 大数据集获取
news = fetch_20newsgroups()
print(news)

2.2 sklearn数据集返回值介绍

load和fetch返回的数据类型datasets.base.Bunch(字典格式)

​ data:特征数据数组,是 [n_samples * n_features] 的二维 numpy.ndarray 数组

​ target:标签数组,是 n_samples 的一维 numpy.ndarray 数组

​ DESCR:数据描述

​ feature_names:特征名,新闻数据,手写数字、回归数据集没有

​ target_names:标签名

from sklearn.datasets import load_iris
# 获取鸢尾花数据集
iris = load_iris()
print("鸢尾花数据集的返回值:\n", iris)
# 返回值是一个继承自字典的Bench
print("鸢尾花的特征值:\n", iris["data"])
print("鸢尾花的目标值:\n", iris.target)
print("鸢尾花特征的名字:\n", iris.feature_names)
print("鸢尾花目标值的名字:\n", iris.target_names)
print("鸢尾花的描述:\n", iris.DESCR)

2.3 查看数据分布

通过创建一些图,以查看不同类别是如何通过特征来区分的。 在理想情况下,标签类将由一个或多个特征对完美分隔。 在现实世界中,这种理想情况很少会发生。

seaborn介绍

​ Seaborn 是基于 Matplotlib 核心库进行了更高级的 API 封装,可以轻松地画出更漂亮的图形。而 Seaborn 的漂亮主要体现在配色更加舒服、以及图形元素的样式更加细腻。

​ 安装 pip3 install seaborn

​ seaborn.lmplot() 是一个非常有用的方法,它会在绘制二维散点图时,自动完成回归拟合

​ 参数说明:

​ sns.lmplot() 里的 x, y 分别代表横纵坐标的列名,

​ data= 是关联到数据集,

​ hue= 代表按照 species即花的类别分类显示,

​ fit_reg=是否进行线性拟合。

# 内嵌绘图
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

# 把数据转换成dataframe的格式,第一个参数为数据源,columns为列名
iris_d = pd.DataFrame(iris['data'], columns = ['Sepal_Length', 'Sepal_Width', 'Petal_Length', 'Petal_Width'])
# 添加target列
iris_d['Species'] = iris.target
# 使用函数进行画图,因为四列两两组合有六种情况,使用函数可以任意组合
def plot_iris(iris, col1, col2):
    # hue为类别(target) fit_reg = false 取消线性拟合
    sns.lmplot(x = col1, y = col2, data = iris, hue = "Species", fit_reg = False)
    plt.xlabel(col1)
    plt.ylabel(col2)
    plt.title('鸢尾花种类分布图')
    plt.show()
plot_iris(iris_d, 'Petal_Width', 'Sepal_Length')

在这里插入图片描述

2.4 数据集的划分

机器学习一般的数据集会划分为两个部分:训练数据:用于训练,构建模型;测试数据:在模型检验时使用,用于评估模型是否有效

划分比例:训练集:70% 80% 75%;测试集:30% 20% 25%

数据集划分api

sklearn.model_selection.train_test_split(arrays, *options)

​ x 数据集的特征值

​ y 数据集的标签值

​ test_size 测试集的大小,一般为float

​ random_state 随机数种子,不同的种子会造成不同的随机采样结果。相同的种子采样结果相同。

​ return 测试集特征,训练集特征值,训练标签,测试标签(默认随机取)

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# 获取鸢尾花数据集
iris = load_iris()
# 对鸢尾花数据集进行分割
# 会返回四个值:
#   训练集的特征值x_train 
#   测试集的特征值x_test 
#   训练集的目标值y_train 
#   测试集的目标值y_test
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size = 0.2, random_state=22)
# 显示训练集特征值的大小
print("x_train:\n", x_train.shape)
# 随机数种子
x_train1, x_test1, y_train1, y_test1 = train_test_split(iris.data, iris.target, random_state=6)
x_train2, x_test2, y_train2, y_test2 = train_test_split(iris.data, iris.target, random_state=6)
print("如果随机数种子不一致:\n", x_train == x_train1)
print("如果随机数种子一致:\n", x_train1 == x_train2)

二 特征工程-特征预处理

1 什么是特征预处理

scikit-learn的解释

provides several common utility functions and transformer classes to change raw feature vectors into a representation that is more suitable for the downstream estimators.

通过一些转换函数将特征数据转换成更加适合算法模型的特征数据过程

在这里插入图片描述

特征的单位或者大小相差较大,或者某特征的方差相比其他的特征要大出几个数量级容易影响(支配)目标结果,使得一些算法无法学习到其它的特征

需要用到一些方法(归一化,标准化)进行无量纲化使不同规格的数据转换到同一规格

特征预处理API:sklearn.preprocessing

2 归一化

通过对原始数据进行变换把数据映射到(默认为[0,1])之间

在这里插入图片描述

作用于每一列,max为一列的最大值,min为一列的最小值,那么X’’为最终结果,mx,mi分别为指定区间值默认mx为1,mi为0
在这里插入图片描述

2.1 API

sklearn.preprocessing.MinMaxScaler (feature_range=(0,1)… )

​ MinMaxScalar.fit_transform(X)

​ X:numpy array格式的数据[n_samples,n_features]

​ 返回值:转换后的形状相同的array

2.2 数据计算

对以下数据进行运算

milage,Liters,Consumtime,target
40920,8.326976,0.953952,3
14488,7.153469,1.673904,2
26052,1.441871,0.805124,1
75136,13.147394,0.428964,1
38344,1.669788,0.134296,1

实例化MinMaxScalar,通过fit_transform转换

import pandas as pd
from sklearn.preprocessing import MinMaxScaler

def minmax_demo():
    """
    归一化演示
    :return: None
    """
    data = pd.read_csv("dating.txt")
    print(data)
    # 1、实例化一个转换器类,其中2,3对应上图计算公式中的mx,mi,默认为0和1
    transfer = MinMaxScaler(feature_range=(2, 3))
    # 2、调用fit_transform方法
    data = transfer.fit_transform(data[['milage','Liters','Consumtime']])
    print("最小值最大值归一化处理的结果:\n", data)

    return None

返回结果:

 milage     Liters  Consumtime  target
0     40920   8.326976    0.953952       3
1     14488   7.153469    1.673904       2
2     26052   1.441871    0.805124       1
3     75136  13.147394    0.428964       1
..      ...        ...         ...     ...
998   48111   9.134528    0.728045       3
999   43757   7.882601    1.332446       3

[1000 rows x 4 columns]
最小值最大值归一化处理的结果:
 [[ 2.44832535  2.39805139  2.56233353]
 [ 2.15873259  2.34195467  2.98724416]
 [ 2.28542943  2.06892523  2.47449629]
 ..., 
 [ 2.29115949  2.50910294  2.51079493]
 [ 2.52711097  2.43665451  2.4290048 ]
 [ 2.47940793  2.3768091   2.78571804]]

存在问题:特别容易受到异常点的影响,鲁棒性较差,只适合传统精确小数据场景,一般不使用此种方法处理数据

3 标准化

通过对原始数据进行变换把数据变换到均值为0,标准差为1范围内
在这里插入图片描述

作用于每一列,mean为平均值,σ为标准差

对于归一化来说:如果出现异常点,影响了最大值和最小值,那么结果显然会发生改变

对于标准化来说:如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大,从而方差改变较小。

3.1 API

sklearn.preprocessing.StandardScaler( )

​ 处理之后每列来说所有数据都聚集在均值0附近标准差差为1

​ StandardScaler.fit_transform(X)

​ X:numpy array格式的数据[n_samples,n_features]

​ 返回值:转换后的形状相同的array

3.2 数据计算

同样对上面的数据进行处理

实例化StandardScaler,通过fit_transform转换

import pandas as pd
from sklearn.preprocessing import StandardScaler

def stand_demo():
    """
    标准化演示
    :return: None
    """
    data = pd.read_csv("dating.txt")
    print(data)
    # 1、实例化一个转换器类
    transfer = StandardScaler()
    # 2、调用fit_transform
    data = transfer.fit_transform(data[['milage','Liters','Consumtime']])
    print("标准化的结果:\n", data)
    print("每一列特征的平均值:\n", transfer.mean_)
    print("每一列特征的方差:\n", transfer.var_)

    return None

返回结果:

    milage     Liters  Consumtime  target
0     40920   8.326976    0.953952       3
1     14488   7.153469    1.673904       2
2     26052   1.441871    0.805124       1
..      ...        ...         ...     ...
997   26575  10.650102    0.866627       3
998   48111   9.134528    0.728045       3
999   43757   7.882601    1.332446       3

[1000 rows x 4 columns]
标准化的结果:
 [[ 0.33193158  0.41660188  0.24523407]
 [-0.87247784  0.13992897  1.69385734]
 [-0.34554872 -1.20667094 -0.05422437]
 ..., 
 [-0.32171752  0.96431572  0.06952649]
 [ 0.65959911  0.60699509 -0.20931587]
 [ 0.46120328  0.31183342  1.00680598]]
每一列特征的平均值:
 [  3.36354210e+04   6.55996083e+00   8.32072997e-01]
每一列特征的方差:
 [  4.81628039e+08   1.79902874e+01   2.46999554e-01]

在已有样本足够多的情况下比较稳定,适合现代嘈杂大数据场景,经常使用

三 案例流程实现

1 K-近邻算法API

sklearn.neighbors.KNeighborsClassifier(n_neighbors=5,algorithm=‘auto’)

​ n_neighbors:

​ int,可选(默认= 5),k_neighbors查询默认使用的邻居数

​ algorithm:{‘auto’,‘ball_tree’,‘kd_tree’,‘brute’}

​ 快速k近邻搜索算法,默认参数为auto,可以理解为算法自己决定合适的搜索算法。除此之外,用户也可以自己指定搜索算法ball_tree、kd_tree、brute方法进行搜索

​ auto 自动选择合适的算法,维数小于20用kd_tree,大于20用ball_tree,数据集特别简单用brute

​ brute是蛮力搜索,也就是线性扫描,当训练集很大时,计算非常耗时。

​ kd_tree,构造kd树存储数据以便对其进行快速检索的树形数据结构,kd树也就是数据结构中的二叉树。以中值切分构造的树,每个结点是一个超矩形(超平面),在维数小于20时效率高。

​ ball_tree是为了克服kd树高维失效而发明的,其构造过程是以质心C和半径r分割样本空间,每个节点是一个超球体。样本特征值大于20维时用ball_tree。

2 实现流程

  • 获取数据集
  • 数据基本处理
  • 特征工程
  • 机器学习(模型训练)
  • 模型评估

2.3 代码过程

(1)导入模块

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier

(2)从sklearn中获取数据集,分割数据集

# 1.获取数据集
iris = load_iris()

# 2.数据基本处理--数据分割
# x_train,x_test,y_train,y_test为训练集特征值、测试集特征值、训练集目标值、测试集目标值
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2, random_state=22)

(3)进行数据特征值标准化

# 3、特征工程:标准化
# 实例化转换器
transfer = StandardScaler()
# 分别标准化训练数据和测试数据
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)

(4)使用模型进行训练预测

# 4、机器学习(模型训练)
# 实例化估计器
estimator = KNeighborsClassifier(n_neighbors=9)
# 模型训练
estimator.fit(x_train, y_train)
# 5、模型评估
# 方法1:比对真实值和预测值
y_predict = estimator.predict(x_test)
print("预测结果为:\n", y_predict)
print("比对真实值和预测值:\n", y_predict == y_test)
# 方法2:直接计算准确率
score = estimator.score(x_test, y_test)
print("准确率为:\n", score)

四 k近邻算法总结

(1)优点:

  • 简单有效

  • 重新训练的代价低

  • 适合类域交叉样本

    KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。

  • 适合大样本自动分类

    该算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量较小的类域采用这种算法比较容易产生误分。

(2)缺点:

  • 惰性学习

    KNN算法是懒散学习方法(lazy learning,基本上不学习),一些积极学习的算法要快很多

  • 类别评分不是规格化

    不像一些通过概率评分的分类

  • 输出可解释性不强

    例如决策树的输出可解释性就较强

  • 对不均衡的样本不擅长

    当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果。可以采用权值的方法(和该样本距离小的邻居权值大)来改进。

  • 计算量较大

    目前常用的解决方法是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本。

五 交叉验证

1 什么是交叉验证(cross validation)

交叉验证:将拿到的训练数据,分为训练和验证集。以下图为例:将数据分成4份,其中一份作为验证集。然后经过4次(组)的测试,每次都更换不同的验证集。即得到4组模型的结果,取平均值作为最终结果。又称4折交叉验证。

之前数据分为训练集和测试集,但是**为了让从训练得到模型结果更加准确。**做以下处理

  • 训练集:训练集+验证集
  • 测试集:测试集

在这里插入图片描述

交叉验证目的:为了让被评估的模型更加准确可信,并不能保证整体准确率提高

2 什么是网格搜索(Grid Search)

通常情况下,有很多参数是需要手动指定的(如k-近邻算法中的K值),这种叫超参数。但是手动过程繁杂,所以需要对模型预设几种超参数组合。每组超参数都采用交叉验证来进行评估。最后选出最优参数组合建立模型。
在这里插入图片描述

注意以上k=3时,模型会根据上图训练集的切分方式执行4次,共计12次,最终选择出最优模型

3 交叉验证,网格搜索(模型选择与调优)API:

sklearn.model_selection.GridSearchCV(estimator, param_grid=None,cv=None)
	对估计器的指定参数值进行详尽搜索
	estimator:估计器对象,选择了那个训练模型
	param_grid:估计器参数(dict){“n_neighbors”:[1,3,5]}
	cv:指定几折交叉验证
	fit:输入训练数据
	score:准确率
结果分析:
	bestscore__:在交叉验证中验证的最好结果
	bestestimator:最好的参数模型
	cvresults:每次交叉验证后的验证集准确率结果和训练集准确率结果

4 鸢尾花案例增加K值调优

(1)使用GridSearchCV构建估计器

# 1、获取数据集
iris = load_iris()
# 2、数据基本处理 -- 划分数据集
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)
# 3、特征工程:标准化
# 实例化一个转换器类
transfer = StandardScaler()
# 调用fit_transform
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 4、KNN预估器流程
#  4.1 实例化预估器类
estimator = KNeighborsClassifier()
############################################################################
# 4.2 模型选择与调优——网格搜索和交叉验证
# 准备要调的超参数
param_dict = {"n_neighbors": [1, 3, 5]}
# n_jobs电脑使用几核CPU进行训练,-1为满负荷执行
estimator = GridSearchCV(estimator, param_grid=param_dict, cv=3, n_jobs=)
# 4.3 fit数据进行训练
estimator.fit(x_train, y_train)
# 5、评估模型效果
# 方法a:比对预测结果和真实值
y_predict = estimator.predict(x_test)
print("比对预测结果和真实值:\n", y_predict == y_test)
# 方法b:直接计算准确率
score = estimator.score(x_test, y_test)
print("直接计算准确率:\n", score)

(2)然后进行评估查看最终选择的结果和交叉验证的结果

print("在交叉验证中验证的最好结果:\n", estimator.best_score_)
print("最好的参数模型:\n", estimator.best_estimator_)
print("每次交叉验证后的准确率结果:\n", estimator.cv_results_)

(3)最终结果

比对预测结果和真实值:
 [ True  True  True  True  True  True  True False  True  True  True  True
  True  True  True  True  True  True False  True  True  True  True  True
  True  True  True  True  True  True  True  True  True  True  True  True
  True  True]
直接计算准确率:
 0.947368421053
在交叉验证中验证的最好结果:
 0.973214285714
最好的参数模型:
 KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
           metric_params=None, n_jobs=1, n_neighbors=5, p=2,
           weights='uniform')
每次交叉验证后的准确率结果:
# 不同的n_neighbors对应的结果
 {'mean_fit_time': array([ 0.00114751,  0.00027037,  0.00024462]), 'std_fit_time': array([  1.13901511e-03,   1.25300249e-05,   1.11011951e-05]), 'mean_score_time': array([ 0.00085751,  0.00048693,  0.00045625]), 'std_score_time': array([  3.52785082e-04,   2.87650037e-05,   5.29673344e-06]), 'param_n_neighbors': masked_array(data = [1 3 5],
             mask = [False False False],
       fill_value = ?)
, 'params': [{'n_neighbors': 1}, {'n_neighbors': 3}, {'n_neighbors': 5}], 'split0_test_score': array([ 0.97368421,  0.97368421,  0.97368421]), 'split1_test_score': array([ 0.97297297,  0.97297297,  0.97297297]), 'split2_test_score': array([ 0.94594595,  0.89189189,  0.97297297]), 'mean_test_score': array([ 0.96428571,  0.94642857,  0.97321429]), 'std_test_score': array([ 0.01288472,  0.03830641,  0.00033675]), 'rank_test_score': array([2, 3, 1], dtype=int32), 'split0_train_score': array([ 1.        ,  0.95945946,  0.97297297]), 'split1_train_score': array([ 1.        ,  0.96      ,  0.97333333]), 'split2_train_score': array([ 1.  ,  0.96,  0.96]), 'mean_train_score': array([ 1.        ,  0.95981982,  0.96876877]), 'std_train_score': array([ 0.        ,  0.00025481,  0.0062022 ])}

六 案例2:预测facebook签到位置

1 数据集介绍

在这里插入图片描述

数据介绍:将根据用户的位置,准确性和时间戳预测用户正在查看的业务。

train.csv,test.csv 
row_id:登记事件的ID
xy:坐标
准确性:定位准确性 
时间:时间戳
place_id:业务的ID,这是您预测的目标

2 步骤分析

对于数据做一些基本处理(这里所做的一些处理不一定达到很好的效果,我们只是简单尝试,有些特征我们可以根据一些特征选择的方式去做处理)

  • 缩小数据集范围 DataFrame.query()
  • 选取有用的时间特征
  • 将签到位置少于n个用户的删除

分割数据集

标准化处理

k-近邻预测

3 代码过程

(1)获取数据集

# 1、获取数据集
facebook = pd.read_csv("./data/FBlocation/train.csv")

(2)基本数据处理

# 2.基本数据处理
# 2.1 缩小数据范围--取部分数据
facebook_data = facebook.query("x>2.0 & x<2.5 & y>2.0 & y<2.5")
# 2.2 选择时间特征
time = pd.to_datetime(facebook_data["time"], unit="s")
time = pd.DatetimeIndex(time)
facebook_data["day"] = time.day
facebook_data["hour"] = time.hour
facebook_data["weekday"] = time.weekday
# 2.3 去掉签到较少的地方
place_count = facebook_data.groupby("place_id").count()
place_count = place_count[place_count["row_id"]>3]
facebook_data = facebook_data[facebook_data["place_id"].isin(place_count.index)]
# 2.4 确定特征值和目标值
x = facebook_data[["x", "y", "accuracy", "day", "hour", "weekday"]]
y = facebook_data["place_id"]
# 2.5 分割数据集
x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=22)

(3)特征工程–特征预处理(标准化)

# 3.特征工程--特征预处理(标准化)
# 3.1 实例化一个转换器
transfer = StandardScaler()
# 3.2 调用fit_transform
x_train = transfer.fit_transform(x_train)
x_test = transfer.fit_transform(x_test)

(4)机器学习–knn+cv

# 4.机器学习--knn+cv
# 4.1 实例化一个估计器
estimator = KNeighborsClassifier()
# 4.2 调用gridsearchCV
param_grid = {"n_neighbors": [1, 3, 5, 7, 9]}
estimator = GridSearchCV(estimator, param_grid=param_grid, cv=5)
# 4.3 模型训练
estimator.fit(x_train, y_train)

(5)模型评估

# 5.模型评估
# 5.1 基本评估方式
score = estimator.score(x_test, y_test)
print("最后预测的准确率为:\n", score)

y_predict = estimator.predict(x_test)
print("最后的预测值为:\n", y_predict)
print("预测值和真实值的对比情况:\n", y_predict == y_test)

# 5.2 使用交叉验证后的评估方式
print("在交叉验证中验证的最好结果:\n", estimator.best_score_)
print("最好的参数模型:\n", estimator.best_estimator_)
print("每次交叉验证后的验证集准确率结果和训练集准确率结果:\n",estimator.cv_results_)
本文含有隐藏内容,请 开通VIP 后查看