Python中单个数组上更快的双迭代

2024-10-03 19:28:29 发布

您现在位置:Python中文网/ 问答频道 /正文

我想找到一种更快计算成对精度的方法,即比较同一数组中的元素(在本例中是panda df列),计算它们的差异,然后比较得到的两个结果。我会有一个dataframedf,有3列(id文档,juging代表人的评估,它是一个int对象,PR嫒u score代表该文档的pagerank,它是一个float对象),我想检查他们是否同意将一个文档分类为另一个文档的更好/最差。在


例如:

id:id1、id2、id3

:1,0,0

公共关系得分:0.18、0.5、0.12

在这种情况下,两个分数在id1分类上比id3好,在id1和id2上不一致,在id2和id3之间存在人类判断平局,因此我的成对准确度为:

协议=1

分歧=1

成对准确度=同意/(同意+不同意)=1/2=0.5


这是我第一个解决方案的代码,其中我使用df的列作为数组(这有助于减少计算时间):

def pairwise(agree, disagree):
    return(agree/(agree+disagree))

def pairwise_computing_array(df):

    humanScores = np.array(df['Judgement'])  
    pagerankScores =  np.array(df['PR_Score']) 

    total = 0 
    agree = 0
    disagree = 0

    for i in range(len(df)-1):  
        for j in range(i+1, len(df)):
            total += 1
            human = humanScores[i] -  humanScores[j] #difference human judg
            if human != 0:
                pr = pagerankScores[i] -  pagerankScores[j]#difference pagerank score
                if pr != 0:
                    if np.sign(human) == np.sign(pr):  
                        agree += 1 #they agree in which of the two is better
                    else:
                        disagree +=1 #they do not agree in which of the two is better
                else:
                    continue;   
            else:
                continue;

    pairwise_accuracy = pairwise(agree, disagree)

    return(agree, disagree, total,  pairwise_accuracy)


为了更快地计算,我尝试了列表理解,但实际上它比第一个解决方案慢:

^{pr2}$

我不能运行我的整个数据集,因为它需要太多的时间,我想有一些东西,可以在不到1分钟内计算理想。在

在我的计算机上对1000行的一小部分进行的计算达到了这个性能:

代码1: 每个回路1.57 s±3.15 ms(7次运行的平均值±标准偏差,每个回路1次)

代码2: 每个回路3.51 s±10.7 ms(7次运行的平均值±标准偏差,每个回路1个)


Tags: 代码in文档dfnparrayid3id2
3条回答

这是一个在合理时间内有效的代码,由于@胡安帕.阿里维拉加建议:

from numba import jit

@jit(nopython = True)
def pairwise_computing(humanScores, pagerankScores):

    total = 0 
    agree = 0
    disagree = 0

    for i in range(len(humanScores)-1):  
        for j in range(i+1, len(humanScores)):
            total += 1
            human = humanScores[i] -  humanScores[j] #difference human judg
            if human != 0:
                pr = pagerankScores[i] -  pagerankScores[j]#difference pagerank score
                if pr != 0:
                    if np.sign(human) == np.sign(pr):  
                        agree += 1 #they agree in which of the two is better
                    else:
                        disagree +=1 #they do not agree in which of the two is better
                else:
                    continue   
            else:
                continue
    pairwise_accuracy = agree/(agree+disagree)
    return(agree, disagree, total,  pairwise_accuracy)

这是我的整个数据集(58k行)达到的时间性能:

每个回路7.98 s±2.78 ms(7次运行的平均值±标准偏差,每个回路1次)

通过利用广播可以消除内部的for循环,因为索引j总是比索引i提前1倍(即,我们不回头看)。但在计算一致性/不一致性时有一个小小的问题:

if np.sign(human) == np.sign(pr):

我不知道该怎么解决。所以,我只是在这里提供了框架代码,以便进行更多的调整并使其工作,因为您更了解问题所在。接下来是:

^{pr2}$

你有numpy数组,为什么不直接使用它呢?您可以将工作从Python卸载到C编译代码(通常,但不总是):

首先,将向量调整为1xN矩阵:

humanScores = np.array(df['Judgement']).resize((1,-1))
pagerankScores =  np.array(judgmentPR['PR_Score']).resize((1,-1))

然后找出差异,我们只对标志感兴趣:

^{pr2}$

这里我假设数据是整数,因此clip函数将只产生-1、0或1。然后你可以数一数:

agree = ((humanDiff != 0) & (pagerankDiff != 0) & (humanDiff == pagerankDiff)).sum()
disagree = ((humanDiff != 0) & (pagerankDiff != 0) & (humanDiff != pagerankDiff)).sum()

但是上面的计数是重复计算的,因为项(i,j)和项(j,i)在humanDiff和{}中都是完全相反的符号。您可以考虑只取方阵的上三角部分求和:

agree = ((humanDiff != 0) &
         (pagerankDiff != 0) &
         (np.triu(humanDiff) == np.triu(pagerankDiff))
        ).sum()

相关问题 更多 >