Свести вложенный список / массив DataFrame с дополнительными индексными ключами (для временных рядов) - PullRequest
0 голосов
/ 05 февраля 2019

У меня есть DataFrame, структурированный следующим образом.(Это результат нормализации JSON)

mydf

id    colA    colB    ...    colArray
foo   a1      b1             [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]
bar   a2      b2             [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]
fooz  a3      b3             [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]
barz  a4      b4             [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]
  • date являются временными метками
  • каждый массив в строках colArray имеет разную длину, но точно такой же массивструктура элемента
  • ['id', 'colA', 'colB'] является примером столбцов, которые я хотел бы использовать в качестве уникальных индексов

Я хотел бы преобразовать эти данные, чтобы использовать их в качестве временных рядов.Мой желаемый результат будет выглядеть примерно так:

id    colA    colB    ...    date               data1    data2 ... data n
foo   a1      b1             '1st timestamp'   'flex'   0.1
foo   a1      b1             '...'   
...
foo   a1      b1             'last_timestamp'   
bar   a2      b2             '1st timestamp'   'zorg'
bar   a2      b2             '...'   
...   
bar   a2      b2             'last_timestamp'   
fooz  a3      b3             '...'   
fooz  a3      b3             '...'   
...
fooz  a3      b3             '...'   
etc.

Это позволит мне построить / проанализировать временные ряды на основе таких кортежей, как [foo, a1, b1]

Для меня это выглядит очень похоже на Сглаживает вложенный файл данных pandas , но принятый ответ разочаровывает: данные JSON / dict действительно не обрабатываются для создания DataFrame с правильными данными.


Есть ли у кого-нибудь какие-либо рекомендации поКак этого добиться?


Первый подход

Используйте следующее, что близко к тому, что я хочу:

tmpdf = pd.DataFrame(mydf['colArray'].tolist())
json_normalize(tmpdf[0])

Но есть 2 проблемы:

  1. Я потерял ['id', 'colA', 'colB'] кортеж, который я хотел бы использовать в качестве уникального идентификатора.
  2. Мне нужно выполнить операцию для каждой строки моего tmpdf

Второй метод

На основе Доступ к вложенным данным JSON как к фреймам данных в Pandas

pd.concat(pd.DataFrame.from_dict(tmp_array) for array in mydf['colArray'])

Он дает мне фрейм данных со всеми уплощенными массивами, правильные имена столбцов, но я потерял соответствующие ключи (['id', 'colA', 'colB']).Я чувствую, что это правильный подход, но я не могу понять, как продолжать индексировать столбцы (чтобы я мог фильтровать каждый результирующий временной ряд по индексам столбцов).

Жаль, что нет функции "json_melt"

Третий метод

На основании этого вопроса Свести вложенный pandas dataframe .Я могу сохранить свои столбцы индексации, но элементы массива все еще находятся в JSON и индексируются как [0, 1, 2, ...].У меня будут проблемы с переменной длиной (много NA для более высоких значений индексов столбцов


Библиография: Создание Pandas DataFrame из глубоко вложенного JSON Но решение основано нана исходной обработке JSON, тогда как я хотел бы сделать это на существующем DataFrame

Доступ к вложенным данным JSON как к фреймам данных в Pandas Это довольно близко к тому, что я хочу.

Выравнивание вложенного pandas-фрейма данных Результат выглядит как моя первая попытка, но базовые данные JSON на самом деле не "матрицированы" в фрейм данных.

Довольно сложный и не удовлетворяющийподход

РЕДАКТИРОВАТЬ: Этот вопрос тот же Но во время запроса, я не мог найти его с помощью поиска. Для дальнейшего использования?

1 Ответ

0 голосов
/ 05 февраля 2019

Используйте словарное понимание с pop для извлечения исходного столбца и concat для MulltiIndex:

df = pd.concat({k: pd.DataFrame(array) for k, array in mydf.pop('colArray').items()})

Альтернативой является параметр использования keys:

df = pd.concat([pd.DataFrame(array) for array in mydf.pop('colArray')], keys=mydf.index)

Затем удалите второй уровень, насколько это возможно join с оригиналом DataFrame:

df = df.reset_index(level=1, drop=True).join(mydf).reset_index(drop=True)

Образец :

mydf = pd.DataFrame({'id': ['foo', 'bar', 'fooz', 'barz'], 'colA': ['a1', 'a2', 'a3', 'a4'], 'colB': ['b1', 'b2', 'b3', 'b4'], 'colArray': [[{'date': 's', 'data1': 't', 'data2': 0.1}, {'date': 'd', 'data1': 'r', 'data2': 0.8}], [{'date': 'd', 'data1': 'y', 'data2': 0.1}], [{'date': 'g', 'data1': 'u', 'data2': 0.1}], [{'date': 'h', 'data1': 'i', 'data2': 0.1}]]})
print (mydf)
     id colA colB                                           colArray
0   foo   a1   b1  [{'date': 's', 'data1': 't', 'data2': 0.1}, {'...
1   bar   a2   b2        [{'date': 'd', 'data1': 'y', 'data2': 0.1}]
2  fooz   a3   b3        [{'date': 'g', 'data1': 'u', 'data2': 0.1}]
3  barz   a4   b4        [{'date': 'h', 'data1': 'i', 'data2': 0.1}]

df = pd.concat({k: pd.DataFrame(array) for k, array in mydf.pop('colArray').items()})
print (df)
    data1  data2 date
0 0     t    0.1    s
  1     r    0.8    d
1 0     y    0.1    d
2 0     u    0.1    g
3 0     i    0.1    h

df = df.reset_index(level=1, drop=True).join(mydf).reset_index(drop=True)
print (df)
  data1  data2 date    id colA colB
0     t    0.1    s   foo   a1   b1
1     r    0.8    d   foo   a1   b1
2     y    0.1    d   bar   a2   b2
3     u    0.1    g  fooz   a3   b3
4     i    0.1    h  barz   a4   b4
...