将月份添加到pandas中的datetime列

时间:2015-05-19 14:23:43

标签: python python-2.7 python-3.x pandas ipython

我有一个带有2列的数据帧df,如下所示 -

<runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="AAA"
          publicKeyToken="dd8b40231cb0196b"
          culture="en-us" />
        <!-- Assembly versions can be redirected in app, 
          publisher policy, or machine configuration files. -->
        <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

2列的数据类型是对象。

               START_DATE             MONTHS
0              2015-03-21                240
1              2015-03-21                240
2              2015-03-21                240
3              2015-03-21                240
4              2015-03-21                240
5              2015-01-01                120
6              2017-01-01                240
7                     NaN                NaN
8                     NaN                NaN
9                     NaN                NaN

现在,我想通过添加df ['START_DATE']&amp;创建一个新列“结果”。 DF ['个月]。所以,我做了以下 -

>>> df.dtypes
START_DATE    object
MONTHS        object
dtype: object

在这里,我得到以下错误 -

from dateutil.relativedelta import relativedelta  

df['START_DATE'] = pd.to_datetime(df['START_DATE'])
df['MONTHS'] = df['MONTHS'].astype(float)

df['offset'] = df['MONTHS'].apply(lambda x: relativedelta(months=x))

df['Result'] = df['START_DATE'] + df['offset'] 

注意:想要将df ['Months']转换为int,但由于该字段具有Null,因此无效。

你能给我一些指示。谢谢。

5 个答案:

答案 0 :(得分:7)

这是一种执行此操作的矢量化方式,因此应该非常高效。请注意,它不处理月份交叉/结尾(并且不能很好地处理DST更改。我相信这就是您获得时间的原因。)

function forEvery(array,action){
    for(var i=0;i<array.length;i++){
       action(array[i]);
    }
}

forEvery(["test1","test2","test3"],console.log);

如果您需要精确的MonthEnd / Begin处理,这是一种合适的方法。 (使用MonthsOffset得到同一天)

In [32]: df['START_DATE'] + df['MONTHS'].values.astype("timedelta64[M]")
Out[32]: 
0   2035-03-20 20:24:00
1   2035-03-20 20:24:00
2   2035-03-20 20:24:00
3   2035-03-20 20:24:00
4   2035-03-20 20:24:00
5   2024-12-31 10:12:00
6   2036-12-31 20:24:00
7                   NaT
8                   NaT
9                   NaT
Name: START_DATE, dtype: datetime64[ns]

答案 1 :(得分:1)

如果您的数据框很小,请使用以下内容。我使用了axis=1,这是行式操作。如果您的数据框很大,那么它将非常慢

> df['offset'] = df.dropna().apply(lambda v: relativedelta(months=int(v['MONTHS'])) + v['START_DATE'], axis=1)
> df
  START_DATE  MONTHS     offset
0 2015-03-21     240 2035-03-21
1 2015-03-21     240 2035-03-21
2 2015-03-21     240 2035-03-21
3 2015-03-21     240 2035-03-21
4 2015-03-21     240 2035-03-21
5 2015-01-01     120 2025-01-01
6 2017-01-01     240 2037-01-01
7        NaT     NaN        NaT
8        NaT     NaN        NaT
9        NaT     NaN        NaT

答案 2 :(得分:1)

这是一种没有dateutil.relativedelta的方法。请注意,我将MONTHS转换为整数(并且仅在删除空值之后,因为int不接受空值)因为我想每年进行12个月的整数除法,事实上,商是年数的增量,模数/余数是几个月的增量。

import pandas as pd

df = pd.DataFrame({'START_DATE':['2015-03-21','2015-03-21','2015-03-21','2015-03-21',
                                 '2015-03-21','2015-01-01','2017-01-01', None,None,None],
                   'MONTHS':[240,240,240,240,240,120,240,None,None,None]},
                  dtype='object') # replicate example data

df.dropna(inplace=True) # drop nulls so can convert MONTHS to int
df['START_DATE'] = pd.to_datetime(df['START_DATE'])
df['MONTHS'] = df.MONTHS.astype(int)

df.apply(lambda x: pd.datetime(x.START_DATE.year + x.MONTHS / 12,
                               x.START_DATE.month + x.MONTHS % 12,
                               x.START_DATE.day), axis=1)

答案 3 :(得分:1)

这是另一个矢量化 numpy解决方案:

In [111]: mask = (df.START_DATE.notnull() & df.MONTHS.notnull())

In [112]: df.loc[mask, 'Result'] = (
     ...:     df.START_DATE.loc[mask].values.astype('M8[M]') + \
     ...:     (df.MONTHS.loc[mask].values.astype(int) * np.timedelta64(1, 'M'))
     ...: ).astype('M8[D]') - np.timedelta64(1, 'D')
     ...:

In [113]: df
Out[113]:
  START_DATE  MONTHS     Result
0 2015-03-21   240.0 2035-02-28
1 2015-03-21   240.0 2035-02-28
2 2015-03-21   240.0 2035-02-28
3 2015-03-21   240.0 2035-02-28
4 2015-03-21   240.0 2035-02-28
5 2015-01-01   120.0 2024-12-31
6 2017-01-01   240.0 2036-12-31
7        NaT     NaN        NaT
8        NaT     NaN        NaT
9        NaT     NaN        NaT

答案 4 :(得分:0)

作为对Jeff的回应,我认为这在数不为12的倍数的月份中无法正常工作,例如我的初始日期为'2020-05-04(yyyy-mm-dd),月份为57。但是加法得到2025-02-01(而不是2025-02-04)。

init_workbook['CALC_DATE']= init_workbook['STRTDATE']+init_workbook['MONTHS'].values.astype("timedelta64[M]")

>>> init_workbook.head(4)
   MONTHS    STRTDATE   CALC_DATE
0      12  2020-05-04  2021-05-04
1      12  2020-05-04  2021-05-04
2      57  2020-05-04  2025-02-01
3      34  2020-05-20  2023-03-20

再次,如果日期大于12,则给出正确的结果,但是如果日期<12,则失败了