熊猫 - 替换派生计算中的行值



我需要根据行索引值进行inplace值替换。 替换值是切片(行和列(数据帧计算。

设置

In [1]: import pandas as pd                                                                                                  
In [2]: cols = [0, 1, 'A0', 'A1', 'A2', 'A3', 'B0', 'B1', 'B2', 'B3']                                                        
In [3]: data = [['sum', 4531.0010, 0, 0, 0, 2, 0, 0, 0, 7], 
...:         ['', 4531.0010, 5, 6, 3, 0, 5, 4, 7, 0], 
...:         ['', 4531.0010, 1, 3, 9, 0, 2, 2, 3, 0], 
...:         ['sum', 5037.0022, 0, 0, 0, 8, 0, 0, 0, 5], 
...:         ['', 5037.0022, 2, 2, 3, 0, 1, 3, 9, 0], 
...:         ['', 5037.0022, 5, 4, 7, 0, 5, 6, 3, 0]]                                                                     
In [4]: df = pd.DataFrame(data=data, columns=cols)                                                                           
In [5]: df = df.set_index(list(df.columns[[0, 1]]))                                                                          
In [6]: df                                                                                                                   
Out[6]: 
A0  A1  A2  A3  B0  B1  B2  B3
0   1                                        
sum 4531.0010   0   0   0   2   0   0   0   7
4531.0010   5   6   3   0   5   4   7   0
4531.0010   1   3   9   0   2   2   3   0
sum 5037.0022   0   0   0   8   0   0   0   5
5037.0022   2   2   3   0   1   3   9   0
5037.0022   5   4   7   0   5   6   3   0

如您所见,该行是多重索引的,index=1 是一个表示数据子集的数字。 在每个数据子集中,index=0 中都有一个"总和",我想将其向上(或向下("分布"到零余额。

计算基本上是将"A"列和具有相同值的索引 1 行相加为分母。 然后,该数据组的行的总和就是分子。 然后使用该比率在行之间分配总和。

对于行 = 4531.0010 和带 A 的列,其计算公式为:

(5+6+3(/(5+6+3+1+3+9(*2 = 第 1 行,A3 列(1+3+9(/(5+6+3+1+3+9(*2 = 第 2 行,A3

生成的df如下所示:

Out[7]: 
A0  A1  A2     A3  B0  B1  B2     B3
0   1                                              
sum 4531.0010   0   0   0  2.000   0   0   0  7.000
4531.0010   5   6   3  1.037   5   4   7  4.870
4531.0010   1   3   9  0.923   2   2   3  2.130
sum 5037.0022   0   0   0  8.000   0   0   0  5.000
5037.0022   2   2   3  2.435   1   3   9  2.407
5037.0022   5   4   7  5.565   5   6   3  2.593

行数不是固定的 - 可能有一个,也可能有 10 行。

我尝试过什么

我尝试使用.pivot_table()的变体,但我不知道如何使用除法来逆转该过程。 举个例子。

我也使用过.sum()的变体,但试图使用切片来约束df是我无法做到的。 众多例子之一。

我想我可以让它与很多 python 函数一起工作,但似乎应该更有效率。 任何方向都非常感谢。

解决方案工作正常,如果唯一的第一级MultiIndex

cols = [0, 1, 'A0', 'A1', 'A2', 'A3', 'B0', 'B1', 'B2', 'B3']
data = [['sum1', 4531.0010, 0, 0, 0, 2, 0, 0, 0, 7], 
['sum1', 4531.0010, 5, 6, 3, 0, 5, 4, 7, 0], 
['sum1', 4531.0010, 1, 3, 9, 0, 2, 2, 3, 0], 
['sum2', 5037.0022, 0, 0, 0, 8, 0, 0, 0, 5], 
['sum2', 5037.0022, 2, 2, 3, 0, 1, 3, 9, 0], 
['sum2', 5037.0022, 5, 4, 7, 0, 5, 6, 3, 0]]
df = pd.DataFrame(data=data, columns=cols)
df = df.set_index(list(df.columns[[0, 1]]))
print (df)
A0  A1  A2  A3  B0  B1  B2  B3
0    1                                        
sum1 4531.0010   0   0   0   2   0   0   0   7
4531.0010   5   6   3   0   5   4   7   0
4531.0010   1   3   9   0   2   2   3   0
sum2 5037.0022   0   0   0   8   0   0   0   5
5037.0022   2   2   3   0   1   3   9   0
5037.0022   5   4   7   0   5   6   3   0

#loop by first letters of values in columns
for c in df.columns.str[0].unique():
#filter values by first letter
df1 = df.filter(like=c)
#get sum per rows
s = df1.iloc[:, :-1].sum(axis=1)
#get last column
last_col = df1.iloc[:, -1]
#replace 0 in last column to previous non 0
last_col = last_col.mask(last_col == 0).ffill()
#divide by sum per first level with multiple by last_col
s = s.div(s.sum(level=0), level=0).mul(last_col)
#add to last column
df[last_col.name] += s
print (df)
A0  A1  A2        A3  B0  B1  B2        B3
0    1                                                    
sum1 4531.0010   0   0   0  2.000000   0   0   0  7.000000
4531.0010   5   6   3  1.037037   5   4   7  4.869565
4531.0010   1   3   9  0.962963   2   2   3  2.130435
sum2 5037.0022   0   0   0  8.000000   0   0   0  5.000000
5037.0022   2   2   3  2.434783   1   3   9  2.407407
5037.0022   5   4   7  5.565217   5   6   3  2.592593

最新更新