Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eva函数存在问题 #17

Open
thirteenbird opened this issue Mar 28, 2021 · 6 comments
Open

eva函数存在问题 #17

thirteenbird opened this issue Mar 28, 2021 · 6 comments

Comments

@thirteenbird
Copy link

在evaluation.py文件里面的评价函数eva,调用了自己写的acc/f1函数,里面存在很大的问题
代码中的acc函数如下
image
在两者类不匹配的时候,会去改写pred的结果,而且这是直接修改原始数据,会导致后续的nmi/ari计算使用被修改了的pred数据,使得acc/nmi/ari/f1这四个评估指标与真实存在差异
比如如下,使用sklearn.metrics提供的指标计算函数
image
在自行构造的特殊场景下,有着很大的差别,假设存在100个点,并且类别都不一样,其原始分类为[0, ..., 100],现在假设全都预测为同一类,此时正常的eval应该是很差的,但是evaluation.py里的eva函数的数据结果却为极好
image

@bdy9527
Copy link
Owner

bdy9527 commented Apr 1, 2021

感谢你指出我们代码里的问题。

首先说这个评价函数我也是用的别人的,但是我确实忘了源代码是从哪里看的了。我用的时候也没注意到这个问题,并不是我们为了效果好而刻意这么做的。

其次我们论文里所有的实验都是在y_pred和y_true是相同类别数的条件下做的实验,所以函数中 if numclass1 != numclass2 这个判断是不会触发的,也就是说我们并没有在评测过程中修改pred来得到更好的结果。

后续我会再确定一下之前的代码来源,然后修改源文件中的代码。再次感谢你的提醒。

@thirteenbird
Copy link
Author

thirteenbird commented Apr 1, 2021 via email

@thirteenbird
Copy link
Author

thirteenbird commented Apr 1, 2021

import numpy as np
from munkres import Munkres, print_matrix
from sklearn.metrics.cluster import normalized_mutual_info_score as nmi_score
from sklearn.metrics import adjusted_rand_score as ari_score
from sklearn.metrics import accuracy_score, f1_score, precision_score
from scipy.optimize import linear_sum_assignment as linear
from sklearn import metrics

def cluster_acc2(y_true, y_pred):
    y_true = y_true - np.min(y_true)

    l1 = list(set(y_true))
    numclass1 = len(l1)

    l2 = list(set(y_pred))
    numclass2 = len(l2)

    ind = 0
    # print(l1, l2)
    #为缺失类别进行补充,保障后面使用匈牙利可以一一映射
    if numclass1 > numclass2:
        for i in l1:
            if i in l2:
                pass
            else:
                # y_pred.append(i)
                # y_true.append(i)
                y_pred = np.append(y_pred, i)
                y_true = np.append(y_true, i)
                ind += 1

    if numclass1 < numclass2:
        print(l2)
        for i in l2:
            if i in l1:
                pass
            else:
                # y_pred.append(i)
                # y_true.append(i)
                y_pred = np.append(y_pred, i)
                y_true = np.append(y_true, i)
                ind += 1

    l1 = list(set(y_true))
    l2 = list(set(y_pred))
    numclass1 = len(l1)
    numclass2 = len(l2)
    # print(numclass1, numclass2)

    if numclass1 != numclass2:
        print('error')
        return

    cost = np.zeros((numclass1, numclass2), dtype=int)
    for i, c1 in enumerate(l1):
        mps = [i1 for i1, e1 in enumerate(y_true) if e1 == c1]
        for j, c2 in enumerate(l2):
            mps_d = [i1 for i1 in mps if y_pred[i1] == c2]
            cost[i][j] = len(mps_d)

    # match two clustering results by Munkres algorithm
    m = Munkres()
    cost = cost.__neg__().tolist()
    indexes = m.compute(cost)

    # get the match results
    new_predict = np.zeros(len(y_pred))
    for i, c in enumerate(l1):
        # correponding label in l2:
        c2 = l2[indexes[i][1]]

        # ai is the index with label==c2 in the pred_label list
        ai = [ind for ind, elm in enumerate(y_pred) if elm == c2]
        new_predict[ai] = c

    y_true = y_true[:len(y_true)-ind]
    new_predict = new_predict[:len(y_pred)-ind]
    y_pred = new_predict

    acc = metrics.accuracy_score(y_true, new_predict)
    f1_macro = metrics.f1_score(y_true, new_predict, average='macro')
    # precision_macro = metrics.precision_score(y_true, new_predict, average='macro')
    # recall_macro = metrics.recall_score(y_true, new_predict, average='macro')
    # f1_micro = metrics.f1_score(y_true, new_predict, average='micro')
    # precision_micro = metrics.precision_score(y_true, new_predict, average='micro')
    # recall_micro = metrics.recall_score(y_true, new_predict, average='micro')
    return acc, f1_macro

@mant-ux
Copy link

mant-ux commented May 31, 2021

@thirteenbird 您好,感谢您的细致分析,看了您的分析并使用了您的代码。可是当我在实际使用时, 通过代码计算的acc与通过混淆矩阵计算的acc会降低一点都,F1 rel与pre 指标则相差很多,当用混淆矩阵手动计算时,这三类指标都比通过此代码计算高很多,当使用macro参数时,F1 rec与pre 指标则特别低,rec相差近特别特别多,我更换了几次标签实验发现还是如此,您可以给我一些帮助吗?

简单来说,acc会降低3个百分点,F1 rec与pre 则相差很多。检查了输入的两列标签与对照变换后的标签并没有发现问题,十分感谢您。

@thirteenbird
Copy link
Author

thirteenbird commented May 31, 2021

@thirteenbird 您好,感谢您的细致分析,看了您的分析并使用了您的代码。可是当我在实际使用时, 通过代码计算的acc与通过混淆矩阵计算的acc会降低一点都,F1 rel与pre 指标则相差很多,当用混淆矩阵手动计算时,这三类指标都比通过此代码计算高很多,当使用macro参数时,F1 rec与pre 指标则特别低,当使用micro参数时,四项指标无论在哪个数据标签结果中都是相同的,我更换了几次标签实验发现还是如此,您可以给我一些帮助吗?
image
简单来说,acc会降低3个百分点,F1 rec与pre 则相差很多。检查了输入的两列标签与对照变换后的标签并没有发现问题,十分感谢您。

@mant-ux 我个人猜测,造成这个的原因可能是我这种逃课的方式,在y_true和pred类别对不上的时候,匈牙利算法做映射时因为增加了新的行导致映射的不对,从而存在这种问题
可以改写上面的代码

add_num = numclass1 + 1 if numclass1 > numclass2 else numclass2+1
if numclass1 > numclass2:
      for i in l1:
          if i in l2:
              pass
          else:
              # y_pred.append(i)
              # y_true.append(i)
              y_pred = np.append(y_pred, add_num)
              y_true = np.append(y_true, add_num)
              ind += 1
              add_num += 1

if numclass1 < numclass2:
    print(l2)
    for i in l2:
        if i in l1:
            pass
        else:
            # y_pred.append(i)
            # y_true.append(i)
            y_pred = np.append(y_pred, add_num)
            y_true = np.append(y_true, add_num)
            ind += 1
            add_num += 1

如果y_true和pred类别数量一直的话,那应该不会存在问题?因为相当于使用匈牙利算法映射后,用sklearn.metrics库做的统计指标计算,应该会和人工使用混淆矩阵一致

@mant-ux
Copy link

mant-ux commented May 31, 2021

@thirteenbird 感谢您的回复,我检查了标签并没有问题,并且通过代码映射变换后的标签与真实标签做混淆矩阵类别数也是一致的,但是代码得到的rec只有8%,混淆矩阵计算得到的大道了70%,acc相差代码低了3%,是我标签处理的问题吗?
代码得到rec pre 的结果低的特别离谱,
image
image
并且我特别检查了映射前后的标签csv文件,并没有发现问题

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants