首页 > 解决方案 > 根据列表复制熊猫数据框中的行并用列表条目填充新列

问题描述

我有一个关于在熊猫数据框中复制行的问题。我已经为列表中“相关冲击”一栏中的每个观察分配了相关日期。观察 22 有一个空列表,23 有一个日期的列表,24 有两个日期的列表和 25 有三个日期的列表(如“listlength”列所示)。

我的目标是以如下方式扩展数据框:具有空列表的观察结果保留在数据集中一行,而具有 x 观察结果的行被重复 x 次 - 因此,第 22 行和第 23 行应该保留在数据框中一次(22 尽管为空列表和 23,因为它有一个相关日期),第 24 行应该被复制一次,因此在数据框中两次,观察 25 应该被复制两次,因此在数据框中三次。因此,每一行在数据框中的次数应与它具有相关冲击的次数一样多(由 listlength 衡量)。除了列表长度为 0 的那些之外,它们仍应保留在数据框中。

此外,我想创建一个新列“相关冲击”,由每个相关冲击分别填充一次。

这是当前的数据框:

    quarter year    pddate      relevant shocks                                                 listlength
22  1       2012    2012-02-15  []                                                              0.0
23  4       2011    2011-11-15  [2011-08-18 00:00:00]                                           1.0
24  3       2011    2011-08-15  [2011-08-18 00:00:00, 2011-09-22 00:00:00]                      2.0
25  2       2011    2011-05-13  [2011-08-04 00:00:00, 2011-08-08 00:00:00, 2011-08-10 00:00:00  3.0

新的数据框应该有 7 行,如下所示:

    quarter year    pddate      relevant shocks                                                 listlength    relevant shock
22  1       2012    2012-02-15  []                                                              0.0
23  4       2011    2011-11-15  [2011-08-18 00:00:00]                                           1.0           2011-08-18 00:00:00
24  3       2011    2011-08-15  [2011-08-18 00:00:00, 2011-09-22 00:00:00]                      2.0           2011-08-18 00:00:00
25  3       2011    2011-08-15  [2011-08-18 00:00:00, 2011-09-22 00:00:00]                      2.0           2011-09-22 00:00:00
26  2       2011    2011-05-13  [2011-08-04 00:00:00, 2011-08-08 00:00:00, 2011-08-10 00:00:00  3.0           2011-08-04 00:00:00
27  2       2011    2011-05-13  [2011-08-04 00:00:00, 2011-08-08 00:00:00, 2011-08-10 00:00:00  3.0           2011-08-08 00:00:00
28  2       2011    2011-05-13  [2011-08-04 00:00:00, 2011-08-08 00:00:00, 2011-08-10 00:00:00  3.0           2011-08-10 00:00:00

所以基本想法是添加新列“相关冲击”,遍历每一行,如果“相关冲击”中有一个空列表,则保持不变,如果“相关冲击”中有一个日期,则保持不变,但是用那个列表条目填充新列“相关冲击”,如果它在“相关冲击”中有两个列表条目,则复制它,并分别用两个列表条目之一填充每一行中的“相关冲击”列,等等。

这可以用 Python 实现吗?

标签: pythonlistpandasdataframeduplicates

解决方案


编辑熊猫版本> = 0.25,一种新方法explode可以很容易地完成这项工作:

#first create a copy of the column
df['relevant shock'] = df['relevant shocks']
#explode the new column
df = df.explode('relevant shock').fillna('')
print (df)
#same result than the one below

旧答案

从“相关冲击”列中,您可以使用apply,pd.Seriesstack为每个日期创建一行,例如:

df['relevant shocks'].apply(pd.Series).stack()
Out[448]: 
23  0    2011-08-18 00:00:00
24  0    2011-08-18 00:00:00
    1    2011-09-22 00:00:00
25  0    2011-08-04 00:00:00
    1    2011-08-08 00:00:00
    2    2011-08-10 00:00:00
dtype: object

我知道一个空的丢失了,但是在你使用a和额外的列之后你join的结果。像这样:dfreset_indexfillnadropdf

df = pd.DataFrame({'quarter':[1,2,3,4],
                   'relevant shocks':[[],['2011-08-18 00:00:00'],
                      ['2011-08-18 00:00:00', '2011-09-22 00:00:00'],
                      ['2011-08-04 00:00:00', '2011-08-08 00:00:00', '2011-08-10 00:00:00']]},
                   index=[22,23,24,25])

然后你做:

df = (df.join(df['relevant shocks'].apply(pd.Series).stack()
                                   .reset_index(1,name='relevant shock'))
         .fillna('').drop('level_1',1))

你得到:

    quarter                                    relevant shocks  \
22        1                                                 []   
23        2                              [2011-08-18 00:00:00]   
24        3         [2011-08-18 00:00:00, 2011-09-22 00:00:00]   
24        3         [2011-08-18 00:00:00, 2011-09-22 00:00:00]   
25        4  [2011-08-04 00:00:00, 2011-08-08 00:00:00, 201...   
25        4  [2011-08-04 00:00:00, 2011-08-08 00:00:00, 201...   
25        4  [2011-08-04 00:00:00, 2011-08-08 00:00:00, 201...   

         relevant shock  
22                       
23  2011-08-18 00:00:00  
24  2011-08-18 00:00:00  
24  2011-09-22 00:00:00  
25  2011-08-04 00:00:00  
25  2011-08-08 00:00:00  
25  2011-08-10 00:00:00  

编辑:似乎对于真实数据,空列表发生错误,所以要解决它,reset_index最后:

df = (df.join(df.loc[df['relevant shocks'].str.len() > 0, 'relevant shocks']
                .apply(pd.Series).stack().reset_index(1,name='relevant shock'))
        .fillna('').drop('level_1',1).reset_index(drop=True))

推荐阅读