首页 > 解决方案 > 带有嵌套字典的 Pandas DataFrame

问题描述

在查看了关于SO的类似问题后,我一直无法找到使用嵌套字典对 DataFrame 格式化的解决方案以获得所需的结果。

作为 Pandas 的新手和 Python 的新手,我花了两天的大部分时间尝试各种潜在的解决方案(json_normalizedictionary flatteningpd.concat等),但都失败了。

我有一个从 API 调用创建 DataFrame 的方法:

def make_dataframes(self):
    # removed non-related code    
    self._data_frame_counts = pd.DataFrame({
            'Created': (self._data_frame_30days.count()['Created']),
            'Closed': (self._data_frame_30days.count()['Closed']),
            'Owner':
            (self._data_frame_30days['Owner'].value_counts().to_dict()),
            'Resolution':
            (self._data_frame_30days['Resolution'].value_counts().to_dict()),
            'Severity':
            (self._data_frame_30days['Severity'].value_counts().to_dict())
        })

从 Pandas value_count/s 写入嵌套字典:

{'Created': 35,
 'Closed': 6,
 'Owner': {'aName': 30, 'first.last': 3, 'last.first': 2},
 'Resolution': {'TruePositive': 5, 'FalsePositive': 1},
 'Severity': {2: 31, 3: 4}}

执行后的样子:

                  Created Closed  Owner  Resolution  Severity
aName             35       6     30.0         NaN       NaN
first.last        35       6      3.0         NaN       NaN
last.first        35       6      2.0         NaN       NaN
TruePositive      35       6      NaN         5.0       NaN
FalsePositive     35       6      NaN         1.0       NaN
2                 35       6      NaN         NaN      31.0
3                 35       6      NaN         NaN       4.0

我希望它看起来像下面这样。数据与轴准确对齐并说明字典中不存在但可能在未来运行中存在的缺失数据点。

                Created Closed  Owner   Resolution  Severity
total           35      6       NaN     NaN         NaN
aName           NaN     NaN     30      NaN         NaN
first.last      NaN     NaN     3       NaN         NaN
last.first      NaN     NaN     2       NaN         NaN
anotherName     NaN     NaN     NaN     NaN         NaN
1               NaN     NaN     NaN     NaN         0
2               NaN     NaN     NaN     NaN         31
3               NaN     NaN     NaN     NaN         4
second.Name     NaN     NaN     NaN     NaN         NaN
third.name      NaN     NaN     NaN     NaN         NaN
TruePositive    NaN     NaN     NaN     5           NaN
FalsePositive   NaN     NaN     NaN     1           NaN

标签: pythonpandasdataframe

解决方案


假设我有一本字典d

d = {
    'Created': 35,
    'Closed': 6,
    'Owner': {'aName': 30, 'first.last': 3, 'last.first': 2},
    'Resolution': {'TruePositive': 5, 'FalsePositive': 1},
    'Severity': {2: 31, 3: 4}
}

我会创建一些额外的键

_d = {
    'Created': {'total': d['Created']},
    'Closed': {'total': d['Closed']},
    'Severity': {k: d['Severity'].get(k, 0) for k in range(1, 4)}
}

pd.DataFrame({**d, **_d})

               Created  Closed  Owner  Resolution  Severity
total             35.0     6.0    NaN         NaN       NaN
aName              NaN     NaN   30.0         NaN       NaN
first.last         NaN     NaN    3.0         NaN       NaN
last.first         NaN     NaN    2.0         NaN       NaN
TruePositive       NaN     NaN    NaN         5.0       NaN
FalsePositive      NaN     NaN    NaN         1.0       NaN
1                  NaN     NaN    NaN         NaN       0.0
2                  NaN     NaN    NaN         NaN      31.0
3                  NaN     NaN    NaN         NaN       4.0

这是我更新一些密钥的方法,我们可以看到我做了什么:

print(_d)

{'Created': {'total': 35}, 'Closed': {'total': 6}, 'Severity': {0: 0, 2: 31, 3: 4}}

默认情况下,pandas.DataFrame构造函数可以使用字典并将键用作列名。它对值的作用取决于值。

  • 如果该值是一个标量,它会为所有索引值广播该标量。(这是您35在列中所有行的重复项中看到的内容'Created'
  • 如果该值是一个类似数组的东西,那么该东西的长度会更好地匹配行数,因为它将逐个元素地将该数组插入列中。
  • 如果值是一个字典,它会将每个键/值对映射到键是索引值的列中。

最后一项是我回答的动机。我将标量值更改为35指定索引值的字典{'total': 35}


我建议将原始方法更改为以下内容:

def make_dataframes(self):
    # removed non-related code    
    counts = self._data_frame_30days['Severity'].value_counts().to_dict()
    self._data_frame_counts = pd.DataFrame({
            'Created': {'total': self._data_frame_30days.count()['Created']},
            'Closed': {'total': self._data_frame_30days.count()['Closed']},
            'Owner':
            (self._data_frame_30days['Owner'].value_counts().to_dict()),
            'Resolution':
            (self._data_frame_30days['Resolution'].value_counts().to_dict()),
            'Severity': {k: counts.get(k, 0) for k in sorted({k, *counts})}
        })

推荐阅读