前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >pandas每天一题-题目19:"炸列"操作的多种方式

pandas每天一题-题目19:"炸列"操作的多种方式

作者头像
咋咋
发布2021-09-01 14:11:23
5900
发布2021-09-01 14:11:23
举报
文章被收录于专栏:数据大宇宙

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

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

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

上期文章:pandas每天一题-题目18:分组填充缺失值

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

如下数据:

代码语言:javascript
复制
import pandas as pd
import numpy as np

df = pd.read_csv('chipotle.tsv',
                 sep='\t',
                 converters={'item_price': lambda x: float(x[1:-1])})

数据描述:

  • 此数据是订单明细表。一个订单会包含很多明细项,表中每个样本(每一行)表示一个明细项
  • order_id 列存在重复
  • item_name 是明细项物品名

前面章节讲解过的知识点,本文不再讲解!

这次只需要4个订单的数据即可:

代码语言:javascript
复制
orders = [311, 1828, 328, 1355]
df.query('order_id in @orders')

然后把同一个订单的 item_name 串起来:

代码语言:javascript
复制
orders = [311, 1828, 328, 1355]

df = (
    df.query('order_id in @orders')
    .groupby('order_id').agg({'item_name':','.join})
    .reset_index()
)

需求:

把 item_name 拆开,变回每个 item_name 一行数据

下面是答案了


横向 + 竖向的拆分

第一步是把"串起来"的 item_name 拆分:

代码语言:javascript
复制
df.assign(item_name = df.item_name.str.split(','))

现在的 item_name 里面全是 列表对象(list):

代码语言:javascript
复制
(
    df.assign(item_name = df.item_name.str.split(','))
    ['item_name'].apply(type)
)

此时,如果你在使用 pandas 0.25或以上版本,那么可以:

代码语言:javascript
复制
(
    df.assign(item_name = df.item_name.str.split(','))
    .explode('item_name')
)

点评:

记住次序,先让单元格里面的内容变成列表,然后对列做 explode

注意返回结果的行索引,这能给出另一种解法的提示


重排索引

很不幸,如果你使用比较旧版本的 pandas,怎么办?

我们使用倒推法找解决思路。

只看 item_name 列,怎么从左边得到右边的结果?

实际就是有一个 列表,里面的元素都是列表,怎么展平成一个列表:

代码语言:javascript
复制
from itertools import chain

list(chain.from_iterable([[1,2,3],[4,5]]))

输出:

代码语言:javascript
复制
[1, 2, 3, 4, 5]

关于 itertools 可以关注我的相关系列教程

也就是:

代码语言:javascript
复制
from itertools import chain

dfx = df.assign(item_name = df.item_name.str.split(','))
names = list(chain.from_iterable(dfx['item_name']))

names

输出:

代码语言:javascript
复制
['Steak Salad',
 'Steak Bowl',
 'Chips and Guacamole',
 'Carnitas Soft Tacos',
 'Chicken Bowl',
 'Chips and Guacamole',
 'Chicken Burrito',
 'Chicken Bowl',
 'Chips and Guacamole',
 'Canned Soft Drink']

接下来,怎么可以从4行,按每一行的 item_name 里面的列表元素数量,拆分成多行?

reindex 可以重复多行数据:

代码语言:javascript
复制
df.reindex([0,0,1,1,2,2,3,3])
  • reindex 中指定的是行索引列表

怎么知道每个订单需要拆分的行数:

代码语言:javascript
复制
dfx = df.assign(item_name = df.item_name.str.split(','))
dfx['item_name'].str.len()

怎么按这个数量,生成对应的行索引值:

代码语言:javascript
复制
dfx = df.assign(item_name = df.item_name.str.split(','))
lens = dfx['item_name'].str.len()
np.repeat(lens.index,lens)

输出:

代码语言:javascript
复制
Int64Index([0, 0, 0, 0, 1, 1, 2, 3, 3, 3], dtype='int64')
  • 行2:此时 item_name 列不是文本类型,但是因为 列表对象 也可以使用 len 函数求得长度,所以这里取巧做到效果

行2也可以使用:

代码语言:javascript
复制
lens = dfx['item_name'].apply(len)

至此,把所有技巧连起来即可:

代码语言:javascript
复制
from itertools import chain

dfx = df.assign(item_name = df.item_name.str.split(','))

# 展开 list 中 list
names = list(chain.from_iterable(dfx['item_name']))

# 展开行
lens = dfx['item_name'].str.len()
idx = np.repeat(lens.index,lens)
dfx = dfx.reindex(idx)
dfx['item_name'] = names
dfx

这就能得到与直接使用 explode 一样的结果

总结:

  1. itertools.chain 展开 list 中 list
  2. numpy.repeat 重复生成指定次数的数据
  3. DataFrame.reindex 按指定行索引值,生成重复数据

推荐阅读:

  1. 懂Excel轻松入门Python数据分析包pandas(十七):合并不规范数据
  2. Python入门必备:细讲Python推导式
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据大宇宙 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 横向 + 竖向的拆分
  • 重排索引
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档