在pandas数据框中自定义排序

Kat*_*mar 63 python pandas

我有python pandas数据帧,其中一列包含月份名称.

如何使用字典进行自定义排序,例如:

custom_dict = {'March':0, 'April':1, 'Dec':3}  
Run Code Online (Sandbox Code Playgroud)

And*_*den 101

Pandas 0.15引入了分类系列,它允许更清晰的方式来执行此操作:

首先使月份列成为分类,并指定要使用的顺序.

In [21]: df['m'] = pd.Categorical(df['m'], ["March", "April", "Dec"])

In [22]: df  # looks the same!
Out[22]:
   a  b      m
0  1  2  March
1  5  6    Dec
2  3  4  April
Run Code Online (Sandbox Code Playgroud)

现在,当您对月份列进行排序时,它将根据该列表进行排序:

In [23]: df.sort("m")
Out[23]:
   a  b      m
0  1  2  March
2  3  4  April
1  5  6    Dec
Run Code Online (Sandbox Code Playgroud)

注意:如果列表中没有值,它将转换为NaN.


那些感兴趣的人的答案较旧

您可以创建一个中间系列,并set_index在其上:

df = pd.DataFrame([[1, 2, 'March'],[5, 6, 'Dec'],[3, 4, 'April']], columns=['a','b','m'])
s = df['m'].apply(lambda x: {'March':0, 'April':1, 'Dec':3}[x])
s.sort()

In [4]: df.set_index(s.index).sort()
Out[4]: 
   a  b      m
0  1  2  March
1  3  4  April
2  5  6    Dec
Run Code Online (Sandbox Code Playgroud)

正如评论的那样,在较新的大熊猫中,Series有一种replace更优雅的方法:

s = df['m'].replace({'March':0, 'April':1, 'Dec':3})
Run Code Online (Sandbox Code Playgroud)

稍有不同的是,如果字典外有一个值,它就不会上升(它只会保持不变).

  • 只需确保在较新的熊猫中使用`df.sort_values(“ m”)`(而不是`df.sort(“ m”)`)即可,否则会出现`AttributeError:'DataFrame'对象没有属性'排序'`;) (6认同)

Mic*_*ado 10

游戏有点晚了,但是这里有一种方法可以创建一个使用任意函数对pandas Series,DataFrame和multiindex DataFrame对象进行排序的函数.

我使用了df.iloc[index]方法,该方法按位置引用Series/DataFrame中的行(与之相比df.loc,引用值).使用这个,我们只需要一个返回一系列位置参数的函数:

def sort_pd(key=None,reverse=False,cmp=None):
    def sorter(series):
        series_list = list(series)
        return [series_list.index(i) 
           for i in sorted(series_list,key=key,reverse=reverse,cmp=cmp)]
    return sorter
Run Code Online (Sandbox Code Playgroud)

您可以使用它来创建自定义排序功能.这适用于Andy Hayden的答案中使用的数据框:

df = pd.DataFrame([
    [1, 2, 'March'],
    [5, 6, 'Dec'],
    [3, 4, 'April']], 
  columns=['a','b','m'])

custom_dict = {'March':0, 'April':1, 'Dec':3}
sort_by_custom_dict = sort_pd(key=custom_dict.get)

In [6]: df.iloc[sort_by_custom_dict(df['m'])]
Out[6]:
   a  b  m
0  1  2  March
2  3  4  April
1  5  6  Dec
Run Code Online (Sandbox Code Playgroud)

这也适用于多索引DataFrames和Series对象:

months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']

df = pd.DataFrame([
    ['New York','Mar',12714],
    ['New York','Apr',89238],
    ['Atlanta','Jan',8161],
    ['Atlanta','Sep',5885],
  ],columns=['location','month','sales']).set_index(['location','month'])

sort_by_month = sort_pd(key=months.index)

In [10]: df.iloc[sort_by_month(df.index.get_level_values('month'))]
Out[10]:
                 sales
location  month  
Atlanta   Jan    8161
New York  Mar    12714
          Apr    89238
Atlanta   Sep    5885

sort_by_last_digit = sort_pd(key=lambda x: x%10)

In [12]: pd.Series(list(df['sales'])).iloc[sort_by_last_digit(df['sales'])]
Out[12]:
2    8161
0   12714
3    5885
1   89238
Run Code Online (Sandbox Code Playgroud)

对我来说,这感觉很干净,但它大量使用python操作,而不是依赖于优化的pandas操作.我没有做任何压力测试,但我想这可能会在非常大的DataFrame上变慢.不确定性能与添加,排序,然后删除列的比较.有关加速代码的任何提示将不胜感激!


eum*_*iro 9

import pandas as pd
custom_dict = {'March':0,'April':1,'Dec':3}

df = pd.DataFrame(...) # with columns April, March, Dec (probably alphabetically)

df = pd.DataFrame(df, columns=sorted(custom_dict, key=custom_dict.get))
Run Code Online (Sandbox Code Playgroud)

返回包含March,April,Dec列的DataFrame


cs9*_*s95 5

v0.23 +答案- sort已弃用。
...但这不是答案的重点。有多个选项可以执行此操作。

一个简单的方法是使用输出Series.mapSeries.argsort索引到df使用DataFrame.iloc(因为argsort产生已排序的整数位置); 因为你有一本字典;这变得容易。

# Setup
df
   a  b      m
0  1  2  March
1  5  6    Dec
2  3  4  April

custom_dict = {'March': 0, 'April': 1, 'Dec': 3}  


df.iloc[df['m'].map(custom_dict).argsort()]

   a  b      m
0  1  2  March
2  3  4  April
1  5  6    Dec
Run Code Online (Sandbox Code Playgroud)

如果需要按降序排序,请反转映射。

df.iloc[(-df['m'].map(custom_dict)).argsort()]

   a  b      m
1  5  6    Dec
2  3  4  April
0  1  2  March
Run Code Online (Sandbox Code Playgroud)

请注意,这仅适用于数字项目。否则,您将需要使用来解决此问题sort_values,并访问索引:

df.loc[df['m'].map(custom_dict).sort_values(ascending=False).index]

   a  b      m
1  5  6    Dec
2  3  4  April
0  1  2  March
Run Code Online (Sandbox Code Playgroud)

更多的选择与astype(这是现在不建议使用),或者pd.Categorical,但你需要指定ordered=True为它工作正常

# Older version,
# df['m'].astype(
#    'category', categories=sorted(custom_dict, key=custom_dict.get), ordered=True)
df['m'] = pd.Categorical(
    df['m'], categories=sorted(custom_dict, key=custom_dict.get), ordered=True
)
Run Code Online (Sandbox Code Playgroud)

现在,一个简单的sort_values调用即可解决问题:

df.sort_values('m')

   a  b      m
0  1  2  March
2  3  4  April
1  5  6    Dec
Run Code Online (Sandbox Code Playgroud)

groupby对输出进行排序时,也将遵守分类顺序。

  • 您已经强调过这一点,但我想重申一下,以防其他人浏览并错过它:Pandas Categorical 默认设置“ordered=None”。如果不设置,排序将会错误,或者在 V23 上中断。Max 函数特别会给出类型错误(对于操作 max ,分类未排序)。 (2认同)