经过研究,我在这个论坛或任何其他论坛上都没有发现类似的问题。
我正在按其内部级别对 MultiIndex 数据框进行分组。问题是,在分组之后我仍然想知道这个内部索引上的“选择值”是什么。
所以我有这样的东西
df = pd.DataFrame([['A', 1, 3],
['A', 2, 4],
['A', 3, 6],
['B', 1, 9],
['B', 2, 10],
['B', 4, 6]],
columns=pd.Index(['Name', 'Date', 'Value'], name='ColumnName')
).set_index(['Name', 'Date'])
ColumnName Value
Name Date
A 1 3
2 4
3 6
B 1 9
2 10
4 6
我想要的是
ColumnName Value
Name Date
A 3 6
B 4 6
我能做的就是使用这个命令:
df.groupby(level=('Name')).last()
正在检索这个:
ColumnName Value
Name
A 6
B 6
或者,通过使用这个命令:
df.groupby(level=('Name','Date')).last()
检索错误。
请记住,这是一个性能敏感的应用程序。
想法?
编辑:与此同时,我确实提交了一个 feature request at GitHub
最佳答案
通过在 groupby 对象上使用 tail(1)
而不是 last()
,您将获得所需的行为:
In [22]: df.groupby(level='Name').tail(1)
Out[22]:
ColumnName Value
Name Date
A 3 6
B 4 6
这是因为 tail
就像一个“过滤器”方法,保持原始索引不变(但只返回某些行,在这种情况下是每个组的最后一行)。 last
不会这样做,因为此方法将为您提供每组中每列的最后一个非 NaN 值,不一定返回原始行。
旧答案(使用 last
):您可以使用 groupby
将要保留在 groupby 中的索引级别作为列来简单地实现此目的:
In [44]: df.reset_index(level='Date').groupby(level=0).last()
Out[44]:
ColumnName Date Value
Name
A 3 6
B 4 6
然后您可以将其设置回索引以获得所需的结果:
In [46]: df.reset_index(level='Date').groupby(level=0).last().set_index('Date', append=True)
Out[46]:
ColumnName Value
Name Date
A 3 6
B 4 6
既然有人问到性能问题,那么 groupby 解决方案在示例数据帧上的速度确实较慢:
In [96]: %timeit get_slice(df)
1000 loops, best of 3: 879 µs per loop
In [97]: %timeit df.reset_index(level='Date').groupby(level='Name').last().set_index('Date', append=True)
100 loops, best of 3: 3.75 ms per loop
In [220]: %timeit df.groupby(level='Name').tail(1)
1000 loops, best of 3: 1.04 ms per loop
但是如果你看一个更大的示例数据框,差异已经小得多(而且 last
方法甚至更快):
In [83]: df1 = pd.DataFrame(
{'Value':np.random.randint(100, size=len(string.letters)*100)},
index=pd.MultiIndex.from_product([list(string.letters), range(100)],
names=['Name', 'Date']))
In [84]: df1
Out[84]:
Value
Name Date
a 0 13
1 9
2 11
3 16
... ...
Z 96 15
97 20
98 40
99 91
[5200 rows x 1 columns]
In [85]: %timeit get_slice(df1)
100 loops, best of 3: 3.24 ms per loop
In [86]: %timeit df1.reset_index(level='Date').groupby(level='Name').last().set_index('Date', append=True)
100 loops, best of 3: 4.69 ms per loop
In [218]: %timeit df1.groupby(level='Name').tail(1)
1000 loops, best of 3: 1.66 ms per loop
当然这取决于具体的应用,但在许多情况下,这种性能差异并不显着。
关于python - Pandas MultiIndex groupby 保留索引级别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37845306/