データ分析エージェントを構築する
CSVファイルと自然言語の質問を受け取り、pandasとmatplotlibのコードを反復的に記述して、完成度の高いレポートを生成するエンドツーエンドのデータ分析エージェントを作成します。
「データ分析エージェントを構築する」はCoddyKit上の無料AI Engineering Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Engineering Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Engineering Academyコースには全4レッスンが含まれています。
データ分析エージェントの構想
データ分析エージェントはCSVファイルと自然言語の質問を受け取り、データを自律的に探索・クリーニングし、統計を計算し、可視化を生成して、完成度の高いレポートを作成します。これらすべてを反復的なコード生成と実行によって行います。これはコードエージェントの最も実用的な用途の1つであり、人手を必要としない点を除けば、データアナリストのワークフローを直接再現するものです。
エージェント全体のアーキテクチャ
データ分析エージェントには、概念上4つのフェーズがあります。探索(データの形状、型、品質を把握する)、クリーニング(欠損値、外れ値、型変換を処理する)、分析(質問に答える指標と統計量を計算する)、レポート作成(グラフを生成し、調査結果を文章で要約する)です。各フェーズは1~5回のコード実行反復に対応します。
DATA_AGENT_SYSTEM_PROMPT = '''
You are a data analysis agent. Given a CSV file and a question, answer it through iterative Python code.
Phases to follow:
1. EXPLORE: Load the data, print shape, dtypes, head(), describe(), and check for nulls.
2. CLEAN: Handle missing values, fix dtypes, remove outliers.
3. ANALYZE: Compute statistics, groupbys, correlations - whatever answers the question.
4. REPORT: Generate a matplotlib chart saved to /workspace/chart.png and write a text summary.
Rules:
- Write code in ```python ... ``` blocks.
- Save intermediate results to /workspace/ for use in later steps.
- Print key findings after each computation so you can observe them.
- When all phases are done, say TASK COMPLETE and summarize the answer.
'''フェーズ1:データ探索コード
探索フェーズではデータを読み込み、分析計画に必要なすべての情報を直ちに出力します。具体的には、形状、列名と型、サンプル行、要約統計量、nullの件数です。LLMはこの出力を読み取り、後続の反復でクリーニングと分析について適切な判断を下します。
import pandas as pd
import numpy as np
# Load dataset
df = pd.read_csv('/workspace/data.csv')
# Basic exploration
print('=== SHAPE ===' )
print(df.shape)
print('\n=== DTYPES ===')
print(df.dtypes)
print('\n=== HEAD ===')
print(df.head())
print('\n=== DESCRIBE ===')
print(df.describe(include='all'))
print('\n=== NULL COUNTS ===')
print(df.isnull().sum())
print('\n=== UNIQUE VALUES (categorical) ===')
for col in df.select_dtypes(include='object').columns:
print(f'{col}: {df[col].nunique()} unique values: {df[col].unique()[:5]}')
# Save for next iteration
df.to_parquet('/workspace/raw.parquet')
print('\nData saved to workspace.')フェーズ2:データクリーニング
探索後、エージェントは観察結果に基づいて、対象を絞ったクリーニングコードを書きます。クリーニング戦略は動的です。たとえば、ある列に15%のnullがあることをLLMが確認した場合、削除するか補完するかを判断します。また、本来負ではない列に負の値があれば、それらをフィルタリングします。このように観察結果に適応するクリーニングによって、固定されたパイプラインを実行するだけでなく、エージェントが本当に役立つものになります。
import pandas as pd
import numpy as np
# Load from previous iteration
df = pd.read_parquet('/workspace/raw.parquet')
# Fill numeric nulls with median (robust to outliers)
for col in df.select_dtypes(include='number').columns:
if df[col].isnull().sum() > 0:
median_val = df[col].median()
df[col] = df[col].fillna(median_val)
print(f'Filled nulls in {col} with median {median_val:.2f}')
# Drop rows where categorical key columns are null
df = df.dropna(subset=['category', 'date'])
# Fix date column type
df['date'] = pd.to_datetime(df['date'], errors='coerce')
df = df.dropna(subset=['date']) # drop unparseable dates
# Remove clear outliers: revenue > 3 std deviations from mean
if 'revenue' in df.columns:
z_scores = (df['revenue'] - df['revenue'].mean()) / df['revenue'].std()
df = df[z_scores.abs() < 3]
print(f'Removed outliers, rows remaining: {len(df)}')
df.to_parquet('/workspace/cleaned.parquet')
print('Cleaning complete:', df.shape)フェーズ3:質問への回答
分析フェーズでは、エージェントはユーザーの質問に対する具体的な答えの計算に集中します。質問が「前四半期の売上が最も高かった商品カテゴリはどれか」であれば、日付でフィルタリングし、カテゴリごとにグループ化し、売上を合計して並べ替えるコードを書きます。分析コードは、質問と探索中にエージェントが確認した内容の両方に基づいて毎回新たに生成され、汎用テンプレートではありません。
import pandas as pd
import matplotlib
matplotlib.use('Agg') # non-interactive backend for server use
import matplotlib.pyplot as plt
df = pd.read_parquet('/workspace/cleaned.parquet')
# Analysis: revenue by category for last quarter
df['date'] = pd.to_datetime(df['date'])
last_quarter = df[df['date'] >= '2024-10-01']
revenue_by_category = (
last_quarter
.groupby('category')['revenue']
.sum()
.sort_values(ascending=False)
)
print('Revenue by category (last quarter):')
print(revenue_by_category)
print(f'\nTop category: {revenue_by_category.index[0]} (${revenue_by_category.iloc[0]:,.0f})')
# Save analysis result
revenue_by_category.to_json('/workspace/analysis_result.json')フェーズ4:グラフの生成
可視化によって、分析結果は明確で説得力のあるものになります。データ分析エージェントはmatplotlibのグラフを生成し、ワークスペースにPNGファイルとして保存します。グラフの種類、カラーパレット、軸ラベル、タイトル、注釈といった重要な設計上の判断は、データの性質に基づいてLLMが行います。最終レポートに含められるよう、エージェントは常にグラフを/workspace/に保存します。
import pandas as pd
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import json
with open('/workspace/analysis_result.json') as f:
data = json.load(f)
categories = list(data.keys())
values = [data[k] / 1e6 for k in categories] # convert to millions
fig, ax = plt.subplots(figsize=(10, 6))
bars = ax.barh(categories, values, color='steelblue', edgecolor='white')
# Add value labels on bars
for bar, val in zip(bars, values):
ax.text(bar.get_width() + 0.05, bar.get_y() + bar.get_height()/2,
f'${val:.1f}M', va='center', fontsize=11)
ax.set_xlabel('Revenue ($ Millions)', fontsize=12)
ax.set_title('Revenue by Product Category - Q4 2024', fontsize=14, fontweight='bold')
ax.invert_yaxis() # highest on top
plt.tight_layout()
plt.savefig('/workspace/chart.png', dpi=150, bbox_inches='tight')
print('Chart saved to /workspace/chart.png')文章レポートの生成
最後の反復で、文章による要約レポートを作成します。LLMは分析結果とグラフの説明を読み取り、具体的な数値を用いて元の質問に答える、簡潔で正確な文章を書きます。レポートではグラフに言及し、主要な洞察、裏付けとなるデータ、ビジネス上の推奨事項または示唆を含めます。
import json
with open('/workspace/analysis_result.json') as f:
revenue_data = json.load(f)
top_category = max(revenue_data, key=revenue_data.get)
top_revenue = revenue_data[top_category]
total_revenue = sum(revenue_data.values())
share = top_revenue / total_revenue * 100
report = f'''# Q4 2024 Revenue Analysis
## Answer
The **{top_category}** category generated the highest revenue in Q4 2024:
**${top_revenue:,.0f}** ({share:.1f}% of total Q4 revenue).
## Key Findings
- Total Q4 revenue: ${total_revenue:,.0f}
- Top 3 categories: {list(revenue_data.items())[:3]}
- The top category outperformed the average by {top_revenue / (total_revenue / len(revenue_data)):.1f}x
## Chart
See chart.png for the full breakdown by category.
## Recommendation
Consider reallocating marketing budget toward {top_category} to
capitalize on its demonstrated strong performance.
'''
with open('/workspace/report.md', 'w') as f:
f.write(report)
print('TASK COMPLETE')
print(report)エージェントオーケストレーターの組み立て
オーケストレーターはすべてのフェーズを連携させます。ワークスペースを初期化し、入力CSVをコピーし、コード実行ループを実行し、TASK COMPLETEシグナルを監視してから、出力ファイル(report.md、chart.png)を収集します。また、エラー、再試行、中間ファイルの最終的なクリーンアップも処理します。
import shutil
from pathlib import Path
def run_data_analysis_agent(csv_path: str, question: str) -> dict:
workspace = setup_workspace()
shutil.copy(csv_path, workspace / 'data.csv')
messages = [
{'role': 'system', 'content': DATA_AGENT_SYSTEM_PROMPT},
{'role': 'user', 'content': f'File: /workspace/data.csv\nQuestion: {question}'}
]
state = ExecutionState(task=question)
for iteration in range(15): # max 15 iterations
response = llm.complete(messages)
code = extract_code_block(response)
if not code or 'TASK COMPLETE' in response:
break
stdout, stderr = execute_in_docker(code, workspace=workspace)
observation = format_observation(stdout, stderr)
messages += [
{'role': 'assistant', 'content': response},
{'role': 'user', 'content': observation}
]
state.after_execution(stdout, f'iteration_{iteration}')
return {
'report': (workspace / 'report.md').read_text() if (workspace / 'report.md').exists() else '',
'chart_path': str(workspace / 'chart.png'),
'iterations': state.iteration
}曖昧な質問への対応
ユーザーは「業績が好調な商品はどれですか?」のような曖昧な質問をよくします。堅牢なデータ分析エージェントは、開始前に曖昧さを明確にします。まずデータを探索して利用可能な指標を特定し、最も妥当な解釈を推測するか、ユーザーに уточ明を求めます。この振り返りのステップにより、技術的には正しいものの実用上は役に立たない回答をエージェントが生成することを防げます。
def handle_ambiguous_question(question: str, df_summary: dict) -> str:
clarification_prompt = f'''The user asked: '{question}'
Available data:
- Columns: {df_summary['columns']}
- Date range: {df_summary['date_range']}
- Metrics available: {df_summary['numeric_columns']}
Is the question clear enough to answer definitively?
If yes, restate the specific interpretation you will use.
If no, list the 2-3 clarifications needed to proceed.'''
response = llm.complete([{'role': 'user', 'content': clarification_prompt}])
return responseエージェント出力の品質チェック
エージェントの処理が完了したら、その出力の品質を検証します。レポートファイルが実際に作成されていること、チャートのPNGが有効な画像ファイルであること、レポート内の数値がanalysis_result.jsonのデータと一致していること、そしてレポートが元の質問に実際に答えていることを確認してください。2回目のLLM呼び出しを使った自動QAステップを設けると、エージェントが一連の処理を完了したものの、質の低い回答を生成したケースを検出できます。
def validate_analysis_output(workspace: str, question: str, report: str) -> dict:
validation_prompt = f'''Original question: {question}
Agent report:
{report[:2000]}
Rate this analysis on a scale of 1-5 for:
1. Does it directly answer the question? (1=No, 5=Yes)
2. Are specific numbers cited? (1=No, 5=Yes)
3. Is the conclusion clearly stated? (1=No, 5=Yes)
Return JSON: {{"question_answered": N, "numbers_cited": N, "clear_conclusion": N, "overall": N}}'''
result = llm.complete([{'role': 'user', 'content': validation_prompt}],
response_format={'type': 'json_object'})
scores = json.loads(result)
passed = scores['overall'] >= 4
return {'scores': scores, 'passed': passed}エージェントをドメイン固有のツールで拡張する
基本的なコードエージェントは、ドメイン固有のツールで拡張すると、さらに強力になります。金融データエージェントには、株価の最新情報を取得する関数を追加します。マーケティングデータエージェントには、Google Analytics APIへのアクセスを追加します。営業エージェントには、Salesforceへのクエリを追加します。これらのツールは、システムプロンプト内の関数定義、またはLangChainの@toolデコレーターを通じてLLMから利用できるようになります。
クイックチェック
このレッスンで学んだデータ分析エージェントについての理解度を確認しましょう。
レッスンのまとめ
このレッスンでは、次のことを学びました。データ分析エージェントは、探索、クリーニング、分析、レポートという4つのフェーズに従い、各フェーズをコードの反復的な生成と実行によって実装します。matplotlibによるチャート生成とファイルベースの状態永続化によって各フェーズが結び付けられ、一貫したワークフローが構成されます。また、出力の検証により、エージェントの最終回答が元の質問に実際に答えていることを確認できます。次は、LLMの可観測性とトレーシングについて学びます。
よくある質問
「データ分析エージェントを構築する」レッスンは無料ですか?
はい。「データ分析エージェントを構築する」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Engineering Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Engineering Academyコースには全4レッスンが含まれています。
「データ分析エージェントを構築する」で何を学びますか?
CSVファイルと自然言語の質問を受け取り、pandasとmatplotlibのコードを反復的に記述して、完成度の高いレポートを生成するエンドツーエンドのデータ分析エージェントを作成します。 ブラウザで直接実行するハンズオンコードでAI Engineering Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
AI Engineering Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAI Engineering Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「データ分析エージェントを構築する」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAI Engineering Academyレッスンでコードを書いて実行できますか?
はい。すべてのAI Engineering Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- コード実行ループ
- DockerとRestrictedPythonによるサンドボックス化
- 実行ステップ間の状態管理
- データ分析エージェントを構築する