2016-06-14 9 views
0

私は、Pythonを使用してjsonファイルをフラットテーブルに変換して出力をcvs形式で保存できる単純なアプリケーションを作成することにしました。もっと効率的に動作させるためにコードを改善する方法をアドバイスできたらと思っていました。私は比較的小さいファイルを変換すればすべてうまくいくが、〜200MBのファイルを変換しようとするとしばらく時間がかかり始めるので、私は尋ねている。大きなファイルで作業を開始すると、データセットを変換するのにかなりの時間がかかることがあります。埋め込まれたJSONをフラットテーブルに変換する - 効率を向上

import sys, os, json, tkFileDialog, tkMessageBox 
from Tkinter import * 
from pandas.io.json import json_normalize 

def openFile(): 
    currdir = os.getcwd() 
    filename = tkFileDialog.askopenfilename(
     initialdir = currdir, 
     title='Please select a file', 
     filetypes=[('JSON file','.json')]) 

    return filename 

def loading_file(path): 
    #File path 
    file_path = path 

    #Loading json file 
    json_data = open(file_path) 
    data = json.load(json_data) 
    return data 

#Function that recursively extracts values out of the object into a flattened dictionary 
def flatten_json(data): 
    flat = [] #list of flat dictionaries 
    def flatten(y): 
     out = {} 

     def flatten2(x, name=''): 
      if type(x) is dict: 
       for a in x: 
        if a == "name": 
          flatten2(x["value"], name + x[a] + '_') 
        else: 
         flatten2(x[a], name + a + '_') 
      elif type(x) is list: 
       for a in x: 
        flatten2(a, name + '_') 
      else: 
       out[name[:-1]] = x 

     flatten2(y) 
     return out 

#Loop needed to flatten multiple objects 
    for i in range(len(data)): 
     flat.append(flatten(data[i]).copy()) 

    return json_normalize(flat) 




#Outputing normalized data into csv 
def csv_out(data, path): 
    #creating csv file name 
    name = '~/Desktop/' + os.path.basename(os.path.splitext(path)[0]) + '.csv' 
    #converting to the csv 
    data.to_csv(name, encoding='utf-8') #'~/Desktop/out.csv' 

def done(): 
    tkMessageBox.showinfo('json2csv',"DONE!") 

def main(): 
    filepath = openFile() 
    data_file = loading_file(filepath) 
    table = flatten_json(data_file) 
    csv_out(table, filepath) 
    done() 

### Application Interface ### 
tk = Tk() 

#Creating window: 
tk.geometry('250x150+600+300') 
tk.title('JSON2CSV') 

#Creating convert button 
convertbutton = Button(tk, text = 'Convert to .csv', command = main) 
convertbutton.place(x = 25, y = 50) 



tk.mainloop() 
ここ

あなたは短いでしょうし、私が一緒に仕事JSON構造の単純な例:ここでは

は、私はJSONオブジェクトを平坦化について this偉大なブログ記事の助けを借りて作成された私のコードであり、

[{ 
"_id": { 
    "id": "123" 
}, 
"device": { 
    "browser": "Safari", 
    "category": "d", 
    "os": "Mac" 
}, 
"exID": { 
    "$oid": "123" 
}, 
"extreme": false, 
"geo": { 
    "city": "London", 
    "country": "United Kingdom", 
    "countryCode": "UK", 
    "ip": "00.000.000.0" 
}, 
"viewed": { 
    "$date": "2011-02-12" 
}, 
"attributes": [{ 
    "name": "gender", 
    "numeric": 0, 
    "value": 0 
}, { 
    "name": "email", 
    "value": false 
}], 
"change": [{ 
    "id": { 
    "$id": "1231" 
    }, 
    "seen": [{ 
    "$date": "2011-02-12" 
    }] 
}] 
}, { 
"_id": { 
    "id": "456" 
}, 
"device": { 
    "browser": "Chrome 47", 
    "category": "d", 
    "os": "Windows" 
}, 
"exID": { 
    "$oid": "345" 
}, 
"extreme": false, 
"geo": { 
    "city": "Berlin", 
    "country": "Germany", 
    "countryCode": "DE", 
    "ip": "00.000.000.0" 
}, 
"viewed": { 
    "$date": "2011-05-12" 
}, 
"attributes": [{ 
    "name": "gender", 
    "numeric": 1, 
    "value": 1 
}, { 
    "name": "email", 
    "value": true 
}], 
"change": [{ 
    "id": { 
    "$id": "1231" 
    }, 
    "seen": [{ 
    "$date": "2011-02-12" 
    }] 
}] 
}] 
+1

フラット化について言えば、ネストされた関数定義を使用することをお勧めします。私の経験では、通常はPythonでより良い方法があります。特にこの場合、外部関数のスコープ内でバインディングを使用していない場合もあります。それはあなたのプログラムをより読みやすくして、各機能が1つの明確なタスクを実行し(そしてそれをうまくやって)、ヘルパーに電話をかけさせるだけです。私の意見では、ネストされた関数定義から得られるカプセル化のほうが読みやすさの損失を上回ることはめったにありません。 [PyのZen: "フラットはネストされたものよりも良い"](https://www.python.org/dev/peps/pep-0020/) –

+0

ありがとう、私はそれをもっと読みやすくして、ピーターズのアドバイス。 –

答えて

0

@マシン憧れです。ネストを避けるようにしてください - それはすぐに醜くなります。当然の

import json 
import csv 

def get_ids(data): 
    ids = [] 
    for datum in data: 
     id = datum["_id"]["id"] 
     ids.append(id) 
    return ids 

def get_devices(data): 
    devices = [] 

    for datum in data: 
     browser = datum["device"]["browser"] 
     category = datum["device"]["category"]   
     os = datum["device"]["os"] 
     devices.append([browser, category, os]) 
    return devices 

def flatten_json(json_file, output_fn): 
    data = json.loads(json_file) 
    flattened_data =[] 

    ids = get_ids(data) 
    devices = get_devices(data) 

    for id, device in zip(ids, devices): 
     browser, category, os = device 
     flattened_data.append([id, browser,category,os]) 
    with open(output_fn, 'ab') as my_csv: 
     csv_file = csv.writer(my_csv, delimiter=',') 
     csv_file.writerows(flattened_data) 
    return "FLATTENED DATA SAVED" 

# example to make this run: 
flatten_json(x, "my_flattened_file.csv") 

あなたがウェブサイトから、または保存されたファイルからJSONデータを取得する機能を行う必要があります。

はここに沿ってあなたを助けるためにしようとの私の刺しあります。データサンプルを見ると、get_devicesに似ている地理属性の属性を作成して、flatten_jsonの機能と同様に、他のものと同様に機能を含めることができます。

希望すると便利です。

+0

@ ansebbian0あなたの答えをありがとうが、私はデータ構造が非常に不規則であるため、ファイル固有の平坦化機能を作成したくありません。さらに、約1000の異なる特性/属性があり、それらを1つずつ供給することは意味がない。そのため、ネストを使用して可能な限り一般的なものにしました(key == 'name'の場合は関数内での唯一の除外です)。それが明らかでない場合は申し訳ありません。 –

+0

@Aneconomist。心配ない。とにかく、あなたにいくつかのアイデアを伝えるために、get関数を変更して特定のタイプのキー(データ内のペア構造)を取ることが一般的です。これらのキーは、forループを使用してすべてのキーを取得し(デバイスのような辞書を作成して)、リストに格納することで取得できます。その後、これらの格納されたキー/キー:辞書をループして、flatten_json関数でデータを回復することができます。がんばろう! – ansebbian0

+0

ありがとうございます!私はできる限り改善するためにあなたの模範に従おうとします。 –

関連する問題