rust - 使用 Rust 中的 Polars 重新采样时间序列

标签 rust time-series resampling rust-polars

我试图通过一些数据解析和重新设计我的一些交易工具来学习 Rust,但很快就陷入困境。

我想将我的数据从 5 分钟重新采样到 15 分钟,Polars 似乎能够以优化的方式做到这一点。

这是我迄今为止的尝试。我设法将时间从 5 分钟分组为 15 分钟,但我无法思考如何将此分组应用于其他列。

use polars::prelude::*;
use std::error::Error;

fn type_of<T>(_: T) {
    println!("--- DATA TYPE: {}", std::any::type_name::<T>());
}

fn main() -> Result<(), Box<dyn Error>> {
    let path = "path/to/.csv";
    let df = LazyCsvReader::new(path)
        .has_header(true)
        .with_parse_dates(true)
        .finish()?
        .fetch(20)?;
   
let tt = df.groupby_dynamic(
        vec![df.column("close")?.clone()],
        &DynamicGroupOptions {
            index_column: "time".into(),
            every: Duration::parse("15m"),
            period: Duration::parse("5m"),
            offset: Duration::parse("0s"),
            truncate: true,
            include_boundaries: false,
            closed_window: ClosedWindow::Left,
        },
    )?;
 
    //type_of(&tt);
    println!("{:?}", tt);

}

输出

Series: 'time' [datetime[μs]]
[
        2019-09-03 09:00:00
        2019-09-03 09:15:00
        2019-09-03 09:30:00
        2019-09-03 09:45:00
        2019-09-03 10:00:00
        2019-09-03 10:15:00
        2019-09-03 10:30:00
        2019-09-03 10:45:00
        2019-09-03 11:00:00
], [], Slice { groups: [[0, 1], [1, 1], [1, 4], [4, 4], [7, 4], [10, 4], [13, 4], [16, 4], [19, 1]], rolling: false })

一旦我尝试添加一个要在“by”字段中分组的系列(groupby_dynamic 中的第一个参数),就不会进行重新采样,我只会得到与放置的系列相同的系列。

该函数输出一个 Slice { groups: ..." ,其类型为 polars_core::frame::groupby::proxy::GroupsProxy 但我不知道该怎么处理。

我的cargo.toml:

[dependencies]
polars = { version = "0.25.1", features = ["lazy"] }

我的 .csv 文件:

time,open,high,low,close,volume
2019-09-03 09:00:00,1183.9999,1183.9999,1183.9999,1183.9999,150
2019-09-03 09:30:00,1178.69,1180.69,1178.47,1178.47,5180
2019-09-03 09:35:00,1177.03,1180.6146,1176.0,1179.47,70575
2019-09-03 09:40:00,1180.6345,1186.89,1180.6345,1185.5141,37267
2019-09-03 09:45:00,1185.9,1186.43,1182.43,1182.47,20569
2019-09-03 09:50:00,1183.54,1184.0,1180.0,1181.96,20754
2019-09-03 09:55:00,1182.5,1186.0,1182.49,1184.83,20848
2019-09-03 10:00:00,1185.5,1185.59,1184.03,1185.145,18581
2019-09-03 10:05:00,1184.65,1184.65,1175.5,1175.86,27714
2019-09-03 10:10:00,1175.49,1176.5,1173.65,1175.47,21779
2019-09-03 10:15:00,1175.295,1177.42,1173.5,1173.68,13588
2019-09-03 10:20:00,1173.01,1176.3717,1173.01,1175.44,9853
2019-09-03 10:25:00,1175.7896,1178.985,1175.7896,1177.468,7866
2019-09-03 10:30:00,1178.05,1179.0,1176.0038,1178.72,11576
2019-09-03 10:35:00,1179.005,1179.005,1176.53,1177.0077,9275
2019-09-03 10:40:00,1177.18,1178.02,1176.0201,1178.02,8852
2019-09-03 10:45:00,1178.3,1182.5,1178.3,1181.7113,14703
2019-09-03 10:50:00,1181.74,1181.9952,1180.01,1181.738,10225
2019-09-03 10:55:00,1182.11,1183.428,1181.33,1183.428,7835
2019-09-03 11:00:00,1183.41,1184.665,1183.41,1184.24,9078

接下来的事情是从“闭合”列中获取第一个、最后一个、最大、最小(是的,我正在尝试获取 OHLC 蜡烛)。

很高兴获得任何帮助!

最佳答案

编辑:Polars 0.29

终于解决了!

我没有正确使用 Lazy-API。我已经并且以某种方式使用了 group_dynamic 的其他实现,我猜它用于 Polars 的内部运作或其他东西。要点是我忘记了 .lazy()

但是,这就是我解决它的方法:

use polars::prelude::*;
use std::error::Error;

fn type_of<T>(_: T) {
    println!("--- DATA TYPE: {}", std::any::type_name::<T>());
}

fn main() -> Result<(), Box<dyn Error>> {
    let path = "/home/niklas/projects/ML-trader/Datasets/Raw/GOOG.csv";
    let df = LazyCsvReader::new(path)
        .has_header(true)
        .with_try_parse_dates(true) // Polars > 0.29
        .finish()?
        .collect()?;

    type_of(&df);
    // println!("{}", &df["close"]);

    let tt = df
        .lazy()
        .groupby_dynamic(
            col("time"), // Polars > 0.29
            vec![],
            DynamicGroupOptions {
                index_column: "time".into(),
                every: Duration::parse("15m"),
                period: Duration::parse("15m"),
                offset: Duration::parse("0s"),
                truncate: false,
                include_boundaries: false,
                closed_window: ClosedWindow::Left,
                start_by: Default::default(), // Polars > 0.29

            },
        )
        .agg([
            col("close").first().alias("firstClose"),
            col("close").last().alias("lastClose"),
            col("close"),
        ])
        .fetch(20);

    println!("{:?}", tt);

    Ok(())
}

输出

--- DATA TYPE: &polars_core::frame::DataFrame
--- DATA TYPE: &core::result::Result<polars_core::frame::DataFrame, polars_core::error::PolarsError>
Ok(shape: (8, 4)
┌─────────────────────┬────────────┬───────────┬─────────────────────────────────┐
│ time                ┆ firstClose ┆ lastClose ┆ close                           │
│ ---                 ┆ ---        ┆ ---       ┆ ---                             │
│ datetime[μs]        ┆ f64        ┆ f64       ┆ list[f64]                       │
╞═════════════════════╪════════════╪═══════════╪═════════════════════════════════╡
│ 2019-09-03 09:00:00 ┆ 1183.9999  ┆ 1183.9999 ┆ [1183.9999]                     │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2019-09-03 09:30:00 ┆ 1178.47    ┆ 1185.5141 ┆ [1178.47, 1179.47, 1185.5141]   │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2019-09-03 09:45:00 ┆ 1182.47    ┆ 1184.83   ┆ [1182.47, 1181.96, 1184.83]     │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2019-09-03 10:00:00 ┆ 1185.145   ┆ 1175.47   ┆ [1185.145, 1175.86, 1175.47]    │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2019-09-03 10:15:00 ┆ 1173.68    ┆ 1177.468  ┆ [1173.68, 1175.44, 1177.468]    │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2019-09-03 10:30:00 ┆ 1178.72    ┆ 1178.02   ┆ [1178.72, 1177.0077, 1178.02]   │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2019-09-03 10:45:00 ┆ 1181.7113  ┆ 1183.428  ┆ [1181.7113, 1181.738, 1183.428] │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2019-09-03 11:00:00 ┆ 1184.24    ┆ 1184.24   ┆ [1184.24]                       │
└─────────────────────┴────────────┴───────────┴─────────────────────────────────┘)

我的.toml

[dependencies]
polars = { version = "0.29", features = ["lazy", "dynamic_groupby"] }

感谢大家参加我的 ted 演讲!

关于rust - 使用 Rust 中的 Polars 重新采样时间序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74668242/

相关文章:

recursion - 在Rust中将递归函数转换为迭代器的技术?

rust - 什么是处理实际数据而不关心数据如何被保护/包装的惯用方式?

r - ggplot2:用 POSIXct 时间戳数据遮蔽隔天

python - Pandas DataFrame 重新采样中出现意外数量的 bin

python - Pandas:重新采样数据框列,获取对应于最大值的离散特征

rust - Rust 中的生命周期如何为函数工作?

rust - 是否可以仅在运行测试时为结构实现特征?

python - 高效加入 Python dataframe 时间序列

python - 带有列表列的 pandas 时间序列数据框

python - Pandas 时间序列重新采样,分箱似乎关闭