【问题标题】:Iterate over rows and expand pandas dataframe遍历行并扩展 pandas 数据框
【发布时间】:2014-11-21 23:08:35
【问题描述】:

我的 pandas 数据框有一列包含值或值列表(长度不等)。我想“扩展”行,因此列表中的每个值都成为列中的单个值。一个例子说明了一切:

dfIn = pd.DataFrame({u'name': ['Tom', 'Jim', 'Claus'],
 u'location': ['Amsterdam', ['Berlin','Paris'], ['Antwerp','Barcelona','Pisa'] ]})

    location     name
0   Amsterdam   Tom
1   [Berlin, Paris] Jim
2   [Antwerp, Barcelona, Pisa]  Claus

我想变成:

dfOut = pd.DataFrame({u'name': ['Tom', 'Jim', 'Jim', 'Claus','Claus','Claus'],
u'location': ['Amsterdam', 'Berlin','Paris', 'Antwerp','Barcelona','Pisa']})

    location     name
0   Amsterdam   Tom
1   Berlin   Jim
2   Paris   Jim
3   Antwerp Claus
4   Barcelona   Claus
5   Pisa    Claus

我第一次尝试使用 apply 但据我所知不可能返回多个系列。 iterrows 似乎是诀窍。但是下面的代码给了我一个空的数据框...

def duplicator(series):
    if type(series['location']) == list:
        for location in series['location']:
            subSeries = series
            subSeries['location'] = location
            dfOut.append(subSeries)
    else:
        dfOut.append(series)

for index, row in dfIn.iterrows():
    duplicator(row)

【问题讨论】:

    标签: python loops pandas


    【解决方案1】:
    import pandas as pd
    
    
    dfIn = pd.DataFrame({
        u'name': ['Tom', 'Jim', 'Claus'],
        u'location': ['Amsterdam', ['Berlin','Paris'], ['Antwerp','Barcelona','Pisa'] ],
    })
    
    print(dfIn.explode('location'))
    
    >>>
        name   location
    0    Tom  Amsterdam
    1    Jim     Berlin
    1    Jim      Paris
    2  Claus    Antwerp
    2  Claus  Barcelona
    2  Claus       Pisa
    

    【讨论】:

      【解决方案2】:

      没有那么多有趣/花哨的 pandas 用法,但这很有效:

      import numpy as np
      dfIn.loc[:, 'location'] = dfIn.location.apply(np.atleast_1d)
      all_locations = np.hstack(dfIn.location)
      all_names = np.hstack([[n]*len(l) for n, l in dfIn[['name', 'location']].values])
      dfOut = pd.DataFrame({'location':all_locations, 'name':all_names})
      

      它比 apply/stack/reindex 方法快大约 40 倍。据我所知,该比率几乎适用于所有数据框大小(没有测试它如何随每行列表的大小缩放)。如果您可以保证所有 location 条目都是可迭代的,则可以删除 atleast_1d 调用,这样可以再提高 20% 的速度。

      【讨论】:

      • 这个方案比较优雅。
      【解决方案3】:

      如果您返回一个系列,其index 是一个位置列表,那么dfIn.apply 会将这些系列整理到一个表格中:

      import pandas as pd
      dfIn = pd.DataFrame({u'name': ['Tom', 'Jim', 'Claus'],
                           u'location': ['Amsterdam', ['Berlin','Paris'],
                                         ['Antwerp','Barcelona','Pisa'] ]})
      
      def expand(row):
          locations = row['location'] if isinstance(row['location'], list) else [row['location']]
          s = pd.Series(row['name'], index=list(set(locations)))
          return s
      
      In [156]: dfIn.apply(expand, axis=1)
      Out[156]: 
        Amsterdam Antwerp Barcelona Berlin Paris   Pisa
      0       Tom     NaN       NaN    NaN   NaN    NaN
      1       NaN     NaN       NaN    Jim   Jim    NaN
      2       NaN   Claus     Claus    NaN   NaN  Claus
      

      然后你可以堆叠这个DataFrame来获得:

      In [157]: dfIn.apply(expand, axis=1).stack()
      Out[157]: 
      0  Amsterdam      Tom
      1  Berlin         Jim
         Paris          Jim
      2  Antwerp      Claus
         Barcelona    Claus
         Pisa         Claus
      dtype: object
      

      这是一个系列,而您需要一个 DataFrame。用reset_index 稍微按摩一下就能得到想要的结果:

      dfOut = dfIn.apply(expand, axis=1).stack()
      dfOut = dfOut.to_frame().reset_index(level=1, drop=False)
      dfOut.columns = ['location', 'name']
      dfOut.reset_index(drop=True, inplace=True)
      print(dfOut)
      

      产量

          location   name
      0  Amsterdam    Tom
      1     Berlin    Jim
      2      Paris    Jim
      3  Amsterdam  Claus
      4    Antwerp  Claus
      5  Barcelona  Claus
      

      【讨论】:

      • 我收到一个错误可能是因为奇怪的数据(这可能是由某些列表中的空值引起的吗?):InvalidIndexError: Reindexing only valid with unique value Index objects
      • 如果您的位置列表之一包含重复项,则可能会发生这种情况。您希望如何处理重复的位置(对于同一个人)?
      • 重复值应被“合并”(例如,结果中应仅保留 1),应忽略空值。
      • 我已将 index=locations 更改为 index=list(set(locations))。这将删除重复项。
      猜你喜欢
      • 2018-09-26
      • 1970-01-01
      • 2022-01-20
      • 2021-04-05
      • 1970-01-01
      • 2018-10-28
      • 2017-08-30
      • 1970-01-01
      • 2017-10-23
      相关资源
      最近更新 更多