Python 熊猫和缺失值中特定组之间的多索引和操作

Python 熊猫和缺失值中特定组之间的多索引和操作,python,pandas,Python,Pandas,考虑以下按对(A,B)索引的单列表: 对于B的一个特定值,比如b2,我想得到一个表,列出它的所有值,以及一个额外的列,如果存在b1或b2的对应值,则给出b2和b1之间的差异。因此,结果应该是: b2 b2-b1 a1 3.0 2.0 a2 30.0 20.0 a3 NaN NaN a4 40.0 NaN 其中a3的两列中的NaN表示b1和b2的值都缺失,而a4的NaN表示只有b1缺失 最初,我尝试的解决方案基于: 但这样就得到了一个没有a3行的表

考虑以下按对(A,B)索引的单列表:

对于B的一个特定值,比如b2,我想得到一个表,列出它的所有值,以及一个额外的列,如果存在b1或b2的对应值,则给出b2和b1之间的差异。因此,结果应该是:

      b2  b2-b1
a1   3.0    2.0
a2  30.0   20.0
a3   NaN    NaN
a4  40.0    NaN
其中a3的两列中的NaN表示b1和b2的值都缺失,而a4的NaN表示只有b1缺失

最初,我尝试的解决方案基于:

但这样就得到了一个没有a3行的表(列名可以通过重命名来固定):

这样做的原因是转换似乎保留了原始索引,并且额外的NaN没有插入到表中,对吗?有可能解决这个问题吗

因此,我尝试了一种组中列之间显式差异的替代方法:

import numpy as np
import pandas as pd
import itertools

index = pd.MultiIndex.from_tuples([
    ('a1', 'b1'), 
    ('a1', 'b2'), 
    ('a2', 'b1'),
    ('a2', 'b2'),
    ('a3', 'b1'),
    ('a4', 'b2'),
], names=['A', 'B'])

input_table = pd.DataFrame({'Value': [1,3, 10, 30, 100, 40]}, index=index)

grouped = input_table.groupby(level='B')
b1 = grouped.get_group('b1')
b1.index = b1.index.droplevel(level='B')

b2 = grouped.get_group('b2')
b2.index = b2.index.droplevel(level='B')
b2 = b2.rename(columns={'Value': 'b2'})

b2 = pd.concat([b2, b2['b2'] - b1['Value']], axis=1)
b2.rename(columns={0: 'b2-b1'}, inplace=True)

print(b2)
这是可行的,但由于所有代码都要降低级别,所以列之间的差异可以工作,而分隔的列可以重命名,这似乎相当复杂。
有没有可能使它更简单?

使用
unstack
B
放到列上,使用
assign
创建
b2-b1
drop
删除不需要的列

In [1120]: table.unstack()['Value'].assign(b2b1=lambda x: x.b2-x.b1).drop(['b1', 'b3'], 1)
Out[1120]:
B     b2  b2b1
A
a1   3.0   2.0
a2  30.0  20.0
a3   NaN   NaN
a4  40.0   NaN
要删除索引名,请使用
重命名\u轴

In [1123]: (table.unstack()['Value'].assign(b2b1=lambda x: x.b2-x.b1).drop(['b1', 'b3'], 1)
                 .rename_axis(None).rename_axis(None, 1))
Out[1123]:
      b2  b2b1
a1   3.0   2.0
a2  30.0  20.0
a3   NaN   NaN
a4  40.0   NaN

或者,您可以存储
取消堆栈
结果

In [1127]: dff = table.unstack()['Value'].rename_axis(None).rename_axis(None, 1)

In [1128]: dff['b2-b1'] = dff['b2'] - dff['b1']

In [1129]: dff
Out[1129]:
       b1    b2    b3  b2-b1
a1    1.0   3.0   NaN    2.0
a2   10.0  30.0  31.0   20.0
a3  100.0   NaN   NaN    NaN
a4    NaN  40.0   NaN    NaN

In [1189]: dff[['b1', 'b2-b1']]  # get specific columns
Out[1189]:
       b1  b2-b1
a1    1.0    2.0
a2   10.0   20.0
a3  100.0    NaN
a4    NaN    NaN

细节

In [1124]: table.unstack()
Out[1124]:
    Value
B      b1    b2    b3
A
a1    1.0   3.0   NaN
a2   10.0  30.0  31.0
a3  100.0   NaN   NaN
a4    NaN  40.0   NaN

是否可以避免硬编码要删除的列的名称?即除去“b1”列以外的所有列?在我的例子中,表可能有相当多的B值。谢谢!现在我得到了unstack的可用性:)
In [1123]: (table.unstack()['Value'].assign(b2b1=lambda x: x.b2-x.b1).drop(['b1', 'b3'], 1)
                 .rename_axis(None).rename_axis(None, 1))
Out[1123]:
      b2  b2b1
a1   3.0   2.0
a2  30.0  20.0
a3   NaN   NaN
a4  40.0   NaN
In [1127]: dff = table.unstack()['Value'].rename_axis(None).rename_axis(None, 1)

In [1128]: dff['b2-b1'] = dff['b2'] - dff['b1']

In [1129]: dff
Out[1129]:
       b1    b2    b3  b2-b1
a1    1.0   3.0   NaN    2.0
a2   10.0  30.0  31.0   20.0
a3  100.0   NaN   NaN    NaN
a4    NaN  40.0   NaN    NaN

In [1189]: dff[['b1', 'b2-b1']]  # get specific columns
Out[1189]:
       b1  b2-b1
a1    1.0    2.0
a2   10.0   20.0
a3  100.0    NaN
a4    NaN    NaN
In [1124]: table.unstack()
Out[1124]:
    Value
B      b1    b2    b3
A
a1    1.0   3.0   NaN
a2   10.0  30.0  31.0
a3  100.0   NaN   NaN
a4    NaN  40.0   NaN