【问题标题】:Trying blend/merge column values across multiple rows into a single row尝试将多行中的列值混合/合并到单行中
【发布时间】:2020-01-31 20:52:33
【问题描述】:

我正在尝试使用 pandas 聚合一些数据,以便创建两个新列来存储来自原始数据集的值,以减少总行数。

例如

d = pd.DataFrame([['0001', None, 'backlog', '2020-01-15', '2020-01-31'], 
                  ['0001', 'backlog', 'complete', '2020-01-31', '9999-12-31'],
                  ['0001', 'backlog', 'complete', '2020-01-31', '9999-12-31'],
                  ['0002', None, 'backlog', '2019-02-15', '2019-02-25'], 
                  ['0002', None, 'backlog', '2019-02-15', '2019-02-25'],
                  ['0002', None, 'backlog', '2019-02-15', '2019-02-25'],
                  ['0002', None, 'backlog', '2019-02-15', '2019-02-25'],
                  ['0002', 'backlog', 'complete', '2019-02-25', '9999-12-31'],
                  ['0003', None, 'backlog', '2020-01-15', '2020-01-31'],
                  ['0003', None, 'backlog', '2020-01-15', '2020-01-31'],
                  ['0003', None, 'backlog', '2020-01-15', '2020-01-31'],
                  ['0003', 'backlog', 'modified', '2020-01-31', '2020-02-05'],
                  ['0003', 'modified', 'qe_backlog', '2020-02-05', '2020-02-20'],
                  ['0003', 'qe_backlog', 'verified', '2020-02-20', '9999-12-31']] ,
                 columns=['id', 'old_state', 'new_state', 'start_dttm', 'end_dttm'])

结果

      id   old_state   new_state  start_dttm    end_dttm
0   0001        None     backlog  2020-01-15  2020-01-31
1   0001     backlog    complete  2020-01-31  9999-12-31
2   0001     backlog    complete  2020-01-31  9999-12-31
3   0002        None     backlog  2019-02-15  2019-02-25
4   0002        None     backlog  2019-02-15  2019-02-25
5   0002        None     backlog  2019-02-15  2019-02-25
6   0002        None     backlog  2019-02-15  2019-02-25
7   0002     backlog    complete  2019-02-25  9999-12-31
8   0003        None     backlog  2020-01-15  2020-01-31
9   0003        None     backlog  2020-01-15  2020-01-31
10  0003        None     backlog  2020-01-15  2020-01-31
11  0003     backlog    modified  2020-01-31  2020-02-05
12  0003    modified  qe_backlog  2020-02-05  2020-02-20
13  0003  qe_backlog    verified  2020-02-20  9999-12-31

最后我想要的是:

id   state       backlog_dttm      completed_dttm  modified_dttm qe_backlog_dttm    verified_dttm
0001 complete     2020-01-15       2020-01-31           null            null       null 
0002 complete     2019-02-15       2019-02-25      null        null     null      null
0003 verified     2020-01-15       null            2020-01-31        2020-02-05        2020-02-20          

目前为止

d.drop_duplicates(subset=d.columns, keep='last', inplace=True)
d.set_index('id', inplace=True)

然后在这一点上,尝试设置 backlog_dttm,事情停止工作。

d2['backlog_dttm'] = d[d['old_state'].isnull() & (d['new_state'] == 'backlog')]['start_dttm']
d2 = d.loc[d['end_dttm'] == d.end_dttm.max()]
d2.loc[d2.index,'backlog_dttm'] = d[d['old_state'].isnull() & (d['new_state'] == 'backlog')]['start_dttm']
d2.loc[d2.index, 'completed_dttm'] = d[d['new_state'] == 'complete']['start_dttm']
d2.loc[d2.index, 'modified_dttm'] = d[d['new_state'] == 'modified']['start_dttm']
d2.loc[d2.index, 'qe_backlog_dttm'] = d[d['new_state'] == 'qe_backlog']['start_dttm']

上述结果会导致 SettingWithCopyWarning,但似乎有效。最终所需的输出应类似于以下内容:

       old_state new_state  start_dttm    end_dttm backlog_dttm  \
id                                                                
0001     backlog  complete  2020-01-31  9999-12-31   2020-01-15   
0002     backlog  complete  2019-02-25  9999-12-31   2019-02-15   
0003  qe_backlog  verified  2020-02-20  9999-12-31   2020-01-15   

     completed_dttm modified_dttm qe_backlog_dttm  
id                                                 
0001     2020-01-31           NaN             NaN  
0002     2019-02-25           NaN             NaN  
0003            NaN    2020-01-31      2020-02-05

作为一个仅供参考:这只是一个示例,真正的数据集基于开发工作流程,其中会有其他状态,如 ready_to_test、verified、in_progress 等......同样会有我需要填充的列这些状态也是如此,即verified_dttm,read_to_test_dttm..

start_dttm 和 end_dttm 字段用于标识记录进入给定状态的日期和离开该状态的日期。

感谢任何想法/建议。 -谢谢!

【问题讨论】:

    标签: python pandas dataframe merge blending


    【解决方案1】:

    您可以尝试使用DataFrame.groupbyDataFrame.unstack

    # find the most recent state for each id
    df1 = df.groupby('id').agg({'new_state':'last'})
    # find start dates for each new state by id and unstack into columns
    df2 = df.groupby(['id','new_state'])['start_dttm'].agg('first').unstack()
    # merge grouped dataframes together by id
    df = df1.join(df2).reset_index() 
    

    print(df)                                                                                                        
         id new_state     backlog    complete    modified  qe_backlog    verified
    0  0001  complete  2020-01-15  2020-01-31         NaN         NaN         NaN
    1  0002  complete  2019-02-15  2019-02-25         NaN         NaN         NaN
    2  0003  verified  2020-01-15         NaN  2020-01-31  2020-02-05  2020-02-20
    

    【讨论】:

      【解决方案2】:

      如果你只是想摆脱 SettingWithCopyWarning,你可以在添加列时指定索引

      d2.loc[d2.index,'backlog_dttm'] = d[d['old_state'].isnull() & (d['new_state'] == 'backlog')]['start_dttm']
      

      Kenan 的 hack 解决方案除了重命名列之外似乎效果很好。

      【讨论】:

        【解决方案3】:

        如果old_state[None, backlog]new_state[backlog, completed]

        你可以破解一个解决方案

        df[df['old_state'].isna()].assign(old_state='complete').drop('new_state', axis=1).rename(columns={'old_state': 'state', 'start_dttm': 'backlog_dttm', 'end_dttm': 'completed_dttm'})
        
             id     state backlog_dttm completed_dttm
        0  0001  complete   2020-01-15     2020-01-31
        2  0002  complete   2019-02-15     2019-02-25
        

        【讨论】:

        • 我要试试这个;然而,我的一个担忧是这只是一个样本数据集。实际数据集有超过 20 列,因此这种方法可能容易出现拼写错误。还有比我提到的更多的州。这是来自开发工程工作流程的数据,因此还有其他状态,例如 read to testverified,其中我还有一个名为 ready_for_test_dttm 和 verify_dttm 的列。
        • 是的,我以为我有一个很好的样本,直到我意识到我没有。
        • 完成,我相信我对数据有更准确的表示。
        猜你喜欢
        • 1970-01-01
        • 2011-09-15
        • 1970-01-01
        • 2012-01-09
        • 2018-10-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多