假设我有这个数据框:
>>> polars.DataFrame([[1,2,3],[4,5,6],[7,8,9]],list('abc'))
shape: (3, 3)
┌─────┬─────┬─────┐
│ a ┆ b ┆ c │
│ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ i64 │
╞═════╪═════╪═════╡
│ 1 ┆ 4 ┆ 7 │
│ 2 ┆ 5 ┆ 8 │
│ 3 ┆ 6 ┆ 9 │
└─────┴─────┴─────┘
请注意,下面我特别询问列“不重要”的情况 - 即我正在寻找一种解决方案,该解决方案不一定依赖于名为
a
、b
和 c
的列或有一定数量的列。
我可以使用以下命令来更新某一行的某一列:
>>> polars.DataFrame([[1,2,3],[4,5,6],[7,8,9]],list('abc')).with_row_count().with_columns(a=polars.when(polars.col('row_nr') == 1).then(42).otherwise(polars.col('a'))).drop('row_nr')
shape: (3, 3)
┌─────┬─────┬─────┐
│ a ┆ b ┆ c │
│ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ i64 │
╞═════╪═════╪═════╡
│ 1 ┆ 4 ┆ 7 │
│ 42 ┆ 5 ┆ 8 │
│ 3 ┆ 6 ┆ 9 │
└─────┴─────┴─────┘
但是如果我不知道我应该更新的话那就有点困难了
a
。
我该如何执行以下操作:
43,42,41
替换第二行:┌─────┬─────┬─────┐
│ a ┆ b ┆ c │
│ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ i64 │
╞═════╪═════╪═════╡
│ 1 ┆ 4 ┆ 7 │
│ 43 ┆ 42 ┆ 41 │
│ 3 ┆ 6 ┆ 9 │
└─────┴─────┴─────┘
> 4
:┌─────┬─────┬─────┐
│ a ┆ b ┆ c │
│ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ i64 │
╞═════╪═════╪═════╡
│ 1 ┆ 4 ┆ 7 │
│ 2 ┆ -5 ┆ -8 │
│ 3 ┆ 6 ┆ 9 │
└─────┴─────┴─────┘
pl.all
可以用作 when
表达式中每一列(即每个元素)的简写。 cumcount
可以延迟复制行索引,无需任何 with_row_count
列。将所有内容放在一起,作为第 2 部分:
df.with_columns(
pl.when((pl.all().cumcount() == 1) & (pl.all() > 4))
.then(-pl.all())
.otherwise(pl.all())
.keep_name()
)
除了将
df
暂时设为一列之外,我不确定第 1 部分是否有更好的方法,请执行与上面类似的方法,然后取消嵌套:
df.select(x=pl.concat_list(pl.all())).select(
x=pl.when(pl.col("x").cumcount() == 1)
.then([43, 42, 41])
.otherwise(pl.col("x"))
.arr.to_struct(fields=df.columns)
).unnest("x")
只需使用生成器/列表理解。
df.select(
(pl.when(pl.first().cumcount()==1)
.then(pl.lit(x))
.otherwise(pl.col(df.columns[i])))
.alias(df.columns[i]) for i, x in enumerate([43,42,41])
)
这种方法的问题在于它依赖于
df.columns
,所以你不能把它放在链的末尾。但是,如果将其放入函数中并将其猴子修补到 DataFrame 命名空间中,则可以解决这个问题。只需将所有对 df
的引用更改为 self,如下所示:
def replace_row(self, row_index, new_values):
return self.select(
(pl.when(pl.first().cumcount()==row_index)
.then(pl.lit(x))
.otherwise(pl.col(self.columns[i])))
.alias(self.columns[i]) for i, x in enumerate(new_values)
)
pl.DataFrame.replace_row=replace_row
del replace_row
现在你可以像这样链接:
df.with_columns(d=pl.Series([2,8,1])).replace_row(0, [1,2,3,4])
shape: (3, 4)
┌─────┬─────┬─────┬─────┐
│ a ┆ b ┆ c ┆ d │
│ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ i64 ┆ i64 │
╞═════╪═════╪═════╪═════╡
│ 1 ┆ 2 ┆ 3 ┆ 4 │
│ 2 ┆ 5 ┆ 8 ┆ 8 │
│ 3 ┆ 6 ┆ 9 ┆ 1 │
└─────┴─────┴─────┴─────┘
您还可以注册自己的命名空间,如所示,但该方法的语法将是
df.mynamespace.replace_row()
我更喜欢将其放在 df 级别。如果您要创建很多这样的辅助函数,那么将它们全部放在自己的命名空间中可能是有意义的。
pl.DataFrame.update
。
# ensure df has index column
df = df.with_row_index()
# create dataframe for row
row = pl.DataFrame(data=[[2, 41, 42, 43]], schema=df.schema, orient="row")
# update df
df.update(row, on="index")
shape: (3, 4)
┌───────┬─────┬─────┬─────┐
│ index ┆ a ┆ b ┆ c │
│ --- ┆ --- ┆ --- ┆ --- │
│ u32 ┆ i64 ┆ i64 ┆ i64 │
╞═══════╪═════╪═════╪═════╡
│ 0 ┆ 1 ┆ 4 ┆ 7 │
│ 1 ┆ 2 ┆ 5 ┆ 8 │
│ 2 ┆ 41 ┆ 42 ┆ 43 │
└───────┴─────┴─────┴─────┘
请注意,传递给
data
的 pl.DataFrame
参数的列表中的第一个值是应更新的行的索引。