You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust的Polars DataFrame中按列名逐行索引数据?

解决方案:Rust Polars 遍历行并按列名访问字段

针对你提到的需求(小数据量下优先简洁易读),以下是几种更优的实现方式:


方案1:反序列化为自定义结构体(推荐)

这是最符合DRY原则且易读的方式,通过serde和Polars的派生宏将每行数据转换为结构体实例,直接通过字段名访问对应列的值。

步骤1:添加依赖

确保Cargo.toml中包含所需特性:

[dependencies]
polars = { version = "0.35", features = ["derive", "serde", "csv"] }
serde = { version = "1.0", features = ["derive"] }

步骤2:实现代码

use polars::prelude::*;
use serde::Deserialize;

// 定义与DataFrame列名匹配的结构体(字段名需与列名一致,可通过#[serde(rename)]调整)
#[derive(Debug, Deserialize)]
struct CityRecord {
    year: i64,
    city: String,
    val: i64,
}

fn main() -> PolarsResult<()> {
    // 示例DataFrame(实际为合并后的CSV数据)
    let df = df!(
        "year" => &[1920, 1920, 1920, 1930, 1930],
        "city" => &["Boston", "Memphis", "Columbus", "Boston", "Seattle"],
        "val"  => &[5, 42, 19, 52, 8])?;

    // 将DataFrame转换为结构体向量
    let records: Vec<CityRecord> = df.to_structs()?;

    // 遍历并按字段名访问数据
    for record in records {
        println!("年份: {}, 城市: {}, 数值: {}", record.year, record.city, record.val);
    }

    Ok(())
}

这种方式即使列数增加,只需在结构体中添加对应字段即可,完全符合简洁性要求。


方案2:优化get_row_amortized的使用

如果你不想引入serde,可以通过预先获取列索引的方式,用get_row_amortized按列名取值:

use polars::prelude::*;

fn main() -> PolarsResult<()> {
    let df = df!(
        "year" => &[1920, 1920, 1920, 1930, 1930],
        "city" => &["Boston", "Memphis", "Columbus", "Boston", "Seattle"],
        "val"  => &[5, 42, 19, 52, 8])?;

    // 预先获取列索引,避免重复计算
    let year_idx = df.column_index("year")?;
    let city_idx = df.column_index("city")?;
    let val_idx = df.column_index("val")?;

    for i in 0..df.height() {
        let row = df.get_row_amortized(i)?;
        // 按索引获取值并转换为对应类型
        let year = row.get(year_idx)?.try_extract::<i64>()?;
        let city = row.get(city_idx)?.try_extract::<&str>()?;
        let val = row.get(val_idx)?.try_extract::<i64>()?;
        
        println!("{:?} {:?} {:?}", year, city, val);
    }

    Ok(())
}

方案3:封装列迭代器工具函数

如果偏好迭代器风格,可以封装一个工具函数,自动根据列名组合迭代器,避免手动写izip!:

use polars::prelude::*;
use itertools::izip;

// 封装一个函数,接收DataFrame和列名列表,返回对应列的迭代器元组
fn get_column_iterators<'a>(df: &'a DataFrame, cols: &[&str]) -> PolarsResult<(
    impl Iterator<Item = i64> + 'a,
    impl Iterator<Item = &'a str> + 'a,
    impl Iterator<Item = i64> + 'a,
)> {
    let year_iter = df.column(cols[0])?.i64()?;
    let city_iter = df.column(cols[1])?.str()?;
    let val_iter = df.column(cols[2])?.i64()?;
    Ok((year_iter, city_iter, val_iter))
}

fn main() -> PolarsResult<()> {
    let df = df!(
        "year" => &[1920, 1920, 1920, 1930, 1930],
        "city" => &["Boston", "Memphis", "Columbus", "Boston", "Seattle"],
        "val"  => &[5, 42, 19, 52, 8])?;

    let (years, cities, vals) = get_column_iterators(&df, &["year", "city", "val"])?;
    for (year, city, val) in izip!(years, cities, vals) {
        println!("{:?} {:?} {:?}", year, city, val);
    }

    Ok(())
}

不过这种方式列数变化时仍需修改函数返回类型,不如结构体方案灵活。


内容的提问来源于stack exchange,提问作者Nick K9

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 01:48:36