1、概述
其基本介绍如下:
2、代码功能
通过本代码采用数据集后8个特征,初始时设置3个聚类中心,然后进行50次迭代之后,实现订单数据中的聚类。
1、数据准备order.csv
(1)数据格式
"customer","order","total_items","discount%","weekday","hour","Food%","Fresh%","Drinks%","Home%","Beauty%","Health%","Baby%","Pets%"
0, 0, 45, 23.03, 4, 13, 9.46, 87.06, 3.48, 0, 0, 0, 0, 0
0, 1, 38, 1.22, 5, 13, 15.87, 75.8, 6.22, 2.12, 0, 0, 0, 0
0, 2, 51, 18.08, 4, 13, 16.88, 56.75, 3.37, 16.48, 6.53, 0, 0, 0
...
为了大家能够更好的学习K-Means聚类算法,我将这个csv文件放到我博客的资源中,通过下面的链接即可下载,注意在将下面的文件放到代码中运行时,注意修改代码中的文件路径。
https://download.csdn.net/download/weixin_43334389/13183776
2、代码
# @Time : 2020/11/22 21:33
# @Author : Li Kunlun
# @Description : KMean算法,聚类算法
import numpy as np
import pandas as pd
# tqdm 是一个快速,可扩展的Python进度条,可以显示进度信息
from tqdm import tqdm
data = pd.read_csv(r"dataset/order.csv", header=0)
# 后8列都要
t = data.iloc[:, -8:]
print(t)
class KMeans:
"""
@desc:Kmeans聚类算法实现
"""
def __init__(self, k, times):
"""
@desc:初始化
@param k:聚成k个类
@param times:迭代次数
"""
self.k = k
self.times = times
def fit(self, X):
"""
@desc:根据训练数据测试模型
@param X:训练数据特征矩阵,数组类型[样本数量,特征数量]
"""
X = np.asarray(X)
# X.shape (30000, 8)
print("X.shape", X.shape)
# 设置随机数种子,以便于可以相同的随机系列,以便随机结果重现
np.random.seed(0)
# 从数组中随机选择K个点作为初始聚类中心
self.cluster_centers_ = X[np.random.randint(0, len(X), self.k)]
# 用于存放数据所属标签
self.labels_ = np.zeros(len(X))
# 开始迭代
for t in tqdm(range(self.times)):
# 循环遍历样本计算每个样本与聚类中心的距离
for index, x in enumerate(X):
# 计算每个样本与每个聚类中心的欧式距离,每行元素进行求和
dis = np.sqrt(np.sum((x - self.cluster_centers_) ** 2, axis=1))
# 将最小距离的索引赋值给标签数组,索引的值就是当前所属的簇。范围(0,K-1)
self.labels_[index] = dis.argmin()
# 循环遍历每一个数据然后更新聚类中心
for i in range(self.k):
# 计算每个簇内所有点的均值,用来更新聚类中心
self.cluster_centers_[i] = np.mean(X[self.labels_ == i], axis=0)
def predict(self, X):
"""
@desc:预测样本属于那个簇
@param X:训练数据特征矩阵,数组类型[样本数量,特征数量]
@return:返回类数组,每一个x所属的簇
"""
X = np.asarray(X)
result = np.zeros(len(X))
for index, x in enumerate(X):
# 计算样本与聚类中心的距离
dis = np.sqrt(np.sum((x - self.cluster_centers_) ** 2, axis=1))
# 找到距离最近的聚类中中心划分一个类别
result[index] = dis.argmin()
return result
kmeans = KMeans(3, 50)
kmeans.fit(t)
print("kmeans.cluster_centers_", kmeans.cluster_centers_)
# 查看某个簇内的所有样本数据
# t[kmeans.labels_ == 0]
# 测试1:每个数据有8个特征 [0. 2. 1.]
print(kmeans.predict([[30, 30, 40, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 30, 30, 40], [30, 30, 0, 0, 0, 0, 20, 20]]))
# 测试2
# 需要注意loc函数是用字符作为索引的。并且包含:后面的那一列
# 按照标签进行选择。
t2 = data.loc[:, "Food%":"Fresh%"]
# Food% Fresh%
# 0 9.46 87.06
# 1 15.87 75.80
# 2 16.88 56.75
print(t2.head(3))
kmeans = KMeans(3, 50)
kmeans.fit(t2)
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams["font.family"] = "SimHei"
mpl.rcParams["axes.unicode_minus"] = False
# 设置画布,将其设置大一点,便于查看
plt.figure(figsize=(10, 10))
# 绘制每个类别散点图
plt.scatter(t2[kmeans.labels_ == 0].iloc[:, 0], t2[kmeans.labels_ == 0].iloc[:, 1], label="类别1")
plt.scatter(t2[kmeans.labels_ == 1].iloc[:, 0], t2[kmeans.labels_ == 1].iloc[:, 1], label="类别2")
plt.scatter(t2[kmeans.labels_ == 2].iloc[:, 0], t2[kmeans.labels_ == 2].iloc[:, 1], label="类别3")
# 绘制聚类中心,s=300设置的 + 号的大小
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], marker="+", s=300)
plt.title("食物与肉类购买聚类分析")
plt.xlabel("食物")
plt.ylabel("肉类")
plt.legend()
plt.show()
3、结果展示
(1)食物与肉类购买聚类分析
(2)聚类中心坐标
[[46.33977936 8.93380516 23.19047005 13.11741633 4.8107557 1.17283735
1.35704647 0.95392773]
[19.5308009 50.42856608 14.70652695 7.89437019 3.69829234 0.91000428
1.92515077 0.82113238]
[ 7.93541008 4.56182052 30.65583437 18.57726789 8.61597195 1.28482514
26.81950293 1.30158264]]
1、np.random.randint生成随机数组
# 默认high是None,如果只有low,那范围就是[0,low)。如果有high,范围就是[low,high)。
np.random.seed(0)
# [5 0]
print(np.random.randint(0, 10, 2))
# 生成2*4维度的二维数组
# [[3 3 3 1]
# [3 2 4 0]]
print(np.random.randint(5, size=(2, 4)))
2、enumerate 类型举例
# enumerate 函数用于遍历序列中的元素以及它们的下标:
# 0 a
# 1 b
# 2 c
for index, value in enumerate(["a", "b", "c"]):
print(index, value)
3、矩阵求和axis=0/1分析
a = np.array([[0, 2, 1], [3, 5, 6], [0, 1, 1]]) # 得到一个矩阵a
# [[0 2 1]
# [3 5 6]
# [0 1 1]]
print(a)
# 将a中所有元素求和 0+2+1+3+5+6+0+1+1=19
print(a.sum())
# 求出每行元素的和 [ 3 14 2]
print(np.sum(a, axis=1))
# 出每列元素的和 [3 8 8]
print(np.sum(a, axis=0))
4、loc/iloc区别
dates = pd.date_range("20130101", periods=3)
df = pd.DataFrame(np.arange(12).reshape(3, 4), index=dates, columns=['A', 'B', 'C', 'D'])
# A B C D
# 2013-01-01 0 1 2 3
# 2013-01-02 4 5 6 7
# 2013-01-03 8 9 10 11
print(df)
# 1。其中loc 用行列标签,iloc用数字索引。
print(df.loc['20130101', 'B'])
# 10
print(df.iloc[2, 2])