【问题标题】:How to merge Pandas DataFrame with dict of lists如何将 Pandas DataFrame 与列表的字典合并
【发布时间】:2019-04-28 01:21:03
【问题描述】:

像这样合并df 的最佳方法是什么:

+------------+----------+
| domain     | username |
+------------+----------+
| @gmail.com | gagaga   |
+------------+----------+
| @mail.com  | bobo     |
+------------+----------+

使用这样的字典:

domain_to_app = {
    '@gmail.com': ['gmail', 'youtube', 'gdrive'],
    '@mail.com': ['email', 'dropbox']
}

得到这个:

+------------+----------+-----------+
| domain     | username | app       |
+------------+----------+-----------+
| @gmail.com | gagaga   | gmail     |
+------------+----------+-----------+
| @gmail.com | gagaga   | youtube   |
+------------+----------+-----------+
| @gmail.com | gagaga   | gdrive    |
+------------+----------+-----------+
| @mail.com  | bobo     | email     |
+------------+----------+-----------+
| @mail.com  | bobo     | dropbox   |
+------------+----------+-----------+

是否建议将dict 转换为具有重复行的df 并使用merge,或者我应该使用map 然后unstack the app column

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    您可以将map 用于新的Series,然后将chain.from_iterablerepeat 用于新的DataFrame

    s = df['domain'].map(domain_to_app)
    
    from itertools import chain
    
    lens = s.str.len()
    df = pd.DataFrame({
        'domain' : df['domain'].values.repeat(lens),
        'username' : df['username'].values.repeat(lens),
         'app' : list(chain.from_iterable(s))
    })
    
    print (df)
           domain username      app
    0  @gmail.com   gagaga    gmail
    1  @gmail.com   gagaga  youtube
    2  @gmail.com   gagaga   gdrive
    3   @mail.com     bobo    email
    4   @mail.com     bobo  dropbox
    

    如果需要重复多个列,则从 mapped 值创建 DaatFrame,通过 stack 重塑并通过 join '重复':

    df['app'] = df['domain'].map(domain_to_app)
    
    df = (df.join(pd.DataFrame(df.pop('app')
                                .values.tolist())
                   .stack()
                   .reset_index(level=1, drop=True)
                   .rename('app'))).reset_index(drop=True)
    print (df)
           domain username      app
    0  @gmail.com   gagaga    gmail
    1  @gmail.com   gagaga  youtube
    2  @gmail.com   gagaga   gdrive
    3   @mail.com     bobo    email
    4   @mail.com     bobo  dropbox
    

    【讨论】:

    • 从来不知道你可以使用s.str.len() 来获取每个系列项目的长度,我一直在使用s.apply(len)
    • s.apply(len) 虽然快了大约 10%
    • @iamanigeeit - 是的,区别在于 .apply(len) 不能与 NaN 一起使用 :)
    • 嗯嗯好的。我以为s.str 只用于字符串操作。
    【解决方案2】:

    试试这个,

    df2= pd.DataFrame.from_dict(domain_to_app,orient='index').unstack().reset_index()
    result= pd.merge(df1,df2[df2[0].notnull()],left_on=['domain'],right_on=['level_1'])
    result=result[['domain','username',0]].rename(columns={0:'app'})
    print result
    

    输出:

           domain username      app
    0  @gmail.com   gagaga    gmail
    1  @gmail.com   gagaga  youtube
    2  @gmail.com   gagaga   gdrive
    3   @mail.com     bobo    email
    4   @mail.com     bobo  dropbox
    

    解释:

    从您的字典中创建数据框,执行pd.merge,然后根据需要清理数据框。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-10
      • 2021-11-10
      • 2021-04-26
      • 2023-03-11
      • 2016-04-01
      • 2018-09-07
      • 2014-01-05
      相关资源
      最近更新 更多