【问题标题】:save pandas data frame to nested dict by splitting keys and reducing values通过拆分键和减少值将熊猫数据框保存到嵌套字典
【发布时间】:2017-08-18 23:35:59
【问题描述】:

试图将 pandas DataFrame 转换为字典。 Pandas 实用程序 to_dictorient 选项似乎不足以解决这种情况。我当前的代码在某些情况下有效。

问题: 1. 有什么建议可以修改当前代码以使其看起来更优雅并且可能更快? 2.如何在这个场景中添加递归,使其适用于任意级别的嵌套。

fs = {'b1':{'f:ban':6, 'f:app':4}, 'b2':{'f:ban':4, 'f:app':2}}
dF = pandas.DataFrame.from_dict(fs, orient='index')
pandas.DataFrame.to_dict(dF, orient='index')
>>>{'b1': {'f:app': 4, 'f:ban': 6}, 'b2': {'f:app': 2, 'f:ban': 4}}

我希望它像这样存储,拆分键并分组/减少值:

{'b1': {'f': {'app': 4, 'ban': 6}}, 'b2': {'f': {'app': 2, 'ban': 4}}

我的代码适用于这种级别的嵌套,但是,可能有一种简洁的方法可以做到这一点。

原词典:

fruits = {'b1': {'f:app': 4, 'f:ban': 6}, 'b2': {'f:app': 2, 'f:ban': 4}}

首先定义一个辅助函数以从平面列表创建嵌套字典:

def create_nested_dict(L):
    if len(L) == 2:
        return {L[0]:L[1]}
    while len(L) > 2:
        d = {}
        key = L[0]
        L = L[1:]
        d.update({key:create_nested_dict(L)})
        return d

L = ['f', 'app','4']
create_nested_dict(L)
>>> {'f': {'app': '4'}}

然后使用上面的函数

new_fruits = {}
for key in fruits.keys():
    _d = {key:{}}
    for k,v in fruits[key].items():
        L = k.split(':')
        N = create_nested_dict(L + [v])
        if list(N)[0] in list(_d[key]):
            _d[key][list(N)[0]].update(N[list(N)[0]])
        else:
            _d[key].update(N)
new_fruits.update(_d)

print (new_fruits)
>>> {'b1': {'f': {'app': 4, 'ban': 6}}, 'b2': {'f': {'app': 2, 'ban': 4}}}

我的代码在以下情况下失败。注意额外的嵌套层次

fruits = {'b1': {'f:app:sim': 4, 'f:app:del': 3, 'f:ban:del': 6}, 'b2': {'f:app:sim': 2, 'f:app:del': 5, 'f:ban:del': 4}}
>>> {'b1': {'f': {'app': {'sim': 4}, 'ban': {'del': 6}}}, 'b2': {'f': {'app': {'sim': 2}, 'ban': {'del': 4}}}}

缺少一个键:值对 ...{'app': {'del': 3},..

【问题讨论】:

    标签: python python-3.x pandas dictionary recursion


    【解决方案1】:

    这是解决问题的递归方法:

    首先,将嵌套字典的键转换为可用于递归嵌套函数。为此,tuplize 只需创建一个新字典,其键是元组,而不是带有 : 分隔符的字符串:

    fruits = {'b1': {'f:app:sim': 4, 'f:app:del': 3, 'f:ban:del': 6}, 
              'b2': {'f:app:sim': 2, 'f:app:del': 5, 'f:ban:del': 4}}
    
    def tuplize(to_tuplize):
        return {tuple(keys.split(":")): value 
                for keys, value in to_tuplize.items()}
    
    tupled = tuplize(fruits["b1"])
    print(tupled)
    
    >>> {('f', 'ban', 'del'): 6, ('f', 'app', 'sim'): 4, ('f', 'app', 'del'): 3}
    

    第二,以递归方式处理tupled的每一项,如nest_dict函数所示。它的工作原理非常简单:

    • 如果您的元组密钥链中只剩下一个密钥,请设置一个值。
    • 否则,将元组密钥链的其余部分传递给当前密钥下的递归函数,并处理现有密钥的可能性。

    就是这样。

    def nest_dict(to_nest, nested=None):
        if nested is None:
            nested = {}
    
        for keys, value in to_nest.items():
            first_key = keys[0]
            if len(keys)== 1:
                nested[first_key] = value
                continue
    
            if first_key in nested:
                nest_dict({keys[1:]: value}, nested[first_key])
            else:
                nested[first_key] = nest_dict({keys[1:]: value})
    
        return nested
    
    print(nest_dict(tupled))
    >>> {'f': {'app': {'del': 3, 'sim': 4}, 'ban': {'del': 6}}}
    

    最后,您可以在字典理解中结合使用这两个辅助函数来获得所需的格式:

    result = {key: nest_dict(tuplize(value))
              for key, value in fruits.items()}
    print(result)
    
    >>> {'b1': {'f': {'app': {'del': 3, 'sim': 4}, 'ban': {'del': 6}}},
         'b2': {'f': {'app': {'del': 5, 'sim': 2}, 'ban': {'del': 4}}}}
    

    【讨论】:

      猜你喜欢
      • 2016-12-17
      • 2023-03-23
      • 2018-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-17
      • 2021-02-15
      相关资源
      最近更新 更多