类型强制转换

强制类型转换会将列的底层数据类型转换为新的数据类型。通过cast函数实现,该函数包含一个参数strict, 用于确定Polars在遇到无法从源数据类型转换为目标数据类型的值时的行为。默认为strict=True, 这意味着 Polars 将抛出一个错误,通知用户转换失败,同时提供无法转换的值的详细信息。如果 strict=False,则任何无法转换为目标数据类型的值都将被静默转换为null。

TIP
  • 简单总结就是:默认情况下进行不同类型间的强制转换,如果存在无法强转的情况就会直接报错(例如字符串转数字时,字符串中包含字母)。但是Polars提供了一个strict参数,它的本质作用就是遇到无法强转的情况时,是否直接进行报错,如果不报错,那么就会将那些不能强转的值置为null。

  • 另外还需要注意一个点:在向下转换时,特别需要注意是否会存在溢出的情况!

  • 在向下转换,在一定程度上可以减少内存占用。

基本示例

数据准备

Python
1df = pl.DataFrame(
2    {
3        "integers": [1, 2, 3],
4        "big_integers": [10000002, 2, 30000003],
5        "floats": [4.0, 5.8, -6.3],
6    }
7)
8
9print(df)
1shape: (3, 3)
2┌──────────┬──────────────┬────────┐
3│ integers ┆ big_integers ┆ floats │
4│ ---      ┆ ---          ┆ ---    │
5│ i64      ┆ i64          ┆ f64    │
6╞══════════╪══════════════╪════════╡
7│ 1        ┆ 10000002     ┆ 4.0    │
8│ 2        ┆ 2            ┆ 5.8    │
9│ 3        ┆ 30000003     ┆ -6.3   │
10└──────────┴──────────────┴────────┘

类型转换

下面代码将i64类型的数据转换为f32, 将f64转换为i32, 需要注意浮点数转换为整数时丢失精度:

Python
1result = df.select(
2    pl.col("integers").cast(pl.Float32).alias("integers_as_floats"),
3    pl.col("floats").cast(pl.Int32).alias("floats_as_integers"),
4)
5print(result)
1shape: (3, 2)
2┌────────────────────┬────────────────────┐
3│ integers_as_floats ┆ floats_as_integers │
4│ ---                ┆ ---                │
5│ f32                ┆ i32                │
6╞════════════════════╪════════════════════╡
7│ 1.0                ┆ 4                  │
8│ 2.0                ┆ 5                  │
9│ 3.0                ┆ -6                 │
10└────────────────────┴────────────────────┘

向下转换

可以通过更改与数值数据类型关联的精度来减少列的内存占用。以下代码演示了如何使用从Int64Int16和从Float64Float32的转换来降低内存使用量:

Python
1print(f"Before downcasting: {df.estimated_size()} bytes")
2result = df.with_columns(
3    pl.col("integers").cast(pl.Int16),
4    pl.col("floats").cast(pl.Float32),
5)
6print(f"After downcasting: {result.estimated_size()} bytes")
1Before downcasting: 72 bytes
2After downcasting: 42 bytes

字符串与数字互转

表示数字的字符串可以通过强制类型转换转换为相应的数据类型。反向转换也是可行的:

Python
1df = pl.DataFrame(
2    {
3        "integers_as_strings": ["1", "2", "3"],
4        "floats_as_strings": ["4.0", "5.8", "-6.3"],
5        "floats": [4.0, 5.8, -6.3],
6    }
7)
8
9result = df.select(
10    pl.col("integers_as_strings").cast(pl.Int32),
11    pl.col("floats_as_strings").cast(pl.Float64),
12    pl.col("floats").cast(pl.String),
13)
14print(result)
1shape: (3, 3)
2┌─────────────────────┬───────────────────┬────────┐
3│ integers_as_strings ┆ floats_as_strings ┆ floats │
4│ ---                 ┆ ---               ┆ ---    │
5│ i32                 ┆ f64               ┆ str    │
6╞═════════════════════╪═══════════════════╪════════╡
7│ 1                   ┆ 4.0               ┆ 4.0    │
8│ 2                   ┆ 5.8               ┆ 5.8    │
9│ 3                   ┆ -6.3              ┆ -6.3   │
10└─────────────────────┴───────────────────┴────────┘

如果列包含非数字值或者格式错误, Polars会抛出错误并给出详细的错误信息, 可以设置strict=False绕过错误获取null值。

Python
1df = pl.DataFrame(
2    {
3        "integers_as_strings": ["1", "2i", "3"],
4        "floats_as_strings": ["4.0", "5.8f", "-6.3"],
5        "floats": [4.0, 5.8, -6.3],
6    }
7)
8
9result = df.select(
10    pl.col("integers_as_strings").cast(pl.Int32, strict=False),
11    pl.col("floats_as_strings").cast(pl.Float64, strict=False),
12    pl.col("floats").cast(pl.String),
13)
14print(result)
1shape: (3, 3)
2┌─────────────────────┬───────────────────┬────────┐
3│ integers_as_strings ┆ floats_as_strings ┆ floats │
4│ ---                 ┆ ---               ┆ ---    │
5│ i32                 ┆ f64               ┆ str    │
6╞═════════════════════╪═══════════════════╪════════╡
7│ 1                   ┆ 4.0               ┆ 4.0    │
8│ null                ┆ null              ┆ 5.8    │
9│ 3                   ┆ -6.3              ┆ -6.3   │
10└─────────────────────┴───────────────────┴────────┘

布尔类型转换

  • 数值转换为布尔类型时, 0转换为false, 非0转换为true

  • 布尔转换为数值类型时, true转换为1, false转换为0

Python
1df = pl.DataFrame(
2    {
3        "integers": [-1, 0, 2, 3, 4],
4        "floats": [0.0, 1.0, 2.0, 3.0, 4.0],
5        "bools": [True, False, True, False, True],
6    }
7)
8
9result = df.select(
10    pl.col("integers").cast(pl.Boolean),
11    pl.col("floats").cast(pl.Boolean),
12    pl.col("bools").cast(pl.Int8),
13)
14print(result)
1shape: (5, 3)
2┌──────────┬────────┬───────┐
3│ integers ┆ floats ┆ bools │
4│ ---      ┆ ---    ┆ ---   │
5│ bool     ┆ bool   ┆ i8    │
6╞══════════╪════════╪═══════╡
7│ true     ┆ false  ┆ 1     │
8│ false    ┆ true   ┆ 0     │
9│ true     ┆ true   ┆ 1     │
10│ true     ┆ true   ┆ 0     │
11│ true     ┆ true   ┆ 1     │
12└──────────┴────────┴───────┘

日期类型处理

所有日期数据类型的数据在内部都表示为: 从参考时间(纪元)到现在所经过的时间单位数, Unix纪元: 1970 年 1 月 1 日 00:00:00 UTC

  • Date: 存储自纪元以来的天数
  • Datetime: 存储自纪元以来的毫秒数(ms)
  • Time: 时间单位是纳秒(ns)
Python
1from datetime import date, datetime, time
2
3print(date(1970,1,1))
4print(datetime(1970,1,1,0,0,0))
5print(time(0,0,1))
11970-01-01
21970-01-01 00:00:00
300:00:01

Polars允许在数字类型和日期数据类型之间进行转换:

日期转为数字

Python
1from datetime import date, datetime, time
2
3df = pl.DataFrame(
4    {
5        "date": [
6            date(1970, 1, 1),  # epoch
7            date(1970, 1, 10),  # 9 days later
8        ],
9        "datetime": [
10            datetime(1970, 1, 1, 0, 0, 0),  # epoch
11            datetime(1970, 1, 1, 0, 1, 0),  # 1 minute later
12        ],
13        "time": [
14            time(0, 0, 0),  # reference time
15            time(0, 0, 1),  # 1 second later
16        ],
17    }
18)
19
20result = df.select(
21    pl.col("date").cast(pl.Int64).alias("days_since_epoch"),
22    pl.col("datetime").cast(pl.Int64).alias("us_since_epoch"),
23    pl.col("time").cast(pl.Int64).alias("ns_since_midnight"),
24)
25print(result)
1shape: (2, 3)
2┌──────────────────┬────────────────┬───────────────────┐
3│ days_since_epoch ┆ us_since_epoch ┆ ns_since_midnight │
4│ ---              ┆ ---            ┆ ---               │
5│ i64              ┆ i64            ┆ i64               │
6╞══════════════════╪════════════════╪═══════════════════╡
7│ 0                ┆ 0              ┆ 0                 │
8│ 9                ┆ 60000000       ┆ 1000000000        │
9└──────────────────┴────────────────┴───────────────────┘

日期类型和字符串互转

  • 日期类型转换为字符串: .dt.to_string()

  • 字符串转换为日期类型: .str.to_datetime()

Python
1from datetime import date
2
3df = pl.DataFrame(
4    {
5        "date": [date(2022, 1, 1), date(2022, 1, 2)],
6        "string": ["2023-01-01", "2023-01-02"],
7    }
8)
9
10result = df.select(
11    pl.col("date").dt.to_string("%Y-%m-%d"),
12    pl.col("string").str.to_datetime("%Y-%m-%d"),
13)
14print(result)
1shape: (2, 2)
2┌────────────┬─────────────────────┐
3│ date       ┆ string              │
4│ ---        ┆ ---                 │
5│ str        ┆ datetime[μs]        │
6╞════════════╪═════════════════════╡
7│ 2022-01-01 ┆ 2023-01-01 00:00:00 │
8│ 2022-01-02 ┆ 2023-01-02 00:00:00 │
9└────────────┴─────────────────────┘
TIP

str.to_datetime具有支持时区功能的其他选项, 更多信息可以参考官方API文档