2015-05-19 133 views
4

我有一个数据帧DF有如下2列 -添加个月到datetime列在熊猫

   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 

2列的数据类型是对象。

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

现在,我希望通过添加DF [ 'START_DATE'] & DF ['个月],以创建新列 “结果”。所以,我也做了以下 -

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'] 

在这里,我得到下面的错误 -

TypeError: incompatible type [object] for a datetime/timedelta operation 

注:本想转换DF [“月”]为int,但不会作为工作场有空。

您能否请给我一些指示。谢谢。

+0

你得到哪些错误?请发布错误报告。 –

+0

@Borja - 嗨。在我的编辑上面添加了错误。谢谢。 – 0nir

回答

6

这是一个矢量化的方式来做到这一点,所以应该是相当高效的。请注意,它不处理月份交叉/结尾(并且不能很好地处理DST更改,我相信这就是您获得时间的原因)。

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] 

如果您需要确切的MonthEnd/Begin处理,这是一个合适的方法。 (使用MonthsOffset拿到当天)

In [33]: df.dropna().apply(lambda x: x['START_DATE'] + pd.offsets.MonthEnd(x['MONTHS']), axis=1) 
Out[33]: 
0 2035-02-28 
1 2035-02-28 
2 2035-02-28 
3 2035-02-28 
4 2035-02-28 
5 2024-12-31 
6 2036-12-31 
dtype: datetime64[ns] 
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 
+0

它的工作。谢谢。 – 0nir

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) 
0

这里是另一个矢量 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