pandasでCSVファイルの書き込み・追記(to_csv)

Modified: | Tags: Python, pandas, CSV

pandas.DataFrame, SeriesをCSVファイルとして書き込み(出力)するにはto_csv()メソッドを使う。既存のCSVファイルへの追記も可能。区切り文字を変更できるので、TSVファイル(タブ区切り)として保存することもできる。

本記事で扱っていない引数もあるので詳細は上記の公式ドキュメントを参照。

CSVファイルの読み込み(入力)については以下の記事を参照。

pandasでのExcel, JSON, pickleファイルの読み書き(入出力)については以下の記事を参照。

本記事のサンプルコードのpandasのバージョンは以下の通り。バージョンによって仕様が異なる可能性があるので注意。以下のpandas.DataFrameを例として使う。

import pandas as pd

print(pd.__version__)
# 2.0.3

df = pd.read_csv('data/src/sample_pandas_normal.csv', index_col=0).head(3)
print(df)
#          age state  point
# name                     
# Alice     24    NY     64
# Bob       42    CA     92
# Charlie   18    CA     70

以下の例はpandas.DataFrameだが、pandas.Seriesでも同様。

to_csv()でCSVファイルに書き込み・保存(出力)

pandas.DataFrameおよびpandas.Seriesのメソッドとしてto_csv()が用意されている。

第一引数にパスを指定すると、CSVファイルとして出力される。

df.to_csv('data/dst/to_csv_out.csv')
name,age,state,point
Alice,24,NY,64
Bob,42,CA,92
Charlie,18,CA,70

パスは絶対パスかカレントディレクトリ(作業ディレクトリ)からの相対パスで指定する。カレントディレクトリの確認や変更については以下の記事を参照。

特定の列のみ出力: 引数columns

特定の列だけ出力したい場合は、引数columnsに列名のリストを指定する。一列だけでもリストで指定する。

df.to_csv('data/dst/to_csv_out_columns.csv', columns=['age', 'point'])
name,age,point
Alice,24,64
Bob,42,92
Charlie,18,70

デフォルトはNoneで、すべての列が出力される。

ヘッダー、インデックス出力の有無: 引数header, index

ヘッダー(列名、pandas.DataFramecolumns)、インデックス(行名、pandas.DataFrameindex)の出力の有無は、引数header, indexTrueFalseで指定する。

df.to_csv('data/dst/to_csv_out_header_index.csv', header=False, index=False)
24,NY,64
42,CA,92
18,CA,70

デフォルトはどちらもTrueで、これまでの例のように、ヘッダーもインデックスも含めて出力される。

エンコーディング: 引数encoding

出力ファイルのエンコーディングは引数encodingで指定する。デフォルトはutf-8

必要に応じてencoding='shift_jis'encoding='cp932'のように適宜設定する。

区切り文字: 引数sep

区切り文字を引数sepで指定できる。デフォルトはカンマ','でCSVファイルとして出力される。

タブ文字\tで区切ったTSVファイルとして保存したい場合はsep='\t'とすればよい。

df.to_csv('data/dst/to_csv_out.tsv', sep='\t')
name    age state   point
Alice   24  NY  64
Bob 42  CA  92
Charlie 18  CA  70

書き込みモード(新規作成・上書き・追記): 引数mode

引数modeに書き込みモードを指定できる。組み込み関数open()と同じ値を指定可能。

デフォルトはmode='w'。指定したパスが存在しない場合は新規作成、存在する場合は上書きとなる。

既存ファイルに上書きしてしまうのを防ぎたい場合はmode='x'とする。指定したパスが存在しない場合は新規作成、存在する場合はエラーとなり上書きされない。

# df.to_csv('data/dst/to_csv_out.csv', mode='x')
# FileExistsError: [Errno 17] File exists: 'data/dst/to_csv_out.csv'

追記はmode='a'。既存ファイルの末尾に新たな行として追記される。

一度保存したファイルに同じデータを追記する例を示す。header=Falseとしないとヘッダー(pandas.DataFramecolumns)もそのまま追記されるので注意。

df.to_csv('data/dst/to_csv_out_a.csv')
df.to_csv('data/dst/to_csv_out_a.csv', mode='a', header=False)
name,age,state,point
Alice,24,NY,64
Bob,42,CA,92
Charlie,18,CA,70
Alice,24,NY,64
Bob,42,CA,92
Charlie,18,CA,70

mode='a'による追記は行の追加。列を追加したい場合は、対象のファイルを読み込み、列を追加し、mode='w'(デフォルトなので省略可能)で同名ファイルに上書き保存する。要素の値を更新する場合も同様。

df.to_csv('data/dst/to_csv_out_a_new_column.csv')

df_new = pd.read_csv('data/dst/to_csv_out_a_new_column.csv', index_col=0)
print(df_new)
#          age state  point
# name                     
# Alice     24    NY     64
# Bob       42    CA     92
# Charlie   18    CA     70

df_new['new_col'] = 'new data'
print(df_new)
#          age state  point   new_col
# name                               
# Alice     24    NY     64  new data
# Bob       42    CA     92  new data
# Charlie   18    CA     70  new data

df_new.to_csv('data/dst/to_csv_out_a_new_column.csv')
name,age,state,point,new_col
Alice,24,NY,64,new data
Bob,42,CA,92,new data
Charlie,18,CA,70,new data

欠損値NaNの扱い: 引数na_rep

欠損値NaNを含むpandas.DataFrameを例とする。

df_nan = df.copy()
df_nan.iat[0, 1] = float('nan')
df_nan.iat[1, 2] = float('nan')

print(df_nan)
#          age state  point
# name                     
# Alice     24   NaN   64.0
# Bob       42    CA    NaN
# Charlie   18    CA   70.0

デフォルトでは欠損値は空白(空文字)として出力される。

df_nan.to_csv('data/dst/to_csv_out_nan.csv')
name,age,state,point
Alice,24,,64.0
Bob,42,CA,
Charlie,18,CA,70.0

引数na_repに欠損値を置き換える文字列を指定できる。

df_nan.to_csv('data/dst/to_csv_out_nan_rep.csv', na_rep='NaN')
name,age,state,point
Alice,24,NaN,64.0
Bob,42,CA,NaN
Charlie,18,CA,70.0

pandas.DataFrameの欠損値の処理については以下の記事を参照。

浮動小数点数floatの書式設定: 引数float_format

以下のpandas.DataFrameを例とする。

df = pd.DataFrame({'col1': [0.123456789, 1000000000.0],
                   'col2': [123456789.0, 0.0],
                   'col3': [123456789, 0]})
print(df)
#            col1         col2       col3
# 0  1.234568e-01  123456789.0  123456789
# 1  1.000000e+09          0.0          0

print(df.dtypes)
# col1    float64
# col2    float64
# col3      int64
# dtype: object

print()での表示は指数表記となっているが、これはあくまでも表示設定によるもので、値自体が丸められているわけではない。

print(df.iat[0, 0])
# 0.123456789

print(df.iat[1, 0])
# 1000000000.0

to_csv()で保存する場合、デフォルトでは値がそのまま保存される。

df.to_csv('data/dst/to_csv_out_float_default.csv')
,col1,col2,col3
0,0.123456789,123456789.0,123456789
1,1000000000.0,0.0,0

to_csv()の引数float_formatで、保存時の浮動小数点数floatの書式を指定できる。%によるprintf形式で用いる書式化文字列、または、format()などの呼び出し可能オブジェクトを指定する。

printf形式で指定する例。小数点以下の桁数を3桁にしている。

print('%.3f' % 0.123456789)
# 0.123

print('%.3f' % 123456789)
# 123456789.000

df.to_csv('data/dst/to_csv_out_float_format_3f.csv', float_format='%.3f')
,col1,col2,col3
0,0.123,123456789.000,123456789
1,1000000000.000,0.000,0

呼び出し可能オブジェクトで指定する例。小数点以下3桁の指数表記にしている。

print('{:.3e}'.format(0.123456789))
# 1.235e-01

print('{:.3e}'.format(123456789))
# 1.235e+08

df.to_csv('data/dst/to_csv_out_float_format_3e.csv', float_format='{:.3e}'.format)
,col1,col2,col3
0,1.235e-01,1.235e+08,123456789
1,1.000e+09,0.000e+00,0

なお、桁数を指定して保存した場合、当然ながら保存された桁数以下の情報は失われる。

任意の書式に変換して保存

引数float_formatは名前の通りデータ型が浮動小数点数floatの列に対してのみ有効。整数intの列はそのまま。また、列ごとに異なる書式を指定することはできない。

整数intの列の書式を指定したい場合や、浮動小数点数floatに対して列ごとに異なる書式を指定したい場合は、元のpandas.DataFrameを任意の書式の文字列に変換してから保存する。

df = pd.DataFrame({'col1': [0.123456789, 1000000000.0],
                   'col2': [123456789.0, 0.0],
                   'col3': [123456789, 0]})

df['col1'] = df['col1'].map('{:.3f}'.format)
df['col2'] = df['col2'].map('{:.3e}'.format)
df['col3'] = df['col3'].map('{:#010x}'.format)

print(df)
#              col1       col2        col3
# 0           0.123  1.235e+08  0x075bcd15
# 1  1000000000.000  0.000e+00  0x00000000

df.to_csv('data/dst/to_csv_out_float_format_str.csv')
,col1,col2,col3
0,0.123,1.235e+08,0x075bcd15
1,1000000000.000,0.000e+00,0x00000000

この例のように、整数intを16進数で保存した場合、pd.read_csv()では文字列として読み込まれるので注意。数値として扱いたい場合は読み込み後に変換する必要がある。

df = pd.read_csv('data/dst/to_csv_out_float_format_str.csv', index_col=0)
print(df)
#            col1         col2        col3
# 0  1.230000e-01  123500000.0  0x075bcd15
# 1  1.000000e+09          0.0  0x00000000

print(df.dtypes)
# col1    float64
# col2    float64
# col3     object
# dtype: object

df['col3'] = df['col3'].map(lambda x: int(x, 16))
print(df)
#            col1         col2       col3
# 0  1.230000e-01  123500000.0  123456789
# 1  1.000000e+09          0.0          0

print(df.dtypes)
# col1    float64
# col2    float64
# col3      int64
# dtype: object

関連カテゴリー

関連記事