pandas每天一题-题目12:复杂筛选

2021-09-01 14:22:30 浏览数 (1)

这是一个关于 pandas 从基础到进阶的练习题系列,来源于 github 上的 guipsamora/pandas_exercises 。这个项目从基础到进阶,可以检验你有多么了解 pandas。

我会挑选一些题目,并且提供比原题库更多的解决方法以及更详尽的解析

计划每天更新一期,希望各位小伙伴先自行思考,再查看答案。如果对你有帮助,记得转发推荐给你的好友!

上期文章:pandas每天一题-题目11:筛选数据也有3种方式,最后一种揭示本质

后台回复"数据",可以下载本题数据集

如下数据:

数据描述:

  • 此数据是订单明细表。一个订单会包含很多明细项,表中每个样本(每一行)表示一个明细项
  • order_id 列存在重复
  • item_name 是明细项物品名称
  • quantity 是明细项数量
  • item_price 是该明细项的总价钱
  • choice_description 是每一项更详尽的描述

例如:某个单子中,客人要 1瓶可乐 和 1瓶雪碧 ,那么这个订单的 order_id 为:'xx',有2个行记录(样本),2行的item_name 都是 "Canned Soda"(苏打水,视为罐装饮料) ,quantity 都是1。

第一行的 choice_description 是 "Diet Coke"(可乐) ,第二行是 "Sprite"(雪碧)

需求:

  1. 找出包含 Canned Soda 的订单(item_name有 Canned Soda 的 order_id)
  2. 找出 Canned Soda 数量大于1的订单
  3. 找出同一个订单中多次出现 Canned Soda 的订单

下面是答案了


需求1

找出包含 Canned Soda 的订单(item_name有 Canned Soda 的 order_id)。

初学者容易写出以下错误代码:

代码语言:javascript复制
df.query('item_name == "Canned Soda"')

你能确保一个订单中只出现一次 "Canned Soda" ?

验证一下:

代码语言:javascript复制
(
    df.query('item_name == "Canned Soda"')['order_id']
    .value_counts()
)
  • 有些订单会同时出现多次 "Canned Soda"
  • 逻辑很简单,第一次点餐的饮料喝完了,还想再喝,"再来一瓶"呗

理解这一点,就很容易解决,去重就可以了:

代码语言:javascript复制
(
    df.query('item_name == "Canned Soda"')['order_id']
    .drop_duplicates()
)

去重是之前章节的内容,不再讲解


需求2

找出 Canned Soda 数量大于1的订单

其实只是在需求1的基础上添加数据条件即可:

代码语言:javascript复制
(
    df.query("item_name == 'Canned Soda' and quantity>1")['order_id']
    .drop_duplicates()
)

需求3

找出同一个订单中多次出现 Canned Soda 的订单

其实在需求1里面,就出现了一种解法:

代码语言:javascript复制
(
    df.query('item_name == "Canned Soda"')['order_id']
    .value_counts()
)

这离需求还差2步:

  1. 把数量大于1的筛选出来
  2. 列出订单(order_id)
代码语言:javascript复制
(
    df.query('item_name == "Canned Soda"')['order_id']
    .value_counts()
    .to_frame('counts')
    .query('counts>1')
    .index
)
代码语言:javascript复制
输出:
Int64Index([108, 1434, 1156, 1484, 81, 1396, 496, 787, 450], dtype='int64')
  • 行3:得到的是一列(Series)
  • 行4:因为 Series 是没有 query 方法,那么我们就把 Series 转成 DataFrame
  • 行5:可以用 query 查询了
  • 行6:现在行索引才是 order_id ,取出来就可以

不得不说,上面的解法很少见。这样写只是为了让代码能够连续调用。

下面是常见做法:

代码语言:javascript复制
counts = (
    df.query('item_name == "Canned Soda"')['order_id']
    .value_counts()
)

cond = counts > 1 
counts[cond].index
  • 行6:构造 bool 列
  • 行7:筛选

推荐阅读:

  1. sql题目pandas解法(01):筛选、all、any常用技巧
  2. 懂Excel就能轻松入门pandas(一):筛选功能

0 人点赞