Pandas DataFrame со вложенным словарем - PullRequest
1 голос
/ 22 октября 2019

После просмотра похожих вопросов по SO я не смог найти решения для форматирования DataFrame с помощью вложенного словаря до желаемого результата.

Будучи новичком в Pandas и в меру новичком в Python, я провел большую часть двух дней, пытаясь и терпя неудачу в различных потенциальных решениях ( json_normalize , уплощение словаря , pd.concat и т. Д.).

У меня есть метод, который создает DataFrame из вызова API:

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

, который пишет вложенный словарь из Pandasvalue_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

1 Ответ

1 голос
/ 22 октября 2019

Если у меня есть словарь 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})}
        })
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...