假设我有一个极坐标数据帧:
import polars as pl
df = pl.DataFrame({'index': [1,2,3,2,1],
'object': [1, 1, 1, 2, 2],
'period': [1, 2, 4, 4, 23],
'value': [24, 67, 89, 5, 23],
})
我如何获得索引 -> 到最后一个值的字典df.col('value').last().over(['index']).alias("last")
是最后一个值,但这需要大量额外的计算和更多的工作才能获得键值对。
over
函数将保留所有行,这可能不是您想要的。 获取index
最后value
的一种简单方法是使用unique
.
(
df
.select(['index', 'value'])
.unique(subset='index', keep="last")
)
shape: (3, 2)
┌───────┬───────┐
│ index ┆ value │
│ --- ┆ --- │
│ i64 ┆ i64 │
╞═══════╪═══════╡
│ 1 ┆ 23 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 2 ┆ 5 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 3 ┆ 89 │
└───────┴───────┘
此时,可以使用to_dicts
方法将数据帧转换为字典列表。
last_values = (
df
.select(["index", "value"])
.unique(subset="index", keep="last")
.to_dicts()
)
last_values
[{'index': 1, 'value': 23}, {'index': 2, 'value': 5}, {'index': 3, 'value': 89}]
如果希望稍后将其导入数据帧,则需要在此时停止。 例如:
pl.DataFrame(last_values)
>>> pl.DataFrame(last_values)
shape: (3, 2)
┌───────┬───────┐
│ index ┆ value │
│ --- ┆ --- │
│ i64 ┆ i64 │
╞═══════╪═══════╡
│ 1 ┆ 23 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 2 ┆ 5 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 3 ┆ 89 │
└───────┴───────┘
但是,如果要将其折叠为index
:value
对的单个字典,则可以使用字典理解。
{
next_dict["index"]: next_dict["value"]
for next_dict in last_values
}
{1: 23, 2: 5, 3: 89}
编辑:根据日期更新
假设我们有这些数据:
import polars as pl
import datetime
df = pl.DataFrame({
"index": [1, 2, 3],
"value": [10, 20, 30],
}).join(
pl.DataFrame({
'date': pl.date_range(datetime.date(2021, 1, 1), datetime.date(2023, 1, 1), "1y")
}),
how="cross"
)
df
shape: (9, 3)
┌───────┬───────┬────────────┐
│ index ┆ value ┆ date │
│ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ date │
╞═══════╪═══════╪════════════╡
│ 1 ┆ 10 ┆ 2021-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 1 ┆ 10 ┆ 2022-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 1 ┆ 10 ┆ 2023-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2 ┆ 20 ┆ 2021-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2 ┆ 20 ┆ 2022-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2 ┆ 20 ┆ 2023-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 3 ┆ 30 ┆ 2021-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 3 ┆ 30 ┆ 2022-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 3 ┆ 30 ┆ 2023-01-01 │
└───────┴───────┴────────────┘
我们有这些想要更新的值。
update_df = pl.DataFrame({
"index": [2, 3],
"value": [200, 300],
})
update_df
shape: (2, 2)
┌───────┬───────┐
│ index ┆ value │
│ --- ┆ --- │
│ i64 ┆ i64 │
╞═══════╪═══════╡
│ 2 ┆ 200 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 3 ┆ 300 │
└───────┴───────┘
注意:我故意省略了index
"1"(以显示将会发生什么)。
如果我们想 更新与每个index
关联的value
,但仅超过某个日期,我们可以使用join_asof
.
由于这是一种高级方法,我们将逐步采用。
我们将current_date
作为文本添加到update_df
中。 (所有行的值相同。
我们还需要确保两个数据帧都按"as_of"列排序(date
,而不是index
)。 (update_df
已经排序,因为它是每行上的相同日期。
我还将对join_asof
进行排序,以便我们可以更清楚地看到正在发生的事情。 (您不需要执行此步骤。
current_date = datetime.date(2022, 1, 1)
(
df
.sort(['date'])
.rename({'value': 'prev_value'})
.join_asof(
update_df.with_column(pl.lit(current_date).alias('date')),
on='date',
by=['index'],
strategy='backward'
)
.sort(['index', 'date'])
)
shape: (9, 4)
┌───────┬────────────┬────────────┬───────┐
│ index ┆ prev_value ┆ date ┆ value │
│ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ date ┆ i64 │
╞═══════╪════════════╪════════════╪═══════╡
│ 1 ┆ 10 ┆ 2021-01-01 ┆ null │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 1 ┆ 10 ┆ 2022-01-01 ┆ null │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 1 ┆ 10 ┆ 2023-01-01 ┆ null │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 2 ┆ 20 ┆ 2021-01-01 ┆ null │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 2 ┆ 20 ┆ 2022-01-01 ┆ 200 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 2 ┆ 20 ┆ 2023-01-01 ┆ 200 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 3 ┆ 30 ┆ 2021-01-01 ┆ null │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 3 ┆ 30 ┆ 2022-01-01 ┆ 300 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 3 ┆ 30 ┆ 2023-01-01 ┆ 300 │
└───────┴────────────┴────────────┴───────┘
请注意,只有日期为>= 2022-01-01 的行才具有value
的非空值。 (最后我将在 2022-01-01 展示如何做一个>。
接下来,我们将使用fill_null
value
prev_value
列填充 null 值。
current_date = datetime.date(2022, 1, 1)
(
df
.sort(['date'])
.rename({'value': 'prev_value'})
.join_asof(
update_df.with_column(pl.lit(current_date).alias('date')),
on='date',
by=['index'],
strategy='backward'
)
.sort(['index', 'date'])
.with_column(pl.col('value').fill_null(pl.col('prev_value')))
)
shape: (9, 4)
┌───────┬────────────┬────────────┬───────┐
│ index ┆ prev_value ┆ date ┆ value │
│ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ date ┆ i64 │
╞═══════╪════════════╪════════════╪═══════╡
│ 1 ┆ 10 ┆ 2021-01-01 ┆ 10 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 1 ┆ 10 ┆ 2022-01-01 ┆ 10 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 1 ┆ 10 ┆ 2023-01-01 ┆ 10 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 2 ┆ 20 ┆ 2021-01-01 ┆ 20 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 2 ┆ 20 ┆ 2022-01-01 ┆ 200 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 2 ┆ 20 ┆ 2023-01-01 ┆ 200 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 3 ┆ 30 ┆ 2021-01-01 ┆ 30 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 3 ┆ 30 ┆ 2022-01-01 ┆ 300 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 3 ┆ 30 ┆ 2023-01-01 ┆ 300 │
└───────┴────────────┴────────────┴───────┘
现在,为了清理,我们可以删除prev_value
列,然后重新排列列。
current_date = datetime.date(2022, 1, 1)
(
df
.sort(['date'])
.rename({'value': 'prev_value'})
.join_asof(
update_df.with_column(pl.lit(current_date).alias('date')),
on='date',
by=['index'],
strategy='backward'
)
.sort(['index', 'date'])
.with_column(pl.col('value').fill_null(pl.col('prev_value')))
.drop(['prev_value'])
.select([
pl.exclude('date'),
pl.col('date')
])
)
shape: (9, 3)
┌───────┬───────┬────────────┐
│ index ┆ value ┆ date │
│ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ date │
╞═══════╪═══════╪════════════╡
│ 1 ┆ 10 ┆ 2021-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 1 ┆ 10 ┆ 2022-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 1 ┆ 10 ┆ 2023-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2 ┆ 20 ┆ 2021-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2 ┆ 200 ┆ 2022-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2 ┆ 200 ┆ 2023-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 3 ┆ 30 ┆ 2021-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 3 ┆ 300 ┆ 2022-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 3 ┆ 300 ┆ 2023-01-01 │
└───────┴───────┴────────────┘
如果您只需要更新那些严格大于current_date
的行,您只需将一天添加到您的current_date
中即可。 Polars 通过offset_by
表达式使这变得容易。
(
df
.sort(['date'])
.rename({'value': 'prev_value'})
.join_asof(
update_df.with_column(pl.lit(current_date).dt.offset_by('1d').alias('date')),
on='date',
by=['index'],
strategy='backward'
)
.sort(['index', 'date'])
.with_column(pl.col('value').fill_null(pl.col('prev_value')))
.drop(['prev_value'])
.select([
pl.exclude('date'),
pl.col('date')
])
)
shape: (9, 3)
┌───────┬───────┬────────────┐
│ index ┆ value ┆ date │
│ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ date │
╞═══════╪═══════╪════════════╡
│ 1 ┆ 10 ┆ 2021-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 1 ┆ 10 ┆ 2022-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 1 ┆ 10 ┆ 2023-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2 ┆ 20 ┆ 2021-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2 ┆ 20 ┆ 2022-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2 ┆ 200 ┆ 2023-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 3 ┆ 30 ┆ 2021-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 3 ┆ 30 ┆ 2022-01-01 │
├╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 3 ┆ 300 ┆ 2023-01-01 │
└───────┴───────┴────────────┘