持续时间字符串转换出现问题

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

我有一些持续时间类型数据(单圈时间)为

pl.String
,无法使用
strptime
进行转换,而常规日期时间按预期工作。

分钟(在 :) 之前和秒(在 . 之前)始终填充为两位数,毫秒始终 3 位数字。

单圈时间总是< 2 min.

df = pl.DataFrame({
    "lap_time": ["01:14.007", "00:53.040", "01:00.123"]
})

df = df.with_columns(
    # pl.col('release_date').str.to_date("%B %d, %Y"), # works
    pl.col('lap_time').str.to_time("%M:%S.%3f").cast(pl.Duration), # fails
)

因此,我使用了

https://docs.rs/chrono/latest/chrono/format/strftime/index.html
中的 chrono 格式说明符定义,这些定义按照
polars
strptime

文档使用

第二次转换(对于

lap_time
)总是失败,无论我是否使用
.%f
.%3f
%.3f
。显然,
strptime
不允许直接创建
pl.Duration
,所以我尝试使用
pl.Time
,但失败并出现错误:

ComputeError: strict conversion to dates failed, maybe set strict=False

但是设置

strict=False
会产生整个系列的所有
null
值。

我是否遗漏了某些东西或

chrono
python-polars
部分的某些奇怪行为?

python parsing duration python-polars rust-chrono
3个回答
3
投票

一般情况

如果您的持续时间可能超过 24 小时,您可以使用 regex 模式从字符串中提取数据(分钟、秒等)。例如:

df = pl.DataFrame({
    "time": ["+01:14.007", "100:20.000", "-05:00.000"]
})

df.with_columns(
    pl.col("time").str.extract_all(r"([+-]?\d+)")
    #                                /
    #                 you will get array of length 3
    #                 ["min", "sec", "ms"]
).with_columns(
    pl.duration(
        minutes=pl.col("time").list.get(0),
        seconds=pl.col("time").list.get(1),
        milliseconds=pl.col("time").list.get(2)
    ).alias("time")
)
┌──────────────┐
│ time         │
│ ---          │
│ duration[ns] │
╞══════════════╡
│ 1m 14s 7ms   │
│ 1h 40m 20s   │
│ -5m          │
└──────────────┘

关于
pl.Time

要将数据转换为

pl.Time
,您还需要指定时间。当您在时间中添加
00
小时时,代码将起作用:

df = pl.DataFrame({"str_time": ["01:14.007", "01:18.880"]})

df.with_columns(
    duration = (pl.lit("00:") + pl.col("str_time"))
        .str.to_time("%T%.3f")
        .cast(pl.Duration)
)
┌───────────┬──────────────┐
│ str_time  ┆ duration     │
│ ---       ┆ ---          │
│ str       ┆ duration[μs] │
╞═══════════╪══════════════╡
│ 01:14.007 ┆ 1m 14s 7ms   │
│ 01:18.880 ┆ 1m 18s 880ms │
└───────────┴──────────────┘

2
投票

创建您自己的解析器 -

strptime
仅适用于日期时间戳,不适用于时间增量。接受的答案是不好的做法,因为它对于合理的输入(例如 80 分钟的持续时间或负持续时间)会失败。

您可以使用

pl.Series.str.extract()
制作自己的正则表达式解析器,并在将它们传递到
Duration
构造函数之前提取所需的值。

据我所知,Rust 中没有“持续时间标记”解析器。如果有人正在读这篇文章,也许放一个板条箱是个好主意。语法可能与

strptime
类似,但处理以下情况:负持续时间、最重要的“数字”/子单位不换行,在这种情况下,如果它是“分钟持续时间标记”,您将在 60 处换行秒,而不是分钟。特别是确保 61 仍然是 61。


0
投票

代码改编自glebcom的答案

df = df.with_columns(
    # pl.col('release_date').str.to_date("%B %d, %Y"), # works
    pl.duration(
        minutes=pl.col("lap_time").str.slice(0,2),
        seconds=pl.col("lap_time").str.slice(3,2),
        milliseconds=pl.col("lap_time").str.slice(6,3)
    ).alias('lap_time'),
)

此答案作为 edit 发布到问题 Trouble with strptime() conversion ofuration time string 由 OP Dorian 根据 CC BY-SA 4.0 发布。

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