如何在Rust的Polars中将宽DataFrame转换为窄DataFrame?
在Rust Polars中实现R的stack+cbind重复列功能
不需要手动遍历Series调用append(),也不用手动重复剩余列再合并——Polars提供的melt方法可以直接实现你要的功能,完全对应R中stack结合cbind重复列的逻辑。
核心思路
你在R中的操作本质是:将指定列堆叠为values+variable两列,同时将剩余列按堆叠后的行数重复并合并。Polars的melt方法原生支持这个逻辑:
- 指定
id_vars:需要保留并自动重复的列(对应你R代码中cbind的那4列) - 指定
value_vars:需要堆叠的列(对应你R中stack(preds[1:(ncol(preds)-4)])的1000列)
执行melt后,Polars会自动完成列堆叠,并将id_vars的列对应到每一行堆叠结果中,无需手动处理重复。
代码示例
use polars::prelude::*; fn main() -> Result<(), PolarsError> { // 模拟你的DataFrame:前n-4列是要堆叠的,最后4列是要保留的 let mut df = df!( "col_1" => [1, 2, 3], "col_2" => [4, 5, 6], // ... 这里省略998列 ... "keep_col_4" => ["x", "y", "z"], "keep_col_3" => [true, false, true], "keep_col_2" => [10.0, 20.0, 30.0], "keep_col_1" => [100, 200, 300] )?; // 拆分要堆叠的列(value_vars)和要保留的列(id_vars) let all_cols = df.get_column_names(); let split_pos = all_cols.len() - 4; let (value_cols, id_cols): (Vec<_>, Vec<_>) = all_cols.split_at(split_pos).into(); // 转换为Polars需要的&str类型集合 let value_vars: Vec<&str> = value_cols.iter().map(|s| s.as_str()).collect(); let id_vars: Vec<&str> = id_cols.iter().map(|s| s.as_str()).collect(); // 执行melt,一步完成堆叠+合并重复列 let result_df = df.melt(id_vars, value_vars)?; println!("{}", result_df); Ok(()) }
适配非连续的保留列
如果你的保留列不是连续的最后4列(比如R代码中取的是preds[ncol(preds)], preds[ncol(preds)-3], preds[ncol(preds)-2], preds[ncol(preds)-1]),直接手动指定id_vars列表即可,无需按顺序:
// 手动指定要保留的4个列名,对应你R代码中的选择逻辑 let col_names = df.get_column_names(); let id_vars = vec![ col_names.last().unwrap(), &col_names[col_names.len()-4], &col_names[col_names.len()-3], &col_names[col_names.len()-2] ]; let id_vars: Vec<&str> = id_vars.iter().map(|s| s.as_str()).collect();
内容的提问来源于stack exchange,提问作者GBPU
相关产品推荐
相关产品推荐

