如何在 Polars Dataframe 中创建非字母顺序的分类列?

问题描述 投票:0回答:3

在 Pandas 中,您可以从现有字符串列创建“有序”分类列,如下所示:

column_values_with_custom_order = ["B", "A", "C"]

df["Column"] = pd.Categorical(df.Column, categories=column_values_with_custom_order, ordered=True)

在Polars文档中,我找不到这样的方法来创建有序列。然而,我可以使用

pl.from_pandas(df)
重现这一点,所以我怀疑这对于 Polars 也是可能的。

推荐的方法是什么?

我尝试创建新专栏:

polars_df.with_columns(col("Column").cast(pl.Categorical))

但我不知道如何将自定义排序包含在内。

我还检查了在极坐标中,我可以自己创建一个带有级别的分类类型吗?,但我不想在我的数据框中添加另一列仅用于排序。

data-science categorical-data python-polars
3个回答
1
投票

说你有

df = pl.DataFrame(
     {"cats": ["z", "z", "k", "a", "b"], "vals": [3, 1, 2, 2, 3]}
     )

并且您想让猫成为一个分类,但您希望分类排序为

myorder=["k", "z", "b", "a"]

有两种方法可以做到这一点。一种方法是使用

pl.StringCache()
,就像您提到的问题一样,另一种方法更混乱。前者不需要您向 df 添加任何列。其实很简洁。

with pl.StringCache():
    pl.Series(myorder).cast(pl.Categorical)
    df=df.with_columns(pl.col('cats').cast(pl.Categorical))

发生的情况是,StringCache 中的所有内容都会获得相同的键值,因此当

myorder
列表被转换时,会保存分配给每个字符串值的键。当您的 df 在同一缓存下进行转换时,它会获得相同的键/字符串值,并且按照您想要的顺序排列。

另一种方法如下:

您必须按顺序对 df 进行排序,然后您才能执行

set_ordering('physical')
。如果您想保持原来的顺序,那么您只需在开始时使用
with_row_count
即可恢复该顺序。

把它们放在一起,看起来像这样:

df=df.with_row_count('i').join(
        pl.from_dicts([{'order':x, 'cats':y} for x,y in enumerate(myorder)]), on='cats') \
    .sort('order').drop('order') \
    .with_columns(pl.col('cats').cast(pl.Categorical).cat.set_ordering('physical')) \
    .sort('i').drop('i')

您可以通过执行以下操作来验证:

df.select(['cats',pl.col('cats').to_physical().alias('phys')])

shape: (5, 2)
┌──────┬──────┐
│ cats ┆ phys │
│ ---  ┆ ---  │
│ cat  ┆ u32  │
╞══════╪══════╡
│ z    ┆ 1    │
│ z    ┆ 1    │
│ k    ┆ 0    │
│ a    ┆ 3    │
│ b    ┆ 2    │
└──────┴──────┘

1
投票

来自文档: 用途:

polars_df.with_columns(col("Column").cast(pl.categorical).cat.set_ordering("lexical"))

参见文档

df = pl.DataFrame(
    {"cats": ["z", "z", "k", "a", "b"], "vals": [3, 1, 2, 2, 3]}
).with_columns(
    [
        pl.col("cats").cast(pl.Categorical).cat.set_ordering("lexical"),
    ]
)
df.sort(["cats", "vals"])

0
投票

Polars pl.Enum

中添加了 
0.20.0
 类型来处理此类情况。

my_order = ["k", "z", "b", "a"]

df.with_columns(pl.col("cats").cast(pl.Enum(my_order)))
shape: (5, 2)
┌──────┬──────┐
│ cats ┆ vals │
│ ---  ┆ ---  │
│ enum ┆ i64  │
╞══════╪══════╡
│ z    ┆ 3    │
│ z    ┆ 1    │
│ k    ┆ 2    │
│ a    ┆ 2    │
│ b    ┆ 3    │
└──────┴──────┘

检查/验证订单:

(df.with_columns(pl.col("cats").cast(pl.Enum(my_order)))
   .sort("cats")
   .with_columns(order = pl.col("cats").to_physical())
)
shape: (5, 3)
┌──────┬──────┬───────┐
│ cats ┆ vals ┆ order │
│ ---  ┆ ---  ┆ ---   │
│ enum ┆ i64  ┆ u32   │
╞══════╪══════╪═══════╡
│ k    ┆ 2    ┆ 0     │
│ z    ┆ 3    ┆ 1     │
│ z    ┆ 1    ┆ 1     │
│ b    ┆ 3    ┆ 2     │
│ a    ┆ 2    ┆ 3     │
└──────┴──────┴───────┘
© www.soinside.com 2019 - 2024. All rights reserved.