将列表的多列拆分为单独的行

问题描述

我有一个这样的数据框-

df = pd.DataFrame(
    {'key': [1,2,3,4],'col1': [['apple','orange'],['pineapple'],['','','guava',''],'orange','apple','']],'col2': [['087','799'],['681'],['078'],['816','018']]
     }
)

我需要拆分列'col1'和'col2'并创建单独的行,但是根据其索引映射列表元素。所需的输出是这个-

desired_df = pd.DataFrame(
    {'key': [1,1,4,'col1': [['apple'],['orange'],['guava'],['apple']],'col2': [['087'],['799'],['816'],['018']]
    }
)

在col1中,元素可能为空,但非空col1元素的总长度将与col2的相应元素的长度匹配。例如:df的第2行和第3行。

我尝试了以下操作,但没有成功-

df.set_index(['key'])[['col1','col2']].apply(pd.Series).stack().reset_index(level=1,drop=True) 

请帮助。我还在学习Python。

解决方法

由于您知道每个列表中的非空元素的数量总是匹配的,因此您可以分别explode每一列,过滤出空白,然后将结果重新加入。如果您想将.reset_index()作为一列添加到'key'上。

import pandas as pd

pd.concat([df.set_index('key')[[col]].explode(col).query(f'{col} != ""')
           for col in ['col1','col2']],axis=1)

# Without the f-string
#pd.concat([df.set_index('key')[[col]].explode(col).query(col + ' != ""')
#           for col in ['col1',axis=1)

          col1 col2
key                
1        apple  087
1       orange  799
2    pineapple  681
3        guava  078
4       orange  816
4        apple  018

如果您使用的pandas的旧版本不允许使用explode方法,请使用@BEN_YO's method to unnest。我将在此处复制相关代码,因为有几个不同的版本可供选择。

import numpy as np

def unnesting(df,explode):
    idx = df.index.repeat(df[explode[0]].str.len())
    df1 = pd.concat([
        pd.DataFrame({x: np.concatenate(df[x].values)}) for x in explode],axis=1)
    df1.index = idx

    return df1.join(df.drop(explode,1),how='left')

pd.concat([unnesting(df.set_index('key')[[col]],explode=[col]).query(f'{col} !=""')
           for col in ['col1',axis=1)
# Same output as above
,

尝试像这样在旧的df上创建新的df

df['key'] =  df.apply(lambda x: [x['key']]*len(x['col2']),axis=1)
lst_col = ['key','col1','col2']
df = pd.DataFrame({
    col:[x for lst in list(df[col]) for x in lst if x!=""] for col in lst_col

})

输出

    key col1       col2
0   1   apple       087
1   1   orange      799
2   2   pineapple   681
3   3   guava       078
4   4   orange      816
5   4   apple       018
,

出于复杂性考虑:)

 pd.DataFrame([j for i in [[{"key": x['key'],"col1": y,'col2':x['col2'][list(filter(None,x['col1'])).index(y)]} for y in list(filter(None,x['col1']))]for idx,x in df.iterrows()] for j in i])

输出

|   key | col1      |   col2 |
|------:|:----------|-------:|
|     1 | apple     |    087 |
|     1 | orange    |    799 |
|     2 | pineapple |    681 |
|     3 | guava     |    078 |
|     4 | orange    |    816 |
|     4 | apple     |    018 |
,

尝试

newkeys= list(itertools.chain.from_iterable(df.apply(lambda vals : [vals[0]]*len(vals[2]),axis=1).tolist()))
newcol1,newcol2 =  list(itertools.chain.from_iterable(df.col1)),list(itertools.chain.from_iterable(df.col2))
newcol1=list(filter(None,newcol1))
pd.DataFrame(zip(*[newkeys,newcol1,newcol2]),columns=df.columns)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...