0043-机器学习-利用Kmeans聚类实现异常值检测

个人微信公众号

在这里插入图片描述

kmeans原理介绍

kmeans算法的思路非常简单,就是不断计算各样本点和簇中心点之间的距离,直到收敛为止,其具体步骤如下:
1.从数据中随机挑选K个样本点作为原始的簇中心;
2.计算剩余样本与簇中心的距离,并把各样本标记为离K个簇中心最近的类别;
3.重新计算各簇中样本点的均值,并以均值作为新的K各簇中心。
4.不断重复2和3,直到簇中心的变化趋于稳定,形成最终的K个簇。
也许上面的4个步骤还不足以让读者明白Kmeans的执行过程,可以结合下图更进一步地理解其背后的思想。
在这里插入图片描述
如上图所示,通过9个子图对Kmeans聚类过程加以说明:图1,从原始样本中随机挑选两个数据点作为初始的簇中心,即子图中对两个五角星;图2,将其余样本点与这两个五角星分别计算距离(距离的度量可选择欧式距离,曼哈顿距离等),然后将每个样本点划分到离五角星最近的簇,即子图中按虚线隔开的两部分;图3,计算两个簇内样本点的均值,得到新的簇中心,即子图中的五角星,图4,根据新的簇中心,继续计算各样本与五角星之间的距离,得到图5的划分结果和图6中新的簇中心,继续计算各样本与五角星之间的距离,得到图5的划分结果和图6中新的簇内样本均值;以此类推,最终得到的理想的聚类效果,如图9所示,途中的五角星为最终的簇中心点。

如何确定K值

在实际应用中,很多数据都无法通过可视化或直觉判断聚类的个数。但这并不代表没有办法确定最佳K值,主要有:“拐点法”,“轮廓系数法”和“间隔统计量法”。下面就通过一个简单的例子来看下基于SSE和轮廓系数法判断最佳K值

import pandas as pd
import numpy as np
#创造数据
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt

x,y=make_blobs(n_samples=500,n_features=2,centers=4,random_state=1)

fig,ax1=plt.subplots(1)
ax1.scatter(x[:,0],x[:,1],
            marker='o',
            s=8)
plt.show()

color=['red','pink','orange','gray']
fig,ax1=plt.subplots(1)
for i in range(4):
    ax1.scatter(x[y==i,0],x[y==i,1],
                marker='o',
                s=8,
                c=color[i])
plt.show()


#对数据进行了解

from sklearn.cluster import KMeans
#使用SSE进行模型评估,
import matplotlib.pyplot as plt
sse=[]
for i in range(1,10):
    cluster=KMeans(n_clusters=i,random_state=0).fit(x)
    inertia=cluster.inertia_
    sse.append(inertia)
plt.figure(figsize=(8,6))
plt.plot(range(1,10),sse,color='red',linewidth=2.0,linestyle='--',marker='o',label='sse')
plt.grid(True)
plt.show()


#使用轮廓系数sc
from sklearn.metrics import silhouette_samples, silhouette_score
import matplotlib.pyplot as plt
sc=[]
for i in range(2,10):#为什么要从2开始,1的话会出错
    cluster_=KMeans(n_clusters=i,random_state=0).fit(x)
    y_pre=cluster_.labels_
    sc_=silhouette_score(x,y_pre)
    sc.append(sc_)
plt.figure(figsize=(8,6))
plt.plot(range(1,10),sse,color='red',linewidth=2.0,linestyle='--',marker='o',label='sse')
plt.show()

案例实战

# 导入第三方包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.cluster import KMeans
from sklearn.preprocessing import scale

# 随机生成两组二元正态分布随机数
np.random.seed(1234)
mean1 = [0.5, 0.5]
cov1 = [[0.3, 0], [0, 0.1]]
x1, y1 = np.random.multivariate_normal(mean1, cov1, 5000).T

mean2 = [0, 8]
cov2 = [[0.8, 0], [0, 2]]
x2, y2 = np.random.multivariate_normal(mean2, cov2, 5000).T

# 绘制两组数据的散点图
plt.rcParams['axes.unicode_minus'] = False


plt.scatter(x1, y1)
plt.scatter(x2, y2)
# 显示图形
plt.show()

# 将两组数据集汇总到数据框中
X = pd.DataFrame(np.concatenate([np.array([x1, y1]), np.array([x2, y2])], axis=1).T)
X.rename(columns={0: 'x1', 1: 'x2'}, inplace=True)
# 自定义函数的调用
# k_SSE(X, 10)


def kmeans_outliers(data, clusters, is_scale=True):
    # 指定聚类个数,准备进行数据聚类
    kmeans = KMeans(n_clusters=clusters)
    # 用于存储聚类相关的结果
    cluster_res = []

    # 判断是否需要对数据做标准化处理
    if is_scale:
        std_data = scale(data)  # 标准化
        kmeans.fit(std_data)  # 聚类拟合
        # 返回簇标签
        labels = kmeans.labels_
        # 返回簇中心
        centers = kmeans.cluster_centers_

        for label in set(labels):
            # 计算簇内样本点与簇中心的距离
            diff = std_data[np.array(labels) == label,] - \
                   - np.array(centers[label])
            dist = np.sum(np.square(diff), axis=1)
            # 计算判断异常的阈值
            UL = dist.mean() + 3 * dist.std()
            # 识别异常值,1表示异常,0表示正常
            OutLine = np.where(dist > UL, 1, 0)
            raw_data = data.loc[np.array(labels) == label,]
            new_data = pd.DataFrame({'Label': label, 'Dist': dist, 'OutLier': OutLine})
            # 重新修正两个数据框的行编号
            raw_data.index = new_data.index = range(raw_data.shape[0])
            # 数据的列合并
            cluster_res.append(pd.concat([raw_data, new_data], axis=1))
    else:
        kmeans.fit(data)  # 聚类拟合
        # 返回簇标签
        labels = kmeans.labels_
        # 返回簇中心
        centers = kmeans.cluster_centers_

        for label in set(labels):
            # 计算簇内样本点与簇中心的距离
            diff = np.array(data.loc[np.array(labels) == label,]) - \
                   - np.array(centers[label])

            dist = np.sum(np.square(diff), axis=1)
            UL = dist.mean() + 3 * dist.std()
            OutLine = np.where(dist > UL, 1, 0)
            raw_data = data.loc[np.array(labels) == label,]
            new_data = pd.DataFrame({'Label': label, 'Dist': dist, 'OutLier': OutLine})
            raw_data.index = new_data.index = range(raw_data.shape[0])
            cluster_res.append(pd.concat([raw_data, new_data], axis=1))
    # 返回数据的行合并结果
    return pd.concat(cluster_res)


# 调用函数,返回异常检测的结果
res = kmeans_outliers(X, 2, False)
# res
# 绘图
sns.lmplot(x="x1", y="x2", hue='OutLier', data=res,
           fit_reg=False, legend=False)
plt.legend(loc='best')
plt.show()

猜你喜欢

转载自blog.csdn.net/zhonglongshen/article/details/113282875