对于具有NaN的列,rowwise min()和max()失败

时间:2017-08-26 20:18:35

标签: python pandas date datetime nan

我试图获取包含日期

的两列的rowwise max(和min)
from datetime import date
import pandas as pd
import numpy as np    

df = pd.DataFrame({'date_a' : [date(2015, 1, 1), date(2012, 6, 1),
                               date(2013, 1, 1), date(2016, 6, 1)],
                   'date_b' : [date(2012, 7, 1), date(2013, 1, 1), 
                               date(2014, 3, 1), date(2013, 4, 1)]})

df[['date_a', 'date_b']].max(axis=1)
Out[46]: 
0    2015-01-01
1    2013-01-01
2    2014-03-01
3    2016-06-01

正如所料。但是,如果数据帧包含单个NaN值,则整个操作将失败

df_nan = pd.DataFrame({'date_a' : [date(2015, 1, 1), date(2012, 6, 1),
                                   np.NaN, date(2016, 6, 1)],
                       'date_b' : [date(2012, 7, 1), date(2013, 1, 1), 
                                   date(2014, 3, 1), date(2013, 4, 1)]})

df_nan[['date_a', 'date_b']].max(axis=1)
Out[49]: 
0   NaN 
1   NaN
2   NaN
3   NaN
dtype: float64

这里发生了什么?我期待这个结果

0    2015-01-01
1    2013-01-01
2    NaN
3    2016-06-01

如何实现这一目标?

修改

有几个人指出问题可能是我将日期与np.NaN(浮动?)混在一起。 NaN是在我的数据框中引入左边合并的。

df_a = pd.DataFrame({'id' : [1, 1, 1, 1, 2], 
                     'date_from' : [date(2012, 1, 1), date(2012, 6, 1), 
                                   date(2013, 1, 1), date(2013, 6, 1),
                                   date(2012, 1, 1)],
                     'date_to' : [date(2012, 6, 1), date(2013, 1, 1), 
                                 date(2013, 6, 1), date(2014, 1, 1),
                                 date(2013, 1, 1)],
                     'data_a' : [1, 2, 3, 4, 5]})

df_b = pd.DataFrame({'id' : [1, 1], 
                     'date_from' : [date(2012, 8, 1), date(2013, 4,1)], 
                     'date_to' : [date(2013, 4,1), date(2013, 8, 1)], 
                     'data_b' :['A','B']})

df = pd.merge(df_a, df_b, on='id', how='left')
df[['date_from_x', 'date_from_y']].max(axis=1)  
Out[65]: 
0   NaN
1   NaN
2   NaN
3   NaN
4   NaN
5   NaN
6   NaN
7   NaN
8   NaN
dtype: float64

可能是合并没有返回正确的'nan-type'

3 个答案:

答案 0 :(得分:8)

我认为最好的解决方案是使用适当的dtype。 Pandas提供了一个非常完整的datetime dtype。请注意,您使用的是object dtypes ...

>>> df
       date_a      date_b
0  2015-01-01  2012-07-01
1  2012-06-01  2013-01-01
2         NaN  2014-03-01
3  2016-06-01  2013-04-01
>>> df.dtypes
date_a    object
date_b    object
dtype: object

但请注意,使用

时问题会消失
>>> df2 = df.apply(pd.to_datetime)
>>> df2
      date_a     date_b
0 2015-01-01 2012-07-01
1 2012-06-01 2013-01-01
2        NaT 2014-03-01
3 2016-06-01 2013-04-01
>>> df2.min(axis=1)
0   2012-07-01
1   2012-06-01
2   2014-03-01
3   2013-04-01
dtype: datetime64[ns]

答案 1 :(得分:6)

date个对象与列中的浮点(例如NaN)混合时,似乎会发生这种情况。默认情况下,由于单个浮点值而设置numeric_only标志。例如,将df_nan替换为:

df_float = pd.DataFrame({'date_a' : [date(2015, 1, 1), date(2012, 6, 1),
                                    1.023, date(2016, 6, 1)],
                        'date_b' : [date(2012, 7, 1), 3.14, 
                                    date(2014, 3, 1), date(2013, 4, 1)]})

print(df_float.max(1))

0   NaN
1   NaN
2   NaN
3   NaN
dtype: float64

如果手动将标志设置为false,则会正确抛出TypeError,因为:

print(date(2015, 1, 1) < 1.0)

TypeError                                 Traceback (most recent call last)
<ipython-input-362-ccbf44ddb40a> in <module>()
      1 
----> 2 print(date(2015, 1, 1) < 1.0)

TypeError: unorderable types: datetime.date() < float()

但是,熊猫似乎强迫所有人NaN。要解决此问题,使用str转换为df.astype似乎可以执行此操作:

out = df_nan.astype(str).max(1)
print(out) 
0    2015-01-01
1    2013-01-01
2           nan
3    2016-06-01
dtype: object

在这种情况下,按字典顺序排序会产生与以前相同的解决方案。

否则,作为juan suggests,您可以使用datetime转换为pd.to_datetime

out = df_nan.apply(pd.to_datetime, errors='coerce').max(1)
print(out)

0   2015-01-01
1   2013-01-01
2   2014-03-01
3   2016-06-01
dtype: datetime64[ns]

答案 2 :(得分:1)

以下内容应该有效:

>>> df_nan.where(df_nan.T.notnull().all()).max(axis=1)
Out[1]:
0    2015-01-01
1    2013-01-01
2          None
3    2016-06-01
dtype: object

其中:

  1. df_nan.T.notnull().all()计算不包含np.nan
  2. 的行的掩码
  3. df_nan.where()将以前的掩码应用于数据框
  4. .max(axis=1)获得行最大值
  5. 这是有效的,因为所有值均为np.nan的数组的最大值为None。它允许通过不显示最大值来跟踪缺少值的行。

    但是这个决定取决于你,否则@ juanpa.arrivillaga将NaN转换为NaT的解决方案就是你想要的。