web-dev-qa-db-ja.com

pythonによって抽出される1つのファイル内の複数のJsonオブジェクト

私はJsonファイルを初めて使用します。次のような複数のjsonオブジェクトを含むjsonファイルがある場合:

{"ID":"12345","Timestamp":"20140101", "Usefulness":"Yes",
  "Code":[{"event1":"A","result":"1"},…]}
{"ID":"1A35B","Timestamp":"20140102", "Usefulness":"No",
  "Code":[{"event1":"B","result":"1"},…]}
{"ID":"AA356","Timestamp":"20140103", "Usefulness":"No",
  "Code":[{"event1":"B","result":"0"},…]}
…

すべての「タイムスタンプ」と「有用性」をデータフレームに抽出したい:

    Timestamp    Usefulness
 0   20140101      Yes
 1   20140102      No
 2   20140103      No
 …

誰もがそのような問題に対処する一般的な方法を知っていますか?ありがとう!

26
user6396

次の形式のjson配列を使用します。

[
{"ID":"12345","Timestamp":"20140101", "Usefulness":"Yes",
  "Code":[{"event1":"A","result":"1"},…]},
{"ID":"1A35B","Timestamp":"20140102", "Usefulness":"No",
  "Code":[{"event1":"B","result":"1"},…]},
{"ID":"AA356","Timestamp":"20140103", "Usefulness":"No",
  "Code":[{"event1":"B","result":"0"},…]},
...
]

次に、それをpythonコードにインポートします

import json

with open('file.json') as json_file:

    data = json.load(json_file)

現在、データのコンテンツは、各要素を表す辞書を持つ配列です。

簡単にアクセスできます、つまり:

data[0]["ID"]
21
danielfranca

json.JSONDecoder.raw_decodeを使用して、「スタックされた」JSONの任意の大きな文字列をデコードできます(メモリに収まる限り)。 raw_decodeは、有効なオブジェクトがあると停止し、解析されたオブジェクトの一部ではなかった最後の位置を返します。文書化されていませんが、この位置をraw_decodeに戻すと、その位置から再び解析を開始できます。残念ながら、Python jsonモジュールは、プレフィックスの空白を含む文字列を受け入れません。したがって、ドキュメントの最初の非空白部分を見つけるために検索する必要があります。

from json import JSONDecoder, JSONDecodeError
import re

NOT_WHITESPACE = re.compile(r'[^\s]')

def decode_stacked(document, pos=0, decoder=JSONDecoder()):
    while True:
        match = NOT_WHITESPACE.search(document, pos)
        if not match:
            return
        pos = match.start()

        try:
            obj, pos = decoder.raw_decode(document, pos)
        except JSONDecodeError:
            # do something sensible if there's some error
            raise
        yield obj

s = """

{"a": 1}  


   [
1
,   
2
]


"""

for obj in decode_stacked(s):
    print(obj)

プリント:

{'a': 1}
[1, 2]
57
Dunes

したがって、配列内のデータを含むいくつかのコメントで述べたように、単純ですが、データセットのサイズが大きくなると、ソリューションは効率の点でうまくスケーリングしません。配列内のランダムなオブジェクトにアクセスしたい場合にのみ、イテレータを実際に使用する必要があります。そうでない場合は、ジェネレータを使用します。以下に、各jsonオブジェクトを個別に読み取り、ジェネレーターを返すリーダー関数のプロトタイプを作成しました。

基本的な考え方は、キャリッジ文字 "\ n"(またはWindowsの場合は "\ r\n")で分割するようにリーダーに通知することです。 Pythonは、これをfile。readline()関数で実行できます。

import json
def json_readr(file):
    for line in open(file, mode="r"):
        yield json.loads(line)

ただし、この方法は、ファイルが記述どおりに書き込まれている場合にのみ機能します。各オブジェクトは改行文字で区切られています。以下に、jsonオブジェクトの配列を分離し、それぞれを新しい行に保存するライターの例を記述しました。

def json_writr(file, json_objects):
    f = open(file, mode="w")
    for jsonobj in json_objects:
        jsonstr = json.dumps(jsonobj)
        f.write(jsonstr+"\n")
    f.flush()
    f.close()

file。writelines()とリスト内包表記でも同じ操作を行うことができます

...
    jsobjs = [json.dumps(j)+"\n" for j in json_objects]
    f.writelines(jsobjs)
...

また、新しいファイルを書き込む代わりにデータを追加したい場合は、 'mode = "w"'を 'mode = "a"'に変更します。

最終的に、これはテキストエディターでjsonファイルを開こうとしたときの読みやすさだけでなく、メモリをより効率的に使用するという点でも非常に役立ちます。

その点について、ある時点で気が変わってリストを読みたくない場合は、Pythonを使用すると、リスト内にジェネレーター関数を配置し、リストに自動的に入力することができます。言葉、ただ書く

lst = list(json_readr(file))

お役に立てれば。少し冗長な場合は申し訳ありません。

7
Dan Temkin