Python Pandas/numpy有助于矢量化数据帧之间的查找、计算和重新排序顺序

Python Pandas/numpy有助于矢量化数据帧之间的查找、计算和重新排序顺序,python,numpy,pandas,Python,Numpy,Pandas,我正在尝试处理三个(csv)文件中的数据,如p、c、f: 在p中,每行都有标签 在c中,每行都有p中对应行标签的分数(p与c匹配) 在f中,每行是一个标签和另一个分数 例如,分别加载到df_p、df_c和df_f中: >>> df_p p1 p2 p3 p4 p5 2614 104 104 102 102 102 3735 100 103 101 100 104 1450 100 102 100 102 102 &

我正在尝试处理三个(csv)文件中的数据,如p、c、f:

  • 在p中,每行都有标签
  • 在c中,每行都有p中对应行标签的分数(p与c匹配)
  • 在f中,每行是一个标签和另一个分数
例如,分别加载到df_p、df_c和df_f中:

>>> df_p
       p1   p2   p3   p4   p5
2614  104  104  102  102  102
3735  100  103  101  100  104
1450  100  102  100  102  102
>>> df_c
            c1        c2        c3        c4        c5
2614  0.338295  0.190882  0.157231  0.135776  0.177816
3735  0.097800  0.124296  0.268475  0.265111  0.244319
1450  0.160922  0.403703  0.122390  0.130612  0.182373
>>> df_f
            c
100  0.183946
101  0.290311
102  0.192049
103  0.725704
104  0.143359
阿尔戈

例如,
df\u c
中的第一个计算单元将是
0.338295*0.143359

这是我的代码,虽然运行非常缓慢:

np_p = []
np_c = []
for i in range(len(df_p)):

    ## determine revised scores
    # Step 1. Revise scores
    r_conf = df_c.iloc[[i]].values[0] # scores for row
    r_place_id = df_p.iloc[[i]].values[0] # labels for row
    p_c = df_f.ix[r_place_id].c.values # class conf for labels
    t_conf = r_conf*p_c # total score

    # Reorder labels
    # Step 2. reorder by revised score
    c = np.sort(t_conf)[::-1]
    c_sort = np.argsort(t_conf)[::-1] 
    # Step 3. reorder labels with revised score order
    p_sort = df_p.iloc[[i]][df_p.columns[c_sort]].values
    np_c.append(c)
    np_p.append(p_sort)
理想情况下,我希望创建一个像
df_p
df_c
这样的数据帧,但要使用重新排序和修订的值(在
np_p
np_c

我有什么想法可以让这更快吗

谢谢

您可以使用将
df\u p
中的值替换为
df\u f
中的值:

In [124]: df_pf = df_p.replace(df_f['c']); df_pf
Out[124]: 
            p1        p2        p3        p4        p5
2614  0.143359  0.143359  0.192049  0.192049  0.192049
3735  0.183946  0.725704  0.290311  0.183946  0.143359
1450  0.183946  0.192049  0.183946  0.192049  0.192049
由于Pandas在两个数据帧相乘之前对齐索引,如果我们去掉
p
s和
c
s,然后我们可以获得所需的产品 使用
df_pf.mul(df_c)

使用指定了轴=1的
np.argsort
可以获得每行列的正确顺序。然后可以使用
np.argsort
返回的
order
数组对
df_c
df_p
进行重新排序:

order = np.argsort(-df_c.values, axis=1)
nrows, ncols = df_c.shape
np_c = df_c.values[np.arange(nrows)[:,None], order]
np_p = df_p.values[np.arange(nrows)[:,None], order]
上面使用NumPy分别对每行中的值重新排序


屈服

[[ 0.04849763  0.03414938  0.03019606  0.02736465  0.02607565]
 [ 0.0902021   0.07794125  0.04876611  0.03502533  0.01798992]
 [ 0.07753076  0.03502455  0.02960096  0.0250839   0.02251315]]
[[104 102 102 104 102]
 [103 101 100 104 100]
 [102 102 100 102 100]]

或者,如果
df_p
df_c
的列和行已经对齐, 然后,您可以通过使用NumPy而不是Pandas进行乘法来获得更快的速度:

def using_numpy(df_p, df_c, df_f):
    # faster than using_pandas, but assumes `df_p` and `df_c` are already aligned
    df_pf = df_p.replace(df_f['c'])
    df_pf = df_pf.values
    df_c = df_c.values
    df_p = df_p.values
    df_c = df_pf * df_c
    order = np.argsort(-df_c, axis=1)
    nrows, ncols = df_c.shape
    np_c = df_c[np.arange(nrows)[:,None], order]
    np_p = df_p[np.arange(nrows)[:,None], order]
    return np_c, np_p
对于这些小数据帧,
使用_numpy
使用_pandas
稍微快一些。 如果数据帧更大,速度上的差异会更明显。 但是再次注意,使用_numpy的
依赖于已经对齐的索引

In [138]: %timeit using_numpy(df_p, df_c, df_f)
1000 loops, best of 3: 1.15 ms per loop

In [139]: %timeit using_pandas(df_p, df_c, df_f)
1000 loops, best of 3: 1.62 ms per loop

试试这个:首先创建一个dict of
df\u f

di = df_f['c'].to_dict()

   {100: 0.183946,
 101: 0.29031099999999999,
 102: 0.192049,
 103: 0.72570400000000002,
 104: 0.14335899999999999}
然后将其映射到df_p:

df_p.replace(di)

#            p1        p2        p3        p4        p5
# 2614  0.143359  0.143359  0.192049  0.192049  0.192049
# 3735  0.183946  0.725704  0.290311  0.183946  0.143359
# 1450  0.183946  0.192049  0.183946  0.192049  0.192049
然后进行乘法运算:

df_c2 =df_c.copy() 
df_c2['c1'] = df_c['c1']* df_p['p1'] 
df_c2['c2'] = df_c['c2']* df_p['p2'] 
df_c2['c3'] = df_c['c3']* df_p['p3'] 
df_c2['c4'] = df_c['c4']* df_p['p4'] 
df_c2['c5'] = df_c['c5']* df_p['p5'] 

 #              c1        c2        c3        c4        c5
 #   2614  0.048498  0.027365  0.030196  0.026076  0.034149
 #   3735  0.017990  0.090202  0.077941  0.048766  0.035025
 #   1450  0.029601  0.077531  0.022513  0.025084  0.035025

有五列可供使用。2.按递减分数对df_c的元素重新排序。@unutbu。你能解释np.argsort(-df_c,axis=1)吗?@Merlin:返回对数组排序的索引。例如,
np.argsort([1,3,2])
返回
数组([0,2,1])
,因为要按升序对
[1,3,2]
进行排序,第0项首先出现,然后是第2项,然后是第1项
np.argsort([[1,3,2],[20,30,10]],axis=1)
类似于行堆叠
np.argsort([1,3,2])
np.argsort([20,30,10])
。在
np.argsort(-df_c,axis=1)
中使用减号对
df_c
的每一行按降序进行argsort。@unutbu-非常有效、完整、直观!我不得不将数据帧分解成块以放入内存中,因为我的数据比上面的示例大得多,但在其他方面非常简洁和优雅,我学会了一些技巧。非常感谢。
di = df_f['c'].to_dict()

   {100: 0.183946,
 101: 0.29031099999999999,
 102: 0.192049,
 103: 0.72570400000000002,
 104: 0.14335899999999999}
df_p.replace(di)

#            p1        p2        p3        p4        p5
# 2614  0.143359  0.143359  0.192049  0.192049  0.192049
# 3735  0.183946  0.725704  0.290311  0.183946  0.143359
# 1450  0.183946  0.192049  0.183946  0.192049  0.192049
df_c2 =df_c.copy() 
df_c2['c1'] = df_c['c1']* df_p['p1'] 
df_c2['c2'] = df_c['c2']* df_p['p2'] 
df_c2['c3'] = df_c['c3']* df_p['p3'] 
df_c2['c4'] = df_c['c4']* df_p['p4'] 
df_c2['c5'] = df_c['c5']* df_p['p5'] 

 #              c1        c2        c3        c4        c5
 #   2614  0.048498  0.027365  0.030196  0.026076  0.034149
 #   3735  0.017990  0.090202  0.077941  0.048766  0.035025
 #   1450  0.029601  0.077531  0.022513  0.025084  0.035025