Claude Codeでpandasのデータ処理を書く実践手順
Claude Codeにpandasの集計・結合スクリプトを書かせるときの権限設定と、実行結果を確認しながら直す検証ループの組み方を解説します。
pandasとClaude Codeを組み合わせる前提
pandasはCSVやExcel、SQLなど複数の形式からデータを読み込み、表形式(DataFrame)として整形・集計・結合するPythonライブラリです。導入はpip install pandasまたはconda install -c conda-forge pandasで完了します。
データの読み込みはread_csv・read_excel・read_sqlのようにread_で始まる関数に統一されています。書き出しもto_csv・to_excelのようにto_で始まるメソッドで揃っています。Claude Codeにスクリプトを書かせるときも、入力元がCSVかExcelかSQLかを最初に伝えておくと、選ぶ関数名がぶれずに済みます。
Claude Codeはファイルの読み書きとBashコマンドの実行を1つのセッションでこなせます。そのため「集計スクリプトを書かせる → 実行させる → 出力を確認させる → 直させる」という一連の流れを対話の中で回せます。このとき鍵になるのは、Bashコマンドをどこまで自動承認するかという権限設定と、実行結果を毎回どう検証させるかという2点です。この記事ではこの2点に絞って手順を扱います。
環境がまだない場合は、仮想環境を切ってpandasを入れるところから始めます。集計の実例としては、GA4とSearch Consoleの数字を結合して伸びないページを探す手順があります。
python -m venv .venv
source .venv/bin/activate
pip install pandas
python -c "import pandas; print(pandas.__version__)"ステップ1: Bashの実行権限を先に決める
pandasスクリプトを書かせるたびにpython analyze.pyの実行を承認していると、検証ループのたびに手が止まります。Claude Codeの権限ルールはBash(コマンド)の形式で書き、末尾にスペース区切りの*を置くと、その後に続く引数を問わず一致します。
{
"permissions": {
"allow": [
"Bash(python *)",
"Bash(pytest *)"
]
}
}このルールを.claude/settings.json(チーム共有)または.claude/settings.local.json(自分だけ)に書いておくと、pythonから始まるコマンドはすべて確認なしで実行されます。プロンプト上で「Yes, and don't ask again」を選んだときも、Claude Codeは同じ形式のルールをGitリポジトリのルートにある.claude/settings.local.jsonへ書き足します。
特定のスクリプトだけに絞りたい場合は、ワイルドカードを使わずにBash(python scripts/aggregate.py)のように完全一致で書きます。実行のたびに引数が変わるなら、末尾のワイルドカードで対応します。Rの解析プロジェクトで同じ線引きをするなら、Claude CodeでRの解析を進めるに手順があります。
allowルールと合わせて、破壊的な操作を拒否するdenyルールも書いておくと安全です。Claude Codeは&&・||・;・|などの区切りでコマンドを分解し、区切られたサブコマンドごとにdeny・askルールを評価します。そのためBash(rm *)をdenyに入れておけば、python clean.py && rm -rf tmp/のように別コマンドと連結されたrmも個別に検知されます。
{
"permissions": {
"allow": ["Bash(python *)", "Bash(pytest *)"],
"deny": ["Bash(rm *)"]
}
}denyルールはallowルールより優先され、より広い範囲を指定したdenyは、それに含まれる狭いallowを上書きします。
denyが止めるのは「書かれた形のコマンド」だけ
Bashのルールは、Claudeが書いたコマンドの文字列に対して照合されます。同じrmでも/bin/rm -rf build/やbash -c 'rm -rf build/'は、Bash(rm *)のdenyには一致しません。公式の権限ドキュメントも、denyルールは「Claudeがいつも書く形」を止めるもので、プログラムの周りの境界ではないと説明しています。
pandas作業でこの差が効くのは、Bash(python *)のallowがpython -c "..."にも一致するためです。*は任意の文字列に一致するので、ワンライナーの中でファイルを消す処理を書かれても、allowの側では素通りします。ファイル削除を確実に防ぎたいなら、denyだけに頼らず、作業ディレクトリを使い捨てにする、元データを別の場所に置くといった構成が前提になります。
ステップ2: 集計スクリプトを生成させる
pandasの集計は、複数行をグループごとにまとめて計算する「split-apply-combine」という考え方に沿っています。列でグループ化し、各グループに関数を適用し、結果を1つの表に戻す流れです。Claude Codeにはこの流れをそのまま伝えると、groupby()とagg()を組み合わせたスクリプトを書きます。
import pandas as pd
df = pd.read_csv("sales.csv")
summary = df.groupby("region").agg(
total_amount=("amount", "sum"),
order_count=("order_id", "count"),
)
summary.to_csv("summary_by_region.csv")書かせたあとは、許可済みのBash(python *)ルールに沿ってそのまま実行させ、出力されたCSVの行数や合計値が入力データと矛盾していないかを確認させます。列名の誤りや欠損値の扱いはこの時点で見つかることが多く、対話の中でスクリプトを直しながら次のステップに進みます。
行×列で数値を突き合わせたい場合は、groupby().agg()の代わりにpivot_table()を使うようClaude Codeに指示します。pandasは集計を伴うピボットテーブルを1つの関数呼び出しで作れるため、縦横の表として得たいときに向きます。どちらを使うかは、結果を後続処理でそのまま使うか(groupby)、人が見て比較する表として出したいか(pivot_table)で決めると指示がぶれません。
ステップ3: 結合スクリプトで複数テーブルを合わせる
複数の表を1つにまとめる処理は、pandasではmerge()やconcat()によるデータベースに近いjoin操作として提供されています。列方向(横に並べる)と行方向(縦に積む)のどちらで結合するかを最初に決めておくと、生成させる指示がぶれません。
import pandas as pd
orders = pd.read_csv("orders.csv")
customers = pd.read_csv("customers.csv")
merged = orders.merge(customers, on="customer_id", how="left")
merged.to_csv("orders_with_customers.csv", index=False)結合キーの型が食い違っていたり、片方のテーブルにキーの重複があったりすると、結合後の行数が想定より増減します。Claude Codeに結合前後の行数をprint()で比較させておくと、この種のずれをその場で検出できます。
ステップ4: 検証ループを自動化する
検証ループの核は、スクリプトの側に条件を持たせることです。Claude Codeはpythonスクリプトを実行したBashツールの標準出力・標準エラー出力を読み取ります。assert文で行数や欠損値の条件を書いておけば、条件を外れたときのトレースバックがそのまま判断材料になります。
assertを軸にした検証ループ
- 1
assertを入れて実行する
スクリプトに行数・欠損値・合計値の条件を
assertで書き、許可済みのpythonコマンドで実行させます。 - 2
トレースバックを読ませる
条件を外れると
AssertionErrorが出力に出ます。どの列の、どの条件で落ちたかを読み取らせます。 - 3
スクリプトを直して再実行する
原因の列や結合キーを直し、同じコマンドで再実行させます。assertが通るまでこの往復が続きます。
人が毎回出力を目視するより、assertで機械的に検知できる条件を増やすほど、この往復の回数は減ります。
非対話モードで検証を回す
対話セッションでの確認に慣れたら、同じスクリプトを繰り返し検証する部分は非対話モードに寄せられます。claude -pに--allowedToolsを渡すと、指定したツールだけを自動承認したまま1回のプロンプトで完結させられます。
claude -p "scripts/aggregate.pyを実行し、出力のNaN行数が0であることを確認して" \
--allowedTools "Bash,Read"注意が要るのは終了コードの読み方です。公式ドキュメントでは、Claude Codeは成功すると終了コード0、実行が失敗すると非0のコードを返すと説明されています。この終了コードはclaudeの実行そのものの成否を表します。「NaNが0行だったか」のようなデータの判定結果は、終了コードには含まれません。
判定結果をシェルやCIで分岐に使いたいなら、--output-format jsonと--json-schemaを組み合わせ、structured_outputフィールドから値を取り出す方法があります。
claude -p "scripts/aggregate.pyを実行し、出力のNaN行数を返して" \
--allowedTools "Bash,Read" \
--output-format json \
--json-schema '{"type":"object","properties":{"nan_rows":{"type":"integer"}},"required":["nan_rows"]}' \
| jq '.structured_output.nan_rows'CIで毎回同じ条件にそろえたいときは--bareを付けます。手元のバージョンを見るには、次のコマンドを使います。
claude --version
claude --help | grep -A8 -e "--bare"
claude --help | grep -A3 -e "--permission-mode"v2.1.289ではclaude --versionが2.1.289 (Claude Code)を返し、--bareの説明は、フック・LSP・プラグイン同期・自動メモリ・キーチェーンの読み取り・CLAUDE.mdの自動検出を省くもので、CLAUDE_CODE_SIMPLE=1が設定されると書かれています。Anthropic APIの認証はANTHROPIC_API_KEYか、--settings経由のapiKeyHelperに限られます。Bedrockなどはそれぞれの認証情報を使います。--permission-modeの選択肢はacceptEdits・auto・bypassPermissions・manual・dontAsk・planの6つです。
--bareあり / なしの非対話実行
--bareなし
プロジェクトの.claude/settings.jsonのフックやMCPサーバーを読み込みます。PostToolUse hookによる自動チェックも効きます。サブスクリプションのログインも使えます。
--bareあり
フック・スキル・CLAUDE.mdを読み込まないので、どのマシンでも同じ結果になります。OAuthでのログインは使えません。
プランモードと実行方法の使い分け
変更方針を先に人が確認したい場合は、claude --permission-mode planでプランモードに切り替えます。ステータスバーに⏸ plan mode onと表示されている間、Claude Codeは承認されたプランが出るまで編集をブロックします。対話中はShift+Tabでもモードを切り替えられ、default→acceptEdits→planの順に進みます。プラン中もシェルコマンドは調査のために走ることがあり、スクリプト実行による上書きまでは止まりません。出力先を別名にするか、元データを退避しておきます。
実行方法は目的によって使い分けます。1つのスクリプトでも、開発が進むにつれて表の上から下へ移っていくのが自然な流れです。
| 目的 | 実行方法 | 向く場面 |
|---|---|---|
| 列名や結合キーを確認しながら試す | 実行方法通常の対話セッション | 向く場面スクリプトの設計をまだ固めていないとき |
| 固まったスクリプトを繰り返し実行 | 実行方法Bash(python *)などのallowルール | 向く場面検証ループを何度も回すとき |
| 変更方針を先に見せる | 実行方法--permission-mode plan | 向く場面編集の前に方針を確認したいとき |
| CIやバッチで自動判定する | 実行方法claude -p --allowedTools | 向く場面構造化出力を後続処理に渡すとき |
実行のたびに承認を挟まず、出力の異常だけを自動で拾いたい場合は、ファイル書き込み後に走るPostToolUse hookでCSVの行数チェックスクリプトを差し込む構成も組めます。ただし--bareではフックが動かないため、この構成は--bareなしの実行が前提です。承認の判定をコマンドの外から細かく制御したい場合は、Agent SDKのcanUseToolでBash呼び出しごとに許可・拒否を返すコールバックを書く方法もあります。
よくあるつまずき
Bash(python *)が対話的なpythonも許可してしまう
末尾の*の前にスペースがあるルールは、後ろに何も付かないpythonだけの起動にも一致します。対話的なインタプリタの起動まで許可したくない場合は、実行するスクリプトのパスまで含めた完全一致のルールを個別に用意します。
出力ファイルへのリダイレクトは別扱いになる
python analyze.py > result.csvのようにシェルのリダイレクトで出力先を切り替えると、Bashの許可ルールはコマンドの実行だけを許可します。リダイレクト先は、Editのallow・denyルール、保護パス、作業ディレクトリに照らして別に検査されます。先頭が~のパスやglob文字を含むパスは、許可ルールがあっても承認を求められます。
Excelを読み込むと依存パッケージ不足で落ちる
pd.read_excel()はpandas本体だけでは動かず、openpyxlのような追加パッケージを別途インストールする必要があります。CSVで検証が通っていたスクリプトを入力元だけExcelに変えるとImportErrorで止まることがあるため、入力形式を変えた回はこの種のエラーも検証ループの想定に含めておきます。
結合後の行数チェックを省略する
merge()は指定したキーが重複していると、その分だけ行が増えます。結合前後の行数をprintで比較する工程を省くと、想定より多い(または少ない)行数のまま次の集計に進んでしまい、誤りに気づくのが遅れます。
データソースがCSVではなくデータベースの場合、MCPサーバー経由で読み取り専用の接続を用意してからpandasに読み込ませる構成もあります。この場合に製品ごとで設定がどう違うかはデータベースMCPサーバーの読み取り専用設定の比較にまとめています。学習データのJSONLに対する重複・欠損の検査をスキーマで固定する流れは、panderaで学習データを検証する手順が扱っています。
まとめ
権限は、python系を広めにallowし、削除系はdenyに加えて作業ディレクトリごと使い捨てにできる構成で組みます。対話でも非対話でも、assertを持つスクリプトを実行して結果を直す往復は同じです。違うのは承認の取り方と、成否を人が読むか構造化出力で機械に渡すかだけです。集計した結果を論文の図に仕上げる工程は、論文図のdpiとフォントを揃える手順で扱っています。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。