我有一个数据框,其中一列文本字符串包含逗号分隔的值。我想分割每个CSV字段,并为每个条目创建一个新行(假设CSV是干净的,只需要在“,”上分割)。例如,a应该变成b:
[7]on
:a
Output[7]:
var1 var2
0 a、b、c 1
1d,e,f2
At[8]:b中
Output[8]:
var1 var2
0 a 1
1 b 1
2 c 1
三维2
4 e 2
5f2
到目前为止,我已经尝试了各种简单的函数,但是.apply方法在轴上使用时似乎只接受一行作为返回值,并且我无法让.transform工作。任何建议都将不胜感激
示例数据:
导入数据帧中的
将numpy作为np导入
a=数据帧([{'var1':'a,b,c','var2':1},
{'var1':'d,e,f','var2':2}])
b=数据帧([{'var1':'a','var2':1},
{'var1':'b','var2':1},
{'var1':'c','var2':1},
{'var1':'d','var2':2},
{'var1':'e','var2':2},
{'var1':'f','var2':2}])
我知道这不起作用,因为我们通过numpy丢失了数据帧元数据,但它应该让您了解我试图做的事情:
定义乐趣(世界其他地区):
字母=行['var1']
字母=字母。拆分(',')
out=np.数组([行]*len(字母))
out['var1']=字母
a['idx']=范围(a.shape[0])
z=a.groupby('idx'))
z、 转变(乐趣)
更新3:使用Series.explode()/DataFrame.explode()方法(在Pandas 0.25.0中实现,在Pandas 1.3.0中扩展以支持多列分解)更有意义,如使用示例所示:
对于单个列:
[1]on
:df=pd.DataFrame({'A':[[0,1,2],'foo',[],[3,4],
…:“B”:1,
…:'C':[[a','b','C'],np.nan,[],['d','e']})
In[2]:df
Output[2]:
A、B、C
0[0,1,2]1[a,b,c]
1富1南
2 [] 1 []
3[3,4]1[d,e]
At[3]on:df.explode('A')
Output[3]:
A、B、C
01[a,b,c]
01[a,b,c]
021[a,b,c]
1富1南
2南1[]
3 1[d,e]
3 4 1[d,e]
对于多列(对于熊猫1.3.0+):
[4]on
:df.explode(['A','C'])
Output[4]:
A、B、C
01 a
011B
0 2 1 c
1富1南
2楠1楠
31D
3 4 1 e
更新2:更通用的矢量化函数,可用于多个normal和多个list列
def explode(df,lst\u cols,fill\u value='',preserve\u index=False):
#确保'lst_cols'与列表相似
如果(lst_cols)不是无
和len(lst_cols)>;0
而不是实例(lst_cols,(list,tuple,np.ndarray,pd.Series)):
lst_cols=[lst_cols]
#除'lst_cols'外的所有列`
idx_cols=df.columns.difference(lst_cols)
#计算列表的长度
lens=df[lst_cols[0]]str.len()
#保留原始索引值
idx=np.重复(df.index.values,镜头)
#创建;“爆炸”;DF
res=(pd.DataFrame)({
列:np.重复(df[col].值,镜头)
对于idx_cols}中的col,
索引=idx)
.assign(**{col:np.concatenate(df.loc[lens>;0,col].values)
对于lst_cols})中的col)
#附加那些具有空列表的行
如果(镜头==0)。任何()
#单元格中至少有一个列表为空
res=(res.append(df.loc[lens==0,idx\u cols],sort=False)
.fillna(填充值))
#恢复原始索引顺序
res=res.sort_index()
#如果需要,重置索引
如果不保留索引:
res=res.reset_索引(drop=True)
返回res
演示:
多个列表列-所有列表列在每行中必须具有相同的元素:
[134]on
:df
Output[134]:
aaa myid num文本
0101[1,2,3][aa,bb,cc]
1 11 2 [] []
2 12 3[1,2][cc,dd]
3 13 4 [] []
At[135]on:分解(df,['num','text'],fill_value='')
Output[135]:
aaa myid num文本
011AA
110121BB
21013毫升
3 11 2
41231毫升
5 12 3 2日
6 13 4
保留原始索引值:
[136]on
:分解(df,['num','text'],填充值='',保留索引=真)
Output[136]:
aaa myid num文本
011AA
010 12 bb
0 10 1 3 cc
1 11 2
2 12 3 1毫升
2012年3月2日
3 13 4
设置:
df=pd.DataFrame({
‘aaa’:{0:10,1:11,2:12,3:13},
'myid':{0:1,1:2,2:3,3:4},
'num':{0:[1,2,3],1:[],2:[1,2],3:[]},
'text':{0:['aa',bb',cc'],1:[],2:['cc',dd'],3:[]
})
CSV列:
[46]on
:df
Output[46]:
var1 var2 var3
0 a、b、c 1 XX
1 d,e,f,x,y 2 ZZ
At[47]on:分解(df.assign(var1=df.var1.str.split(','),'var1'))
Output[47]:
var1 var2 var3
0 a 1 XX
1b1xx
2 c 1 XX
3D 2 ZZ
4 e 2 ZZ
5F2ZZ
6 x 2 ZZ
7 y 2 ZZ
使用此小技巧,我们可以将类似CSV的列转换为list列:
[48]on
:df.assign(var1=df.var1.str.split(','))
Output[48]:
var1 var2 var3
0[a,b,c]1 XX
1[d,e,f,x,y]2 ZZ
更新:通用矢量化方法(也适用于多列):
原始DF:
[177]on
:df
Output[177]:
var1 var2 var3
0 a、b、c 1 XX
1 d,e,f,x,y 2 ZZ
解决方案:
首先,让我们将CSV字符串转换为列表:
[178]on
:lst_col='var1'
At[179]on:x=df.assign(**{lst_col:df[lst_col].str.split(',')})
In[180]:x
Output[180]:
var1 var2 var3
0[a,b,c]1 XX
1[d,e,f,x,y]2 ZZ
现在我们可以这样做:
[181]on
:pd.DataFrame({
…:col:np.repeat(x[col].values,x[lst_col].str.len())
…:用于x列中的列。差异([lst_col])
赋值(**{lst_col:np.concatenate(x[lst_col].values)})[x.columns.tolist()]
...:
Output[181]:
var1 var2 var3
0 a 1 XX
1b1xx
2 c 1 XX
3D 2 ZZ
4 e 2 ZZ
5F2ZZ
6 x 2 ZZ
7 y 2 ZZ
旧答案:
受@AFinkelstein solution的启发,我想让它更具通用性,可以应用于具有两列以上的DF,并且速度几乎与AFinkelstein的解决方案一样快):
[2]on
:df=pd.DataFrame(
…:[{'var1':'a,b,c','var2':1',var3':'XX'},
…:{'var1':'d,e,f,x,y','var2':2',var3':'ZZ'}]
...: )
In[3]:df
Output[3]:
var1 var2 var3
0 a、b、c 1 XX
1 d,e,f,x,y 2 ZZ
At[4]on:(df.set_index(df.columns.drop('var1',1.tolist())
…:.var1.str.split(“,”,expand=True)
…:.stack()
…:.reset_index()
…:.rename(列={0:'var1'})
…:.loc[:,df.列]
...: )
Output[4]:
var1 var2 var3
0 a 1 XX
1b1xx
2 c 1 XX
3D 2 ZZ
4 e 2 ZZ
5F2ZZ
6 x 2 ZZ
7 y 2 ZZ