定义:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。通俗来说,就是根据你的邻居来推断你的类别
来源:KNN算法最早是由Cover和Hart提出的一种分类算法
相似的样本,特征之间的值应该都是相近的
K-近邻算法需要对数据作标准化处理
https://www.kaggle.com/c/facebook-v-predicting-check-ins
题意分析:
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler
# 一、数据集的处理
# 读取数据
data = pd.read_csv('./data/train.csv')
# 处理数据
# 1.缩小数据-缩小数据集范围 DataFrame.query()查询数据筛选
data = data.query('x>1.0 & x<1.25 & y>2.5 & y<2.75')
# 2.处理时间数据
time_value = pd.to_datetime(data['time'], unit='s')
# 3、增加分割的日期数据
# 把日期格式转化成字典格式
time_value = pd.DatetimeIndex(time_value)
# 根据时间 构造一些特征
data.loc[:, 'day'] = time_value.day
data.loc[:, 'hour'] = time_value.hour
data.loc[:, 'weekday'] = time_value.weekday
# 4、删除没用的日期数据
# 把时间戳特征删除,axis的重点在于方向而不在于行或列
# axis = 0表示纵轴表示数据的变化从上至下,体现在行的增加与减少
# axis = 1表示横轴表示数据的变化从左至右,体现在列的增加与减少
data = data.drop(labels='time', axis=1)
# 5.将少于n个用户的签到位置删除
place_count = data.groupby('place_id').count()
tf = place_count[place_count.row_id > 3].reset_index()
# 过滤后的表格
data = data[data['place_id'].isin(tf.place_id)]
# 删除无用的row_id
data = data.drop(labels='row_id', axis=1)
print(data)
# 取出数据中的目标值和特征值
y = data["place_id"]
x = data.drop(labels='place_id', axis=1)
# 二、分割数据集
# 进行数据的分割-训练集测试集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25)
# 三、对数据集进行标准化
# 特征工程(标准化)
std = StandardScaler()
# 对训练集与测试集的特征值进行标准化
x_train = std.fit_transform(x_train)
x_test = std.transform(x_test)
# 四、estimator流程进行分类预测
# 进行算法流程-estimator流程进行分类预测
knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(x_train, y_train)
# 得到预测结果
y_predict = knn.predict(x_test)
print('预测的目标签到位置为:', y_predict)
# 得到预测的准确率-预测值与真实值进行比较
print('预测的准确率为:', knn.score(x_test, y_test))
优点:
缺点:
小数据场景,几千~几万样本,具体场景具体业务去测试
算出属于每个类别的概率,取最高的概率
(朴素=>条件独立的意思)
朴素贝叶斯-贝叶斯公式:
理论上,概率模型分类器是一个条件概率模型。
p ( C ∣ F 1 , … , F n ) p(C\vert F_{1},\dots ,F_{n})\, p(C∣F1,…,Fn)
独立的类别变量 C C C 有若干类别,条件依赖于若干特征变量 F 1 , F 2 F 2 , . . . , F n F_{1},{\displaystyle F_{2}}F_{2},...,F_n F1,F2F2,...,Fn。但问题在于如果特征数量 n n n 较大或者每个特征能取大量值时,基于概率模型列出概率表变得不现实。所以我们修改这个模型使之变得可行。 贝叶斯定理有以下式子:
p ( C ∣ F 1 , … , F n ) = p ( C ) p ( F 1 , … , F n ∣ C ) p ( F 1 , … , F n ) . = 1 Z p ( C ) ∏ i = 1 n p ( F i ∣ C ) p(C\vert F_{1},\dots ,F_{n})={\frac {p(C)\ p(F_{1},\dots ,F_{n}\vert C)}{p(F_{1},\dots ,F_{n})}}.\,\\ = {\frac {1}{Z}}p(C)\prod _{{i=1}}^{n}p(F_{i}\vert C) p(C∣F1,…,Fn)=p(F1,…,Fn)p(C) p(F1,…,Fn∣C).=Z1p(C)i=1∏np(Fi∣C)
其中 Z Z Z (证据因子)是一个只依赖与 F 1 , … , F n F_{1},\dots ,F_{n} F1,…,Fn 等的缩放因子,当特征变量的值已知时是一个常数。 由于分解成所谓的类先验概率 p ( C ) p(C) p(C) 和独立概率分布 p ( F i ∣ C ) p(F_{i}\vert C) p(Fi∣C),上述概率模型的可掌控性得到很大的提高。
https://zhuanlan.zhihu.com/p/87832246
https://zhuanlan.zhihu.com/p/26329951
计算每个分类样本集中每个特征出现的概率,但是这个时候会出现一个问题:可能当前分类样本集中有一个特征 F i F_i Fi 未出现,就会导致的分子项为0,也就是概率为0,进而产生对新样本进行预测时,连积为0.
拉普拉斯平滑就是解决贝叶斯分类问题下的零概率问题!
对类别 C C C 下,特征 F i F_i Fi 的取值加 α \alpha α,同时为了满足特征 F i F_i Fi 所有特征值的概率和为1,也要为分母加上特征取值个数 * α \alpha α。
p ( F i ∣ C ) = n i + α N + α m p(F_i|C) = \frac{n_i + \alpha}{N + \alpha m} p(Fi∣C)=N+αmni+α
其中, α \alpha α 系数一般为 1, m m m 为类别 C C C 的取值个数
推导:https://zhuanlan.zhihu.com/p/24291822
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB
news = fetch_20newsgroups(subset='all')
# 进行数据分割
x_train, x_test, y_train, y_test = train_test_split(news.data, news.target, test_size=0.25)
# 对数据集进行特征抽取
tf = TfidfVectorizer()
# 以训练集当中的词的列表进行每篇文章重要性统计['a','b','c','d']
x_train = tf.fit_transform(x_train)
print(len(tf.get_feature_names()))
x_test = tf.transform(x_test)
# 进行朴素贝叶斯算法的预测
mlt = MultinomialNB(alpha=1.0)
print(len(x_train.toarray()))
mlt.fit(x_train, y_train)
y_predict = mlt.predict(x_test)
print("预测的文章类别为:", y_predict)
# 得出准确率
print("准确率为:", mlt.score(x_test, y_test))
print("每个类别的精确率和召回率:", classification_report(y_test, y_predict, target_names=news.target_names))
152002
14134
预测的文章类别为: [ 7 15 7 ... 7 15 16]
准确率为: 0.8539898132427843
每个类别的精确率和召回率:
precision recall f1-score support
alt.atheism 0.90 0.77 0.83 202
comp.graphics 0.86 0.76 0.81 246
comp.os.ms-windows.misc 0.82 0.87 0.85 237
comp.sys.ibm.pc.hardware 0.78 0.84 0.81 246
comp.sys.mac.hardware 0.90 0.88 0.89 240
comp.windows.x 0.96 0.81 0.87 272
misc.forsale 0.91 0.67 0.77 249
rec.autos 0.85 0.93 0.89 222
rec.motorcycles 0.96 0.95 0.96 253
rec.sport.baseball 0.92 0.97 0.94 243
rec.sport.hockey 0.93 0.96 0.94 253
sci.crypt 0.79 0.98 0.87 251
sci.electronics 0.88 0.84 0.86 224
sci.med 0.96 0.89 0.93 244
sci.space 0.90 0.95 0.92 260
soc.religion.christian 0.56 1.00 0.72 242
talk.politics.guns 0.77 0.97 0.86 234
talk.politics.mideast 0.92 0.97 0.94 241
talk.politics.misc 1.00 0.58 0.73 201
talk.religion.misc 1.00 0.20 0.34 152
accuracy 0.85 4712
macro avg 0.88 0.84 0.84 4712
weighted avg 0.88 0.85 0.85 4712
优点:
缺点:
其他:
在分类任务下,预测结果(Predicted Condition)
与正确标记(True Condition)之间存在四种不同的组合,构成混淆矩阵(适用于多分类)
https://blog.csdn.net/xys430381_1/article/details/88198167
estimator.score()
一般最常见使用的是准确率,即预测结果正确的百分比F 1 S c o r e = 1 T P 2 T P + F N + F P = 2 P R P + R F1\ Score = \frac{1TP}{2TP + FN + FP} = \frac{2PR}{P+R} F1 Score=2TP+FN+FP1TP=P+R2PR
其中,P 代表 Precision,R 代表 Recall。
F1-Score 指标综合了 Precision 与 Recall 的产出的结果。F1-Score 的取值范围从 0 到 1 的,1 代表模型的输出最好,0 代表模型的输出结果最差。
F1-score,反应了模型的稳健性
https://www.zhihu.com/question/19645541
交叉验证:为了让被评估的模型更加准确可信
交叉验证过程:
通常情况下,有很多参数是需要手动指定的(如k-近邻算法中的K值),这种叫超参数。但是手动过程繁杂,所以需要对模型预设几种超参数组合。每组超参数都采用交叉验证来进行评估。最后选出最优参数组合建立模型。
https://www.kaggle.com/c/facebook-v-predicting-check-ins
from sklearn.neighbors import KNeighborsClassifier
import pandas as pd
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
# 一、数据集的处理
# 读取数据
data = pd.read_csv('./data/train.csv')
# 处理数据
# 1.缩小数据-缩小数据集范围 DataFrame.query()查询数据筛选
data = data.query('x>1.0 & x<1.25 & y>2.5 & y<2.75')
# 2.处理时间数据
time_value = pd.to_datetime(data['time'], unit='s')
# 3、增加分割的日期数据
# 把日期格式转化成字典格式
time_value = pd.DatetimeIndex(time_value)
# 根据时间 构造一些特征
data.loc[:, 'day'] = time_value.day
data.loc[:, 'hour'] = time_value.hour
data.loc[:, 'weekday'] = time_value.weekday
# 4、删除没用的日期数据
# 把时间戳特征删除,axis的重点在于方向而不在于行或列
# axis = 0表示纵轴表示数据的变化从上至下,体现在行的增加与减少
# axis = 1表示横轴表示数据的变化从左至右,体现在列的增加与减少
data = data.drop(labels='time', axis=1)
# 5.将签到位置少于n个用户的删除
place_count = data.groupby('place_id').count()
tf = place_count[place_count.row_id > 3].reset_index()
# 过滤后的表格
data = data[data['place_id'].isin(tf.place_id)]
# 删除无用的row_id
data = data.drop(labels='row_id', axis=1)
print(data)
# 取出数据中的目标值和特征值
y = data["place_id"]
x = data.drop(labels='place_id', axis=1)
# 二、分割数据集
# 进行数据的分割-训练集测试集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25)
# 三、对数据集进行标准化
# 特征工程(标准化)
std = StandardScaler()
# 对训练集与测试集的特征值进行标准化
x_train = std.fit_transform(x_train)
x_test = std.transform(x_test)
# 四、estimator流程进行分类预测
# 进行算法流程-estimator流程进行分类预测
knn = KNeighborsClassifier()
# 五、算法调优-网格搜索
# 构造一些参数的值进行搜索
param = {'n_neighbors': [3, 5, 10]}
# 交叉验证分为两组
gc = GridSearchCV(knn, param_grid=param, cv=2)
gc.fit(x_train, y_train)
# 预测准确率
print('在测试集上的准确率:\n', gc.score(x_test, y_test))
print('在交叉验证中最好的结果:\n', gc.best_score_)
print('最好的参数模型:\n', gc.best_estimator_)
print('每个超参数每次交叉验证后的结果:\n', gc.cv_results_)