2016-07-08 3 views
4

У меня есть namedtuples определена следующим образом:Вложенный словаря namedtuples для панды dataframe

In[37]: from collections import namedtuple 
     Point = namedtuple('Point', 'x y') 

вложенный словарь имеет следующий формат:

In[38]: d 
Out[38]: 
{1: {None: {1: Point(x=1.0, y=5.0), 2: Point(x=4.0, y=8.0)}}, 
2: {None: {1: Point(x=45324.0, y=24338.0), 2: Point(x=45.0, y=38.0)}}} 

Я пытаюсь создать панда dataframe из словаря d без необходимости делать для циклов.

мне удалось в создании dataframe из подмножества словаря, делая это:

In[40]: df=pd.DataFrame(d[1][None].values()) 

In[41]: df 

Out[41]: 
    x y 
0 1 5 
1 4 8 

Но я хочу, чтобы иметь возможность создать dataframe из всего словаря.

Я хочу dataframe для вывода следующего (я использую несколько индекса обозначение):

In[42]: df 
Out[42]: 
Subcase Step ID x  y 
1  None 1 1.0  5.0 
      2 4.0  8.0 
2  None 1 45324.0 24338.0 
      2 45.0 38.0 

Метод from_dict из DataFrame, поддерживает только до двух уровней вложенности, так что я не был в состоянии использовать Это. Я также рассматриваю возможность изменения структуры словаря d для достижения моей цели. Кроме того, возможно, это не должен быть словарь.

спасибо.

+0

Вы говорите, что это не обязательно должен быть dict - какой источник данных в dict? Или вы имели в виду преобразование dict в промежуточную структуру, прежде чем превращать его в dataframe? – Jeff

+0

Источник данных из двоичного файла. Он преобразуется в dict для удобства доступа и быстрого запроса. В идеале это будет диктовать. То, что я пытался сказать, это то, что я могу изменить код, который изменяет двоичный файл на dict, и использовать что-то более дружелюбное к pandas. Трансформирование дикта представляется неэффективным. – snowleopard

ответ

0

я решил сплющить ключи в кортеж (протестированы с использованием PANDAS 0.18.1):

In [5]: from collections import namedtuple 

In [6]: Point = namedtuple('Point', 'x y') 

In [11]: from collections import OrderedDict 

In [14]: d=OrderedDict() 

In [15]: d[(1,None,1)]=Point(x=1.0, y=5.0) 

In [16]: d[(1,None,2)]=Point(x=4.0, y=8.0) 

In [17]: d[(2,None,1)]=Point(x=45324.0, y=24338.0) 

In [18]: d[(2,None,2)]=Point(x=45.0, y=38.0) 

Наконец,

In [7]: import pandas as pd 

In [8]: df=pd.DataFrame(d.values(), index=pd.MultiIndex.from_tuples(d.keys(), names=['Subcase','Step','ID'])) 


In [9]:df 
Out[9]: 
         x  y 
Subcase Step ID     
1  NaN 1  1.0  5.0 
      2  4.0  8.0 
2  NaN 1 45324.0 24338.0 
      2  45.0  38.0 
1

Есть несколько ответов на подобные вопросы по SO (here, here, или here). Эти решения также могут быть адаптированы к этой проблеме. Тем не менее, ни один из них на самом деле не является генералом для произвольного диктата. Поэтому я решил написать нечто более универсальное.

Это функция, которая может работать на любом dict. У дикта должно быть одинаковое количество уровней (глубина) на любом из его элементов, иначе оно, скорее всего, будет расти.

def frame_from_dict(dic, depth=None, **kwargs): 
    def get_dict_depth(dic): 
     if not isinstance(dic, dict): 
      return 0 
     for v in dic.values(): 
      return get_dict_depth(v) + 1 

    if depth is None: 
     depth = get_dict_depth(dic) 

    if depth == 0: 
     return pd.Series(dic) 
    elif depth > 0: 
     keys = [] 
     vals = [] 
     for k, v in dic.items(): 
      keys.append(k) 
      vals.append(frame_from_dict(v, depth - 1)) 
     try: 
      keys = sorted(keys) 
     except TypeError: 
      # unorderable types 
      pass 
     return pd.concat(vals, axis=1, keys=keys, **kwargs) 

    raise ValueError("depth should be a nonnegative integer or None") 

Я пожертвовал именованным случаем из этого вопроса для общности. Но при необходимости он может быть изменен.

В данном конкретном случае он может быть применен следующим образом:

df = frame_from_dict(d, names=['Subcase', 'Step', 'ID']).T 
df.columns = ['x', 'y'] 
df 
Out[115]: 
         x  y 
Subcase Step ID     
1  NaN 1  1.0  5.0 
      2  4.0  8.0 
2  NaN 1 45324.0 24338.0 
      2  45.0  38.0 
+0

Спасибо за это, он работал как шарм. Я знал об этом решении, но я старался избегать использования для циклов, поскольку я могу контролировать, что такое определение словаря. Я решил свернуть ключи в кортеж. См. Решение ниже – snowleopard

+0

@snowleopard Я вижу. У вас есть общий метод сглаживания ключей вложенного словаря в кортежи? Я думал, что это проблема проблемы. – ptrj

+0

Да, вы правы, но я создаю словарь из двоичного файла, поэтому я могу контролировать, как определяется словарь. – snowleopard

Смежные вопросы