【问题标题】:Python Pandas: How to optimally compare each value of a dictionary with all other values?Python Pandas:如何以最佳方式将字典的每个值与所有其他值进行比较?
【发布时间】:2015-06-28 15:33:26
【问题描述】:

我有一个字典'orgs_dict',我想将每个值与所有值进行比较,因为我将所有值放在一个集合中,然后进行比较,如果它们相同,我添加它到“final_hosts”字典:

orgs_dict = {'Ridgway School': 'ridgway','Ridgway Uni': 'ridgway', 'Aktieselskapet': 'aktieselskapet','Aktieselskapet_1': 'aktieselskapet', 'Chinese Education Association Ex': 'chinese association ex', 'Gestora de Infraestructuras de Telecomunicaciones': 'gestora infraestructuras telecomunicaciones','Aktieselskapet_5': 'aktieselskapet'}

这是我的代码:

set_neworgs=set()
for key in orgs_dict.keys():
    set_neworgs.add(orgs_dict[key])

final_hosts = defaultdict(list)
for i in set_neworgs:
    for k,v in orgs_dict.items():
        if i == v:
            final_hosts[i].append(k) 

这很好,但是当我的 'orgs_dict' 非常大时,需要 3 个小时才能完成。我想知道有没有人知道更可选的方法?

【问题讨论】:

  • 所以您想根据是否有 2 个或更多重复项来过滤您的 dict?您的示例 dict 没有显示重复项,您关心键吗?
  • @EdChum 我编辑了示例字典。我想知道值相同的键。
  • 提示:set_neworgs = set(orgs_dict.keys())
  • @MrE 感谢也是一个很好的提示。我猜瓶颈更多的是在比较方面。您对此也有什么建议吗?

标签: python dictionary pandas comparison


【解决方案1】:

您可以使用键作为列'new_orgs',值作为'hosts'来构造一个df,然后使用value_counts() > 1作为布尔过滤器,然后使用isin过滤本系列中存在的主机:

In [150]:

orgs_dict = {'Ridgway School': 'ridgway','Ridgway Uni': 'ridgway', 'Aktieselskapet': 'aktieselskapet','Aktieselskapet_1': 'aktieselskapet', 'Chinese Education Association Ex': 'chinese association ex', 'Gestora de Infraestructuras de Telecomunicaciones': 'gestora infraestructuras telecomunicaciones','Aktieselskapet_5': 'aktieselskapet'}
df =pd.DataFrame({'new_orgs':list(orgs_dict.keys()), 'hosts':list(orgs_dict.values())})
df
Out[150]:
                                         hosts  \
0                               aktieselskapet   
1                                      ridgway   
2                               aktieselskapet   
3                                      ridgway   
4                       chinese association ex   
5  gestora infraestructuras telecomunicaciones   
6                               aktieselskapet   

                                            new_orgs  
0                                   Aktieselskapet_1  
1                                     Ridgway School  
2                                   Aktieselskapet_5  
3                                        Ridgway Uni  
4                   Chinese Education Association Ex  
5  Gestora de Infraestructuras de Telecomunicaciones  
6                                     Aktieselskapet  

In [157]:

df[df['hosts'].isin((df['hosts'].value_counts()[df['hosts'].value_counts()> 1].index))]
Out[157]:
            hosts          new_orgs
0  aktieselskapet  Aktieselskapet_1
1         ridgway    Ridgway School
2  aktieselskapet  Aktieselskapet_5
3         ridgway       Ridgway Uni
6  aktieselskapet    Aktieselskapet

另一种方法是 groupby 'host`,然后只计算 'new_orgs' 的数量并使用它来过滤:

In [167]:

df['host_count'] = df.groupby('hosts')['new_orgs'].transform('count')
df[df['host_count'] > 1]
Out[167]:
            hosts          new_orgs  host_count
0  aktieselskapet  Aktieselskapet_1           3
1         ridgway    Ridgway School           2
2  aktieselskapet  Aktieselskapet_5           3
3         ridgway       Ridgway Uni           2
6  aktieselskapet    Aktieselskapet           3

时间

在这个小样本集上我得到了

In [168]:

%%timeit
df['host_count'] = df.groupby('hosts')['new_orgs'].transform('count')
df[df['host_count'] > 1]
1000 loops, best of 3: 1.65 ms per loop

In [169]:

%timeit df[df['hosts'].isin((df['hosts'].value_counts()[df['hosts'].value_counts()> 1].index))]
1000 loops, best of 3: 1.49 ms per loop

所以差别不大,你现在的方法更快:

In [175]:

%%timeit
set_neworgs=set()
for key in orgs_dict.keys():
    set_neworgs.add(orgs_dict[key])
​
final_hosts = defaultdict(list)
for i in set_neworgs:
    for k,v in orgs_dict.items():
        if i == v:
            final_hosts[i].append(k) 
100000 loops, best of 3: 6.85 µs per loop

但是,它不能很好地扩展到您的实际数据集大小,而上述 2 种方法可以

【讨论】:

  • 感谢 EdChum,对数据有不同的看法,更适合熊猫。我刚刚尝试了第一种方法,在某些情况下,我仍然得到具有一个值的“主机”(而条件是 >1 )为什么认为会发生这种情况?
  • 您必须发布数据以便我可以重现它,groupby 方法有效吗?
  • 对不起,我犯了一个错误。他们都完美地工作。谢谢
  • EdChum 一个额外的问题。如果有一组字典而不是'orgs_dict',使用不同的键,比如:final_dict[key]=orgs_dict。我可以将你的代码放在 final_dict 中所有键的循环中吗?
  • 我要么为每个 dict 构造一个 df,然后 concat 它们全部,要么将所有 dicts 扁平化为一个 dict,然后从扁平化的 dict 构造一个 df
【解决方案2】:

Python 2.7+:值相同的键可以通过这个字典推导找到:

{k: orgs_dict[k] for k in orgs_dict  if orgs_dict.values().count(orgs_dict[k])>1}

Python 3.x:将orgs_dict.values() 包装在对list 的调用中:

{k: orgs_dict[k] for k in orgs_dict  if list(orgs_dict.values()).count(orgs_dict[k])>1}

输出:

{'Aktieselskapet_1': 'aktieselskapet', 'Ridgway School': 'ridgway', 'Aktieselskapet': 'aktieselskapet', 'Ridgway Uni': 'ridgway', 'Aktieselskapet_5': 'aktieselskapet'}

另一种方法: 在 2.7+ 和 3.x 中使用来自 collections 模块的 Counter:

from collections import Counter
c = Counter(orgs_dict.values()) # count values
{k : orgs_dict[k] for k in orgs_dict.keys() if c[orgs_dict[k]]>1}

【讨论】:

  • 我在这里看到的是值,而不是键
  • @Vidhya GAttributeError: 'dict_values' 对象没有属性 'count'。我正在寻找相同的值和键
  • @Vidhya 我的代码出现此错误 AttributeError: 'dict_values' object has no attribute 'count'
  • 我不确定您为什么会收到属性错误(我使用的是 Python 2.7.6)。我会更新,让你有钥匙。
  • 谢谢。因为我使用的是 Python 3.x
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多