コンテンツにスキップ

単元 5:CSV を読む・書く

  • pd.read_csv() で日本語 CSV を読み込める
  • 文字コード(utf-8 / cp932)の違いに気付き、適切に指定できる
  • header / index_col / usecols / dtype / na_values などの主要オプションを使い分けられる
  • to_csv() で加工結果を CSV として書き出せる

CSV は「データ交換の標準形式」

Section titled “CSV は「データ交換の標準形式」”

CSV(Comma-Separated Values)は カンマで区切られた値の集まり という単純なテキスト形式です。Excel、Google スプレッドシート、Tableau、ほとんどの政府統計ポータル、あらゆるデータベース・分析ツールが入出力に対応しているため、データを「他のツールに渡す/他のツールから受け取る」場面の事実上の標準になっています。

本コースでも、サンプルデータも公開データも CSV で渡されることがほとんどです。この単元では pandas で CSV を読み書きする基本と、よく遭遇する 文字コード問題 への対処を扱います。

最もシンプルな読み込みは 1 行:

import pandas as pd
df = pd.read_csv("users.csv")
df.head()

pd.read_csv() は CSV ファイルを読み込んで DataFrame を返します。読み込んだ直後に df.head() で先頭 5 行を覗くのが最初の習慣にすべき動作です。データの形と中身がイメージできていれば、次の操作の選択を間違えにくくなります。

日本語を含む CSV を扱うとき、最初の壁が 文字コード です。代表的なものは 2 種類:

  • UTF-8 — Web・Mac・Linux の標準。海外発のデータセットもほとんどこれ
  • cp932(Shift_JIS) — Windows の Excel が「CSV として保存」したファイルでよく使われる

pandas はデフォルトで UTF-8 として読もうとします。cp932 のファイルをデフォルトで読むと、UnicodeDecodeError というエラーになるか、文字化けが起きます。エラーが出たら encoding を変えて試す のが定石です。

df = pd.read_csv("data.csv", encoding="utf-8") # 既定
df = pd.read_csv("data.csv", encoding="cp932") # Excel 由来の CSV

「どちらか分からない場合は両方試す」のが最も実用的なアプローチです。判別ツールに頼るより、読んでみてエラーが出る/出ないで判断する方が早いことが多いです。

読み込みでよく使うオプション

Section titled “読み込みでよく使うオプション”

実データを扱い始めると、デフォルトの読み込みでは扱いにくいファイルが出てきます。よく使うオプション:

オプション用途
header=0 / header=None1 行目を列名にする/しない
index_col="列名"特定の列を行インデックスとして使う
usecols=["列1", "列2"]必要な列だけ読み込む(大規模 CSV で有効)
dtype={"列名": str}列の型を明示(電話番号や郵便番号など、数字に見えて文字列扱いしたいもの)
na_values=["なし", "-"]「なし」「-」のような独自表現を欠損値 NaN として認識させる

例:1 列目を行インデックスにし、欠損値表記をカスタマイズしながら読む:

df = pd.read_csv(
"data.csv",
index_col="ID",
na_values=["なし", "未回答", "-"],
)

このように 最初の読み込みでデータ整形の半分は済ませる のがコツです。後から fillna などで対処するより、読み込み時点で na_values を指定するほうがコードが短くなります。

加工した結果を CSV として保存するなら:

df.to_csv("out.csv", index=False, encoding="utf-8")
  • index=False — 行インデックスを書き出さない。普通はこちらが望ましい(デフォルトの整数連番インデックスを保存しても意味がない)
  • encoding="utf-8" — UTF-8 で保存(既定)
  • encoding="utf-8-sig" — Excel で開く前提なら BOM 付き UTF-8 にしておくと文字化けしない

Colab で Google Drive をマウントすると、/content/drive/MyDrive/... 以下のファイルにアクセスできます:

from google.colab import drive
drive.mount("/content/drive")
df = pd.read_csv("/content/drive/MyDrive/datasets/users.csv")

毎回 drive.mount(...) を呼ぶ必要があるのは、ノートブックを開き直したりランタイムをリセットしたりするとマウントが切れるためです。

  • 「文字化け」と「エラー」は別物 — エラーは読み込み失敗、文字化けは「読めたが表示がおかしい」。前者は encoding を変えて再試行、後者は元データの文字コードを調べる
  • CSV と TSV を混同する — タブ区切りの場合は pd.read_csv("data.tsv", sep="\t") のように sep を指定する
  • Excel の .xlsx は CSV ではないpd.read_excel() を使うか、いったん CSV にエクスポートしてから読む
  • インデックスが二重になるread_csv でインデックスを指定しないと整数連番が付き、書き出した CSV を再度読むときに前回のインデックス列が新しい列として残ることがある。index=False で書き出すか、index_col=0 で読み直す

users.csv を題材に、次を行うコードを Colab で書きなさい。

  1. users.csv を読み込み、先頭 5 行を表示する
  2. 「年齢が 30 以上」の行だけを抽出する
  3. 抽出結果を users_30plus.csv として書き出す(行インデックスは含めない)
  4. 書き出した users_30plus.csv を再度 read_csv で読み込み、内容を確認する

書き出した CSV を再読み込みする一往復で、index=False の有無による差を体感してみてください。index=False を外して書き出すと、再読み込み時に余計な列(Unnamed: 0)が増えるはずです。

users.csv を一度 cp932 でエンコードし直して保存し、encoding を指定せずに read_csv を実行するとどうなるかを観察する。エラーメッセージを読み、encoding="cp932" で解決する流れを体験する。