Почему isinstance возвращает неправильное значение только внутри последовательной карты? - PullRequest
0 голосов
/ 14 мая 2018

При вызове isinstance возвращается True снаружи, но False внутри карты над серией (и applymap поверх фрейма данных) ...

import pandas as pd
import pytz
s = pd.Series([pd.Timestamp(2018,5,11,6,0,0,0, pytz.timezone('UTC'))])
s

0   2018-05-11 06:00:00+00:00
dtype: datetime64[ns, UTC]

Вызов isinstance для единственного значения в этой серии приводит кTrue.

isinstance(s.iloc[0], pd.Timestamp)
True

Внутри карты над сериями это дает True.

s.map(lambda x: isinstance(x, pd.Timestamp)).iloc[0]
True

Но если мы попробуем что-то зависящее от этого значения, скажем, преобразовать в строку ...

s.map(lambda x: x.isoformat() if isinstance(x, pd.Timestamp) else x).iloc[0]
Timestamp('2018-05-11 06:00:00+0000', tz='UTC')

... похоже, он возвратил False и метод isoformat не вызывается (фактический вызов метода не имеет значения, поскольку он не вызывается).

Ответы [ 2 ]

0 голосов
/ 14 мая 2018

Похоже, ряды даты и времени преобразуются в DatetimeIndex, а затем индекс передается функции. Конечно, индекс не проходит проверку isinstance.

def f(x):
    print(x)
    if isinstance(x, pd.Timestamp):
        print('{} == {}'.format(type(x).__name__, pd.Timestamp.__name__))
        return x.isoformat()
    else:
        print('{} != {}'.format(type(x).__name__, pd.Timestamp.__name__))
        return x

print(s.map(f))

Выход:

DatetimeIndex(['2018-05-11 06:00:00+00:00'], dtype='datetime64[ns, UTC]', freq=None)
DatetimeIndex != Timestamp
0   2018-05-11 06:00:00+00:00
dtype: datetime64[ns, UTC]

Это не происходит со всеми сериями, но, похоже, зависит от типа. Возможно, это происходит с расширениями или только с datetime.

0 голосов
/ 14 мая 2018

Глядя на источник из .map, выясняется, что Панда проверяет, является ли тип Серии типом расширения .Как указывает OP, это будет вести себя по-разному для разных часовых поясов.Пусть

s1 = pd.Series([
    pd.Timestamp(2018,5,11,6,0,0,0),
])

s2 = pd.Series([
    pd.Timestamp(2018,5,11,6,0,0,0, pytz.timezone('UTC')),
])

Когда вызывается .map, он проверяет pd.api.types.is_extension_type(s).Если s == s1, возвращается False, а если s == s2 - True.

В результате s2.map превращается в s2._values.map.Поскольку s2._values имеет тип DatetimeIndex, вызывается соответствующая реализация .map.Сначала он пытается вызвать f(s2._values) и возвращается к s2._values.map(f) в случае возникновения ошибки.

В этом случае f = lambda x: x.isoformat(x) if isinstance(x, pd.Timestamp) else x.Ошибка не возникает, потому что f проверяет, не завершено ли isinstance(s2._values, pd.Timestamp).Следовательно, f(s2._values) возвращает s2._values.В самом деле, это можно проверить с помощью s2._values is f(s2._values) == True.

Один из обходных путей - убедиться, что pd.api.types.is_extension_type не вызывается, например, s.astype(object).map.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...