Интерполяция пропущенных значений в Python

Все - я надеюсь, что вы сможете помочь, так как это одна из тех задач, где я знаю, что почти сломалась из-за различных сообщений здесь и в Интернете, но не совсем заставила ее работать.

По сути, у меня есть следующие данные в базе данных, которые возвращаются объекту Pandas через psql.read_sql(sql, cnxn)

+------------------------------------+
|              StartTime  StartLevel |
+------------------------------------+
| 0  2015-02-16 00:00:00     480.000 |
| 1  2015-02-16 00:30:00     480.000 |
| 2  2015-02-16 00:34:00     390.000 |
| 3  2015-02-16 01:00:00     390.000 |
| 4  2015-02-16 01:30:00     390.000 |
| 5  2015-02-16 02:00:00     480.000 |
| 6  2015-02-16 02:17:00     420.000 |
+------------------------------------+

StartTime     datetime64[ns]
StartLevel           float64
dtype: object

Я просто хочу получить поминутную интерполяцию приведенных выше данных.

Я также создал серию дат и времени с минутной частотой, но на всю жизнь я не могу решить, как «сопоставить» мою таблицу с этим, а затем интерполировать или как я могу передискретизировать StartTime до минутной детализации, а затем интерполировать недостающие данные .

Любая помощь будет принята с благодарностью (и я уверен, что буду пинать себя, когда узнаю решение!) - Большое спасибо

ОБНОВИТЬ

Следуя приведенным ниже предложениям, код выглядит следующим образом:

import datetime
import numpy as np
import pandas as pd
import pyodbc
import pandas.io.sql as psql


cnxn = pyodbc.connect('DSN=MySQL;DATABASE=db;UID=uid;PWD=pwd')
cursor = cnxn.cursor()
sql = """
    SELECT
    StartTime,StartLevel
FROM
    aa.bb
    where cc = 'dd'
    and StartTime < '2015-02-16 02:30:00'
    order by StartTime asc"""

old_df = psql.read_sql(sql, cnxn)


num_minutes = 120
base = datetime.datetime(2015, 02, 16, 00, 00, 00)
date_list = [base + datetime.timedelta(minutes=x) for x in range(0, num_minutes)]
# set num_minutes for whatever is the correct number of minutes you require
new_data = [dict(StartTime=d, fake_val=np.NaN) for d in date_list]
new_df = pd.DataFrame(new_data)
new_df['StartLevel'] = old_df['StartLevel']
new_df.interpolate(inplace=True)

вывод из new_df в приглашении:

+-----------------------------------------------+
|              StartTime  fake_val  StartLevel  |
+-----------------------------------------------+
| 0   2015-02-16 00:00:00       NaN         480 |
| 1   2015-02-16 00:01:00       NaN         480 |
| 2   2015-02-16 00:02:00       NaN         390 |
| 3   2015-02-16 00:03:00       NaN         390 |
| 4   2015-02-16 00:04:00       NaN         390 |
| 5   2015-02-16 00:05:00       NaN         480 |
| 6   2015-02-16 00:06:00       NaN         480 |
+-----------------------------------------------+

person Patrick A    schedule 17.02.2015    source источник


Ответы (1)


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

Сначала создайте все объекты даты и времени, для которых вы хотите получить значения.

num_minutes = 120
base = datetime.datetime(2015, 02, 16, 00, 00, 00)
date_list = [base + datetime.timedelta(minutes=x) for x in range(0, num_minutes)]
# set num_minutes for whatever is the correct number of minutes you require

Затем создайте «поддельный» фрейм данных с этими значениями индекса.

new_data = [dict(StartTime=d, fake_val=np.NaN) for d in date_list]
new_df = pd.DataFrame(new_data)

EDIT: исправлен ответ

Теперь мы хотим объединить два фрейма данных в один (и отсортировать по дате):

final_df = new_df.merge(df, how='outer', on='date').sort(columns='date')

final_df теперь будет сортироваться по дате и содержать правильные значения для StartLevel, когда у вас были данные, и NaN, когда у вас не было данных для него. Тогда вы можете позвонить interpolate

EDIT: Interpolate не вызывается inplace по умолчанию, поэтому вам нужно либо установить этот флаг, либо сохранить результат.

final_df = final_df.interpolate()

or

final_df.interpolate(inplace=True)

Очевидно, что столбец fake_val можно выбросить, как только вы объедините хорошие данные. Цель создания этого фрейма данных состоит в том, чтобы проиндексировать его со всеми нужными вам значениями (именно здесь я уверен, что есть более питонический ответ)

Полную документацию по interpolate можно найти здесь

person sedavidw    schedule 17.02.2015
comment
Спасибо за предложение, но оно не совсем работает, поскольку генерирует список времени по минутам, столбец с NaN, а затем просто сопоставляет исходное время начала с этим - person Patrick A; 17.02.2015
comment
@PatrickA Ты звонил interpolate()? Возможно, вы не сохраняете результат. Глядя на документацию, она не делает этого автоматически на месте, поэтому вы можете сделать что-то вроде new_df = new_df.interpolate() или new_df.interpolate(inplace=True). Я отредактировал ответ, чтобы отразить это - person sedavidw; 17.02.2015
comment
Я так считаю. Он генерирует правильные поминутные временные ряды и NaN в столбцах fake_val. Также кажется, что последнее значение интерполируется до конца минуты за минутой, но не интерполируется StartLevel - я хотел бы опубликовать вывод для вас здесь, но я не уверен, как - person Patrick A; 17.02.2015
comment
@PatrickA Можете ли вы отредактировать свой вопрос и поместить его туда? Если бы вы могли включить код, который вы использовали, это тоже было бы полезно - person sedavidw; 17.02.2015
comment
Готово - опубликовано в исходном вопросе - person Patrick A; 17.02.2015
comment
@PatrickA А, я вижу проблему. Мне было лень читать мой вывод, и я извиняюсь, только что обновил свой ответ, попробуйте это - person sedavidw; 18.02.2015