问题:对一部分样本进行聚类,得到了聚类标签,同时这部分数据有真实标签,为了计算聚类之后的准确率,如何将聚类标签数据映射到真实标签数据呢?
Python包的安装:pip install munkres
munkres:假设n个工人完成n个工作,每个工人完成工作的代价不同,一个工作只能由一个工人来完成,一个工人也只能完成一个工作。如matrix所示,有3个工人,第1个工人完成第1个工作需要5天,完成第2个工作需要9天,完成第3个工作需要1天;第2个工人完成第1个工作需要10天,完成第2个工作需要3天,依次类推。问如何将每个工作分配给每个工人(1个工作分配给1个工人),使得总的代价cost最少。
munkres提供了一个方法,通过调用可以实现这个问题,如下代码所示。
munkres库链接:https://pypi.org/project/munkres/
from munkres import Munkres,print_matrix
matrix=[[5,9,1],
[10,3,2],
[8,7,4]]
m=Munkres()
indexes=m.compute(matrix)
print(indexes)
print_matrix(matrix,msg='Lowest cost through this matrix')
total=0
for row,column in indexes:
value=matrix[row][column]
total+=value
print('(%d,%d)->%d'%(row,column,value))
print('total cost:%d'%total)
运行结果:
以COIL20数据集为例,该数据集是一个object datasets,由1440个samples,20个objects组成,每张图片的维度是32*32。该数据集由训练集[‘fea’]和标签集['gnd']组成。labels的数据形式为:
[ 1 1 1 ... 20 20 20]
假设聚类后的标签为:
[ 3 3 3 ... 14 14 14]
使用一下代码可以将预测标签映射为真实标签:
def best_map(L1,L2):
#L1 should be the labels and L2 should be the clustering number we got
Label1 = np.unique(L1) # 去除重复的元素,由小大大排列
nClass1 = len(Label1) # 标签的大小
Label2 = np.unique(L2)
nClass2 = len(Label2)
nClass = np.maximum(nClass1,nClass2)
G = np.zeros((nClass,nClass))
for i in range(nClass1):
ind_cla1 = L1 == Label1[i]
ind_cla1 = ind_cla1.astype(float)
for j in range(nClass2):
ind_cla2 = L2 == Label2[j]
ind_cla2 = ind_cla2.astype(float)
G[i,j] = np.sum(ind_cla2 * ind_cla1)
m = Munkres()
index = m.compute(-G.T)
index = np.array(index)
c = index[:,1]
newL2 = np.zeros(L2.shape)
for i in range(nClass2):
newL2[L2 == Label2[i]] = Label1[c[i]]
return newL2
def err_rate(gt_s,s):
print(gt_s)
print(s)
c_x=best_map(gt_s,s)
err_x=np.sum(gt_s[:]!=c_x[:])
missrate=err_x.astype(float)/(gt_s.shape[0])
return missrate
在err_rate(gt_s,s)方法中,gt_s表示真实标签数组,s表示预测标签数组。通过调用best_map(gt_s,s)方法可以得到映射后的标签,然后使用np.sum(gt_s[:]!=c_x[:])可以得到预测错误的标签个数err_x,err_x除以总的标签个数即可以得到错误率,进而可以计算聚类之后的准确率