我正在尝试获取包含日期的两列的行最大值(和最小值(
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
如何实现这一点?
我会说最好的解决方案是使用适当的dtype
。熊猫提供了一个非常好的集成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]
当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
。作为一种解决方法,使用df.astype
转换为str
似乎可以做到这一点:
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 建议的那样,您可以使用pd.to_datetime
投射到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]
以下方法应该有效:
>>> 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
哪里:
df_nan.T.notnull().all()
计算不包含np.nan
的行掩码df_nan.where()
将以前的掩码应用于数据帧.max(axis=1)
获取逐行最大值
这是有效的,因为np.nan
所有值的数组的最大值为None
。它允许通过不显示最大值来跟踪缺少值的行。
但是这个决定取决于您,否则您想要将NaN
转换为NaT
的 @juanpa.arrivillaga 的解决方案。