社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

提升效率,必看这个Python数据处理神器!

学姐带你玩AI • 5 月前 • 412 次点击  

来源:投稿  作者:sunny
编辑:学姐

unsetunsetPolars简介unsetunset

Polars 是一个速度极快的 DataFrame 库,用于处理结构化数据。核心是用 Rust 编写的,可用于 Python、R 和 NodeJS。

对于Polar而言,它有着如下特点:

  • 快速:用 Rust 从头开始编写,设计接近机器,没有外部依赖。
  • I/O:对所有常见数据存储层的一流支持:本地、云存储和数据库。
  • 直观的 API:按预期方式编写查询。Polars 将在内部确定使用其查询优化器执行的最有效方式。
  • Out of Core:流式处理 API 允许您处理结果,而无需所有数据同时在内存中。
  • 并行:通过在可用的 CPU 内核之间分配工作负载来利用计算机的强大功能,而无需任何额外的配置。
  • 矢量化查询引擎:使用 Apache Arrow(一种列式数据格式)以矢量化方式处理查询,并使用 SIMD 优化 CPU 使用率。

Polars 的目标是提供一个闪电般快速的 DataFrame 库,该库:

  • 利用计算机上所有可用的内核。
  • 优化查询以减少不必要的工作/内存分配。
  • 处理比可用 RAM 大得多的数据集。
  • 一致且可预测的 API。
  • 遵循严格的架构(在运行查询之前应知道数据类型)。

Polars 是用 Rust 编写的,这赋予了它 C/C++ 性能,并允许它完全控制查询引擎中的性能关键部分。

unsetunsetPolars安装和使用unsetunset

在正式讲述这个库之前,我们先来安装该库。

pip install polars

读取/写入文件

Polars 支持常见文件格式(e.g. csv、json、parquet)、云存储(S3、Azure Blob、BigQuery)和数据库(如 postgres、mysql)的读写。

import polars as pl
from datetime import datetime

df = pl.DataFrame(
    {
        "integer": [123],
        "date": [
            datetime(202511),
            datetime(202512),
            datetime(202513),
        ],
        "float": [4.05.06.0],
        "string": ["a""b""c"],
    }
)

print(df)

# 结果如下:
shape: (34)
┌─────────┬─────────────────────┬───────┬────────┐
│ integer ┆ date                ┆ float ┆ string │
│ ---     ┆ ---                 ┆ ---   ┆ ---    │
│ i64     ┆ datetime[μs]        ┆ f64   ┆ str    │
╞═════════╪═════════════════════╪═══════╪════════╡
│ 1       ┆ 2025-01-01 00:00:00 ┆ 4.0   ┆ a      │
│ 2       ┆ 2025-01-02 00 :00:00 ┆ 5.0   ┆ b      │
│ 3       ┆ 2025-01-03 00:00:00 ┆ 6.0   ┆ c      │
└─────────┴─────────────────────┴───────┴────────┘

在下面的示例中,我们将 DataFrame 写入一个名为 output.csv 的 csv 文件。之后,我们用 read_csv 回读它,然后 print 用结果进行检查。

df.write_csv("docs/data/output.csv")
df_csv = pl.read_csv("docs/data/output.csv")
print(df_csv)

# 结果如下:
shape: (34)
┌─────────┬────────────────────────────┬───────┬────────┐
│ integer ┆ date                       ┆ float ┆ string │
│ ---     ┆ ---                        ┆ ---   ┆ ---    │
│ i64     ┆ str                        ┆ f64   ┆ str    │
╞═════════╪════════════════════════════╪═══════╪════════╡
│ 1       ┆ 2025-01-01T00:00:00.000000 ┆ 4.0   ┆ a      │
│ 2       ┆ 2025-01-02T00:00:00.000000 ┆ 5.0   ┆ b      │
│ 3       ┆ 2025-01-03T00:00:00.000000 ┆ 6.0   ┆ c      │
└─────────┴────────────────────────────┴───────┴────────┘

表达式

Expressions 是极地的核心力量。它 expressions 提供了一个模块化结构,允许您将简单的概念组合到复杂的查询中。下面我们将介绍作为所有查询的构建块(或在 Polars 术语上下文中)的基本组件:

  • select
  • filter
  • with_columns
  • group_by

Select选择

要选择列,我们需要做两件事:

  • 定义 DataFrame 我们想要的数据来源。
  • 选择我们需要的数据。

在下面的示例中,您会看到我们选择 col('*') 。星号代表所有列。

df.select(pl.col("*"))

# 结果如下:
shape: (54)
┌─────┬──────────┬─────────────────────┬───────┐
│ a   ┆ b        ┆ c                   ┆ d     │
│ --- ┆ ---      ┆ ---                 ┆ ---   │
│ i64 ┆ f64      ┆ datetime[μs]        ┆ f64   │
╞═════╪══════════╪═════════════════════╪═══════╡
│ 0   ┆ 0.337071 ┆ 2025-12-01 00:00:00 ┆ 1.0   │
│ 1   ┆ 0.930258 ┆ 2025-12-02 00:00:00 ┆ 2.0   │
│ 2   ┆ 0.24564  ┆ 2025-12-03 00:00:00 ┆ NaN   │
│ 3   ┆ 0.673248 ┆ 2025-12-04 00:00:00 ┆ -42.0 │
│ 4   ┆ 0.460631 ┆ 2025-12-05 00:00:00 ┆ null  │
└─────┴──────────┴─────────────────────┴───────┘

您还可以指定要返回的特定列。有两种方法可以做到这一点。第一个选项是传递列名称,如下所示。

df.select(pl.col("a""b"))

# 结果如下:
shape: (52)
┌─────┬──────────┐
│ a   ┆ b        │
│ --- ┆ ---      │
│ i64 ┆ f64      │
╞═════╪══════════╡
│ 0   ┆ 0.337071 │
│ 1   ┆ 0.930258 │
│ 2   ┆ 0.24564  │
│ 3   ┆ 0.673248 │
│ 4   ┆ 0.460631 │
└─────┴──────────┘

Filter过滤器

filter 选项允许我们创建 DataFrame .我们使用与之前相同的 DataFrame 方法,并在两个指定日期之间进行过滤。

df.filter(
    pl.col("c").is_between(datetime(2025122), datetime(2025123)),
)

# 结果如下:
shape: (24)
┌─────┬──────────┬─────────────────────┬─────┐
│ a   ┆ b        ┆ c                   ┆ d   │
│ --- ┆ ---      ┆ ---                 ┆ --- │
│ i64 ┆ f64      ┆ datetime[μs]        ┆ f64 │
╞═════╪══════════╪═════════════════════╪═════╡
│ 1   ┆ 0.930258 ┆ 2025-12-02 00:00:00 ┆ 2.0 │
│ 2   ┆ 0.24564  ┆ 2025-12-03 00:00:00 ┆ NaN │
└─────┴──────────┴─────────────────────┴─────┘

您还可以 filter 创建包含多个列的更复杂的过滤器。

df.filter((pl.col("a") <= 3) & (pl.col("d").is_not_nan()))

# 结果如下:
shape: (34)
┌─────┬──────────┬─────────────────────┬───────┐
│ a   ┆ b        ┆ c                   ┆ d     │
│ --- ┆ ---      ┆ ---                 ┆ ---   │
│ i64 ┆ f64      ┆ datetime[μs]        ┆ f64   │
╞═════╪══════════╪═════════════════════╪═══════╡
│ 0   ┆ 0.337071 ┆ 2025-12-01 00:00:00 ┆ 1.0   │
│ 1   ┆ 0.930258 ┆ 2025-12-02 00:00:00 ┆ 2.0   │
│ 3   ┆ 0.673248 ┆ 2025-12-04 00:00:00 ┆ -42.0 │
└─────┴──────────┴─────────────────────┴───────┘

添加列Add columns

with_columns 允许您为分析创建新列。我们创建两个新列 eb+42 .首先,我们将列 b 中的所有值相加,并将结果存储在列 e 中。之后,我们添加 42b 值。创建一个新列 b+42 来存储这些结果。

df.with_columns(pl.col("b").sum().alias("e"), (pl.col("b") + 42).alias("b+42"))

# 结果如下:
shape: (56)
┌─────┬──────────┬─────────────────────┬───────┬──────────┬───────────┐
│ a   ┆ b        ┆ c                   ┆ d     ┆ e        ┆ b+42      │
│ --- ┆ ---      ┆ ---                 ┆ ---   ┆ ---      ┆ ---       │
│ i64 ┆ f64      ┆ datetime[μs]        ┆ f64   ┆ f64      ┆ f64       │
╞═════╪══════════╪═════════════════════╪═══════╪══════════╪═══════════╡
│ 0   ┆ 0.337071 ┆ 2025-12-01 00:00:00 ┆ 1.0   ┆ 2.646848 ┆ 42.337071 │
│ 1   ┆ 0.930258 ┆ 2025-12-02 00:00:00 ┆ 2.0   ┆ 2.646848 ┆ 42.930258 │
│ 2   ┆ 0.24564  ┆ 2025-12-03 00:00:00 ┆ NaN   ┆ 2.646848 ┆ 42.24564  │
│ 3   ┆ 0.673248 ┆ 2025-12-04 00:00:00 ┆ -42.0 ┆ 2.646848 ┆ 42.673248 │
│ 4   ┆ 0.460631 ┆ 2025-12-05 00:00:00 ┆ null  ┆ 2.646848 ┆ 42.460631 │
└─────┴──────────┴─────────────────────┴───────┴──────────┴───────────┘

分组依据Group by

我们将按功能为组创建一个新 DataFrame 功能。这个新内容 DataFrame 将包括我们想要分组的几个“组”。

df2 = pl.DataFrame(
    {
        "x": range(8),
        "y": ["A""A""A""B""B""C""X""X"],
    }
)

# 结果如下:
shape: (82)
┌─────┬─────┐
│ x   ┆ y   │
│ --- ┆ --- │
│ i64 ┆ str │
╞═════╪═════╡
│ 0   ┆ A   │
│ 1   ┆ A   │
│ 2   ┆ A   │
│ 3   ┆ B   │
│ 4   ┆ B   │
│ 5   ┆ C   │
│ 6   ┆ X   │
│ 7   ┆ X   │
└─────┴─────┘

df2.group_by("y", maintain_order=True).len()

# 结果如下:
shape: (42)
┌─────┬─────┐
│ y   ┆ len │
│ --- ┆ --- │
│ str ┆ u32 │
╞═════╪═════╡
│ A   ┆ 3   │
│ B   ┆ 2   │
│ C   ┆ 1   │
│ X   ┆ 2   │
└─────┴─────┘

df2.group_by("y", maintain_order=True).agg(
    pl.col("*").count().alias("count"),
    pl.col("*").sum().alias("sum"),
)

# 结果如下:
shape: (43)
┌─────┬───────┬─────┐
│ y   ┆ count ┆ sum │
│ --- ┆ ---   ┆ --- │
│ str ┆ u32   ┆ i64 │
╞═════╪═══════╪═════╡
│ A   ┆ 3     ┆ 3   │
│ B   ┆ 2     ┆ 7   │
│ C   ┆ 1     ┆ 5   │
│ X   ┆ 2     ┆ 13  │
└─────┴───────┴─────┘

组合Combination

下面是有关如何组合操作以创建 DataFrame 所需的操作的一些示例。

df_x = df.with_columns((pl.col("a") * pl.col("b")).alias("a * b")).select(
    pl.all().exclude(["c""d"])
)

print(df_x)

# 结果如下:
shape: (53)
┌─────┬──────────┬──────────┐
│ a   ┆ b        ┆ a * b    │
│ --- ┆ ---      ┆ ---      │
│ i64 ┆ f64      ┆ f64      │
╞═════╪══════════╪══════════╡
│ 0   ┆ 0.337071 ┆ 0.0      │
│ 1   ┆ 0.930258 ┆ 0.930258 │
│ 2   ┆ 0.24564  ┆ 0.491279 │
│ 3   ┆ 0.673248 ┆ 2.019744 │
│ 4   ┆ 0.460631 ┆ 1.842525 │
└─────┴──────────┴──────────┘

df_y = df.with_columns((pl.col("a") * pl.col("b")).alias("a * b")).select(
    pl.all().exclude("d")
)

print(df_y)

# 结果如下:
shape: (54)
┌─────┬──────────┬─────────────────────┬──────────┐
│ a   ┆ b        ┆ c                   ┆ a * b    │
│ --- ┆ ---      ┆ ---                 ┆ ---      │
│ i64 ┆ f64      ┆ datetime[μs]        ┆ f64      │
╞═════╪══════════╪═════════════════════╪══════════╡
│ 0   ┆ 0.337071 ┆ 2025-12-01 00:00:00 ┆ 0.0      │
│ 1   ┆ 0.930258 ┆ 2025-12-02 00:00:00 ┆ 0.930258 │
│ 2   ┆ 0.24564  ┆ 2025 -12-03 00:00:00 ┆ 0.491279 │
│ 3   ┆ 0.673248 ┆ 2025-12-04 00:00:00 ┆ 2.019744 │
│ 4   ┆ 0.460631 ┆ 2025-12-05 00:00:00 ┆ 1.842525 │
└─────┴──────────┴─────────────────────┴──────────┘

合并DataFrame

根据用例,有两种方法可以 DataFrame 组合 s:join 和 concat。

Join

Polars 支持所有类型的连接(例如左连接、右连接、内连接、外连接)。让我们仔细看看如何 join 将两个 DataFrames 合并为一个 DataFrame 。我们两个 DataFrames 都有一个类似“id”的列: axDataFrames 在此示例中,我们可以将 join 这些列用于 。

df = pl.DataFrame(
    {
        "a": range(8),
        "b": np.random.rand(8),
        "d": [12.0, float("nan"), float("nan"), 0-5-42None],
    }
)

df2 = pl.DataFrame(
    {
        "x": range(8),
        "y": ["A""A""A""B""B" "C""X""X"],
    }
)
joined = df.join(df2, left_on="a", right_on="x")
print(joined)

# 结果如下:
shape: (84)
┌─────┬──────────┬───────┬─────┐
│ a   ┆ b        ┆ d     ┆ y   │
│ --- ┆ ---      ┆ ---   ┆ --- │
│ i64 ┆ f64      ┆ f64   ┆ str │
╞═════╪══════════╪═══════╪═════╡
│ 0   ┆ 0.371542 ┆ 1.0   ┆ A   │
│ 1   ┆ 0.748599 ┆ 2.0   ┆ A   │
│ 2   ┆ 0.490039 ┆ NaN   ┆ A   │
│ 3   ┆ 0.292075 ┆ NaN   ┆ B   │
│ 4   ┆ 0.227413 ┆ 0.0   ┆ B   │
│ 5   ┆ 0.410372 ┆ -5.0  ┆ C   │
│ 6   ┆ 0.549948 ┆ -42.0 ┆ X   │
│ 7   ┆ 0.48205  ┆ null  ┆ X   │
└─────┴──────────┴───────┴─────┘

Concat

我们也可以 concatenate 两个 DataFrames .垂直串联将使 DataFrame 时间更长。水平串联将使 DataFrame 宽度更大。下面你可以看到我们两个 DataFrames 的水平串联的结果。

stacked = df.hstack(df2)
print(stacked)

# 结果如下:
shape: (85)
┌─────┬──────────┬───────┬─────┬─────┐
│ a   ┆ b        ┆ d     ┆ x   ┆ y   │
│ --- ┆ ---      ┆ ---   ┆ --- ┆ --- │
│ i64 ┆ f64      ┆ f64   ┆ i64 ┆ str │
╞═════╪══════════╪═══════╪═════╪═════╡
│ 0   ┆ 0.371542 ┆ 1.0   ┆ 0   ┆ A   │
│ 1   ┆ 0.748599 ┆ 2.0   ┆ 1   ┆ A   │
│ 2   ┆ 0.490039 ┆ NaN   ┆ 2   ┆ A   │
│ 3   ┆ 0.292075 ┆ NaN   ┆ 3   ┆ B   │
│ 4   ┆ 0.227413 ┆ 0.0   ┆ 4   ┆ B   │
│ 5   ┆ 0.410372 ┆ -5.0  ┆ 5   ┆ C   │
│ 6   ┆ 0.549948 ┆ -42.0 ┆ 6   ┆ X   │
│ 7   ┆ 0.48205  ┆ null  ┆ 7   ┆ X   │
└─────┴──────────┴───────┴─────┴─────┘

unset unset数据结构unsetunset

Polars 提供的核心基础数据结构是 SeriesDataFrame

Series

Series是一维数据结构。在序列中,所有元素都具有相同的数据类型。下面的代码片段显示了如何创建简单的命名 Series 对象。

import polars as pl

s = pl.Series("a", [12345])
print(s)

# 结果如下:
shape: (5,)
Series: 'a' [i64]
[
    1
    2
    3
    4
    5
]

DataFrame

A DataFrame 是一个由 支持 Series 的二维数据结构,它可以看作是 的集合(例如列表)的 Series 抽象。可以对 执行 DataFrame 的操作与 SQL 在类似查询中执行的操作非常相似。您可以 GROUP BYJOINPIVOT 定义自定义函数。

from datetime import datetime

df = pl.DataFrame(
    {
        "integer": [12345],
        "date": [
            datetime(202211),
            datetime(202212),
            datetime(202213),
            datetime(202214),
            datetime(202215),
        ],
        "float": [4.05.06.07.08.0],
    }
)

print(df)

# 结果如下:
shape: (53)
┌─────────┬─────────────────────┬───────┐
│ integer ┆ date                ┆ float │
│ ---     ┆ ---                 ┆ ---   │
│ i64     ┆ datetime[μs]        ┆ f64   │
╞═════════╪═════════════════════╪═══════╡
│ 1       ┆ 2022-01-01 00:00:00 ┆ 4.0   │
│ 2       ┆ 2022-01-02 00:00:00 ┆ 5.0   │
│ 3       ┆ 2022-01-03 00:00:00 ┆ 6.0   │
│ 4       ┆ 2022-01-04 00:00:00 ┆ 7.0   │
│ 5       ┆ 2022-01-05 00:00:00 ┆ 8.0   │
└─────────┴─────────────────────┴───────┘

查看数据

本部分重点介绍如何 DataFrame 查看 .我们将使用上一个示例中的 作为 DataFrame 起点。

head

默认情况下,该 head 函数显示 . DataFrame 您可以指定要查看的行数(例如)。 df.head(10)

print(df.head(3))

# 结果如下:
shape: (33)
┌─────────┬─────────────────────┬───────┐
│ integer ┆ date                ┆ float │
│ ---     ┆ ---                 ┆ ---   │
│ i64     ┆ datetime[μs]        ┆ f64   │
╞═════════╪═════════════════════╪═══════╡
│ 1       ┆ 2022-01-01 00:00:00 ┆ 4.0   │
│ 2       ┆ 2022-01-02 00:00:00 ┆ 5.0   │
│ 3       ┆ 2022-01-03 00:00:00 ┆ 6.0   │
└─────────┴─────────────────────┴───────┘

tail

tail 函数显示 . DataFrame 您还可以指定要查看的行数,类似于 head

print(df.tail(3))

# 结果如下:
shape: (33)
┌─────────┬─────────────────────┬───────┐
│ integer ┆ date                ┆ float │
│ ---     ┆ ---                 ┆ ---   │
│ i64     ┆ datetime[μs]        ┆ f64   │
╞═════════╪═════════════════════╪═══════╡
│ 3       ┆ 2022-01-03 00:00:00 ┆ 6.0   │
│ 4       ┆ 2022-01-04 00:00:00 ┆ 7.0   │
│ 5       ┆ 2022-01-05 00 :00:00 ┆ 8.0   │
└─────────┴─────────────────────┴───────┘

sample

如果你想得到你 DataFrame 的数据的印象,你也可以使用 sample 。从 sample 中得到 DataFrame n 个随机行。

print(df.sample(2))

# 结果如下:
shape: (23)
┌─────────┬─────────────────────┬───────┐
│ integer ┆ date                ┆ float │
│ ---     ┆ ---                 ┆ ---   │
│ i64     ┆ datetime[μs]        ┆ f64   │
╞═════════╪═════════════════════╪═══════╡
│ 5       ┆ 2022-01-05 00:00:00 ┆ 8.0   │
│ 1       ┆ 2022-01-01 00:00:00 ┆ 4.0   │

describe

Describe 返回 . DataFrame 如果可能,它将提供一些快速统计信息。

print(df.describe())

# 结果如下:
shape: (94)
┌────────────┬──────────┬─────────────────────┬──────────┐
│ statistic  ┆ integer  ┆ date                ┆ float    │
│ ---        ┆ ---      ┆ ---                 ┆ ---      │
│ str        ┆ f64      ┆ str                 ┆ f64      │
╞════════════╪══════════╪═════════════════════╪══════════╡
│ count      ┆ 5.0      ┆ 5                   ┆ 5.0      │
│ null_count ┆ 0.0      ┆ 0                   ┆ 0.0      │
│ mean       ┆ 3.0      ┆ 2022-01-03 00:00:00 ┆ 6.0      │
│ std        ┆ 1.581139 ┆ null                ┆ 1.581139 │
│ min        ┆ 1.0      ┆ 2022-01-01 00:00:00 ┆ 4.0      │
│ 25%        ┆ 2.0      ┆ 2022-01-02 00:00:00 ┆ 5.0      │
│ 50%        ┆ 3.0      ┆ 2022-01-03  00:00:00 ┆ 6.0      │
│ 75%        ┆ 4.0      ┆ 2022-01-04 00:00:00 ┆ 7.0      │
│ max        ┆ 5.0      ┆ 2022-01-05 00:00:00 ┆ 8.0      │
└────────────┴──────────┴─────────────────────┴──────────┘

unsetunset上下文unsetunset

Polars 开发了自己的领域特定语言 (DSL) 来转换数据。该语言非常易于使用,并允许复杂的查询保持人类可读性。该语言的两个核心组件是上下文和表达式,后者我们将在下一节中介绍。

顾名思义,上下文是指需要计算表达式的上下文。主要有三种情况:

  • Selection: df.select(...), df.with_columns(...)
  • Filtering: df.filter()
  • Group by / Aggregation: df.group_by(...).agg(...)

以下示例在以下 DataFrame 情况下执行:

df = pl.DataFrame(
    {
        "nrs": [12 3None5],
        "names": ["foo""ham""spam""egg"None],
        "random": np.random.rand(5),
        "groups": ["A""A""B""C""B"],
    }
)
print(df)

# 结果如下:
shape: (54)
┌──────┬───────┬──────────┬────────┐
│ nrs  ┆ names ┆ random   ┆ groups │
│ ---  ┆ ---   ┆ ---      ┆ ---    │
│ i64  ┆ str   ┆ f64      ┆ str    │
╞══════╪═══════╪══════════╪════════╡
│ 1    ┆ foo   ┆ 0.154163 ┆ A      │
│ 2    ┆ ham   ┆ 0.74005  ┆ A      │
│ 3    ┆ spam  ┆ 0.263315 ┆ B      │
│ null ┆ egg   ┆ 0.533739 ┆ C      │
│ 5    ┆ null  ┆ 0.014575 ┆ B      │
└──────┴───────┴──────────┴────────┘

Selection

选择上下文将表达式应用于列。 select 可能会生成聚合、表达式组合或文本的新列。

选择上下文中的表达式必须生成 Series 长度相同或长度为 1 的表达式。文本被视为 length-1 Series

out = df.select(
    pl.sum("nrs"),
    pl.col("names").sort(),
    pl.col("names").first().alias("first name"),
    (pl.mean("nrs") * 10).alias("10xnrs"),
)
print(out)

# 结果如下:
shape: (54)
┌─────┬───────┬────────────┬────────┐
│ nrs ┆ names ┆ first name ┆ 10xnrs │
│ --- ┆ ---   ┆ ---        ┆ ---    │
│ i64 ┆ str   ┆ str        ┆ f64    │
╞═════╪═══════╪════════════╪════════╡
│ 11  ┆ null  ┆ foo        ┆ 27.5   │
│ 11  ┆ egg   ┆ foo        ┆ 27.5   │
│ 11  ┆ foo   ┆ foo        ┆ 27.5   │
│ 11  ┆ ham   ┆ foo        ┆ 27.5   │
│ 11  ┆ spam  ┆ foo        ┆ 27.5   │
└─────┴───────┴────────────┴────────┘

从查询中可以看出,选择上下文非常强大,允许您计算彼此独立(并行)的任意表达式。

select 语句类似,该 with_columns 语句也进入选择上下文。和 select 之间的 with_columns 主要区别在于保留 with_columns 原始列并添加新列,而 select 删除原始列。

df = df.with_columns(
    pl.sum("nrs").alias("nrs_sum"),
    pl.col("random").count().alias("count"),
)
print(df)

# 结果如下:
shape: (56)
┌──────┬───────┬──────────┬────────┬─────────┬───────┐
│ nrs  ┆ names ┆ random   ┆ groups ┆ nrs_sum ┆ count │
│ ---  ┆ ---   ┆ ---      ┆ ---    ┆ ---     ┆ ---   │
│ i64  ┆ str   ┆ f64      ┆ str    ┆ i64     ┆ u32   │
╞══════╪═══════╪══════════╪════════╪═════════╪═══════╡
│ 1    ┆ foo   ┆ 0.154163 ┆ A      ┆ 11      ┆ 5     │
│ 2    ┆ ham   ┆ 0.74005  ┆ A      ┆ 11      ┆ 5     │
│ 3    ┆ spam  ┆ 0.263315 ┆ B      ┆ 11      ┆ 5     │
│ null ┆ egg   ┆ 0.533739 ┆ C      ┆ 11      ┆ 5     │
│ 5    ┆ null  ┆ 0.014575 ┆ B      ┆ 11      ┆ 5     │
└──────┴───────┴──────────┴────────┴─────────┴───────┘

Filtering

筛选上下文根据计算结果为 Boolean 数据类型的一个或多个表达式筛选 a DataFrame

out = df.filter(pl.col("nrs") > 2)
print(out)

# 结果如下:
shape: (26)
┌─────┬───────┬──────────┬────────┬─────────┬───────┐
│ nrs ┆ names ┆ random   ┆ groups ┆ nrs_sum ┆ count │
│ --- ┆ ---   ┆ ---      ┆ ---    ┆ ---     ┆ ---   │
│ i64 ┆ str   ┆ f64      ┆ str    ┆ i64     ┆ u32   │
╞═════╪═══════╪══════════╪════════╪═════════╪═══════╡
│ 3   ┆ spam  ┆ 0.263315 ┆ B      ┆ 11      ┆ 5     │
│ 5   ┆ null  ┆ 0.014575 ┆ B      ┆ 11      ┆ 5     │
└─────┴───────┴──────────┴────────┴─────────┴───────┘

Group by

group_by 上下文中,表达式适用于组,因此可以产生任何长度的结果(一个组可能有许多成员)。




    
out = df.group_by("groups").agg(
    pl.sum("nrs"),  # sum nrs by groups
    pl.col("random").count().alias("count"),  # count group members
    # sum random where name != null
    pl.col("random").filter(pl.col("names").is_not_null()).sum().name.suffix("_sum"),
    pl.col("names").reverse().alias("reversed names"),
)
print(out)

# 结果如下:
shape: (35)
┌────────┬─────┬───────┬────────────┬────────────────┐
│ groups ┆ nrs ┆ count ┆ random_sum ┆ reversed names │
│ ---    ┆ --- ┆ ---   ┆ ---        ┆ ---            │
│ str    ┆ i64 ┆ u32   ┆ f64        ┆ list[str]      │
╞════════╪═════╪═══════╪════════════╪════════════════╡
│ B      ┆ 8   ┆ 2     ┆ 0.263315   ┆ [null, "spam"] │
│ A      ┆ 3   ┆ 2     ┆ 0.894213   ┆ ["ham""foo"] │
│ C      ┆ 0   ┆ 1     ┆ 0.533739   ┆ ["egg"]        │
└────────┴─────┴───────┴────────────┴────────────────┘

从结果中可以看出,所有表达式都应用于上下文定义的 group_by 组。除了标准 group_bygroup_by_dynamicgroup_by_rolling 之外,还通过上下文进入该组。

unsetunset表达式unsetunset

Polars 有一个强大的概念,称为表达式,这是其非常快速的性能的核心。

表达式是描述如何构造一个或多个系列的操作树。由于输出是 Series,因此可以直接应用一系列表达式(类似于 pandas 中的方法链),每个表达式都会转换上一步的输出。

下面是一个表达式:

pl.col("foo").sort().head(2)

选择列“foo”,然后对列进行排序(不按相反的顺序排列),取排序输出的前两个值。

表达式的力量在于,每个表达式都会产生一个新的表达式,并且它们可以通过管道连接在一起。您可以通过将表达式传递给其中一个 Polars 执行上下文来运行表达式。

在这里,我们通过运行 df.select 以下命令来运行两个表达式:

df.select(pl.col("foo").sort().head(2), pl.col("bar").filter(pl.col("foo") == 1).sum())

所有表达式都是并行运行的,这意味着单独的 Polars 表达式是令人尴尬的并行。请注意,在表达式中可能会进行更多的并行化。

在前面中,我们概述了什么是 Expressions 以及它们如何是无价的。在本节中,我们将重点介绍 Expressions 它们本身。每个部分都概述了它们的作用,并提供了其他示例。

基本运算符

本节介绍如何将基本运算符(例如加法、减法)与表达式结合使用。我们将在以下数据帧的上下文中使用不同的主题提供各种示例。

df = pl.DataFrame(
{
"nrs": [1, 2, 3, None, 5],
"names": ["foo", "ham", "spam", "egg", None],
"random": np.random.rand(5),
"groups": ["A", "A", "B", "C", "B"],
}
)
print(df)

# 结果如下:
shape: (5, 4)
┌──────┬───────┬──────────┬────────┐
│ nrs ┆ names ┆ random ┆ groups │
│ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ str ┆ f64 ┆ str │
╞══════╪═══════╪══════════╪════════╡
│ 1 ┆ foo ┆ 0.154163 ┆ A │
│ 2 ┆ ham ┆ 0.74005 ┆ A │
│ 3 ┆ spam ┆ 0.263315 ┆ B │
│ null ┆ egg ┆ 0.533739 ┆ C │
│ 5 ┆ null ┆ 0.014575 ┆ B │
└──────┴───────┴──────────┴────────┘

Numerical

df_numerical = df.select(
    (pl.col("nrs") + 5).alias("nrs + 5"),
    (pl.col("nrs") - 5).alias("nrs - 5"),
    (pl.col("nrs") * pl.col("random")).alias("nrs * random"),
    (pl.col("nrs") / pl.col("random")).alias("nrs / random"),
)
print(df_numerical)

# 结果如下:
shape: (54)
┌─────────┬─────────┬──────────────┬──────────────┐
│ nrs + 5 ┆ nrs - 5 ┆ nrs * random ┆ nrs / random │
│ ---     ┆ ---     ┆ ---          ┆ ---          │
│ i64     ┆ i64     ┆ f64          ┆ f64          │
╞═════════╪═════════╪══════════════╪══════════════╡
│ 6       ┆ -4      ┆ 0.154163     ┆ 6.486647     │
│ 7       ┆ -3      ┆ 1.480099     ┆ 2.702521     │
│ 8       ┆ -2       ┆ 0.789945     ┆ 11.393198    │
│ null    ┆ null    ┆ null         ┆ null         │
│ 10      ┆ 0       ┆ 0.072875     ┆ 343.054056   │
└─────────┴─────────┴──────────────┴──────────────┘

Logical

df_logical = df.select(
    (pl.col("nrs") > 1).alias("nrs > 1"),
    (pl.col("random") <= 0.5).alias("random <= .5"),
    (pl.col("nrs") != 1).alias("nrs != 1"),
    (pl.col("nrs") == 1).alias("nrs == 1"),
    ((pl.col("random") <= 0.5) & (pl.col("nrs") > 1)).alias("and_expr"),  # and
    ((pl.col("random") <= 0.5) | (pl.col("nrs") > 1)).alias("or_expr"),  # or
)
print(df_logical)

# 结果如下:
shape: (56)
┌─────────┬──────────────┬──────────┬──────────┬──────────┬─────────┐
│ nrs > 1 ┆ random <= .5 ┆ nrs != 1 ┆ nrs == 1 ┆ and_expr ┆ or_expr │
│ ---     ┆ ---          ┆ ---      ┆ ---      ┆ ---      ┆ ---     │
│ bool    ┆ bool         ┆ bool     ┆ bool     ┆ bool     ┆ bool    │
╞═════════╪══════════════╪══════════╪══════════╪══════════╪═════════╡
│ false   ┆ true         ┆ false    ┆ true     ┆ false    ┆ true    │
│ true    ┆ false        ┆ true     ┆ false    ┆ false    ┆ true    │
│ true    ┆ true         ┆ true     ┆ false    ┆ true     ┆ true    │
│ null    ┆ false        ┆ null     ┆ null     ┆ false    ┆ null    │
│ true    ┆ true         ┆ true     ┆ false    ┆ true     ┆ true    │
└─────────┴──────────────┴──────────┴──────────┴──────────┴─────────┘

列选择

让我们创建一个数据集以在本节中使用:

from datetime import date, datetime

import polars as pl

df = pl.DataFrame(
    {
        "id": [942],
        "place": ["Mars""Earth""Saturn"],
        "date": pl.date_range(date(202211), date(202213), "1d", eager=True),
        "sales": [33.42142134.144.7],
        "has_people": [FalseTrueFalse],
        "logged_at": pl.datetime_range(
            datetime(2022121), datetime(2022121002), "1s", eager=True
        ),
    }
).with_row_index("index")
print(df)

# 结果如下:
shape: (37)
┌───────┬─────┬────────┬────────────┬───────────┬────────────┬─────────────────────┐
│ index ┆ id  ┆ place  ┆ date       ┆ sales     ┆ has_people ┆ logged_at           │
│ ---   ┆ --- ┆ ---    ┆ ---        ┆ ---       ┆ ---        ┆ ---                 │
│ u32   ┆ i64 ┆ str    ┆ date       ┆ f64       ┆ bool       ┆ datetime[μs]        │
╞═══════╪═════╪════════╪════════════╪═══════════╪════════════╪═════════════════════╡
│ 0     ┆ 9   ┆ Mars   ┆ 2022-01-01 ┆ 33.4      ┆ false      ┆ 2022-12-01 00:00:00 │
│ 1     ┆ 4   ┆ Earth  ┆ 2022-01-02 ┆ 2142134.1 ┆ true       ┆ 2022-12-01 00:00:01 │
│ 2     ┆ 2   ┆ Saturn ┆ 2022-01-03 ┆ 44.7      ┆ false      ┆ 2022-12-01 00:00:02 │
└───────┴─────┴────────┴────────────┴───────────┴────────────┴─────────────────────┘

函数

Polars 表达式具有大量内置函数。这些允许您创建复杂的查询,而无需用户定义的函数。这里要介绍的太多了,但我们将介绍一些更流行的用例。如果要查看所有函数,请转到编程语言的 API 参考。

df = pl.DataFrame(
    {
        "nrs": [123None5],
        "names": ["foo""ham""spam""egg""spam"],
        "random": np.random.rand(5),
        "groups": ["A""A""B""C""B"],
    }
)
print(df)

# 结果如下:
shape: (54)
┌──────┬───────┬──────────┬────────┐
│ nrs  ┆ names ┆ random   ┆ groups │
│ ---  ┆ ---   ┆ ---      ┆ ---    │
│ i64  ┆ str   ┆ f64      ┆ str    │
╞══════╪═══════╪══════════╪════════╡
│ 1    ┆ foo   ┆ 0.154163 ┆ A      │
│ 2    ┆ ham   ┆ 0.74005  ┆ A      │
│ 3    ┆ spam  ┆ 0.263315 ┆ B      │
│ null ┆ egg   ┆ 0.533739 ┆ C      │
│ 5    ┆ spam  ┆ 0.014575 ┆ B      │
└──────┴───────┴──────────┴────────┘

字符串

以下部分讨论对 String 数据执行的操作,这是 DataType 在使用 DataFrames .但是,由于字符串的内存大小不可预测,处理字符串通常效率低下,导致 CPU 访问许多随机内存位置。为了解决这个问题,Polars 使用 Arrow 作为其后端,将所有字符串存储在一个连续的内存块中。因此,字符串遍历对于 CPU 来说是缓存最优且可预测的。

可以通过具有 String 数据类型的列的 .str 属性访问 str 命名空间。在以下示例中,我们创建一个名为 animal 的列,并根据字节数和字符数计算列中每个元素的长度。如果您使用的是 ASCII 文本,那么这两个计算的结果将是相同的,建议使用 lengths ,因为它更快。

df = pl.DataFrame({"animal": ["Crab""cat and dog""rab$bit"None]})

out = df.select(
    pl.col("animal").str.len_bytes().alias("byte_count"),
    pl.col("animal").str.len_chars().alias("letter_count"),
)
print(out)

# 结果如下:
shape: (42)
┌────────────┬──────────────┐
│ byte_count ┆ letter_count │
│ ---        ┆ ---          │
│ u32        ┆ u32          │
╞════════════╪══════════════╡
│ 4          ┆ 4            │
│ 11         ┆ 11           │
│ 7          ┆ 7            │
│ null       ┆ null         │
└────────────┴──────────────┘

out = df.select(
    pl.col("animal"),
    pl.col("animal").str.contains("cat|bit").alias("regex"),
    pl.col("animal").str.contains("rab$", literal=True).alias("literal"),
    pl.col("animal").str.starts_with("rab").alias("starts_with"),
    pl.col("animal").str.ends_with("dog").alias("ends_with"),
)
print(out)

# 结果如下:
shape: (45)
┌─────────────┬───────┬─────────┬─────────────┬───────────┐
│ animal      ┆ regex ┆ literal ┆ starts_with ┆ ends_with │
│ ---         ┆ ---   ┆ ---     ┆ ---         ┆ ---       │
│ str         ┆ bool  ┆ bool    ┆ bool        ┆ bool      │
╞═════════════╪═══════╪═════════╪═════════════╪═══════════╡
│ Crab        ┆ false ┆ false   ┆ false       ┆ false     │
│ cat and dog ┆ true  ┆ false   ┆ false       ┆ true      │
│ rab$bit     ┆ true  ┆ true    ┆ true        ┆ false     │
│ null        ┆ null  ┆ null    ┆ null        ┆ null      │


df = pl.DataFrame(
    {
        "a": [
            "http://vote.com/ballon_dor?candidate=messi&ref=polars",
            "http://vote.com/ballon_dor?candidat=jorginho&ref=polars",
            "http://vote.com/ballon_dor?candidate=ronaldo&ref=polars",
        ]
    }
)
out = df.select(
    pl.col("a").str.extract(r"candidate=(\w+)", group_index=1),
)
print(out)

# 结果如下:
shape: (31)
┌─────────┐
│ a       │
│ ---     │
│ str     │
╞═════════╡
│ messi   │
│ null    │
│ ronaldo │
└─────────┘

df = pl.DataFrame({"foo": ["123 bla 45 asd""xyz 678 910t"]})
out = df.select(
    pl.col("foo").str.extract_all(r"(\d+)").alias("extracted_nrs"),
)
print(out)

# 结果如下:
shape: (21)
┌────────────────┐
│ extracted_nrs  │
│ ---            │
│ list[str]      │
╞════════════════╡
│ ["123""45"]  │
│ ["678""910"] │
└────────────────┘

df = pl.DataFrame({"id": [12], "text": ["123abc""abc456"]})
out = df.with_columns(
    pl.col("text").str.replace(r"abc\b""ABC"),
    pl.col("text").str.replace_all("a""-", literal=True).alias("text_replace_all"),
)
print(out)

# 结果如下:
shape: (23)
┌─────┬────────┬──────────────────┐
│ id  ┆ text   ┆ text_replace_all │
│ --- ┆ ---    ┆ ---              │
│ i64 ┆ str    ┆ str              │
╞═════╪════════╪══════════════════╡
│ 1   ┆ 123ABC ┆ 123-bc           │
│ 2   ┆ abc456 ┆ -bc456           │
└─────┴────────┴──────────────────┘

缺失值

DataFrame 或等效的 ) Series 中的每一列都是一个 Arrow 数组或基于 Apache Arrow 规范的 Arrow 数组的集合。缺失数据在箭头和极坐标中表示,并带有一个 null 值。此 null 缺失值适用于所有数据类型,包括数值。

Polars还允许 NotaNumber 浮点列的值。 NaN 这些 NaN 值被视为一种浮点数据,而不是缺失数据。我们将在下面单独讨论 NaN 值。

您可以使用 python None 值手动定义缺失值:

df = pl.DataFrame(
    {
        "value": [1None],
    },
)
print(df)

# 结果如下:
shape: (21)
┌───────┐
│ value │
│ ---   │
│ i64   │
╞═══════╡
│ 1     │
│ null  │
└───────┘

null_count_df = df.null_count()
print(null_count_df)

# 结果如下:
shape: (11)
┌───────┐
│ value │
│ ---   │
│ u32   │
╞═══════╡
│ 1     │
└───────┘

is_null_series = df.select(
    pl.col("value").is_null(),
)
print(is_null_series)

# 结果如下:
shape: (21)
┌───────┐
│ value │
│ ---   │
│ bool  │
╞═══════╡
│ false │
│ true  │
└───────┘

# 填充缺失值
df = pl.DataFrame(
    {
        "col1": [123],
        "col2": [1None3],
    },
)
print(df)

# 结果如下:
shape: (32)
┌──────┬──────┐
│ col1 ┆ col2 │
│ ---  ┆ ---  │
│ i64  ┆ i64  │
╞══════╪══════╡
│ 1    ┆ 1    │
│ 2    ┆ null │
│ 3     ┆ 3    │
└──────┴──────┘

# 使用指定文本填充
fill_literal_df = df.with_columns(
    pl.col("col2").fill_null(pl.lit(2)),
)
print(fill_literal_df)

# 结果如下:
shape: (32)
┌──────┬──────┐
│ col1 ┆ col2 │
│ ---  ┆ ---  │
│ i64  ┆ i64  │
╞══════╪══════╡
│ 1    ┆ 1    │
│ 2    ┆ 2    │
│ 3    ┆ 3    │
└──────┴──────┘

窗口函数

窗口函数是具有超能力的表达式。它们允许您对 select 上下文中的组执行聚合。首先,我们创建一个数据集。

import polars as pl

# then let's load some csv data with information about pokemon
df = pl.read_csv(
    "https://gist.githubusercontent.com/ritchie46/cac6b337ea52281aa23c049250a4ff03/raw/89a957ff3919d90e6ef2d34235e6bf22304f3366/pokemon.csv"
)
print(df.head())

# 结果如下:
shape: (513)
┌─────┬───────────────────────┬────────┬────────┬───┬─────────┬───────┬────────────┬───────────┐
│ #   ┆ Name                  ┆ Type 1 ┆ Type 2 ┆ … ┆ Sp. Def ┆ Speed ┆ Generation ┆ Legendary │
│ --- ┆ ---                   ┆ ---    ┆ ---    ┆   ┆ ---     ┆ ---   ┆ ---        ┆ ---       │
│ i64 ┆ str                   ┆ str    ┆ str    ┆   ┆ i64     ┆ i64   ┆ i64        ┆ bool      │
╞═════╪═══════════════════════╪════════╪════════╪═══╪═════════╪═══════╪════════════╪═══════════╡
│ 1   ┆ Bulbasaur             ┆ Grass  ┆ Poison ┆ … ┆ 65      ┆ 45    ┆ 1          ┆ false     │
│ 2   ┆ Ivysaur               ┆ Grass  ┆ Poison ┆ … ┆ 80      ┆ 60    ┆ 1          ┆ false     │
│ 3   ┆ Venusaur              ┆ Grass  ┆ Poison ┆ … ┆ 100     ┆ 80    ┆ 1          ┆ false     │
│ 3   ┆ VenusaurMega Venusaur ┆ Grass  ┆ Poison ┆ … ┆ 120     ┆ 80    ┆ 1          ┆ false     │
│ 4   ┆ Charmander            ┆ Fire   ┆ null   ┆ … ┆ 50      ┆ 65    ┆ 1          ┆ false     │
└─────┴───────────────────────┴────────┴────────┴───┴─────────┴───────┴────────────┴───────────┘

按选择中的聚合进行分组:

out = df.select(
    "Type 1",
    "Type 2",
    pl.col("Attack").mean().over("Type 1").alias("avg_attack_by_type"),
    pl.col("Defense")
    .mean()
    .over(["Type 1""Type 2"])
    .alias("avg_defense_by_type_combination"),
    pl.col("Attack").mean().alias("avg_attack"),
)
print(out)

# 结果如下:
shape: (1635)
┌─────────┬────────┬────────────────────┬─────────────────────────────────┬────────────┐
│ Type 1  ┆ Type 2 ┆ avg_attack_by_type ┆ avg_defense_by_type_combinatio… ┆ avg_attack │
│ ---     ┆ ---    ┆ ---                ┆ ---                             ┆ ---        │
│ str     ┆ str    ┆ f64                ┆ f64                             ┆ f64        │
╞═════════╪════════╪════════════════════╪═════════════════════════════════╪════════════╡
│ Grass   ┆ Poison ┆ 72.923077          ┆ 67.8                            ┆ 75.349693  │
│ Grass   ┆ Poison ┆ 72.923077          ┆ 67.8                            ┆ 75.349693  │
│ Grass   ┆ Poison ┆ 72.923077          ┆ 67.8                            ┆ 75.349693  │
│ Grass   ┆ Poison ┆ 72.923077          ┆ 67.8                            ┆ 75.349693  │
│ Fire    ┆ null   ┆ 88.642857           ┆ 58.3                            ┆ 75.349693  │
│ …       ┆ …      ┆ …                  ┆ …                               ┆ …          │
│ Fire    ┆ Flying ┆ 88.642857          ┆ 82.0                            ┆ 75.349693  │
│ Dragon  ┆ null   ┆ 94.0               ┆ 55.0                            ┆ 75.349693  │
│ Dragon  ┆ null   ┆ 94.0               ┆ 55.0                            ┆ 75.349693  │
│ Dragon  ┆ Flying ┆ 94.0               ┆ 95.0                            ┆ 75.349693  │
│ Psychic ┆ null   ┆ 53.875             ┆ 51.428571                       ┆ 75.349693  │
└─────────┴────────┴────────────────────┴─────────────────────────────────┴────────────┘

每个组的操作数:

filtered = df.filter(pl.col("Type 2") == "Psychic").select(
    "Name",
    "Type 1",
    "Speed",
)
print(filtered)

# 结果如下:
shape: (73)
┌─────────────────────┬────────┬───────┐
│ Name                ┆ Type 1 ┆ Speed │
│ ---                 ┆ ---    ┆ ---   │
│ str                 ┆ str    ┆ i64   │
╞═════════════════════╪════════╪═══════╡
│ Slowpoke            ┆ Water  ┆ 15    │
│ Slowbro             ┆ Water  ┆ 30    │
│ SlowbroMega Slowbro ┆ Water  ┆ 30    │
│ Exeggcute           ┆ Grass  ┆ 40    │
│ Exeggutor           ┆ Grass  ┆ 55    │
│ Starmie             ┆ Water  ┆ 115   │
│ Jynx                ┆ Ice    ┆ 95    │
└─────────────────────┴────────┴───────┘

out = filtered.with_columns(
    pl.col(["Name""Speed"]).sort_by("Speed", descending=True).over("Type 1"),
)
print(out)

# 结果如下:
shape: (73)
┌─────────────────────┬────────┬───────┐
│ Name                ┆ Type 1 ┆ Speed │
│ ---                 ┆ ---    ┆ ---   │
│ str                 ┆ str    ┆ i64   │
╞═════════════════════╪════════╪═══════╡
│ Starmie             ┆ Water  ┆ 115   │
│ Slowbro             ┆ Water  ┆ 30    │
│ SlowbroMega Slowbro ┆ Water  ┆ 30    │
│ Exeggutor           ┆ Grass  ┆ 55    │
│ Exeggcute           ┆ Grass  ┆ 40    │
│ Slowpoke            ┆ Water  ┆ 15    │
│ Jynx                ┆ Ice    ┆ 95    │
└─────────────────────┴────────┴───────┘

unsetunset列表和数组unset unset

Polars 对 List 列具有一流的支持:即每行都是不同长度的同构元素列表的列。Polars 也有一个 Array 数据类型,类似于 NumPy 的 ndarray 对象,其中行的长度相同。

注意:这与 Python list 的对象不同,Python 的对象元素可以是任何类型。Polars 可以将这些存储在列中,但作为一种通用 Object 数据类型,它不具有我们将要讨论的特殊列表操作功能。

强大的 List 操纵

假设我们有来自全州不同气象站的以下数据。当气象站无法获得结果时,将记录错误代码,而不是当时的实际温度。

weather = pl.DataFrame(
    {
        "station": ["Station " + str(x) for x in range(16)],
        "temperatures": [
            "20 5 5 E1 7 13 19 9 6 20",
            "18 8 16 11 23 E2 8 E2 E2 E2 90 70 40",
            "19 24 E9 16 6 12 10 22",
            "E2 E0 15 7 8 10 E1 24 17 13 6",
            "14 8 E0 16 22 24 E1",
        ],
    }
)
print(weather)

# 结果如下:
shape: (52)
┌───────────┬─────────────────────────────────┐
│ station   ┆ temperatures                    │
│ ---       ┆ ---                             │
│ str       ┆ str                             │
╞═══════════╪═════════════════════════════════╡
│ Station 1 ┆ 20 5 5 E1 7 13 19 9 6 20        │
│ Station 2 ┆ 18 8 16 11 23 E2 8 E2 E2 E2 90… │
│ Station 3 ┆ 19 24 E9 16 6 12 10 22          │
│ Station 4 ┆ E2 E0 15 7 8 10 E1 24 17 13 6   │
│ Station 5 ┆ 14 8 E0 16 22 24 E1             │
└───────────┴─────────────────────────────────┘

创建 List

对于上面创建的 weather DataFrame ,我们很可能需要对每个站点捕获的温度进行一些分析。为了实现这一点,我们首先需要能够获得单独的温度测量值。这是通过以下方式完成的:

out = weather.with_columns(pl.col("temperatures").str.split(" "))
print(out)

# 结果如下:
shape: (52)
┌───────────┬──────────────────────┐
│ station   ┆ temperatures         │
│ ---       ┆ ---                  │
│ str       ┆ list[str]            │
╞═══════════╪══════════════════════╡
│ Station 1 ┆ ["20""5", … "20"]  │
│ Station 2 ┆ ["18""8", … "40"]  │
│ Station 3 ┆ ["19""24", … "22"] │
│ Station 4 ┆ ["E2""E0", … "6"]  │
│ Station 5 ┆ ["14""8", … "E1"]  │
└───────────┴──────────────────────┘

操作 List

Polars 在色谱柱上 List 提供了多种标准操作。如果我们想要前三个测量,我们可以做一个 head(3) .最后三个可以通过 tail(3) 获得,也可以 slice 通过(支持负索引)获得。我们还可以通过 lengths 来识别观测值的数量。让我们看看它们在行动中:

out = weather.with_columns(pl.col("temperatures").str.split(" ")).with_columns(
    pl.col("temperatures").list.head(3).alias("top3"),
    pl.col("temperatures").list.slice(-33).alias("bottom_3"),
    pl.col("temperatures").list.len().alias("obs"),
)
print(out)

# 结果如下:
shape: (55)
┌───────────┬──────────────────────┬────────────────────┬────────────────────┬─────┐
│ station   ┆ temperatures         ┆ top3               ┆ bottom_3           ┆ obs │
│ ---       ┆ ---                  ┆ ---                ┆ ---                ┆ --- │
│ str       ┆ list[str]            ┆ list[str]          ┆ list[str]          ┆ u32 │
╞═══════════╪══════════════════════╪════════════════════╪════════════════════╪═════╡
│ Station 1 ┆ ["20""5", … "20"]  ┆ ["20""5""5"]   ┆ ["9""6""20"]   ┆ 10  │
│ Station 2 ┆ ["18""8", … "40"]  ┆ ["18""8""16"]  ┆ ["90""70""40"] ┆ 13  │
│ Station 3 ┆ ["19""24", … "22"] ┆ ["19""24""E9"] ┆ ["12""10""22"] ┆ 8   │
│ Station 4 ┆ ["E2""E0", … "6"]  ┆ ["E2""E0""15"] ┆ ["17""13""6"]  ┆ 11  │
│ Station 5 ┆ ["14""8", … "E1"]  ┆ ["14""8""E0"]  ┆ ["22""24""E1"] ┆ 7   │
└───────────┴──────────────────────┴────────────────────┴────────────────────┴─────┘

按行计算

我们可以使用 list.evallist().eval in Rust) 表达式对列表的元素应用任何 Polars 操作!这些表达式完全在 Polars 的查询引擎上运行,并且可以并行运行,因此会得到很好的优化。假设我们有另一组三天的天气数据,适用于不同的台站:

weather_by_day = pl.DataFrame(
    {
        "station": ["Station " + str(x) for x in range(111)],
        "day_1": [1711822921208817],
        "day_2": [151110871418211513],
        "day_3": [1615242482319231610],
    }
)
print(weather_by_day)

# 结果如下:
shape: (104)
┌────────────┬───────┬───────┬───────┐
│ station    ┆ day_1 ┆ day_2 ┆ day_3 │
│ ---        ┆ ---   ┆ ---   ┆ ---   │
│ str        ┆ i64   ┆ i64   ┆ i64   │
╞════════════╪═══════╪═══════╪═══════╡
│ Station 1  ┆ 17    ┆ 15    ┆ 16    │
│ Station 2  ┆ 11    ┆ 11    ┆ 15    │
│ Station 3  ┆ 8     ┆ 10    ┆ 24    │
│ Station 4  ┆ 22    ┆ 8     ┆ 24    │
│ Station 5  ┆ 9     ┆ 7     ┆ 8     │
│ Station 6  ┆ 21    ┆ 14    ┆ 23    │
│ Station 7  ┆ 20    ┆ 18    ┆ 19    │
│ Station 8  ┆ 8     ┆ 21    ┆ 23    │
│ Station 9  ┆ 8     ┆ 15    ┆ 16    │
│ Station 10 ┆ 17    ┆ 13    ┆ 10    │
└────────────┴───────┴───────┴───────┘


推荐课程

《Python ·  AI&数据科学入门》

点这里👇关注我,回复“python”了解课程

往期精彩阅读

👉 kaggle比赛baseline合集

👉经典论文推荐合集

👉人工智能必读书籍

👉本专科硕博学习经验

10个赞学姐的午饭就可以有个鸡腿🍗

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/172376
 
412 次点击