1

假设我有一个 csv

transaction_id,user,book
1,bob,bookA
2,bob,bookA
3,bob,bookB
4,tim,bookA
5,lucy,bookA
6,lucy,bookC
7,lucy,bookC
8,lucy,bookC

每个用户,我想找到他们最喜欢的书。例如,输出应该是;

shape: (3, 2)
┌──────┬──────────┐
│ user ┆ fav_book │
│ ---  ┆ ---      │
│ str  ┆ str      │
╞══════╪══════════╡
│ bob  ┆ bookA    │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┤
│ tim  ┆ bookA    │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┤
│ lucy ┆ bookC    │
└──────┴──────────┘

现在我已经想出了如何做到这一点

import polars as pl

df = pl.read_csv("book_aggs.csv")

print(df)

df2 = df.groupby(["user", "book"]).agg([
  pl.col("book").count(),
  pl.col("transaction_id") # just so we can double check where it all came from - TODO: how to output this to csv?
  ])

print(df2)

df3 = df2.sort(["user", "book_count"], reverse=True).groupby("user").agg([
  pl.col("book").first().alias("fav_book")
])

print(df3)

但实际上,正常的 sql 方法是按书籍数量降序排序的 dense_rank,其中 rank = 1。我已经尝试了几个小时来让它工作,但我在文档中找不到相关示例。

问题是在文档中,所有 agg 示例都没有引用另一个 agg 的输出 - 在这种情况下,它需要引用每个用户每本书的计数,然后对这些计数进行降序排序,然后根据该排序顺序进行排名。

请提供一个示例来说明如何使用排名来执行此任务,以及如何有效地嵌套聚合。

4

1 回答 1

3

方法一

我们可以首先 groupbyuser和 'book' 来获取所有user -> book组合并计算最常见的组合。

这将给出这个中间值DataFrame

shape: (5, 3)
┌──────┬───────┬────────────┐
│ user ┆ book  ┆ book_count │
│ ---  ┆ ---   ┆ ---        │
│ str  ┆ str   ┆ u32        │
╞══════╪═══════╪════════════╡
│ lucy ┆ bookC ┆ 3          │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ lucy ┆ bookA ┆ 1          │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ bob  ┆ bookB ┆ 1          │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ tim  ┆ bookA ┆ 1          │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ bob  ┆ bookA ┆ 2          │
└──────┴───────┴────────────┘

然后我们可以做另一个 groupbyuser计算索引maximum book_count并使用该索引来take正确book

整个查询如下所示:

df = pl.DataFrame({'book': ['bookA',
          'bookA',
          'bookB',
          'bookA',
          'bookA',
          'bookC',
          'bookC',
          'bookC'],
 'transaction_id': [1, 2, 3, 4, 5, 6, 7, 8],
 'user': ['bob', 'bob', 'bob', 'tim', 'lucy', 'lucy', 'lucy', 'lucy']
})

(df.groupby(["user", "book"])
 .agg([
     pl.col("book").count()
 ])
 .groupby("user")
 .agg([
     pl.col("book").take(pl.col("book_count").arg_max()).alias("fav_book")
 ])
)

并创建此输出:

shape: (3, 2)
┌──────┬──────────┐
│ user ┆ fav_book │
│ ---  ┆ ---      │
│ str  ┆ str      │
╞══════╪══════════╡
│ tim  ┆ bookA    │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┤
│ bob  ┆ bookA    │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┤
│ lucy ┆ bookC    │
└──────┴──────────┘

方法二

另一种方法是book_count使用 a 创建一个列,window_expression然后take在聚合中使用正确书籍的最大值索引:

(df
 .with_column(pl.count("book").over(["user", "book"]).alias("book_count"))
 .groupby("user")
 .agg([
     pl.col("book").take(pl.col("book_count").arg_max())
 ])
)
于 2021-12-21T07:14:51.453 回答