无法向量化时如何优化熊猫数据帧的迭代

时间:2020-11-03 21:16:14

标签: python dataframe optimization vectorization

我要优化一个相当复杂的计算。我会利用pandas / numpy向量化,但不确定是否可以通过向量化解决此任务。目前,我正在使用pandas数据框,但使用for循环遍历该数据框。

任务说明:

查找表给出了映射。例如,old“ 1”在new“ 11”和“ 12”之间分配,分配比例为weight。 60%的“ 1”传递给“ 11”,40%的传递给“ 12”。 另一个示例是将old“ 2”重命名为new“ 20”。因此,此处的分配比例为100%。 对于old“ 3”(也分为{{1})“ 31”,“ 32”,“ 33”类似。

new中给出了“ 1”,“ 2”,“ 3”的实际值。在结果表df中,new_df的值需要通过乘以各个old /比率来替换为new

我希望这种解释就足够了。下表将提供更多帮助。

  1. 权重(这是一个查找表)

    weights
  2. df(实际数据表/矩阵)

    data = {'old':['1','1','2','3','3','3'], 'new':['11','12', '20','31','32','33'], 'Weight': [0.6, 0.4,1 ,0.2, 0.5, 0.3]} 
    weights = pd.DataFrame(data) 
    weights
    
         old   new    Weight
    0    1     11     0.6
    1    1     12     0.4
    2    2     20     1
    3    3     31     0.2
    4    3     32     0.5
    5    3     33     0.3
    

new_df(结果数据帧)

data = {'A1':['1','1', '1', '2','2','2', '3','3'], 'A2':['1','2','3','1','2','3','1','2'], 'value': [50, 40, 30 ,10, 20, 70, 80, 90]} 
df = pd.DataFrame(data) 
df

     A1  A2  value
0    1   1   50   
1    1   2   40    
2    1   3   30     
3    2   1   10    
4    2   2   20    
5    2   3   70    
6    3   1   80
7    3   2   90

下面是我现在正在使用的代码。但是,我给出的示例只是数据样本。有数千行,所以我需要以某种方式对其进行优化。

        A1_new  A2_new  value_new  | calculation (only for explanation)
   0    11      11      18         | 50 * 0.6 * 0.6
   1    12      12      8          | 50 * 0.4 * 0.4
   2    11      12      12         | 50 * 0.6 * 0.4
   3    12      11      12         | 50 * 0.6 * 0.4
   4    11      20      24         | 40 * 1 * 0.6
   5    12      20      16         | 40 * 1 * 0.4
   6    11      31      3.6        | 30 * 0.6 * 0.2
   7    11      32      9          | 30 * 0.6 * 0.5
   8    11      33      5.4        | 30 * 0.6 * 0.3
   9    12      31      2.4        | 30 * 0.4 * 0.2
  10    12      32      6          | 30 * 0.4 * 0.5
  11    12      33      3.6        | 30 * 0.4 * 0.3
   12   31      11      9.6        | 80 * 0.2 * 0.6
   13   32      11      24         | 80 * 0.5 * 0.6
   14   33      11      14.4       | 80 * 0.3 * 0.6 
   15   31      12      6.4        | 80 * 0.2 * 0.4 
   16   32      12      16         | 80 * 0.5 * 0.4 
   17   33      12      9.6        | 80 * 0.3 * 0.4 
   18   31      20      16         | 80 * 0.2 * 1
   19   32      20      40         | 80 * 0.5 * 1
   20   33      20      24         | 80 * 0.3 * 1 

1 个答案:

答案 0 :(得分:4)

前言

据我所知,您想根据其权重将(A1, A2)的每种组合分成其所有可能的新组合(A1_new, A2_new)和每种各自的新value

从您想要的输出中,当您有第一行时,我发现了一个小的不一致之处:

     A1  A2  value
0    1   1   50   

您是否只将以下两个结果行确实是真的?

        A1_new  A2_new  value_new  
   0    11      11      30        
   1    12      12      20        

而不是四行(例如所有可能的对)

    A1_new  A2_new  value_new
0       11      11       18.0
1       11      12       12.0
2       12      11       12.0
3       12      12        8.0

如果确实如此,请在发生这种情况时添加有关确切规则的评论,我将编辑答案。

解决方案

如上所述,以下解决方案使用所有可用的A1A2替换对。通常的想法是使用两个A列上的内部联接来“替换”列的所有旧值,然后根据联接的权重计算新值。

df = df\
    .merge(weights, left_on="A1", right_on="old") \
    .drop(columns=["A1", "old"]) \
    .rename(columns={"new": "A1_new"}) \
    .merge(weights, left_on="A2", right_on="old") \
    .drop(columns=["A2", "old"]) \
    .rename(columns={"new": "A2_new"}) 

df["value_new"] = df["value"] * df["Weight_x"] * df["Weight_y"]
df = df.drop(columns=["value", "Weight_x", "Weight_y"])

结果数据

    A1_new  A2_new  value_new
0       11      11       18.0
1       11      12       12.0
2       12      11       12.0
3       12      12        8.0
4       20      11        6.0
5       20      12        4.0
6       31      11        9.6
7       31      12        6.4
8       32      11       24.0
9       32      12       16.0
10      33      11       14.4
11      33      12        9.6
12      11      20       24.0
13      12      20       16.0
14      20      20       20.0
15      31      20       18.0
16      32      20       45.0
17      33      20       27.0
18      11      31        3.6
19      11      32        9.0
20      11      33        5.4
21      12      31        2.4
22      12      32        6.0
23      12      33        3.6
24      20      31       14.0
25      20      32       35.0
26      20      33       21.0