按月份名称对 pandas 数据框系列进行排序

Posted

技术标签:

【中文标题】按月份名称对 pandas 数据框系列进行排序【英文标题】:Sort a pandas dataframe series by month name 【发布时间】:2018-06-11 02:14:34 【问题描述】:

我有一个 Series 对象:

    date   price
    dec      12
    may      15
    apr      13
    ..

问题陈述:我想让它按月显示,并计算每个月的平均价格,然后按月排序。

期望的输出:

 month mean_price
  Jan    XXX
  Feb    XXX
  Mar    XXX

我想制作一个列表并将其传递给排序函数:

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

sort_values 不支持系列。

我遇到的一个大问题是,即使

df = df.sort_values(by='date',ascending=True,inplace=True) 有效 到最初的df,但在我做了groupby 之后,它没有保持从排序的df 出来的顺序。

总之,我需要从初始数据框中这两列。使用月份 (dt.strftime('%B')) 对日期时间列和分组进行排序,排序搞砸了。现在我必须按月份名称对其进行排序。


我的代码:

df # has 5 columns though I need the column 'date' and 'price'

df.sort_values(by='date',inplace=True) #at this part it is sorted according to date, great
total=(df.groupby(df['date'].dt.strftime('%B'))['price'].mean()) # Though now it is not as it was but instead the months appear alphabetically

【问题讨论】:

您是否尝试过df.sort_values(by='Date_col', inplace=True),正如this question 的答案所示? 是的,我只是忘了提及。问题出现在 group by 之后。它只是按字母顺序排列。 好的,您是否尝试过this answer 中概述的在数据框组内排序的过程? 在我的示例中需要按月转换的日期时间的存在使得它难以实现 如何首先将列映射到一系列索引(因此对于每个月,将它的索引存储在months 数组中,而不是名称字符串中),然后对这些数字进行排序? 【参考方案1】:

您可以使用分类数据通过pd.Categorical 启用正确排序:

months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", 
          "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
df['months'] = pd.Categorical(df['months'], categories=months, ordered=True)
df.sort_values(...)  # same as you have now; can use inplace=True

当您指定类别时,pandas 会记住指定的顺序作为默认排序顺序。

文档:Pandas 类别 > sorting & order.

【讨论】:

【参考方案2】:

感谢@Brad Solomon 提供了一种更快的字符串大写方式!

注意 1 @Brad Solomon 使用 pd.categorical 的回答应该比我的回答更能节省您的资源。他展示了如何为您的分类数据分配顺序。你不应该错过它:P

或者,您可以使用。

df = pd.DataFrame([["dec", 12], ["jan", 40], ["mar", 11], ["aug", 21],
                  ["aug", 11], ["jan", 11], ["jan", 1]], 
                   columns=["Month", "Price"])
# Preprocessing: capitalize `jan`, `dec` to `Jan` and `Dec`
df["Month"] = df["Month"].str.capitalize()

# Now the dataset should look like
#   Month Price
#   -----------
#    Dec    XX
#    Jan    XX
#    Apr    XX

# make it a datetime so that we can sort it: 
# use %b because the data use the abbreviation of month
df["Month"] = pd.to_datetime(df.Month, format='%b', errors='coerce').dt.month
df = df.sort_values(by="Month")

total = (df.groupby(df['Month'])['Price'].mean())

# total 
Month
1     17.333333
3     11.000000
8     16.000000
12    12.000000

注意 2 groupby 默认会为你排序组键。请注意在df = df.sort_values(by=SAME_KEY)total = (df.groupby(df[SAME_KEY])['Price'].mean()). 中使用相同的键进行排序和分组,否则可能会出现意外行为。请参阅Groupby preserve order among groups? In which way? 了解更多信息。

注意 3 一种计算效率更高的方法是首先计算均值,然后按月进行排序。这样,您只需要对 12 个项目而不是整个df 进行排序。如果不需要对df 进行排序,它将降低计算成本。

注意 4 对于已经有 month 作为索引的人,并且想知道如何使其分类,请查看 pandas.CategoricalIndex @jezrael 有一个工作示例关于在Pandas series sort by month index中排序的分类索引

【讨论】:

月份和价格是两个不同的列,这些行用于显示其打印方式 酷。然后你只需要大写月份列。然后运行第 3 行和第 4 行。 @J_p 已编辑。 给南。请记住,日期已经在日期时间中,唯一的问题是分组后的排序,如果您愿意,请再次阅读问题 您将缩写名称和全名混合在一起,这就是导致错误的原因。只需尝试找到您使用的所有月份并将其正确映射到整数并使用整数对其进行排序。 aprildec 用于大写:df["Month"].str.upper()。 - 比.apply 快得多。【参考方案3】:

您应该考虑根据轴 0(索引)重新索引它

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

df1 = df.reindex(new_order, axis=0)

【讨论】:

【参考方案4】:

我会使用calender 模块和reindex

series.str.capitalize 帮助大写系列,然后我们使用 calender 模块和带有系列的 map 创建一个字典以获取月份编号。

一旦我们有了月份编号,我们就可以sort_values() 并获取索引。然后reindex

import calendar
df.date=df.date.str.capitalize() #capitalizes the series
d=i:e for e,i in enumerate(calendar.month_abbr) #creates a dictionary
#d=i[:3]:e for e,i in enumerate(calendar.month_name) 
df.reindex(df.date.map(d).sort_values().index) #map + sort_values + reindex with index

  date  price
2  Apr     13
1  May     15
0  Dec     12

【讨论】:

【参考方案5】:

您可以将数字月份值与索引中的名称一起添加(即“01 January”),进行排序然后去掉数字:

total=(df.groupby(df['date'].dt.strftime('%m %B'))['price'].mean()).sort_index()

它可能看起来像这样:

01 January  xxx
02 February     yyy
03 March    zzz
04 April    ttt

 total.index = [ x.split()[1] for x in total.index ]

January xxx
February yyy
March zzz
April ttt

【讨论】:

【参考方案6】:

使用Sort_Dataframeby_Month函数按时间顺序对月份名称进行排序

需要安装包。

$ pip install sorted-months-weekdays
$ pip install sort-dataframeby-monthorweek

示例:

from sorted_months_weekdays import *

from sort_dataframeby_monthorweek import *

df = pd.DataFrame([['Jan',23],['Jan',16],['Dec',35],['Apr',79],['Mar',53],['Mar',12],['Feb',3]], columns=['Month','Sum'])
df
Out[11]: 
  Month  Sum
0   Jan   23
1   Jan   16
2   Dec   35
3   Apr   79
4   Mar   53
5   Mar   12
6   Feb    3

使用以下函数按月份对数据框进行排序

Sort_Dataframeby_Month(df=df,monthcolumnname='Month')
Out[14]: 
  Month  Sum
0   Jan   23
1   Jan   16
2   Feb    3
3   Mar   53
4   Mar   12
5   Apr   79
6   Dec   35

【讨论】:

以上是关于按月份名称对 pandas 数据框系列进行排序的主要内容,如果未能解决你的问题,请参考以下文章

如何以正确的顺序对月份进行排序 Jan-Dec Pandas [重复]

按字符串长度对熊猫系列中的列表进行排序

python - 如何按python中的因子级别对pandas数据框中的行进行重新排序?

python pandas:重命名数据框中的系列?

将 JSON 读取到 pandas 数据框 - ValueError:将 dicts 与非系列混合可能会导致排序不明确

Pandas:排序数据透视表