通过列组合提高算术运算的性能

时间:2019-03-12 07:55:29

标签: python pandas numpy numba

我有以下类型的数据框-
df

A   B   C
5   10  15
20  25  30

我希望完成以下操作-

A_B   A_C  B_C
-0.33 -0.5 -0.2
-0.11 -0.2 -0.09

A_B,A_C,B_C对应--

A_B: A-B/A+B
A_C: A-C/A+C
B_C: B-C/B+C    

我正在使用的-

 colnames = df.columns.tolist()[:-1]
 list_name=[]
 for i,c in enumerate(colnames):
     if i!=len(colnames):
        for k in range(i+1,len(colnames)):
            df[c+'_'+colnames[k]]=(df[c]- 
            df[colnames[k]])/(df[c]+df[colnames[k]])
            list_name.append(c+'_'+colnames[k])

但是问题是我的实际数据框的大小为5*381形状,因此A_B, A_C and so on的实际组合数变为5*72390形状,这需要60分钟才能完成跑。 因此,我尝试将其转换为numpy数组,以便可以使用Numba对其进行优化以有效地进行计算(Parallel programming approach to solve pandas problems),但无法将其转换为numpy数组。 同样,也欢迎任何其他解决此问题的解决方案。

1 个答案:

答案 0 :(得分:2)

这是一个使用NumPy的程序,它具有slicing-

的强大功能
def func1(df):
    a = df.values
    n = a.shape[1]
    L = n*(n-1)//2
    idx = np.concatenate(( [0], np.arange(n-1,0,-1).cumsum() ))
    start, stop = idx[:-1], idx[1:]
    c = df.columns.values.astype(str)
    d = 2*int(''.join(x for x in str(c.dtype) if x.isdigit()))+1
    outc = np.empty(L,dtype='S'+str(2*d+1))
    out = np.empty((a.shape[0],L))
    for i,(s0,s1) in enumerate(zip(start, stop)):
        outc[s0:s1] = np.char.add(c[i]+'_',c[i+1:])
        out[:,s0:s1] = (a[:,i,None]-a[:,i+1:])/(a[:,i,None]+a[:,i+1:])
    return pd.DataFrame(out,columns=outc)

样品运行-

In [361]: df
Out[361]: 
    A   B   C
0   5  10  15
1  20  25  30

In [362]: func1(df)
Out[362]: 
        A_B  A_C       B_C
0 -0.333333 -0.5 -0.200000
1 -0.111111 -0.2 -0.090909

5 x 381随机数组的计时-

In [147]: df = cdf(np.random.randint(10,100,(5,381)))
     ...: df.columns = ['c'+str(i+1) for i in range(df.shape[1])]

# @jezrael's soln
In [148]: %%timeit
     ...: a, b = zip(*(combinations(df.columns, 2)))
     ...: df1 = df.loc[:, a]
     ...: df2 = df.loc[:, b]
     ...: c = [x+'_'+y for x, y in zip(a, b)]
     ...: pd.DataFrame((df1.values-df2.values)/(df1.values+df2.values), columns=c)
10 loops, best of 3: 58.1 ms per loop

# From this post
In [149]: %timeit func1(df)
10 loops, best of 3: 22.6 ms per loop