机器学习算法 01 —— K-近邻算法(数据集划分、归一化、标准化)
机器学习算法 02 —— 线性回归算法(正规方程、梯度下降、模型保存)
机器学习算法 03 —— 逻辑回归算法(精确率和召回率、ROC曲线和AUC指标、过采样和欠采样)
机器学习算法 04 —— 决策树(ID3、C4.5、CART,剪枝,特征提取,回归决策树)
机器学习算法 05 —— 集成学习(Bagging、随机森林、Boosting、AdaBost、GBDT)
机器学习算法 06 —— 聚类算法(k-means、算法优化、特征降维、主成分分析PCA)
机器学习算法 07 —— 朴素贝叶斯算法(拉普拉斯平滑系数、商品评论情感分析案例)
机器学习算法 08 —— 支持向量机SVM算法(核函数、手写数字识别案例)
机器学习算法 09 —— EM算法(马尔科夫算法HMM前置学习,EM用硬币案例进行说明)
机器学习算法 10 —— HMM模型(马尔科夫链、前向后向算法、维特比算法解码、hmmlearn)
学习目标:
用下面这个图来简单说明就是,你所处的位置距离小明最近,那么你就被认为也处于地区A。即根据你最近的“邻居”来推断你所属的类别。
K Nearest Neighbor算法⼜叫KNN算法,这个算法是机器学习⾥⾯⼀个⽐较经典的算法, 总体来说KNN算法是相对⽐较容易理解的算法。
定义:如果⼀个样本在特征空间中的k个最相似**(即特征空间中最邻近)**的样本中的⼤多数属于某⼀个类别,则该样本也属于这个类别。上面的例子里K取的是1,如果k取3,那么在最近的3个地区中取众数,距离最近的3个邻居是小明、小呆、小绿,而小呆和小绿都是地区B,所以你属于地区B。
距离公式:两个样本的距离可以通过如下公式计算(又叫欧式距离)。关于距离公式会在后面说明。
下面通过一个例子来说明:通过K-近邻算法预测一部电影的类型。
现在已知前8部电影的类型,根据它们的各种镜头来判断第9部电影是什么类型。根据图表我们知道,喜剧片搞笑镜头较多,动作片打斗镜头较多,爱情片拥抱镜头较多。
现在对《唐人街探案》的三种镜头和其他电影的三种镜头运用距离公式
假设我们K取5(即最近的5部电影),根据众数,这五部电影中有3部喜剧,1部爱情,所以得出结果《唐人街探案》是喜剧片。
Science Kit Learn,包含了许多知名机器学习算法的实现,内置了很多数据集,scikit-learn文档比较完善且容易上手,因此对于初学者比较友好。要安装使用scikit-learn,需要先安装numpy、scipy等库,所以推荐直接安装Anaconda,它专门管理Python库,内置了许多科学库,可以参考我另外的博客 Python包/库/环境管理 —— Anaconda、PyCharm导入Anaconda的包。
sklearn.neighbors.KNeighborsClassifier(n_neighbors=5)
,n_neighbors就是K值,默认是5。
下面简单举例使用,这里推荐用PyCharm,jupyter主要是一些探索性工作,PyCharm更适合一个项目开发。同时,由于只是简单使用,所以机器学习开发流程中的一些布置就省略了。
获取数据集
数据基本处理(该案例中省略)
特征⼯程(该案例中省略)
机器学习
模型评估(该案例中省略)
from sklearn.neighbors import KNeighborsClassifier
# 1. 获取数据集(这里是我们自己构造一个简单的)
x = [[0], [1], [3], [5]] # 特征值
y = [0, 0, 1, 1] # 目标值
# 4. 机器学习
# 4.1 实例化一个估计器
estimator = KNeighborsClassifier(1) # K 取1
# 4.2 模型训练
estimator.fit(x, y) # 简单来说,fit就是求得训练集X的均值,方差,最大值,最小值,这些训练集X固有的属性。
# 数据预测
result = estimator.predict([[6]])
print(result) # 结果 1,因为6距离【5】最近,而【5】的结果是1,所以6归类为1
看到这里,你肯定会有一些疑惑:
这里后面将会一一进行解答。
在机器学习过程中,对于函数 dist(., .),若它是"距离度量" (distance measure),则需满⾜⼀些基本性质:
⾮负性: dist(X , X ) >= 0 ;
同⼀性:dist(x , x ) = 0。当且仅当 X = X ;
对称性: dist(x , x ) = dist(x , x );
直递性: dist(x , x ) <= dist(x , x ) + dist(x , x )
直递性常被直接称为“三⻆不等式”。
欧⽒距离是最容易直观理解的距离度量⽅法,我们⼩学、初中和⾼中接触到的两个点在空间中的距离⼀般都是指欧⽒距离。
# 点A、B、C、D
X=[[1,1],[2,2],[3,3],[4,4]];
经计算得: AB距离-1.4142、AC距离-2.8284、AD距离-4.2426、BC距离-1.4142、BD距离-2.8284、CD距离-1.4142
在曼哈顿街区要从⼀个⼗字路⼝开⻋到另⼀个⼗字路⼝,驾驶距离显然不是两点间的直线距离。这个实际驾驶距离就是“曼哈顿距离”。曼哈顿距离也称为“城市街区距离”(City Block distance)。 下图中,从A到B的三条线路距离是相同的。
# A、B、C、D
X=[[1,1],[2,2],[3,3],[4,4]];
经计算得: AB=2、AC=4、AD=6、BC=2、BD=4、CD=2
国际象棋中,国王可以直⾏、横⾏、斜⾏,所以国王⾛⼀步可以移动到相邻8个⽅格中的任意⼀个。国王从格⼦(x1,y1)⾛到格⼦(x2,y2)最少需要多少步?这个距离就叫切⽐雪夫距离。
X=[[1,1],[2,2],[3,3],[4,4]];
经计算得: d = 1 2 3 1 2 1
闵⽒距离不是⼀种距离,⽽是⼀组距离的定义,是对多个距离度量公式的概括性的表述。
两个n维变量a(x11,x12,…,x1n)与b(x21,x22,…,x2n)间的闵可夫斯基距离定义为:
其中p是⼀个变参数:
当p=1时,就是曼哈顿距离;
当p=2时,就是欧⽒距离;
当p→∞时,就是切⽐雪夫距离。
根据p的不同,闵⽒距离可以表示某⼀类/种的距离。
⼩结:
例如:⼆维样本(身⾼[单位:cm],体重[单位: ]),现有三个样本:a(180,50),b(190,50),c(180,60)。a与b的闵⽒距离(⽆论是曼哈顿距离、欧⽒距离或切⽐雪夫距离)等于a与c的闵⽒距离。但实际上身⾼的10cm并不能和体重的10kg划等号。
我们常将属性划分为"连续属性和"离散属性",前者在定义域上有⽆穷多个可能的取值,后者在定义域上是有限个取值。
若属性值之间存在序关系,则可以将其转化为连续值,例如:身⾼属性“⾼”“中等”“矮”,可转化为{1, 0.5, 0}。
若属性值之间不存在序关系,则通常将其转化为向量的形式,例如:性别属性“男” “⼥”,可转化为{(1,0),(0,1)}。
假如我们之前电影类型预测案例中的K值取1或者取6会发生什么问题呢?
K值选择问题,李航博⼠的⼀书「统计学习⽅法」上说:
概念解释
问题导入:在实现K-邻近算法时,主要考虑的问题是如何对训练数据快速进行K-邻近搜索(即找出最近的“邻居”),最简单的方法当然是线性扫描,将输入值与每一个训练数据进行距离计算,但这在训练数据量大时会非常耗时。
因此,为了提高KNN搜索效率,使用的是特殊存储结构,以减少计算距离的次数。
KNN每次要预测一个点时,都需要计算这个点到训练数据集里每个点的距离,针对N个样本,每个样本有D个特征的数据集,这样的时间复杂度是O(DN2)。
KD树的原理:假如点A和点B距离很远,点B和点C距离很近,那么可以得出点A和点C距离也很远,在计算距离时就可以跳过点C。这样算法复杂度可以降低到O(DNlogN)。
KD树类似于二叉排序树,先对所有点进行大小排序,将中间的点作为根节点(事例里是黄点),将黄点上面的归为左子树,下面的归为右子树,然后再对这两个区域继续划分直到区域里没有点。分割的那条线叫超平面。(在一维里是点,二维里是线,三维里是面)
第一层是黄色根节点,第二层是红色,第三层是绿色,第四层是蓝色。
构造好树后,距离计算就类⽐“⼆分查找”:
给出⼀组数据:[9 1 4 7 2 5 0 3 8],要查找8。如果挨个查找(线性扫描),那么将会把数据集都遍历⼀遍。⽽如果排⼀下序那数据集就变成了:[0 1 2 3 4 5 6 7 8 9],按前⼀种⽅式我们进⾏了很多没有必要的查找,现在如果我们以5为分界点,那么数据集就被划分为了左右两个“簇” [0 1 2 3 4]和[6 7 8 9]。因此,根本就没有必要进⼊第⼀个簇,可以直接进⼊第⼆个簇进⾏查找。
下面通过一个例子来说明KD树的如何构造的。
给定一个二维数据集:T={(2, 3), (5, 4), (9, 6), (4, 7), (8, 1), (7, 2)}
,将其构造成一个平衡KD树。其结果如下:
首先将x和y分开成两个维度,然后选择方差更大的那个维度找出中位数
第一维度 x:2、5、9、4、8、7
第二维度 y:3、4、6、7、1、2
由于第一维度 x的方差更大(肉眼观察,x的分散程度更高,方差就更大),所以选x来排序。
排序后 第一维度 x:2、4、5、7、8、9
中位数是5和7的平均值:6
由于中位数是6,接下来选择最接近中位数的点来作为根节点时,这里既可以选(5, 4)又可以选(7, 2),它们x距离相同。这里选的是(7, 2)。
选择(7,2),所以树的第一层是(7,2)
此时,根据排序,在7左边的有 2、4、5,在7右边的有8、9。
对应的点是 (2, 3)、(4, 7)、(5, 4),(8, 1)、(9, 6)
接下来再对剩余的点进行划分,但这次是要根据第二维度y来找中位数。
左边的点的y排序:3、4、7,即点(2, 3)、(5, 4)、(4, 7),此时中位数是4,所以第二层左子树根节点是(5, 4)
右边的点的y排序:1、6,即点(8, 1)、(9, 6),此时中位数是5,随便选一个点(9, 6)作为根节点。
所以特征空间划分(图里面的线就是超平面)和KD树就是下面这样的:
假设标记为星星的点是待测试点, 绿⾊的点是初次找到的近似点,在回溯过程中,需要⽤到⼀个栈,用来存储需要回溯的点。每次回溯判断其他⼦节点是否有可能有距离查询点更近的数据点时。具体做法是以查询点为圆⼼,以当前的最近距离为半径画圆,这个圆称为候选超球,如果圆与回溯点的轴相交,则需要将轴另⼀边的节点都放到回溯栈中。之后继续弹栈并重复,直到栈空。
下面举两个例子。
查找点(2.1, 3.1)
查找点(2, 4.5)
Iris数据集是常⽤的分类实验数据集,由Fisher, 1936收集整理。Iris也称鸢尾花卉数据集,是⼀类多重变量分析的数据集。关于数据集的具体介绍:
通常一个领域的数据集选择是由该领域的行业专家来判断,不需要机器学习开发者来做。
sklearn.datasets
加载数据集,它有两种方式:
sklearn.datasets.load_xx()
:获取小规模数据集,sklearn本身就有,无需下载。
sklearn.datasets.load_iris()
sklearn.datasets.fetch_xx(datahome=None)
:获取大规模数据集,需要联网下载,参数datahome是下载到本地的位置,默认是~/scikit_learn_data/
sklearn.datasets.fetch_20newsgroups(data_home=None,subset=‘train’)
,其中subset可取训练集’train’、测试集’test’、全部’all’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)
下面通过seaborn来查看鸢尾花的数据分布情况,我另一篇博客有说明seaborn使用:机器学习入门 06 —— Seaborn使用
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.datasets import load_iris, fetch_20newsgroups
# 获取数据
iris = load_iris()
# 把数据转换成DataFrame的格式
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):
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')
通常机器学习的数据集会被划分为两个部分:
训练数据:⽤于训练、构建模型
测试数据:在模型检验时使⽤,⽤于评估模型是否有效
划分比例大致分为:
训练集:70%、80%、75%
测试集:30%、20%、25%
sklearn.model_selection.train_test_split(arrays, *options)
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# 1、获取鸢尾花数据集
iris = load_iris()
# 对鸢尾花数据集进⾏分割
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, 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", y_test == y_test1) # 数组中,有False,也有True,因为可能随机到相同的
print("如果随机数种⼦⼀致:\n", y_test1 == y_test2) # 全为True
定义:通过一些转换函数将特征数据转换成更适合算法模型的特征数据的过程(主要是归一化和标准化)。例如下图,将特征1234都转换到一个范围里。(这就是归一化)
特征的单位或者⼤⼩相差较⼤,或者某特征的⽅差相⽐其他的特征要⼤出⼏个数量级,容易影响(⽀配)⽬标结果,使得⼀些算法⽆法学习到其它的特征。所以,我们需要⽤到⼀些⽅法进⾏⽆量纲化,使不同规格的数据转换到同⼀规格。
定义:通过对原始数据进行变化,把数据映射到某个区间。(默认是[0, 1],所以叫归一)
公式如下:
作⽤于每⼀列,max为⼀列的最⼤值,min为⼀列的最⼩值,那么X’’为最终结果,mx,mi分别为指定区间值默认mx为1,mi为0
前面那张图就是归一化,其中每个特征都套用了这个公式。90转换到1,就是 x ′ = 90 − 60 90 − 60 x'=\frac{90-60}{90-60} x′=90−6090−60、 x ′ ′ = x ′ ( 1 − 0 ) + 0 = 1 x''=x'(1-0)+0=1 x′′=x′(1−0)+0=1。
代码实现归一化:
先实例化转换器对象MinMaxScaler(feature_range=(0, 1))
,再调用转换器的fit_transform(X)
方法进行转换。
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
def minmax_demo():
"""
归一化演示
:return:None
"""
data = pd.DataFrame({"特征1": [90, 60, 75],
"特征2": [2, 4, 3],
"特征3": [10, 15, 13],
"特征4": [40, 45, 46]})
print(data)
# 1. 实例化一个转换器对象;feature_range指定区间
transfer = MinMaxScaler(feature_range=(0, 1))
# 2. 调用转换器的fit_transform,开始转换
data = transfer.fit_transform(data[["特征1", "特征2", "特征3", "特征4"]])
print("归一化:\n", data)
minmax_demo()
如果数据中的异常点比较多,例如特征2中突然有个数据是100,这明显比其他数据大很多,那么归一化时就会对结果产生很大影响。因为归一化会受到最大和最小值影响,因此归一化的鲁棒性(稳定性)比较差,只适合传统精确的小数据场景。
标准化定义:通过对原始数据进⾏变换把数据变换到平均值为0,标准差为1范围内。对于标准化来说,如果出现异常点,由于具有⼀定数据量,少量的异常点对于平均值的影响并不⼤,从⽽⽅差改变较⼩。 更适合现代嘈杂大数据场景,因此常用的是标准化。
公式如下:
作⽤于每⼀列,mean为平均值,σ为标准差
这次我们把上面的特征2里的4改成100。
代码实现标准化:
先实例化转换器对象StandardScaler()
,再调用转换器的fit_transform(X)
方法进行转换。
import pandas as pd
from sklearn.preprocessing import StandardScaler
def stand_demo():
"""
标准化演示
:return:None
"""
data = pd.DataFrame({"特征1": [90, 60, 75],
"特征2": [2, 100, 3],
"特征3": [10, 15, 13],
"特征4": [40, 45, 46]})
print(data)
# 1. 实例化一个转换器对象;
transfer = StandardScaler()
# 2. 调用转换器的fit_transform,开始转换
data = transfer.fit_transform(data[["特征1", "特征2", "特征3", "特征4"]])
print("标准化:\n", pd.DataFrame(data))
print("每一列未转化特征值的平均值:", transfer.mean_)
print("每一列未转化特征的方差:", transfer.var_)
stand_demo()
fit()
:该函数是求得训练集X的均值,方差,最大值,最小值等这些训练集X固有的属性。transform()
:在fit的基础上,进行标准化,降维,归一化等操作(看具体用的是哪个工具,StandardScaler就是标准化)fit_transform()
:fit_transform是fit和transform的组合,既包括了训练又包含了转换。根据对之前部分trainData进行fit的整体指标,对剩余的数据(testData)使用同样的均值、方差、最大最小值等指标进行转换transform(testData),从而保证train、test处理方式相同。所以,在预处理阶段一般都是这么用:
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
sc.fit_tranform(X_train)
sc.tranform(X_test)
sklearn.neighbors.KNeighborsClassifier(n_neighbors=5,algorithm='auto')
下面完整展示对鸢尾花种类预测的流程
# -*- coding = utf-8 -*-
# @Time : 2021/8/5 10:17 上午
# @Author : zcy
# @File : 4.iris_example.py
# @Software : PyCharm
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
# K-近邻算法 —— 鸢尾花种类预测
# 实例数量:150(3个种类,0山鸢花、1变色鸢尾、2维吉尼亚鸢尾,每种各50个)
# 属性数量:4(数值型。萼片长度、萼片宽度、花瓣长度、花瓣宽度)
# 1. 获取数据集
iris = load_iris()
# 2. 数据基本处理 - 这里是只是把数据集划分为训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(
iris.data, iris.target, test_size=0.2, random_state=10)
# 3. 特征工程 - 特征预处理 标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test) # 这里看前面特征预处理部分,有解释
# 4. 机器学习 - KNN
# 4.1 实例化一个估计器
estimator = KNeighborsClassifier(n_neighbors=5)
# 4.2 估计器训练
estimator.fit(x_train, y_train)
# 5. 模型评估
# 5.1 预测值结果输出
y_pre = estimator.predict(x_test)
print("预测值是:\n", y_pre)
print("预测值和真实值的对比:\n", y_pre == y_test)
# 5.2 准确率
score = estimator.score(x_test, y_test)
print("准确率:\n", score)
结果每次运行都是下面这样,因为在划分数据时指定了random_state=10,如果去掉该属性,那么每次结果都随机。
优点:
是一种非常典型的分类监督学习算法,可以解决多分类的问题。
适合类域交叉样本,适合大样本的自动分类
整体思想简单
重新训练的代价低
精度高、对异常值不敏感、无数据输入假定。
缺点:
效率低,时间复杂度高、空间复杂度高
惰性学习,正是因为没有模型学习,所以效率更低
对不均衡的样本不擅长
解释性不强,类别评分不是规格化
计算量较大
交叉验证:数据处理中把数据集划分为训练数据和测试数据,而交叉验证则再把训练数据划分为训练集和验证集。如下图,将训练数据分为4分,一份作为验证集,另外三分作为训练集。然后进行N次测试,每次都更换不同的验证集(下图是进行4次验证),最后把所有验证结果取平均值,作为最终结果。这就是N折交叉验证。(下图是4折交叉验证)
注意:交叉验证只是让被评估的模型更加可信,并不能提高最后的准确率。
超参数:在sklearn中需要我们手动指定的参数,例如K-近邻里的K值。
网格搜索:一个模型通常都会有超参数,例如K-近邻的K,我们可能预设不同的K值,然后根据结果确定最好的K值。但这个过程比较麻烦,要反复调用函数,而网格搜索就是预先设置好超参数,每组超参数都采取交叉验证进行评估,最后选出最优参数建立模型。
sklearn.model_selection.GridSearchCV(estimator, param_grid=None,cv=None)
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
# K-近邻算法 —— 鸢尾花种类预测
# 实例数量:150(3个种类,山鸢花、变色鸢尾、维吉尼亚鸢尾,每种各50个)
# 属性数量:4(数值型。萼片长度、萼片宽度、花瓣长度、花瓣宽度)
# 1. 获取数据集
iris = load_iris()
# 2. 数据基本处理 - 这里是只是把数据集划分为训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(
iris.data, iris.target, test_size=0.2, random_state=10)
# 3. 特征工程 - 特征预处理 标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test) # fit_transform和transform的区别是 前者
# 4. 机器学习 - KNN
# 4.1 实例化一个估计器
estimator = KNeighborsClassifier() # 不指定K值了
# 4.2 模型选择与调优——⽹格搜索和交叉验证
# 准备要调的超参数
param_dict = {"n_neighbors": [1, 3, 5, 7]} # 预设K为 1、3、5、7,最后会选择一个最好的参数
estimator = GridSearchCV(estimator, param_grid=param_dict, cv=5) # 4折交叉验证
# 4.3 估计器训练
estimator.fit(x_train, y_train)
# 5. 模型评估
# 5.1 预测值结果输出
y_pre = estimator.predict(x_test)
print("预测值是:\n", y_pre)
print("预测值和真实值的对比:\n", y_pre == y_test)
# 5.2 准确率
score = estimator.score(x_test, y_test)
print("准确率:\n", score)
# 5.3 交叉验证和网格搜索的特有属性
print("在交叉验证中验证的最好结果:\n", estimator.best_score_)
print("最好的参数模型:\n", estimator.best_estimator_)
print("每次交叉验证后的准确率结果:\n", estimator.cv_results_)
项目数据集来自Kaggle:https://www.kaggle.com/c/facebook-v-predicting-check-ins
为了方便下载,我也上传到CSDN里了(免积分):https://download.csdn.net/download/qq_39763246/21002651
本次⽐赛的⽬的是预测⼀个⼈将要签到的地⽅。 为了本次⽐赛,Facebook创建了⼀个虚拟世界,其中包括10公⾥10 公⾥共100平⽅公⾥的约10*万个地⽅。 对于给定的坐标集,您的任务将根据⽤户的位置,准确性和时间戳等预测⽤户下⼀次的签到位置。 数据被制作成类似于来⾃移动设备的位置数据。 请注意:您只能使⽤提供的数据进⾏预测。
数据集情况:
id:签⼊事件的id
x y:坐标
accuracy: 准确度,定位精度
time: 时间戳
place_id: 签到的位置,这也是你需要预测的内容
步骤分析:
对于数据做⼀些基本处理
分割数据集
标准化处理
k-近邻预测
具体步骤:
# 1.获取数据集
# 2.基本数据处理
# 2.1 缩⼩数据范围
# 2.2 选择时间特征
# 2.3 去掉签到较少的地⽅
# 2.4 确定特征值和⽬标值
# 2.5 分割数据集
# 3.特征⼯程 -- 特征预处理(标准化)
# 4.机器学习 -- knn+cv
# 5.模型评估
具体代码如下(建议用jupyter编程,里面每个步骤单独运行查看):
import pandas as pd
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
# 1.获取数据集
facebook = pd.read_csv("FaceBook_train.csv")
facebook.head(3)
# 2. 数据基本处理
# 2.1 缩小数据范围以减少训练时间()
facebook_data = facebook.query("x > 2.0 & x < 3.0 & y > 2.0 & y < 3.0")
# 2.2 对time进行转换处理(time是时间戳,将其转为日期格式)
time = pd.to_datetime(facebook_data["time"], unit="s") # 时间戳的单位是秒,所以用unit设置下
time = pd.DatetimeIndex(time)
facebook_data["day"] = time.day # 在源数据里新增day列
facebook_data["week"] = time.week # 在源数据里新增week列
facebook_data["hour"] = time.hour # 在源数据里新增hour列
# 2.3 去除 签到 比较少的地方(place_id是地区编号,每一行签到都会属于一个地区)
place_count = facebook_data.groupby("place_id").count() # 根据地区编号进行分组聚合,统计每个地区有多少签到处
place_count = place_count[place_count["row_id"]>3] #根据统计结果,筛选出签到处大于3的地区
# place_count此时只包含签到处大于3的地区,但不是一个完整的表,根据place_count的索引(索引就是place_id)来获取完整数据
facebook_data = facebook_data[facebook_data["place_id"].isin(place_count.index)]
# 2.4 确定特征值和目标值
x = facebook_data[["x", "y", "accuracy", "day", "week", "hour"]] # 特征值
y = facebook_data["place_id"] # 目标值
# 2.5 分割数据
x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=10)
# 3. 特征工程 —— 特征预处理 标准化
# 3.1 实例化一个转换器
transfer = StandardScaler()
# 3.2 开始转换
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 4. 机器学习 KNN
# 4.1 实例化一个估计器
estimator = KNeighborsClassifier()
# 4.2 交叉验证、网格搜索
param_grid = {"n_neighbors":[3, 5, 7, 9]}
# n_jobs表示用几核CPU来跑这个程序,我的电脑是8核,-1表示整个CPU都来跑,花了12秒。
estimator = GridSearchCV(estimator=estimator, param_grid=param_grid, cv=3, n_jobs=6)
# 4.3 模型训练
estimator.fit(x_train, y_train)
# 5. 模型评估
# 5.1 基本评估方式
score = estimator.score(x_test, y_test)
print("预测的准确率:", score)
y_predic = estimator.predict(x_test)
print("预测值为:", y_predic)
print("预测试和真实值的对比:", y_predic == y_test)
# 5.2 交叉验证的评估
print("在交叉验证中的最好结果:", estimator.best_score_)
print("在交叉验证中的最好参数模型:", estimator.best_estimator_)
print("每次交叉验证后的验证集和训练集的准确率结果:", estimator.cv_results_)
效果:准确度这么低是因为数据只使用了一部分