k折交叉验证法python实现_k-means算法python实现

1.k-means算法的思想

k-means算法是一种非监督学习方式,没有目标值,是一种聚类算法,因此要把数据划分成k个类别,那么一般k是知道的。

那么假设k=3,聚类过程如下:

  1. 随机在数据当中抽取三个样本,当做三个类别的中心点(k1,k2,k3);
  2. 计算其余点(除3个中心点之外的点)到这三个中心点的距离,每一个样本应该有三个距离(a,b,c),然后选出与自己距离最近的中心点作为自己的标记,形成三个簇群;
  3. 分别计算这三个簇群的平均值,把三个平均值与之前的旧三个中心点比较,那么分两种情况:

如果相同:结束聚类。

如果不同:把这三个平均值当做新的中心点,然后重复第二步。

2.轮廓系数sci

那么,我们有一个评估标准:轮廓系数sci=(bi-ai)/max(bi,ai),其中i是样本,bi是i到其他簇群的所有样本距离的最小值,ai是i到本身簇群距离的平均值。需要注意:每一个样本都有一个轮廓系数,它的范围是[-1,1]。

4c3c6f1222b69a4d4fc7b024dfe61109.png

那么以这个图为例,说明一下怎么计算轮廓系数:

  1. 计算蓝1到自身类别的点距离的平均值ai;
  2. 计算蓝1分别到红、绿类别所有点的距离,求出平均值b1,b2,取其中最小值bi

那么蓝1的轮廓系数=(bi-ai)/max(bi,ai),我们希望做到外部距离最大化,内部距离最小化

sci的极端情况,如果bi>>>ai,则sci=1,这个是聚类的最好的情况;如果bi<<<ai,则sci=-1,这是糟糕的情况。

因此,当 不知道k的值时,可以通过计算轮廓系数来找到合适的k值。

3.用python实现

主要是两种方式实现了k-means算法,一种是直接调用sklearn中提供的接口,另一种是自己实现这个算法的过程,其实代码实现过程就是思想的应用,这两种方式都使用了相同的数据集,那么用到的数据集下载地址是:原始数据EXCEL。

3.1方式一:使用sklearn中提供的API实现

from copy import deepcopy

import numpy as np

import pandas as pd

from matplotlib import pyplot as plt

from sklearn.cluster import KMeans

from sklearn.metrics import silhouette_score

data = pd.read_csv('venv/xclara.csv')

f1 = data['V1'].values

f2 = data['V2'].values

km = KMeans(n_clusters=3)

km.fit(data)

predict = km.predict(data)

print(predict)

plt.figure(figsize=(10,10))

colored = ['green','blue','red']

colr = [colored[i] for i in predict]

plt.scatter(f1,f2,color=colr)

a = silhouette_score(data,predict)

print(a)

plt.show()

那么这种方式直接调用了api,因此代码比较短,但是看不到具体实现细节,其运行结果如下图所示:

1d9d671f6ea6619809af286047f96b99.png

3.2方式二:实现了算法的思想,完整代码如下:

from copy import deepcopy

import numpy as np

import pandas as pd

from matplotlib import pyplot as plt

plt.rcParams['figure.figsize'] = (16, 9)

"""

使用plt.style.use('ggplot')命令,可以作出ggplot风格的图片。

"""

plt.style.use('ggplot')

data = pd.read_csv('venv/xclara.csv')

f1 = data['V1'].values

f2 = data['V2'].values

"""

zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,

然后返回由这些元组组成的对象,这样做的好处是节约了不少的内存。

我们可以使用 list() 转换来输出列表。

"""

X = np.array(list(zip(f1, f2)))

print(X)

plt.scatter(f1, f2, c='black', s=6)

# 设定分区数

k = 3

# 随机获得中心点的X轴坐标

"""

numpy.random.randint(low, high=None, size=None, dtype='l')

函数的作用是,返回一个随机整型数,范围从低(包括)到高(不包括),即[low, high)。

如果没有写参数high的值,则返回[0,low)的值。

"""

C_x = np.random.randint(0, np.max(X)-20, size=k)

# 随机获得中心点的Y轴坐标

C_y = np.random.randint(0, np.max(X)-20, size=k)

C = np.array(list(zip(C_x, C_y)), dtype=np.float32)

# 将初始化中心点画到输入的样例数据上

plt.scatter(f1, f2, c='black', s=7)

plt.scatter(C_x, C_y, marker='*', s=200, c='red')

# 按行的方式计算两个坐标点之间的距离

def dist(a, b, ax=1):

return np.linalg.norm(a - b, axis=ax)

# 用于保存中心点更新前的坐标

C_old = np.zeros(C.shape)

# 用于保存数据所属中心点,就是保存每个点的标记,标记它属于哪个中心点

clusters = np.zeros(len(X))

# 迭代标识位,通过计算新旧中心点的距离

iteration_flag = dist(C, C_old, 1)

tmp = 1

# 若中心点不再变化或循环次数不超过20次(此限制可取消),则退出循环

while iteration_flag.any() != 0 and tmp < 20:

# 循环计算出每个点对应的最近中心点

for i in range(len(X)):

# 计算出每个点与中心点的距离

distances = dist(X[i], C, 1)

# 记录0 - k-1个点中距离近的点

cluster = np.argmin(distances)

# 记录每个样例点与哪个中心点距离最近

clusters[i] = cluster

# 采用深拷贝将当前的中心点保存下来

# print("the distinct of clusters: ", set(clusters))

C_old = deepcopy(C)

# 从属于中心点放到一个数组中,然后按照列的方向取平均值

for i in range(k):

points = [X[j] for j in range(len(X)) if clusters[j] == i]

# print(points)

# print(np.mean(points, axis=0))

"""

numpy.mean(a, axis, dtype, out,keepdims )

mean()函数功能:求取均值 ,以m * n矩阵举例

axis 不设置值,对 m*n 个数求均值,返回一个实数

axis = 0:压缩行,对各列求均值,返回 1* n 矩阵

axis =1 :压缩列,对各行求均值,返回 m *1 矩阵

"""

C[i] = np.mean(points, axis=0)

# print(C[i])

# print(C)

# 计算新旧节点的距离

print('循环第%d次' % tmp)

tmp = tmp + 1

iteration_flag = dist(C, C_old, 1)

print("新中心点与旧点的距离:", iteration_flag)

# 最终结果图示

colors = ['r', 'g', 'b', 'y', 'c', 'm']

fig, ax = plt.subplots()

# 不同的子集使用不同的颜色

for i in range(k):

points = np.array([X[j] for j in range(len(X)) if clusters[j] == i])

ax.scatter(points[:, 0], points[:, 1], s=7, c=colors[i])

ax.scatter(C[:, 0], C[:, 1], marker='*', s=200, c='black')

#轮廓系数

a = silhouette_score(data,clusters)

print(a)

plt.show()

运行结果如下图:

cc8df1e590156933d416b5c6a67a8b1c.png

《来源于科技文献,经本人分析整理,以技术会友,广交天下朋友》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值