LoginSignup
18
24

More than 5 years have passed since last update.

PythonでのCSV,JSONファイルの読み書き

Last updated at Posted at 2017-09-02

オライリーの本「PythonとJavaScriptではじめるデータビジュアライゼーション」に、
pythonでのcsv,jsonファイルのいい感じの入出力方法がまとまっていたのでメモ。
Jupyter Notebookで動作確認したところ、エラーが出た箇所が少しあったので、
本のコードと少し異なっているところがあります。

本の公式サイト:https://www.oreilly.co.jp/books/9784873118086/#toc

動作環境

Windows 10 Pro 64bit
Python: 3.6.1
Anaconda: 4.4.0
Jupyter Notebook: 1.0.0

使用例データ

入出力のデータは以下を使用

nobel_winners = [
{ 'category': 'Physics',
  'name': 'Albert Einstein',
  'nationality': 'Swiss',
  'sex': 'male',
  'year': 1921},
{ 'category': 'Physics',
  'name': 'Paul Dirac',
  'nationality': 'British',
  'sex': 'male',
  'year': 1933},
{ 'category': 'Chemistry',
  'name': 'Marie Curie',
  'nationality': 'Polish',
  'sex': 'female',
  'year': 1911},
]

コード例

csvファイル読み書き

pythonで辞書をcsvファイルに書き込むのは以下。
nobel_winners[0].keys()で配列の第1要素を取り出し、辞書のキーを取得している。
キーをソートするため、sorted(cols)を使い、colsに代入。
本では、cols.sort()でソートしていたが、エラーが出たため以下のように書いている。

cols = nobel_winners[0].keys()
cols = sorted(cols)

with open('data/nobel_winners.csv', 'w') as f:
    f.write(','.join(cols) + '\n')

    for o in nobel_winners:
        row = [str(o[col]) for col in cols]
        f.write(','.join(row) + '\n')

書き出したnobel_winners.csvを読み込むときは以下を実行する。

with open('data/nobel_winners.csv', 'r') as f:
    for line in f.readlines():
        print(line, sep='')
Out
category,name,nationality,sex,year

Physics,Albert Enistein,Swiss,male,1921

Physics,Paul Dirac,British,male,1933

Chemistry,Marie Curie,Polish,female,1911

csvモジュールを使用しての読み書き

次にpythonのcsvモジュールを使用しての読み書きを行う。
openにnewline=''を指定しないとJupyter Notebookで実行したとき、
writer.writerowの下にさらにもう一つ改行が入ってしまったので入れている。

import csv

with open('data/nobel_winners.csv', 'w', newline='') as f:
    fieldnames = nobel_winners[0].keys()
    fieldnames = sorted(fieldnames)
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    for w in nobel_winners:
        writer.writerow(w)

csvモジュールを使用してファイルを読み込む時は以下のようになる。

import csv

with open('data/nobel_winners.csv', 'r') as f:
    reader = csv.reader(f)
    for row in reader:
        print(row, sep='')
Out
['category', 'name', 'nationality', 'sex', 'year']
['Physics', 'Albert Enistein', 'Swiss', 'male', '1921']
['Physics', 'Paul Dirac', 'British', 'male', '1933']
['Chemistry', 'Marie Curie', 'Polish', 'female', '1911']

行をPythonディクショナリに変換することでも、csvデータは取得できる。
そのように取得したのが以下になる。

import csv

with open('data/nobel_winners.csv') as f:
    reader = csv.DictReader(f)
    nobel_winners = list(reader)

for w in nobel_winners:
    w['year'] = int(w['year'])

nobel_winners
Out
[OrderedDict([('category', 'Physics'),
              ('name', 'Albert Enistein'),
              ('nationality', 'Swiss'),
              ('sex', 'male'),
              ('year', 1921)]),
 OrderedDict([('category', 'Physics'),
              ('name', 'Paul Dirac'),
              ('nationality', 'British'),
              ('sex', 'male'),
              ('year', 1933)]),
 OrderedDict([('category', 'Chemistry'),
              ('name', 'Marie Curie'),
              ('nationality', 'Polish'),
              ('sex', 'female'),
              ('year', 1911)])]

csvリーダーはcsvファイルから読み込むときにデータ型を推測せず、
すべてを文字列として扱うので、yearはintにキャストする必要がある。

JSONファイル読み書き

Pythonディクショナリはjsonモジュールを使ってJSONファイルに保存できます。
保存の際はjsonモジュールのdumpメソッドを用います。

import json

with open('data/nobel_winners.json', 'w') as f:
    json.dump(nobel_winners, f)

JSONファイルの読み込みについては、jsonモジュールの
loadメソッドを使うことでできます。

import json

with open('data/nobel_winners.json') as f:
    nobel_winners = json.load(f)

nobel_winners
Out
[{'category': 'Physics',
  'name': 'Albert Enistein',
  'nationality': 'Swiss',
  'sex': 'male',
  'year': 1921},
 {'category': 'Physics',
  'name': 'Paul Dirac',
  'nationality': 'British',
  'sex': 'male',
  'year': 1933},
 {'category': 'Chemistry',
  'name': 'Marie Curie',
  'nationality': 'Polish',
  'sex': 'female',
  'year': 1911}]

jsonモジュールの読み込みでは、csvとは異なりyearの整数型は
保たれたまま読み込まれるのでキャストは不要です。

datetime型のJSONでのエンコード

datetime型を含むPythonデータをエンコードするには、
以下のようなカスタムエンコーダを作成する。

import datetime
import json

class JSONDateTimeEncoder(json.JSONEncoder):  
    def default(self, obj):
        if isinstance(obj, (datetime.date, datetime.datetime)):
            return obj.isoformat()
        else:
            return json.JSONEncoder.default(self, obj)

def dumps(obj):
    return json.dumps(obj, cls=JSONDateTimeEncoder)

now_str = dumps({'time': datetime.datetime.now()})
now_str
Out
'{"time": "2017-09-03T01:03:32.634095"}'

まず、カスタマイズした日付処理エンコーダを
作成するためにJSONEncoderをサブクラス化する。
この処理では、渡された引数objがdatetimeオブジェクトであれば、
日付や日時のisoformatを返すことを実行している。
json.dumpsメソッドにcls引数にカスタム日付エンコーダを設定する。

参考文献

18
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
24