namedtuples 的嵌套字典到 pandas 数据框
Nested dictionary of namedtuples to pandas 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)}}}
我正在尝试从字典 d 创建一个 pandas 数据框,而无需执行循环。
我已经通过这样做成功地从字典的一个子集创建了数据框:
In[40]: df=pd.DataFrame(d[1][None].values())
In[41]: df
Out[41]:
x y
0 1 5
1 4 8
但我希望能够从整个字典创建数据框。
我希望数据框输出以下内容(我使用的是多索引符号):
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
DataFrame的from_dict方法,最多只支持两层嵌套,所以没能使用。我也在考虑修改d字典的结构来达到我的目的。此外,也许它不一定是字典。
谢谢。
SO (here, here, or ) 上已经有几个类似问题的答案。这些解决方案也可以适用于这个问题。然而,其中 none 确实是一般的 运行 在任意指令上。所以我决定写一些更通用的东西。
这是一个可以在任何字典上 运行 的函数。 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")
为了通用性,我从这个问题中牺牲了一个 namedtuple 案例。但如果需要,可以对其进行调整。
在这种特殊情况下,可以按如下方式应用:
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
我决定将键压平成一个元组(使用 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
我已将命名元组定义如下:
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)}}}
我正在尝试从字典 d 创建一个 pandas 数据框,而无需执行循环。
我已经通过这样做成功地从字典的一个子集创建了数据框:
In[40]: df=pd.DataFrame(d[1][None].values())
In[41]: df
Out[41]:
x y
0 1 5
1 4 8
但我希望能够从整个字典创建数据框。
我希望数据框输出以下内容(我使用的是多索引符号):
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
DataFrame的from_dict方法,最多只支持两层嵌套,所以没能使用。我也在考虑修改d字典的结构来达到我的目的。此外,也许它不一定是字典。
谢谢。
SO (here, here, or
这是一个可以在任何字典上 运行 的函数。 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")
为了通用性,我从这个问题中牺牲了一个 namedtuple 案例。但如果需要,可以对其进行调整。
在这种特殊情况下,可以按如下方式应用:
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
我决定将键压平成一个元组(使用 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