Polars:用每组内唯一有效的值填充空值

ste*_*ven 5 python-polars

每组在随机行中只有一个有效值或 not_null 值。如何为每个组填充该值?

\n
import polars as pl\n\ndata = {\n    \'group\': [\'1\', \'1\', \'1\', \'2\', \'2\', \'2\', \'3\', \'3\', \'3\'],\n    \'col1\': [1, None, None, None, 3, None, None, None, 5],\n    \'col2\': [\'a\', None, None, None, \'b\', None, None, None, \'c\'],\n    \'col3\': [False, None, None, None, True, None, None, None, False]\n}\ndf = pl.DataFrame(data)\n
Run Code Online (Sandbox Code Playgroud)\n
shape: (9, 4)\n\xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n\xe2\x94\x82 group \xe2\x94\x86 col1 \xe2\x94\x86 col2 \xe2\x94\x86 col3  \xe2\x94\x82\n\xe2\x94\x82 ---   \xe2\x94\x86 ---  \xe2\x94\x86 ---  \xe2\x94\x86 ---   \xe2\x94\x82\n\xe2\x94\x82 str   \xe2\x94\x86 i64  \xe2\x94\x86 str  \xe2\x94\x86 bool  \xe2\x94\x82\n\xe2\x95\x9e\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xa1\n\xe2\x94\x82 1     \xe2\x94\x86 1    \xe2\x94\x86 a    \xe2\x94\x86 false \xe2\x94\x82\n\xe2\x94\x82 1     \xe2\x94\x86 null \xe2\x94\x86 null \xe2\x94\x86 null  \xe2\x94\x82\n\xe2\x94\x82 1     \xe2\x94\x86 null \xe2\x94\x86 null \xe2\x94\x86 null  \xe2\x94\x82\n\xe2\x94\x82 2     \xe2\x94\x86 null \xe2\x94\x86 null \xe2\x94\x86 null  \xe2\x94\x82\n\xe2\x94\x82 2     \xe2\x94\x86 3    \xe2\x94\x86 b    \xe2\x94\x86 true  \xe2\x94\x82\n\xe2\x94\x82 2     \xe2\x94\x86 null \xe2\x94\x86 null \xe2\x94\x86 null  \xe2\x94\x82\n\xe2\x94\x82 3     \xe2\x94\x86 null \xe2\x94\x86 null \xe2\x94\x86 null  \xe2\x94\x82\n\xe2\x94\x82 3     \xe2\x94\x86 null \xe2\x94\x86 null \xe2\x94\x86 null  \xe2\x94\x82\n\xe2\x94\x82 3     \xe2\x94\x86 5    \xe2\x94\x86 c    \xe2\x94\x86 false \xe2\x94\x82\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n
Run Code Online (Sandbox Code Playgroud)\n

期望的输出:

\n
shape: (9, 4)\n\xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n\xe2\x94\x82 group \xe2\x94\x86 col1 \xe2\x94\x86 col2 \xe2\x94\x86 col3  \xe2\x94\x82\n\xe2\x94\x82 ---   \xe2\x94\x86 ---  \xe2\x94\x86 ---  \xe2\x94\x86 ---   \xe2\x94\x82\n\xe2\x94\x82 str   \xe2\x94\x86 i64  \xe2\x94\x86 str  \xe2\x94\x86 bool  \xe2\x94\x82\n\xe2\x95\x9e\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xa1\n\xe2\x94\x82 1     \xe2\x94\x86 1    \xe2\x94\x86 a    \xe2\x94\x86 false \xe2\x94\x82\n\xe2\x94\x82 1     \xe2\x94\x86 1    \xe2\x94\x86 a    \xe2\x94\x86 false \xe2\x94\x82\n\xe2\x94\x82 1     \xe2\x94\x86 1    \xe2\x94\x86 a    \xe2\x94\x86 false \xe2\x94\x82\n\xe2\x94\x82 2     \xe2\x94\x86 3    \xe2\x94\x86 b    \xe2\x94\x86 true  \xe2\x94\x82\n\xe2\x94\x82 2     \xe2\x94\x86 3    \xe2\x94\x86 b    \xe2\x94\x86 true  \xe2\x94\x82\n\xe2\x94\x82 2     \xe2\x94\x86 3    \xe2\x94\x86 b    \xe2\x94\x86 true  \xe2\x94\x82\n\xe2\x94\x82 3     \xe2\x94\x86 5    \xe2\x94\x86 c    \xe2\x94\x86 false \xe2\x94\x82\n\xe2\x94\x82 3     \xe2\x94\x86 5    \xe2\x94\x86 c    \xe2\x94\x86 false \xe2\x94\x82\n\xe2\x94\x82 3     \xe2\x94\x86 5    \xe2\x94\x86 c    \xe2\x94\x86 false \xe2\x94\x82\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n
Run Code Online (Sandbox Code Playgroud)\n

在 pandas 中,我可以对每一列执行以下操作

\n
shape: (9, 4)\n\xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n\xe2\x94\x82 group \xe2\x94\x86 col1 \xe2\x94\x86 col2 \xe2\x94\x86 col3  \xe2\x94\x82\n\xe2\x94\x82 ---   \xe2\x94\x86 ---  \xe2\x94\x86 ---  \xe2\x94\x86 ---   \xe2\x94\x82\n\xe2\x94\x82 str   \xe2\x94\x86 i64  \xe2\x94\x86 str  \xe2\x94\x86 bool  \xe2\x94\x82\n\xe2\x95\x9e\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xa1\n\xe2\x94\x82 1     \xe2\x94\x86 1    \xe2\x94\x86 a    \xe2\x94\x86 false \xe2\x94\x82\n\xe2\x94\x82 1     \xe2\x94\x86 null \xe2\x94\x86 null \xe2\x94\x86 null  \xe2\x94\x82\n\xe2\x94\x82 1     \xe2\x94\x86 null \xe2\x94\x86 null \xe2\x94\x86 null  \xe2\x94\x82\n\xe2\x94\x82 2     \xe2\x94\x86 null \xe2\x94\x86 null \xe2\x94\x86 null  \xe2\x94\x82\n\xe2\x94\x82 2     \xe2\x94\x86 3    \xe2\x94\x86 b    \xe2\x94\x86 true  \xe2\x94\x82\n\xe2\x94\x82 2     \xe2\x94\x86 null \xe2\x94\x86 null \xe2\x94\x86 null  \xe2\x94\x82\n\xe2\x94\x82 3     \xe2\x94\x86 null \xe2\x94\x86 null \xe2\x94\x86 null  \xe2\x94\x82\n\xe2\x94\x82 3     \xe2\x94\x86 null \xe2\x94\x86 null \xe2\x94\x86 null  \xe2\x94\x82\n\xe2\x94\x82 3     \xe2\x94\x86 5    \xe2\x94\x86 c    \xe2\x94\x86 false \xe2\x94\x82\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n
Run Code Online (Sandbox Code Playgroud)\n

在极坐标中如何做到这一点,最好使用窗口函数 (.over()) ?

\n

Dea*_*gor 5

完全按照您的要求进行操作的直接方法是(它看起来最像您的 pandas 方法):

df.with_columns(pl.exclude('group').forward_fill().backward_fill().over('group'))
Run Code Online (Sandbox Code Playgroud)

使用pl.all()代替pl.exclude('group')也可以,但它不会让它在group列中查找填充,从而节省一些理论上的时间。

如果您想要对一系列列执行此操作(而不是除 之外的所有列group),那么您可以将 替换pl.exclude为生成器或列表理解

cols=['col1','col2','col3']
df.with_columns(pl.col(x).forward_fill().backward_fill().over('group') for x in cols)
Run Code Online (Sandbox Code Playgroud)

pl.col只要使用和 锚点,您甚至可以使用^正则表达式 in $

df.with_columns(pl.col("^col\d$").forward_fill().backward_fill().over('group'))
Run Code Online (Sandbox Code Playgroud)

除了向前/向后填充之外的另一种方法:

df.with_columns(pl.col("^col\d$").drop_nulls().first().over('group'))
Run Code Online (Sandbox Code Playgroud)

如果first看起来有点奇怪,那是因为它将drop_nulls返回与原始行数不同的行数df,这将导致错误。如果表达式是聚合(例如summinmax等),那么它不会抱怨获取不同数量的行,而是仅将该答案传播到所有行。在这种情况下first,聚合仅意味着它看到的第一件事。由于过滤器只返回一个东西,我们只需要一种方法来告诉它传播它。

不同的列选择技巧也适用于这种方法,但我不会让读者进行额外的复制/粘贴

最后说明:

如果你的下一步是采取unique那么你应该把它作为df.groupby开始

df \
    .groupby('group', maintain_order=True) \
    .agg(pl.col("^col\d$").drop_nulls().first())
Run Code Online (Sandbox Code Playgroud)