机器学习 Python实验
聚类算法实现-性能度量
实验内容
一、编程实现变量:a, b, c, d
相关定义:
代码部分:
def abcd(set1, set2):
"""
找出变量a,b,c,d
:param set1:簇标识集合1
:param set2:簇标识集合2
:return:返回a,b,c,d值
"""
a, b, c, d, = 0, 0, 0, 0
i = 0
while i < len(set1):
j = i + 1
while j < len(set1):
if set1[i] == set1[j] and set2[i] == set2[j]:
a += 1
elif set1[i] == set1[j] and set2[i] != set2[j]:
b += 1
elif set1[i] != set1[j] and set2[i] == set2[j]:
c += 1
elif set1[i] != set1[j] and set2[i] != set2[j]:
d += 1
j += 1
i += 1
return a, b, c, d
二、Jaccard系数(Jaccard Coefficient, JC)
Jaccard系数公式:
代码部分:
def jaccard(a, b, c):
"""
Jaccard系数
"""
jc = a / (a + b + c)
return jc
三、常用距离
闵可夫斯基距离(Minkowski distance):
p=2: 欧氏距离(Euclidean distance).
p=1:曼哈顿距离(Manhattan distance).
代码部分:
def minkowski_distance(vec1, vec2, p):
"""
闵可夫斯基距离
:param vec1:样本 1
:param vec2:样本 2
:param p:p=1:曼哈顿距离;p=2: 欧氏距离
:return:返回所求距离值
"""
vec = []
i = 0;
sum = 0
while i < len(vec1):
# vec[i] = abs(vec1[i] - vec2[i]) ** p
sum += abs(vec1[i] - vec2[i]) ** p
i += 1
if p == 1:
return sum
elif p == 2:
return sum ** 0.5
四、聚类性能度量
代码部分:
- 平均距离
def avg_dist(c):
"""
簇C内样本间的平均距离
:param c:簇C
:return:样本间的平均距离
"""
i = 0
sum = 0
while i < len(c):
j = i
while j < len(c):
sum += minkowski_distance(c[i], c[j], 2)
j += 1
i += 1
avg_ = (2 / len(c) * (len(c) - 1)) * sum
return avg_
- 簇C内样本间的最远距离
def max_dist(c):
"""
簇C内样本间的最远距离
:param c: 簇C
:return: 簇间样本最远距离
"""
i = 0
max_ = 0
while i < len(c):
j = i
while j < len(c):
temp = minkowski_distance(c[i], c[j], 2)
if temp > max_:
max_ = temp
j += 1
i += 1
return max_
- 簇c1与c2最近样本间的距离
def min_dist(c1, c2):
"""
簇c1与c2最近样本间的距离
:param c1:簇c1
:param c2:簇c2
:return:簇c1与c2最近样本间的距离
"""
i, j = 0, 0
min_ = 10 # 取一个较大数值避免初始值过小无法更新到最小距离的新数据
while i < len(c1):
while j < len(c2):
temp = minkowski_distance(c1[i], c2[j], 2)
if temp < min_:
min_ = temp
j += 1
i += 1
return min_
- 两个向量相加
def sum_vec(vec1, vec2):
"""
两个向量相加
:param vec1: 向量1
:param vec2: 向量2
:return: 返回向量
"""
vec = []
i = 0
while i < len(vec1):
temp = round(vec1[i] + vec2[i], 2)
vec.append(temp)
i += 1
return vec
- 簇C1和簇C2两个簇的中心点的距离
def cen_vec(c):
"""
簇C的中心点
:param c: 簇C
:return: 返回中心点的向量
"""
# u = c[0]
i = 0
temp = [0, 0, 0, 0]
while i < len(c):
temp = sum_vec(c[i], temp)
i += 1
for i in range(len(temp)):
t = temp[i] / len(c)
temp[i] = t
u = temp
return u
def cen_dist(u1, u2):
"""
簇C1和簇C2两个簇的中心点的距离
:param u1: 簇C1的中心点
:param u2: 簇C2的中心点
:return: 返回距离
"""
return minkowski_distance(u1, u2, 2)
五、DB指数(Davies-Bouldin Index, DBI)
公式:
代码部分:
def DaviesBouldin(X, labels):
"""
计算DB指数
:param X: 数据集
:param labels: 聚类标签
:return: 返回DBI
"""
n_cluster = len(np.bincount(labels)) # 簇的个数
cluster_k = [X[labels == k] for k in range(n_cluster)] # 对应簇的数据集
centroids = [np.mean(k, axis=0) for k in cluster_k] # 按照标签列,已经分好了集群,那么每个集群的数据的平均值就是质心所在的位置
# 求S 簇类中数据到质心欧氏距离和的平均距离
S = [np.mean([euclidean(p, centroids[i]) for p in k]) for i, k in enumerate(cluster_k)]
Ri = []
for i in range(n_cluster):
Rij = []
# 计算Rij
for j in range(n_cluster):
if j != i:
r = (S[i] + S[j]) / euclidean(centroids[i], centroids[j])
Rij.append(r)
# 求Ri
Ri.append(max(Rij))
# 求dbi
dbi = np.mean(Ri)
return dbi
六、Value Difference Metric, VDM(处理无序属性):
代码部分:
def vdm(X, labels, u, a, b, p=2):
"""
处理无序属性
:param X:数据集
:param labels:簇标签
:param p:默认为2
:param u:属性u的位置
:param a:在属性u的取值a
:param b:在属性u的取值b
:return:返回vdm
"""
u = u - 1
n_cluster = len(np.bincount(labels)) # 簇的个数
cluster_k = [X[labels == k] for k in range(n_cluster)] # 对应簇的数据集
ma, mb, = 0, 0
for i in range(len(X)):
if X[i][u] == a:
ma += 1
if X[i][u] == b:
mb += 1
# print("\n数据集在属性u上对a,b取值上的样本数:", ma, mb)
v = []
for i in range(n_cluster):
mai = 0
mbi = 0
j = 0
while j < len(cluster_k[i]):
if cluster_k[i][j][u] == a:
mai += 1
if cluster_k[i][j][u] == b:
mbi += 1
j += 1
v.append(abs(mai / ma - mbi / mb) ** p)
# print("在簇标签 ", i, "的簇中在属性u上对a,b取值的样本数:", mai, mbi)
vdm = 0
for k in range(len(v)):
vdm += v[k]
return vdm
七、MinkovDMp(处理混合属性)
公式:
代码部分:
def MinkovDM(X, labels, x1, x2, nc, seq, p):
"""
处理混合属性
:param X: 数据集
:param labels: 划分好的簇标签
:param x1: 样本1
:param x2: 样本2
:param nc: 连续属性和离散属性的分界
:param seq:seq为1或2,表示先离散后连续或反之
:param p:距离选择,默认欧式距离
:return:
"""
sum1, sum2 = 0, 0
if seq == 1:
u = 0
while u < nc:
sum1 = sum1 + vdm(X, labels, u + 1, x1[u], x2[u], p)
u += 1
while u < len(x1):
sum2 = sum2 + abs(x1[u] - x2[u]) ** p
u += 1
elif seq == 2:
u = 0
while u < nc:
sum2 = sum2 + abs(x1[u] - x2[u]) ** p
u += 1
while u < len(x1):
sum1 = sum1 + vdm(X, labels, u + 1, x1[u], x2[u], p)
u += 1
mvdm = (sum1 + sum2) ** (1/p)
return mvdm
八、归一化
代码部分:
def autoNorm(dataSet):
"""
归一化
:param dataSet: 数据集
:return:
"""
minVals = dataSet.min(0) # 取每一列的最小值
maxVals = dataSet.max(0) # 取每一列的最大值
ranges = maxVals - minVals
normDataSet = np.zeros(np.shape(dataSet))
m = dataSet.shape[0]
normDataSet = dataSet - np.tile(minVals, (m, 1))
normDataSet = normDataSet / np.tile(ranges, (m, 1))
return normDataSet, ranges, minVals
验证
变量a,b,c,d
先设定划分好的簇标识集合
label1 = [0, 0, 0, 1, 1, 1] # 划分好的簇标识集合1
label2 = [1, 1, 3, 3, 5, 5] # 划分好的簇标识集合2
运行
a, b, c, d = abcd(label1, label2)
结果:
变量a,b,c,d: 2 4 1 8
Jaccard系数
根据上述获得的结果,运行函数
print("jaccard系数:", jaccard(a, b, c))
结果:
jaccard系数: 0.2857142857142857
常用距离
先设定好两个样本:
x1 = [0.2, 0.25, 0.58, 0.48] # 样本1
x2 = [0.3, 0.45, 0.28, 0.18] # 样本2
调用函数:
print("\n欧氏距离:", minkowski_distance(x1, x2, 1))
print("曼哈顿距离:", minkowski_distance(x1, x2, 2))
结果:
欧氏距离: 0.8999999999999999
曼哈顿距离: 0.4795831523312719
性能度量
假定划分好了两个簇
C1 = [[0.2, 0.25, 0.58, 0.48], [0.3, 0.64, 0.28, 0.18],[0.18, 0.45, 0.38, 0.18],[0.15, 0.55, 0.40, 0.30]]
C2 = [[0.6, 0.78, 0.98, 0.76], [0.55, 0.75, 0.68, 0.70],[0.77, 0.65, 0.58, 0.48],[0.77, 0.55, 0.40, 0.87]]
调用相关函数:
print("簇C内样本间的平均距离: ",avg_dist(C1))
print("簇C内样本间的最远距离: ",max_dist(C1))
print("簇C1和簇C2样本间最近距离: ", min_dist(C1, C2))
print("簇C1的中心点: ",cen_vec(C1))
print("簇C2的中心点: ",cen_vec(C2))
print("簇C1和簇C2的中心点间的距离: ",cen_dist(cen_vec(C1),cen_vec(C2)))
结果:
簇C内样本间的平均距离: 3.066449950245757
簇C内样本间的最远距离: 0.5848931526355903
簇C1和簇C2样本间最近距离: 0.6564297372910524
簇C1的中心点: [0.2075, 0.4725, 0.41, 0.285]
簇C2的中心点: [0.6725, 0.6825, 0.66, 0.7025]
簇C1和簇C2的中心点间的距离: 0.7050753505831842
采用iris数据集验证
①导入数据集
# 使用iris数据集验证
iris = load_iris()
# X = iris.data[:] # #表示我们取特征空间中的四个维度
# X = iris.data[:, 2:] ##表示我们只取特征空间中的后两个维度
X = iris.data[:, 2:] ##表示我们只取特征空间中的前两个维度
# print(X)
②聚类
estimator = KMeans(n_clusters=3) # 构造聚类器
estimator.fit(X) # 聚类
label_pred = estimator.labels_ # 获取聚类标签
labels = list(set(label_pred))
③输出对应簇的质心,簇中数据到质心的欧式距离,DB指数
n_cluster = len(np.bincount(label_pred)) # 质心的数量(簇的个数)
cluster_k = [X[label_pred == k] for k in range(n_cluster)] # 标签对应的数据
centroids = [np.mean(k, axis=0) for k in cluster_k] # 质心所在的位置
S = [np.mean([euclidean(p, centroids[i]) for p in k]) for i, k in enumerate(cluster_k)] # 簇中数据到质心的距离
for k in range(len(labels)):
print("\n簇标签", k)
print("内置函数计算出来的质心:", centroids[k])
print("自编函数计算的质心:", cen_vec(cluster_k[k]))
print("簇中数据到质心的欧式距离:", S[k])
print("\nDB 指数:", DaviesBouldin(X, label_pred))
④聚类结果:
簇标签 0
内置函数计算出来的质心: [1.462 0.246]
自编函数计算的质心: [1.462, 0.24600000000000002]
簇中数据到质心的欧式距离: 0.16809670151957523
簇标签 1
内置函数计算出来的质心: [5.59583333 2.0375 ]
自编函数计算的质心: [5.595833333333334, 2.0375]
簇中数据到质心的欧式距离: 0.5186381094063833
簇标签 2
内置函数计算出来的质心: [4.26923077 1.34230769]
自编函数计算的质心: [4.269230769230769, 1.3423076923076922]
簇中数据到质心的欧式距离: 0.42337511774304964
DB 指数: 0.484729922604757
处理无序属性
我们假设iris数据集属性是无序的
运行代码:
表示在iris数据集上对第2个属性上两个离散值0.2 与 1.4之间的VDM距离
print("\nvdm:", vdm(X, label_pred, 2, 0.2, 1.4, 2))
结果:
vdm: 1.78125
处理混合属性
我们假设出两个样本,第一个属性取值是连续的,第二个是离散的,假定他们属于划分后的iris数据集
x3 = [1.4, 0.2]
x4 = [1.5, 1.4]
运行代码:
print("\nMinkovDM:",MinkovDM(X,label_pred,x3,x4,1,2,2))
结果:
MinkovDM: 1.3383758814324174
归一化
运行代码:
group = X
print("\n原数据:\n", X)
newgroup, _, _ = autoNorm(group)
print("\n归一化后的数据:\n", newgroup)
结果:
原数据:
[[1.4 0.2]
[1.4 0.2]
[1.3 0.2]
[1.5 0.2]
[1.4 0.2]
[1.7 0.4]
[1.4 0.3]
[1.5 0.2]
[1.4 0.2]
[1.5 0.1]
[1.5 0.2]
[1.6 0.2]
[1.4 0.1]
[1.1 0.1]
归一化后的数据:
[[0.06779661 0.04166667]
[0.06779661 0.04166667]
[0.05084746 0.04166667]
[0.08474576 0.04166667]
[0.06779661 0.04166667]
[0.11864407 0.125 ]
[0.06779661 0.08333333]
[0.08474576 0.04166667]
[0.06779661 0.04166667]
[0.08474576 0. ]
[0.08474576 0.04166667]
[0.10169492 0.04166667]
[0.06779661 0. ]
[0.01694915 0. ]
[0.03389831 0.04166667]
[0.08474576 0.125 ]
总结
提示:这里对文章进行总结:
本次实验一部分为自己编写函数,一部分使用了内置函数,使用数据集验证时选取iris数据集可能会有不当,函数还有待优化。