Как преобразовать csv в json с многоуровневой вложенностью с использованием pandas

#python #pandas #csv

#python #pandas #csv

Вопрос:

Я пытался следовать нескольким ответам, которые я видел на SO, но я действительно застрял здесь. Я пытаюсь преобразовать CSV в JSON.

Схема JSON имеет несколько уровней вложенности, и некоторые значения в CSV будут общими.

Вот ссылка на одну запись в CSV.

Представьте этот пример как две разные стороны, прикрепленные к одному документу.

Поля в документе (document_source_id, document_amount, record_date, source_url, document_file_url, document _ type__title, apn, situs_county_id, state_code) не должны дублироваться.

При этом поля каждого объекта уникальны.

Я пытался вложить их, используя сложную инструкцию groupby, но застрял в получении данных в моей схеме.

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

 j = (df.groupby(['state_code', 
                 'record_date',
                 'situs_county_id',
                 'document_type__title',
                 'document_file_url',
                 'document_amount',
                 'source_url'], as_index=False)
             .apply(lambda x: x[['source_url']].to_dict('r'))
             .reset_index()
             .rename(columns={0:'metadata', 1:'parcels'})
             .to_json(orient='records'))
  

Вот как должен выводиться пример CSV

 {
   "metadata":{
      "source_url":"https://a836-acris.nyc.gov/DS/DocumentSearch/DocumentDetail?doc_id=2019012901225004",
      "document_file_url":"https://a836-acris.nyc.gov/DS/DocumentSearch/DocumentImageView?doc_id=2019012901225004"
   },
   "state_code":"NY",
   "nested_data":{
      "parcels":[
         {
            "apn":"3972-61",
            "situs_county_id":"36005"
         }
      ],
      "participants":[
         {
            "entity":{
               "name":"5 AIF WILLOW, LLC",
               "situs_street":"19800 MACARTHUR BLVD",
               "situs_city":"IRVINE",
               "situs_unit":"SUITE 1150",
               "state_code":"CA",
               "situs_zip":"92612"
            },
            "participation_type":"Grantee"
         },
         {
            "entity":{
               "name":"5 ARCH INCOME FUND 2, LLC",
               "situs_street":"19800 MACARTHUR BLVD",
               "situs_city":"IRVINE",
               "situs_unit":"SUITE 1150",
               "state_code":"CA",
               "situs_zip":"92612"
            },
            "participation_type":"Grantor"
         }
      ]
   },
   "record_date":"01/31/2019",
   "situs_county_id":"36005",
   "document_source_id":"2019012901225004",
   "document_type__title":"ASSIGNMENT, MORTGAGE"
}
  

Ответ №1:

Возможно, вам потребуется использовать функцию json_normalize из pandas.io.json

 from pandas.io.json import json_normalize
import csv
li = []
with open('filename.csv', 'r') as f:
    reader = csv.DictReader(csvfile)
        for row in reader:
          li.append(row)
df = json_normalize(li)
  

Здесь мы создаем список словарей из файла csv и фрейм данных с помощью функции json_normalize.

Ответ №2:

Ниже приведен один из способов экспорта ваших данных:

 # all columns used in groupby()
grouped_cols = ['state_code', 'record_date', 'situs_county_id', 'document_source_id'
    , 'document_type__title', 'source_url', 'document_file_url']

# adjust some column names to map to those in the 'entity' node in the desired JSON
situs_mapping = {
    'street_number_street_name': 'situs_street'
,   'city_name': 'situs_city'
,   'unit': 'situs_unit'
,   'state_code': 'state_code'
,   'zipcode_full': 'situs_zip'
}
# define columns used for 'entity' node. python 2 need to adjust to the syntax
entity_cols = ['name', *situs_mapping.values()]
#below for python 2#
#entity_cols = ['name']   list(situs_mapping.values())

# specify output fields
output_cols = ['metadata','state_code','nested_data','record_date'
    , 'situs_county_id', 'document_source_id', 'document_type__title']

# define a function to get nested_data
def get_nested_data(d):
    return {
        'parcels': d[['apn', 'situs_county_id']].drop_duplicates().to_dict('r')
    ,   'participants': d[['entity', 'participation_type']].to_dict('r')
    }

j = (df.rename(columns=situs_mapping)
    .assign(entity=lambda x: x[entity_cols].to_dict('r'))
    .groupby(grouped_cols)
    .apply(get_nested_data)
    .reset_index()
    .rename(columns={0:'nested_data'})
    .assign(metadata=lambda x: x[['source_url', 'document_file_url']].to_dict('r'))[output_cols]
    .to_json(orient="records")
)

print(j)
  

Примечание: Если participants содержат дубликаты и должны выполняться drop_duplicates(), как мы делаем на parcels , тогда assign(entity ) можно перейти к определению participants в get_nested_data() функции:

     ,   'participants': d[['participation_type', *entity_cols]] 
           .drop_duplicates() 
           .assign(entity=lambda x: x[entity_cols].to_dict('r')) 
           .loc[:,['entity', 'participation_type']] 
           .to_dict('r')