Интерполировать (или экстраполировать) только небольшие пробелы в кадре данных панд

У меня есть pandas DataFrame со временем как индекс (1 мин. Freq) и несколько столбцов данных. Иногда данные содержат NaN. Если это так, я хочу интерполировать только в том случае, если разрыв не превышает 5 минут. В этом случае это будет максимум 5 последовательных NaN. Данные могут выглядеть так (несколько тестовых примеров, которые показывают проблемы):

import numpy as np import pandas as pd from datetime import datetime start = datetime(2014,2,21,14,50) data = pd.DataFrame(index=[start + timedelta(minutes=1*x) for x in range(0, 8)], data={'a': [123.5, np.NaN, 136.3, 164.3, 213.0, 164.3, 213.0, 221.1], 'b': [433.5, 523.2, 536.3, 464.3, 413.0, 164.3, 213.0, 221.1], 'c': [123.5, 132.3, 136.3, 164.3] + [np.NaN]*4, 'd': [np.NaN]*8, 'e': [np.NaN]*7 + [2330.3], 'f': [np.NaN]*4 + [2763.0, 2142.3, 2127.3, 2330.3], 'g': [2330.3] + [np.NaN]*7, 'h': [2330.3] + [np.NaN]*6 + [2777.7]}) 

Он читается следующим образом:

 In [147]: data Out[147]: abcdefgh 2014-02-21 14:50:00 123.5 433.5 123.5 NaN NaN NaN 2330.3 2330.3 2014-02-21 14:51:00 NaN 523.2 132.3 NaN NaN NaN NaN NaN 2014-02-21 14:52:00 136.3 536.3 136.3 NaN NaN NaN NaN NaN 2014-02-21 14:53:00 164.3 464.3 164.3 NaN NaN NaN NaN NaN 2014-02-21 14:54:00 213.0 413.0 NaN NaN NaN 2763.0 NaN NaN 2014-02-21 14:55:00 164.3 164.3 NaN NaN NaN 2142.3 NaN NaN 2014-02-21 14:56:00 213.0 213.0 NaN NaN NaN 2127.3 NaN NaN 2014-02-21 14:57:00 221.1 221.1 NaN NaN 2330.3 2330.3 NaN 2777.7 

Я знаю data.interpolate() но у него есть несколько недостатков, так как он дает этот результат, что хорошо для столбцов ae, но для столбцов fh это не удается по разным причинам ::

  abcdefg \ 2014-02-21 14:50:00 123.5 433.5 123.5 NaN NaN NaN 2330.3 2014-02-21 14:51:00 129.9 523.2 132.3 NaN NaN NaN 2330.3 2014-02-21 14:52:00 136.3 536.3 136.3 NaN NaN NaN 2330.3 2014-02-21 14:53:00 164.3 464.3 164.3 NaN NaN NaN 2330.3 2014-02-21 14:54:00 213.0 413.0 164.3 NaN NaN 2763.0 2330.3 2014-02-21 14:55:00 164.3 164.3 164.3 NaN NaN 2142.3 2330.3 2014-02-21 14:56:00 213.0 213.0 164.3 NaN NaN 2127.3 2330.3 2014-02-21 14:57:00 221.1 221.1 164.3 NaN 2330.3 2330.3 2330.3 h 2014-02-21 14:50:00 2330.300000 2014-02-21 14:51:00 2394.214286 2014-02-21 14:52:00 2458.128571 2014-02-21 14:53:00 2522.042857 2014-02-21 14:54:00 2585.957143 2014-02-21 14:55:00 2649.871429 2014-02-21 14:56:00 2713.785714 2014-02-21 14:57:00 2777.700000 

f) Вначале разрыв состоит из NaN в 4 минуты, их следует заменить на это значение 2763,0 (т.е. экстраполяция назад во времени)

g) Разрыв длится более 5 минут, но все же он экстраполируется

h) Разрыв длится более 5 минут, но промежуток интерполируется.

Я понимаю эти причины, конечно, я нигде не указал, что он не должен интерполировать более длинные промежутки времени, чем 5 минут. Я понимаю, что interpolate только экстраполирует вперед во времени, но я хочу, чтобы она также экстраполировала назад во времени. Есть ли какие-либо известные методы, которые я могу использовать для своей проблемы, не изобретая колесо?

Изменить: метод data.interpolate принимает limit входного параметра, которое определяет максимальное количество последовательных NaN для замены интерполяцией. Но это все еще интерполирует до предела, но я хочу продолжить все NaN в этом случае.

One Solution collect form web for “Интерполировать (или экстраполировать) только небольшие пробелы в кадре данных панд”

Итак, вот маска, которая должна решить проблему. Просто interpolate а затем примените маску для сброса соответствующих значений в NaN. Честно говоря, это было немного больше работы, чем я понял, это было бы потому, что мне пришлось перебирать каждый столбец, но затем группа не работала без меня, предоставляя некоторые фиктивные столбцы, такие как «те».

Во всяком случае, я могу объяснить, если что-то неясно, но на самом деле только несколько строк трудно понять. См. Здесь немного больше объяснений трюка на линии df['new'] или просто распечатывайте отдельные строки, чтобы лучше видеть, что происходит.

 mask = data.copy() for i in list('abcdefgh'): df = pd.DataFrame( data[i] ) df['new'] = ((df.notnull() != df.shift().notnull()).cumsum()) df['ones'] = 1 mask[i] = (df.groupby('new')['ones'].transform('count') < 5) | data[i].notnull() In [7]: data Out[7]: abcdefgh 2014-02-21 14:50:00 123.5 433.5 123.5 NaN NaN NaN 2330.3 2330.3 2014-02-21 14:51:00 NaN 523.2 132.3 NaN NaN NaN NaN NaN 2014-02-21 14:52:00 136.3 536.3 136.3 NaN NaN NaN NaN NaN 2014-02-21 14:53:00 164.3 464.3 164.3 NaN NaN NaN NaN NaN 2014-02-21 14:54:00 213.0 413.0 NaN NaN NaN 2763.0 NaN NaN 2014-02-21 14:55:00 164.3 164.3 NaN NaN NaN 2142.3 NaN NaN 2014-02-21 14:56:00 213.0 213.0 NaN NaN NaN 2127.3 NaN NaN 2014-02-21 14:57:00 221.1 221.1 NaN NaN 2330.3 2330.3 NaN 2777.7 In [8]: mask Out[8]: abcdefgh 2014-02-21 14:50:00 True True True False False True True True 2014-02-21 14:51:00 True True True False False True False False 2014-02-21 14:52:00 True True True False False True False False 2014-02-21 14:53:00 True True True False False True False False 2014-02-21 14:54:00 True True True False False True False False 2014-02-21 14:55:00 True True True False False True False False 2014-02-21 14:56:00 True True True False False True False False 2014-02-21 14:57:00 True True True False True True False True 

Это легко оттуда, если вы не сделаете ничего интересного в отношении экстраполяции:

 In [9]: data.interpolate().bfill()[mask] Out[9]: abcdefgh 2014-02-21 14:50:00 123.5 433.5 123.5 NaN NaN 2763.0 2330.3 2330.3 2014-02-21 14:51:00 129.9 523.2 132.3 NaN NaN 2763.0 NaN NaN 2014-02-21 14:52:00 136.3 536.3 136.3 NaN NaN 2763.0 NaN NaN 2014-02-21 14:53:00 164.3 464.3 164.3 NaN NaN 2763.0 NaN NaN 2014-02-21 14:54:00 213.0 413.0 164.3 NaN NaN 2763.0 NaN NaN 2014-02-21 14:55:00 164.3 164.3 164.3 NaN NaN 2142.3 NaN NaN 2014-02-21 14:56:00 213.0 213.0 164.3 NaN NaN 2127.3 NaN NaN 2014-02-21 14:57:00 221.1 221.1 164.3 NaN 2330.3 2330.3 NaN 2777.7 

Редактировать, чтобы добавить: Вот более быстрая (около 2x по этим образцам данных) и немного более простой способ, перемещая некоторые вещи за пределы цикла:

 mask = data.copy() grp = ((mask.notnull() != mask.shift().notnull()).cumsum()) grp['ones'] = 1 for i in list('abcdefgh'): mask[i] = (grp.groupby(i)['ones'].transform('count') < 5) | data[i].notnull() 
  • Самый быстрый способ сравнить строку и предыдущую строку в кадре данных pandas с миллионами строк
  • Изменение значений столбца в заголовках столбцов в pandas
  • Как выполнить функцию в группе строк в pandas dataframe?
  • Pandas Get_dummies для вложенных таблиц
  • Может ли pandas SparseSeries хранить значения в формате float16?
  • Панды: заполните NaNs следующими не NaN / # последовательными NaN
  • Запись фрейма данных pandas в таблицу документов Word через pywin32
  • Преобразование столбцов времени в минутах в формате времени в формате HH: MM: SS в пандах
  • подзаголовки pandas в цикле
  • Подсвечник Matplotlib (внутридневной) - один большой блок
  • Pandas: SettingWithCopyWarning
  •  
    Interesting Posts for Van-Lav

    Использование super с методом класса

    Захват сообщения «Ошибка сегментации» для разбитого подпроцесса: нет выхода и ошибки после вызова для связи ()

    почему моя математическая викторина всегда печатает неправильно, когда ответ правильный

    генератор против понимания списка

    NZEC – Ошибка выполнения в python

    Python 2.7: заменить метод строкового объекта устаревшим

    Каков самый простой и сжатый способ сделать выбранные атрибуты в экземпляре только для чтения?

    Почему PyCharm использует 120 символов, хотя PEP8 указывает 79?

    Почему ранний возврат медленнее, чем другой?

    Как получить объект tz_info, соответствующий текущему часовому поясу?

    Перемешать и повторно перетасовать список в python?

    Попытка получить приложение django для работы с mod_wsgi на CentOS 5

    Как проверить, установлено ли соединение SSH с экземпляром AWS

    IOError: Нет такого файла или каталога, записывающего в файл в домашнем каталоге

    Найти значение min в массиве> 0

    Python - лучший язык программирования в мире.