将单元格拆分为熊猫数据框中的多行

2025-01-14 08:51:00
admin
原创
121
摘要:问题描述:我有一个包含订单数据的数据框,每个订单都有多个包存储为逗号分隔的字符串 [ package& package_code] 列我想拆分包裹数据并为每个包裹创建一行,包括其订单详细信息以下是示例输入数据框:import pandas as pd df = pd.DataFrame({"orde...

问题描述:

我有一个包含订单数据的数据框,每个订单都有多个包存储为逗号分隔的字符串 [ package& package_code] 列

我想拆分包裹数据并为每个包裹创建一行,包括其订单详细信息

以下是示例输入数据框:

import pandas as pd
df = pd.DataFrame({"order_id":[1,3,7],"order_date":["20/5/2018","22/5/2018","23/5/2018"], "package":["p1,p2,p3","p4","p5,p6"],"package_code":["#111,#222,#333","#444","#555,#666"]})

输入数据框

这就是我想要实现的输出:
输出

我怎样才能用熊猫做到这一点?


解决方案 1:

熊猫> = 0.25

假设所有可拆分的列都有相同数量的以逗号分隔的项目,您可以按逗号拆分,然后Series.explode在每列上使用:

(df.set_index(['order_id', 'order_date'])
   .apply(lambda x: x.str.split(',').explode())
   .reset_index())                                                   

   order_id order_date package package_code
0         1  20/5/2018      p1         #111
1         1  20/5/2018      p2         #222
2         1  20/5/2018      p3         #333
3         3  22/5/2018      p4         #444
4         7  23/5/2018      p5         #555
5         7  23/5/2018      p6         #666

细节

将不被触及的列设置为索引,

df.set_index(['order_id', 'order_date'])

                      package    package_code
order_id order_date                          
1        20/5/2018   p1,p2,p3  #111,#222,#333
3        22/5/2018         p4            #444
7        23/5/2018      p5,p6       #555,#666

下一步是一个两步过程:按逗号拆分以获取一列列表,然后调用explode将列表值分解到它们自己的行中。

_.apply(lambda x: x.str.split(',').explode())

                    package package_code
order_id order_date                     
1        20/5/2018       p1         #111
         20/5/2018       p2         #222
         20/5/2018       p3         #333
3        22/5/2018       p4         #444
7        23/5/2018       p5         #555
         23/5/2018       p6         #666

最后,重置索引。

_.reset_index()

   order_id order_date package package_code
0         1  20/5/2018      p1         #111
1         1  20/5/2018      p2         #222
2         1  20/5/2018      p3         #333
3         3  22/5/2018      p4         #444
4         7  23/5/2018      p5         #555
5         7  23/5/2018      p6         #666

熊猫<= 0.24

这应该适用于任何数量的列。本质是使用 进行堆叠-拆分的小魔法str.split

(df.set_index(['order_date', 'order_id'])
   .stack()
   .str.split(',', expand=True)
   .stack()
   .unstack(-2)
   .reset_index(-1, drop=True)
   .reset_index()
)

  order_date  order_id package package_code
0  20/5/2018         1      p1         #111
1  20/5/2018         1      p2         #222
2  20/5/2018         1      p3         #333
3  22/5/2018         3      p4         #444
4  23/5/2018         7      p5         #555
5  23/5/2018         7      p6         #666

还有另一种涉及 的高性能替代方案chain,但您需要明确链接和重复每一列(列很多时会出现一些问题)。选择最适合您问题描述的任何方法,因为没有唯一的答案。

细节

首先,将不被触碰的列设置为索引。

df.set_index(['order_date', 'order_id'])
 
                      package    package_code
order_date order_id                          
20/5/2018  1         p1,p2,p3  #111,#222,#333
22/5/2018  3               p4            #444
23/5/2018  7            p5,p6       #555,#666

接下来stack是行。

_.stack()

order_date  order_id              
20/5/2018   1         package               p1,p2,p3
                      package_code    #111,#222,#333
22/5/2018   3         package                     p4
                      package_code              #444
23/5/2018   7         package                  p5,p6
                      package_code         #555,#666
dtype: object

我们现在有一系列。所以请拨打str.split逗号。

_.str.split(',', expand=True)

                                     0     1     2
order_date order_id                               
20/5/2018  1        package         p1    p2    p3
                    package_code  #111  #222  #333
22/5/2018  3        package         p4  None  None
                    package_code  #444  None  None
23/5/2018  7        package         p5    p6  None
                    package_code  #555  #666  None

我们需要摆脱 NULL 值,因此请stack再次调用。

_.stack()

order_date  order_id                 
20/5/2018   1         package       0      p1
                                    1      p2
                                    2      p3
                      package_code  0    #111
                                    1    #222
                                    2    #333
22/5/2018   3         package       0      p4
                      package_code  0    #444
23/5/2018   7         package       0      p5
                                    1      p6
                      package_code  0    #555
                                    1    #666
dtype: object

我们快完成了。现在我们希望索引的倒数第二级成为我们的列,因此使用unstack(-2)(unstack在倒数第二级 )进行拆分

_.unstack(-2)

                      package package_code
order_date order_id                       
20/5/2018  1        0      p1         #111
                    1      p2         #222
                    2      p3         #333
22/5/2018  3        0      p4         #444
23/5/2018  7        0      p5         #555
                    1      p6         #666

使用以下方法去掉多余的最后一级reset_index

_.reset_index(-1, drop=True)

                    package package_code
order_date order_id                     
20/5/2018  1             p1         #111
           1             p2         #222
           1             p3         #333
22/5/2018  3             p4         #444
23/5/2018  7             p5         #555
           7             p6         #666

最后,

_.reset_index()

  order_date  order_id package package_code
0  20/5/2018         1      p1         #111
1  20/5/2018         1      p2         #222
2  20/5/2018         1      p3         #333
3  22/5/2018         3      p4         #444
4  23/5/2018         7      p5         #555
5  23/5/2018         7      p6         #666

解决方案 2:

numpy.repeat这是使用和 的一种方法itertools.chain。从概念上讲,这正是您想要做的:重复一些值,链接其他值。建议用于少量列,否则stack基于方法可能会更好。

import numpy as np
from itertools import chain

# return list from series of comma-separated strings
def chainer(s):
    return list(chain.from_iterable(s.str.split(',')))

# calculate lengths of splits
lens = df['package'].str.split(',').map(len)

# create new dataframe, repeating or chaining as appropriate
res = pd.DataFrame({'order_id': np.repeat(df['order_id'], lens),
                    'order_date': np.repeat(df['order_date'], lens),
                    'package': chainer(df['package']),
                    'package_code': chainer(df['package_code'])})

print(res)

   order_id order_date package package_code
0         1  20/5/2018      p1         #111
0         1  20/5/2018      p2         #222
0         1  20/5/2018      p3         #333
1         3  22/5/2018      p4         #444
2         7  23/5/2018      p5         #555
2         7  23/5/2018      p6         #666

解决方案 3:

看看今天的 Pandas 版本 0.25:
https ://pandas.pydata.org/pandas-docs/stable/whatsnew/v0.25.0.html#series-explode-to-split-list-like-values-to-rows

df = pd.DataFrame([{'var1': 'a,b,c', 'var2': 1}, {'var1': 'd,e,f', 'var2': 2}])
df_splitted = df.assign(var1=df.var1.str.split(',')).explode('var1').reset_index(drop=True)
print(df_splitted)

解决方案 4:

鉴于explode这只影响列表列,一个简单的解决方案是:

# Convert columns of interest to list columns
d["package"]      = d["package"].str.split(",")
d["package_code"] = d["package_code"].str.split(",")

# Explode the entire data frame
d = d.apply( pandas.Series.explode )

优点

  • 避免将核心数据移动到索引以“避免妨碍”,因此当数据包含重复时不会因“重复索引”错误而失败。

缺点

  • 仅当数据中没有列表列时才有效(尽管几乎总是如此)。

解决方案 5:

接近冷的方法:-)

df.set_index(['order_date','order_id']).apply(lambda x : x.str.split(',')).stack().apply(pd.Series).stack().unstack(level=2).reset_index(level=[0,1])
Out[538]: 
  order_date  order_id package package_code
0  20/5/2018         1      p1         #111
1  20/5/2018         1      p2         #222
2  20/5/2018         1      p3         #333
0  22/5/2018         3      p4         #444
0  23/5/2018         7      p5         #555
1  23/5/2018         7      p6         #666
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2044  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1453  
  锋云服务器在众多企业和用户的数字化运营中扮演着关键角色,其系统的更新与维护对于保障服务的稳定性、性能优化以及功能拓展至关重要。尤其是在涉及曲库更新这类与内容服务紧密相关的操作上,需要一套严谨且高效的流程,以确保用户能够持续享受到最新、最优质的音乐资源服务。接下来,我们将深入探讨锋云服务器如何更新曲库这一重要议题。前期准...
更新过程   0  
  群晖作为一款功能强大的网络附属存储(NAS)设备,为用户提供了丰富的应用和便捷的管理体验。设置邮件服务器是群晖众多实用功能之一,它能让用户在本地搭建一个稳定且高效的邮件服务环境,满足企业或个人在邮件通信方面的多样化需求。通过合理配置群晖邮件服务器,不仅可以提升工作效率,还能增强数据的安全性和隐私性。接下来,我们将详细探...
IP地址   0  
  在网络环境日益复杂的当下,涉及内网服务器密码的管理与操作成为众多技术人员和网络管理者关注的焦点。其中,删除进内网服务器密码这一操作,既需要谨慎对待,又要遵循特定的流程和方法,以确保服务器的安全性和稳定性不受影响。接下来,我们将深入探讨进内网服务器密码删除的相关内容。理解内网服务器密码删除的影响内网服务器密码是保障服务器...
身份验证   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用