【问题标题】:polars intersection of list columns in dataframe数据框中列表列的极坐标交集
【发布时间】:2022-07-06 05:48:42
【问题描述】:
import polars as pl

df = pl.DataFrame({'a': [[1, 2, 3], [8, 9, 4]], 'b': [[2, 3, 4], [4, 5, 6]]})

所以给定数据框 df

    a           b
[1, 2, 3]   [2, 3, 4]
[8, 9, 4]   [4, 5, 6]

我想得到一列c,即a和b的交集

    a           b          c
[1, 2, 3]   [2, 3, 4]    [2, 3]
[8, 9, 4]   [4, 5, 6]     [4]

我知道我可以将 apply 函数与 python 集合交集一起使用,但我想使用极坐标表达式来做到这一点。

【问题讨论】:

    标签: python-polars


    【解决方案1】:

    我们可以使用arr.eval 表达式完成交集。 arr.eval 表达式允许我们将列表视为系列/列,以便我们可以使用与列和系列相同的上下文和表达式。

    首先,让我们扩展您的示例,以便我们可以显示当交叉点为空时会发生什么。

    df = pl.DataFrame(
        {
            "a": [[1, 2, 3], [8, 9, 4], [0, 1, 2]],
            "b": [[2, 3, 4], [4, 5, 6], [10, 11, 12]],
        }
    )
    df
    
    shape: (3, 2)
    ┌───────────┬──────────────┐
    │ a         ┆ b            │
    │ ---       ┆ ---          │
    │ list[i64] ┆ list[i64]    │
    ╞═══════════╪══════════════╡
    │ [1, 2, 3] ┆ [2, 3, 4]    │
    ├╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
    │ [8, 9, 4] ┆ [4, 5, 6]    │
    ├╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
    │ [0, 1, 2] ┆ [10, 11, 12] │
    └───────────┴──────────────┘
    

    算法

    df.with_column(
        pl.col("a")
        .arr.concat('b')
        .arr.eval(pl.element().filter(pl.count().over(pl.element()) > 1))
        .arr.unique()
        .alias('intersection')
    )
    
    shape: (3, 3)
    ┌───────────┬──────────────┬──────────────┐
    │ a         ┆ b            ┆ intersection │
    │ ---       ┆ ---          ┆ ---          │
    │ list[i64] ┆ list[i64]    ┆ list[i64]    │
    ╞═══════════╪══════════════╪══════════════╡
    │ [1, 2, 3] ┆ [2, 3, 4]    ┆ [2, 3]       │
    ├╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
    │ [8, 9, 4] ┆ [4, 5, 6]    ┆ [4]          │
    ├╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
    │ [0, 1, 2] ┆ [10, 11, 12] ┆ []           │
    └───────────┴──────────────┴──────────────┘
    

    工作原理

    我们首先将两个列表连接成一个列表。两个列表中的任何元素都会出现两次。

    df.with_column(
        pl.col("a")
        .arr.concat('b')
        .alias('ablist')
    )
    
    shape: (3, 3)
    ┌───────────┬──────────────┬────────────────┐
    │ a         ┆ b            ┆ ablist         │
    │ ---       ┆ ---          ┆ ---            │
    │ list[i64] ┆ list[i64]    ┆ list[i64]      │
    ╞═══════════╪══════════════╪════════════════╡
    │ [1, 2, 3] ┆ [2, 3, 4]    ┆ [1, 2, ... 4]  │
    ├╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
    │ [8, 9, 4] ┆ [4, 5, 6]    ┆ [8, 9, ... 6]  │
    ├╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
    │ [0, 1, 2] ┆ [10, 11, 12] ┆ [0, 1, ... 12] │
    └───────────┴──────────────┴────────────────┘
    

    然后我们可以使用arr.eval 函数,它允许我们将连接列表视为一个系列/列。在这种情况下,我们将使用filter 上下文来查找任何出现多次的元素。 (polars.element 表达式在列表上下文中的使用就像polars.col 在系列中使用一样。)

    df.with_column(
        pl.col("a")
        .arr.concat('b')
        .arr.eval(pl.element().filter(pl.count().over(pl.element()) > 1))
        .alias('filtered')
    )
    
    shape: (3, 3)
    ┌───────────┬──────────────┬───────────────┐
    │ a         ┆ b            ┆ filtered      │
    │ ---       ┆ ---          ┆ ---           │
    │ list[i64] ┆ list[i64]    ┆ list[i64]     │
    ╞═══════════╪══════════════╪═══════════════╡
    │ [1, 2, 3] ┆ [2, 3, 4]    ┆ [2, 3, ... 3] │
    ├╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
    │ [8, 9, 4] ┆ [4, 5, 6]    ┆ [4, 4]        │
    ├╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
    │ [0, 1, 2] ┆ [10, 11, 12] ┆ []            │
    └───────────┴──────────────┴───────────────┘
    

    剩下的就是使用arr.unique 表达式(即开头显示的结果)从结果中删除重复项。

    其他说明

    我假设您的列表确实是集合,因为元素在每个列表中只出现一次。如果原始列表中有重复项,我们可以在连接步骤之前将arr.unique 应用于每个列表。

    此外,这个过程可以扩展到找到两个以上集合的交集。只需将所有列表连接在一起,然后将filter 步骤从> 1 更改为== n(其中n 是集合数)。

    使用这种技术,我们还可以通过将filter 标准更改为== 1(并跳过arr.unique 步骤)来计算两组的对称差。

    arr.eval 方法确实有一个 parallel 关键字。您可以尝试将其设置为True,看看它在您的特定情况下是否会产生更好的性能。

    我们可以得到集合并集,使用arr.concatarr.unique

    可以通过计算交集(如上)获得集合差异,然后将结果连接回任一集合,然后过滤仅出现一次的项目。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-03-28
      • 1970-01-01
      • 1970-01-01
      • 2023-02-26
      • 2017-08-15
      • 2020-06-22
      • 1970-01-01
      相关资源
      最近更新 更多