通过拆分键和减少值将pandas数据框保存到嵌套dict

时间:2017-03-26 08:03:29

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

尝试将pandas DataFrame转换为字典。具有to_dict选项的Pandas实用程序orient似乎不足以满足此情况。我目前的代码在某些情况下有用。

问题: 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},..

1 个答案:

答案 0 :(得分: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函数所示。它的工作原理非常简单:

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

那就是它。

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}}}}