我在不同数据帧的不同时间轴上有时间序列数据。我需要将一个 df 中的数据插值到另一个 df df_ref 的时间轴上。例如:
import polars as pl
# DataFrame with the reference time axis:
df_ref = pl.DataFrame({"dt": ["2022-12-14T14:00:01.000", "2022-12-14T14:00:02.000",
"2022-12-14T14:00:03.000", "2022-12-14T14:00:04.000",
"2022-12-14T14:00:05.000", "2022-12-14T14:00:06.000"]})
df_ref = df_ref.with_column(pl.col("dt").str.strptime(pl.Datetime).cast(pl.Datetime))
# DataFrame with a different frequency time axis, to be interpolated onto the reference time axis:
df = pl.DataFrame({
"dt": ["2022-12-14T14:00:01.500", "2022-12-14T14:00:03.500", "2022-12-14T14:00:05.500"],
"v1": [1.5, 3.5, 5.5]})
df = df.with_column(pl.col("dt").str.strptime(pl.Datetime).cast(pl.Datetime))
由于 key 不匹配,我无法加入
dfs:
print(df_ref.join(df, on="dt", how="left").interpolate())
shape: (6, 2)
┌─────────────────────┬──────┐
│ dt ┆ v1 │
│ --- ┆ --- │
│ datetime[μs] ┆ f64 │
╞═════════════════════╪══════╡
│ 2022-12-14 14:00:01 ┆ null │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 2022-12-14 14:00:02 ┆ null │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 2022-12-14 14:00:03 ┆ null │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 2022-12-14 14:00:04 ┆ null │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 2022-12-14 14:00:05 ┆ null │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 2022-12-14 14:00:06 ┆ null │
└─────────────────────┴──────┘
所以我的“迭代”方法是单独插入每一列,例如
from scipy.interpolate import interp1d
f = interp1d(df["dt"].dt.timestamp(), df["v1"],
kind="linear", bounds_error=False, fill_value="extrapolate")
out = f(df_ref["dt"].dt.timestamp())
df_ref = df_ref.with_column(pl.Series(out).alias("v1_interp"))
print(df_ref.head(6))
shape: (6, 2)
┌─────────────────────┬───────────┐
│ dt ┆ v1_interp │
│ --- ┆ --- │
│ datetime[μs] ┆ f64 │
╞═════════════════════╪═══════════╡
│ 2022-12-14 14:00:01 ┆ 1.0 │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-12-14 14:00:02 ┆ 2.0 │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-12-14 14:00:03 ┆ 3.0 │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-12-14 14:00:04 ┆ 4.0 │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-12-14 14:00:05 ┆ 5.0 │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-12-14 14:00:06 ┆ 6.0 │
└─────────────────────┴───────────┘
虽然这给出了我需要的结果,但我想知道是否有更惯用的方法?我不愿意在这里提及效率,因为我还没有用真实数据对其进行基准测试(“测量,不要猜测!”)。不过,我认为底层 Rust 代码中的 native 实现可以增加一些性能优势。
最佳答案
scipy.interpolate.interpol1d
示例最终调用 this function.
您可以使用相同的方法并使用 .map() 处理每一列
def polars_ip(df_ref, df):
old = df["dt"].dt.timestamp().to_numpy()
new = df_ref["dt"].dt.timestamp().to_numpy()
hi = np.searchsorted(old, new).clip(1, len(old) - 1)
lo = hi - 1
def _interp(column):
column = column.to_numpy()
slope = (column[hi] - column[lo]) / (old[hi] - old[lo])
return pl.Series(slope * (new - old[lo]) + column[lo])
values = (
pl.concat([df, df_ref], how="diagonal")
.select(pl.exclude("dt").map(_interp))
)
values.columns = [f"{name}_ref_ip" for name in values.columns]
return df_ref.hstack(values)
>>> %time polars_ip(df_ref, df)
CPU times: user 48.1 ms, sys: 20.4 ms, total: 68.5 ms
Wall time: 22 ms
shape: (85536, 11)
>>> %time scipy_ip(df_ref, df)
CPU times: user 75.5 ms, sys: 5.51 ms, total: 81 ms
Wall time: 74.3 ms
shape: (85536, 11)
检查它们返回相同的值:
>>> polars_ip(df_ref, df).frame_equal(scipy_ip(df_ref, df))
True
您还可以使用以下方法生成相同的值:
N_COLS = 10
names = list(map(str, range(N_COLS)))
has_reading = pl.col(names[0]).is_not_null()
has_no_reading = has_reading.is_not()
(
pl.concat([df, df_ref], how="diagonal")
.sort("dt")
.with_columns([
pl.when(has_reading).then(pl.all())
.shift(-1).backward_fill().suffix("_hi"),
pl.when(has_reading).then(pl.all())
.shift(+1).forward_fill().suffix("_lo")
])
.with_columns([
pl.when(has_reading).then(pl.col(r"^.+_hi$"))
.forward_fill().backward_fill(),
pl.when(has_reading).then(pl.col(r"^.+_lo$"))
.backward_fill().forward_fill()
])
.filter(has_no_reading)
.with_column(
pl.col(r"^dt.*$").dt.timestamp().suffix("_ts"))
.with_columns([
(((pl.col(f"{name}_hi") - pl.col(f"{name}_lo"))
/ (pl.col("dt_hi_ts") - pl.col("dt_lo_ts")))
* (pl.col("dt_ts") - pl.col("dt_lo_ts"))
+ pl.col(f"{name}_lo"))
.alias(f"{name}_ref_ip") for name in names
])
.select([
pl.col("dt"), pl.col("^.+_ref_ip$")
])
)
关于python - 在Python极坐标中将时间序列数据从一个df插值到另一个df的时间轴,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74811931/