【问题标题】:Grouping by similar lists in a column within a dataframe按数据框中列中的相似列表分组
【发布时间】:2021-08-18 10:50:14
【问题描述】:

我有一个包含一列列表的数据框。 我想对具有相似列表的行进行分组,而不考虑列表中项目的顺序。每个列表可以在列中出现多次。我希望根据列中出现的次数对分组列表进行排序。

data = [['a', ['tiger', 'cat', 'lion']], ['b', ['dolphin', 'goldfish', 'shark']], ['c', ['lion', 'cat', 'tiger']], ['d', ['bee', 'cat', 'tiger']],\
       ['e', ['cat', 'lion', 'tiger']],  ['f', ['cat', 'bee', 'tiger']], ['g', ['shark', 'goldfish', 'dolphin']]]
df = pd.DataFrame(data)
df.columns = ['ID', 'animals']
df
   ID   animals
0   a   [tiger, cat, lion]
1   b   [dolphin, goldfish, shark]
2   c   [lion, cat, tiger]
3   d   [bee, cat, tiger]
4   e   [cat, lion, tiger]
5   f   [cat, bee, tiger]
6   g   [shark, goldfish, dolphin]

我想对上述数据框中的类似列表进行分组。列表中动物的顺序可以不同。 我目前正在使用以下代码来执行此操作:

import collections as cs
animals_grouped = pd.DataFrame()
for q in range(len(df)):
    for r in range(len(df)):
        if (cs.Counter(df.iloc[q]['animals']) == cs.Counter(df.iloc[r]['animals'])):
            animals_grouped = animals_grouped.append(df.iloc[[r]], ignore_index = True)
            
animals_grouped.drop_duplicates('ID').reset_index(drop = True)

结果:

animals_grouped

    ID  animals
0   a   [tiger, cat, lion]
1   c   [lion, cat, tiger]
2   e   [cat, lion, tiger]
3   b   [dolphin, goldfish, shark]
4   g   [shark, goldfish, dolphin]
5   d   [bee, cat, tiger]
6   f   [cat, bee, tiger

考虑到我的原始数据框中有 100,000 多行,这个嵌套 for 循环的替代方法是什么。

【问题讨论】:

  • 您考虑过使用DataFrame.groupby 方法吗?你想对每个组执行什么功能?
  • 这些列表有多长,如果相似,动物是否总是以相同的大小写拼写顺序出现?
  • @Tabaraei pandas groupby 的性能也会很糟糕,因为关键是 python 列表对象。如果这些列表可以转换为字节串数组(当然,它们必须足够小),它可能会有所帮助。要考虑的另一件事是有多少个唯一列表。如果可以将列表“按摩”成易于散列的列,则 pandas groupby 应该可以正常工作。
  • @luthervespers 列表有 3 个项目。动物不能以任何顺序出现,分组时动物的顺序无关紧要。拼写相同,但大小写并不总是相同。

标签: python pandas list dataframe nested-loops


【解决方案1】:
data = [['a', ['tiger', 'cat', 'lion']], ['b', ['dolphin', 'goldfish', 'shark']], ['c', ['lion', 'cat', 'tiger']], ['d', ['bee', 'cat', 'tiger']],\
       ['e', ['cat', 'lion', 'tiger']],  ['f', ['cat', 'bee', 'tiger']], ['g', ['shark', 'goldfish', 'dolphin']]]
df = pd.DataFrame(data)
df.columns = ['ID', 'animals']
df1 = df.assign(temp=df.animals.apply(lambda x: ''.join(sorted(x))))
df = df1.assign(temp2 =df1.groupby(df1['temp'].values)['temp'].transform('count')).sort_values(['temp2','temp'], ascending=False).drop(['temp','temp2'], 1)

输出:

  ID                     animals
0  a          [tiger, cat, lion]
2  c          [lion, cat, tiger]
4  e          [cat, lion, tiger]
1  b  [dolphin, goldfish, shark]
6  g  [shark, goldfish, dolphin]
3  d           [bee, cat, tiger]
5  f           [cat, bee, tiger]

【讨论】:

  • 我认为这考虑了列表中项目的顺序。列表中项目的顺序无关紧要。
  • @vikingd。查看更新的答案。如果您想反向排序,请将ascending=False 更改为True
  • 我用更新的数据框尝试了你的代码。 data = [['a', ['tiger', 'cat', 'lion']], ['b', ['dolphin', 'goldfish', 'shark']], ['c', ['lion', 'cat', 'tiger']], ['d', ['bee', 'cat', 'tiger']], \ ['e', ['cat', 'lion', 'tiger']], ['f', ['cat', 'bee', 'tiger']], ['g', ['shark', 'goldfish', 'dolphin']]] df = pd.DataFrame(data) df.columns = ['ID', 'animals'] 这不考虑多个列表出现相同次数的情况。
  • @vikingd 你现在可以检查一下吗?
【解决方案2】:

您可以通过对列表进行排序、对 df 进行排序然后将其删除来创建临时排序键。

(
    df.assign(sort_key = df.animals.apply(sorted))
    .sort_values('sort_key')
    .drop('sort_key', axis=1)
)

    ID  animals
0   a   [cat, lion, tiger]
2   c   [cat, lion, tiger]
1   b   [dolphin, goldfish, shark]

【讨论】:

  • 我已将问题编辑得更准确。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-26
  • 2020-11-05
  • 1970-01-01
  • 2022-01-13
  • 2021-10-12
  • 2022-06-11
相关资源
最近更新 更多