CSVファイルの作法

CSVファイルの概要

CSV(comma-separated values)ファイルは、値をコンマで区切って並べただけのテキストファイルです。Excel で読み書きできます。表形式のデータを表すのに便利です。Excel で読み書きできます(後述)。

表形式のデータの例:

名前質量電荷
陽子938.31
電子0.511-1

上と同じ内容の CSV ファイル:

名前,質量,電荷
陽子,938.3,1
電子,0.511,-1

Python で CSV ファイルを読むには次のようにするのが基本です:

import pandas as pd

df = pd.read_csv("test.csv")

ファイル名の代わりにネット上のURLでもかまいません。

ちなみに、CSV 以外に最近は JSON という形式もよく使われます。上と同じ内容の JSON ファイル:

[
  {"名前":"陽子", "質量":938.3, "電荷":1},
  {"名前":"電子", "質量":0.511, "電荷":-1}
]

表形式のデータの場合は JSON より CSV のほうが無駄がないですね。

CSV ファイルの構造は RFC 4180 という文書で定められています。それによれば、1行目(ヘッダ行)は、なくてもかまいません。行末は CRLF(0D 0A の2バイト)とされていますが、現実には LF(0A の1バイト)だけの場合もよくあります。文字コードは特に定められていませんが、国際化を考えれば UTF-8 が望ましいでしょう(JSON は UTF-8 と定められています)。ただし、日本語環境の Excel で単純に開く場合は、CP932(拡張 Shift JIS)または BOM 付き UTF-8 のどちらかでないと文字化けします。

RFC 4180 では定められていませんが、CSV には次のように通常 # で始まるコメントを付けることがあります:

# 質量: MeV/c^2
# 電荷: e
名前,質量,電荷
陽子,938.3,1
電子,0.511,-1

この場合、pd.read_csv() にオプション comment='#' が必要です(以下の例参照)。その際、コメント以外の # はダブルクォートで囲む必要があります:

# 素粒子のハッシュタグ
名前,ハッシュタグ
陽子,"#proton"
電子,"#electron"

ダブルクォートで囲めばフィールド中に改行を含んでいても大丈夫です。コメント以外のすべてのフィールドをダブルクォートで囲んでしまってもかまいません。ダブルクォートで囲まれたフィールド中にダブルクォートが含まれる場合は、内側のダブルクォートは "" のように2重にします(つまりダブルクォートをダブルクォートでエスケープします)。

文字コード、コメント開始文字を指定して読むには、次のようにします:

df = pd.read_csv("test.csv", encoding="cp932", comment="#")

文字コードは Python(pandas)では UTF-8(utf_8)や BOM 付き UTF-8(utf_8_sig)はデフォルトで読めますので、指定する必要があるのは cp932(拡張 Shift JIS)くらいでしょう。

データ型は自動で判断されます(対話型の Python 環境で df.dtypes と打ち込めば、各列のデータ型が表示されますので、確認しましょう)。ただ、大きいデータの場合、データ型を指定するほうが速く読めます。文字列は str または object、整数は "int8", "int16", "int32", "int64"int と同じ)、浮動小数点数は "float16", "float32", "float64"float と同じ)、"float128"、論理型(True, False)の bool などが指定できます。例:

df = pd.read_csv("test.csv",
                 dtype={"名前": str, "質量": float, "電荷": int})

欠測値(欠損値)は、Python(pandas)では、空文字列、#N/A, #N/A N/A, #NA, -1.#IND, -1.#QNAN, -NaN, -nan, 1.#IND, 1.#QNAN, <NA>, N/A, NA, NULL, NaN, n/a, nan, null のどれかで表すのがデフォルトです。空文字列が無難ですが、未入力と区別するために何か入れたい場合には "#N/A" とすれば Excel でも欠測値と解釈されます(コメントと解釈されないようにダブルクォートで囲んでおきます)。なお、R では NA がよく使われます。これ以外に例えば - を使いたいなら、次のように明示的に指定しておきます(本当は na_values='-' だけでいいのですが、複数人で管理するデータでは、似た文字が混入してしまうことが多々あります):

df = pd.read_csv("test.csv", na_values=['-', '―', '-'], keep_default_na=False)

整数型のデータでは欠測値を表すことができません。文字列型のデータではデフォルトでは空文字列は欠測値扱いになりますので、空文字列をデータとして使いたい場合は上の例のように明示的に空文字列以外を欠測値に設定します。

コメントを行末に付ける場合は注意が必要です。例えば

2022-04-09,3
2022-04-10,  # 測定を忘れた
2022-04-11,5

では空文字列ではなくスペースになるので欠測値になりません。

最初のうちは値が小さかったけれども、そのうちに1000以上になって、"1,234" のようにコンマが入ってエラーになることがあります。本来はコンマで区切らないほうがいいのですが、混入しそうな場合は thousands="," というオプションを付けておきます。

数値に単位や注釈記号(* など)を付けてはいけないのですが、よく混入してエラーになることがあります(具体例は気象庁の「世界の年平均気温偏差」データ参照)。

Excel で CSV ファイルを扱う場合の注意

CSV ファイルは、Excel でデータを作成し、保存時に「CSV UTF-8 (コンマ区切り)」を指定するのが簡単です。この場合、文字コードは BOM 付きの UTF-8 になります。「CSV (コンマ区切り)」にすれば文字コードは CP932(拡張 Shift JIS)になります。

ただし、Excel は # で始まる文字列を入力しても、コメントと認識せず、通常の文字列フィールドと同じ扱いになりますので、データ中に # が含まれる場合は例えば "#abc" のようにダブルクォートで囲んで入力するしかありませんが、その場合 CSV は """#abc""" のようになります。

0 で始まる数字の列は要注意です。Excel は数値だと解釈して、頭の 0 を消してしまいます。例えば都道府県の地域コード(01 北海道、02 青森県、……、47 沖縄県)は 0 で始まるものがありますので要注意です。入力時に例えば '01 のように頭にシングルクォートを付ければ文字列として解釈されるので 01 が入力できますが、そのような CSV ファイルを読み込む際には、やはり先頭の 0 が消えてしまいます。対策として 01 北海道 までを一つのセルに入れてしまうような工夫がなされているようですが、本来は一つのセルに二つの情報を入れるべきではなく、悩ましいところです。

さらに微妙なのが、日付として解釈される文字列です。データ作法でも詳しく説明しましたが、例えば Oct4 のような遺伝子名は日付 4-Oct に化けます。1-2-3 は日付 2001/2/3 に、1E3 は指数表示の数 1.00E+03 になります。

こういったことが該当する CSV 形式のデータは Excel で扱わないほうが安全です。そういったデータを Excel で作る場合は、非数値部分は「セルの書式設定」で文字列に設定し、CSV には書き出さず xlsx 形式で閉じるようにします。別の方法として、Excel に "Oct4" のように入力します。その際 CSV は """Oct4""" のようにダブルクォートが増殖します。Python で読んだときは "Oct4" のようにダブルクォート付きの文字列になります。

テキストエディタには CSV 閲覧・編集用のモードがあるものがあります。特に Windows 用のテキストエディタ EmEditor Professional の CSV 編集機能は定評があります(最強のCSVエディター「EmEditor」はExcelの代わりにも使える ~テキスト編集上級者への道 参照)。VS Code にも Edit csv という拡張機能があります。Emacs にも csv-mode があります。

CSV ファイルの閲覧・編集に特化した無償アプリもいくつかあるようです(例:CSV+)。

Web で提供する CSV ファイル

Web で CSV ファイルを提供する場合、ブラウザで見たときに文字化けしないように、文字コードを指定したいことがあります。システム全体で AddDefaultCharset UTF-8 などと設定してあればいいのですが、そうでない場合(あるいはそれを上書きしたい場合)、Web サーバの当該ディレクトリに .htaccess というファイルを置いて、それに

AddType text/csv;charset=utf-8 csv

または

AddType text/csv;charset=Shift_JIS csv

のように書いておきます(これができない場合もありますのでサーバの管理者にお問い合わせください)。

例えば毎日更新する情報を 20220221.csv のような日付入りのファイル名で提供する場合、最新のものに latest.csv のようなシンボリックリンクを張っておくと便利です。

CSV ファイルのメタデータ(各列のデータ型など)を提供するための仕組みで一般に使われているものはなさそうです。W3C は CSV on the Web というものを提案しています(suikawiki の CSVW のページ も参照)。あまり使われているところを見ないのですが、GOV.UK では使われている とのことです。

CSV on the Web では、例えばこのページの最初の例なら、同じディレクトリに test.csv-metadata.json という名前の JSON ファイルを作り、次のように書き込みます。

{
  "@context": "http://www.w3.org/ns/csvw",
  "url": "test.csv",
  "tableSchema": {
    "columns": [
      {
        "titles": "名前",
        "datatype": "string"
      }, {
        "titles": "質量",
        "datatype": "number"
      }, {
        "titles": "電荷",
        "datatype": "integer"
      }
    ]
  }
}

このファイルのメディアタイプは application/json ではなく application/csvm+json とするとのことですが、そのためのうまい方法がありません。


Last modified: