Menu
日本語

Python CSV入門|csvモジュールで読み込み・書き込み

PythonでCSVファイルを扱う基本を解説。csvモジュールのreader/writer、DictReader・DictWriterの使い方、ヘッダーや引用符の扱い、pandasとの使い分けまで整理します。

CSVは見た目ほど単純ではない(意外とクセがある)

CSVファイルは要するにただのテキストです。行は改行で区切られ、各フィールドはカンマで区切られる。基本はそれだけ。ところが現実には、カンマを含むクォート付きの文字列、改行を含むフィールド、地域ごとの慣習の違い(カンマ区切り vs セミコロン区切り)、Excelで保存したときに先頭に付くBOMなど、細かい罠がたくさんあります。自前で line.split(",") を書くと、まずハマります。

そんなときに活躍するのが、Python標準の csv モジュールです。小〜中規模のファイルなら、これひとつでほぼ事足ります。

csv.reader でCSVを読み込む方法

csv.reader は、各行を文字列のリストとして返してくれます。

import csv

with open("people.csv", newline="") as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)

ハマりやすい細かいポイントをいくつか挙げておきます。

  • open には必ず newline="" を渡す。改行コードの処理は csv モジュール側でやってくれます。これを指定しないと、Windows で空行が混ざることがあります。
  • 値はすべて文字列として読み込まれる"42"int(...) で変換するまで文字列のままです。CSV に型の概念はありません。
  • ヘッダー行も単なる1行のデータ。ヘッダー付きのファイルを扱うときは、最初の行を手動でスキップするか、DictReader に切り替えましょう。

ヘッダー行をスキップする

import csv

with open("people.csv", newline="") as f:
    reader = csv.reader(f)
    headers = next(reader)         # pulls the first row out
    for row in reader:
        print(row)

next(reader) はイテレータを1つ進めて、その行を返します。

DictReader で辞書として読み込む

csv.DictReader は1行目をヘッダーとして扱い、それ以降の各行を辞書形式で返してくれます。

import csv

with open("people.csv", newline="") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row["name"], row["email"])

実務ではほぼ間違いなくこちらを選ぶことになります。カラム名がそのままドキュメント代わりになりますし、元ファイルの列順が入れ替わってもコードが壊れません。

ヘッダー行がないファイルを扱う場合は、fieldnames=["name", "email", ...] のように明示的に渡してください。

csv.writer でCSVに書き込む

csv.writer は、リスト形式の行データをCSVの1行に変換して書き出してくれます。

import csv

rows = [
    ["name", "age", "city"],
    ["Rosa", 30, "Lisbon"],
    ["Ada", 36, "London"],
]

with open("out.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerows(rows)

writerow(row) は1行だけ書き込み、writerows(rows) はイテラブルをまとめて一気に書き込みます。どちらもフィールドにカンマ・クォート・改行が含まれていれば自動でクォートしてくれるので、こちらで気を使う必要はありません。

DictWriter で辞書をCSVに書き込む

データがすでに辞書形式になっているなら、DictWriter を使えば「リストに変換する」手間を省けます。

import csv

people = [
    {"name": "Rosa", "age": 30, "city": "Lisbon"},
    {"name": "Ada", "age": 36, "city": "London"},
]

with open("out.csv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=["name", "age", "city"])
    writer.writeheader()
    writer.writerows(people)

fieldnames 引数は、ヘッダーとカラムの順序の両方を決める役割を持ちます。辞書の中に fieldnames に含まれないキーがあった場合、黙って捨てられます(extrasaction="raise" を指定すれば例外を投げさせることも可能)。

区切り文字とクォート処理を変える

「CSV」と言ってもカンマ区切りだけとは限りません。ヨーロッパ圏のロケールでは ; がよく使われますし、タブ区切り(\t)のファイルや、| を使うシステムもあります。こういう場合は delimiter= 引数を渡してあげればOKです。

import csv

with open("data.tsv", newline="") as f:
    reader = csv.reader(f, delimiter="\t")
    for row in reader:
        print(row)

変わったクォートルールを持つファイルを扱うときは、csv.register_dialect(...) で一度設定しておけば何度でも使い回せます。ただ、たいていのファイルならデフォルト設定に delimiter= を足すくらいで十分です。

文字コード(エンコーディング)

CSVファイルはあくまでテキストなので、必ずエンコーディングが絡んできます。最近の標準はUTF-8ですが、WindowsのExcelから出力されたファイルは cp1252 だったり、UTF-8のBOM付きだったりすることがあります。Pythonでcsvを読み込むときに文字化けを避けるには、エンコーディングを明示的に指定するのが鉄則です。

with open("data.csv", newline="", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    ...

UnicodeDecodeError が出たときは、指定したエンコーディングがファイルの実際のものと合っていません。よくある候補としては utf-8-sig(ExcelのBOM付きに対応)、cp1252latin-1 あたりを順番に試してみましょう。

CSVの各行を使える型に変換する

CSVから読み込んだ値はすべて文字列になるので、型変換は自分でやる必要があります。

main.py
Output
Click Run to see the output here.

(StringIOを使えば実ファイルなしでサンプルを動かせます。実際のコードではopen(path)を使ってください)

日付、null許容の数値、10通りのスペルで書かれたtrue/falseなど、型まわりがややこしいCSVを扱うなら、pandasを検討しましょう。こうしたケースの大半に対応する作法があらかじめ組み込まれています。

pandasを使うべきタイミング

pandas.read_csv(path)はDataFrameを返します。次のような操作をしたくなった瞬間から、DataFrameこそが最適な構造になります。

  • 行のフィルタ: df[df["active"] == True]
  • 集計: df.groupby("city")["age"].mean()
  • 別のテーブルとの結合
  • ちょっとした整形をかけて書き出し
import pandas as pd

df = pd.read_csv("people.csv")
adults = df[df["age"] >= 18]
adults.to_csv("adults.csv", index=False)

小さくて単純な読み込みなら Pandas はオーバースペックですし、依存関係としてもかなり重めです(仮想環境に pip install する必要があります)。とはいえ、データらしいデータを扱う場面では、Python でデータ分析をする人がまず手に取るのが Pandas なのも事実です。

巨大な CSV ファイルをストリーム処理する

csv.reader はもともと遅延評価で、1 行ずつ読み込む作りになっています。最初に list(reader) でまとめて展開したりせず、そのままイテレートしていけば、ファイルサイズに関係なくメモリ使用量はほぼ一定に保てます。

import csv

with open("huge.csv", newline="") as f:
    reader = csv.DictReader(f)
    error_count = 0
    for row in reader:
        if row["status"] == "error":
            error_count += 1

print(f"Found {error_count} errors.")

この書き方なら、行をリストに溜め込まない限り、10GBのファイルでも10KBのファイルと同じようにサクサク処理できます。

身につけておきたい習慣

  • CSVを読み書きするときは、open に必ず newline="" を渡しましょう。
  • ヘッダー付きのファイルなら DictReader / DictWriter を使うのがおすすめ。数値インデックスより圧倒的に読みやすくなります。
  • エンコーディングは明示的に指定を。特にExcelが吐いたファイルや日本語以外のソースを扱うときは要注意です(CSV 文字化け対策の基本)。
  • 型変換は読み込みの段階で済ませておくと、後続のコードがラクになります。
  • 単にデータを移すだけでなく「分析」したくなったら、そこで初めて pandas の出番です。

次のステップ

これでJSONもCSVも扱えるようになりました。実務で使うスキルとして最後に押さえておきたいのが、ネットワーク越しのデータ取得です。次のドキュメントでは requests ライブラリを使ったHTTPリクエストを見ていきます。

よくある質問

PythonでCSVファイルを読み込むには?

標準ライブラリの csv モジュールを使います。csv.reader は各行を文字列のリストとして返し、csv.DictReader は1行目をヘッダーとして扱い、各行を辞書として返してくれます。ファイルを開くときは改行コードが崩れないように newline='' を必ず指定してください: with open('data.csv', newline='') as f:

PythonでCSVファイルを書き出すには?

書き込みモードで newline='' を付けて開いたファイルに csv.writer を組み合わせます。1行ずつなら writer.writerow([...])、まとめて書くなら writer.writerows([[...], [...]]) を呼び出します。辞書データを扱う場合は csv.DictWriter が便利で、ヘッダー出力も任せられます。

csvモジュールとpandas、どちらを使うべき?

ちょっと読み書きしたいだけ、1行ずつ処理したい、余計な依存を増やしたくない——そんな場面では csv で十分です。一方、フィルタリングやグループ集計、結合などの加工をしたい場合や、ベクトル演算の速さが効いてくる大きなファイルを扱うならpandasの出番です。ファイル自体はどちらでも扱えるので、「読み込んだ後に何をするか」で選ぶのがポイントです。

WindowsでCSVに空行が入ってしまうのはなぜ?

newline='' を付けずにファイルを開いているのが原因です。csv モジュールは自分で改行コードを書き出すのですが、この引数がないとWindowsでは余分な改行が追加されてしまいます。読み込み・書き込みどちらでも open(path, newline='') の形で開くようにしましょう。

Coddyでコードを学ぼう

始める