Pandasはファイルの入出力に関する関数が豊富で、機能も多いです。

その中でも、CSVファイルで書き出すことでエクセルや他のアプリケーションでも読み込める場合が多いことから、CSVで書き出したいことは多いはずです。本記事で紹介するto_csv関数は名前の通り、CSV形式のファイルを出力してくれる便利な関数です。

  • to_csv関数の簡単な使い方

について使いこなせるように解説します。

csv形式のファイルを読み込む関数であるread_csv関数の解説は以下の記事でしています。

Pandasのread_csv関数でCSVファイルを読み込む方法 /features/pandas-readcsv-light.html

to_csv

id,age,name,math,english,birth
012,21,Amanda,78,25,1996/9/21
014,22,Bob,65,67,1995/10/31
019,21,Charlotte,98,87,1997/4/24
033,23,David,35,40.1995/5/1
051,22,Emily,69,72,1996/6/4
081,21,Fred,95,90,1997/7/10
090,22,Gary,23,25,1995/12/21

このcsvファイルのデータを例に考えてみます。

このファイルは以下のリンクをクリックすればダウンロードできます。 sample_tocsv.csv

Pythonのインタラクティブシェルを起動して、このファイルを読み込みます。
index_colでインデックスにする列(カラム)を指定し、parse_datesでTimeStamp型で読み込む列(カラム)を指定しています。

In [1]:import pandas as pd

In [6]: df = pd.read_csv("sample_tocsv.csv", index_col=0, parse_dates=['birth'])

In [7]: df
Out[7]:
    age       name  math  english      birth
id                                          
12   21     Amanda    78       25 1996-09-21
14   22        Bob    65       67 1995-10-31
19   21  Charlotte    98       87 1997-04-24
33   23      David    35       40 1995-05-01
51   22      Emily    69       72 1996-06-04
81   21       Fred    95       90 1997-07-10
90   22       Gary    23       25 1995-12-21

基本的な操作

まずは特に何もせずそのまま保存してみます。(DataFrame).to_csv(<保存先のpath>)で保存できます。

s1.csvの名前で保存してみましょう。

ちなみにipythonでは!catのように!をつけてコマンドを実行するとコマンドシェルでの操作を行なってくれます。

In [9]: df.to_csv("s1.csv")

In [10]: !cat s1.csv
id,age,name,math,english,birth
12,21,Amanda,78,25,1996-09-21
14,22,Bob,65,67,1995-10-31
19,21,Charlotte,98,87,1997-04-24
33,23,David,35,40,1995-05-01
51,22,Emily,69,72,1996-06-04
81,21,Fred,95,90,1997-07-10
90,22,Gary,23,25,1995-12-21

うまく保存できていますね。

headerの有無の指定 header

今度はheaderをなくして保存してみます。引数header=Falseにすればうまく保存されたcsvファイルにヘッダーが書き込まれません。

In [11]: df.to_csv("s2.csv", header=False)

In [12]: !cat s2.csv
12,21,Amanda,78,25,1996-09-21
14,22,Bob,65,67,1995-10-31
19,21,Charlotte,98,87,1997-04-24
33,23,David,35,40,1995-05-01
51,22,Emily,69,72,1996-06-04
81,21,Fred,95,90,1997-07-10
90,22,Gary,23,25,1995-12-21

indexの有無の指定 index

index=Falseにすればインデックスが書き込まれません。

In [13]: df.to_csv("s3.csv", index=False)

In [14]: !cat s3.csv
age,name,math,english,birth
21,Amanda,78,25,1996-09-21
22,Bob,65,67,1995-10-31
21,Charlotte,98,87,1997-04-24
23,David,35,40,1995-05-01
22,Emily,69,72,1996-06-04
21,Fred,95,90,1997-07-10
22,Gary,23,25,1995-12-21

インデックスが連番であってもデフォルトだとcsvファイルに書き込まれてしまうのでindex=Falseでそれを防ぎます。

In [15]: df_2 = df.reset_index() # インデックスに指定されたデータを列(カラム)に戻す

In [16]: df_2
Out[16]:
   id  age       name  math  english      birth
0  12   21     Amanda    78       25 1996-09-21
1  14   22        Bob    65       67 1995-10-31
2  19   21  Charlotte    98       87 1997-04-24
3  33   23      David    35       40 1995-05-01
4  51   22      Emily    69       72 1996-06-04
5  81   21       Fred    95       90 1997-07-10
6  90   22       Gary    23       25 1995-12-21

In [17]: df_2.to_csv("s5.csv", index=False)

In [18]: !cat s5.csv
id,age,name,math,english,birth
12,21,Amanda,78,25,1996-09-21
14,22,Bob,65,67,1995-10-31
19,21,Charlotte,98,87,1997-04-24
33,23,David,35,40,1995-05-01
51,22,Emily,69,72,1996-06-04
81,21,Fred,95,90,1997-07-10
90,22,Gary,23,25,1995-12-21

特定の列(カラム)だけを保存する columns

columns=<使用したいカラムのリスト>とすれば特定のカラムだけ保存することが可能です。

In [19]: df.to_csv("s6.csv", columns=["name","math"])

In [20]: !cat s6.csv
id,name,math
12,Amanda,78
14,Bob,65
19,Charlotte,98
33,David,35
51,Emily,69
81,Fred,95
90,Gary,23

読み込みモードの指定 mode

デフォルトでmode="w"になっており、同じ名前のファイルがあったとしても内容が上書きされることになっています。
上書きせず、データをそのまま付け足す形で使いたいときはmode="a"にすれば上書きではなく書き足すことが可能です。


In [32]: data = {
         "id": [ 88, 110],
         "age": [22, 21],
         "name":["Cathy", "Ronald"],
         "math":[80,81],
         "english":[34,87],
         "birth":[pd.Timestamp(1995,8,25),pd.Timestamp(1996,9,4)]
     }

In [48]: df_ad = pd.DataFrame(data, columns=["age","name","math","english","birth", "id"])

In [51]: df_ad.set_index("id", inplace=True) # インデックスに"id"を設定

In [53]: df_ad.to_csv("s1.csv", mode="a", header=False) # s1.csvに書き足す

In [54]: !cat s1.csv
id,age,name,math,english,birth
12,21,Amanda,78.0,25,1996-09-21
14,22,Bob,65.0,67,1995-10-31
19,21,Charlotte,98.0,87,1997-04-24
33,23,David,35.0,40,1995-05-01
51,22,Emily,69.0,72,1996-06-04
81,21,Fred,95.0,90,1997-07-10
90,22,Gary,23.0,25,1995-12-21
88,22,Cathy,80,34,1995-08-25
110,21,Ronald,81,87,1996-09-04

きちんと追記できていますね。header=Falseにしないと間にヘッダーが書き込まれることになりますので注意が必要です。

大量のデータを扱うときなどはこうやって逐一ファイルに保存できるようになるとメモリを圧迫せずにすむのでこの使い方は覚えておくと便利だと思います。

read_csv関数のchunksize引数との相性が良いです。

Using Chunksize in Pandas – Another Dev Notes

上記のサイトでその例を示しています(英語ですが比較的読みやすいです)。100億以上ものデータセットを受け取ってメモリーに入りきらなかったのでread_csv関数のchunksizeを使って小さくした塊ごとに処理を行ったというものです。

ここでも注記でto_csv関数の引数mode"a"にしておきましょうと書いてあります。

区切り文字の変更 sep

sep引数で区切り文字を変更できます。;で区切ってみましょう。

In [55]: df.to_csv("s7.csv", sep=";")

In [56]: !cat s7.csv
id;age;name;math;english;birth
12;21;Amanda;78.0;25;1996-09-21
14;22;Bob;65.0;67;1995-10-31
19;21;Charlotte;98.0;87;1997-04-24
33;23;David;35.0;40;1995-05-01
51;22;Emily;69.0;72;1996-06-04
81;21;Fred;95.0;90;1997-07-10
90;22;Gary;23.0;25;1995-12-21

アウトプット先をsys.stdoutに変更

データをファイルに保存するのではなく標準出力に出力させることもできます。先ほどまでファイル保存先のpathをしていた箇所にsys.stdoutを指定してやるとデータの中身が標準出力されます。

以下のコードをto_csv_stdout.pyの名前で保存してください。

import pandas as pd
import sys

df  = pd.read_csv("sample_tocsv.csv", index_col=0, parse_dates=['birth'])

df.to_csv(sys.stdout)

これをコマンドライン上で

$ python to_csv_stdout.py

で実行するとファイルの中身が表示されるはずです。
Pandasのバージョン(0.23.1)では表示されないバグが混入しているので注意してください。

成功すると、以下のようにコンソールに出力されます。

id,age,name,math,english,birth
12,21,Amanda,78,25,1996-09-21
14,22,Bob,65,67,1995-10-31
19,21,Charlotte,98,87,1997-04-24
33,23,David,35,40,1995-05-01
51,22,Emily,69,72,1996-06-04
81,21,Fred,95,90,1997-07-10
90,22,Gary,23,25,1995-12-21

うまく表示されました。

まとめ

今回はPandasのto_csv関数の使い方についてまとめました。

全ての引数について解説したわけではありませんが、これで一通り扱えるようになるはずです。元のファイルから読み込む場合と違って、ファイル出力するときは形式に特にこだわらない限り(DataFrame または Series).to_csv(<出力するファイル名>)とシンプルに記述することが可能です。

Pythonの標準モジュールを使ってファイルを書き込むこともできますが、Pandasを使っているならこの関数が非常に簡単で便利でしょう。

参考