【问题标题】:Pandas order rows by datetime month given external order给定外部订单的 Pandas 按日期时间月份排序行
【发布时间】:2018-04-06 15:00:48
【问题描述】:

所以我在订购我的 Dataframe 时遇到了一点麻烦,我尝试使用 this 问题,但没有设法让它工作。我有一个 Dataframe nudf 像这样:

                     date  level_1      0 
0     2016-10-01 00:00:00      0.0  74.00    
1     2016-10-01 00:30:00      0.5     72    
2     2016-10-01 01:00:00      1.0     70    
3     2016-10-01 01:30:00      1.5     64    
4     2016-10-01 02:00:00      2.0     63    
5     2016-10-01 02:30:00      2.5     60    
...                   ...      ...    ...   
19003 2017-09-31 21:30:00     21.5    129    
19004 2017-09-31 22:00:00     22.0    118    
19005 2017-09-31 22:30:00     22.5    106  
19006 2017-09-31 23:00:00     23.0     84    
19007 2017-09-31 23:30:00     23.5     76    

我想做的是按外部月份顺序对行进行排序:

[4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3]

这是过去 12 个月,从上个月开始。我想忽略年份并按照上面的顺序排列每个月的行块。

例如,给定以下行:

0     2016-02-01 00:00:00      0.0  74.00    
1     2016-02-01 00:30:00      0.5     72    
2     2016-03-01 01:00:00      1.0     70    
3     2016-03-01 01:30:00      1.5     64    
4     2017-04-01 02:00:00      2.0     63    
5     2017-04-01 02:30:00      2.5     60  

结果应该是:

4     2017-04-01 02:00:00      2.0     63    
5     2017-04-01 02:30:00      2.5     60
0     2016-02-01 00:00:00      0.0  74.00    
1     2016-02-01 00:30:00      0.5     72    
2     2016-03-01 01:00:00      1.0     70    
3     2016-03-01 01:30:00      1.5     64      

我试过了:

nudf['month'] = nudf.apply(lambda row: row.date.month, axis=1)
nudf.month = nudf.month.astype("category")
nudf.month.cat.set_categories([x.month for x in reversed(_get_last_x_months(12))], inplace=True)

nudf.sort_values(["month"], inplace=True)

但不维护日期和时间顺序。

【问题讨论】:

    标签: python pandas datetime


    【解决方案1】:

    您可以使用单独的categoricalargsortiloc
    另外,请注意我使用了kind='mergesort',因为mergesort 是一种“稳定”的排序算法,并且会保持等值行的相对顺序。

    mcats = [4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3]
    nudf.iloc[pd.Categorical(nudf.date.dt.month, mcats, True).argsort(kind='mergesort')]
    
                     date  level_1     0
    4 2017-04-01 02:00:00      2.0  63.0
    5 2017-04-01 02:30:00      2.5  60.0
    0 2016-02-01 00:00:00      0.0  74.0
    1 2016-02-01 00:30:00      0.5  72.0
    2 2016-03-01 01:00:00      1.0  70.0
    3 2016-03-01 01:30:00      1.5  64.0
    

    您也可以添加列

    mcats = [4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3]
    nudf = nudf.assign(month=pd.Categorical(nudf.date.dt.month, mcats, True))
    nudf.sort_values('month', kind='mergesort')
    
                     date  level_1     0 month
    4 2017-04-01 02:00:00      2.0  63.0     4
    5 2017-04-01 02:30:00      2.5  60.0     4
    0 2016-02-01 00:00:00      0.0  74.0     2
    1 2016-02-01 00:30:00      0.5  72.0     2
    2 2016-03-01 01:00:00      1.0  70.0     3
    3 2016-03-01 01:30:00      1.5  64.0     3
    

    如果我们尝试按月然后按日期排序,我们不需要指定稳定的排序,只需按两列排序

    mcats = [4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3]
    nudf = nudf.assign(month=pd.Categorical(nudf.date.dt.month, mcats, True))
    nudf.sort_values(['month', 'date'])
    

    或者代替argsort 答案,我们可以使用np.lexsort 返回基于多个数组的排序排列。

    mcats = [4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3]
    nudf.iloc[np.lexsort(
        [nudf.date, pd.Categorical(nudf.date.dt.month, mcats, True)]
    )]
    

    【讨论】:

    • 另一个我从来不知道的方便的 pandas 东西。非常有趣的答案!我想知道订单是如何运作的......我会测试一下
    • 如您所见here,我拥有的较大文件的顺序不正确。
    • 我修改了我的帖子以指定一个稳定的排序算法。看看有没有帮助。
    • 与合并排序添加完美结合。非常感谢。
    【解决方案2】:

    您可以使用map 更改值并重新排列列

    # creates an int value based on the date using .dt.month (must be a date type)
    df['month_value'] = df['date'].dt.month
    
    # creates a dictionary that will remap the values
    new_order = {4:1, 5:2, 6:3, 7:4, 8:5, 9:6, 10:7, 11:8, 12:9, 1:10, 2:11, 3:12}
    
    # creates a new column based on the mapping
    df['new_value'] = df['month_value'].map(new_order)
    
    # sorts the values based on the new column
    df.sort_values(by='new_value')
    
               date  month_value  new_value
    4 2017-04-01            4          1
    5 2017-04-01            4          1
    0 2016-02-01            2         11
    1 2016-02-01            2         11
    2 2016-03-01            3         12
    3 2016-03-01            3         12
    

    【讨论】:

      【解决方案3】:

      您可以使用% 完成订购。但要获得您想要的输出,请先按日期时间排序。

      nudf.sort_values(by='date', inplace=True)
      
      mcats = [x.month for x in reversed(_get_last_x_months(12))]
      #[4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3]
      nudf['m_fake'] = (nudf.date.dt.month+(12-mcats[0]))%12
      nudf.sort_values(by='m_fake')
      
      #                 date  val1  val2  m_fake
      #4 2017-04-01 02:00:00   2.0    63       0
      #5 2017-04-01 02:30:00   2.5    60       0
      #0 2016-02-01 00:00:00   0.0    74       10
      #1 2016-02-01 00:30:00   0.5    72       10
      #2 2016-03-01 01:00:00   1.0    70       11
      #3 2016-03-01 01:30:00   1.5    64       11
      

      【讨论】:

      • 排序是由[x.month for x in reversed(_get_last_x_months(12))]生成的,所以我最好使用它。
      • 好的,那么你只需要做 12-order[0] 就再也不用担心了
      • 可以看到here,在更大的数据集上,有些日子是不正常的。
      • 这是因为在大文件中它们没有按日期排序,而在示例中它们是。我刚刚更新为首先根据日期排序,然后应用月份排序。应该这样做。
      • 是的,那是我的错误,您的答案似乎也有效 - 感谢您的帮助,其他答案首先出现,但这也是一个很好的解决方案。
      猜你喜欢
      • 2017-05-26
      • 2018-04-11
      • 2022-08-11
      • 1970-01-01
      • 1970-01-01
      • 2011-05-13
      • 1970-01-01
      • 2018-08-03
      • 2018-01-24
      相关资源
      最近更新 更多