【问题标题】:pandas: grouping by key to cluster messy stringspandas:按键分组以聚集杂乱的字符串
【发布时间】:2017-06-06 07:26:58
【问题描述】:

我有一张如下所示的表格:

company_id,company_name
1,Amazon
1,Amazon Ltd
2,Google
1,Amazon
2,Gogle
3,Facebook Ltd
3,Facebook LTD
1,AMAZON
1,AMAZON LTD
2,GOOGLE
3,Facebook
3,Face book

所以我对每家公司都有一个唯一的标识符,但它们的文本表示不同。我努力的是消除这些不一致的地方,并有一些类似的东西:

company_id,company_name
1,Amazon
1,Amazon
2,Google
1,Amazon
2,Google
3,Facebook
3,Facebook
1,Amazon
1,Amazon
2,Google
3,Facebook
3,Facebook

我对选择标准没有死心——它可以是所述组中最常见的值,也可以是随机值。但我需要的是高效的,因为我的表已经增长到包含数百万行。

我的解决方案是创建 id -> name 的独特组合的哈希映射,然后根据这些组合进行替换。大致如下:

dd = df.drop_duplicates().set_index('company_id').to_dict()['company_name']
df.company_name = df.company_id
df.company_name = df.company_name.replace(dd)

这在较小的集合上工作得很好,但由于它创建的哈希映射很大,它变得相当慢并且内存效率低。

我还尝试了基于company_id 的groupby 并将每个组中的所有company_names 替换为随机值,但我无法修改底层数据帧(没有.locing它,这是双重低效的)。

想到的最后一个选项是创建一个具有唯一值 (df.drop_duplicates('company_id')) 的单独框架,并将其与基于 company_id 的原始框架合并,但这听起来也不是很有效。

【问题讨论】:

  • 您的解决方案对我来说似乎很好。 df.company_name = df.company_name.replace(dd) 在这里而不是 replace 如果你使用 map 它会快很多。但是,无论如何您都需要这些对,所以我不知道您将如何解决内存问题。你确定这是个问题?你有多少个唯一标识符?
  • 您不需要.loc 将它们重新分配回底层DF。 Groupby.transform 会处理的。

标签: python pandas data-cleaning


【解决方案1】:

我已经使用 map 在一个相当大的 DataFrame 上测试了您的解决方案,它看起来非常有效:

prng = np.random.RandomState(0)
df = pd.DataFrame({'company_id': prng.randint(10**6, size=10**7), 
                   'company_name': prng.rand(10**7).astype('str')})
# It has 10m unique identifiers each having 10 entries on average
# ranges from 1 to 28.

df.head()
   company_id         company_name
0      985772   0.4097176168442743
1      305711    0.506659503051052
2      435829  0.45049621797963846
3      117952  0.21756825314220174
4      963395  0.07977409062048224

现在您可以在 company_id 和该 ID 的第一次出现的 company_name 之间创建一个映射器:

%%timeit
mapper = df.drop_duplicates(subset='company_id').set_index('company_id')['company_name']
df['company_id'].map(mapper)
1 loop, best of 3: 1.86 s per loop

作为Nickil Maveli mentioned,transform 也是可能的,尽管我创建的这个特定数据集的性能不如地图:

%timeit df.groupby('company_id')['company_name'].transform('first')
1 loop, best of 3: 2.33 s per loop

.loc 看起来效率很低:

%timeit df.groupby('company_id').first().loc[df.company_id]
1 loop, best of 3: 26.4 s per loop

一般来说,对此类数据使用分类可能会更好。请参阅另一个讨论 here。

【讨论】:

    【解决方案2】:

    您可以按company_id 分组并访问公司ID:

    df.groupby('company_id').first().loc[df.company_id]
    

    结果:

    如果你想作为一列,重置索引:

    df.groupby('company_id').first().loc[df.company_id].reset_index()
    

    结果:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-16
      • 1970-01-01
      • 1970-01-01
      • 2019-08-22
      • 1970-01-01
      相关资源
      最近更新 更多