在pandas数据框中扩展时间序列数据

4

我正在尝试对 Pandas 数据帧中的所有数据进行时间插值。当前数据的时间增量为 0.04 秒。我想将其增量设为 0.01 秒以匹配另一个数据集。我意识到我可以使用 DataFrame.interpolate() 函数来实现这一点。然而,我卡在了如何以高效的方式在数据帧的每一行之间插入 3 行 NaN 值。

import pandas as pd
import numpy as np

df = pd.DataFrame(data={"Time": [0.0, 0.04, 0.08, 0.12], 
                        "Pulse": [76, 74, 77, 80],
                        "O2":[99, 100, 99, 98]})
df_ins = pd.DataFrame(data={"Time": [np.nan, np.nan, np.nan], 
                            "Pulse": [np.nan, np.nan, np.nan],
                            "O2":[np.nan, np.nan, np.nan]})

我希望将df从这个样子转换为:

    Time    Pulse   O2
0   0.00    76      99
1   0.04    74      100
2   0.08    77      99
3   0.12    80      98

转换成类似下面的形式:

    Time    Pulse   O2
0   0.00    76      99
1   NaN     NaN     NaN
2   NaN     NaN     NaN
3   NaN     NaN     NaN
4   0.04    74      100
5   NaN     NaN     NaN
6   NaN     NaN     NaN
7   NaN     NaN     NaN
8   0.08    77      99
9   NaN     NaN     NaN
10  NaN     NaN     NaN
11  NaN     NaN     NaN
12  0.12    80      98

我可以随后调用

df = df.interpolate()

这将产生类似于以下内容(这里我举个例子):

    Time    Pulse   O2
0   0.00    76      99
1   0.01    76      99
2   0.02    75      99
3   0.03    74      100
4   0.04    74      100
5   0.05    75      100
6   0.06    76      99
7   0.07    77      99
8   0.08    77      99
9   0.09    77      99
10  0.10    78      98
11  0.11    79      98
12  0.12    80      98

我尝试使用iterrows技术,在每一行后插入df_ins帧。但是在迭代过程中,我的索引被打乱了。我还尝试过对df进行切片并将df切片和df_ins进行连接,但是循环又一次打乱了索引。

有没有人有关于如何高效地完成这个任务的建议?

2个回答

3

在此处使用resample(用所需的行为替换ffill,或者可能对interpolate进行调整)

df["Time"] = pd.to_timedelta(df["Time"], unit="S")
df.set_index("Time").resample("0.01S").ffill()

                 Pulse   O2
Time
00:00:00            76   99
00:00:00.010000     76   99
00:00:00.020000     76   99
00:00:00.030000     76   99
00:00:00.040000     74  100
00:00:00.050000     74  100
00:00:00.060000     74  100
00:00:00.070000     74  100
00:00:00.080000     77   99
00:00:00.090000     77   99
00:00:00.100000     77   99
00:00:00.110000     77   99
00:00:00.120000     80   98

如果你确实想要插值:
df.set_index("Time").resample("0.01S").interpolate()

                 Pulse      O2
Time
00:00:00         76.00   99.00
00:00:00.010000  75.50   99.25
00:00:00.020000  75.00   99.50
00:00:00.030000  74.50   99.75
00:00:00.040000  74.00  100.00
00:00:00.050000  74.75   99.75
00:00:00.060000  75.50   99.50
00:00:00.070000  76.25   99.25
00:00:00.080000  77.00   99.00
00:00:00.090000  77.75   98.75
00:00:00.100000  78.50   98.50
00:00:00.110000  79.25   98.25
00:00:00.120000  80.00   98.00

谢谢您的回答。它非常出色且速度很快。我唯一添加的是使用 df = df.set_index(df.index.total_seconds()) 将时间索引转换回浮点数。这可能不是最合乎逻辑的,但对于我的另一半编码界面来说,它需要一个浮点数而不是日期时间。 - chris-ulmy
另外,感谢您向我展示了ffill()方法。我不知道我可以使用它,而且它在将来可能是我需要的。拥有ffill()或interpolate()选项是很好的。 - chris-ulmy

1
我认为使用 np.linspace 并逐列处理应该比插值更快(如果您的时间列不是精确的时间格式):
import numpy as np
import pandas as pd

new_dict = {}
for c in df.columns:
    arr = df[c]
    ret = []
    for i in range(1, len(arr)):
        ret.append(np.linspace(arr[i-1], arr[i], 4, endpoint=False)[1:])
    new_dict[c] = np.concatenate(ret)
pd.concat([df, pd.DataFrame(new_dict)]).sort_values('Time').reset_index(drop=True)

    Time    Pulse   O2
0   0.00    76.00   99.00
1   0.01    75.50   99.25
2   0.02    75.00   99.50
3   0.03    74.50   99.75
4   0.04    74.00   100.00
5   0.05    74.75   99.75
6   0.06    75.50   99.50
7   0.07    76.25   99.25
8   0.08    77.00   99.00
9   0.09    77.75   98.75
10  0.10    78.50   98.50
11  0.11    79.25   98.25
12  0.12    80.00   98.00

非常感谢您的回答!这正是我在寻找的解决方案。您很聪明地意识到我的时间列实际上并不是时间,而只是一个增量浮点数。然而,在测试了@user3483203的答案后,他们的确比这种方法更快。 - chris-ulmy

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