Клип Pandas 0.25.3 в некоторых случаях падает на чанки, созданные при повторной выборке - PullRequest
4 голосов
/ 16 апреля 2020

У меня довольно узкая проблема, связанная с результатом групповой работы на основе времени в pandas 0.25.3.

Я пишу библиотеку для выполнения различных агрегаций на основе времени и встретил то, что может быть ошибка в очень специфических c случаях. Это не происходит в pandas> = 1, но я хотел бы по-прежнему поддерживать pandas 0.25.3, если это возможно (это все еще актуально для наших пользователей).

Следующий случай Я сузил результаты в бесконечном l oop отловах исключений в "pandas / core / internals / blocks.py in where" и в конечном итоге python cra sh с кодом выхода 134:

import pandas as pd

data = pd.DataFrame(
    data=[15.0, 0.0, 0.0, -10.0,  0.0],
    index=pd.to_datetime(
        [
            "2018-01-01 00:00:00.000000",
            "2018-01-01 00:25:00.000000",
            "2018-01-01 00:30:00.000000",
            "2018-01-01 00:31:00.000000",
            "2018-01-01 00:47:00.000000",
        ]
    )
)


def clip_low_at_0(x):
    return x.clip(lower=0).sum()


data.resample("30min").agg(clip_low_at_0)

Моя Python версия 3.7.6, pandas 0.25.3.

В качестве примечания, она хорошо работает с итераторами:

for entry, group in data.resample("30min"):
    clip_low_at_0(x=group)

И data.groupby(pd.Grouper(freq="30min")) имеет точно такая же проблема.

Группа, вызывающая проблему, является следующей (второй):

                        0
2018-01-01 00:30:00   0.0
2018-01-01 00:31:00 -10.0
2018-01-01 00:47:00   0.0

Кажется, это происходит, насколько я проверял:

  • Только с определенным количеством значений, т.е. 2 значения не проблема, 3 и 4 есть проблема, 7 нет ..
  • Только с определенными комбинациями значений. Это вызывает его, некоторые нет, некоторые делают.
  • С любым значением индекса это не похоже на связь.
  • Положение группы имеет значение

На самом деле, копая немного дальше, кажется, что серия, сгенерированная группой, которая вызывает ошибку на .clip(), повреждена. Попытка .copy() не удалась, и некоторые другие методы, такие как сериализация, заканчиваются ошибкой. Может быть, я неправильно использую группу и агг, но был бы другой хороший способ использовать pandas для вычисления этого?

Что меня беспокоит, так это то, что это работает в большинстве случаев, и этот точный случай имеет место в pandas> = 1.0.0.

Если это окажется настоящей ошибкой, я, конечно, сообщу команде pandas 'о проблеме. (редактировать: не похоже, что pandas поощряет сообщения об ошибках в более старых версиях)

редактировать: Чтобы уточнить, я бы хотел:

1) Знать, является ли это неправильным использованием или фактическая ошибка на стороне groupby / agg

2) Если есть лучший обходной путь, чем делать сам клип (x.loc [x <0] = 0). Потому что эта группа может привести к другим проблемам в будущем с другими функциями, используемыми для агрегирования. Я хочу придерживаться подхода повторной выборки, чтобы по возможности не обрабатывать индексы самостоятельно, на самом деле я делаю некоторые другие агрегаты, используя ту же структуру. </p>

1 Ответ

5 голосов
/ 24 апреля 2020

Я могу воспроизвести вашу проблему, но, похоже, она ограничена использованием clip(), не так ли? Другие функции, такие как round() et c, работают нормально. Так что для меня это определенно похоже на ошибку Pandas.

В качестве общего обходного пути вы можете напрямую использовать numpy функции вместо Pandas функций в Ваша функция агрегации:

def clip_low_at_0(x):
    return numpy.clip(x, a_min=0, a_max=None).sum()

Тем не менее, ради полноты: конкретный c обходной путь странный один тоже) для багги Поведение Pandas 'clip() заключается в явной установке верхнего предела. Хотя я не получил понимания , почему это работает, на самом деле это так (здесь, по крайней мере):

def clip_low_at_0(x):
    # using numpy's 'double' dtype max value here, but this could
    # be replaced with sys.maxsize or any other sensible constant
    maxval = numpy.finfo('d').max
    return x.clip(lower=0, upper=maxval).sum()

Последнее (вы уже это знаете): нет необходимости обрезать значения внутри функции агрегирования, вы можете просто применить ее заранее ко всему DataFrame:

data.clip(lower=0).resample("30min").sum()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...