我正试图从NaT的角度获取几个包含datetime64数据的Pandas Series对象的最小值和最大值。如果dtype是float64,np.minimum和np.maximum会按照我想要的方式工作。也就是说,一旦比较中的任何元素为NaN,NaN就是该比较的结果。例如:
>>> s1
0 0.0
1 1.8
2 3.6
3 5.4
dtype: float64
>>> s2
0 10.0
1 17.0
2 NaN
3 14.0
dtype: float64
>>> np.maximum(s1, s2)
0 10.0
1 17.0
2 NaN
3 14.0
dtype: float64
>>> np.minimum(s1, s2)
0 0.0
1 1.8
2 NaN
3 5.4
dtype: float64
如果s1和s2是datetime64对象,则此方法不起作用:
>>> s1
0 2199-12-31
1 2199-12-31
2 2199-12-31
3 2199-12-31
dtype: datetime64[ns]
>>> s2
0 NaT
1 2018-10-30
2 NaT
3 NaT
dtype: datetime64[ns]
>>> np.maximum(s1, s2)
0 2199-12-31
1 2199-12-31
2 2199-12-31
3 2199-12-31
dtype: datetime64[ns]
>>> np.minimum(s1, s2)
0 2199-12-31
1 2018-10-30
2 2199-12-31
3 2199-12-31
dtype: datetime64[ns]
我希望无论计算最小值还是最大值,索引0、2和3都会显示为NaT。 (我意识到numpy的功能可能不是最佳选择,但我没有成功找到合适的Pandas类似物。)
稍作阅读后,我发现NaT大约等于NaN,后者具有适当的浮点表示形式。进一步的阅读表明,没有简单的方法可以使NaT“污染”这些比较。 NaN在浮点上下文中以最小/最大比较的方式传播NaT的正确方法是什么?也许有相当于numpy的Pandas等效物。{maximum,minimum}可以识别NaT吗?
答案 0 :(得分:1)
pd.Series.mask
似乎是一种不放弃向量化的解决方案:
s1 = pd.Series([pd.datetime(2099, 12, 31)]*4)
s2 = pd.Series([pd.NaT, pd.datetime(2018, 10, 30), pd.NaT, pd.NaT])
null_check = s1.isnull() | s2.isnull()
res_max = np.maximum(s1, s2).mask(null_check, np.nan)
res_min = np.minimum(s1, s2).mask(null_check, np.nan)
print(res_max)
print(res_min)
0 NaT
1 2099-12-31
2 NaT
3 NaT
dtype: datetime64[ns]
0 NaT
1 2018-10-30
2 NaT
3 NaT
dtype: datetime64[ns]
如您所发现的,您看到的行为的原因是pd.NaT
具有关联的int
值,该值用于比较操作:
print(pd.to_numeric(pd.Series([pd.NaT])))
0 -9223372036854775808
dtype: int64
答案 1 :(得分:0)
不确定这是最好的方法,但是如果您使用object
将s1和s2的类型更改为astype
,则使用np.minimum
和np.maximum
仍然可以得到一系列datetime64[ns]
,例如:
print (np.maximum(s1.astype(object), s2.astype(object)))
0 NaT
1 2199-12-31
2 NaT
3 NaT
Name: 1, dtype: datetime64[ns]
答案 2 :(得分:0)
我相信我已经弄清楚了。 (好吧,至少我想出了一种给猫做皮的方法。)它虽然不是很漂亮,但是比我最初将所有逻辑嵌入apply()的解决方案要快得多。简要地说,该解决方案涉及将datetime元素转换为int,将pd.NaT的int版本映射到np.nan,应用np.minimum / np.maximum,然后再转换回datetime64。 apply()仍然涉及,但是逻辑比我原来的要多得多。 (毫无疑问,它仍然可以改进。我对Pandas / NumPy的了解并不多...)
>>> s1 = pd.Series([pd.NaT, pd.datetime(2018, 10, 30), pd.NaT, pd.NaT])
>>> s1
0 NaT
1 2018-10-30
2 NaT
3 NaT
dtype: datetime64[ns]
>>> nanish = int(pd.NaT)
>>> nanish
-9223372036854775808
>>> s2 = pd.to_numeric(s1)
>>> s2
0 -9223372036854775808
1 1540857600000000000
2 -9223372036854775808
3 -9223372036854775808
dtype: int64
>>> s3 = s2.apply(lambda x: np.nan if x == nanish else x)
>>> s3
0 NaN
1 1.540858e+18
2 NaN
3 NaN
dtype: float64
>>> s5 = np.maximum(s3, s4)
>>> s5
0 NaN
1 1.540858e+18
2 NaN
3 NaN
dtype: float64
>>> s6 = pd.to_datetime(s5)
>>> s6
0 NaT
1 2018-10-30
2 NaT
3 NaT
dtype: datetime64[ns]