机器学习算法基础 3

K-近邻算法(KNN)

定义:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。通俗来说,就是根据你的邻居来推断你的类别
来源:KNN算法最早是由Cover和Hart提出的一种分类算法

计算距离公式(欧氏距离)(重点)

相似的样本,特征之间的值应该都是相近的

K-近邻算法需要对数据作标准化处理

K-近邻算法实例-预测入住位置

https://www.kaggle.com/c/facebook-v-predicting-check-ins

题意分析:

  • 特征值:x、y 坐标,定位准确性,时间戳
  • 目标值:入住位置 id
  • 问题类型:分类类型
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))

问题

  1. k值(n_neighbors)取多大?有什么影响?
    k值取很小:容易受异常点影响;k值取很大:容易受最近数据太多导致比例变化
  2. 性能问题

k-近邻算法优缺点

优点:

  • 简单,易于理解,易于实现,无需估计参数,无需训练

缺点:

  • 懒惰算法,对测试样本分类时的计算量大,内存开销大
  • 必须指定K值,K值选择不当则分类精度不能保证

使用场景

小数据场景,几千~几万样本,具体场景具体业务去测试

朴素贝叶斯算法

算出属于每个类别的概率,取最高的概率

(朴素=>条件独立的意思)

朴素贝叶斯-贝叶斯公式:

理论上,概率模型分类器是一个条件概率模型。

p ( C ∣ F 1 , … , F n )   p(C\vert F_{1},\dots ,F_{n})\, p(CF1,,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(CF1,,Fn)=p(F1,,Fn)p(C) p(F1,,FnC).=Z1p(C)i=1np(FiC)

其中 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(FiC),上述概率模型的可掌控性得到很大的提高。

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(FiC)=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

特点

优点:

  1. 朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率。
  2. 对缺失数据不太敏感,算法也比较简单,常用于文本分类。
  3. 分类准确度高,速度快

缺点:

  1. 训练集误差大时,结果肯定不好;不允许调参
  2. 由于使用样本属性独立性的假设,故样本属性有关联时,其效果最好

其他:

  1. 不需要调参
  2. 神经网络的效果更好

分类模型评估

混淆矩阵

在分类任务下,预测结果(Predicted Condition)
与正确标记(True Condition)之间存在四种不同的组合,构成混淆矩阵(适用于多分类)

https://blog.csdn.net/xys430381_1/article/details/88198167

二级指标

  • 准确率(accuracy) = 预测对的/所有 = (TP+TN)/(TP+FN+FP+TN)
    • estimator.score() 一般最常见使用的是准确率,即预测结果正确的百分比
  • 精确率(precision) = TP/(TP+FP)
  • 召回率(recall) = TP/(TP+FN)

三级指标

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

模型的选择与调优

交差验证

交叉验证:为了让被评估的模型更加准确可信

交叉验证过程:

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

网格搜索(超参数搜索)

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

  • 多个超参数时,对模型预设多超参数组合,如,二个参数-两两组合、三个参数-三三组合,
  • 每组超参数采用交叉验证(一般采用10折交叉验证)来进行评估,最后选出最优参数组合建立模型

案例 (GridSearchCV)

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_)

你可能感兴趣的:(机器学习,算法,人工智能)