【问题标题】:pandas how to flatten a list in a column while keeping list ids for each element熊猫如何在保持每个元素的列表ID的同时展平列中的列表
【发布时间】:2019-02-04 20:32:23
【问题描述】:

我有以下df

 A                                                          id
[ObjectId('5abb6fab81c0')]                                  0
[ObjectId('5abb6fab81c3'),ObjectId('5abb6fab81c4')]         1
[ObjectId('5abb6fab81c2'),ObjectId('5abb6fab81c1')]         2

我喜欢将A 中的每个列表展平,并将其对应的id 分配给列表中的每个元素,例如,

 A                               id
 ObjectId('5abb6fab81c0')        0
 ObjectId('5abb6fab81c3')        1
 ObjectId('5abb6fab81c4')        1
 ObjectId('5abb6fab81c2')        2
 ObjectId('5abb6fab81c1')        2

【问题讨论】:

  • daiyue,出于好奇,我根据@Wen 的代码测试了我的代码,并将结果发布为对我答案的编辑。事实证明,我们的每个代码都根据您的输入数据进行了更优化,其中一个可能比另一个运行得更快!

标签: python-3.x pandas dataframe


【解决方案1】:

我认为评论来自这个问题?你可以使用我的original post 或这个

df.set_index('id').A.apply(pd.Series).stack().reset_index().drop('level_1',1)
Out[497]: 
   id    0
0   0  1.0
1   1  2.0
2   1  3.0
3   1  4.0
4   2  5.0
5   2  6.0

或者

pd.DataFrame({'id':df.id.repeat(df.A.str.len()),'A':df.A.sum()})
Out[498]: 
   A  id
0  1   0
1  2   1
1  3   1
1  4   1
2  5   2
2  6   2

【讨论】:

  • 就我而言,df.A 不是字符串列,所以我得到了AttributeError: Can only use .str accessor with string values, which use np.object_ dtype in pandas
  • @daiyue 那你能告诉我A列是什么类型的吗?
  • @daiyue 所以 [2,3,4] 这是 int 吗?您向我们展示的样本是否可以重现您的问题?
  • 编辑了我的操作,我的示例过于简单,我也尝试了解决方案 2,但收到错误 TypeError: unsupported operand type(s) for +: 'ObjectId' and 'ObjectId',但解决方案 1 运行良好。
  • 这是我在写答案时想象的魔法。干得好。
【解决方案2】:

这可能不是最优雅的解决方案,但它确实有效。这里的想法是遍历df(这就是为什么这可能是一个低效的解决方案),然后遍历A 列中的每个列表,将每个项目和id 附加到新列表中。然后将这两个新列表变成一个新的 DataFrame。

a_list = []
id_list = []
for index, a, i in df.itertuples():
    for item in a:
        a_list.append(item)
        id_list.append(i)
df1 = pd.DataFrame(list(zip(alist, idlist)), columns=['A', 'id'])

正如我所说,不优雅,但它完成了工作。可能至少有一种更好的方法来优化它,但希望它能让你继续前进。

编辑(2018 年 4 月 2 日)

出于好奇,我想在我的代码和 Wen 的代码之间进行时间比较。这两个变量是A 列的长度和A 列中列表条目的长度。我运行了一堆测试用例,每次都以数量级迭代。例如,我从 A 长度 = 10 开始,一直到 1,000,000,在每一步迭代随机的 A 条目列表长度为 1-10、1-100 ... 1-1,000,000。我发现了以下内容:

  • 总体而言,只要列表长度小于 ~1,000,我的代码就会明显更快(尤其是在增加 A 长度时)。只要随机列表长度达到~1,000 的障碍,Wen 的代码在速度上占了上风。这对我来说是一个巨大的惊喜!我完全预料到我的代码每次都会丢失。
  • A 列的长度通常无关紧要 - 它只是线性地增加了整体执行时间。它改变结果的唯一情况是Alength = 10。在这种情况下,无论列表长度如何,我的代码运行得更快(对我来说也很奇怪)。

结论:如果A 中的列表条目大约有几百个元素(或更少),那么我的代码就是要走的路。但是,如果您正在处理大量数据集,请使用 Wen's!还值得注意的是,当您达到 1,000,000 关口时,这两种方法都会大幅减慢。我正在使用一台功能相当强大的计算机,最后每台计算机都需要几分钟(它实际上在 A 长度 = 1,000,000 和列表长度 = 1,000,000 的情况下崩溃了)。

【讨论】:

    【解决方案3】:

    可以使用这个函数进行展平和去展

    def flatten(df, col):
        col_flat = pd.DataFrame([[i, x] for i, y in df[col].apply(list).iteritems() for x in y], columns=['I', col])
        col_flat = col_flat.set_index('I')
        df = df.drop(col, 1)
        df = df.merge(col_flat, left_index=True, right_index=True)
    
        return df
    

    展平:

    def unflatten(flat_df, col):
        flat_df.groupby(level=0).agg({**{c:'first' for c in flat_df.columns}, col: list})
    

    展开后,除了列顺序,我们得到相同的数据框:

    (df.sort_index(axis=1) == unflatten(flatten(df)).sort_index(axis=1)).all().all()
    >> True
    

    要创建唯一索引,您可以在展平后调用reset_index

    【讨论】:

      猜你喜欢
      • 2020-05-21
      • 1970-01-01
      • 2022-01-12
      • 2018-11-21
      • 2019-07-21
      • 2018-02-09
      • 1970-01-01
      • 2021-05-16
      • 2020-07-24
      相关资源
      最近更新 更多