У меня есть следующий фрейм данных и вектор имен.
Я хотел бы выбрать строки по именам в векторе и рассчитать средний возраст выбранных строк. У меня есть следующий код:
let names = vec!["panda", "seahorse"];
let avg = df.lazy()
.select([col("name").filter(|c| names.contains(c))])
.agg([col("age").mean()]);
Интуиция подсказывает, что нужно передать функцию фильтру (как это сделал я), однако это неправильно. По-видимому, в игре есть какой-то Expr API. Как это работает? Я нахожу документы немного загадочными.
Это помогает? pola-rs.github.io/polars-book/user-guide/dsl/…
Они представляют собой API, в котором вы можете выбирать столбцы с помощью регулярных выражений, но вместо этого у меня есть произвольный список имен. Должен быть какой-то простой способ сделать это, которого мне не хватает.
Я не уверен, что есть простой способ отфильтровать так, как вы хотите. Один из вариантов, который у вас есть, — создать отдельный DataFrame, содержащий имена, которые вы хотите отфильтровать, и выполнить соединение:
let filter_df = df! [
"name" => ["panda", "seahorse"]
].unwrap();
let avg = df.lazy()
.join(filter_df.lazy(), [col("name")], [col("name")], JoinType::Inner)
.select([col("age").mean()]);
Было неясно, хотите ли вы выполнить среднее значение для всех возрастов, возвращенных этой фильтрацией (именно так это было сформулировано в вашем вопросе), если это так, то этот код должен работать для вас. Это результат:
Ok(shape: (1, 1)
┌─────┐
│ age │
│ --- │
│ f64 │
╞═════╡
│ 3.0 │
└─────┘)
Ваш код создает впечатление, что вы пытались вычислить среднее значение для всех панд по сравнению со средним значением для всех морских коньков. Если это так, вы можете использовать цепочку .groupby().agg():
let avg = df.lazy()
.join(names_df.lazy(), [col("name")], [col("name")], JoinType::Inner)
.groupby([col("name")])
.agg([col("age").mean()]);
Что производит:
Ok(shape: (2, 2)
┌──────────┬─────┐
│ name ┆ age │
│ --- ┆ --- │
│ str ┆ f64 │
╞══════════╪═════╡
│ seahorse ┆ 1.0 │
├╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┤
│ panda ┆ 5.0 │
└──────────┴─────┘)
Спасибо, это работает! Я думаю, что is_in и создание Series, а затем Expr от BallpointBen немного больше подходят для моего варианта использования, но вы также правильно поняли мой немного глупый пример и помогли со средним значением для всех выбранных имен, а не для групп!
Если вы используете функцию is_in
, вы можете фильтровать непосредственно столбец, присутствующий в другом Expr
, что приводит к следующему.
fn main() -> Result<(), PolarsError> {
// Added another panda to see the effect of groupby-mean
let df = df! [
"name" => ["panda", "panda", "polarbear", "seahorse"],
"age" => [5, 55, 7, 1],
]?;
let names = vec!["panda", "seahorse"];
let df = df
.lazy()
.filter(col("name").is_in(lit(Series::from_iter(names))))
.groupby([col("name")])
.agg([col("age").mean()]);
println!("{:?}", df.collect()?);
Ok(())
}
┌──────────┬──────┐
│ name ┆ age │
│ --- ┆ --- │
│ str ┆ f64 │
╞══════════╪══════╡
│ panda ┆ 30.0 │
├╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ seahorse ┆ 1.0 │
└──────────┴──────┘
Спасибо, у меня все заработало! Действительно, для тех, кто интересуется, функция is_in должна быть добавлена в Cargo.toml. polars = { version = "*", features = ["lazy", "is_in"] }
этот API выполняет проверку регулярных выражений?