前言

在机器学习的世界里,有监督学习与无监督学习如同“两条腿”并驾齐驱。而朴素贝叶斯(Naïve Bayes) 和K-Means聚类,分别是这两大分支中最为经典、应用广泛的入门级算法。
朴素贝叶斯基于贝叶斯定理,借助“特征条件独立”这一强力假设,将复杂的联合概率计算大大简化,在文本分类、垃圾邮件过滤、情感分析等任务中表现高效且稳健。

K-Means聚类则是一种典型的无监督学习算法,通过迭代寻找最优的聚类中心,将相似的样本自动归为一类,在用户画像、图像分割、异常检测等场景中扮演重要角色。


朴素贝叶斯

朴素贝叶斯介绍

常见的概率公式

在这里插入图片描述
条件概率: 表示事件A在另外一个事件B已经发生条件下的发生概率,P(A|B)

在女神喜欢的条件下,职业是程序员的概率?

  1. 女神喜欢条件下,有 2、3、4、7 共 4 个样本
  2. 4 个样本中,有程序员 3、4 共 2 个样本
  3. 则 P(程序员|喜欢) = 2/4 = 0.5

联合概率: 表示多个条件同时成立的概率,P(AB) = P(A) P(B|A)
特征条件独立性假设:P(AB) = P(A) P(B)

职业是程序员并且体型匀称的概率?

  1. 数据集中,共有 7 个样本
  2. 职业是程序员有 1、3、4 共 3 个样本,则其概率为:3/7
  3. 在职业是程序员,体型是匀称有 3 共 1 个样本,则其概率为:1/3
  4. 则即是程序员又体型匀称的概率为:3/7 * 1/3 = 1/7

联合概率 + 条件概率:

在女神喜欢的条件下,职业是程序员、体重超重的概率? P(AB|C) = P(A|C) P(B|AC)

  1. 在女神喜欢的条件下,有 2、3、4、7 共 4 个样本
  2. 在这 4 个样本中,职业是程序员有 3、4 共 2 个样本,则其概率为:2/4=0.5
  3. 在在 2 个样本中,体型超重的有 4 共 1 个样本,则其概率为:1/2 = 0.5
  4. 则 P(程序员, 超重|喜欢) = 0.5 * 0.5 = 0.25

简言之:
条件概率:在去掉部分样本的情况下,计算某些样本的出现的概率,表示为:P(B|A)
联合概率:多个事件同时发生的概率是多少,表示为:P(AB) = P(B)*P(A|B)

贝叶斯公式

在这里插入图片描述

  1. P© 表示 C 出现的概率
  2. P(W|C) 表示 C 条件 W 出现的概率
  3. P(W) 表示 W 出现的概率

在这里插入图片描述

  1. P(C|W) = P(喜欢|程序员,超重)
  2. P(W|C) = P(程序员,超重|喜欢)
  3. P© = P(喜欢)
  4. P(W) = P(程序员,超重)

  1. 根据训练样本估计先验概率P©:P(喜欢) = 4/7
  2. 根据条件概率P(W|C)调整先验概率:P(程序员,超重|喜欢) = 1/4
  3. 此时我们的后验概率P(C|W)为:P(程序员,超重|喜欢) * P(喜欢) = 4/7 * 1/4 = 1/7
  4. 那么该部分数据占所有既为程序员,又超重的人中的比例是多少呢?
    1. P(程序员,超重) = P(程序员) * P(超重|程序员) = 3/7 * 2/3 = 2/7
    2. P(喜欢|程序员, 超重) = 1/7 ➗ 2/7 = 0.5

朴素贝叶斯

贝叶斯概率计算过程中,需要计算 P(程序员,超重|喜欢) 和 P(程序员, 超重) 等联合概率,为了简化联合概率的计算,朴素贝叶斯在贝叶斯基础上增加:特征条件独立假设,即:特征之间是互为独立的。

此时,联合概率的计算即可简化为:

  1. P(程序员,超重|喜欢) = P(程序员|喜欢) * P(超重|喜欢)
  2. P(程序员,超重) = P(程序员) * P(超重)

拉普拉斯平滑系数

在这里插入图片描述

  1. α 是拉普拉斯平滑系数,一般指定为 1
  2. Ni 是 F1 中符合条件 C 的样本数量
  3. N 是在条件 C 下所有样本的总数
  4. m 表示所有独立样本的总数

为了避免概率值为 0,在分子和分母分别加上一个数值,这就是拉普拉斯平滑系数的作用。

情感分析案例

api介绍

sklearn.naive_bayes.MultinomialNB(alpha = 1.0)

  • 朴素贝叶斯分类
  • alpha:拉普拉斯平滑系数

商品评论情感分析

已知商品评论数据,根据数据进行情感分类(好评、差评
在这里插入图片描述

步骤分析

  • 1)获取数据
  • 2)数据基本处理
    • 2.1) 取出内容列,对数据进行分析
    • 2.2) 判定评判标准
    • 2.3) 选择停用词
    • 2.4) 把内容处理,转化成标准格式
    • 2.5) 统计词的个数
    • 2.6)准备训练集和测试集
  • 3)模型训练
  • 4)模型评估

代码实现

import pandas as pd
import numpy as np
import jieba
import matplotlib.pyplot as plt
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
data = pd.read_csv("../data/书籍评价.csv",encoding='gbk')


# 数据预处理
# 添加labels列,充当标签列 1:好评 ,0:差评
data['labels'] = np.where(data['评价'] == '好评', 1, 0)
# 抽取labels列作为标签
y = data['labels']
# 对用户的评价内容做分词
comment_list = [','.join(jieba.lcut(comment)) for comment in data['内容']]


# 加载停用词列表,即:里面记录的词,不需要参与模型训练,预测,要被删除的词,例如:的,啊,哈,从,都
with open("../data/stopwords.txt",'r',encoding='utf-8') as f:
    # 一次性读取所有行
    stopwords_list = f.readlines()

    # 删除最后的\n
    stopwords_list = [stopword.strip() for stopword in stopwords_list]

    # 对停用词列表进行去重
    stopwords_list = list(set(stopwords_list))


# 创建向量化对象,从评论切词列表中删除停用词,并且统计词频
transfer = CountVectorizer(stop_words=stopwords_list) # 参数:停用词列表
# 统计词频矩阵
x = transfer.fit_transform(comment_list).toarray()
print(x)

x_train = x[:10]
y_train = y[:10]
x_test = x[10:]
y_test = y[10:]


# 特征工程

# 模型训练
estimator = MultinomialNB() # 创建朴素贝叶斯对象
estimator.fit(x_train,y_train)

# 模型预测
y_pre = estimator.predict(x_test)
print(f"模型预测结果:{y_pre}")

# 模型评估
print(f"准确率:{accuracy_score(y_test,y_pre)}")
[[0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0
  0]
 [0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0
  0]
 [0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1
  1]
 [0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0
  0]
 [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0]
 [0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
  0]
 [0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 1 0
  0]
 [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
  0]
 [0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0
  0]
 [0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0]
 [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0
  0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0
  0]]
模型预测结果:[0 0 0]
准确率:1.0

聚类算法

聚类算法简介

聚类算法介绍

一种典型的无监督学习算法,主要用于将相似的样本自动归到一个类别中。

在聚类算法中根据样本之间的相似性,将样本划分到不同的类别中,对于不同的相似度计算方法,会得到不同的聚类结果,常用的相似度计算方法有欧式距离法。
在这里插入图片描述

聚类算法在现实中的应用

  • 用户画像,广告推荐,Data Segmentation,搜索引擎的流量推荐,恶意流量识别
  • 基于位置信息的商业推送,新闻聚类,筛选排序
  • 图像分割,降维,识别;离群点检测;信用卡异常消费;发掘相同功能的基因片段

在这里插入图片描述

分类

在这里插入图片描述

聚类API的初步使用

api介绍

sklearn.cluster.KMeans(n_clusters=8)

  • 参数:
    • n_clusters:开始的聚类中心数量
      • 整型,缺省值=8,生成的聚类数,即产生的质心(centroids)数。
  • 方法:
    • estimator.fit(x)
    • estimator.predict(x)
    • estimator.fit_predict(x)
      • 计算聚类中心并预测每个样本属于哪个类别,相当于先调用fit(x),然后再调用predict(x)

案例

随机创建不同二维数据集作为训练集,并结合k-means算法将其聚类,你可以尝试分别聚类不同数量的簇,并观察聚类效果:
在这里插入图片描述

import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs # 默认会按照高斯分布生成数据集,只需要指定均值,标准差
from sklearn.cluster import KMeans # 聚类的API,采用指定质心来分簇
from sklearn.metrics import calinski_harabasz_score # 评价指标,值越大,聚类效果越好


# 准备数据集
#参1:样本数量 参2:样本特征数量 参3:样本标签数量 参4:标准差 参5:随机种子
x, y = make_blobs(n_samples=1000, n_features=2,
                  centers=[[-1, -1], [0, 0], [1, 1], [2, 2]],
                  cluster_std=[0.4, 0.2, 0.2, 0.2],
                  random_state=23)
# 绘制上述的图形
# 参1:横坐标 参2:纵坐标  参3:颜色
plt.scatter(x[:, 0], x[:, 1])
plt.show()

# 创建KMeans对象
estimator = KMeans(n_clusters=4,random_state=23)

# 模型训练和预测
y_pre = estimator.fit_predict(x) # 预测值

# 绘制预测结果
plt.scatter(x[:, 0], x[:, 1],c=y_pre)
plt.show()

# 评价指标
print(f'评价指标:{calinski_harabasz_score(x,y_pre)}') # 越大越好

在这里插入图片描述
在这里插入图片描述

Kmeans算法流程

k-means聚类流程

1、随机设置K个特征空间内的点作为初始的聚类中心

2、对于其他每个点计算到K个中心的距离,未知的点选择最近的一个聚类中心点作为标记类别

3、接着对着标记的聚类中心之后,重新计算出每个聚类的新中心点(平均值)

4、如果计算得出的新中心点与原中心点一样(质心不再移动),那么结束,否则重新进行第二步过程

通过下图解释实现流程:
在这里插入图片描述

在这里插入图片描述

k-means聚类动态效果图:
在这里插入图片描述

案例练习

在这里插入图片描述
1、随机设置K个特征空间内的点作为初始的聚类中心(本案例中设置p1和p2)
在这里插入图片描述

2、对于其他每个点计算到K个中心的距离,未知的点选择最近的一个聚类中心点作为标记类别
在这里插入图片描述
3、接着对着标记的聚类中心之后,重新计算出每个聚类的新中心点(平均值)
在这里插入图片描述
注意:这里P2′=(2.3,3.3),下同。

4、如果计算得出的新中心点与原中心点一样(质心不再移动),那么结束,否则重新进行第二步过程【经过判断,需要重复上述步骤,开始新一轮迭代】
在这里插入图片描述
5、当每次迭代结果不变时,认为算法收敛,聚类完成,K-Means一定会停下,不可能陷入一直选质心的过程。
在这里插入图片描述

评价指标

SSE-误差平方和

在这里插入图片描述

  1. K 表示聚类中心的个数
  2. Ci 表示簇
  3. p 表示样本
  4. mi 表示簇的质心

在这里插入图片描述
SSE 越小,表示数据点越接近它们的中心,聚类效果越好。

SC 系数

结合了聚类的凝聚度(Cohesion)和分离度(Separation),用于评估聚类的效果。

在这里插入图片描述
其计算过程如下:

  1. 计算每一个样本 i 到同簇内其他样本的平均距离 ai,该值越小,说明簇内的相似程度越大
  2. 计算每一个样本 i 到最近簇 j 内的所有样本的平均距离 bij,该值越大,说明该样本越不属于其他簇 j
  3. 计算所有样本的平均轮廓系数
  4. 轮廓系数的范围为:[-1, 1],值越大聚类效果越好

肘部法

肘部法可以用来确定 K 值.

  • 对于n个点的数据集,迭代计算 k from 1 to n,每次聚类完成后计算 SSE
  • SSE 是会逐渐变小的,因为每个点都是它所在的簇中心本身。
  • SSE 变化过程中会出现一个拐点,下降率突然变缓时即认为是最佳 n_clusters 值。
  • 在决定什么时候停止训练时,肘形判据同样有效,数据通常有更多的噪音,在增加分类无法带来更多回报时,我们停止增加类别。

在这里插入图片描述

CH 系数

CH 系数结合了聚类的凝聚度(Cohesion)和分离度(Separation)、质心的个数,希望用最少的簇进行聚类。
在这里插入图片描述
SSW 的含义:

  1. Cpi 表示质心
  2. xi 表示某个样本
  3. SSW 值是计算每个样本点到质心的距离,并累加起来
  4. SSW 表示表示簇内的内聚程度,越小越好
  5. m 表示样本数量
  6. k 表示质心个数

SSB 的含义:

  1. Cj 表示质心,X 表示质心与质心之间的中心点,nj 表示样本的个数
  2. SSB 表示簇与簇之间的分离度,SSB 越大越好

聚类评估的使用

# 定义函数,演示:SSE + 肘部法

def dm01_sse():
    # 定义sse列表,记录每个k值的SSE值
    sse_list = []

    # 生成数据集 参1:样本数量 参2:样本特征数量 参3:样本标签数量 参4:标准差 参5:随机种子
    x,y = make_blobs(
        n_samples=1000,
        n_features=2,
        centers=[[-1, -1], [0, 0], [1, 1], [2, 2]],
        cluster_std=[0.4, 0.2, 0.2, 0.2],
        random_state=23
    )

    # for循环遍历,获取每个k值,计算其对应的sse值,并添加到sse
    for k in range(1,100):
        # 创建KMeans对象,指定 k值,迭代次数,随机种子
        estimator = KMeans(n_clusters=k, max_iter=100, random_state=23)
        # 训练模型
        estimator.fit(x)
        # 模型预测
        y_pred = estimator.predict(x)
        # 获取每个簇的sse值
        sse_value = estimator.inertia_
        # 将每个k值对应的sse值,添加到sse_list列表中
        sse_list.append(sse_value)

    # 绘制SSE曲线-数据可视化

    plt.figure(figsize=(20, 10))
    plt.title("SSE value")
    plt.xticks(range(0, 100, 3))
    plt.xlabel('k')
    plt.ylabel('sse')
    plt.grid()
    # 参1:k值 参2:该k值对应的SSE值
    plt.plot(range(1,100), sse_list)
    plt.show()

在这里插入图片描述

from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
from sklearn.metrics import silhouette_score
from sklearn.metrics import calinski_harabasz_score


if __name__ == '__main__':
    x, y = make_blobs(n_samples=1000,
                      n_features=2,
                      centers=[[-1, -1], [0, 0], [1, 1], [2, 2]],
                      cluster_std=[0.4, 0.2, 0.2, 0.2],
                      random_state=9)

    plt.figure(figsize=(18, 8), dpi=80)
    plt.scatter(x[:, 0], x[:, 1], c=y)
    plt.show()

    estimator = KMeans(n_clusters=4, random_state=0)
    estimator.fit(x)
    y_pred = estimator.predict(x)

    # 1. 计算 SSE 值
    print('SSE:', estimator.inertia_)

    # 2. 计算 SC 系数
    print('SC:', silhouette_score(x, y_pred))

    # 3. 计算 CH 系数

案例

案例介绍

已知:客户性别、年龄、年收入、消费指数

需求:对客户进行分析,找到业务突破口,寻找黄金客户
在这里插入图片描述
数据集共包含顾客的数据, 数据共有 4 个特征, 数据共有 200 条。接下来,使用聚类算法对具有相似特征的的顾客进行聚类,并可视化聚类结果。

案例实现

# 定义函数 找聚类的质心数(K值)
def dm01_find_k():
    # 加载数据集
    data = ps.read_csv("../data/customers.csv")
    # 定义sse_list,sc_list,记录:不同k值的评估效果
    sse_list = [] #sse: 只考虑簇内,越小越好
    sc_list = [] # sc:考虑簇内和簇间,越大越好

    # 抽取特征
    x = data.iloc[:,3:5]

    # 定义for训练,测试不同k值的评估效果
    for k in range(2,20):
        # 创建KMeans对象,指定 k值,迭代次数,随机种子
        estimator = KMeans(n_clusters=k, max_iter=100, random_state=23)
        # 训练模型
        estimator.fit(x)
        # 模型预测
        y_pred = estimator.predict(x)
        # 获取每个簇的sse值
        sse_value = estimator.inertia_
        # 将每个k值对应的sse值,添加到sse_list列表中
        sse_list.append(sse_value)
        sc_value = silhouette_score(x, y_pred)
        # 将每个k值对应的sc值,添加到sc_list列表中
        sc_list.append(sc_value)

    # 绘制折线图,看看k值哪个最好
    plt.figure(figsize=(20, 10))
    plt.plot(range(2,20), sse_list, label='SSE')
    plt.legend()
    plt.show()
    plt.figure(figsize=(20, 10))
    plt.plot(range(2, 20), sc_list, label='SC')
    plt.legend()
    plt.show()

    # 结论:k=5的时候,效果最好

在这里插入图片描述
在这里插入图片描述

# 定义函数,实现:模型训练,模型预测、模型评估
def dm02():
    data = ps.read_csv("../data/customers.csv")
    x = data.iloc[:,3:5]
    # k=5是之前通过上面方法获取到的
    estimator = KMeans(n_clusters=5, max_iter=100, random_state=23)
    estimator.fit(x)
    # 模型预测
    y_pre = estimator.predict(x)
    # 绘制5个簇的样本点 ->散点图
    plt.scatter(x.values[y_pre == 0, 0], x.values[y_pre == 0, 1], s=100, c='red', label='Standard') # [[15,39],[15, 81]...] 0号簇
    plt.scatter(x.values[y_pre == 1, 0], x.values[y_pre == 1, 1], s=100, c='blue', label='Traditional') # 1号簇
    plt.scatter(x.values[y_pre == 2, 0], x.values[y_pre == 2, 1], s=100, c='green', label='Normal') # 2号簇
    plt.scatter(x.values[y_pre == 3, 0], x.values[y_pre == 3, 1], s=100, c='cyan', label='Youth') # 3号簇
    plt.scatter(x.values[y_pre == 4, 0], x.values[y_pre == 4, 1], s=100, c='magenta', label='TA') # 4号簇
    # 绘制5个簇的质心 -> 散点图
    plt.scatter(estimator.cluster_centers_[:, 0], estimator.cluster_centers_[:, 1])
    plt.title('Clusters of Customers')
    plt.xlabel('Annual Income (k$)')
    plt.ylabel('Spending Score (1-100)')
    plt.legend()
    plt.show()

x.values[y_pre == 0, 0]:
x.values:因为 x 是 Pandas 的 DataFrame(带表头),而 plt.scatter 只认 Numpy 数组,所以用 .values 把它变成纯粹的二维数组(200行,2列)。第 0 列是“年收入”,第 1 列是“消费指数”。

y_pre == 0:y_pre 里存的是每个客户的组别(0,1,2,3,4)。y_pre == 0 会生成一个布尔掩码(Boolean Mask),比如 [True, False, True, …],长度为200。相当于一个“筛选器”,告诉程序“只要属于 0 号簇的行”。

合在一起 x.values[布尔掩码, 0]:在 Numpy 中,逗号前面管“行”,逗号后面管“列”。

它先根据布尔掩码,把属于 0 号簇的那些行挑出来;

然后 , 0 表示只取这些行的第 0 列(年收入),作为散点图的 X 轴数据。
同理,x.values[y_pre == 0, 1] 就是取这些行的第 1 列(消费指数),作为 Y 轴。

在这里插入图片描述


总结

机器学习不仅在于“调包”,更在于理解算法背后的数学逻辑与适用边界。希望本文能帮助你建立起从理论到实践的桥梁,在未来面对分类或聚类任务时,能够从容选择、高效实现。欢迎在评论区交流你的实战心得或疑问,让我们共同进步!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐