这一节展示如何在DataFrame columns
上做一些基本操作, 比如基本的算数运算, 执行比较和其他通用操作
1import polars as pl
2import numpy as np
3
4np.random.seed(42) # For reproducibility.
5
6df = pl.DataFrame(
7 {
8 "nrs": [1, 2, 3, None, 5],
9 "names": ["foo", "ham", "spam", "egg", "spam"],
10 "random": np.random.rand(5),
11 "groups": ["A", "A", "B", "A", "B"],
12 }
13)
14print(df)
1shape: (5, 4)
2┌──────┬───────┬──────────┬────────┐
3│ nrs ┆ names ┆ random ┆ groups │
4│ --- ┆ --- ┆ --- ┆ --- │
5│ i64 ┆ str ┆ f64 ┆ str │
6╞══════╪═══════╪══════════╪════════╡
7│ 1 ┆ foo ┆ 0.37454 ┆ A │
8│ 2 ┆ ham ┆ 0.950714 ┆ A │
9│ 3 ┆ spam ┆ 0.731994 ┆ B │
10│ null ┆ egg ┆ 0.598658 ┆ A │
11│ 5 ┆ spam ┆ 0.156019 ┆ B │
12└──────┴───────┴──────────┴────────┘
pl.col("nrs")+5
: 会将nrs这一列中的每一个值都+5pl.col("nrs)/pl.col("random")
: 会将nrs这一列中的每一个值都除以random列中的值1result = df.select(
2 (pl.col("nrs") + 5).alias("nrs + 5"),
3 (pl.col("nrs") - 5).alias("nrs - 5"),
4 (pl.col("nrs") * pl.col("random")).alias("nrs * random"),
5 (pl.col("nrs") / pl.col("random")).alias("nrs / random"),
6 (pl.col("nrs") ** 2).alias("nrs ** 2"),
7 (pl.col("nrs") % 3).alias("nrs % 3"),
8)
9
10print(result)
1shape: (5, 6)
2┌─────────┬─────────┬──────────────┬──────────────┬──────────┬─────────┐
3│ nrs + 5 ┆ nrs - 5 ┆ nrs * random ┆ nrs / random ┆ nrs ** 2 ┆ nrs % 3 │
4│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
5│ i64 ┆ i64 ┆ f64 ┆ f64 ┆ i64 ┆ i64 │
6╞═════════╪═════════╪══════════════╪══════════════╪══════════╪═════════╡
7│ 6 ┆ -4 ┆ 0.37454 ┆ 2.669941 ┆ 1 ┆ 1 │
8│ 7 ┆ -3 ┆ 1.901429 ┆ 2.103681 ┆ 4 ┆ 2 │
9│ 8 ┆ -2 ┆ 2.195982 ┆ 4.098395 ┆ 9 ┆ 0 │
10│ null ┆ null ┆ null ┆ null ┆ null ┆ null │
11│ 10 ┆ 0 ┆ 0.780093 ┆ 32.047453 ┆ 25 ┆ 2 │
12└─────────┴─────────┴──────────────┴──────────────┴──────────┴─────────┘
上面结果中高亮的那一行显示, 当算术运算中将 null
作为其操作数之一的时候, 结果为 null
.add()
.sub()
.mul()
.truediv()
.pow()
.mod()
1# Python only:
2result_named_operators = df.select(
3 (pl.col("nrs").add(5)).alias("nrs + 5"),
4 (pl.col("nrs").sub(5)).alias("nrs - 5"),
5 (pl.col("nrs").mul(pl.col("random"))).alias("nrs * random"),
6 (pl.col("nrs").truediv(pl.col("random"))).alias("nrs / random"),
7 (pl.col("nrs").pow(2)).alias("nrs ** 2"),
8 (pl.col("nrs").mod(3)).alias("nrs % 3"),
9)
10
11print(result.equals(result_named_operators))
与算数运算一样, Polars支持运算符重载或命名函数来进行比较
使用运算符
1result = df.select(
2 (pl.col("nrs") > 1).alias("nrs > 1"),
3 (pl.col("nrs") >= 3).alias("nrs >= 3"),
4 (pl.col("random") < 0.2).alias("random < 0.2"),
5 (pl.col("random") <= 0.5).alias("random <= 0.5"),
6 (pl.col("nrs") != 1).alias("nrs != 1"),
7 (pl.col("nrs") == 1).alias("nrs == 1"),
8)
9print(result)
1shape: (5, 6)
2┌─────────┬──────────┬──────────────┬───────────────┬──────────┬──────────┐
3│ nrs > 1 ┆ nrs >= 3 ┆ random < 0.2 ┆ random <= 0.5 ┆ nrs != 1 ┆ nrs == 1 │
4│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
5│ bool ┆ bool ┆ bool ┆ bool ┆ bool ┆ bool │
6╞═════════╪══════════╪══════════════╪═══════════════╪══════════╪══════════╡
7│ false ┆ false ┆ false ┆ true ┆ false ┆ true │
8│ true ┆ false ┆ false ┆ false ┆ true ┆ false │
9│ true ┆ true ┆ false ┆ false ┆ true ┆ false │
10│ null ┆ null ┆ false ┆ false ┆ null ┆ null │
11│ true ┆ true ┆ true ┆ true ┆ true ┆ false │
12└─────────┴──────────┴──────────────┴───────────────┴──────────┴──────────┘
使用命名函数
1result = df.select(
2 (pl.col("nrs").gt(1).alias("nrs > 1")), # greater than
3 (pl.col("nrs").ge(3)).alias("nrs >= 3"), # greater than or equal
4 (pl.col("random").lt(0.2)).alias("random < 0.2"),
5 (pl.col("random").le(0.5)).alias("random <= 0.5"),
6 (pl.col("nrs").ne(1)).alias("nrs != 1"),
7 (pl.col("nrs").eq(1)).alias("nrs == 1"),
8)
9print(result)
1shape: (5, 6)
2┌─────────┬──────────┬──────────────┬───────────────┬──────────┬──────────┐
3│ nrs > 1 ┆ nrs >= 3 ┆ random < 0.2 ┆ random <= 0.5 ┆ nrs != 1 ┆ nrs == 1 │
4│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
5│ bool ┆ bool ┆ bool ┆ bool ┆ bool ┆ bool │
6╞═════════╪══════════╪══════════════╪═══════════════╪══════════╪══════════╡
7│ false ┆ false ┆ false ┆ true ┆ false ┆ true │
8│ true ┆ false ┆ false ┆ false ┆ true ┆ false │
9│ true ┆ true ┆ false ┆ false ┆ true ┆ false │
10│ null ┆ null ┆ false ┆ false ┆ null ┆ null │
11│ true ┆ true ┆ true ┆ true ┆ true ┆ false │
12└─────────┴──────────┴──────────────┴───────────────┴──────────┴──────────┘
&
, |
, ~
and_
, or_
, not_
使用运算符
1result = df.select(
2 ((~pl.col("nrs").is_null()) & (pl.col("groups") == "A"))
3 .alias("number not null and group A"),
4
5 ((pl.col("random") < 0.5) | (pl.col("groups") == "B"))
6 .alias("random < 0.5 or group B"),
7)
8print(result)
1shape: (5, 2)
2┌─────────────────────────────┬─────────────────────────┐
3│ number not null and group A ┆ random < 0.5 or group B │
4│ --- ┆ --- │
5│ bool ┆ bool │
6╞═════════════════════════════╪═════════════════════════╡
7│ true ┆ true │
8│ true ┆ false │
9│ false ┆ true │
10│ false ┆ false │
11│ false ┆ true │
12└─────────────────────────────┴─────────────────────────┘
使用命名函数, 由于and
,or
,not
是Python的关键字, 所以使用and_
,or_
,not_
1result2 = df.select(
2 (pl.col("nrs").is_null().not_().and_(pl.col("groups") == "A"))
3 .alias("number not null and group A"),
4 ((pl.col("random") < 0.5).or_(pl.col("groups") == "B"))
5 .alias("random < 0.5 or group B"),
6)
7# 比较两个DataFrame是否相同
8print(result2.equals(result))
1True
1result = df.select(
2 pl.col("nrs"),
3 (pl.col("nrs") & 6).alias("nrs & 6"), # 与运算
4 (pl.col("nrs") | 6).alias("nrs | 6"), # 或运算
5 (~pl.col("nrs")).alias("not nrs"), # 取反
6 (pl.col("nrs") ^ 6).alias("nrs ^ 6"), # 异或运算
7)
8
9print(result)
1shape: (5, 5)
2┌──────┬─────────┬─────────┬─────────┬─────────┐
3│ nrs ┆ nrs & 6 ┆ nrs | 6 ┆ not nrs ┆ nrs ^ 6 │
4│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
5│ i64 ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
6╞══════╪═════════╪═════════╪═════════╪═════════╡
7│ 1 ┆ 0 ┆ 7 ┆ -2 ┆ 7 │
8│ 2 ┆ 2 ┆ 6 ┆ -3 ┆ 4 │
9│ 3 ┆ 2 ┆ 7 ┆ -4 ┆ 5 │
10│ null ┆ null ┆ null ┆ null ┆ null │
11│ 5 ┆ 4 ┆ 7 ┆ -6 ┆ 3 │
12└──────┴─────────┴─────────┴─────────┴─────────┘
n_unique
可用于计算序列中唯一值的确切数量. 但是对于非常大的数据集, 此操作可能会非常缓慢.
在这种情况下, 如果近似值足够好, 可以使用approx_n_unique
基于HyperLogLog++
算法的函数来估算结果
1import numpy as np
2import polars as pl
3# 数据准备, 生成10万个随机数
4long_df = pl.DataFrame({"numbers": np.random.randint(0, 100_000, 100_000)})
5
6result = long_df.select(
7 pl.col("numbers").n_unique().alias("n_unique"),
8 pl.col("numbers").approx_n_unique().alias("approx_n_unique"),
9)
10
11print(result)
1shape: (1, 2)
2┌──────────┬─────────────────┐
3│ n_unique ┆ approx_n_unique │
4│ --- ┆ --- │
5│ u32 ┆ u32 │
6╞══════════╪═════════════════╡
7│ 63217 ┆ 63699 │
8└──────────┴─────────────────┘
value_counts
: 获取有关唯一值及其计数的更多信息, df
依然为最初提供的数据#result = df.select(
pl.col("names").value_counts().alias("value_counts"),
)
print(result)
1shape: (4, 1)
2┌──────────────┐
3│ value_counts │
4│ --- │
5│ struct[2] │
6╞══════════════╡
7│ {"ham",1} │
8│ {"foo",1} │
9│ {"spam",2} │
10│ {"egg",1} │
11└──────────────┘
unique
,unique_counts
: 让每个值只出现一次, 并且获取每个值出现的次数#1result = df.select(
2 pl.col("names").unique().alias("unique"),
3 pl.col("names").unique_counts().alias("unique_counts"),
4)
5
6print(result)
name这一列有两行spam
, 其余都是一行
1shape: (4, 2)
2┌────────┬───────────────┐
3│ unique ┆ unique_counts │
4│ --- ┆ --- │
5│ str ┆ u32 │
6╞════════╪═══════════════╡
7│ foo ┆ 1 │
8│ ham ┆ 1 │
9│ spam ┆ 2 │
10│ egg ┆ 1 │
11└────────┴───────────────┘
when
,then
,otherwise
, 可以链式调用来完成自己的需求比如想新增一列color, groups值为A的, 就为red, 否则就为blue
下面的then()
中如果是字符串, 会被解析为一个列, 如果想填充一个值, 请使用pl.lit()
1df.select(
2 pl.col("groups"),
3 pl.when(pl.col("groups")=="A").then(pl.lit("red")).otherwise(pl.lit("blue"))
4)
1shape: (5, 2)
2┌────────┬─────────┐
3│ groups ┆ literal │
4│ --- ┆ --- │
5│ str ┆ str │
6╞════════╪═════════╡
7│ A ┆ red │
8│ A ┆ red │
9│ B ┆ blue │
10│ A ┆ red │
11│ B ┆ blue │
12└────────┴─────────┘
Polars是条件选择, 而不是条件执行
意思不是: "如果条件满足, 就执行该表达式, 否则就忽略"
而是: "并行执行所有表达式, 然后根据where条件决定用哪个结果"