在Python中插值缺失值

3

大家好 - 希望你们能帮忙,因为这是一项任务,我知道通过这里和在线上的各种帖子,我已经几乎掌握了它,但还没有完全让它工作。

本质上,我在数据库中有以下数据,通过psql.read_sql(sql, cnxn)返回到Pandas对象中:

+------------------------------------+
|              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 |
+-----------------------------------------------+
1个回答

1

我相信这不是最符合Python语言习惯的答案,因此我欢迎评论以改进它,但我认为您可以像这样做:

首先创建所有您想要值的日期时间对象。

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)

编辑: 更正回复

现在我们想将这两个数据框合并成一个(并按日期排序):

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

final_df现在将按日期排序,并包含正确的StartLevel值,当您有数据时,它将包含数据,而当您没有数据时,它将包含NaN。然后,您可以调用interpolate

编辑:默认情况下,interpolate不会调用inplace,因此您需要设置该标志或保存结果。

final_df = final_df.interpolate()

或者

final_df.interpolate(inplace=True)

显然,一旦你合并了好的数据,fake_val列就可以被舍弃。创建该数据框的目的是为了拥有一个索引包含所有所需值的数据框(我确信这里有一个更pythonic的答案)。 interpolate的完整文档可以在这里找到。

谢谢您的建议,但它并不完全可行,因为它按分钟生成时间列表,一个带NaN的列,然后简单地将原始的StartTimes映射到此上。 - Patrick A
@PatrickA 你调用了 interpolate() 吗?可能你没有保存结果。从文档来看,它不会自动地就地进行操作,所以你可以像这样做:new_df = new_df.interpolate() 或者 new_df.interpolate(inplace=True)。我已经编辑了答案以反映这一点。 - sedavidw
我相信是的。它正在生成正确的逐分钟时间序列和fake_val列中的NaN。它似乎也将最后一个值插值到了逐分钟结束的位置,但没有对StartLevel进行插值 - 我想把输出贴在这里,但不确定该怎么做。 - Patrick A
@PatrickA 能否编辑你的问题并将其放在那里?如果您能包含您使用的代码,那会很有帮助。 - sedavidw
完成 - 已发布在原问题中 - Patrick A
@PatrickA 哦,我明白问题了。我在阅读输出时有些懒惰,对此我深表歉意。我刚刚更新了我的答案,请试一下。 - sedavidw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接