Polars有4种原生嵌套的列类型。这对解决以下问题非常有帮助,例如:
- 使用ML嵌入
- 分割字符串
- 使用嵌套的JSON数据
- 使用聚合
要充分利用它们,了解这些类型之间的区别是很重要的。特别是嵌套列类型之间的关键区别。
嵌套列类型概述
在Polars中的4种原生嵌套列类型为:
- pl.List
- pl.Array
- pl.Object
- pl.Struct
我们可以立即把它们分成两组:
- pl.List, pl.Array和pl.Object在每一行上存储某种序列
- pl.Struct是列的嵌套集合
序列类型
序列类型 pl.List, pl.Array和pl.Object在每一行上存储某种序列。它们之间的主要区别是它们如何存储序列,以及序列的长度在每一行上是否可以有所不同。
我们可以将序列类型分成两组:
- pl.List和pl.Array将每行中数据存储在一个 Polars Series中
- pl.Object将每行中数据存储在一个Python列表中
pl.List 和 pl.Array
在每一行中, pl.List和pl.Array将数据存储在一个Polars Series中。与任何Polars Series一样,系列中的数据必须具有同质的数据类型,例如浮动为 pl.Float32或字符串作为 pl.Utf8。对于列中的所有行,数据类型也必须相同。
pl.List和pl.Array之间的区别是,pl.List序列的长度可以不同,而pl.Array每行必须是相同的。在这个意义上,与2D numpy数组相对而言,pl.Array更具可比性,2D numpy数组第一个维度是DataFrame的长度,第二个维度是数组的长度。
pl.List和pl.Array 另一个实际区别是: pl.Array 相对较新,功能较少。pl.List更方便使用,而 pl.Array 需要进一步发展。
在这个例子中,我们创建了一个带有浮点数pl.List和一个混合的pl.Object类型的DataFrame。Polars将pl.List类型推断为pl.Float64,将pl.Object类型推断为数据类型混合的pl.Object列。
然后通过将浮点列转换为 pl.Array类型创建了一个新的pl.Array。为此,我们将数组的宽度指定为2,并将内部类型指定为pl.Float64。
为了说明这一点,我们使用每个序列类型创建一个DataFrame
import polars as pl
df = pl.DataFrame(
{
"floats": [[0.0, 1], [2, 3]],
"mixed_object": [["a", 0], ["b", 1]]
}
).with_columns(
floats_array=pl.col("floats").cast(pl.Array(width=2, inner=pl.Float64))
)
shape: (2, 3)
注意, pl.Object列中有一些列表,其中每个列表都混合了不同的数据类型。
序列类型的用例包括使用向量数据和拆分字符串。
数据类型在内部也被广泛使用-
一个group_by创建一个pl.List 列,其中包含每个group的数据,并在这个 pl.List列上发生聚合。
pl.DataFrame(
{
"grp": ["a", "a", "b"],
"value": [0, 1, 2]
}
).group_by("grp").agg(
pl.col("value")
)
shape: (2, 2)
嵌套列的pl.Struct类型
上面的序列类型在每一行上都有一个序列,而pl.Struct 类型是列的嵌套集合。pl.Struct 实际上只是为列设置嵌套名称空间的一种方法,其下的列只是普通的Polars的Series。
当然,像任何Polars的Series一样,在以pl.Struct为基础的列中的数据必须有一个同质的数据类型。
df_struct = (
pl.DataFrame(
{
"year":[2020,2021],
"trades":[
{"exporter":"India","importer":"USA","quantity":0.0},
{"exporter":"India","importer":"USA","quantity":1.5},
]
}
))
shape: (2, 2)
如果你有一个pl.Struct构造列,并希望将列取消嵌套,展开为平面DataFrame,可以使用unnest,如下:
df_struct.unnest('trades')
shape: (2, 4)
pl.Struct类型的用例包括使用嵌套的JSON数据,以及在使用宽DataFrames时将列折叠成组。