2017-02-10 3 views
1

Меня попросил коллега, чтобы он конвертировал 6 огромных файлов из «Yelp Dataset Challenge» из нескольких «плоских» обычных JSON в CSV (он думает, что они выглядят как увлекательные учебные данные).Python Performance Tuning: JSON to CSV, большой файл

Я думал, что я мог бы ударить его с:

# With thanks to http://www.diveintopython3.net/files.html and https://www.reddit.com/r/MachineLearning/comments/33eglq/python_help_jsoncsv_pandas/cqkwyu8/ 

import os 
import pandas 

jsondir = 'c:\\example\\bigfiles\\' 
csvdir = 'c:\\example\\bigcsvfiles\\' 
if not os.path.exists(csvdir): os.makedirs(csvdir) 

for file in os.listdir(jsondir): 
    with open(jsondir+file, 'r', encoding='utf-8') as f: data = f.readlines() 
    df = pandas.read_json('[' + ','.join(map(lambda x: x.rstrip(), data)) + ']') 
    df.to_csv(csvdir+os.path.splitext(file)[0]+'.csv',index=0,quoting=1) 

К сожалению, память моего компьютера не до задачи на этот размер файла. (Даже если я избавлюсь от цикла, хотя он удаляет файл размером 50 МБ менее чем за минуту, он изо всех сил пытается избежать замораживания моего компьютера или сбоя в файлах 100 МБ +, а самый большой файл - 3,25 ГБ.)

Есть ли что-то еще простое, но мощное, что я могу запустить вместо этого?

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

Вот пример содержимого файла «.json» - обратите внимание, что в каждом файле на самом деле много объектов JSON, по 1 на строку.

{"business_id":"xyzzy","name":"Business A","neighborhood":"","address":"XX YY ZZ","city":"Tempe","state":"AZ","postal_code":"85283","latitude":33.32823894longitude":-111.28948,"stars":3,"review_count":3,"is_open":0,"attributes":["BikeParking: True","BusinessAcceptsBitcoin: False","BusinessAcceptsCreditCards: True","BusinessParking: {'garage': False, 'street': False, 'validated': False, 'lot': True, 'valet': False}","DogsAllowed: False","RestaurantsPriceRange2: 2","WheelchairAccessible: True"],"categories":["Tobacco Shops","Nightlife","Vape Shops","Shopping"],"hours":["Monday 11:0-21:0","Tuesday 11:0-21:0","Wednesday 11:0-21:0","Thursday 11:0-21:0","Friday 11:0-22:0","Saturday 10:0-22:0","Sunday 11:0-18:0"],"type":"business"} 
{"business_id":"dsfiuweio2f","name":"Some Place","neighborhood":"","address":"Strip or something","city":"Las Vegas","state":"NV","postal_code":"89106","latitude":36.189134,"longitude":-115.92094,"stars":1.5,"review_count":2,"is_open":1,"attributes":["BusinessAcceptsBitcoin: False","BusinessAcceptsCreditCards: True"],"categories":["Caterers","Grocery","Food","Event Planning & Services","Party & Event Planning","Specialty Food"],"hours":["Monday 0:0-0:0","Tuesday 0:0-0:0","Wednesday 0:0-0:0","Thursday 0:0-0:0","Friday 0:0-0:0","Saturday 0:0-0:0","Sunday 0:0-0:0"],"type":"business"} 
{"business_id":"abccb","name":"La la la","neighborhood":"Blah blah","address":"Yay that","city":"Toronto","state":"ON","postal_code":"M6H 1L5","latitude":43.283984,"longitude":-79.28284,"stars":2,"review_count":6,"is_open":1,"attributes":["Alcohol: none","Ambience: {'romantic': False, 'intimate': False, 'classy': False, 'hipster': False, 'touristy': False, 'trendy': False, 'upscale': False, 'casual': False}","BikeParking: True","BusinessAcceptsCreditCards: True","BusinessParking: {'garage': False, 'street': False, 'validated': False, 'lot': False, 'valet': False}","Caters: True","GoodForKids: True","GoodForMeal: {'dessert': False, 'latenight': False, 'lunch': False, 'dinner': False, 'breakfast': False, 'brunch': False}","HasTV: True","NoiseLevel: quiet","OutdoorSeating: False","RestaurantsAttire: casual","RestaurantsDelivery: True","RestaurantsGoodForGroups: True","RestaurantsPriceRange2: 1","RestaurantsReservations: False","RestaurantsTableService: False","RestaurantsTakeOut: True","WiFi: free"],"categories":["Restaurants","Pizza","Chicken Wings","Italian"],"hours":["Monday 11:0-2:0","Tuesday 11:0-2:0","Wednesday 11:0-2:0","Thursday 11:0-3:0","Friday 11:0-3:0","Saturday 11:0-3:0","Sunday 11:0-2:0"],"type":"business"} 

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

+0

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

ответ

1

Проблема в том, что ваш код считывает весь файл в память, а затем создает его копию в памяти. Я подозреваю, что он также создает третью копию, но не подтвердил это. Решение, предложенное Neo X, заключается в том, чтобы читать файл в очереди и обрабатывать его соответствующим образом. Вот замена для цикла for:

for file in os.listdir(jsondir): 
    csv_file = csvdir + os.path.splitext(file)[0] + '.csv' 
    with open(jsondir+file, 'r', encoding='utf-8') as f, open(csv_file, 'w', encoding='utf-8') as csv: 
     header = True 
     for line in f: 
      df = pandas.read_json(''.join(('[', line.rstrip(), ']'))) 
      df.to_csv(csv, header=header, index=0, quoting=1) 
      header = False 

Я тестировал это, используя python 3.5 на Mac; он должен работать на Windows, но я его не тестировал.

Примечание:

  1. Я скорректированная ваши данные в формате JSON; в первой строке появилась ошибка вокруг широты/долготы.

  2. Это было протестировано только с небольшим архивом; Я не знаю, где взять файл с 3,5 ГБ.

  3. Я предполагаю, что это разовое использование для вашего друга. Если это был код Production, вам нужно проверить правильность обработки исключений для оператора «with». См. How can I open multiple files using "with open" in Python?.

  4. Это должно быть довольно результативным, но опять же, я не уверен, откуда взять ваши большие файлы.

+0

Проверьте [ijson] (https://pypi.python.org/pypi/ijson/), он делает потоковое JSON-файл таким же простым, как с использованием итератора Python – sundance

+0

@kevin: Вопрос: Почему ваш 'to_csv () 'включить параметр' mode = 'a''? Есть ли что-то о вызове 'to_csv()' внутри 'with open', что делает его автоматически добавлением? Кроме того, ваш код работает красиво - преобразование небольшого файла занимает больше времени, но мой компьютер больше не зависает, и работа по-прежнему завершается в течение разумного промежутка времени (это должно быть легко сделано к концу дня), поэтому Я могу просто позволить ему работать в фоновом режиме. Бесконечно благодарен. (Наконец, я отредактировал ваш код, чтобы включить кодировку UTF-8 в выходной файл - я получал ошибки с чужими входными данными, пока не сделал это.) –

+0

@k .. Рад, что я мог помочь! Поскольку 'csv' уже открыт и передается в' to_csv() ', последний не закрывает файл после записи. Вы можете проверить, посмотрев 'def save()' в источнике; он устанавливает 'close = False' в строке 1476. https://github.com/pandas-dev/pandas/blob/master/pandas/formats/format.py. Хороший вопрос! – kevin