Rust: polars行遍历,从dataframe到struct及Bar设计比较

pandas提供了iterrows()、itertuples()、apply等行遍历的方式,还是比较方便的。
polars的列操作功能非常强大,这个在其官网上有详细的介绍。由于polars底层的arrow是列存储模式,行操作效率低下,官方也不推荐以行方式进行数据操作。但是还是有部分场景可能会用到行遍历的情况。

polars如何进行行遍历,今天尝试一下非apply的方式。

场景:polars读取相应的关于历史股价的csv文件,其中有基本的行情信息,那么,如何对读取到的文件进行快速的行遍历?这种场景在行情驱动的策略回测中比较常见。

在这里插入图片描述一、初步方案:

1、总体方案

1、csv => dataframe 
2、dataframe =>into_struct ,得到structchunked
3、struchchunked =>在bars进行行遍历。

2、Bar类型
至于Bar类型的设计,存在两种方案:

(1)值类型的Bar

#[warn(dead_code)]
struct Bar{
    code:String,
    date:String,
    open:f32,
    high:f32,
    close:f32,
    low:f32,
    volume:f32,
    amount:f32,
    is_fq:bool,
}

(2)有引用类型的Bar

#[warn(dead_code)]
struct Bar2<'a>{
    code:&'a str,
    date:&'a str,
    open:f32,
    high:f32,
    close:f32,
    low:f32,
    volume:f32,
    amount:f32,
    is_fq:bool,
}

二、toml

注意,polars对features的设置要求高,有些用到的特性需要准确打开,否则代码编译会通不过。这一点在polars文档中经常没有写清楚,也算是一个坑。

[package]
name = "my_duckdb"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
polars = { version = "*", features = ["lazy","dtype-struct"] }

注意,features中,一定要加上"dtype-struct"。

三、main.rs

根据上面的设计,全部代码如下:

use polars::prelude::*;
use std::time::Instant;

#[warn(dead_code)]
struct Bar{
    code:String,
    date:String,
    open:f32,
    high:f32,
    close:f32,
    low:f32,
    volume:f32,
    amount:f32,
    is_fq:bool,
}
#[warn(dead_code)]
struct Bar2<'a>{
    code:&'a str,
    date:&'a str,
    open:f32,
    high:f32,
    close:f32,
    low:f32,
    volume:f32,
    amount:f32,
    is_fq:bool,
}
fn main() {
    let time0 = Instant::now();
    // test2.csv:64w行
    let csv = "test2.csv"; 
    let df = polars_lazy_read_csv(csv);
    println!("read raw csv cost time : {:?} seconds",time0.elapsed().as_secs_f32());
    let time1 = Instant::now();
    let rows = df.into_struct("bars");
    println!("dataframe => structs cost time : {:?} seconds",time1.elapsed().as_secs_f32());
    let time2 = Instant::now();
    let bars = get_vec_bars(&rows);
    println!("dataframe => bars cost time : {:?} seconds",time2.elapsed().as_secs_f32());
    let time3 = Instant::now();
    let bar2s = get_vec_bar2s(&rows);
    println!("dataframe => bar2s cost time : {:?} seconds",time3.elapsed().as_secs_f32());
    println!("bars length :{:?}",bars.len());
    println!("bar2s length:{:?}",bar2s.len());
}

fn get_bar(row:&[AnyValue])->Bar{
    let code = row.get(0).unwrap();
    let mut new_code = "";
    if let &AnyValue::Utf8(value) = code{
        new_code = value;
    }
    let mut new_date = ""; 
    let date = row.get(1).unwrap();
    if let &AnyValue::Utf8(v) = date {
       new_date = v;
    }
    let open =row[2].extract::<f32>().unwrap();
    let high:f32 = row[3].extract::<f32>().unwrap();
    let close =row[4].extract::<f32>().unwrap();
    let low:f32 = row[5].extract::<f32>().unwrap();
    let volume =row[6].extract::<f32>().unwrap();
    let amount:f32 = row[7].extract::<f32>().unwrap();
    let mut is_fq = false;
    if let &AnyValue::Boolean(b) = row.get(8).unwrap(){
        is_fq = b;
    }
    let bar = Bar{
        code: String::from(new_code),
        date: String::from(new_date),
        open:open,
        high:high,
        close:close,
        low:low,
        volume:volume,
        amount,
        is_fq:is_fq,
    };
    bar
}

fn get_bar2<'a>(row:&'a [AnyValue])->Bar2<'a>{
    let code = row.get(0).unwrap();
    let mut new_code = "";
    if let &AnyValue::Utf8(value) = code{
        new_code = value;
    }
    let mut new_date = ""; 
    let date = row.get(1).unwrap();
    if let &AnyValue::Utf8(v) = date {
       new_date = v;
    }
    let open =row[2].extract::<f32>().unwrap();
    let high:f32 = row[3].extract::<f32>().unwrap();
    let close =row[4].extract::<f32>().unwrap();
    let low:f32 = row[5].extract::<f32>().unwrap();
    let volume =row[6].extract::<f32>().unwrap();
    let amount:f32 = row[7].extract::<f32>().unwrap();
    let mut is_fq = false;
    if let &AnyValue::Boolean(b) = row.get(8).unwrap(){
        is_fq = b;
    }
    let bar = Bar2{
        code: new_code,
        date: new_date,
        open:open,
        high:high,
        close:close,
        low:low,
        volume:volume,
        amount,
        is_fq:is_fq,
    };
    bar
}
fn get_vec_bars(data: &StructChunked)-> Vec<Bar>{
    let mut bars = Vec::new();
    for row in data{
        let bar = get_bar(row);
        bars.push(bar);
    }
    bars
}

fn get_vec_bar2s(data: &StructChunked)-> Vec<Bar2>{
    let mut bars = Vec::new();
    for row in data{
        let bar = get_bar2(row);
        bars.push(bar);
    }
    bars
}
fn polars_lazy_read_csv(filepath:&str) ->DataFrame{
    let polars_lazy_csv_time  = Instant::now();
    let p = LazyCsvReader::new(filepath)
    .has_header(true)
    .finish().unwrap();
    let mut df = p.collect().expect("error to dataframe!");
    println!("polars lazy 读出csv的行和列数:{:?}",df.shape());
    println!("polars lazy 读csv 花时: {:?} 秒!", polars_lazy_csv_time.elapsed().as_secs_f32());
    df
}

四、输出与比较
对于一个64万行,9列的csv文件,需要遍历转换Vec< Bar >类型,
1、输出如下:

polars lazy 读出csv的行和列数:(640710, 9)
polars lazy 读csv 花时: 0.058484446 秒!
read raw csv cost time : 0.058487203 seconds
dataframe => structs cost time : 2.8842e-5 seconds
dataframe => bars cost time : 0.131985 seconds
dataframe => bar2s cost time : 0.10357016 seconds
bars length :640710
bar2s length:640710

总体上看,从dataframe到struct这层,效率比较高,主要的时间花在了structchunked至bars这部分上面。

2、值类型Bar和引用类型Bar

从输出结果,可以看出,引用类型的Bar的效率要高一些,提效了20%。因为减少了堆分配所需要的时间。

五、其它:硬遍历探索

找了3种关于硬遍历的方案,分别如下:

fn iter_dataframe_as_row1(df:&DataFrame) {
    let starttime = Instant::now();
    let (_row,_col) = df.shape();
    for i in 0.._row{
        let _df    = df.slice(i as i64,1);
        let mut row_value = Vec::new();
        for j in 0.._col{
            let value = _df[j].get(0).unwrap();
            row_value.push(value);
        }
        //println!("row_value :{:?} ",row_value);
    }
    println!("method1 => dataframe按行遍历cost time :{:?} seconds!",starttime.elapsed().as_secs_f32());
}

fn iter_dataframe_as_row2(df:&DataFrame) {
    let starttime = Instant::now();
    let (_row,_col) = df.shape();
    for i in 0.._row{
        let mut rows = Vec::new();
        for j in 0.._col{
            let value = df[j].get(i).unwrap();
            rows.push(value);
        }
    }
    println!("method2 => dataframe按行遍历cost time :{:?} seconds!",starttime.elapsed().as_secs_f32());
}
fn iter_dataframe_as_row3(df:&DataFrame) {
    let starttime = Instant::now();
    let (_row,_col) = df.shape();
    let mut rows= Vec::new();
    for i in 0.._row{
        let rows_value = df.get_row(i).unwrap();
        rows = rows_value.0;
    }
    println!("method3 => dataframe按行遍历cost time :{:?} seconds!",starttime.elapsed().as_secs_f32());
}

输出:

method1 => dataframe按行遍历cost time :0.55091226 seconds!
method2 => dataframe按行遍历cost time :0.111569375 seconds!
method3 => dataframe按行遍历cost time :0.17757274 seconds!

尽管第2种方法好很多,但是仍不太理想。但是方法1和方法3更差,特别是方法1。可见,对于同样的对象,简单的行遍历的方法选择的重要性。

polars目前还没有发现有类似pandas的相对高效的行遍历的方式,后面将持续跟踪。
此外,dataframe转bars的效率并不高,期待找到更高效的方式替代。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/777371.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

谷粒商城 - 树形菜单递归流查询、三级分类数据查询性能优化、Jmter 性能压测

目录 树形分类菜单&#xff08;递归查询&#xff0c;强扩展&#xff09; 1&#xff09;需求 2&#xff09;数据库表设计 3&#xff09;实现 4&#xff09;关于 asSequence 优化 性能压测 1&#xff09;Jmeter 安装使用说明 2&#xff09;中间件对性能的影响 三级分类数…

昇思25天学习打卡营第5天|GAN图像生成

文章目录 昇思MindSpore应用实践基于MindSpore的生成对抗网络图像生成1、生成对抗网络简介零和博弈 vs 极大极小博弈GAN的生成对抗损失 2、基于MindSpore的 Vanilla GAN3、基于MindSpore的手写数字图像生成导入数据数据可视化模型训练 Reference 昇思MindSpore应用实践 本系列…

01 企业网站架构部署于优化之Web基础与HTTP协议

目录 1.1 Web基础 1.1.1 域名和DNS 1. 域名的概念 2. Hosts文件 3. DNS 4. 域名注册 1.1.2 网页与HTML 1. 网页概述 2. HTML概述 3. HTML基本标签 4. 网站和主页 5. Web1.0与Web2.0 1.1.3 静态网页与动态网页 1. 静态网页 2. 动态网页 3. 动态网页语言 1.2 HTTP协议 1…

如何快速开展每日待办工作 待办任务高效管理

每天&#xff0c;我们都需要处理大量的待办工作&#xff0c;如何高效有序地开展这些工作成为了我们必须要面对的问题。仅仅依靠个人的记忆和脑力去管理这些繁杂的事务&#xff0c;显然是一项艰巨的挑战。在这个时候&#xff0c;如果能有一款实用的待办工具来辅助我们&#xff0…

7年跨境业务资深从业者的代理IP使用经验分享

作为一个拥有7年跨境业务经验的资深从业者&#xff0c;今天大家分享一下在使用各种代理IP服务中的宝贵经验。无论你是新手还是老手&#xff0c;这篇文章都能为你带来一些新的启发和实用技巧。 在我刚开始跨境业务的那几年&#xff0c;最大的挑战之一就是如何跨境访问&#xff0…

ORB 特征点提取

FAST关键点 选取像素p&#xff0c;假设它的亮度为Ip&#xff1b; . 设置一个阈值T&#xff08;比如Ip的20%&#xff09;&#xff1b; 以像素p为中心&#xff0c;选取半径为3的圆上的16个像素点&#xff1b; 假如选取的圆上&#xff0c;有连续的N个点的亮度大于IpT或小于…

CSS实现图片裁剪居中(只截取剪裁图片中间部分,图片不变形)

1.第一种方式&#xff1a;&#xff08;直接给图片设置&#xff1a;object-fit:cover;&#xff09; .imgbox{width: 100%;height:200px;overflow: hidden;position: relative;img{width: 100%;height: 100%; //图片要设置高度display: block;position: absolute;left: 0;right…

【Python基础篇】你了解python中运算符吗

文章目录 1. 算数运算符1.1 //整除1.2 %取模1.3 **幂 2. 赋值运算符3. 位运算符3.1 &&#xff08;按位与&#xff09;3.2 |&#xff08;按位或&#xff09;3.3 ^&#xff08;按位异或&#xff09;3.4 ~&#xff08;按位取反&#xff09;3.5 <<&#xff08;左移&#…

【JavaWeb程序设计】JSP编程II

目录 一、输入并运行下面的import_test.jsp页面 1.1 代码运行结果 1.2 修改编码之后的运行结果 二、errorPage属性和isErrorPage属性的使用 2.1 下面的hello.jsp页面执行时将抛出一个异常&#xff0c;它指定了错误处理页面为errorHandler.jsp。 2.1.2 运行截图 2.2 下面…

压测工具---Ultron

压测工具&#xff1a;Ultron 类型&#xff1a;接口级和全链路 接口级 对于接口级别的压测我们可以进行 http接口压测、thrift压测、redis压测、kafka压测、DDMQ压测、MySQL压测等&#xff0c;选对对应的业务线、选择好压测执行的时间和轮数就可以执行压测操作了 全链路 对…

Java新特性梳理——Java15

highlight: xcode theme: vuepress 概述 2020 年 9 月 15 日&#xff0c;Java 15 正式发布&#xff0c;(风平浪静的一个版本)共有 14 个 JEP&#xff0c;是时间驱动形式发布的第六个版本。相关文档&#xff1a;https://openjdk.java.net/projects/jdk/15/ 语法层面变化 密封类 …

【机器学习】基于密度的聚类算法:DBSCAN详解

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 基于密度的聚类算法&#xff1a;DBSCAN详解引言DBSCAN的基本概念点的分类聚类过…

JVM原理(十七):JVM虚拟机即时编译器详解

编译器无论在何时、在何种状态下把Class文件转换成与本地基础设施相关的二进制机器码&#xff0c;他都可以视为整个编译过程的后端。 后端编译器编译性能的好坏、代码优化质量的高低却是衡量一款商用虛拟机优秀与否的关键指标之一。 1. 即时编译器 即时编译器是一个把Java的…

19.【C语言】初识指针(重难点)

内存&#xff1a;所有程序的运行在内存中 用Cheat Engine查看任意程序的内存(16进制&#xff09;&#xff1a; 显示大量的数据 想要定位某个数字 &#xff0c;需要知道地址(类比二维坐标) 如F8的地址为00BCB90008,所以是00BCB908(偏移) ctrlG 则有 内存单元的说明&#xff1…

动态颤抖的眼睛效果404页面源码

动态颤抖的眼睛效果404页面源码&#xff0c; 源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c;重定向这个界面 动态颤抖的眼睛效果404页面源码

Portainer 是一个开源的容器管理平台-非常直观好用的Docker图形化项目

在这个容器化技术大行其道的时代&#xff0c;Docker和Kubernetes几乎成了技术圈的新宠。可是管理起容器来&#xff0c;有时候还是有点头大。命令行操作对于某些小伙伴来说&#xff0c;可能还是有点不太友好。 今天开源君分享一个叫 Portainer 的开源项目&#xff0c;一个用来简…

AI大模型时代的存储发展趋势

从2022年下半年&#xff0c;大模型和AIGC这两个词变得极其火热&#xff0c;而GPU的市场也是一卡难求。对于这种迷乱和火热&#xff0c;让我想起了当年的比特币挖矿和IPFS。似乎世界一年一个新风口&#xff0c;比特币、元宇宙、NFT、AIGC&#xff0c;金钱永不眠&#xff0c;IT炒…

【React】React18 Hooks 之 useReducer

目录 useReducer案例1&#xff1a;useReducer不带初始化函数案例2&#xff1a;useReducer带初始化函数注意事项1&#xff1a;dispatch函数不会改变正在运行的代码的状态注意事项2&#xff1a;获取dispatch函数触发后 JavaScript 变量的值注意事项3&#xff1a;触发了reducer&am…

【MotionCap】pycharm 远程在wsl2 ubuntu20.04中root的miniconda3环境

pycharm wsl2 链接到pycharmsbin 都能看到内容,/root 下内容赋予了zhangbin 所有,pycharm还是看不到/root 下内容。sudo 安装了miniconda3 引发了这些问题 由于是在 root 用户安装的miniconda3 所以安装路径在/root/miniconda3 里 这导致了环境也是root用户的,会触发告警 WA…

Xilinx原语

1. 原语介绍 原语是 Xilinx 器件底层硬件中的功能模块&#xff0c;它使用专用的资源来实现一系列的功能。相比于 IP 核&#xff0c;原语的调用方法更简单&#xff0c;但是一般只用于实现一些简单的功能。本章主要用到了 BUFG、 BUFIO、 IDDR、 ODDR、IDELAYE2 和 IDELAYCTRL。…