2017-02-10 11 views
1

私は同僚から「Yelp Dataset Challenge」の6つの巨大なファイルをCSV に幾分平らなJSONから変換するように要請されています楽しい教授データ)Pythonのパフォーマンスチューニング:JSONから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) 

残念ながら、私のコンピュータのメモリは、ファイルのこのサイズにまでタスクにはありません。 (私がループを取り除いても、1分以内に50MBのファイルを鳴らしますが、コンピュータをフリーズさせたり、100MB以上のファイルをクラッシュさせたりするのに苦労します。最大ファイルは3.25GBです。

私は代わりに走らせることができる、シンプルだがパフォーマンスの良いものはありますか?

ループでは素晴らしいかもしれませんが、メモリに違いがある場合は6つのファイル名で実行することもできます(わずか6ファイルあります)。

".json"ファイルの内容の例です。実際には、各ファイルには1行に1つのJSONオブジェクトがたくさんあります。

{"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

**ファイル**を一度に読み込んで解析するのではなく、**を一度に** 1つのjson辞書または1つのcsv行で読み込み、次にそれを解析してcsv。もう少し手作業でコーディングする必要がありますが、ファイルストリームスタイルでうまくいくでしょう。 –

答えて

1

問題は、コードがファイル全体をメモリに読み込んだ後、そのメモリに近いコピーをメモリに作成することです。私はそれも3番目のコピーを作成すると思われるが、それを確認していない。 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 

私はこれをMac上でpython 3.5を使用してテストしました。それはWindows上で動作するはずですが、私はそこでそれをテストしていません。

注:

  1. 私はあなたのJSONデータを調整してきました。最初の行に緯度/経度の周りに誤差があるように見えました。

  2. これは小さなファイルでのみテストされています。あなたの3.5 GBファイルをどこから入手するのか分かりません。

  3. 私はこれがあなたの友人のための1回の使用であると仮定しています。これがプロダクションコードの場合、 'with'ステートメントの例外処理が正しいことを確認する必要があります。詳細は、How can I open multiple files using "with open" in Python?を参照してください。

  4. これはかなりパフォーマンスが良いはずですが、もう一度、大きなファイルをどこから入手するのかわかりません。

+0

[ijson](https://pypi.python.org/pypi/ijson/)をチェックすると、Pythonイテレータを使用するのと同じくらい簡単にJSONファイルをストリーミングできます – sundance

+0

@kevin:Question:なぜあなたの 'to_csv( ) '' mode = 'a''パラメータを含めますか?自動的に追加される 'with open'の中に' to_csv() 'を呼び出す方法はありますか? また、あなたのコードは美しく動作します。小さなファイルの変換には時間がかかりますが、コンピュータが凍結しなくなり、妥当な時間内にジョブが完了します(その日の終わりまでに簡単に完了するはずです)。私はちょうどそれがバックグラウンドで実行させることができます。感謝万円。 (最後に、出力ファイルにUTF-8エンコーディングを組み込むようにコードを編集しました - 私がそれを行うまで、外国の入力データにエラーが発生しました) –

+0

@k。 'csv'は既に開いていて' to_csv() 'に渡されるので、後者は書いた後にファイルを閉じません。ソースで 'def save()'を見ることで確認できます。 1476行目で 'close = False'を設定します。https://github.com/pandas-dev/pandas/blob/master/pandas/formats/format.py。良い質問! – kevin

関連する問題