使用Pandas DataFrame按特定顺序排序列

14

给定这个数据框:

df = pd.DataFrame([['August', 2], ['July', 3], ['Sept', 6]], columns=['A', 'B'])

我希望按照这个顺序对A列进行排序:七月,八月,九月。是否有一种方法可以使用类似于“sort_values”这样的排序函数,但预先定义排序顺序?

7个回答

16

使用Categorical

df.A=pd.Categorical(df.A,categories=['July', 'August', 'Sept'])
df=df.sort_values('A')
df
Out[310]: 
        A  B
1    July  3
0  August  2
2    Sept  6

谢谢,当它存在时,你能分类定义列吗? - sparrow
@Sparrow,抱歉,您的意思是它存在之后发生什么? - BENY
df.A=df.A.astype('category') @sparrow pd.DataFrame(data=df.A, dtype='category') - BENY
需要注意的是,如果您想自定义排序顺序,您将不得不构建一个自定义可迭代对象。这可能是最方便的方法,更何况速度也是最快的。 - PMende
1
当我以这种方式传递它们时,它可以正常工作:df['A'] = df['A'].astype(pd.api.types.CategoricalDtype(categories=['July','August','Sept']))。参考链接:https://dev59.com/YFYN5IYBdhLWcg3wXnNa - sparrow
显示剩余4条评论

8

在字典中定义顺序并根据它进行排序。

sort_dict = {'July':0,'August':1,'Sept':2}
df.iloc[df['A'].map(sort_dict).sort_values().index]

输出

       A    B
1   July    3
0   August  2
2   Sept    6

5
自 pandas 版本 1.1.0 开始,sort_values 支持按键排序。
df = df.sort_values('A', key=lambda s: s.apply(['July', 'August', 'Sept'].index), ignore_index=True)

这是排序的规范且最通用的方式。要求键函数向量化有点荒谬,并迫使您使用这个不太简单的s.apply结构,而文档中也没有提供示例! - Praveen

4
你反对使用完整的月份名称或统一的缩写吗?
df = pd.DataFrame([['August', 2], ['July', 3], ['Sept', 6]], columns=['A', 'B'])

df

import calendar

df = df.replace({'Sept':'September'})

calendar.month_name[1:]

输出:

['January',
 'February',
 'March',
 'April',
 'May',
 'June',
 'July',
 'August',
 'September',
 'October',
 'November',
 'December']

df['A'] = pd.Categorical(df.A, categories=calendar.month_name[1:], ordered=True)

df.sort_values('A')

输出:

           A  B
1       July  3
0     August  2
2  September  6

或者使用calendar.month_abbr

calendar.month_abbr[1:]

输出:

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

1
你可以为列分配自己的排序值,按这些值排序,然后将它们删除:
df = pd.DataFrame([['August', 2], ['July', 3], ['Sept', 6]], columns=['A', 'B'])
value_map = {'August': 1, 'July': 0, 'Sept': 2}
def sort_by_key(df, col, value_map):
    df = df.assign(sort = lambda df: df[col].map(value_map))
    return df.sort_values('sort') \
             .drop('sort', axis='columns')

sort_by_key(df, 'A', value_map)

结果为:
        A  B
1    July  3
0  August  2
2    Sept  6

1

暂时将字符串月份转换为日期时间并排序

df = pd.DataFrame([['August', 2], ['July', 3], ['Sept', 6]], columns=['A', 'B'])
df['tmp'] = pd.to_datetime(df['A'].str[:3], format='%b').dt.month
df.sort_values(by = ['tmp']).drop('tmp', 1)


    A       B
1   July    3
0   August  2
2   Sept    6

1
我将您的“Sept”更改为“September”,以保持与其他月份命名约定一致。
然后,我使用pd.date_range创建了一个按月份名称排序的有序列表。
通过您提供的值对该子列表进行了细分(保持正确的月份顺序)。
使用该子列表创建了一个分类变量,然后根据这些值进行了排序。
import pandas as pd


df = pd.DataFrame([['August', 2], ['July', 3], ['September', 6]], columns=['A', 'B'])

full_month_list = pd.date_range('2018-01-01','2019-01-01', freq='MS').strftime("%B").tolist()
partial_month_list = [x for x in month_list if x in df['A'].values]
df['A'] = pd.Categorical(df['A'], partial_month_list)

df.sort_values('A')

结果为:

    A           B
1   July        3
0   August      2
2   September   6

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接