首页 > 解决方案 > 根据一个列表对元素进行分组并将另一个列表中的相应条目相加

问题描述

问题:给定相同长度的整数列表uu,ww,在 Python 3 中,我希望计算较短的列表 u,w 相同长度,其中 u=uu 的唯一元素,w[i]=所有 ww[j] 的总和,使得 uu[ j]=u[i],即对元素进行累加。例如,对于uu=[1,2,1,3,2,2,1,3,1,4]; ww=[0,4,2,1,6,3,2,6,3,0]输出应该是[1,2,3,4],[7,13,7,0].

解决方案:我找到了这些方法来实现我的目标:

import numpy as np
import pandas as pd
import itertools, collections
def ti(): return time.perf_counter() #current time
def acml(method,uu,ww): 
    if method==1: #result is not sorted
        d=collections.defaultdict(int)
        for i in range(len(uu)): d[uu[i]]+=ww[i]
        return list(d.keys()),list(d.values())
    if method==2: #result is sorted
        uw=list(zip(uu,ww)); #transposed list
        uw.sort(key=lambda x:x[0]); #sorted by zeroth coordinate
        uw=itertools.groupby(uw,lambda x: x[0]); #iterator
        uw=[[k,sum([i[1] for i in v])] for k,v in uw];
        return list(zip(*uw))
    if method==3: #slow, result is sorted
        x=pd.DataFrame(data={'u':uu,'w':ww}); x=x.groupby('u');
        u=[i for i,xi in x]; w=[xi['w'].sum() for i,xi in x]; return u,w
n=10**5; r=n//2; uu=list(np.random.randint(0,r,size=n)); ww=list(np.random.randint(-10,10,size=n));
t0=ti(); uw1=acml(1,uu,ww); t1=ti(); print(t1-t0)
t0=ti(); uw2=acml(2,uu,ww); t1=ti(); print(t1-t0)
t0=ti(); uw3=acml(3,uu,ww); t1=ti(); print(t1-t0)

有没有更快的功能可以实现这一点?(元素的顺序无关紧要)

背景:我需要这个函数的原因acml是我正在构建一个巨大的稀疏矩阵(大小高达 10^7 x 10^7,每列有几个条目)。我通过为每一列计算v条目来做到这一点(u,w)。通常,会出现多个具有相同第一个坐标的此类条目,因此应将这些元素的第二个坐标相加。

我意识到构造scipy.sparse.csr_matrix(ww,(uu,vv))已经解决了这个问题(即它对属于同一位置的值求和),但我仍然想使用acml,因为我的矩阵几乎不能放入内存中,所以累积每列的条目(在条目之前甚至找到其他列)将节省 RAM。

标签: performanceoptimizationsplitgroupingperformance-testing

解决方案


推荐阅读