Skip to content

Pandas DataFrameをCSVに変換:to_csv()完全ガイド

Updated on

データをクリーニングし、すべての列を変換し、分析を実行しました。今度は結果を共有する必要があります -- しかし、エクスポートしたCSVファイルがExcelで文字化けして開いたり、不要なインデックス列が含まれていたり、4GBのファイルが同僚のノートパソコンをフリーズさせたりします。Pandas DataFrameをCSVにエクスポートすることは、エンコーディング、区切り文字、圧縮、大規模ファイルのパフォーマンスが一行のコードをデバッグセッションに変えるまでは簡単に聞こえます。

これらの問題が頻発するのは、to_csv()に20以上のパラメータがあり、デフォルト値が下流の消費者が期待するものと常に一致するわけではないためです。間違ったエンコーディングは非ASCIIテキストを壊します。index=Falseの欠落は謎の列を追加します。圧縮なしでは、適切なサイズのデータセットが巨大なファイル添付になります。

DataFrame.to_csv()メソッドは、どのパラメータを設定すべきかを知っていれば、これらすべてのケースを処理できます。このガイドでは、基本的なエクスポートから数百万行のDataFrameのチャンク書き込みまで、あらゆる実用的なシナリオを解説します。これにより、最初の試みで正しくデータをエクスポートできるようになります。

📚

基本的な使い方

最もシンプルな呼び出しは、現在の作業ディレクトリにDataFrameをCSVファイルとして書き出します:

import pandas as pd
 
df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie'],
    'age': [28, 35, 42],
    'salary': [72000, 88000, 95000]
})
 
df.to_csv('employees.csv')

これにより、以下の内容のemployees.csvが作成されます:

,name,age,salary
0,Alice,28,72000
1,Bob,35,88000
2,Charlie,42,95000

最初の列に注目してください -- これはDataFrameのインデックスです。ほとんどの場合、これは不要です。index=Falseで修正します:

df.to_csv('employees.csv', index=False)

出力:

name,age,salary
Alice,28,72000
Bob,35,88000
Charlie,42,95000

メソッドの完全なシグネチャ

以下は、最も頻繁に使用するパラメータを含むto_csv()の完全なシグネチャです:

DataFrame.to_csv(
    path_or_buf=None,   # ファイルパスまたはバッファ
    sep=',',            # 区切り文字
    na_rep='',          # 欠損値の文字列
    float_format=None,  # 浮動小数点数のフォーマット文字列
    columns=None,       # 書き出す列のサブセット
    header=True,        # 列名を書き出す
    index=True,         # 行インデックスを書き出す
    index_label=None,   # インデックスの列ラベル
    mode='w',           # 書き込みモード ('w', 'a', 'x')
    encoding=None,      # ファイルエンコーディング(デフォルトutf-8)
    compression='infer',# 圧縮タイプ
    quoting=None,       # csv.QUOTE_*定数
    lineterminator=None,# 改行文字
    chunksize=None,     # チャンクあたりの行数
    date_format=None,   # 日時のフォーマット文字列
    errors='strict',    # エンコーディングエラー処理
)

主要パラメータの説明

sep -- カスタム区切り文字

すべてのシステムがカンマを読み取るわけではありません。sepを使用して区切り文字を変更します:

import pandas as pd
 
df = pd.DataFrame({
    'product': ['Widget A', 'Widget B'],
    'price': [19.99, 29.99]
})
 
# タブ区切り
df.to_csv('products.tsv', sep='\t', index=False)
 
# セミコロン区切り(ヨーロッパの地域設定で一般的)
df.to_csv('products_eu.csv', sep=';', index=False)
 
# パイプ区切り
df.to_csv('products.txt', sep='|', index=False)

columns -- サブセットのエクスポート

DataFrame全体ではなく、特定の列のみを書き出します:

import pandas as pd
 
df = pd.DataFrame({
    'id': [1, 2, 3],
    'name': ['Alice', 'Bob', 'Charlie'],
    'email': ['a@x.com', 'b@x.com', 'c@x.com'],
    'internal_score': [0.87, 0.92, 0.78]
})
 
# クライアントが必要な列のみエクスポート
df.to_csv('export.csv', columns=['id', 'name', 'email'], index=False)

header -- 列名の制御

import pandas as pd
 
df = pd.DataFrame({
    'name': ['Alice', 'Bob'],
    'score': [85, 92]
})
 
# ヘッダー行なし
df.to_csv('no_header.csv', header=False, index=False)
 
# カスタムヘッダー名
df.to_csv('custom_header.csv', header=['氏名', 'テストスコア'], index=False)

na_rep -- 欠損値の表現

デフォルトでは、NaN値は空文字列になります。na_repを使用して明示的にします:

import pandas as pd
import numpy as np
 
df = pd.DataFrame({
    'sensor': ['A', 'B', 'C'],
    'reading': [23.5, np.nan, 18.2]
})
 
# デフォルト:NaNに対して空文字列
df.to_csv('readings_default.csv', index=False)
# sensor,reading
# A,23.5
# B,
# C,18.2
 
# 明示的な欠損値マーカー
df.to_csv('readings_marked.csv', na_rep='NULL', index=False)
# sensor,reading
# A,23.5
# B,NULL
# C,18.2

float_format -- 小数精度の制御

import pandas as pd
 
df = pd.DataFrame({
    'item': ['Widget', 'Gadget'],
    'price': [19.999999, 42.123456]
})
 
# 小数点以下2桁
df.to_csv('prices.csv', float_format='%.2f', index=False)
# item,price
# Widget,20.00
# Gadget,42.12

date_format -- 日時列のフォーマット

import pandas as pd
 
df = pd.DataFrame({
    'event': ['Launch', 'Review'],
    'date': pd.to_datetime(['2026-03-15 14:30:00', '2026-04-01 09:00:00'])
})
 
# ISO日付のみ(時刻なし)
df.to_csv('events.csv', date_format='%Y-%m-%d', index=False)
# event,date
# Launch,2026-03-15
# Review,2026-04-01

エンコーディングと特殊文字の処理

エンコーディングは、文字化けしたCSVファイルの最大の原因です。to_csv()のデフォルトエンコーディングはutf-8で、ほとんどのシステムで動作します。しかし、Windows上のExcelは非ASCII文字を正しく表示するためにBOM(バイトオーダーマーク)を必要とします。

UTF-8(デフォルト)

import pandas as pd
 
df = pd.DataFrame({
    'city': ['チューリッヒ', 'ミュンヘン', '東京'],
    'greeting': ['グリュエツィ', 'ゼルヴス', 'こんにちは']
})
 
# 標準UTF-8
df.to_csv('cities.csv', index=False, encoding='utf-8')

Excel用UTF-8(BOM付き)

CSVにアクセント付き文字、CJKテキスト、または特殊記号が含まれ、Microsoft Excelで正しく開く必要がある場合:

import pandas as pd
 
df = pd.DataFrame({
    'city': ['チューリッヒ', 'ミュンヘン', 'サンパウロ', '北京'],
    'population': [434000, 1472000, 12330000, 21540000]
})
 
# utf-8-sigはExcelが認識するBOMを追加
df.to_csv('cities_excel.csv', index=False, encoding='utf-8-sig')

その他のエンコーディング

import pandas as pd
 
df = pd.DataFrame({'col': ['data']})
 
# 旧西ヨーロッパシステム用のLatin-1
df.to_csv('legacy.csv', index=False, encoding='latin-1')
 
# 旧日本語システム用のShift-JIS
df.to_csv('japanese.csv', index=False, encoding='shift_jis')
エンコーディング使用する場面Excel互換?
utf-8ほとんどのシステム、API、データベースのデフォルト部分的(BOMなし)
utf-8-sig非ASCIIテキストを含むWindows上のExcelはい
latin-1 / iso-8859-1旧西ヨーロッパシステムはい
shift_jis旧日本語システムはい
cp1252Windows西ヨーロッパはい

大規模DataFrame:圧縮とチャンキング

圧縮

圧縮はデータ損失なしでファイルサイズを60-90%削減します。Pandasは複数のフォーマットをサポートしています:

import pandas as pd
import numpy as np
 
# 大規模DataFrameを作成
df = pd.DataFrame({
    'id': range(1_000_000),
    'value': np.random.randn(1_000_000),
    'category': np.random.choice(['A', 'B', 'C', 'D'], 1_000_000)
})
 
# gzip圧縮(最も一般的)
df.to_csv('large_data.csv.gz', index=False, compression='gzip')
 
# zip圧縮
df.to_csv('large_data.zip', index=False, compression='zip')
 
# bz2圧縮(より小さいが遅い)
df.to_csv('large_data.csv.bz2', index=False, compression='bz2')
 
# Zstandard(高速、良好な圧縮率 -- zstandardパッケージが必要)
df.to_csv('large_data.csv.zst', index=False, compression='zstd')
圧縮ファイル拡張子速度サイズ削減読み戻し
なし.csv最速の書き込み0%pd.read_csv('f.csv')
gzip.csv.gz中程度70-85%pd.read_csv('f.csv.gz')
zip.zip中程度70-85%pd.read_csv('f.zip')
bz2.csv.bz2遅い75-90%pd.read_csv('f.csv.bz2')
zstd.csv.zst高速70-85%pd.read_csv('f.csv.zst')

Pandasはファイル拡張子から圧縮フォーマットを自動的に推測するため、compression='infer'(デフォルト)は通常正しく動作します。

Chunksize -- バッチ書き込み

メモリを圧迫する非常に大規模なDataFrameの場合、チャンクで書き込みます:

import pandas as pd
import numpy as np
 
df = pd.DataFrame({
    'id': range(5_000_000),
    'value': np.random.randn(5_000_000)
})
 
# 一度に500,000行書き込む
df.to_csv('huge_data.csv', index=False, chunksize=500_000)

chunksizeパラメータは最終的なファイルサイズを削減しません -- 一度にディスクにフラッシュされる行数を制御します。これにより、書き込み操作中のピークメモリ使用量を削減できます。

文字列またはバッファへの書き込み

常にファイルに書き込むわけではありません。API呼び出し、データベース挿入、またはメモリ内処理のためにCSVを文字列として必要とすることがあります:

import pandas as pd
 
df = pd.DataFrame({
    'name': ['Alice', 'Bob'],
    'score': [85, 92]
})
 
# CSVを文字列として取得
csv_string = df.to_csv(index=False)
print(csv_string)
# name,score
# Alice,85
# Bob,92

StringIOまたはBytesIOへの書き込み

import pandas as pd
from io import StringIO, BytesIO
 
df = pd.DataFrame({
    'x': [1, 2, 3],
    'y': [4, 5, 6]
})
 
# StringIOバッファ
buffer = StringIO()
df.to_csv(buffer, index=False)
csv_text = buffer.getvalue()
 
# BytesIOバッファ(HTTPレスポンス、S3アップロードに便利)
byte_buffer = BytesIO()
df.to_csv(byte_buffer, index=False, encoding='utf-8')
csv_bytes = byte_buffer.getvalue()

このパターンは、ローカルファイルを作成せずにCSVデータをクラウドストレージ(S3、GCS)にアップロードする際に一般的です。

既存のCSVへの追記

既存のファイルを上書きせずに行を追加するには、mode='a'header=Falseを使用します:

import pandas as pd
 
# 最初のバッチ -- ヘッダー付きで書き込み
df1 = pd.DataFrame({'name': ['Alice'], 'score': [85]})
df1.to_csv('results.csv', index=False)
 
# 2番目のバッチ -- ヘッダーを複製せずに追記
df2 = pd.DataFrame({'name': ['Bob', 'Charlie'], 'score': [92, 78]})
df2.to_csv('results.csv', mode='a', header=False, index=False)

結果のファイルは、1つのヘッダー行の後に3つのデータ行が続きます。header=Falseを省略すると、データの途中に2番目のヘッダー行が挿入されます。

クォートとエスケープ

区切り文字、改行、または引用符を含むフィールドには適切なクォートが必要です。Pandasはこれを自動的に処理しますが、動作を制御できます:

import pandas as pd
import csv
 
df = pd.DataFrame({
    'name': ['O\'Brien', 'Smith, Jr.', 'Alice "Ace" Wong'],
    'notes': ['アポストロフィを含む', 'カンマを含む', '引用符を含む']
})
 
# デフォルト:必要な場合のみクォート (QUOTE_MINIMAL)
df.to_csv('minimal.csv', index=False)
 
# すべてのフィールドをクォート
df.to_csv('all_quoted.csv', index=False, quoting=csv.QUOTE_ALL)
 
# 非数値フィールドのみクォート
df.to_csv('nonnumeric.csv', index=False, quoting=csv.QUOTE_NONNUMERIC)

エクスポートフォーマットの比較:to_csv() vs to_excel() vs to_parquet()

適切なエクスポートフォーマットの選択は、誰がファイルを使用するかとファイルサイズに依存します:

特徴to_csv()to_excel()to_parquet()
ファイル形式プレーンテキストバイナリ (xlsx)バイナリ(列指向)
人間が読めるはいExcel/Sheets経由いいえ
ファイルサイズ(100万行)~50-100 MB~30-60 MB~5-15 MB
書き込み速度高速遅い高速
読み取り速度中程度遅い非常に高速
型の保持なし(すべて文字列)部分的完全
追加ライブラリが必要なしopenpyxlpyarrow / fastparquet
圧縮サポートgzip, zip, bz2, zstd組み込み組み込み (snappy, gzip)
最適な用途相互運用性、API、素早い共有ビジネスユーザー、Excelユーザー分析パイプライン、ビッグデータ

経験則:非技術ユーザーや外部システムとのデータ共有にはCSVを使用します。速度と型の忠実性が重要な内部パイプラインにはParquetを使用します。受信者がフォーマットや複数シートを必要とする場合はExcelを使用します。

よくある落とし穴とその回避方法

1. 不要なインデックス列

最も頻繁な苦情です。インデックスに意味のあるデータが含まれていない限り、常にindex=Falseを渡してください:

# 間違い -- 読み戻し時に謎の "Unnamed: 0" 列が追加される
df.to_csv('data.csv')
 
# 正しい
df.to_csv('data.csv', index=False)

2. 読み戻し時の無名列

インデックス付きでエクスポートし、ファイルを読み戻すと、Unnamed: 0列が表示されます:

import pandas as pd
 
# インデックス付きでエクスポートされたCSVを読み戻す
df = pd.read_csv('data.csv', index_col=0)  # どの列がインデックスかをread_csvに伝える

3. 日時精度の損失

date_formatなしでは、日時列はマイクロ秒を含む完全なタイムスタンプとしてエクスポートされます。明示的に制御してください:

import pandas as pd
 
df = pd.DataFrame({
    'ts': pd.to_datetime(['2026-01-15 08:30:00.123456'])
})
 
df.to_csv('ts.csv', index=False, date_format='%Y-%m-%d %H:%M:%S')

4. 浮動小数点の丸め問題

浮動小数点数は予期しない末尾の桁を生成することがあります:

import pandas as pd
 
df = pd.DataFrame({'val': [0.1 + 0.2]})
df.to_csv('float.csv', index=False)
# val
# 0.30000000000000004
 
df.to_csv('float_clean.csv', index=False, float_format='%.2f')
# val
# 0.30

5. 列内の混合型

列に混合型(整数と文字列)がある場合、to_csv()はすべてを文字列に変換します。エクスポート前にデータ型を確認してください:

import pandas as pd
 
df = pd.DataFrame({'id': [1, 2, 'three']})
print(df.dtypes)
# id    object  <-- 混合型
 
# エクスポート前にクリーニング
df['id'] = pd.to_numeric(df['id'], errors='coerce')
df.to_csv('clean.csv', index=False)

エクスポート前にPyGWalkerでデータを可視化

DataFrameをCSVにエクスポートする前に、データが正しいか確認することが有効です。PyGWalker (opens in a new tab)は、Jupyter Notebook内で任意のPandas DataFrameをインタラクティブなビジュアルインターフェースに変換します -- プロットコードを書かずに、列をドラッグ&ドロップしてチャートを作成できます:

import pandas as pd
import pygwalker as pyg
 
df = pd.read_csv('raw_data.csv')
 
# エクスポート前に視覚的に探索
walker = pyg.walk(df)
 
# 満足したら、エクスポート
df.to_csv('verified_export.csv', index=False, encoding='utf-8-sig')

このワークフローは、予期しないnull値、外れ値、または間違ったデータ型などの問題を、CSVの消費者に届く前にキャッチします。

FAQ

インデックスなしでPandas DataFrameをCSVにエクスポートするには?

to_csv()index=Falseを渡します:df.to_csv('file.csv', index=False)。これにより、行インデックスが最初の列として書き込まれることを防ぎます。ファイルを読み戻す際、余分なUnnamed: 0列は表示されません。

CSVエクスポート時の特殊文字とエンコーディングの処理方法は?

非ASCII文字(アクセント付き文字、CJKテキスト)を含むCSVをMicrosoft Excelで正しく開く必要がある場合は、encoding='utf-8-sig'を使用します。標準的なシステムとAPIには、デフォルトのencoding='utf-8'が動作します。レガシーシステムには、必要な特定のエンコーディング(latin-1shift_jisなど)を使用してください。

Pandasからエクスポート時に大きなCSVファイルを圧縮するには?

ファイル名に圧縮拡張子を追加すれば、Pandasが残りを処理します:df.to_csv('data.csv.gz', index=False)でgzip圧縮ファイルが作成されます。compression='gzip''zip''bz2'、または'zstd'を明示的に設定することもできます。圧縮ファイルは通常70-90%小さくなり、pd.read_csv()で直接読み戻せます。

既存のCSVファイルに上書きせずにデータを追記できますか?

はい。mode='a'header=Falseを使用します:df.to_csv('file.csv', mode='a', header=False, index=False)mode='a'は追記モードでファイルを開き、header=Falseはファイルの途中にヘッダー行が重複して書き込まれることを防ぎます。

Pandasのto_csv()とto_parquet()の違いは?

to_csv()は人間が読めるテキストファイルを生成しますが、型情報が失われます(すべてが文字列になります)。to_parquet()はデータ型(整数、浮動小数点、日時)を保持するコンパクトなバイナリファイルを作成し、5-10倍高速に読み取れ、5-10倍小さくなります。非技術ユーザーや外部システムとの共有にはCSVを使用し、パフォーマンスと型の忠実性が重要な内部データパイプラインにはParquetを使用してください。

まとめ

DataFrame.to_csv()は、PandasデータをCSVファイルにエクスポートする標準的な方法です。クリーンなエクスポートには、常にindex=Falseを渡してください。Excel互換性が重要な場合はencoding='utf-8-sig'を使用します。gzipまたはzstdで大きなファイルを圧縮してサイズを70-90%削減します。float_formatで小数精度を制御し、na_repで欠損値を処理し、mode='a'で既存ファイルに追記します。型の保持と速度が重要なデータパイプラインには、代わりにto_parquet()を検討してください。エクスポート前に、PyGWalkerなどのツールでデータを視覚的に確認して、問題を早期に発見しましょう。

📚