根据日期时间进行插值

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

在 pandas 中,我可以根据这样的日期时间进行插值:

df1 = pd.DataFrame(
    {
        "ts": [
            datetime(2020, 1, 1),
            datetime(2020, 1, 3, 0, 0, 12),
            datetime(2020, 1, 3, 0, 1, 35),
            datetime(2020, 1, 4),
        ],
        "value": [1, np.nan, np.nan, 3],
    }
)
df1.set_index('ts').interpolate(method='index')

输出:

                        value
ts
2020-01-01 00:00:00  1.000000
2020-01-03 00:00:12  2.333426
2020-01-03 00:01:35  2.334066
2020-01-04 00:00:00  3.000000

polars中有类似的方法吗?说,从

开始
df1 = pl.DataFrame(
    {
        "ts": [
            datetime(2020, 1, 1),
            datetime(2020, 1, 3, 0, 0, 12),
            datetime(2020, 1, 3, 0, 1, 35),
            datetime(2020, 1, 4),
        ],
        "value": [1, None, None, 3],
    }
)
shape: (4, 2)
┌─────────────────────┬───────┐
│ ts                  ┆ value │
│ ---                 ┆ ---   │
│ datetime[μs]        ┆ i64   │
╞═════════════════════╪═══════╡
│ 2020-01-01 00:00:00 ┆ 1     │
│ 2020-01-03 00:00:12 ┆ null  │
│ 2020-01-03 00:01:35 ┆ null  │
│ 2020-01-04 00:00:00 ┆ 3     │
└─────────────────────┴───────┘

编辑:我更新了示例,使其更加“不规则”,因此

upsample
不能用作解决方案,并明确我们需要更通用的东西

python interpolation python-polars
3个回答
1
投票

看来 pandas 在进行插值之前首先进行上采样。因此,我们可以在 Polars 中执行相同的操作,方法是上采样,然后插值,然后将其自身连接回来,这样我们只保留您最初拥有的日期时间:

(df1
        .sort('ts')
        .with_columns(pl.col('value').cast(pl.Float64))
        .upsample(time_column='ts', every='1d')
        .interpolate()
        .join(
            df1.select('ts'), on='ts'
            )
        )

您还需要注意列数据类型,它应该是浮点型,否则您会得到整数插值。

ts(日期时间[μs]) 值(f64)
2020-01-01 00:00:00 1.0
2020-01-03 00:00:00 2.333333
2020-01-04 00:00:00 3.0

1
投票

这是一个使用

scipy
的解决方案。对于这些值,转换为
numpy
应该是零拷贝,所以我认为它应该是高效的

from scipy import interpolate
df1 = pl.DataFrame(
    {
        "ts": [
            datetime(2020, 1, 1),
            datetime(2020, 1, 3, 0, 0, 12),
            datetime(2020, 1, 3, 0, 1, 35),
            datetime(2020, 1, 4),
        ],
        "value": [1, None, None, 3],
    }
)
x = (
    df1.filter(pl.col("value").is_not_null())["ts"]
    .dt.timestamp()
    .to_numpy(zero_copy_only=True)
)
y = df1.filter(pl.col("value").is_not_null())[
    "value"
].to_numpy(zero_copy_only=True)
xnew = (
    df1["ts"].dt.timestamp().to_numpy(zero_copy_only=True)
)
ynew = interpolate.interp1d(x, y)(xnew)
df1 = df1.with_columns(pl.Series(ynew).alias("value"))

结果是

In [6]: df1
Out[6]:
shape: (4, 2)
┌─────────────────────┬──────────┐
│ ts                  ┆ value    │
│ ---                 ┆ ---      │
│ datetime[μs]        ┆ f64      │
╞═════════════════════╪══════════╡
│ 2020-01-01 00:00:00 ┆ 1.0      │
│ 2020-01-03 00:00:12 ┆ 2.333426 │
│ 2020-01-03 00:01:35 ┆ 2.334066 │
│ 2020-01-04 00:00:00 ┆ 3.0      │
└─────────────────────┴──────────┘

1
投票

更新:

Expr.interpolate_by
已添加到 Polars
0.20.28

df1.with_columns(pl.col("value").interpolate_by("ts"))
shape: (4, 2)
┌─────────────────────┬──────────┐
│ ts                  ┆ value    │
│ ---                 ┆ ---      │
│ datetime[μs]        ┆ f64      │
╞═════════════════════╪══════════╡
│ 2020-01-01 00:00:00 ┆ 1.0      │
│ 2020-01-03 00:00:12 ┆ 2.333426 │
│ 2020-01-03 00:01:35 ┆ 2.334066 │
│ 2020-01-04 00:00:00 ┆ 3.0      │
└─────────────────────┴──────────┘

不确定这有多有用,但看起来 pandas 调用

np.interp()
来做到这一点:

invalid = pl.when(pl.col('value').is_null()).then(pl.col('ts')).alias('invalid')
valid   = pl.when(pl.col('value').is_not_null()).then(pl.col('ts')).alias('valid')
values  = pl.when(pl.col('value').is_not_null()).then(pl.col('value')).alias('values')

df.select(
   pl.struct(invalid, valid, values)
     .map(lambda args: 
         np.interp(
            args.struct['invalid'].drop_nulls().dt.timestamp().to_numpy(zero_copy_only=True), 
            args.struct['valid'].drop_nulls().dt.timestamp().to_numpy(zero_copy_only=True), 
            args.struct['values'].drop_nulls().to_numpy(zero_copy_only=True)
         )
     ) 
     .flatten()
)
shape: (2, 1)
┌──────────┐
│ invalid  │
│ ---      │
│ f64      │
╞══════════╡
│ 2.333426 │
│ 2.334066 │
└──────────┘

尽管似乎确实还有很多其他事情正在发生。

© www.soinside.com 2019 - 2024. All rights reserved.