跳到内容

重采样

我们可以通过以下方式进行重采样:

  • 上采样(将数据移动到更高的频率)
  • 下采样(将数据移动到更低的频率)
  • 这些的组合,例如先上采样再下采样

下采样到较低的频率

Polars 将下采样视为 group_by 操作的一种特殊情况,您可以使用 group_by_dynamicgroup_by_rolling 来实现 - 有关示例请参阅时间分组页面

上采样到较高的频率

让我们看一个以 30 分钟间隔生成数据的例子

DataFrame · date_range

df = pl.DataFrame(
    {
        "time": pl.datetime_range(
            start=datetime(2021, 12, 16),
            end=datetime(2021, 12, 16, 3),
            interval="30m",
            eager=True,
        ),
        "groups": ["a", "a", "a", "b", "b", "a", "a"],
        "values": [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0],
    }
)
print(df)

DataFrame · date_range · 在 feature range 上可用 · 在 feature dtype-date 上可用

let time = polars::time::date_range(
    "time".into(),
    NaiveDate::from_ymd_opt(2021, 12, 16)
        .unwrap()
        .and_hms_opt(0, 0, 0)
        .unwrap(),
    NaiveDate::from_ymd_opt(2021, 12, 16)
        .unwrap()
        .and_hms_opt(3, 0, 0)
        .unwrap(),
    Duration::parse("30m"),
    ClosedWindow::Both,
    TimeUnit::Milliseconds,
    None,
)?;
let df = df!(
    "time" => time,
    "groups" => &["a", "a", "a", "b", "b", "a", "a"],
    "values" => &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0],
)?;
println!("{}", &df);

shape: (7, 3)
┌─────────────────────┬────────┬────────┐
│ time                ┆ groups ┆ values │
│ ---                 ┆ ---    ┆ ---    │
│ datetime[μs]        ┆ str    ┆ f64    │
╞═════════════════════╪════════╪════════╡
│ 2021-12-16 00:00:00 ┆ a      ┆ 1.0    │
│ 2021-12-16 00:30:00 ┆ a      ┆ 2.0    │
│ 2021-12-16 01:00:00 ┆ a      ┆ 3.0    │
│ 2021-12-16 01:30:00 ┆ b      ┆ 4.0    │
│ 2021-12-16 02:00:00 ┆ b      ┆ 5.0    │
│ 2021-12-16 02:30:00 ┆ a      ┆ 6.0    │
│ 2021-12-16 03:00:00 ┆ a      ┆ 7.0    │
└─────────────────────┴────────┴────────┘

上采样可以通过定义新的采样间隔来完成。通过上采样,我们会在没有数据的地方添加额外的行。因此,上采样本身会产生一个包含空值 (null) 的 DataFrame。这些空值可以通过填充策略或插值来填充。

上采样策略

在此示例中,我们将原始的 30 分钟数据上采样到 15 分钟,然后使用 forward 策略将空值替换为前一个非空值

upsample

out1 = df.upsample(time_column="time", every="15m").fill_null(strategy="forward")
print(out1)

upsample

let out1 = df
    .clone()
    .upsample::<[String; 0]>([], "time", Duration::parse("15m"))?
    .fill_null(FillNullStrategy::Forward(None))?;
println!("{}", &out1);

shape: (13, 3)
┌─────────────────────┬────────┬────────┐
│ time                ┆ groups ┆ values │
│ ---                 ┆ ---    ┆ ---    │
│ datetime[μs]        ┆ str    ┆ f64    │
╞═════════════════════╪════════╪════════╡
│ 2021-12-16 00:00:00 ┆ a      ┆ 1.0    │
│ 2021-12-16 00:15:00 ┆ a      ┆ 1.0    │
│ 2021-12-16 00:30:00 ┆ a      ┆ 2.0    │
│ 2021-12-16 00:45:00 ┆ a      ┆ 2.0    │
│ 2021-12-16 01:00:00 ┆ a      ┆ 3.0    │
│ …                   ┆ …      ┆ …      │
│ 2021-12-16 02:00:00 ┆ b      ┆ 5.0    │
│ 2021-12-16 02:15:00 ┆ b      ┆ 5.0    │
│ 2021-12-16 02:30:00 ┆ a      ┆ 6.0    │
│ 2021-12-16 02:45:00 ┆ a      ┆ 6.0    │
│ 2021-12-16 03:00:00 ┆ a      ┆ 7.0    │
└─────────────────────┴────────┴────────┘

在此示例中,我们转而通过线性插值填充空值

upsample · interpolate · fill_null

out2 = (
    df.upsample(time_column="time", every="15m")
    .interpolate()
    .fill_null(strategy="forward")
)
print(out2)

upsample · interpolate · fill_null

let out2 = df
    .clone()
    .upsample::<[String; 0]>([], "time", Duration::parse("15m"))?
    .lazy()
    .with_columns([col("values").interpolate(InterpolationMethod::Linear)])
    .collect()?
    .fill_null(FillNullStrategy::Forward(None))?;
println!("{}", &out2);

shape: (13, 3)
┌─────────────────────┬────────┬────────┐
│ time                ┆ groups ┆ values │
│ ---                 ┆ ---    ┆ ---    │
│ datetime[μs]        ┆ str    ┆ f64    │
╞═════════════════════╪════════╪════════╡
│ 2021-12-16 00:00:00 ┆ a      ┆ 1.0    │
│ 2021-12-16 00:15:00 ┆ a      ┆ 1.5    │
│ 2021-12-16 00:30:00 ┆ a      ┆ 2.0    │
│ 2021-12-16 00:45:00 ┆ a      ┆ 2.5    │
│ 2021-12-16 01:00:00 ┆ a      ┆ 3.0    │
│ …                   ┆ …      ┆ …      │
│ 2021-12-16 02:00:00 ┆ b      ┆ 5.0    │
│ 2021-12-16 02:15:00 ┆ b      ┆ 5.5    │
│ 2021-12-16 02:30:00 ┆ a      ┆ 6.0    │
│ 2021-12-16 02:45:00 ┆ a      ┆ 6.5    │
│ 2021-12-16 03:00:00 ┆ a      ┆ 7.0    │
└─────────────────────┴────────┴────────┘