简体   繁体   English

仅重新索引 MultiIndex 数据帧的级别,reindex() 损坏了吗?

[英]Reindexing only level of a MultiIndex dataframe, reindex() broken?

I try to reindex a dataframe with two or more indices on one level only, but using .reindex() with the level argument, as I have seen in this answer seems to do nothing instead of the expected behavior.我尝试仅在一个级别上使用两个或多个索引重新索引数据帧,但是使用.reindex()level参数,正如我在这个答案中看到的那样,似乎除了预期的行为之外什么都不做。

Here is the code I try to make work:这是我尝试使用的代码:

import pandas as pd

dtest = pd.DataFrame([['Martin', 'room_1', 3],
                      ['Martin', 'room_2', 2],
                      ['Georges', 'room_2', 4],
                      ['Georges', 'room_1', 12]],
                     columns=['name', 'room', 'time_spent'])
dtest.set_index(['name', 'room',], inplace=True)
display(dtest)
print(dtest.reindex(
    ['room_1', 'room_2', 'room_3'], level=1, fill_value=0))

which outputs哪个输出

                time_spent
name    room              
Martin  room_1           3
        room_2           2
Georges room_1          12
        room_2           4

whereas the output I am expecting is而我期待的输出是

                time_spent
name    room              
Martin  room_1           3
        room_2           2
        room_3           0
Georges room_1          12
        room_2           4
        room_3           0

reindex() literally didn't do anything. reindex()实际上什么也没做。

Did I miss an important detail on the use of reindex or is something broken?我是否错过了使用reindex的重要细节,或者有什么问题?

I'm using the last version of pandas with Python 3.6.7 (v3.6.7:6ec5cf24b7, Oct 20 2018, 03:02:14).我正在使用 Python 3.6.7(v3.6.7:6ec5cf24b7,2018 年 10 月 20 日,03:02:14)的最新版本的 Pandas。

Edit after accepting the answer接受答案后编辑

I have accepted @anky_91's answer who actually provides two different solutions.我接受了@anky_91 的回答,他实际上提供了两种不同的解决方案。 As my actual use case involves more levels in the multi-index, let me underline the behaviour of his two solutions with more levels.由于我的实际用例涉及多索引中的更多级别,让我用更多级别强调他的两个解决方案的行为。

The starting dataframe is now given by起始数据帧现在由

import pandas as pd

dtest2 = pd.DataFrame([['2020-01-05', 'Martin', 'room_1', 3],
                      ['2020-01-05', 'Martin', 'room_2', 2],
                      ['2020-01-06', 'Georges', 'room_2', 4],
                      ['2020-01-06', 'Georges', 'room_1', 12]],
                     columns=['date', 'name', 'room', 'time_spent'])
dtest2.set_index(['date', 'name', 'room',], inplace=True)
print(dtest2)

which outputs哪个输出

                           time_spent
date       name    room              
2020-01-05 Martin  room_1           3
                   room_2           2
2020-01-06 Georges room_2           4
                   room_1          12

The first solution adapted to this case is适应这种情况的第一个解决方案是

mux = pd.MultiIndex.from_product((dtest2.index.get_level_values(0).unique(),
                                  dtest2.index.get_level_values(1).unique(),
                                  ['room_1', 'room_2', 'room_3']
                            ))
final_first_solution = dtest2.reindex(mux,fill_value=0)
print(final_first_solution)

which outputs哪个输出

                           time_spent
2020-01-05 Martin  room_1           3
                   room_2           2
                   room_3           0
           Georges room_1           0
                   room_2           0
                   room_3           0
2020-01-06 Martin  room_1           0
                   room_2           0
                   room_3           0
           Georges room_1          12
                   room_2           4
                   room_3           0

This is not my desired output as Martin needs to only appear on 2020-01-05 and Georges only appears on 2020-01-06.这不是我想要的输出,因为 Martin 只需要出现在 2020-01-05,而 Georges 只需要出现在 2020-01-06。 In other words, I only want to expand the index on the last level room .换句话说,我只想扩展最后一层room上的索引。 However, I managed to adapt the second solution to get my desired output:但是,我设法调整了第二个解决方案以获得我想要的输出:

final_second_solution = dtest2.unstack((0, 1)).reindex(['room_1', 'room_2', 'room_3'], fill_value=0)\
        .stack((-2, -1)).swaplevel(i=-1, j=0).swaplevel(i=1, j=0).sort_index()
print(final_second_solution)

correctly gives me正确地给我

                           time_spent
date       name    room              
2020-01-05 Martin  room_1         3.0
                   room_2         2.0
                   room_3         0.0
2020-01-06 Georges room_1        12.0
                   room_2         4.0
                   room_3         0.0

hence why I accepted the answer.这就是为什么我接受了答案。 Thanks!谢谢!

Edit 2 for a different use case针对不同的用例编辑 2

After testing more, the above solution fails when you are not adding a new room, but instead want to complete all rooms appearing in the dataframe.经过更多测试,当您没有添加新房间,而是想要完成数据框中出现的所有房间时,上述解决方案失败。 But the solution is simpler, as in this case unstack already creates the missing lines so we just have to use fillna instead of reindex .但是解决方案更简单,因为在这种情况下unstack已经创建了缺失的行,所以我们只需要使用fillna而不是reindex The following code以下代码

import pandas as pd

dtest3 = pd.DataFrame([['2020-01-05', 'Martin', 'room_1', 3],
                      ['2020-01-06', 'Georges', 'room_2', 4]],
                     columns=['date', 'name', 'room', 'time_spent'])
dtest3.set_index(['date', 'name', 'room',], inplace=True)
print(dtest3)
final_third_solution = dtest3.unstack((0, 1)).fillna(0).stack((-2, -1)).reorder_levels([1,2,0]).sort_index()
print(final_third_solution)

hence gives the desired outcome因此给出了想要的结果

                           time_spent
date       name    room              
2020-01-05 Martin  room_1         3.0
                   room_2         0.0
2020-01-06 Georges room_1         0.0
                   room_2         4.0

(I have also included the suggestion in the comments of using reorder_levels instead of using multiple swaplevel ). (我还在评论中包含了使用reorder_levels而不是使用多个swaplevel )。

Using .fillna(0).reindex(..., fill_value=0) should encompass the two cases where you want to complete and add new elements.使用.fillna(0).reindex(..., fill_value=0)应该包含您想要完成和添加新元素的两种情况。

You would need to create a multi index for this using pd.MultiIndex.from_product() and get_level_values :您需要为此使用pd.MultiIndex.from_product()get_level_values创建一个多索引:

mux=(pd.MultiIndex.from_product((dtest.index.get_level_values(0).unique()
                             ,['room_1', 'room_2', 'room_3'])))
final=dtest.reindex(mux,fill_value=0)

                time_spent
Martin  room_1           3
        room_2           2
        room_3           0
Georges room_1          12
        room_2           4
        room_3           0

If you want to just add another index with the existing indexes , use Index.union to the from_product() arg:如果您只想使用现有索引添加另一个索引,请使用Index.unionfrom_product()参数:

mux=(pd.MultiIndex.from_product((dtest.index.get_level_values(0).unique()
        ,dtest.index.get_level_values(1).unique().union(['room3'],sort=False))))
final=dtest.reindex(mux,fill_value=0)

                time_spent
Martin  room_1           3
        room_2           2
        room_3           0
Georges room_1          12
        room_2           4
        room_3           0

Adding another metod with stack() and unstack() with swaplevel :添加另一个梅托德stack()unstack()swaplevel

final=dtest.unstack(0).reindex(['room_1', 'room_2', 'room_3']
                     ,fill_value=0).stack().swaplevel().sort_index()

                time_spent
name    room              
Georges room_1          12
        room_2           4
        room_3           0
Martin  room_1           3
        room_2           2
        room_3           0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM