Pandas Dataframe Multiindex 按级别和列值排序

Posted

技术标签:

【中文标题】Pandas Dataframe Multiindex 按级别和列值排序【英文标题】:Pandas Dataframe Mutli index sorting by level and column value 【发布时间】:2017-10-16 17:33:20 【问题描述】:

我有一个看起来像这样的熊猫数据框:

                         value
           Id              
2014-03-13 1          -3
           2          -6
           3          -3.2
           4          -3.1
           5          -5
2014-03-14 1          -3.4
           2          -6.2
           3          -3.2
           4          -3.2
           5          -5.9

这基本上是一个具有两级多索引的 groupby 对象。

我想根据value 列按升序对其进行排序,但保持级别 0(日期)不变,这样结果应该如下所示:

                         value
           Id              
2014-03-13 2          -6
           5          -5
           3          -3.2
           4          -3.1
           1          -3
2014-03-14 2          -6.2
           5          -5.9
           1          -3.4
           3          -3.2
           4          -3.2

这里是生成初始数据的代码:

import pandas as pd

dates = [pd.to_datetime('2014-03-13', format='%Y-%m-%d'), pd.to_datetime('2014-03-13', format='%Y-%m-%d'), pd.to_datetime('2014-03-13', format='%Y-%m-%d'), pd.to_datetime('2014-03-13', format='%Y-%m-%d'),
         pd.to_datetime('2014-03-13', format='%Y-%m-%d'),pd.to_datetime('2014-03-14', format='%Y-%m-%d'), pd.to_datetime('2014-03-14', format='%Y-%m-%d'), pd.to_datetime('2014-03-14', format='%Y-%m-%d'), 
         pd.to_datetime('2014-03-14', format='%Y-%m-%d'), pd.to_datetime('2014-03-14', format='%Y-%m-%d')]

values = [-3,-6,-3.2,-3.1,-5,-3.4,-6.2,-3.2,-3.2,-5.9]
Ids = [1,2,3,4,5,1,2,3,4,5]
df = pd.DataFrame('Id': pd.Series(Ids, index=dates),
                   'value': pd.Series(values, index=dates))

df = df.groupby([df.index,'Id']).sum()

【问题讨论】:

【参考方案1】:

据我所知,不可能同时对索引和列进行排序,但一个简单的解决方法如下:

df = df.reset_index().sort_values(by = ['level_0','values']).set_index(['level_0','Id'])

...如果您需要摆脱“level_0”索引标签:

df.index.names = [None, 'Id']

设置:

import pandas as pd
import io

c = io.StringIO(u'''
                Id      value
2014-03-13      1       -3
2014-03-13      2       -6
2014-03-13      3       -3.2                                                                                                                      2014-03-13      4       -3.1
2014-03-13      5       -5
2014-03-14      1       -3.4
2014-03-14      2       -6.2
2014-03-14      3       -3.2
2014-03-14      4       -3.2
2014-03-14      5       -5.9
''')

df = pd.read_csv(c, delim_whitespace = True)
df = df.groupby([df.index,'Id']).max()

初始df:

               value
           Id
2014-03-13 1    -3.0
           2    -6.0
           3    -3.2
           4    -3.1
           5    -5.0
2014-03-14 1    -3.4
           2    -6.2
           3    -3.2
           4    -3.2
           5    -5.9

输出:

               value
           Id
2014-03-13 2    -6.0
           5    -5.0
           3    -3.2
           4    -3.1
           1    -3.0
2014-03-14 2    -6.2
           5    -5.9
           1    -3.4
           3    -3.2
           4    -3.2

【讨论】:

这不行,我得到的和我输入的数据一样! 对,在我的设置中,我包含了一个 date 列,我现在意识到你没有。正在努力。 由于我的索引(包括日期)没有名称,它最终将成为level_0。但即使将date 替换为level_0 也不会改变任何事情。 @JefeBelfort - 我运行了它,它运行良好。使用 level_0 并按要求对值进行排序。 第 5 行出现错误:pandas.io.common.CParserError: Error tokenizing data.【参考方案2】:

对我来说工作reset_index + sort_values + set_index + rename_axis

df = df.reset_index() \
       .sort_values(['level_0','value']) \
       .set_index(['level_0','Id']) \
       .rename_axis([None, 'Id'])
print (df)
               value
           Id       
2014-03-13 2    -6.0
           5    -5.0
           3    -3.2
           4    -3.1
           1    -3.0
2014-03-14 2    -6.2
           5    -5.9
           1    -3.4
           3    -3.2
           4    -3.2

sort_values + swaplevel + sort_index 的另一种解决方案:

df = df.sort_values('value')
       .swaplevel(0,1)
       .sort_index(level=1, sort_remaining=False)
       .swaplevel(0,1)
print (df)
               value
           Id       
2014-03-13 2    -6.0
           5    -5.0
           3    -3.2
           4    -3.1
           1    -3.0
2014-03-14 2    -6.2
           5    -5.9
           1    -3.4
           3    -3.2
           4    -3.2

交换级别是必要的,因为:

print (df.sort_values('value').sort_index(level=0, sort_remaining=False))
               value
           Id       
2014-03-13 1    -3.0
           2    -6.0
           3    -3.2
           4    -3.1
           5    -5.0
2014-03-14 1    -3.4
           2    -6.2
           3    -3.2
           4    -3.2
           5    -5.9

对于熊猫0.23.0 可以排序columns and index levels together:

df.index.names = ['level1','level2']
print (df.sort_values(['level1','value']))
                   value
level1     level2       
2014-03-13 2        -6.0
           5        -5.0
           3        -3.2
           4        -3.1
           1        -3.0
2014-03-14 2        -6.2
           5        -5.9
           1        -3.4
           3        -3.2
           4        -3.2

【讨论】:

这个解决方案假定外层是“可排序的”,有没有办法对多索引的内层进行排序,尊重外层?我的外层由字符串组成,我不想按字母顺序对外层进行排序。 没有数据的难题。但也许需要像df = df.reset_index().groupby('level_0', sort=False).apply(lambda x : x.sort_values('level_1')).set_index(['level_1'], append=True) 这样的东西应该可以工作。如果没有,您可以添加一些数据吗? 谢谢您,先生。这解决了这个问题,但有两个意想不到的后果......如果你能帮助我理解 (1) 索引如何成为表的一部分 (2) 如果列在此处运行 df.reset_index().groupby('level_0', sort=False).apply(lambda x : x.sort_values('level_1')) 后重复,那就太好了是before 和after。概述了数据框的一般结构here 我显然通过删除列解决了这些问题,我只是想弄清楚幕后发生了什么。 Yoi 可以尝试将参数group_keys=False 添加到 groupby。不确定它是否有效,因为现在只能在手机上使用。

以上是关于Pandas Dataframe Multiindex 按级别和列值排序的主要内容,如果未能解决你的问题,请参考以下文章

pandas.DataFrame.loc好慢,怎么遍历访问DataFrame比较快

将 Pandas Multiindexed DataFrame 与 Singleindexed Pandas DataFrame 合并

pandas.DataFrame.loc好慢,怎么遍历访问DataFrame比较快

python pandas dataframe 写入hdfs

pandas怎么选取dataframe中几列

详解pandas获取Dataframe元素值的几种方法