我有一个像这样的数据框:

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

每对列表的长度可能不一样,我想将爆炸“截断”为两个列表中最短的一个:

"""
┌─────┬─────┐
│ a   ┆ b   │
│ --- ┆ --- │
│ i64 ┆ i64 │
╞═════╪═════╡
│ 2   ┆ 8   │
│ 3   ┆ 9   │
│ 4   ┆ 10  │
│ 5   ┆ 11  │
│ 6   ┆ 12  │
└─────┴─────┘
"""

我在想,也许我必须用 填充两个列表中最短的列表以None匹配两个长度,然后drop_nulls。但我想知道是否有更直接的方法可以解决这个问题?

1

  • 如果列表中有一个空值,会发生什么情况?例如,如果在示例中[3, 4]更改为[None, 4]?框架中还有其他非列表列吗?


    – 


最佳答案
2

以下是一种方法:

min_length = pl.min_horizontal(pl.col('a', 'b').list.len())

out = (df.filter(min_length != 0)
       .with_columns(
           pl.col('a', 'b').list.head(min_length)
           )
       .explode('a', 'b')
       )

输出:

shape: (5, 2)
┌─────┬─────┐
│ a   ┆ b   │
│ --- ┆ --- │
│ i64 ┆ i64 │
╞═════╪═════╡2839410511612
└─────┴─────┘

解释

  • 使用 获取两列列表的长度,并使用 获取每行的最短列表
  • min_length == 0现在,过滤出( )中的行,并用 选择每个列表的前 n 个值
  • 最后,应用

2

  • 为什么需要过滤器?


    – 

  • @Hericks:第一行有一个空列表([]),因此如果没有过滤器,就会导致出现一行[ null, null ],而这是OP不想要的。


    – 


我无法将其挤在评论中,因此我只能在这里提供另一个答案,因为对于给定的示例来说它更为通用:

(
    df.with_columns(
        (x := pl.all().list).head(
            pl.min_horizontal(x.len())
        )
    ).explode("*")
    .drop_nulls()
)
shape: (5, 2)
┌─────┬─────┐
│ a   ┆ b   │
│ --- ┆ --- │
│ i64 ┆ i64 │
╞═════╪═════╡2839410511612
└─────┴─────┘