如何在Python Polars中创建FICO分数降序十分位列?
原代码问题出在哪?
- 排序方向反了:
rank()默认是升序计算,高FICO分(比如850)的rank值会比低分大,你再除以总行数乘10,结果肯定小于1,转成UInt32直接变成0。 - 分组逻辑不对:直接用
rank/总行数*10的方式不适合做十分位分组,尤其是当总行数不是10的倍数时,分组会乱。 - 缺失值没处理:如果
fico列有null,rank()会返回null,最终fico_decile也会是null。
两种可行的解决方法
方法1:修正rank逻辑
先按降序排名,再计算十分位,顺便处理缺失值:
df1 = df.with_columns( pl.when(pl.col('fico').is_not_null()) .then(pl.col('fico').rank(method='dense', descending=True).apply(lambda x: (x - 1) // (df.height / 10) + 1).cast(pl.UInt32)) .otherwise(None) .alias('fico_decile') )
嫌lambda麻烦的话,换个更简洁的写法:
df1 = df.with_columns( pl.when(pl.col('fico').is_not_null()) .then((pl.col('fico').rank(method='dense', descending=True) / (df.height / 10)).ceil().cast(pl.UInt32)) .otherwise(None) .alias('fico_decile') )
descending=True:让高分的rank值最小(850的rank是1)ceil():向上取整,保证每个rank都落到正确的十分位组里
方法2:用qcut直接分(更简单)
Polars自带的qcut()可以直接按等频分位分组,一步到位:
df1 = df.with_columns( pl.col('fico') .qcut(10, labels=[str(i) for i in range(1, 11)], descending=True) .alias('fico_decile') .cast(pl.UInt32) )
qcut(10):把数据分成10个等数量的组descending=True:最高分组对应标签1,最低对应10- 要是有缺失值,加个
.fill_null(None)就行
额外提醒
如果不是要等频分组,而是按固定分数区间(比如800-850算1,750-799算2),直接用when-then写区间判断就行。另外如果后续会过滤数据,别用df.height,换成pl.count().over(),这样行数会自动对应当前数据集。
内容的提问来源于stack exchange,提问作者kstats9pt3
相关产品推荐
相关产品推荐

