我想对列进行序数编码。 Pandas 有很好且方便的方法
pd.factorize()
,但是,我想在 Polars 中实现同样的功能。
df = pl.DataFrame({"a": [5, 8, 10], "b": ["hi", "hello", "hi"]})
┌─────┬───────┐
│ a ┆ b │
│ --- ┆ --- │
│ i64 ┆ str │
╞═════╪═══════╡
│ 5 ┆ hi │
│ 8 ┆ hello │
│ 10 ┆ hi │
└─────┴───────┘
想要的结果:
┌─────┬─────┐
│ a ┆ b │
│ --- ┆ --- │
│ i64 ┆ i64 │
╞═════╪═════╡
│ 0 ┆ 0 │
│ 1 ┆ 1 │
│ 2 ┆ 0 │
└─────┴─────┘
您可以加入一个虚拟
DataFrame
,其中包含您感兴趣的唯一值和序数编码:
df = pl.DataFrame({"a": [5, 8, 10], "b": ["hi", "hello", "hi"]})
unique = df.select(
pl.col("b").unique(maintain_order=True)
).with_row_index(name="ordinal")
df.join(unique, on="b")
或者您可能“滥用”分类值由
u32
整数支持这一事实。
df.with_columns(
pl.col("b").cast(pl.Categorical).to_physical().alias("ordinal")
)
两种方法输出:
shape: (3, 3)
┌─────┬───────┬─────────┐
│ a ┆ b ┆ ordinal │
│ --- ┆ --- ┆ --- │
│ i64 ┆ str ┆ u32 │
╞═════╪═══════╪═════════╡
│ 5 ┆ hi ┆ 0 │
│ 8 ┆ hello ┆ 1 │
│ 10 ┆ hi ┆ 0 │
└─────┴───────┴─────────┘
这是另一种方法,尽管我怀疑它比 @ritchie46 的虚拟 Dataframe 更好
df.with_columns([pl.col('b').unique().list().alias('uniq'),
pl.col('b').unique().list().arr.eval(pl.element().rank()).alias('uniqid')]).explode(['uniq','uniqid']).filter(pl.col('b')==pl.col('uniq')).select(pl.exclude('uniq')).with_column(pl.col('uniqid')-1)
几乎肯定有一种方法可以改进这一点,但基本上它会创建一个名为
uniq
的新列,它是该列的所有唯一值的列表,以及 uniqid
(我认为,似乎是)1 -基于索引的值顺序。 然后它会分解那些为 uniq
中的任意值创建行的行,然后过滤掉不等于列 b
的行。 由于 rank
给出 1 索引(而不是 0 索引),因此您必须减去 1
并排除我们不关心的 uniq
列,因为它与 b
相同。
如果顺序不重要,您可以使用DENSE RANK()
df.select(pl.all().rank(method="dense") - 1)
shape: (3, 2)
┌─────┬─────┐
│ a ┆ b │
│ --- ┆ --- │
│ u32 ┆ u32 │
╞═════╪═════╡
│ 0 ┆ 1 │
│ 1 ┆ 0 │
│ 2 ┆ 1 │
└─────┴─────┘
如果是,您可以:
(
df.with_row_index()
.with_columns(
pl.col("index").first().over(col)
.rank(method="dense")
.alias(col) - 1
for col in df.columns
)
)
shape: (3, 3)
┌───────┬─────┬─────┐
│ index ┆ a ┆ b │
│ --- ┆ --- ┆ --- │
│ u32 ┆ u32 ┆ u32 │
╞═══════╪═════╪═════╡
│ 0 ┆ 0 ┆ 0 │
│ 1 ┆ 1 ┆ 1 │
│ 2 ┆ 2 ┆ 0 │
└───────┴─────┴─────┘