k近邻算法(KNN)
定义:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
来源:KNN算法最早是由Cover和Hart提出的一种分类算法
优点:
简单,易于理解,易于实现,无需估计参数,无需训练
缺点:
懒惰算法,对测试样本分类时的计算量大,内存开销大
必须指定K值,K值选择不当则分类精度不能保证
使用场景:小数据场景,几千~几万样本,具体情况具体分析
api: sklearn.neighbors.KNeighborsClassifier
k近邻算法实例-预测入住位置
数据来源:kaggle预测入住位置
x, y为位置坐标,accuracy准确率暂时没用上,time入住时间,place_id入住位置
import pandas as pd
from sklearn.neighbors import KNeighborsClassifier # KNN
from sklearn.model_selection import train_test_split # 数据集划分
from sklearn.preprocessing import StandardScaler # 标准化
data = pd.read_csv(r'C:\Users\Administrator\Downloads\机器学习代码和资料\facebook-v-predicting-check-ins_2\train\train.csv')
# step1 : 把data处理成我们需要的数据
data = data.query('x>1.25 & x < 1.5 & y > 2.5 & y < 2.75') # 使用一小部分数据,太大了跑不动
time_vue = pd.to_datetime(data['time'],unit='s')
'''# 构造一些特征
time_vue = pd.DatetimeIndex(time_vue) # 把日期格式转换成 字典格式
data['day'] = time_vue.day
data['hour'] = time_vue.hour
data['weekday'] = time_vue.weekday
data.drop(['time'], axis=1,inplace=True)'''
place_cnt = data.groupby('place_id').count()
tf = place_cnt[place_cnt.x>3].reset_index() # 筛选出cnt>3的行后重设index
data = data[data['place_id'].isin(tf.place_id)] # 从data表中选出那些place_id也tf中也存在的行
data.drop('row_id',axis=1,inplace=True) # 删除列时要axis=1
# step2 prepocess
x_train, x_test, y_train, y_test = train_test_split(data.drop('place_id',axis=1),data['place_id'],test_size=.25)
std = StandardScaler()
x_train = std.fit_transform(x_train)
x_test = std.transform(x_test)
# step 3 使用api进行预测
knn = KNeighborsClassifier(n_neighbors=5) # 指定k
knn.fit(x_train,y_train) # 训练
y_predict = knn.predict(x_test) # 用测试集进行预测
print('预测结果为:',y_predict)
print("准确率为:",knn.score(x_test,y_test))
jupy运行截图:
朴素贝叶斯
条件概率:就是事件A在另外一个事件B已经发生条件下的发生概率
记作:\(P(B|A) = \frac{P(AB)}{P(A)}\)
全概率公式:\(P(B) = \sum P(A_i)P(B|A_i)\)
\(P(A|B)=\frac{P(AB)}{P(B)}\),分母条件概率,分子全概率展开得
贝叶斯公式:\(P(A|B) = \frac{P(B|A)*P(A)}{\sum P(A_i)P(B|A_i)}\)
拉普拉斯平滑系数:
从上面的例子我们得到娱乐概率为0,这是不合理的,如果词频列表里面
有很多出现次数都为0,很可能计算结果都为零
解决方法:拉普拉斯平滑系数
\(P(F1│C)=\frac{Ni+α}{N+αm}\)
\(α\)为指定的系数一般为1,\(m\)为训练文档中统计出的特征词个数
朴素贝叶斯api:sklearn.naive_bayes.MultinomialNB
优点:
朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率。
对缺失数据不太敏感,算法也比较简单,常用于文本分类。
分类准确度高,速度快
缺点:
需要知道先验概率P(F1,F2,…|C),因此在某些时候会由于假设的先验
模型的原因导致预测效果不佳。
from sklearn.preprocessing import StandardScaler
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.datasets import fetch_20newsgroups
from sklearn.model_selection import train_test_split
import pandas as pd
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(tf.get_feature_names())
x_test = tf.transform(x_test)
# 进行朴素贝叶斯算法的预测
mlt = MultinomialNB(alpha=1.0) # alpha拉普拉斯平滑系数
print(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))
精确率和召回率
二分类和一些概念:
A binary classifier is an algorithm that predicts the classes of instances, which may be positive (\({+}\)) or negative (\({-}\)). A typical binary classifier consists of a scoring function \({S}\) that gives a score for every instance and a threshold \(\theta\) that determines the category. Specifically, if the score of an instance \(S(x) \geq \theta\), then the instance \({x}\)
Of course, a binary classifier may have misclassification: it could either classify a positive instance as negative (false negative) or classify a negative instance as positive (false positive).
Given a dataset and a classifier, we may define the true positive rate \({TPR}\) and the false positive rate \({FPR}\) as follows:
\({TPR} = \frac{\# {TP}} {\# {TP} + \# {FN}}, \quad {FPR} = \frac{\# {FP}} {\# {TN} + \# {FP}}\)
where \(\# TP\) is the number of true positives in the dataset; \(\# FP\), \(\#TN\), \(\#FN\)
Now you have trained a scoring function, and you want to evaluate the performance of your classifier. The classifier may exhibit different TPR and FPR if we change the threshold \(\theta\). Let \({TPR}(\theta), FPR(\theta)\) be the \({TPR, FPR}\) when the threshold is \(\theta\), define the \({area\;under\;curve}\) (\({AUC}\)) as
\({AUC} = \int_{0}^{1} \max_{\theta \in \mathbb{R}} \{TPR(\theta)|FPR(\theta) \leq r\}\)
where the integrand, called \({receiver\;operating\;characteristic}\) (ROC), means the maximum possible of \({TPR}\) given that \(FPR \leq r\).
精确率(Precision)与召回率(Recall)
精确率是针对我们预测结果而言的,它表示的是预测为正的样本中有多少是真正的正样本。那么预测为正就有两种可能了,一种就是把正类预测为正类(TP),另一种就是把负类预测为正类(FP),也就是
\(P = \frac{TP}{TP+FP}\)
而召回率是针对我们原来的样本而言的,它表示的是样本中的正例有多少被预测正确了。那也有两种可能,一种是把原来的正类预测成正类(TP),另一种就是把原来的正类预测为负类(FN)。
\(R = \frac{TP}{TP+FN}\)
在信息检索领域,精确率和召回率又被称为查准率和查全率,
查准率=检索出的相关信息量 / 检索出的信息总量
查全率=检索出的相关信息量 / 系统中的相关信息总量
交叉验证与网格搜索对K-近邻算法调优
交叉验证:为了让被评估的模型更加准确可信
过程:将拿到的数据,分为训练和验证集。以下图为例:将数据分成5份,其中一份作为验证集。然后经过5次(组)的测试,每次都更换不同的验证集。即得到5组模型的结果,取平均值作为最终结果。又称5折交叉验证。
超参数搜索-网格搜索:KNN调优
通常情况下,有很多参数是需要手动指定的(如k-近邻算法中的K值),这种叫超参数。但是手动过程繁杂,所以需要对模型预设几种超参数组合。每组超参数都采用交叉验证来进行评估。最后选出最优参数组合建立模型。
(source)在k折交叉验证方法中其中K-1份作为训练数据,剩下的一份作为验真数据:
这个过程一共需要进行K次,将最后K次使用实现选择好的评分方式的评分求平均返回,然后找出最大的一个评分对用的参数组合。这也就完成了交叉验证这一过程。
api:sklearn.model_selection.GridSearchCV(GridSearchCV可以拆分为两部分,GridSearch和CV,即网格搜索和交叉验证。)
# 读取数据
data = pd.read_csv("./data/FBlocation/train.csv")
# print(data.head(10))
# 处理数据
# 1、缩小数据,查询数据晒讯
data = data.query("x > 1.0 & x < 1.25 & y > 2.5 & y < 2.75")
# 处理时间的数据
time_value = pd.to_datetime(data['time'], unit='s')
print(time_value)
# 把日期格式转换成 字典格式
time_value = pd.DatetimeIndex(time_value)
# 构造一些特征
data['day'] = time_value.day
data['hour'] = time_value.hour
data['weekday'] = time_value.weekday
# 把时间戳特征删除
data = data.drop(['time'], axis=1)
print(data)
# 把签到数量少于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)]
# 取出数据当中的特征值和目标值
y = data['place_id']
x = data.drop(['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)
# 进行算法流程 # 超参数
knn = KNeighborsClassifier()
# 构造一些参数的值进行搜索
param = {"n_neighbors": [3, 5, 10]}
# 进行网格搜索
gc = GridSearchCV(knn, param_grid=param, cv=2)
gc.fit(x_train, y_train)
# 预测准确率
print("在测试集上准确率:", gc.score(x_test, y_test))
print("在交叉验证当中最好的结果:", gc.best_score_)
print("选择最好的模型是:", gc.best_estimator_)
print("每个超参数每次交叉验证的结果:", gc.cv_results_)