如何在聚合时使用python-polars计算众数
我正在参与一个数据挖掘项目,但在做特征工程的时候遇到了一些问题。我的目标之一是根据主键来汇总数据,并生成新的列。所以我写了以下代码:
df = df.group_by("case_id").agg(date_exprs(df,df_base))
def date_expr(df, df_base):
# Join df and df_base on 'case_id' column
df = df.join(df_base[['case_id','date_decision']], on="case_id", how="left")
for col in df.columns:
if col[-1] in ("D",):
df = df.with_columns(pl.col(col) - pl.col("date_decision"))
df = df.with_columns(pl.col(col).dt.total_days())
cols = [col for col in df.columns if col[-1] in ("D",)]
# Generate expressions for max, min, mean, mode, and std of date differences
expr_max = [pl.max(col).alias(f"max_{col}") for col in cols]
expr_min = [pl.min(col).alias(f"min_{col}") for col in cols]
expr_mean = [pl.mean(col).alias(f"mean_{col}") for col in cols]
expr_mode = [pl.mode(col).alias(f"mode_{col}") for col in cols]
expr_std = [pl.std(col).alias(f"std_{col}") for col in cols]
return expr_max + expr_min + expr_mean + expr_mode + expr_std
然而,出现了一个错误:AttributeError: module 'polars' has no attribute 'mode'。
我在GitHub上查找了polars的文档,发现没有Dataframe.mode()这个方法,只有Series.mode(),我觉得这可能是出错的原因?我还咨询了chatGPT,但它也帮不了我,因为这些出错的代码就是从它那得到的。
另外,这里只是处理浮点数类型的一个例子。那字符串类型呢?我也可以用你们的方法吗?
我期待你们的帮助!!
1 个回答
3
在你的例子中,它失败了,因为对于 Expr.mode()
这个函数没有像聚合函数那样的简写方式(比如,pl.max()
是 Expr.max()
的简写)。其实,mode()
不是一个聚合函数,而是一个计算函数,这意味着它只是计算列中出现次数最多的值。
所以,给定一个这样的数据框:
df = (
pl.DataFrame({
'aD' : [200, 200, 300, 400, 1, 3],
'bD': [2, 3, 6, 4, 5, 1],
'case_id': [1,1,1,2,2,2]
})
)
┌─────┬─────┬─────────┐
│ aD ┆ bD ┆ case_id │
│ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ i64 │
╞═════╪═════╪═════════╡
│ 200 ┆ 2 ┆ 1 │
│ 200 ┆ 3 ┆ 1 │
│ 300 ┆ 6 ┆ 1 │
│ 400 ┆ 4 ┆ 2 │
│ 1 ┆ 5 ┆ 2 │
│ 3 ┆ 1 ┆ 2 │
└─────┴─────┴─────────┘
你可以用以下代码来计算 mode()
:
df.with_columns(
pl.col('aD').mode(),
pl.col('bD').mode()
)
┌─────┬─────┬─────────┐
│ aD ┆ bD ┆ case_id │
│ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ i64 │
╞═════╪═════╪═════════╡
│ 200 ┆ 1 ┆ 1 │
│ 200 ┆ 5 ┆ 1 │
│ 200 ┆ 6 ┆ 1 │
│ 200 ┆ 4 ┆ 2 │
│ 200 ┆ 2 ┆ 2 │
│ 200 ┆ 3 ┆ 2 │
└─────┴─────┴─────────┘
基于这个,我们仍然可以计算你需要的结果。我会通过使用 selectors
和 Expr.prefix()
来简化你的函数:
import polars.selectors as cs
def date_expr():
# Generate expressions for max, min, mean, mode, and std of date differences
expr_max = cs.ends_with('D').max().name.prefix("max_")
expr_min = cs.ends_with('D').min().name.prefix("min_")
expr_mean = cs.ends_with('D').mean().name.prefix("mean_")
expr_mode = cs.ends_with('D').mode().first().name.prefix("mode_")
expr_std = cs.ends_with('D').std().name.prefix("std_")
return expr_max, expr_min, expr_mean, expr_std, expr_mode
df.group_by("case_id").agg(date_expr())
┌─────────┬────────┬────────┬────────┬───┬────────────┬──────────┬─────────┬─────────┐
│ case_id ┆ max_aD ┆ max_bD ┆ min_aD ┆ … ┆ std_aD ┆ std_bD ┆ mode_aD ┆ mode_bD │
│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ i64 ┆ i64 ┆ ┆ f64 ┆ f64 ┆ i64 ┆ i64 │
╞═════════╪════════╪════════╪════════╪═══╪════════════╪══════════╪═════════╪═════════╡
│ 2 ┆ 400 ┆ 5 ┆ 1 ┆ … ┆ 229.787583 ┆ 2.081666 ┆ 3 ┆ 4 │
│ 1 ┆ 300 ┆ 6 ┆ 200 ┆ … ┆ 57.735027 ┆ 2.081666 ┆ 200 ┆ 2 │
└─────────┴────────┴────────┴────────┴───┴────────────┴──────────┴─────────┴─────────┘
请注意,我使用了 Expr.first()
来获取 mode
的一个值,因为可能会有多个值出现的频率相同。你可以使用 list
表达式来指定你想要获取哪个值。