【问题标题】:Speedy complex Pandas & dictionary manipulation快速复杂的 Pandas 和字典操作
【发布时间】:2020-06-05 23:52:12
【问题描述】:

我是 Pandas 的新手,请就棘手的数据透视表操作寻求一些建议。

我有两个 Pandas 数据透视表和一个字典。第一个数据透视表有一些为零的值。第二个数据透视表具有相同的因子和级别,但值不同。字典是每个因素的所有可能水平对的集合。示例代码:

df = pd.DataFrame({'MyColumn1': ['A', 'A', 'B', 'B'],
                   'MyColumn2': ['M', 'N', 'M', 'P'],
                   'Value': [1, 1, 1, 1]})
table = pd.pivot_table(df, values='Value', index=['MyColumn1', 'MyColumn2'], aggfunc=np.sum, fill_value = 0, dropna = False)

df2 = pd.DataFrame({'MyColumn1': ['A', 'A', 'A', 'B', 'B', 'B'],
                   'MyColumn2': ['M', 'N', 'P', 'M', 'N', 'P'],
                   'Value': [5, 10, 15, 20, 25, 30]})
table2 = pd.pivot_table(df2, values='Value', index=['MyColumn1', 'MyColumn2'], aggfunc=np.sum)

myDictionary = {'MyColumn1': {('A', 'A'): 10, ('A', 'B'): 20, 
                  ('B', 'A'): 30, ('B', 'B'): 40},
        'MyColumn2': {('M', 'M'): 1, ('M', 'N'): 2, ('M', 'P'): 3,
                  ('N', 'M'): 4, ('N', 'N'): 5, ('N', 'P'): 6,
                  ('P', 'M'): 7, ('P', 'N'): 8, ('P', 'P'): 9}}

此代码生成以下表格:

TABLE                Value
MyColumn1 MyColumn2       
A         M              1
          N              1
          P              0
B         M              1
          N              0
          P              1

TABLE2               Value
MyColumn1 MyColumn2       
A         M              5
          N             10
          P             15
B         M             20
          N             25
          P             30

对于Table 中的每个非零条目,我想 (1) 遍历 Table 中的每个零条目,并找到 myDictionary 中与零条目键对应的数字的乘积和非零输入键,(2) 将每个乘积乘以 Table2 中对应的值,然后 (3) 找到这些乘积的总和。

例如,根据上面的数据,算法会计算:

(A, P) -> (A, M) = 10 * 7 = 70, 70 * 15 = 1050
(A, P) -> (A, N) = 10 * 8 = 80, 80 * 15 = 1200
(A, P) -> (B, M) = 20 * 7 = 140, 140 * 15 = 2100
(A, P) -> (B, P) = 20 * 9 = 180, 180 * 15 = 2700

(B, N) -> (A, M) = 30 * 4 = 120, 120 * 25 = 3000
(B, N) -> (A, N) = 30 * 5 = 150, 150 * 25 = 3750
(B, N) -> (B, M) = 40 * 4 = 160, 160 * 25 = 4000
(B, N) -> (B, P) = 40 * 6 = 240, 240 * 25 = 6000

前四行对应于Table 中的第一个零条目,后四行对应于第二个零条目。因为有四个非零条目,所以有四行。接下来,算法乘以Table2 中的对应值。最后,它将为每个非零条目加起来:

(A, M) total = 1050 + 3000 = 4050
(A, N) total = 1200 + 3750 = 4950
(B, M) total = 2100 + 4000 = 6100
(B, P) total = 2700 + 6000 = 8700

所需的结果是一个与原始表形状相同但将这些总和作为值的数据透视表。

                     Value
MyColumn1 MyColumn2       
A         M           4050
          N           4950
          P              0
B         M           6100
          N              0
          P           8700

我正在寻找一种有效执行此操作的方法,因为在实践中,我将有 100,000+ 个零条目、

【问题讨论】:

    标签: python arrays pandas numpy multidimensional-array


    【解决方案1】:

    不确定这对您的实际数据有多快,但这是我会做的:

    col1_df = pd.Series(myDictionary['MyColumn1']).unstack()
    col2_df = pd.Series(myDictionary['MyColumn2']).unstack()
    
    out_df = pd.DataFrame()
    
    # loop through columns
    for col in table.columns:    
        zeros = table['Value'].eq(0)
        non_zero_idx = np.array(table.index[~zeros].to_list())
        zero_idx = np.array(table.index[zeros].to_list())
    
        num_nz, num_z = len(non_zero_idx), len(zero_idx)
    
        xs,ys = np.meshgrid(np.arange(num_z),np.arange(num_nz))
        xs, ys = xs.ravel(), ys.ravel()
    
        col1 = col1_df.lookup(zero_idx[xs,0], non_zero_idx[ys,0])
        col2 = col2_df.lookup(zero_idx[xs,1], non_zero_idx[ys,1])
    
        prods = (col1* col2).reshape(num_nz, num_z).T
    
        values = table2.loc[zeros, ['Value']].values
    
        out_df[col] = (pd.Series((prods * values).sum(0), index=non_zero_idx)
                         .reindex(table.index, fill_value=0)
                      )
    

    输出:

                         Value
    MyColumn1 MyColumn2       
    A         M           4050
              N           4950
              P              0
    B         M           6100
              N              0
              P           8700
    

    【讨论】:

      猜你喜欢
      • 2015-09-13
      • 2016-11-17
      • 1970-01-01
      • 2014-01-05
      • 2020-05-01
      • 2021-08-29
      • 2012-10-01
      • 1970-01-01
      • 2017-05-10
      相关资源
      最近更新 更多