Преобразование фрейма данных Pandas в JSON

#python #json #pandas #dataframe #to-json

#python #json #pandas #фрейм данных #to-json

Вопрос:

У меня есть данные, хранящиеся в фрейме данных pandas, и я хочу преобразовать tat в формат JSON. Примерные данные могут быть реплицированы с помощью следующего кода

 data = {'Product':['A', 'B', 'A'],
        'Zone':['E/A', 'A/N', 'E/A'],
        'start':['08:00:00', '09:00:00', '12:00:00'],
        'end':['12:30:00', '17:00:00', '17:40:00'],
        'seq':['0, 1, 2 ,3 ,4','0, 1, 2 ,3 ,4', '0, 1, 2 ,3 ,4'],
        'store':['Z',"'AS', 'S'", 'Z']
        }

df = pd.DataFrame(data)
 

Я попытался преобразовать его в формат JSON, используя следующий код

 df_parsed = json.loads(df.to_json(orient="records"))
 

Вывод, сгенерированный сверху

 [{'Product': 'A', 'Zone': 'E/A', 'start': '08:00:00', 'end': '17:40:00', 'seq': '0, 1, 2 ,3 ,4', 'store': 'Z'}, {'Product': 'B', 'Zone': 'A/N', 'start': '09:00:00', 'end': '17:00:00', 'seq': '0, 1, 2 ,3 ,4', 'store': 'AS'}, {'Product': 'A', 'Zone': 'E/A', 'start': '08:00:00', 'end': '17:40:00', 'seq': '0, 1, 2 ,3 ,4', 'store': 'Z'}]
 

Желаемый результат:

 {
'A': {'Zone': 'E/A', 
'tp': [{'start': [8, 0], 'end': [12, 0], 'seq': [0, 1, 2 ,3 ,4]},
      {'start': [12, 30], 'end': [17, 40], 'seq': [0, 1, 2 ,3 ,4]}],
      
'store': ['Z']
}, 
'B': {'Zone': 'A/N', 
'tp': [{'start': [9, 0], 'end': [17, 0], 'seq': [0, 1, 2 ,3 ,4]}],
      
'store': ['AS', 'S']
}
}
 

Если продукт принадлежит одному и тому же, сохраните результат для столбца start end и seq должен быть объединен, как показано в желаемом выводе. Также время начала и время окончания должны быть представлены так, как [9,0] если бы значение времени составляло "09:00:00" только час, а минута должна быть представлена, чтобы мы могли отбросить значение секунд из time столбцов.

Комментарии:

1. Вам необходимо преобразовать свой фрейм данных перед преобразованием в формат JSON. Например, вы можете попробовать агрегировать свои данные с помощью df.groupby('Product') того или иного метода pandas.

2. @Sura-da если ответ выполняет некоторую обработку с фреймом данных, тогда все в порядке. и groupby должен использоваться для объединения данных

3. Если мой ответ поможет, отметьте его как принятый ответ, нажав на галочку.

Ответ №1:

Это будет немного сложнее. Итак, вы должны делать это шаг за шагом:

 def funct(row):
    row['start'] = row['start'].str.split(':').str[0:2]
    row['end'] = row['end'].str.split(':').str[0:2]
    row['store'] = row['store'].str.replace("'", "").str.split(', ')

    d = (row.groupby('Zone')[row.columns[1:]]
        .apply(lambda x: x.to_dict(orient='record'))
        .reset_index(name='tp').to_dict(orient='row'))
    return d

di = df.groupby(['Product'])[df.columns[1:]].apply(funct).to_dict()
 

di:

 {'A': [{'Zone': 'E/A',
   'tp': [{'start': ['08', '00'],
     'end': ['12', '30'],
     'seq': '0, 1, 2 ,3 ,4',
     'store': ['Z']},
    {'start': ['12', '00'],
     'end': ['17', '40'],
     'seq': '0, 1, 2 ,3 ,4',
     'store': ['Z']}]}],
 'B': [{'Zone': 'A/N',
   'tp': [{'start': ['09', '00'],
     'end': ['17', '00'],
     'seq': '0, 1, 2 ,3 ,4',
     'store': ['AS', 'S']}]}]}
 

Объяснение:

  • 1-й создайте свою собственную пользовательскую функцию.
  • измените столбец start , end на форму списка.
  • сгруппируйте по Zone и примените to_dict к остальным столбцам.
  • сбросьте индекс и назовите столбец, имеющий [{'start': ['08', '00'], 'end': ['12', '30'], 'seq': '0, 1, 2 ,3 ,4', as tp .
  • теперь примените to_dict ко всему результату и верните его.

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

 Zone    tp
E/A    [{'start': ['08', '00'], 'end': ['12', '30'], ...
A/N    [{'start': ['09', '00'], 'end': ['17', '00'], ... 
 

Редактировать:

 import pandas as pd
import ast

def funct(row):
    y = row['start'].str.split(':').str[0:-1]
    row['start'] = row['start'].str.split(':').str[0:2].apply(lambda x: list(map(int, x)))
    row['end'] = row['end'].str.split(':').str[0:2].apply(lambda x: list(map(int, x)))
    row['seq'] = row['seq'].apply(lambda x: list(map(int, ast.literal_eval(x))))
    row['store'] = row['store'].str.replace("'", "")

    d = (row.groupby('Zone')[row.columns[1:-1]]
        .apply(lambda x: x.to_dict(orient='record'))
        .reset_index(name='tp'))
    ######### For store create a different dataframe and then merge it to the other df ########
    d1 = (row.groupby('Zone').agg({'store': pd.Series.unique}))
    d1['store'] = d1['store'].str.split(",")
    d_merged = (pd.merge(d,d1, on='Zone', how='left')).to_dict(orient='record')[0]
    return d_merged

di = df.groupby(['Product'])[df.columns[1:]].apply(funct).to_dict()
 

di:

 {'A': {'Zone': 'E/A',
  'tp': [{'start': [8, 0], 'end': [12, 30], 'seq': [0, 1, 2, 3, 4]},
   {'start': [12, 0], 'end': [17, 40], 'seq': [0, 1, 2, 3, 4]}],
  'store': ['Z']},
 'B': {'Zone': 'A/N',
  'tp': [{'start': [9, 0], 'end': [17, 0], 'seq': [0, 1, 2, 3, 4]}],
  'store': ['AS', ' S']}}
 
 

Комментарии:

1. ваш ответ почти правильный, за исключением нескольких вещей, которые являются частью желаемого результата, но не могут быть достигнуты с помощью вашего решения. например start , end и seq где не в виде строки, вы можете обратиться к моему вопросу, чтобы увидеть фактический результат, который требуется. начало / конец должны быть представлены как [8, 0] также последовательность должна быть представлена как [1, 2, 3, 4, 5] . Вы столкнулись store с tp тем, что можете увидеть мой желаемый результат, который не является частью tp , можете ли вы исправить?