Rust高性能数据处理库polars-ffi的使用,polars-ffi提供高效数据分析和操作接口

Rust高性能数据处理库polars-ffi的使用,polars-ffi提供高效数据分析和操作接口

安装

在你的项目目录中运行以下Cargo命令:

cargo add polars-ffi

或者在你的Cargo.toml中添加以下行:

polars-ffi = "0.49.1"

基本信息

  • 版本: 0.49.1
  • 发布时间: 约1个月前
  • 许可证: MIT
  • 大小: 10.4 KiB

所有者

  • Ritchie Vink
  • Stijn

完整示例代码

以下是一个使用polars-ffi进行数据处理的完整示例:

use polars_ffi::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建一个新的数据帧
    let mut df = DataFrame::default();
    
    // 添加列
    let names = Series::new("name", &["Alice", "Bob", "Charlie"]);
    let ages = Series::new("age", &[25, 30, 35]);
    let cities = Series::new("city", &["New York", "London", "Paris"]);
    
    df.with_column(names)?;
    df.with_column(ages)?;
    df.with_column(cities)?;
    
    // 打印数据帧
    println!("原始数据帧:");
    println!("{}", df);
    
    // 过滤年龄大于30的记录
    let filtered = df.filter(&df.column("age")?.gt(30))?;
    println!("过滤后的数据帧:");
    println!("{}", filtered);
    
    // 计算平均年龄
    let avg_age = df.column("age")?.mean()?;
    println!("平均年龄: {}", avg_age);
    
    Ok(())
}

这个示例展示了:

  1. 创建一个新的数据帧
  2. 添加多个列
  3. 打印数据帧内容
  4. 过滤数据
  5. 计算聚合值

polars-ffi提供了高效的数据处理接口,特别适合需要高性能数据分析的Rust应用场景。


1 回复

Rust高性能数据处理库polars-ffi使用指南

概述

polars-ffi是Polars生态系统的FFI(Foreign Function Interface)接口,允许通过C API与其他语言进行交互,同时保持Polars的高性能数据处理能力。它提供了高效的数据分析和操作接口,特别适合需要跨语言集成的场景。

主要特性

  • 高性能的列式数据处理
  • 惰性执行和查询优化
  • 支持多种数据类型
  • 内存高效
  • 线程安全设计

基本使用方法

安装

在Cargo.toml中添加依赖:

[dependencies]
polars-ffi = "0.30"

基本示例

use polars_ffi::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建上下文
    let ctx = unsafe { create_context() };
    
    // 创建DataFrame
    let df = unsafe {
        let series1 = create_series_i32("numbers", &[1, 2, 3, 4, 5], 5);
        let series2 = create_series_utf8("letters", &["a", "b", "c", "d", "e"], 5);
        create_dataframe(&[series1, series2], 2)
    };
    
    // 执行操作
    let result = unsafe {
        let lazy_df = dataframe_to_lazy(df);
        let filtered = lazy_filter(lazy_df, "numbers > 2");
        collect(filtered)
    };
    
    // 打印结果
    unsafe {
        print_dataframe(result);
    }
    
    // 释放资源
    unsafe {
        free_dataframe(df);
        free_dataframe(result);
        free_context(ctx);
    }
    
    Ok(())
}

完整示例代码

下面是一个完整的polars-ffi使用示例,展示了从数据创建、处理到结果输出的完整流程:

use polars_ffi::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建上下文环境
    let ctx = unsafe { create_context() };
    if ctx.is_null() {
        return Err("Failed to create context".into());
    }

    // 创建两个Series:一个整数列和一个字符串列
    let series1 = unsafe { create_series_i32("id", &[1, 2, 3, 4, 5], 5) };
    let series2 = unsafe { create_series_utf8("name", &["Alice", "Bob", "Charlie", "David", "Eve"], 5) };
    
    // 检查Series创建是否成功
    if series1.is_null() || series2.is_null() {
        unsafe {
            free_context(ctx);
        }
        return Err("Failed to create series".into());
    }

    // 从Series创建DataFrame
    let df = unsafe { create_dataframe(&[series1, series2], 2) };
    if df.is_null() {
        unsafe {
            free_series(series1);
            free_series(series2);
            free_context(ctx);
        }
        return Err("Failed to create DataFrame".into());
    }

    // 转换为惰性DataFrame以进行查询优化
    let lazy_df = unsafe { dataframe_to_lazy(df) };
    
    // 执行过滤操作:选择id大于2的记录
    let filtered = unsafe { lazy_filter(lazy_df, "id > 2") };
    
    // 添加计算列:名字长度
    let with_length = unsafe {
        lazy_with_column(
            filtered,
            "name_length",
            "str_length(name)",
            None
        )
    };
    
    // 执行查询并收集结果
    let result = unsafe { collect(with_length) };
    
    // 打印结果DataFrame
    unsafe {
        print_dataframe(result);
    }

    // 释放所有分配的资源
    unsafe {
        free_dataframe(df);
        free_dataframe(result);
        free_context(ctx);
    }

    Ok(())
}

高级功能

1. 数据聚合

unsafe {
    let lazy_df = dataframe_to_lazy(df);
    let aggregated = lazy_groupby(
        lazy_df,
        &["letters"],
        &[("numbers", "sum")],
        GroupByOptions::default()
    );
    let result = collect(aggregated);
    print_dataframe(result);
    free_dataframe(result);
}

2. 数据连接

unsafe {
    let df1 = create_sample_dataframe_1();
    let df2 = create_sample_dataframe_2();
    
    let joined = join_dataframes(
        df1,
        df2,
        "id",
        "id",
        JoinType::Inner,
        JoinOptions::default()
    );
    
    print_dataframe(joined);
    free_dataframe(joined);
}

3. 自定义函数应用

unsafe {
    let lazy_df = dataframe_to_lazy(df);
    let with_custom = lazy_with_column(
        lazy_df,
        "squared",
        "numbers * numbers",
        None
    );
    let result = collect(with_custom);
    print_dataframe(result);
    free_dataframe(result);
}

性能提示

  1. 尽可能使用惰性评估(Lazy API)来构建整个查询计划,最后再执行collect
  2. 批量操作比逐行操作更高效
  3. 合理使用数据类型,避免不必要的类型转换
  4. 复用DataFrame和Context对象,减少创建开销

内存管理注意事项

由于polars-ffi使用C API,需要手动管理内存:

  • 每个create_函数创建的对象都需要对应的free_函数释放
  • 操作完成后及时释放不再需要的对象
  • 在多线程环境中确保正确的内存访问顺序

错误处理

所有FFI函数都可能返回错误,实际使用时应检查返回状态:

unsafe {
    let result = create_series_i32("data", &[1, 2, 3], 3);
    if result.is_null() {
        let error = get_last_error();
        eprintln!("Error creating series: {}", error);
        free_error_message(error);
        return Err("Failed to create series".into());
    }
    // 正常处理...
}

polars-ffi为Rust程序提供了高性能数据处理能力,同时保持了与其他语言交互的可能性,是构建数据密集型应用的强大工具。

回到顶部