如何在 Polars 或 Pyarrow 中获取字符串列的哈希值
How to get hash of string column in Polars or Pyarrow
我有一个 Pandas DataFrame/Polars dataframe / Pyarrow table 带有字符串键列。您可以假设字符串是随机的。我想根据这个键列将该数据帧分成 N 个较小的数据帧。
对于整数列,我可以只使用 df1 = df[df.key % N == 1]
、df2 = df[df.key % N == 2]
等
我对如何使用字符串列执行此操作的最佳猜测是应用哈希函数(例如,对字符串的 ascii 值求和)将其转换为整数列,然后使用模数。
请告诉我在 Pandas、Polars 或 Pyarrow 中最有效的方法是什么,最好是在 API 中使用纯柱状操作。对于我的用例,执行 df.apply 可能太慢了。
我会尝试使用 hash_rows
来查看它在您的数据集和计算平台上的表现。 (请注意,在计算中,我实际上只选择了 key
字段和 运行 上的 hash_rows
)
N = 50
df = df.with_column(
pl.lit(df.select(['key']).hash_rows() % N).alias('hash')
)
我只是 运行 在一个 32 核系统上有近 4900 万条记录的数据集上,它在几秒钟内完成。 (我数据集中的 'key' 字段是人的姓氏。)
我还应该注意,有一个 partition_by
方法可能对分区有帮助。
我对@cbilots 的回答有一点补充。 Polars 有一个 hash
表达式,因此计算分区 ID 很简单。
如果将其与 partition_by
结合使用,您可以通过以下方式以极快的速度创建分区:
df = pl.DataFrame({
"strings": ["A", "A", "B", "A"],
"payload": [1, 2, 3, 4]
})
N = 2
(df.with_columns([
(pl.col("strings").hash() % N).alias("partition_id")
]).partition_by("partition_id"))
[shape: (3, 3)
┌─────────┬─────────┬──────────────┐
│ strings ┆ payload ┆ partition_id │
│ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ u64 │
╞═════════╪═════════╪══════════════╡
│ A ┆ 1 ┆ 0 │
├╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ A ┆ 2 ┆ 0 │
├╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ A ┆ 4 ┆ 0 │
└─────────┴─────────┴──────────────┘,
shape: (1, 3)
┌─────────┬─────────┬──────────────┐
│ strings ┆ payload ┆ partition_id │
│ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ u64 │
╞═════════╪═════════╪══════════════╡
│ B ┆ 3 ┆ 1 │
└─────────┴─────────┴──────────────┘]
分区的分组和具体化将并行完成。
我有一个 Pandas DataFrame/Polars dataframe / Pyarrow table 带有字符串键列。您可以假设字符串是随机的。我想根据这个键列将该数据帧分成 N 个较小的数据帧。
对于整数列,我可以只使用 df1 = df[df.key % N == 1]
、df2 = df[df.key % N == 2]
等
我对如何使用字符串列执行此操作的最佳猜测是应用哈希函数(例如,对字符串的 ascii 值求和)将其转换为整数列,然后使用模数。
请告诉我在 Pandas、Polars 或 Pyarrow 中最有效的方法是什么,最好是在 API 中使用纯柱状操作。对于我的用例,执行 df.apply 可能太慢了。
我会尝试使用 hash_rows
来查看它在您的数据集和计算平台上的表现。 (请注意,在计算中,我实际上只选择了 key
字段和 运行 上的 hash_rows
)
N = 50
df = df.with_column(
pl.lit(df.select(['key']).hash_rows() % N).alias('hash')
)
我只是 运行 在一个 32 核系统上有近 4900 万条记录的数据集上,它在几秒钟内完成。 (我数据集中的 'key' 字段是人的姓氏。)
我还应该注意,有一个 partition_by
方法可能对分区有帮助。
我对@cbilots 的回答有一点补充。 Polars 有一个 hash
表达式,因此计算分区 ID 很简单。
如果将其与 partition_by
结合使用,您可以通过以下方式以极快的速度创建分区:
df = pl.DataFrame({
"strings": ["A", "A", "B", "A"],
"payload": [1, 2, 3, 4]
})
N = 2
(df.with_columns([
(pl.col("strings").hash() % N).alias("partition_id")
]).partition_by("partition_id"))
[shape: (3, 3)
┌─────────┬─────────┬──────────────┐
│ strings ┆ payload ┆ partition_id │
│ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ u64 │
╞═════════╪═════════╪══════════════╡
│ A ┆ 1 ┆ 0 │
├╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ A ┆ 2 ┆ 0 │
├╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ A ┆ 4 ┆ 0 │
└─────────┴─────────┴──────────────┘,
shape: (1, 3)
┌─────────┬─────────┬──────────────┐
│ strings ┆ payload ┆ partition_id │
│ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ u64 │
╞═════════╪═════════╪══════════════╡
│ B ┆ 3 ┆ 1 │
└─────────┴─────────┴──────────────┘]
分区的分组和具体化将并行完成。