Python 在数据帧中将单元格拆分为多行
我有一个包含订单数据的数据框,每个订单都有多个以逗号分隔的字符串[Python 在数据帧中将单元格拆分为多行,python,pandas,dataframe,Python,Pandas,Dataframe,我有一个包含订单数据的数据框,每个订单都有多个以逗号分隔的字符串[package&package\u 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
&package\u 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"]})
这就是我试图实现的输出:
我怎样才能对熊猫做到这一点呢?pandas>=0.25
假设所有可拆分列具有相同数量的逗号分隔项,则可以按逗号拆分,然后在每列上使用:
(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
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
熊猫这里有一种使用
numpy.repeat
和itertools.chain
的方法。从概念上讲,这正是您想要做的:重复某些值,链接其他值。建议用于少量列,否则基于堆栈的方法可能会更好
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
接近cold的方法:-)
看看今天的熊猫0.25版:
鉴于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 )
优势:
- 避免了必须将核心数据移动到索引以“防止其妨碍”,因此当数据包含重复数据时,不会因“重复索引”错误而失败
缺点:
- 仅当数据中没有列表列时才有效(尽管几乎总是这样)
这有用吗@coldspeed是的,我将在我的脑海中再次强调它(应用是不好的!:-()如果apply(pd.Series)
是不好的,是不是stack
更差?我看到它经常表现得比简单的迭代差!@jpp是的,这是对温的一般建议(他明白了)因为他使用它的次数比他应该使用的多了一点,而且你会期望一个拥有金徽章的60k用户想要尽可能地宣传好的实践;-)当然堆栈很糟糕,但是它的灵活性是有用的。你能补充一下吗details@pyd关于这一点,您具体想知道什么?使用-2
解压和使用-1
@AdarshRavi重置索引时会发生什么情况?您可以这样做:保留列=列表(设置(df.columns)-set([重塑列])
I更新的熊猫(版本1.0.3)最新的表单似乎不再有效:ValueError:无法处理非唯一的多索引代码>。如果有两列需要扩展并且具有不同的镜头,该怎么办?@Moj,这个问题还没有很好地定义。例如,不能使用1对1映射将3个值与5个值对齐。我建议你问一个新问题,如果你的问题没有在其他地方得到回答,那么你可以精确地指定你想要的输出。这很好。很高兴知道(a)Pandas是如何在内部实现此功能的,(b)此解决方案在性能方面与其他解决方案相比如何。今年只能分解一列way@cs95不,可以通过如下方式在多个列上分解:df=pd.DataFrame([{'var1':'a,b,c','var3':'x1,x2,x3','var2':1},{'var1':'d,e,f','var3':'x1,x2,x4','var2':2}])df.assign(var1=df.var1.str.split(','),var3=df.var3.str.split(',')).explode('var1')。explode('var3')。reset_index(drop=True)
结果不正确,每列单独分解,而不是相互串联,结果中产生的行数超过预期。我不明白,你能举一个所需数据和结果的示例吗?
_.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
_.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)
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(-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
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
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
df = pd.DataFrame([{'var1': 'a,b,c', 'var2': 1}, {'var1': 'd,e,f', 'var2': 2}])
df.assign(var1=df.var1.str.split(',')).explode('var1').reset_index(drop=True)
# 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 )