python pandas将数据帧乘以矢量化方式随类别变化的权重

时间:2017-05-12 19:47:00

标签: python pandas numpy group-by weighted-average

我的问题与outlined here

非常相似

除了我的主数据框有一个类别列,我的权重也是如此:

df
Out[3]: 
Symbol         var_1      var_2     var_3     var_4    Category  
Index                                              
1903          0.000443  0.006928  0.000000  0.012375      A
1904         -0.000690 -0.007873  0.000171  0.014824      A
1905         -0.001354  0.001545  0.000007 -0.008195      C
1906         -0.001578  0.008796 -0.000164  0.015955      D
1907         -0.001578  0.008796 -0.000164  0.015955      A
1909         -0.001354  0.001545  0.000007 -0.008195      B


wgt_df
Out[4]: 
  Category   var_1_wgt var_2_wgt var_3_wgt var_4_wgt
0    A       0.182022   0.182022  0.131243  0.182022
1    B       0.534814   0.534814  0.534814  0.534814
2    C       0.131243   0.534814  0.131243  0.182022  
3    D       0.182022   0.151921  0.151921  0.131243

我要做的是为每个类别应用正确的权重以创建新列df ['new_var'],这是加权和。在没有类别的情况下,我可以将权重转换为numpy数组并使用似乎非常快的.dot()方法。但是,我无法看到如何解决我的问题:如果我在主数据帧上使用groupby(),df,我必须以某种方式对我的权重数据框wgt_df执行相同的操作。

实际上,df包含数百万行,我需要多次重复这个计算,所以我很想找到一个矢量化解决方案;否则我可以df.groupby('Category')创建一个数据帧的字典,其关键是类别,例如wgts_dict['A'] = wgts_df[wgts_df.Category == 'A'],并通过lambda x应用我的点逻辑,虽然我也不确定如何执行此操作,因为我需要明确引用当前正在处理的哪个组元素才能撤出正确的wgts_df切片。

2 个答案:

答案 0 :(得分:1)

<强>设置

print(df)
Out[655]: 
           var_1     var_2     var_3     var_4 Category
Symbol                                                 
1903    0.000443  0.006928  0.000000  0.012375        A
1904   -0.000690 -0.007873  0.000171  0.014824        A
1905   -0.001354  0.001545  0.000007 -0.008195        C
1906   -0.001578  0.008796 -0.000164  0.015955        D
1907   -0.001578  0.008796 -0.000164  0.015955        A
1909   -0.001354  0.001545  0.000007 -0.008195        B

print(w)
Out[656]: 
  Category  var_1_wgt  var_2_wgt  var_3_wgt  var_4_wgt
0        A   0.182022   0.182022   0.131243   0.182022
1        B   0.534814   0.534814   0.534814   0.534814
2        C   0.131243   0.534814   0.131243   0.182022
3        D   0.182022   0.151921   0.151921   0.131243

<强>解决方案

#convert Category to numerical encoding
df['C_Number'] = df.Category.apply(lambda x: ord(x.lower())-97)

#Get a dot product for each row with all category weights and the extract the weights by the category number

df['new_var'] = ((df.iloc[:,:4].values).dot(w.iloc[:,-4:].values))[np.arange(len(df)),df.C_Number]

Out[654]: 
           var_1     var_2     var_3     var_4 Category  C_Number   new_var
Symbol                                                                     
1903    0.000443  0.006928  0.000000  0.012375        A         0  0.006038
1904   -0.000690 -0.007873  0.000171  0.014824        A         0 -0.001615
1905   -0.001354  0.001545  0.000007 -0.008195        C         2 -0.000595
1906   -0.001578  0.008796 -0.000164  0.015955        D         3  0.006481
1907   -0.001578  0.008796 -0.000164  0.015955        A         0  0.007300
1909   -0.001354  0.001545  0.000007 -0.008195        B         1 -0.000661

答案 1 :(得分:1)

您可以执行分组(按类别选择),然后执行dot(),或者您可以执行dot(),然后按类别进行选择。后者在熊猫中更快更简单。请注意,我使用的数据匹配数据中的列名称和权重框架。

dot()的代码,然后选择:

df['dot'] = df[df_wgt.columns].dot(df_wgt.T).lookup(df.index, df.Category)

已执行的步骤......

  1. 选择要用于df[df_wgt.columns]

    的列

    这使用了重量数据框中的列标签和排序。这很重要,因为dot()需要数据的顺序正确。

  2. 使用.dot(df_wgt.T)

    对转置的权重数据框执行点积

    调整权重会使它们处于.dot()的正确方向。这样可以计算每行数据的所有权重类别。这意味着在这种情况下,我们所做的乘法数量将是所需数量的四倍,但它仍然可能比分组更快。

  3. 使用.lookup(df.index, df.Category)

    选择所需的点积

    使用lookup()我们可以收集该行类别的正确结果。

  4. select(groupby)和dot()的代码:

    def dot(group):
        category = group['Category'].iloc[0]
        weights = df_wgt.loc[category].values
        return pd.Series(
            np.dot(group[df_wgt.columns].values, weights), index=group.index)
    
    df['dot'] = df.groupby(['Category']).apply(dot) \
        .reset_index().set_index('Index')[0]
    

    测试代码:

    import pandas as pd
    from io import StringIO
    
    df = pd.read_fwf(StringIO(u"""
        Index          var_1      var_2     var_3     var_4    Category
        1903          0.000443  0.006928  0.000000  0.012375      A
        1904         -0.000690 -0.007873  0.000171  0.014824      A
        1905         -0.001354  0.001545  0.000007 -0.008195      C
        1906         -0.001578  0.008796 -0.000164  0.015955      D
        1907         -0.001578  0.008796 -0.000164  0.015955      A
        1909         -0.001354  0.001545  0.000007 -0.008195      B"""),
                     header=1, skiprows=0).set_index(['Index'])
    
    df_wgt = pd.read_fwf(StringIO(u"""
         Category     var_1      var_2     var_3     var_4
            A       0.182022   0.182022  0.131243  0.182022
            B       0.534814   0.534814  0.534814  0.534814
            C       0.131243   0.534814  0.131243  0.182022
            D       0.182022   0.151921  0.151921  0.131243"""),
                     header=1, skiprows=0).set_index(['Category'])
    
    df['dot'] = df[df_wgt.columns].dot(df_wgt.T).lookup(df.index, df.Category)
    print(df)
    

    <强>结果:

              var_1     var_2     var_3     var_4 Category       dot
    Index                                                           
    1903   0.000443  0.006928  0.000000  0.012375        A  0.003594
    1904  -0.000690 -0.007873  0.000171  0.014824        A  0.001162
    1905  -0.001354  0.001545  0.000007 -0.008195        C -0.000842
    1906  -0.001578  0.008796 -0.000164  0.015955        D  0.003118
    1907  -0.001578  0.008796 -0.000164  0.015955        A  0.004196
    1909  -0.001354  0.001545  0.000007 -0.008195        B -0.004277