从 Pandas 到 Polars 四:groupby和unique的排序

Polars被设计得非常注重数据的保护,所以您不会遇到类似Pandas代码中的意外情况,其中因为缺失值而导致整数列被转换为浮点数。

df = pd.DataFrame({'ints':[None,1,2],'strings':['a','b','c']})

然而,每个大型库都会做一些某些用户不会期望的事情。这些通常被称为“陷阱”(gotchas)。在本文中,我们将探讨一些与group_by和unique的排序输出相关的少数陷阱。

groupby的排序

让我们定义一个简单的DataFrame并进行group_by聚合操作。

df = pl.DataFrame(
    {
        "color": ["red", "green", "green", "red", "red"],
        "value": [0, 1, 2, 3, 4],
    }
)
(
    df
    .group_by("color")
    .agg(
        pl.col("value").count()
    )
)

如果我们运行这段代码,可能会得到以下输出:

shape: (2, 2)
┌───────┬───────┐
│ color ┆ value │
│ ---   ┆ ---   │
│ str   ┆ u32   │
╞═══════╪═══════╡
│ green ┆ 2     │
│ red   ┆ 3     │
└───────┴───────┘

好的——那么组是按照字母顺序排序的,对吧?

其实不然——再运行几次,我们最终会得到一个行顺序不同的输出:

shape: (2, 2)
┌───────┬───────┐
│ color ┆ value │
│ ---   ┆ ---   │
│ str   ┆ u32   │
╞═══════╪═══════╡
│ red   ┆ 3     │
│ green ┆ 2     │
└───────┴───────┘

我们看到group_by的输出顺序既不是按字母顺序也不是按输入顺序固定的。这可能会成为一个问题,如果我们想要确保获得一致的排序——例如在编写测试时。

如果我们想要获得一致的输出,我们有两个选择。第一个选择是在group_by中传递maintain_order=True参数:

(
    df
    .group_by("color",maintain_order = True)
    .agg(
        pl.col("value").count()
        )
)

将maintain_order=True设置为确保组的顺序与输入数据的顺序一致。然而,使用maintain_order=True会阻止Polars对于大于内存的数据使用流式处理引擎。

第二种解决方案是在输出上调用sort函数,以对组进行排序。

(
    df
    .group_by("color")
    .agg(
        pl.col("value").count(),
        )
    .sort("color")
)

由于sort现在可以在流式处理引擎中使用,因此这个解决方案也可以在流式模式下运行。

对于“unique”的排序

我们使用unique函数来获取与某些列相关的DataFrame的唯一行。在这个例子中,我们定义了一个简单的DataFrame,其中我们根据color和value列定义唯一值,并使用row列来跟踪行的顺序。

df = pl.DataFrame(
    {
        "color": ["red", "green", "red", "green", "red"],
        "value": [0, 1, 0, 1, 2],
        "row":[0,1,2,3,4]
    }
)
df.unique(subset=["color","value"])

运行一次,我们可能会得到如下的输出:

shape: (3, 3)
┌───────┬───────┬─────┐
│ color ┆ value ┆ row │
│ ---   ┆ ---   ┆ --- │
│ str   ┆ i64   ┆ i64 │
╞═══════╪═══════╪═════╡
│ red   ┆ 0     ┆ 0   │
│ green ┆ 1     ┆ 1   │
│ red   ┆ 2     ┆ 4   │
└───────┴───────┴─────┘

在Polars的早期版本(即v0.17.0之前)中,我们每次都会得到这样的顺序。

这是因为unique方法的行为与group_by不同,在unique中maintain_order默认设置为True。但现在情况已经改变了——maintain_order现在默认设置为False,因此unique的输出不再按照输入DataFrame的顺序进行排序。这意味着上面的输出也可能是无序的。

shape: (3, 3)
┌───────┬───────┬─────┐
│ color ┆ value ┆ row │
│ ---   ┆ ---   ┆ --- │
│ str   ┆ i64   ┆ i64 │
╞═══════╪═══════╪═════╡
│ green ┆ 1     ┆ 1   │
│ red   ┆ 0     ┆ 0   │
│ red   ┆ 2     ┆ 4   │
└───────┴───────┴─────┘

在某些方面,之前的有序行为是直观的,因为我们通常认为unique是返回没有重复行的输入DataFrame。然而,与group_by一样,如果默认设置maintain_order=True,那么默认情况下unique将无法在流式处理模式下工作。保持顺序对于流式处理是不友好的,因为它需要将所有块加载到内存中以便比较行的顺序。

随着这个默认设置的改变,开发者希望确保Polars能够处理各种大小的数据集,同时允许用户根据需要在不同行为之间进行选择。

一个相关的问题是unique在选择每个重复组中的哪一行时的默认行为。在Pandas中,这默认为每个重复组的第一行。而在Polars中,默认是any,因为这样可以再次进行更多的优化。

要点总结

当输出的顺序对您很重要时,请注意是否存在maintain_order参数。其他一些具有此参数的函数包括:

partition_by

pivot

upsample

cut(应用于序列)

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值