python - Pandas MultiIndex groupby 保留索引级别

标签 python performance pandas

经过研究,我在这个论坛或任何其他论坛上都没有发现类似的问题。

我正在按其内部级别对 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/

相关文章:

python - 为什么这个 Jinja 宏渲染文本而不是 HTML?

python - 如何只打印字典中的一项

python - 为什么 [] 比 list() 快?

c - 使用 SSE 从 _m128i 寄存器中提取非零值

python - 如何 MatPlotLib 绘制两个 DataFrame?

python - Pycharm 3 调试器不适用于 Django

python - 以特殊格式打印当前 UTC 日期时间

c# - 托管代码能否像非托管代码一样快速地执行计算?

python - Pandas 滚动窗口和日期时间索引 : What does `offset` mean?

python - 向量化操作中的 Pandas if 语句