【问题标题】:Convert negative datetime to NaT将负日期时间转换为 NaT
【发布时间】:2017-07-15 11:53:04
【问题描述】:

我有两列:“已询问”和“已回答”,但“已回答”是一个对象,而“已询问”是 datetime64[ns]。所以我将“已回答”转换为日期时间:

df['answered'] = pd.to_datetime(df['answered'])

index,  asked,    answered
0     2016-07-04  07/07/2016
1     2016-07-03  07/01/2016
2     2016-07-05  07/09/2016
3     NaT         NaN

然后,我制作了第三列,给出了两者之间的时间差异:

df['Days']= df['answered'] - df['asked']

 index,     asked,    answered,    Days     
    0     2016-07-04  07/07/2016   3 days
    1     2016-07-03  07/01/2016   -2 days
    2     2016-07-05  07/09/2016   4
    3     NaT         NaN          NaT

在@piRSquared 的帮助下,我试图将负数 Days 变成 NaT,但是当我这样做时什么也没发生:

df.update(df[['Days']].mask(df < 0))

我怎样才能把消极的日子变成 NaT?

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    使用mask

    df.mask(df < 0)
    
             Days    col2
    index                
    0     20 days     NaT
    1     61 days 78 days
    2         NaT 10 days
    

    pd.DataFrame.mask 采用一个布尔数组来标识要屏蔽的位置。如果传递了可选的第二个参数,它将用可选参数中指定的值替换标识位置中的值。如果未传递该参数,就像我提出的解决方案一样,则将标识的值替换为空值。由于这些列的dtypestimedelta,因此相应的空值将是NaT


    假设您的数据框由许多列组成。您可以只关注您关心的特定列。

    df[['Days', 'col2']].mask(df < 0)
    

    然后您可以使用 df 就地更新

    df.update(df[['Days', 'col2']].mask(df < 0))
    

    假设您想获取所有 timedelta 列

    df.select_dtypes([np.timedelta]).mask(df < 0)
    

    更新

    df.update(df.select_dtypes([np.timedelta64]).mask(df < 0))
    

    【讨论】:

    • 我得到“无效的类型比较”。是不是因为我有更多的列,而我只放了这两个?我试过这个但无济于事: df.mask(df['Days']
    • 由于某种原因仍然无法正常工作。当我打印出负日期时,我得到:“-5 天 +00:00:00”。您提供的解决方案不会引发错误,但不会将否定变为 NaT。这个问题还有其他解决方案吗?
    • @AdamSchroeder dtype 是什么? df.Days.dtype
    • 我得到了这个:
    • 对不起,我的错误。我得到了这个:dtype('
    【解决方案2】:

    对于我来说,Series(列)由0 Timedelta 工作,然后由Series.maskloc 创建NaT

    mask = df['Days'] < pd.Timedelta(0)
    df['Days'] = df['Days'].mask(mask)
    print (df)
           asked   answered   Days
    0 2016-07-04 2016-07-07 3 days
    1 2016-07-03 2016-07-01    NaT
    2 2016-07-05 2016-07-09 4 days
    3        NaT        NaT    NaT
    

    或者:

    mask = df['Days'] < pd.Timedelta(0)
    df.loc[mask, 'Days'] = np.nan
    print (df)
           asked   answered   Days
    0 2016-07-04 2016-07-07 3 days
    1 2016-07-03 2016-07-01    NaT
    2 2016-07-05 2016-07-09 4 days
    3        NaT        NaT    NaT
    

    但如果将0 TimedeltaDataFrame 进行比较,则会出现错误:

    print (df)
           asked   answered    Days   Days2
    0 2016-07-04 2016-07-07  3 days  3 days
    1 2016-07-03 2016-07-01 -2 days -2 days
    2 2016-07-05 2016-07-09  4 days  4 days
    3        NaT        NaT     NaT     NaT
    
    df1 = df.select_dtypes([np.timedelta64])
    
    #return wrong mask
    m1 = df1 < pd.Timedelta(0)
    print (m1)
        Days  Days2
    0  False  False
    1  False  False
    2  False  False
    3   True   True
    
    #if comapre with apply by Series it works
    m2 = df1.apply(lambda x: x < pd.Timedelta(0))
    print (m2)
        Days  Days2
    0  False  False
    1   True   True
    2  False  False
    3  False  False
    
    #compare numpy array works but warning 
    m3 = df1.values < np.array(0, dtype=np.timedelta64)
    print (m3)
    [[False False]
     [ True  True]
     [False False]
     [ True  True]]
    

    FutureWarning:在未来,'NAT

    df[df1.columns] = df1.mask(m2)
    print (df)
           asked   answered   Days  Days2
    0 2016-07-04 2016-07-07 3 days 3 days
    1 2016-07-03 2016-07-01    NaT    NaT
    2 2016-07-05 2016-07-09 4 days 4 days
    3        NaT        NaT    NaT    NaT
    

    【讨论】:

    • 谢谢@jezrael,我已经为此工作了好几个小时。您的解决方案和详细解释对我很有帮助。
    猜你喜欢
    • 2022-12-21
    • 2018-05-20
    • 1970-01-01
    • 1970-01-01
    • 2014-07-01
    • 1970-01-01
    • 2013-09-20
    相关资源
    最近更新 更多