pandas

【pandas】DataFrameによるCSVファイルの入出力

【pandas】DataFrameによるcsvファイルの入出力

pandasのDataFrameでCSVファイルを入出力する方法について解説します。

DataFrameのCSVファイル入出力

CSVファイルは、カンマで区切られたテキストファイルで各種データ保存に広く使用されています。Pythonでは、CSVファイルを扱うためのcsvモジュールというものが標準で用意されており、簡単にCSVファイルの入出力が可能です。

しかし、データ分析では、pandasで用意されているread_csv関数やto_csvメソッドを使って操作する方が便利です。

本記事では、pandasのDataFrameでCSVファイルを入出力する方法について説明します。

Python標準のcsvモジュールの使い方の基本は以下を参考にしてください。

CSVファイルの入出力

CSVファイルの読み込み read_csv

基本的な読み込み方法

CSVファイルの読み込みには、pandasのread_csv関数を使用します。ここでは以下のtestdata.csvファイルを例に基本的な読み込み方法を紹介します。

id,data,text,update_datetime
1,100,sample1,2022/1/1 9:00
2,200,sample2,2022/1/15 0:00
3,300,sample3,2022/2/1 9:00
4,400,sample4,2022/2/15 5:00
5,500,sample5,2022/2/28 0:00

CSVファイルをDataFrameに読み込む場合には以下のようにread_csv関数を使用します。

import pandas as pd

# CSVファイルを読み込む
df = pd.read_csv("testdata.csv", encoding="utf-8")

print(df, "\n")
print(df.dtypes)
【実行結果】
   id  data     text update_datetime
0   1   100  sample1   2022/1/1 9:00
1   2   200  sample2  2022/1/15 0:00
2   3   300  sample3   2022/2/1 9:00
3   4   400  sample4  2022/2/15 5:00
4   5   500  sample5  2022/2/28 0:00 

id                  int64
data                int64
text               object
update_datetime    object
dtype: object

read_csvの引数にはファイルパスを指定します。文字コードは、encoding=で指定可能で、一般的には”utf-8″を使用しますが、場合によっては、”cp932″(Windowsの日本語環境で一般的)を使用することもあります。適切なエンコーディングの指定は、文字化けを防ぐために重要です。

読み込んだCSVファイルは、DataFrameとして取り込まれ、dtypesプロパティで列のデータ型を確認できます。この例では、iddataint64textupdate_datetimeobjectとして取り込まれています。

インデックスとなる列を指定して読み込む方法 index_col引数

インデックス列を指定してCSVファイルを読み込むには、read_csv関数のindex_col引数を使用します。この引数にはインデックスとして使用する列名または列番号を指定できます。

特定の列を指定する場合
import pandas as pd

# インデックス列を指定して読み込む ※index_col=0のように列番号でも同じ
df = pd.read_csv("testdata.csv", encoding="utf-8", index_col="id")

print(df, "\n")
print(df.index, "\n")
print(df.dtypes)
【実行結果】
    data     text update_datetime
id                               
1    100  sample1   2022/1/1 9:00
2    200  sample2  2022/1/15 0:00
3    300  sample3   2022/2/1 9:00
4    400  sample4  2022/2/15 5:00
5    500  sample5  2022/2/28 0:00 

Int64Index([1, 2, 3, 4, 5], dtype='int64', name='id') 

data                int64
text               object
update_datetime    object
dtype: object

上記では、index_col引数でid列を指定しています。結果としては、id列がInt64Indexとして設定されています。なお、「index_col=0」のように列番号で指定することも可能です。

階層インデックス(MultiIndex)として指定する場合

データによっては以下のような階層的インデックス構造を持っているCSVファイルもあります。以下は、level1, level2の順で階層になっているようなCSVファイルです。

level1,level2,data,text,update_datetime
1,1,100,sample1,2022/1/1 9:00
1,2,200,sample2,2022/1/15 0:00
1,3,300,sample3,2022/2/1 9:00
2,1,400,sample4,2022/2/15 5:00
2,2,500,sample5,2022/2/28 0:00

このような階層的なインデックスを持つCSVファイルに対しては、以下のようにindex_colに複数列をレベル順にリスト指定することで対応できます。

import pandas as pd

# 階層インデックスを指定する場合
df = pd.read_csv(
    "testdata_multi_index.csv",
    encoding="utf-8",
    index_col=["level1", "level2"],
)

print(df, "\n")
print(df.index, "\n")
print(df.dtypes)
【実行結果】
               data     text update_datetime
level1 level2                               
1      1        100  sample1   2022/1/1 9:00
       2        200  sample2  2022/1/15 0:00
       3        300  sample3   2022/2/1 9:00
2      1        400  sample4  2022/2/15 5:00
       2        500  sample5  2022/2/28 0:00 

MultiIndex([(1, 1),
            (1, 2),
            (1, 3),
            (2, 1),
            (2, 2)],
           names=['level1', 'level2']) 

data                int64
text               object
update_datetime    object
dtype: object

上記例では、index_col=["level1", "level2"]というように複数列をリストで指定しています。これにより、階層的なMultiIndexを持ったDataFrameとしてCSVファイルが読み込まれていることが分かります。

pandasにおけるIndexの基本については以下にまとめていますので参考にしてください。

Indexの基本

特定の列だけを指定して読み込む方法 usecols引数

特定の列だけを読み込むには、read_csv関数のusecols引数を使用します。この引数に読み込みたい列名のリストを指定することで、CSVファイルから必要な列のみを効率的に読み込むことができます。

import pandas as pd

# 特定の列だけを指定して読み込む
df = pd.read_csv("testdata.csv", encoding="utf-8", usecols=["id", "text"])

print(df, "\n")
print(df.dtypes)
【実行結果】
   id     text
0   1  sample1
1   2  sample2
2   3  sample3
3   4  sample4
4   5  sample5 

id       int64
text    object
dtype: object

上記例では、usecols=["id", "text"]を指定することで、id列とtext列のみが読み込まれていることが分かります。このように必要な列のみ指定して絞ることで、データ分析時に不要なデータを読み込む必要がなくなり処理の効率化が図れます。

取得するデータの型を指定する方法 dtype引数

CSVファイルからデータを特定の型として読み込むには、read_csv関数のdtype引数を使用します。この引数には、列名をキーとして読み込む型を値とする辞書を指定します。

import pandas as pd

# 取得するデータの型を指定する
df = pd.read_csv(
    "testdata.csv", encoding="utf-8", dtype={"id": "float64", "data": str}
)

print(df, "\n")
print(df.dtypes)
【実行結果】
    id data     text update_datetime
0  1.0  100  sample1   2022/1/1 9:00
1  2.0  200  sample2  2022/1/15 0:00
2  3.0  300  sample3   2022/2/1 9:00
3  4.0  400  sample4  2022/2/15 5:00
4  5.0  500  sample5  2022/2/28 0:00 

id                 float64
data                object
text                object
update_datetime     object
dtype: object

上記例では、id列をfloat64として、data列を文字列であるstrとして読み込んでいます。型指定は、Pythonの型名、文字列、NumPyのデータ型、型コード等複数の指定方法を用いることができます。例えば、float"float64"numpy.float64"f8"は同じ結果をもたらしますが、NumPyのデータ型を使用する場合は、NumPyをインポートする必要があります。

read_csv関数は型を指定しない場合も型推定を行いますが、開発者が期待する型で必ず読み込まれるとは限りません。例えば、数値を文字列として、またはその逆で読み込まれることもあります。予期しない型でデータが読み込まれると、分析処理で問題が発生する可能性があります。経験上、このような問題に直面することが多いため、dtypeで各列の型を指定して読み込むことを推奨します。

日付列を指定して取り込む方法 parse_dates引数

CSVファイル内の日付列を適切な日時型で読み込むためには、read_csv関数のparse_dates引数を使用します。この引数には、日付として扱いたい列名のリストを指定します。

import pandas as pd

# 日付列を指定してデータを読み込む (parse_dates引数)
df = pd.read_csv(
    "testdata.csv",
    encoding="utf-8",
    dtype={"id": int, "data": int, "text": str},
    parse_dates=["update_datetime"],
)

print(df, "\n")
print(df.dtypes)
【実行結果】
   id  data     text     update_datetime
0   1   100  sample1 2022-01-01 09:00:00
1   2   200  sample2 2022-01-15 00:00:00
2   3   300  sample3 2022-02-01 09:00:00
3   4   400  sample4 2022-02-15 05:00:00
4   5   500  sample5 2022-02-28 00:00:00 

id                          int32
data                        int32
text                       object
update_datetime    datetime64[ns]
dtype: object

上記例では、update_datetime列を日付列としてparse_datesに指定しています。この方法を使用することで、列はdatetime64[ns]型で読み込まれ、日時として適切に扱うことができます。複数の日付列がある場合は、列名をリストに列挙して指定します。

内部では、dateutilライブラリを利用して日付の解析が行われます。dateutilは多くの日付フォーマットに対応しているため、幅広いフォーマットの日付データを扱うことが可能です。dateutilで対応できないフォーマットの場合は、date_parser引数にカスタム解析関数を指定することも可能です。

dtypes引数と併用することが可能です。型を適切に読み込むことはデータ分析において重要です。不適切な型での読み込みは分析時に想定外の結果を引き起こすことがあるため、parse_dates引数を利用して日付列を正確に取り込むことを推奨します。

ヘッダー行を指定する場合 header引数

ヘッダー行を指定してCSVファイルを読み込む場合、read_csv関数のheader引数を使用します。なお、ファイルの先頭行は0に該当します。

ヘッダー行があるファイルを読み込む場合

CSVファイルの中には以下のtestdata_header.csvのようにヘッダー行が先頭ではないデータもあります。以下の例では、3行目がヘッダー行です。

サンプルデータ
testdata_1.txt
id,data,text,update_datetime
1,100,sample1,2022/1/1 9:00
2,200,sample2,2022/1/15 0:00
3,300,sample3,2022/2/1 9:00
4,400,sample4,2022/2/15 5:00
5,500,sample5,2022/2/28 0:00

上記例のCSVファイルの場合は、以下のようにheader=2を指定します。ファイルの1行目が0であることから、指定する数字は2である点に注意してください。

import pandas as pd

# ヘッダー行を指定する
df = pd.read_csv("testdata_header.csv", encoding="utf-8", header=2)

print(df, "\n")
print(df.dtypes)
【実行結果】
   id  data     text update_datetime
0   1   100  sample1   2022/1/1 9:00
1   2   200  sample2  2022/1/15 0:00
2   3   300  sample3   2022/2/1 9:00
3   4   400  sample4  2022/2/15 5:00
4   5   500  sample5  2022/2/28 0:00 

id                  int64
data                int64
text               object
update_datetime    object
dtype: object
ヘッダー行がないファイルを読み込む場合 header=None

CSVファイルの中には、以下のtestdata_header_none.csvのようにヘッダー行がないようなデータの場合があります。この場合は、header=Noneと指定してファイルの1行目からデータを読み込みます。

1,100,sample1,2022/1/1 9:00
2,200,sample2,2022/1/15 0:00
3,300,sample3,2022/2/1 9:00
4,400,sample4,2022/2/15 5:00
5,500,sample5,2022/2/28 0:00
import pandas as pd

# ヘッダー行がないcsvファイルを読み込む
df = pd.read_csv("testdata_header_none.csv", encoding="utf-8", header=None)

print(df, "\n")
print(df.dtypes)
【実行結果】
   0    1        2               3
0  1  100  sample1   2022/1/1 9:00
1  2  200  sample2  2022/1/15 0:00
2  3  300  sample3   2022/2/1 9:00
3  4  400  sample4  2022/2/15 5:00
4  5  500  sample5  2022/2/28 0:00 

0     int64
1     int64
2    object
3    object
dtype: object

header=Noneとした場合は、列方向のインデックスには自動的に数字が割り当てられます。

上記のようにheader引数をうまく使うことでヘッダーの有無に関わらず、様々な形式のCSVファイルを柔軟に読み込むことが可能です。

CSVファイルの書き込み to_csv

CSVファイルへの書き込みには、pandasのDataFrameのto_csvメソッドを使用します。ここでは、DataFrameをCSVファイルに書き込む基本的な方法について説明します。

基本的な書き込み方法

DataFrameをCSVファイルに書き込むには、to_csvメソッドを以下のように使用します。

import pandas as pd

# csvファイルを読み込む
df = pd.read_csv("testdata.csv", encoding="utf-8")

# 別名でcsvを書き込む
df.to_csv("writedata.csv")
【出力結果の中身】
,id,data,text,update_datetime
0,1,100,sample1,2022/1/1 9:00
1,2,200,sample2,2022/1/15 0:00
2,3,300,sample3,2022/2/1 9:00
3,4,400,sample4,2022/2/15 5:00
4,5,500,sample5,2022/2/28 0:00

上記例では、testdata.csvを読み込んだ後、writedata.csvという新しいファイル名でDataFrameを書き込んでいます。to_csvメソッドを使用する際、デフォルトでは行のインデックス番号もCSVファイルに出力されます。インデックスの出力有無を調整するには、後述するindex引数を使用します。

インデックスを出力しない index=False

DataFrameの行のインデックス番号をCSVファイルに出力しないようにしたい場合は、index引数を使用してindex=Falseを指定します。この引数はインデックスが不要な場合に役立ちます。

import pandas as pd

# csvファイルを読み込む
df = pd.read_csv("testdata.csv", encoding="utf-8")

# 別名でcsvを書き込む (インデックスは出力しない)
df.to_csv("writedata_index_false.csv", encoding="utf-8", index=False)
【出力結果の中身】
id,data,text,update_datetime
1,100,sample1,2022/1/1 9:00
2,200,sample2,2022/1/15 0:00
3,300,sample3,2022/2/1 9:00
4,400,sample4,2022/2/15 5:00
5,500,sample5,2022/2/28 0:00

この方法により、出力されたCSVファイルにはDataFrameの行インデックス番号は含まれません。ヘッダーも不要な場合には、後述するheader引数と併用します。

ヘッダーを出力しない header=False

DataFrameのヘッダーをCSVファイルに出力しないようにしたい場合は、header引数を使用してheader=Falseを指定します。この引数はヘッダーが不要な場合に役立ちます。

import pandas as pd

# csvファイルを読み込む
df = pd.read_csv("testdata.csv", encoding="utf-8")

# 別名でcsvを書き込む (インデックスは出力しない)
df.to_csv("writedata_header_false.csv", encoding="utf-8", header=False)
【出力結果の中身】
0,1,100,sample1,2022/1/1 9:00
1,2,200,sample2,2022/1/15 0:00
2,3,300,sample3,2022/2/1 9:00
3,4,400,sample4,2022/2/15 5:00
4,5,500,sample5,2022/2/28 0:00

この方法により、出力されたCSVファイルにはヘッダーが含まれません。行インデックス番号も不要な場合は、上記で紹介したindex引数と併用します。

特定の列のみ出力する columns引数

DataFrameから特定の列のみをCSVファイルに出力するには、to_csvメソッドのcolumns引数を使用して、出力したい列名をリストで指定します。デフォルトでは、columns=Noneが設定されており、これはDataFrameの全ての列を出力することを意味します。

import pandas as pd

# CSVファイルを読み込む
df = pd.read_csv("testdata.csv", encoding="utf-8")

# 指定した列名のみ出力する
df.to_csv("writedata_columns.csv", columns=["id", "data"])
【出力結果の中身】
,id,data
0,1,100
1,2,200
2,3,300
3,4,400
4,5,500

上記例では、id列とdata列のみがCSVファイルに出力されています。単一列のみを出力する場合でも、columns=["data"]のようにリスト形式で指定する必要がある点に注視してください。

また、インデックス番号やヘッダーを出力したくない場合は、上記で紹介したindex引数やheader引数と併用することができます。これらの引数を適切に組み合わせることで、出力したいデータを柔軟にカスタマイズすることが可能です。

区切り文字を指定して出力する sep引数

DataFrameをカンマ区切り以外の形式で出力したい場合、to_csvメソッドのsep引数を使用して区切り文字を指定することができます。デフォルトでは、CSV(Comma Separated Value)の規格に従ってカンマ「,」が区切り文字として使用されますが、sep引数を使用することにより変更可能です。

以下の例は、タブ「\t」を区切り文字として指定し、TSV(Tab Separated Value)ファイルとして保存しています。

import pandas as pd

# CSVファイルを読み込む
df = pd.read_csv("testdata.csv", encoding="utf-8")

# 区切り文字を指定する (\tでTSVファイルとして保存)
df.to_csv("writedata_sep.tsv", encoding="utf-8", sep="\t")
【出力結果の中身】
	id	data	text	update_datetime
0	1	100	sample1	2022/1/1 9:00
1	2	200	sample2	2022/1/15 0:00
2	3	300	sample3	2022/2/1 9:00
3	4	400	sample4	2022/2/15 5:00
4	5	500	sample5	2022/2/28 0:00

この例では、タブ「\t」を区切り文字としていますが、スペース「" "」等、他の文字を区切り文字として指定することも可能です。この柔軟性により、CSV以外のテキストベースのデータフォーマットでデータを簡単に保存できます。

区切り文字の変更により、異なるアプリケーション間でのデータ互換性を高めることが可能になります。また、特定のデータ処理や分析ツールで要求されるフォーマットに合わせてデータをエクスポートする際にも有用です。

書き込みモードの指定 mode引数

to_csvメソッドは、書き込みモードを指定することにより、ファイルへのデータの書き込み方を制御できます。デフォルトの書き込みモードは"w"で、これは指定したパスが存在しない場合は新規にファイルを作成し、存在する場合には上書きします。以下に、書き込みモードの指定方法について説明します。

上書きを防止したい場合 mode=”x”

既存ファイルの上書きを防止したい場合は、mode="x"を指定します。これによりファイルが既に存在する場合で新規作成を試みるとFileExsitsErrorというエラーが発生し、意図せずデータを失うことを防げます。

import pandas as pd

# CSVファイルを読み込む
df = pd.read_csv("testdata.csv", encoding="utf-8")

# 上書き防止 ファイルが存在しない場合:新規作成、存在する場合:エラー
df.to_csv("writedata_mode_x.csv", mode="x")

ファイルが既に存在する場合には、以下のようなエラーが発生します。

FileExistsError: [Errno 17] File exists: 'writedata_mode_x.csv'
追記したい場合 mode=”a”

既存ファイルにデータを追記したい場合は、mode="a"を指定します。追記モードでは、ファイルの末尾にデータが追加されます。2回目以降の書き込みでヘッダーを省略したい場合は、header=Falseを指定する必要があります。

import pandas as pd

# CSVファイルを読み込む
df = pd.read_csv("testdata.csv", encoding="utf-8")

# 追記モードで追加する場合
df.to_csv("writedata_mode_a.csv")
df.to_csv("writedata_mode_a.csv", mode="a", header=False)

追記の場合は、最初の書き込みでヘッダーを含め、その後の書き込みでheader=Falseを追加することで、ヘッダーの重複を防ぐことができます。これにより、既存ファイルに対して安全にデータを追加することが可能です。

これらの指定方法を適切に使用することで、データの上書きを防いだり、必要に応じでデータを追記したりすることができます。

まとめ

pandasのDataFrameでCSVファイルを入出力する方法について解説しました。具体的には、read_csv関数やto_csvメソッドの使い方を例を使って紹介しています。

Python標準でcsvモジュールが存在しますが、データ分析を行う際には、DataFrameを介してデータを取り込む方が、その後のデータ操作がより容易になります。そのため、DataFrameを用いたCSVファイル入出力方法に慣れることは、一連のデータ分析作業を効率的に進めるうえで非常に重要です。

DataFrameを通じてCSVデータを柔軟に扱えるようになることで、データの読み込み、加工、保存といった一連の作業がスムーズにできるようになりますので、是非使い方を覚えてもらえたらと思います。

Note

read_csvの公式ドキュメントはこちらを参照してください。
to_csvの公式ドキュメントはこちらを参照してください。