[解決!Python]CSVファイルに書き込みを行うには(pandas編):解決!Python
pandas.DataFrameクラスのto_csvメソッドを使って、データフレームの内容をCSVファイルに書き込む方法を紹介する。
import pandas as pd
import numpy as np
from pathlib import Path
data = {
'name': ['isshiki', 'endo', 'kawasaki'],
'age': [20, 25, np.nan],
'weight': [55.44, 66.77, 123.456]
}
df = pd.DataFrame(data)
print(df)
# name age weight
#0 isshiki 20.0 55.440
#1 endo 25.0 66.770
#2 kawasaki NaN 123.456
# 基本
fname = 'test.csv'
df.to_csv(fname)
print(Path(fname).read_text())
#,name,age,weight
#0,isshiki,20.0,55.44
#1,endo,25.0,66.77
#2,kawasaki,,123.456
# 区切り文字の変更
df.to_csv(fname, sep=' ')
print(Path(fname).read_text())
# name age weight
#0 isshiki 20.0 55.44
#1 endo 25.0 66.77
#2 kawasaki 123.456
# 欠損値の表現を指定する
df.to_csv(fname, na_rep='nan')
print(Path(fname).read_text())
#,name,age,weight
#0,isshiki,20.0,55.44
#1,endo,25.0,66.77
#2,kawasaki,nan,123.456
# 数値を文字列化する際の書式指定
df.to_csv(fname, float_format='%+08.3f')
print(Path(fname).read_text())
#,name,age,weight
#0,isshiki,+020.000,+055.440
#1,endo,+025.000,+066.770
#2,kawasaki,,+123.456
# ヘッダー行の指定
df.to_csv(fname, header=['col0', 'col1', 'col2'])
print(Path(fname).read_text())
#,col0,col1,col2
#0,isshiki,20.0,55.44
#1,endo,25.0,66.77
#2,kawasaki,,123.456
# 行インデックスの列名を指定
df.to_csv(fname, index_label='idx')
print(Path(fname).read_text())
#idx,name,age,weight
#0,isshiki,20.0,55.44
#1,endo,25.0,66.77
#2,kawasaki,,123.456
# 行インデックスを出力しない
df.to_csv(fname, index=False)
print(Path(fname).read_text())
#name,age,weight
#isshiki,20.0,55.44
#endo,25.0,66.77
#kawasaki,,123.456
# 書き出す列の指定
df.to_csv(fname, columns=['name', 'weight'])
print(Path(fname).read_text())
#,name,weight
#0,isshiki,55.44
#1,endo,66.77
#2,kawasaki,123.456
# クオートの指定
import csv
df.to_csv(fname, quoting=csv.QUOTE_ALL)
print(Path(fname).read_text())
#"","name","age","weight"
#"0","isshiki","20.0","55.44"
#"1","endo","25.0","66.77"
#"2","kawasaki","","123.456"
df.to_csv(fname, quoting=csv.QUOTE_NONNUMERIC, quotechar="'")
print(Path(fname).read_text())
#'','name','age','weight'
#0,'isshiki',20.0,55.44
#1,'endo',25.0,66.77
#2,'kawasaki','',123.456
# フィールドを囲むのに使う引用符自体がフィールドに含まれている場合の処理
data = {
"name": ["chak'n", "and pop"],
"value": [100, 120]
}
df = pd.DataFrame(data)
print(df)
# name value
#0 chak'n 100
#1 and pop 120
df.to_csv(fname, quoting=csv.QUOTE_NONNUMERIC, quotechar="'")
print(Path(fname).read_text())
#'','name','value'
#0,'chak''n',100
#1,'and pop',120
df.to_csv(fname, sep=' ', quoting=csv.QUOTE_NONE, escapechar='\\')
print(Path(fname).read_text())
# name value
#0 chak'n 100
#1 and\ pop 120
pandas.DataFrame.to_csvメソッド
pandasが提供するDataFrameクラスにはto_csvメソッドがあり、これを使うことでデータフレームに格納されているデータをCSVファイルへと書き出せる。
以下は本稿で紹介するパラメーターを含む、to_csvメソッドの基本的な構文だ。
pandas.DataFrame.to_csv(path, sep, na_rep, float_format, columns, header,
index, index_label, quoting, quotechar)
本稿では以下のパラメーターを紹介する。全てのパラメーターについては、pandasのドキュメント「pandas.DataFrame.to_csv」を参照のこと。
- path:データフレームの内容を書き出すファイルの名前。必須
- sep:区切り文字。省略可。省略時はカンマ「,」が指定されたものとして扱われる
- na_rep:欠損値を表す文字列表現。省略可。省略時は空文字列「""」が指定したものとして扱われる
- float_format:数値を文字列化してファイルに書き込む際に使われる書式化指定文字列。省略可。省略時は元の値がそのまま文字列化される
- columns:どの列の値を書き込むかの指定。省略可。省略時は行インデックスに続いて、全ての列が書き込まれる。
- header:ヘッダー行の指定。True/False、文字列リストを指定可能。文字列リストを指定した場合は、それらがデータフレームの列名の代わりにヘッダー行に使われる。Falseを指定した場合は、ヘッダー行は書き込まれない。Trueを指定した場合は、データフレームの列名がヘッダー行に書き込まれる。省略可。省略時はTrueが指定されたものとして扱われる
- index:行インデックスを書き込むかどうかを指定する(True/False)。省略可。省略時はTrueが指定されたものとして扱われる(行インデックスが書き込まれる)
- index_label:行インデックスの列名としてヘッダー行に書き込む値を指定する。headerパラメーターとindexパラメーターがTrueの場合に、index_labelパラメーターに渡した値が行インデックスの列名としてヘッダー行に書き込まれる。省略可。省略時は行インデックスの列名は書き込まれない
- quoting:CSVファイルに書き込む各フィールドを何らかの引用符で囲むかどうかを指定する。指定可能なのは、Pythonに標準で添付されるcsvモジュールで定義されている定数
- quotechar:各フィールドを囲む引用符の指定。長さ1の文字。省略可。省略時はダブルクオート「"」が指定されたものとして扱われる
基本的な使い方
以下では、次のコードで作成したデータフレームをCSVファイルに書き込むものとする。
import pandas as pd
import numpy as np
from pathlib import Path
data = {
'name': ['isshiki', 'endo', 'kawasaki'],
'age': [20, 25, np.nan],
'weight': [55.44, 66.77, 123.456]
}
df = pd.DataFrame(data)
print(df)
# name age weight
#0 isshiki 20.0 55.440
#1 endo 25.0 66.770
#2 kawasaki NaN 123.456
一番簡単なのは、書き込むファイル名を指定して、このメソッドを呼び出すだけだ。以下に例を示す。
fname = 'test.csv'
df.to_csv(fname)
print(Path(fname).read_text())
#,name,age,weight
#0,isshiki,20.0,55.44
#1,endo,25.0,66.77
#2,kawasaki,,123.456
出力結果を見ると、ヘッダー行の先頭には行インデックスの列名がない、各行の先頭に行インデックスがある、区切り文字がカンマ「,」となっている、欠損値があれば空文字列が書き込まれることなどが分かるはずだ。
区切り文字の変更
区切り文字を変更するにはsepパラメーターに長さ1の文字を指定する。以下に例を示す。
df.to_csv(fname, sep=' ')
print(Path(fname).read_text())
# name age weight
#0 isshiki 20.0 55.44
#1 endo 25.0 66.77
#2 kawasaki 123.456
上の例では「sep=' '」としているので半角空白文字で各フィールドが区切られている。
欠損値の表現を指定する
欠損値を含むフィールドをCSVファイルに書き込む際に、どんな文字列表現とするかを指定するにはna_repパラメーターにその値を指定する。以下に例を示す。
df.to_csv(fname, na_rep='nan')
print(Path(fname).read_text())
#,name,age,weight
#0,isshiki,20.0,55.44
#1,endo,25.0,66.77
#2,kawasaki,nan,123.456
この例では、「na_rep='nan'」としているので、CSVファイルの該当するフィールドには「nan」が書き込まれている。
数値を文字列化する際の書式指定
数値を文字列化してCSVファイルに書き込む際に、どのような形式に書式化するかはfloat_formatパラメーターで指定できる。以下に例を示す。
df.to_csv(fname, float_format='%+08.3f')
print(Path(fname).read_text())
#,name,age,weight
#0,isshiki,+020.000,+055.440
#1,endo,+025.000,+066.770
#2,kawasaki,,+123.456
書式化指定文字列は「%」で始まり、その後に(符号の付加、左寄せなどを指定する)フラグとフィールドの最小文字数、さらに「.」の後に小数点以下の精度と(整数、小数、指数表記などを示す)指定子が続く。
上の例では「+」は常に符号を付加するフラグで、「0」は0埋めを表すフラグ、「8」がフィールドの最小文字数、「3」は小数点以下3桁までを表示する指示、最後の「f」が小数点表示を意味している。CSVファイルの内容と付き合わせてみてほしい。
ヘッダー行の指定
データフレームの列名とCSVファイルのヘッダー行とを異なるものにしたければ、headerパラメーターにヘッダー行の内容を指定する。以下に例を示す。
df.to_csv(fname, header=['col0', 'col1', 'col2'])
print(Path(fname).read_text())
#,col0,col1,col2
#0,isshiki,20.0,55.44
#1,endo,25.0,66.77
#2,kawasaki,,123.456
なお、ヘッダー行を出力したくないときには、「header=False」とすればよい(例は省略)。
行インデックスの列名を指定
行インデックスの列名をヘッダー行に含めたいときには、index_labelパラメーターを使用する。以下はその例だ。
df.to_csv(fname, index_label='idx')
print(Path(fname).read_text())
#idx,name,age,weight
#0,isshiki,20.0,55.44
#1,endo,25.0,66.77
#2,kawasaki,,123.456
なお、このパラメーターはheaderパラメーターがFalse以外のとき、かつ以下で紹介するindexパラメーターがTrueのときにだけ機能する(つまり、ヘッダー行を出力し、行インデックスを出力するときだけ、このパラメーターに指定した列名も出力される)。
行インデックスを出力しない
これまでに見てきた通り、to_csvメソッドはデフォルトで行インデックスを(行の先頭に)出力する。これをやめたいときには、indexパラメーターにFalseを指定する。以下に例を示す。
df.to_csv(fname, index=False)
print(Path(fname).read_text())
#name,age,weight
#isshiki,20.0,55.44
#endo,25.0,66.77
#kawasaki,,123.456
書き出す列の指定
特定の列だけをCSVファイルに書き込みたければ、その列名を要素とするリスト(シーケンス)をcolumnsパラメーターに指定する。以下に例を示す。
df.to_csv(fname, columns=['name', 'weight'])
print(Path(fname).read_text())
#,name,weight
#0,isshiki,55.44
#1,endo,66.77
#2,kawasaki,123.456
クオートの指定
to_csvメソッドでは基本的には各フィールドを何らかの引用符でなるべく囲まないようにしている(Pythonに標準添付されるcsvモジュールのcsv.QUOTE_MINIMAL値に対応)。これを変更するには、quotingパラメーターにcsvモジュールで定義されている値を指定する。
以下の例では、全てのフィールドを囲むように指定している。
import csv
df.to_csv(fname, quoting=csv.QUOTE_ALL)
print(Path(fname).read_text())
#"","name","age","weight"
#"0","isshiki","20.0","55.44"
#"1","endo","25.0","66.77"
#"2","kawasaki","","123.456"
デフォルトでは引用符にダブルクオート「"」が使われるので、上のような出力結果となる。引用符を変更するには、quotecharパラメーターに長さ1の文字を指定する。
以下は数値以外のフィールドをシングルクオート「'」で囲むように指示する例だ。
df.to_csv(fname, quoting=csv.QUOTE_NONNUMERIC, quotechar="'")
print(Path(fname).read_text())
#'','name','age','weight'
#0,'isshiki',20.0,55.44
#1,'endo',25.0,66.77
#2,'kawasaki','',123.456
なお、フィールドを囲むのに使う引用符自体がフィールドに含まれていた場合には、それらは自動的に二重化される(その文字を二度繰り返す)。
例えば、以下のようなデータフレームがあったとする。
data = {
"name": ["chak'n", "and pop"],
"value": [100, 120]
}
df = pd.DataFrame(data)
print(df)
# name value
#0 chak'n 100
#1 and pop 120
これをCSVファイルに(数値以外のフィールドを)シングルクオートで囲んで出力するとしたらどうなるだろう。「chak'n」というフィールドに注目されたい。
df.to_csv(fname, quoting=csv.QUOTE_NONNUMERIC, quotechar="'")
print(Path(fname).read_text())
#'','name','value'
#0,'chak''n',100
#1,'and pop',120
出力を見ると「chak''n」とシングルクオートが二重化されていることが分かる。
また、以下は区切り文字を空白文字として、CSVファイルに書き込みを行おうとするコードだが、今度は「and pop」というフィールドに空白文字が含まれていることが分かる。二重化するのではなく、何らかの文字でエスケープしたいときには次のようにescapecharパラメーターが使える。
df.to_csv(fname, sep=' ', quoting=csv.QUOTE_NONE, escapechar='\\')
print(Path(fname).read_text())
# name value
#0 chak'n 100
#1 and\ pop 120
escapecharパラメーターは、doublequoteパラメーターと組み合わせて使うこともできる。doublequoteパラメーターは今見た二重化を制御するパラメーターでデフォルト値はTrue(二重化する)になっている。これをFalseにしてescapecharパラメーターと組み合わせた例も示しておこう。
df.to_csv(fname, quoting=csv.QUOTE_ALL, quotechar="'", doublequote=False, escapechar='\\')
print(Path(fname).read_text())
#'','name','value'
#'0','chak\'n','100'
#'1','and pop','120'
Copyright© Digital Advantage Corp. All Rights Reserved.