【问题标题】:How to make dictionary keys is one column of Pandas dataframe to the columns?如何使字典键是一列 Pandas 数据框的列?
【发布时间】:2019-12-21 08:15:57
【问题描述】:

我有一个数据框,其中一列包含包含字典的字符串化列表。我想知道如何从这些字典键中创建新列。

我正在寻找使用像 apply stack etc 这样的 pandas 方法的解决方案,并且尽可能不使用 FOR LOOP。

问题来了:

speakers = ['Einstein','Newton']
views = [1000,2000]
ratings0 = ("[{'id': 7, 'name': 'Funny', 'count': 100}, {'id': 1, 'name': 'Sad', "
 "'count': 110}, {'id': 9, 'name': 'Happy', 'count': 120}]")

ratings1 = ("[{'id': 7, 'name': 'Happy', 'count': 200}, {'id': 3, 'name': 'Funny', "
 "'count': 210}, {'id': 2, 'name': 'Sad', 'count': 220}]")


ratings = [ratings0, ratings1]
df = pd.DataFrame({'speaker': speakers, 'ratings': ratings,'views':views})

print(df)
speaker                                            ratings  views
0  Einstein  [{'id': 7, 'name': 'Funny', 'count': 100}, {'i...   1000
1    Newton  [{'id': 7, 'name': 'Happy', 'count': 200}, {'i...   2000

到目前为止我的尝试,

# new dataframe only for ratings
dfr = df['ratings'].apply(ast.literal_eval)
dfr = dfr.apply(pd.DataFrame)
dfr = dfr.apply(lambda x: x.sort_values(by='name'))
dfr = dfr.apply(pd.DataFrame.stack)

print(dfr)

 0               1               2          
  count id   name count id   name count id   name
0   100  7  Funny   110  1    Sad   120  9  Happy
1   200  7  Happy   210  3  Funny   220  2    Sad

这提供了多索引数据框。我尝试对字典进行排序,但仍然没有排序,name 列没有相同的值。另外,我不确定如何移动列 name 的值以替换列 count 并删除其他不需要的列。

最终通缉解决方案

speaker   views Funny Sad Happy
Einstein  1000 100   110 120  
Newton    2000 210   220 200

更新

我正在使用 Pandas 0.20,我的工作场所没有 .explode() 方法,并且不允许我更新 Pandas。

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    您可以使用sumindex.repeat 构造一个新的数据框并将其加入df[['speaker', 'views']] 并将其分配给df1。接下来是set_indexunstackreset_index

    df['ratings'] = df['ratings'].apply(ast.literal_eval)
    df1 = (pd.DataFrame(df.ratings.sum(), index=df.index.repeat(df.ratings.str.len()))
                       .drop('id', 1).join(df[['speaker', 'views']]))
    df1.set_index(['speaker', 'views', 'name'])['count'].unstack().reset_index()
    
    Out[213]:
    name   speaker  views  Funny  Happy  Sad
    0     Einstein  1000   100    120    110
    1     Newton    2000   210    200    220
    

    注意:最终输出中的name 是列轴的标签。如果你不想看到它,只需链接额外的rename_axis,如下所示

    df1.set_index(['speaker', 'views', 'name'])['count'].unstack().reset_index() \
                                                        .rename_axis([None], axis=1)
    
    Out[214]:
        speaker  views  Funny  Happy  Sad
    0  Einstein  1000   100    120    110
    1  Newton    2000   210    200    220
    

    【讨论】:

      【解决方案2】:

      For 循环并不总是坏事。你可以试试看:

      dfr = pd.DataFrame(columns=['id','name','count'])
      
      for i in range(len(df)):
          x = pd.DataFrame(df['ratings'].apply(ast.literal_eval)[i])
          x.index = [i]*len(x)
          dfr = dfr.append(x)
      
      
      dfr = dfr.reset_index()   
      dfr = (dfr.drop('id',axis=1)
               .pivot_table(index=['index'], columns='name',
                            values='count',aggfunc='sum')
               .rename_axis(None, axis=1).reset_index())
      
      df_final = df.join(dfr)
      df_final.drop(['index','ratings'],axis=1,inplace=True)
      
      df_final
      

      给予:

          speaker  views  Funny  Happy  Sad
      0  Einstein   1000    100    120  110
      1    Newton   2000    210    200  220
      

      【讨论】:

        【解决方案3】:

        对于pandas >= 0.25.0,您可以使用ast.literal_eval + explode + pivot

        ii = df.set_index('speaker')['ratings'].apply(ast.literal_eval).explode()
        
        u = pd.DataFrame(ii.tolist(), index=ii.index).reset_index()
        
        u.pivot('speaker', 'name', 'count')
        

        name      Funny  Happy  Sad
        speaker
        Einstein    100    120  110
        Newton      210    200  220
        

        对于旧版本的pandas

        a = df['speaker']
        b = df['ratings']
        
        ii = [
          {**{'speaker': name}, **row}
          for name, element in zip(a, b) for row in ast.literal_eval(element)
        ]
        
        pd.DataFrame(ii).pivot('speaker', 'name', 'count')
        

        【讨论】:

        • 我正在使用 pandas 0.20,很遗憾无法更新 pandas 并使用 .explode。
        • @astro123 发布了旧版本pandas 的版本,它甚至可能比第一个更快
        • 谢谢,这节省了我剩下的时间,我从上午 10 点到下午 3 点一直在尝试这个问题。
        • 如果我们还有一列 views = [1000,2000] 怎么办?对不起,我不能让它工作。
        • 将其包含在zip中,并制作第一个字典{'speaker': name, 'views': view}。您可能需要将 pivot_table 与多个 index 列一起使用
        猜你喜欢
        • 1970-01-01
        • 2023-04-10
        • 2016-05-03
        • 2021-02-13
        • 1970-01-01
        • 1970-01-01
        • 2017-09-12
        • 2016-06-13
        • 2019-01-05
        相关资源
        最近更新 更多