Polars(Rust)中如何用众数填充Cabin列的空值?
问题:Polars(Rust)中用众数填充Cabin列空值无效
我在泰坦尼克数据集上使用Polars(Rust)处理数据,发现Cabin列存在大量空值,尝试用fill_null方法以该列的众数填充空值,但空值数量完全没变化,相关代码及输出如下,请帮忙找出问题所在?
fn main() -> Result<()> { let q = LazyCsvReader::new("data/train.csv") .has_header(true) .finish()?; let df = q .collect()?; let fill = df.clone() .lazy() .with_columns([col("Cabin").fill_null(col("Cabin").mode())]) .collect()?; println!("{:?}", df.null_count()); println!("{:?}", fill.null_count()); Ok(()) }
输出:
shape: (1, 12) ┌─────────────┬──────────┬────────┬──────┬───┬────────┬──────┬───────┬──────────┐ │ PassengerId ┆ Survived ┆ Pclass ┆ Name ┆ … ┆ Ticket ┆ Fare ┆ Cabin ┆ Embarked │ │ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │ │ u32 ┆ u32 ┆ u32 ┆ u32 ┆ ┆ u32 ┆ u32 ┆ u32 ┆ u32 │ ╞═════════════╪══════════╪════════╪══════╪═══╪════════╪══════╪═══════╪══════════╡ │ 0 ┆ 0 ┆ 0 ┆ 0 ┆ … ┆ 0 ┆ 0 ┆ 687 ┆ 2 │ └─────────────┴──────────┴────────┴──────┴───┴────────┴──────┴───────┴──────────┘ shape: (1, 12) ┌─────────────┬──────────┬────────┬──────┬───┬────────┬──────┬───────┬──────────┐ │ PassengerId ┆ Survived ┆ Pclass ┆ Name ┆ … ┆ Ticket ┆ Fare ┆ Cabin ┆ Embarked │ │ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │ │ u32 ┆ u32 ┆ u32 ┆ u32 ┆ ┆ u32 ┆ u32 ┆ u32 ┆ u32 │ ╞═════════════╪══════════╪════════╪══════╪═══╪════════╪══════╪═══════╪══════════╡ │ 0 ┆ 0 ┆ 0 ┆ 0 ┆ … ┆ 0 ┆ 0 ┆ 687 ┆ 2 │ └─────────────┴──────────┴────────┴──────┴───┴────────┴──────┴───────┴──────────┘
解决方案
问题根源在于col("Cabin").mode()的返回值类型:
- Polars的
mode()函数返回的是包含众数的列表(支持多众数场景),而fill_null()需要接收单个标量值,直接传入列表会导致填充逻辑无法触发,空值自然不会被替换。 - 你需要从mode的结果中提取出单个众数值(泰坦尼克数据集的Cabin列众数唯一),再传入
fill_null。
修正方案1:提前计算众数标量值
fn main() -> Result<()> { let q = LazyCsvReader::new("data/train.csv") .has_header(true) .finish()?; let df = q.collect()?; // 计算Cabin列的众数并提取第一个值(数据集众数唯一) let cabin_mode = df .lazy() .select([col("Cabin").mode().alias("mode")]) .collect()? .column("mode")? .str() .get(0) .unwrap() // 实际项目中建议处理None情况,避免panic .to_string(); let fill = df .clone() .lazy() .with_columns([col("Cabin").fill_null(lit(cabin_mode))]) .collect()?; println!("原数据空值计数:\n{:?}", df.null_count()); println!("填充后空值计数:\n{:?}", fill.null_count()); Ok(()) }
修正方案2:在Lazy Pipeline中直接提取众数
无需提前collect,直接在Lazy API中用first()提取众数的第一个值:
fn main() -> Result<()> { let q = LazyCsvReader::new("data/train.csv") .has_header(true) .finish()?; let df = q.collect()?; let fill = df .clone() .lazy() .with_columns([ col("Cabin").fill_null( col("Cabin").mode().first() // 直接提取第一个众数 ) ]) .collect()?; println!("原数据空值计数:\n{:?}", df.null_count()); println!("填充后空值计数:\n{:?}", fill.null_count()); Ok(()) }
修改后,Cabin列的空值会被正确填充为该列的众数,空值数量会变为0。
内容的提问来源于stack exchange,提问作者kasn
相关产品推荐
相关产品推荐

