Как заставить Pandas NaT размножаться как NaN - PullRequest
0 голосов
/ 02 ноября 2018

Я пытаюсь взять минимум и максимум пары объектов серии Pandas, содержащих данные datetime64, в лице NaT. np.minimum и np.maximum работают так, как я хочу, если dtype равен float64. То есть, если какой-либо элемент сравнения представляет собой 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 «загрязнил» эти сравнения. Как правильно распространять NaT в сравнениях мин / макс, как NaN в контексте с плавающей запятой? Может быть, есть эквиваленты Pandas для numpy. {Максимум, минимум}, которые знают NaT?

Ответы [ 3 ]

0 голосов
/ 07 ноября 2018

Мне кажется, я понял это. (Ну, по крайней мере, я нашел один способ ободрать кошку.) Это не очень красиво, но гораздо быстрее, чем мое оригинальное решение, включающее всю логику в apply (). Вкратце, решение включает в себя перевод элементов datetime в ints, сопоставление int-версии pd.NaT с 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]
0 голосов
/ 07 ноября 2018

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
0 голосов
/ 02 ноября 2018

Не уверен, что это лучший способ, но если вы измените тип s1 и s2 на object с помощью 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]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...