【问题标题】:Turning column of list of lists (of unequal length) into separate variable columns (python, pandas)将列表列表(长度不等)的列转换为单独的变量列(python,pandas)
【发布时间】:2022-08-21 11:41:34
【问题描述】:

我无法将一列列表列表转换为单独的列。我有一个糟糕的解决方案,它通过独立处理每一行然后将它们相互附加来工作,但这对于大约 500k 行来说花费的时间太长了。想知道是否有人有更好的解决方案。

这是输入:

>>> import pandas as pd 
>>> import numpy as np 
>>> pd.DataFrame({\'feat\': [[[\"str1\",\"\", 3], [\"str3\",\"\", 5], [\"str4\",\"\", 3]],[[\"str1\",\"\", 4], [\"str2\",\"\", 5]] ]})
feat
0 [[str1, , 3], [str3, , 5], [str4, , 3]]
1 [[str1, , 4], [str2, , 5]]

期望的输出:

>>> pd.DataFrame({\'str1\': [3, 4], \'str2\': [np.nan,5] , \'str3\': [5,np.nan], \'str4\': [3,np.nan]})
str1 str2 str3 str4
0 3 NaN 5 3
1 4 5 NaN NaN

更新:由@ifly6 解决!迄今为止最快的解决方案。对于 100k 行和 80 个总变量,我的机器所用的总时间为 8.9 秒。

  • 为什么您的列表中有所有这些空字符串?
  • @ifly6 只是部分数据,不太清楚为什么。它不是最重要的,但我只是为了完整性而将其包括在内。
  • 总而言之,在小数据集上快速的算法在大数据集上可能不一样。感谢所有答案和测量所花费的时间!

标签: python pandas list dataframe numpy


【解决方案1】:

加载您的df,创建df1,如下所示:

df1 = pd.DataFrame.from_records(df.explode('feat').values.flatten()).replace('', np.nan)
df1.index = df.explode('feat').index

从原始数据中对df1 设置索引以保留行标记(传递index=df.explode('feat').index 不起作用)。 (或者,要将列表分成列,可以使用df.explode('feat')['feat'].apply(pd.Series)。但是,我更喜欢避免apply,因此请改用DataFrame构造函数。)

df1 上重置索引,然后设置多索引(不能直接设置第 0 列索引,因为它会覆盖原始索引):

df1.reset_index().set_index(['index', 0])
# df1.set_index(0, append=True)  # alternatively should work

然后解压。您可以通过附加 .dropna(how='all', axis=1) 来删除全部为 NaN 的列,从而产生:

>>> df1.reset_index().set_index(['index', 0]).unstack().dropna(how='all', axis=1)
         2               
0     str1 str2 str3 str4
index                    
0      3.0  NaN  5.0  3.0
1      4.0  5.0  NaN  NaN

该解决方案还很大程度上避免了硬编码要查看或移动的特定列。

【讨论】:

  • 这是完美的,谢谢。并且是迄今为止最快的解决方案。感谢您的帮助 - 完成每个步骤并打印出中间输出以了解发生了什么是非常有启发性的。再次感谢
【解决方案2】:

这是一种方法

# explode the list to rows

df=df.explode('feat')

# remove the [] from the list, and split on ","
df[['col1','col3','col2']]=df['feat'].astype('str').replace('[\[\]]','', regex=True).str.split(',', expand=True)

# use pivot after reindexing
df=df.reset_index()
df.pivot(index='index', columns='col1', values='col2')
df
col1    'str1'  'str2'  'str3'  'str4'
index               
0         3       NaN      5      3
1         4         5    NaN    NaN

【讨论】:

    【解决方案3】:

    将您的嵌套列表转换为 pd.Series 可以解释的字典:

    df = df.feat.apply(lambda val: pd.Series({y[0]:y[2] for y in val}))
    df = df[df.columns.sort_values()]
    print(df)
    

    输出:

       str1  str2  str3  str4
    0   3.0   NaN   5.0   3.0
    1   4.0   5.0   NaN   NaN
    

    【讨论】:

      【解决方案4】:

      我的解决方案是使用df1.loc[i, col_name] 逐个单元格地构建新的df1 的蛮力方法。

      import pandas as pd
      
      df= pd.DataFrame({'feat': [[["str1","", 3], ["str3","", 5], ["str4","", 3]],[["str1","", 4], ["str2","", 5]] ]})
      df1 = pd.DataFrame()
      for i in range(df.shape[0]):
          for e in df.loc[i, 'feat']:
              df1.loc[i, e[0]] = e[2]
      print(df1)
      

      输出(不按列顺序):

         str1  str3  str4  str2
      0   3.0   5.0   3.0   NaN
      1   4.0   NaN   NaN   5.0
      

      所花费的时间是

      import timeit
      timeit.timeit('''
      import pandas as pd
      df= pd.DataFrame({'feat': [[["str1","", 3], ["str3","", 5], ["str4","", 3]],[["str1","", 4], ["str2","", 5]] ]})
      df1 = pd.DataFrame()
      for i in range(df.shape[0]):
          for e in df.loc[i, 'feat']:
              df1.loc[i, e[0]] = e[2]
      ''', number=10000)
      
      19.209370899999996
      

      所以 10K 运行大约需要 20 秒。我很想知道其他算法的表现如何。也请自行运行它,因为所花费的时间因不同的电脑.并且也随着不同的数据集.他们来了:

      #来自@ifly6 的回答

      import timeit
      timeit.timeit('''
      import pandas as pd
      import numpy as np
      df= pd.DataFrame({'feat': [[["str1","", 3], ["str3","", 5], ["str4","", 3]],[["str1","", 4], ["str2","", 5]] ]})
      df1 = pd.DataFrame.from_records(df.explode('feat').values.flatten()).replace('', np.nan)
      df1.index = df.explode('feat').index
      df1 = df1.reset_index().set_index(['index', 0]).unstack().dropna(how='all', axis=1)
      ''', number=10000)
      
      48.217678400000295
      

      #来自@Naveed 的回答

      import timeit
      timeit.timeit('''
      import pandas as pd
      df= pd.DataFrame({'feat': [[["str1","", 3], ["str3","", 5], ["str4","", 3]],[["str1","", 4], ["str2","", 5]] ]})
      df = df.explode('feat')
      df[['col1','col3','col2']] = df['feat'].astype('str').replace('[\[\]]','', regex=True).str.split(',', expand=True)
      df = df.reset_index()
      df = df.pivot(index='index', columns='col1', values='col2')
      ''', number=10000)
      
      34.94540550000056
      

      #来自@BeRT2me 的回答(不用df = df[df.columns.sort_values()] 重新排列列会更快)

      import timeit
      timeit.timeit('''
      import pandas as pd
      df= pd.DataFrame({'feat': [[["str1","", 3], ["str3","", 5], ["str4","", 3]],[["str1","", 4], ["str2","", 5]] ]})
      df = df.feat.apply(lambda val: pd.Series({y[0]:y[2] for y in val}))
      df = df[df.columns.sort_values()]
      ''', number=10000)
      
      12.745890199999849
      

      【讨论】:

      • 当我将观察次数增加到约 100k 时,@ifly6 的时间最快。我不知道重新运行它 n 次,但至少对于 100k 行的一次迭代,这是迄今为止最快的(<5 秒,而其他解决方案约为 1 分钟)
      • 哦,我认为 for-loop 和 .apply(lambda x) 对于大型数据集来说计算量很大。请您发布 100k 行所花费的时间作为答案吗?
      • 当然,将编辑原件!我只用了大约 9 秒就处理了 100k 行。
      猜你喜欢
      • 1970-01-01
      • 2018-08-14
      • 2021-10-07
      • 2017-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-15
      • 1970-01-01
      相关资源
      最近更新 更多