【问题标题】:Convert pandas dictionary to a multi key dictionary where key order is irrelevant将 pandas 字典转换为与键顺序无关的多键字典
【发布时间】:2022-01-25 08:31:14
【问题描述】:

我想将 pandas 数据框转换为多键字典,使用 2 列或更多列作为字典键,并且我希望这些键与顺序无关。

以下是将 pandas 字典转换为常规多键字典的示例,其中顺序是相关的。

import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randint(0,100,size=(5, 3)), columns=list('ABC'))

df_dict = df.set_index(['B', 'C']).to_dict()['A']
print(df_dict)
{(33, 21): 85, (61, 46): 88, (78, 12): 48, (89, 18): 65, (91, 19): 41}

所以df_dict[(33, 21)] 将得到85,但df_dict[(21, 33)] 将导致密钥错误。

潜在的解决方案

这是一个 SO 问题,涵盖了使用 sorted、tuple、Counter 和/或 freezeset 制作与订单无关的字典的方法。

Multiples-keys dictionary where key order doesn't matter

但是,在我使用 Pandas 转换方法中使用这些数据类型和函数时,没有明显的解决方案。

下一个想法是在数据帧转换后转换字典键。

我试过了

new_d = {frozenset(key): value for key, value in df_dict}

但是出现了这个错误

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-49-6a3244440ac2> in <module>()
----> 1 new_d = {frozenset(key): value for key, value in df_dict}
      2 new_d

<ipython-input-49-6a3244440ac2> in <dictcomp>(.0)
----> 1 new_d = {frozenset(key): value for key, value in df_dict}
      2 new_d

TypeError: 'int' object is not iterable

【问题讨论】:

    标签: python pandas dataframe dictionary


    【解决方案1】:

    您忘记循环遍历 df_dict.items() 而不仅仅是 df_dict ;)

    >>> new_d = {frozenset(key): value for key, value in df_dict.items()}
    >>> new_d
    {frozenset({10, 99}): 92,
     frozenset({60, 76}): 54,
     frozenset({6, 20}): 31,
     frozenset({36, 46}): 31,
     frozenset({3, 68}): 59}
    
    >>> new_d[frozenset({99, 10})]
    92
    

    奖励:由于使用frozenset({...}) 访问所有内容令人毛骨悚然,因此我编写了一个小包装类以使其更容易:

    >>> class Test:
    ...     def __init__(self, fs):
    ...         self.fs = fs
    ...     def __getitem__(self, key):
    ...         return self.fs[frozenset(key)]
    ...     def __setitem__(self, key, val):
    ...         self.fs[frozenset(key)] = val
    ...     def __repr__(self):
    ...         import re
    ...         return re.sub(r'frozenset\({(.+?)}\)', r'(\1)', self.fs.__repr__())
    ...     __str__ = __repr__
    
    >>> new_d = Test(new_d)
    >>> new_d
    {(10, 99): 92, (76, 60): 54, (20, 6): 31, (36, 46): 31, (3, 68): 59}
    
    # Internally still just a dict of frozensets:
    >>> new_d.fs
    {frozenset({10, 99}): 92,
     frozenset({60, 76}): 54,
     frozenset({6, 20}): 31,
     frozenset({36, 46}): 31,
     frozenset({3, 68}): 59}
    
    >>> new_d[10, 99]
    92
    
    >>> new_d[99, 10]
    92
    
    >>> new_d[99, 10] = 123456789
    
    >>> new_d[10, 99]
    123456789
    

    【讨论】:

      【解决方案2】:

      为什么不从 df 创建

      d = dict(zip(df[['B', 'C']].apply(frozenset,1),df['A']))
      d
      {frozenset({72, 12}): 34, frozenset({98, 76}): 82, frozenset({67, 7}): 35, frozenset({60, 70}): 18, frozenset({8, 53}): 81}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-06-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-02
        • 2022-01-11
        相关资源
        最近更新 更多