• Rust学以致用(一)——读取k线csv文件,生成dataframe后计算MA5指标


    一、业务内容

    • 读入csv文件到dataframe里
    • 生成新的列【“MA5"】
    • 计算MA5指标
    • 把dataframe重新保存成csv文件

    二、涉及的rust知识

    • ploars包(用于dataframe的处理)的简单使用
    • dataframe增加列的操作
    • dataframe的打印
    • 自定义函数
    • 闭包的使用
    • 读取csv到df中
    • 把df保存到csv中
    • map的使用
    • series的切片
    • 条件表达式的使用

    三、具体实现

    1、待处理的csv文件——某只k线文件

    在这里插入图片描述

    2、包的引用

    主要用到的是polars,这个包等同于python中的pandas以及julia中的dataframes。
    参观和学习的地址:
    官网地址:https://docs.rs/polars/latest/polars/
    仓库地址:https://github.com/pola-rs/polars

    extern crate polars; 
    use polars::prelude::*;
    use std::fs::File;
    
    • 1
    • 2
    • 3

    3、生成一个dataframe

    DataFrame::default()

    let mut df = DataFrame::default();
    
    • 1

    4、df里面增加一列

    df.with_column()

    df.with_column(Series::new("榜号",vec![1,2,3]));
    df.with_column(Series::new("姓名",vec!["张三丰","黄老邪","老顽童"]));
    
    • 1
    • 2

    5、 生成一个series

    Series::new()

    let mySeries = Series::new("姓名",vec!["张三丰","黄老邪","老顽童"]);
    
    • 1

    6、读取csv到df 中

    CsvReader::new()

    /// 功能:读取csv文件,转成dataframe
    /// 输入:filePath:String ,文件路径和名字
    /// 输出:Result 
    /// 
    ///  # Examples
    /// ```
    /// use polars::prelude::*;
    /// use std::fs::File;
    /// let df = read_csv("D:/csvTest/000004.csv".to_string());
    /// println!("{:?}", df);
    /// ```
    /// 
    fn read_csv(filePath: String) -> Result<DataFrame> 
    {
        let file = File::open(filePath).expect("找不到文件");
        CsvReader::new(file)
            .infer_schema(None)
            .has_header(true)
            .finish()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    测试代码:

    use polars::prelude::*;
    use std::fs::File;
    let df = read_csv("D:/csvTest/000004.csv".to_string());
    println!("{:?}", df);
    
    • 1
    • 2
    • 3
    • 4

    7、把df保存成csv文件

    write_csv::new()

    /// 【功能】把dataframe保存成csv
    /// 输入:
    /// df: &mut DataFrame
    /// filePath:String
    /// 输出:Result<()>
    /// 
    ///  # Examples
    /// ```
    /// extern crate polars; 
    /// use polars::prelude::*;
    /// let mut df = DataFrame::default();
    /// df.with_column(Series::new("榜号",vec![1,2,3]));
    /// df.with_column(Series::new("姓名",vec!["张三丰","黄老邪","老顽童"]));
    /// write_csv(& mut df,"e:/bbb.csv".to_string());
    /// ```
    /// 
    fn write_csv(df: &mut DataFrame,filePath:String) -> Result<()> {
        let mut file = File::create(filePath).expect("创建文件失败");
    
        CsvWriter::new(&mut file)
        .has_header(true)    //.has_headers(true)
        .with_delimiter(b',')
        .finish(df)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    测试代码:

    extern crate polars; 
    use polars::prelude::*;
    let mut df = DataFrame::default();
    df.with_column(Series::new("榜号",vec![1,2,3]));
    df.with_column(Series::new("姓名",vec!["张三丰","黄老邪","老顽童"]));
    write_csv(& mut df,"e:/bbb.csv".to_string());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    8、Series如何切片?

    mySeries.slice()

    let s = Series::new("x",  vec!(1,2,3,4,5,6));
    let mySliceMean = s.slice(0,3).mean();  //从index为0的item开始取数据,取3个item
    println!("{:?}",mySliceMean);
    
    • 1
    • 2
    • 3

    9、map的使用

    • 涵义
      map,apply以及C#中的select,他们其实是玩法相同。
      [1,2,3,4] × 2 = [2,4,6,8]
      对系列中的每个item都执行一次相同的处理,处理结果重新生成一个新的系列

    • 举例

    (1)julia
    f(x)=2x
    [1,2,3,4] .|> f
    结果
    [2,4,6,8]

    (2)C#
    [1,2,3,4] .select(x=>2*x)
    结果
    [2,4,6,8]

    (3)Rust

    let q:Series = (0..100).map(|x|(2 * x) as i32).collect(); 
    println!("{:?}", q);
    
    • 1
    • 2
    [0,2,4,6,8,.......198]
    
    • 1

    夫人看了我写的代码,说了句:茴香豆的茴字都写出花来了,有意思吗?

    10、闭包的使用

    • 话说什么是闭包?
      函数、匿名函数、委托、兰姆达、闭包,看见这些词,是不是有想吐的感觉——想吐就对了,我就经常吐。

    对于大多数人而言,上古时代的编程语言多半是过程式,比如C.其它古早的函数式语言另论。

    我们定义的变量一般都是用来存储数据的。加入有人提出:我有一个函数,我要把它存在一个变量里?
    怎么弄,用一种特殊的变量,用来保存该函数的地址,这就是函数指针。

    要调用一个函数,你的先定义一个有名有姓(函数签名)的函数,这是传统做法(明媒正娶,昭告乡间)。

    后来有人说,我不想提前写那么多琐碎的小函数,我用的时候在定义,于是出现了现写现用的函数,在同一个代码块里面,写好一个临时的函数,然后接着就调用它,这个临时的函数就是匿名函数、表达式。(有点像童养媳了)。

    后来有人说,我要在调用的时候直接写,于是你把函数逻辑直接写在一大条语句里,写完即代表调用结束,该求值的也求了,这就是闭包。(我也不知道怎么形容了)

    • rust中使用闭包

    写在一行里面的闭包

    let q:Series = (0..100).map(|x|(2 * x) as i32).collect(); 
    println!("{:?}", q);
    
    • 1
    • 2

    如果你的逻辑比较复杂,需要多行处理,那就写多行呗,如下所示,你还能写return!

     let q:Series = (0..100).map(
            |x|
            {
                let y = 2*x;
                
                return 2 * y;
            }
             as i32).collect();  //.collect::>()
        println!("{:?}", q);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    11、k线MA的计算函数

    ma是啥,计算公式是啥,去查通*达&信软件,此地不敢多说,免得被封,直接上菜

    ///【功能】给定一个价格系列,计算周期为n的移动平均MA
    fn Ma(prices:&Series,n:usize)->Vec<f32>
    {
        (0..prices.len()).map(
            |x|-> f32
            {
                let m2 = if(x< n){
                    NAN
                }
                else{
                    prices.slice((x-n) as i64, n).mean().unwrap() as f32
                };
    
                return m2;           
            }
        ).collect::<Vec<f32>>() 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    收尾:附上一个测试代码,没时间整理,随便看吧,我出门买菜去了

    
    extern crate polars; 
    
    //use polars::export::num::ToPrimitive;
    // #[cfg(feature = "rolling_window")]
    use polars::prelude::*;
    
    use polars::df;
    use std::f32::NAN;
    use std::fs::File;
    
    use std::collections::HashMap;
    
    //use std::iter::zip;
    
    fn main1() {
        println!("Hello, world!!!!!!");
        println!("who are you?");
        println!("Hello world");
        println!("Hello error2");
        format!("Hello {}", "world111111");
    
        let df = df!["字母" => ["a", "b", "c", "d"],"数字" => [1, 2, 3, 4]];
        println!("{:?}",df);
    }
    
    fn main2() 
    {    
        let x = std::f64::consts::PI;
        let r = 8.0;
        println!("计算出来的面积为: {}", x * r * r);
    }
    
    /// 功能:读取csv文件,转成dataframe
    /// 输入:filePath:String ,文件路径和名字
    /// 输出:Result 
    /// 
    ///  # Examples
    /// ```
    /// use polars::prelude::*;
    /// use std::fs::File;
    /// let df = read_csv("D:/csvTest/000004.csv".to_string());
    /// println!("{:?}", df);
    /// ```
    /// 
    fn read_csv(filePath: String) -> Result<DataFrame> 
    {
        let file = File::open(filePath).expect("找不到文件");
    
        CsvReader::new(file)
            .infer_schema(None)
            .has_header(true)
            .finish()
    }
    
    /// 【功能】把dataframe保存成csv
    /// 输入:
    /// df: &mut DataFrame
    /// filePath:String
    /// 输出:Result<()>
    /// 
    ///  # Examples
    /// ```
    /// extern crate polars; 
    /// use polars::prelude::*;
    /// let mut df = DataFrame::default();
    /// df.with_column(Series::new("榜号",vec![1,2,3]));
    /// df.with_column(Series::new("姓名",vec!["张三丰","黄老邪","老顽童"]));
    /// write_csv(& mut df,"e:/bbb.csv".to_string());
    /// ```
    /// 
    fn write_csv(df: &mut DataFrame,filePath:String) -> Result<()> {
        let mut file = File::create(filePath).expect("创建文件失败");
    
        CsvWriter::new(&mut file)
        .has_header(true)    //.has_headers(true)
        .with_delimiter(b',')
        .finish(df)
    }
    
    fn read_csv_test()
    {
        let df = read_csv("D:/csvTest/000004.csv".to_string());
        println!("{:?}", df);
    }
    
    fn main3()
    {
        //main1();
        //main2();
        //read_csv_test()
    
        // use iterators
        let ca: UInt32Chunked = (0..10).map(Some).collect();
        println!("{:?}", ca);
    
        // from slices
        let ca = UInt32Chunked::new("foo", &[1, 2, 3]);
        println!("{:?}", ca);
    
        // use builders
        let mut builder = PrimitiveChunkedBuilder::<UInt32Type>::new("foo", 10);
        println!("-----------------------开始打印item------------------------");
        for value in 0..10 {
            println!("{}",value);
            builder.append_value(value);
        }
        println!("------------------------结束打印item-------------------------");
        let ca = builder.finish();
        println!("{:?}", ca);
    }
    
    fn main_dict()
    {
        let mut hd: HashMap<&str,DataFrame> = HashMap::new();
        let df = read_csv("D:/csvTest/000004.csv".to_string()).unwrap();
        hd.insert(&"df", df); 
        println!("------------------------12131321321321321-------------------------");   
        println!("{:?}", hd["df"]);
    
        let k = &"df";
        hd.remove(k);
        println!("{}",hd.len());
    }
    
    fn main5()
    {
        let mut df = read_csv("D:/csvTest/000004.csv".to_string()).unwrap();
        println!("{:?}", df);
    
        let ma5 = Series::new("ma5",&df["close"] + &df["open"]);    
        println!("{:?}", ma5);
    
        df.with_column(ma5); //df增加一列
        println!("{:?}", df);
    
        let x = df.column("open").unwrap();
        println!("{:?}",x);
    
        let y = &df["close"];
        println!("{:?}",y);    
        
        println!("{:?}",y); 
    }
    
    fn main6(){
        let arr = [100,200,300,400,500,600];  
        let mut i=0;  
        let a=&arr[1..=3];  
        let len=a.len();  
        println!("Elements of 'a' array:");  
        while i<len  
        {  
         println!("{}",a[i]);  
         i=i+1;  
        } 
    
        let mut df = read_csv("D:/csvTest/000004.csv".to_string()).unwrap();
        println!("{:?}", df);
    
        let x = df.column("open").unwrap();
        println!("{:?}",x);
    }
    
    ///【功能】给定一个价格系列,计算周期为n的移动平均MA
    fn Ma(prices:&Series,n:usize)->Vec<f32>
    {
        (0..prices.len()).map(
            |x|-> f32
            {
                let m2 = if(x< n){
                    NAN
                }
                else{
                    prices.slice((x-n) as i64, n).mean().unwrap() as f32
                };
    
                return m2;           
            }
        ).collect::<Vec<f32>>() 
    }
    
    fn main(){
        let s = Series::new("x",  vec!(1,2,3,4,5,6));
        let mySliceMean = s.slice(0,3).mean();
        println!("{:?}",mySliceMean);
    
        let mut df = read_csv("D:/csvTest/000004.csv".to_string()).unwrap();
        println!("{:?}", df);
    
        let ma5 = Series::new("ma5",&df["close"]);    
        println!("{:?}", ma5);    
    
        let myMean = ma5.slice(0, 5).mean();
        println!("{:?}", ma5);
    
        let a = &df["close"];
    
        let v6 = Ma(&df["close"], 6);
        println!("{:?}", v6);
        let ma6= Series::new("ma6",v6);
        df.with_column(ma6); //df增加一列
        println!("{:?}", df);
    
        write_csv(& mut df,"e:/aaa.csv".to_string());
    
        let mut df = DataFrame::default();
        df.with_column(Series::new("榜号",vec![1,2,3]));
        df.with_column(Series::new("姓名",vec!["张三丰","黄老邪","老顽童"]));
        write_csv(& mut df,"e:/bbb.csv".to_string());
    
        let q:Series = (0..100).map(|x|(2 * x) as i32).collect();  //.collect::>()
        println!("{:?}", q);
    
        let q:Series = (0..100).map(
            |x|
            {
                let y = 2*x;
                
                return 2 * y;
            }
             as i32).collect();  //.collect::>()
        println!("{:?}", q);
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
  • 相关阅读:
    Linux 查找动态库位置
    我是如何使用ChatGPT和CoPilot作为编码助手的
    Service和启动其他应用的功能和替换Fragment
    【数据结构与算法】拓扑排序与关键路径
    bug:XShell无法连接CentOS虚拟机
    【MySQL】MySQL的存储过程(1)
    网络安全(黑客)自学
    IDEA通过原型(骨架)创建MavenJavaWeb项目
    clock gating check
    Vue3中动态渲染菜单栏(TS)
  • 原文地址:https://blog.csdn.net/dzj2021/article/details/126317006