【问题标题】:Pandas - Number of Months Between Two DatesPandas - 两个日期之间的月数
【发布时间】:2017-08-06 23:02:05
【问题描述】:

我认为这应该很简单,但我所看到的是涉及迭代数据框日期字段以确定两个日期之间差异的技术。我遇到了麻烦。我熟悉 MSSQL DATEDIFF,所以我认为 Pandas 日期时间会有类似的东西。我也许是这样,但我错过了。

是否有一种 Pandonic 方法可以将两个日期(日期时间)之间的月数确定为整数而无需迭代?请记住,可能有数百万行,因此性能是一个考虑因素。

日期是日期时间对象,结果是这样的 - 新列是月份:

Date1           Date2         Months
2016-04-07      2017-02-01    11
2017-02-01      2017-03-05    1

【问题讨论】:

    标签: python pandas date diff


    【解决方案1】:

    这适用于 pandas 1.1.1:

    df['Months'] = df['Date2'].dt.to_period('M').astype(int) - df['Date1'].dt.to_period('M').astype(int)
    
    df
    
    # Out[11]: 
    #        Date1      Date2  Months
    # 0 2016-04-07 2017-02-01      10
    # 1 2017-02-01 2017-03-05       1
    

    【讨论】:

      【解决方案2】:

      只是对@pberkes 答案的一个小补充。 如果您希望答案是整数值并且不是 pandas._libs.tslibs.offsets.MonthEnd,只需将 .n 附加到上述代码即可。

      (pd.to_datetime('today').to_period('M') - pd.to_datetime('2020-01-01').to_period('M')).n
      # [Out]:
      # 7
      

      【讨论】:

        【解决方案3】:

        时差有两种概念,在某种意义上都是正确的。让我们比较一下 7 月 31 日和 9 月 1 日之间的月份差异:

        import numpy as np
        import pandas as pd
        
        dtr = pd.date_range(start="2016-07-31", end="2016-09-01", freq="D")
        delta1 = int((dtr[-1] - dtr[0])/np.timedelta64(1,'M'))
        delta2 = (dtr[-1].to_period('M') - dtr[0].to_period('M')).n
        print(delta1,delta2)
        

        使用 numpy 的 timedelta,delta1=1,考虑到两者之间只有一个月,这是正确的,但 delta2=2,考虑到 9 月距离 7 月还有两个月,这也是正确的。在大多数情况下,两者都会给出相同的答案,但考虑到上下文,一个可能比另一个更正确。

        【讨论】:

          【解决方案4】:

          另一种可能更优雅的解决方案是 df.Date2.dt.to_period('M') - df.Date1.dt.to_period('M'),避免了舍入错误。

          【讨论】:

          • 我认为这是更正确的答案,因为舍入错误肯定会造成麻烦。
          • 返回 int 系列,使用以下代码; from operator import attrgetter (df.Date2.dt.to_period('M') - df.Date1.dt.to_period('M')).to_period('M')).apply(attrgetter('n')) 根据this post
          • 不适用于 pandas 版本 > 0.24.0。更新代码见this答案。
          【解决方案5】:

          这是我朋友的一个非常简单的答案:

          df['nb_months'] = ((df.date2 - df.date1)/np.timedelta64(1, 'M'))
          

          现在:

          df['nb_months'] = df['nb_months'].astype(int)
          

          【讨论】:

          • 只需使用 astype('int') bro 转换为整数
          • df['month'] = ((df.date2 - df.date1) / np.timedelta64(1, 'M')).astype(int) 可以解决问题。快速完成。谢谢兄弟。
          • 我同意不和谐。另一个解决方案更好,因为它负责舍入。此处建议的 .asType 方法因 NaT 行而失败(如果您刚刚计算了最后一行始终是 NaT 的“下一个日期”字段,您可能会得到)
          • 当心:例如,2 月 1 日到 3 月 1 日之间的 0 个月——这就是你真正想要的吗?根据所讨论的月份,它给出的月份数略多于或少于一个整数。例如,(pd.Timestamp('2018-03-01') - pd.Timestamp('2018-02-01')) / np.timedelta64(1, 'M') == 0.91993675。 @piRSquared 的解决方案,或者.round() 可能更好。
          • 假设你运行的是 Python 3,你可以使用 // 运算符进行整数除法得到整数 df['nb_months'] = (df.date2 - df.date1) // np.timedelta64(1, 'M')
          【解决方案6】:
          df.assign(
              Months=
              (df.Date2.dt.year - df.Date1.dt.year) * 12 +
              (df.Date2.dt.month - df.Date1.dt.month)
          )
          
                 Date1      Date2  Months
          0 2016-04-07 2017-02-01      10
          1 2017-02-01 2017-03-05       1
          

          【讨论】:

          • 这个也可以。我得到 10 和 1 个月。使用@Noobie 解决方案,我得到 9 和 1。所以这个是包容性的。根据我对任何特定项目的需求,两者都非常有用。谢谢。
          • 或者简单地说:df["Months"] = (df.Date2.dt.year - df.Date1.dt.year) * 12 + (df.Date2.dt.month - df.Date1 .dt.month)
          猜你喜欢
          • 2011-01-01
          • 1970-01-01
          • 2019-03-28
          • 2011-06-06
          相关资源
          最近更新 更多