分类算法之k-近邻
k-近邻算法采用测量不同特征值之间的距离来进行分类
优点:精度高、对异常值不敏感、无数据输入假定
缺点:计算复杂度高、空间复杂度高
使用数据范围:数值型和标称型
一个例子弄懂k-近邻
电影可以按照题材分类,每个题材又是如何定义的呢?那么假如两种类型的电影,动作片和爱情片。动作片有哪些公共的特征?那么爱情片又存在哪些明显的差别呢?我们发现动作片中打斗镜头的次数较多,而爱情片中接吻镜头相对更多。当然动作片中也有一些接吻镜头,爱情片中也会有一些打斗镜头。所以不能单纯通过是否存在打斗镜头或者接吻镜头来判断影片的类别。那么现在我们有6部影片已经明确了类别,也有打斗镜头和接吻镜头的次数,还有一部电影类型未知。
电影名称 | 打斗镜头 | 接吻镜头 | 电影类型 |
---|---|---|---|
California Man | 3 | 104 | 爱情片 |
He's not Really into dues | 2 | 100 | 爱情片 |
Beautiful Woman | 1 | 81 | 爱情片 |
Kevin Longblade | 101 | 10 | 动作片 |
Robo Slayer 3000 | 99 | 5 | 动作片 |
Amped II | 98 | 2 | 动作片 |
? | 18 | 90 | 未知 |
那么我们使用K-近邻算法来分类爱情片和动作片:存在一个样本数据集合,也叫训练样本集,样本个数M个,知道每一个数据特征与类别对应关系,然后存在未知类型数据集合1个,那么我们要选择一个测试样本数据中与训练样本中M个的距离,排序过后选出最近的K个,这个取值一般不大于20个。选择K个最相近数据中次数最多的分类。那么我们根据这个原则去判断未知电影的分类
电影名称 | 与未知电影的距离 |
---|---|
California Man | 20.5 |
He's not Really into dues | 18.7 |
Beautiful Woman | 19.2 |
Kevin Longblade | 115.3 |
Robo Slayer 3000 | 117.4 |
Amped II | 118.9 |
我们假设K为3,那么排名前三个电影的类型都是爱情片,所以我们判定这个未知电影也是一个爱情片。那么计算距离是怎样计算的呢?
欧氏距离 那么对于两个向量点a1a_{1}a1和a2a_{2}a2之间的距离,可以通过该公式表示:
(x1−x2)2+(y1−y2)2sqrt{left({x_{1}-x_{2}} ight)^{2}+left({y_{1}-y_{2}} ight)^{2}}√(x1−x2)2+(y1−y2)2
如果说输入变量有四个特征,例如(1,3,5,2)和(7,6,9,4)之间的距离计算为:
(1−7)2+(3−6)2+(5−9)2+(2−4)2sqrt{left({1-7} ight)^{2}+left({3-6} ight)^{2}+left({5-9} ight)^{2}+left({2-4} ight)^{2}}√(1−7)2+(3−6)2+(5−9)2+(2−4)2
sklearn.neighbors
sklearn.neighbors提供监督的基于邻居的学习方法的功能,sklearn.neighbors.KNeighborsClassifier是一个最近邻居分类器。那么KNeighborsClassifier是一个类,我们看一下实例化时候的参数
class sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, weights='uniform', algorithm='auto', leaf_size=30, p=2, metric='minkowski', metric_params=None, n_jobs=1, **kwargs)**
"""
:param n_neighbors:int,可选(默认= 5),k_neighbors查询默认使用的邻居数
:param algorithm:{'auto','ball_tree','kd_tree','brute'},可选用于计算最近邻居的算法:'ball_tree'将会使用 BallTree,'kd_tree'将使用 KDTree,“野兽”将使用强力搜索。'auto'将尝试根据传递给fit方法的值来决定最合适的算法。
:param n_jobs:int,可选(默认= 1),用于邻居搜索的并行作业数。如果-1,则将作业数设置为CPU内核数。不影响fit方法。
"""
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
neigh = KNeighborsClassifier(n_neighbors=3)
Method
fit(X, y)
使用X作为训练数据拟合模型,y作为X的类别值。X,y为数组或者矩阵
X = np.array([[1,1],[1,1.1],[0,0],[0,0.1]])
y = np.array([1,1,0,0])
neigh.fit(X,y)
kneighbors(X=None, n_neighbors=None, return_distance=True)
找到指定点集X的n_neighbors个邻居,return_distance为False的话,不返回距离
neigh.kneighbors(np.array([[1.1,1.1]]),return_distance= False)
neigh.kneighbors(np.array([[1.1,1.1]]),return_distance= False,an_neighbors=2)
predict(X)
预测提供的数据的类标签
neigh.predict(np.array([[0.1,0.1],[1.1,1.1]]))
predict_proba(X)
返回测试数据X属于某一类别的概率估计
neigh.predict_proba(np.array([[1.1,1.1]]))
k-近邻算法案例分析
本案例使用最著名的”鸢尾“数据集,该数据集曾经被Fisher用在经典论文中,目前作为教科书般的数据样本预存在Scikit-learn的工具包中。
读入Iris数据集细节资料
from sklearn.datasets import load_iris
# 使用加载器读取数据并且存入变量iris
iris = load_iris()
# 查验数据规模
iris.data.shape
# 查看数据说明(这是一个好习惯)
print iris.DESCR
通过上述代码对数据的查验以及数据本身的描述,我们了解到Iris数据集共有150朵鸢尾数据样本,并且均匀分布在3个不同的亚种;每个数据样本有总共4个不同的关于花瓣、花萼的形状特征所描述。由于没有制定的测试集合,因此按照惯例,我们需要对数据进行随即分割,25%的样本用于测试,其余75%的样本用于模型的训练。
由于不清楚数据集的排列是否随机,可能会有按照类别去进行依次排列,这样训练样本的不均衡的,所以我们需要分割数据,已经默认有随机采样的功能。
对Iris数据集进行分割
from sklearn.cross_validation import train_test_split
X_train,X_test,y_train,y_test = train_test_split(iris.data,iris.target,test_size=0.25,random_state=42)
对特征数据进行标准化
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
X_train = ss.fit_transform(X_train)
X_test = ss.fit_transform(X_test)
K近邻算法是非常直观的机器学习模型,我们可以发现K近邻算法没有参数训练过程,也就是说,我们没有通过任何学习算法分析训练数据,而只是根据测试样本训练数据的分布直接作出分类决策。因此,K近邻属于无参数模型中非常简单一种。
from sklearn.datasets import load_iris
from sklearn.cross_validation import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import classification_report
from sklearn.model_selection import GridSearchCV
def knniris():
"""
鸢尾花分类
:return: None
"""
# 数据集获取和分割
lr = load_iris()
x_train, x_test, y_train, y_test = train_test_split(lr.data, lr.target, test_size=0.25)
# 进行标准化
std = StandardScaler()
x_train = std.fit_transform(x_train)
x_test = std.transform(x_test)
# estimator流程
knn = KNeighborsClassifier()
# # 得出模型
# knn.fit(x_train,y_train)
#
# # 进行预测或者得出精度
# y_predict = knn.predict(x_test)
#
# # score = knn.score(x_test,y_test)
# 通过网格搜索,n_neighbors为参数列表
param = {"n_neighbors": [3, 5, 7]}
gs = GridSearchCV(knn, param_grid=param, cv=10)
# 建立模型
gs.fit(x_train,y_train)
# print(gs)
# 预测数据
print(gs.score(x_test,y_test))
# 分类模型的精确率和召回率
# print("每个类别的精确率与召回率:",classification_report(y_test, y_predict,target_names=lr.target_names))
return None
if __name__ == "__main__":
knniris()