AgentSkillsCN

survey-report-builder

从 CSV 问卷数据中构建 Quarto 报告(PDF)与演示文稿(PPTX)。适用于“分析问卷”、“survey analysis”、“制作报告”、“进行汇总”等请求中使用。

SKILL.md
--- frontmatter
name: survey-report-builder
description: CSVアンケートデータから Quarto レポート(PDF)と発表用スライド(PPTX)を構築するスキル。「アンケートを分析して」「survey analysis」「レポートを作成」「集計して」などのリクエストで使用する。
disable-model-invocation: true
argument-hint: "[csv-file-path]"

アンケート分析レポート構築

data/ に配置された CSV アンケートデータから、Quarto レポート(PDF)と発表用スライド(PPTX)を構築する。

目次

  1. 前提チェック・CSV読み込み
  2. 列の分類
  3. metadata.json 作成
  4. index.qmd 構築
  5. スクリプト追加
  6. quarto render
  7. PPTX生成(任意)

進捗チェックリスト

code
- [ ] Step 1: 前提チェック・CSV読み込み・列構造把握
- [ ] Step 2: ユーザーと列分類を確認
- [ ] Step 3: exam_metadata.json 作成
- [ ] Step 4: index.qmd 構築(setup → セクション)
- [ ] Step 5: pyproject.toml にスクリプト追加
- [ ] Step 6: quarto render → エラー修正 → 再render
- [ ] Step 7: PPTX スライド生成(該当時)

ステップ1: 前提チェックとCSV読み込み

まず前提条件を確認する:

bash
uv --version && quarto --version
python -c "import pandas; import matplotlib; print('OK')"

いずれかが失敗する場合は /quarto-survey-setup を先に実行するよう案内する。

次に引数 [csv-file-path] を読み込み、列構造を把握する:

python
import pandas as pd
df = pd.read_csv("[csv-file-path]", encoding="utf-8-sig")
print(f"回答数: {len(df)}, 列数: {len(df.columns)}")
for col in df.columns:
    print(f"  {col}: {df[col].nunique()} unique, {df[col].isna().mean()*100:.0f}% missing")

ステップ2: 列の分類

各列を以下の4カテゴリに分類する。必ずユーザーに確認しながら進める:

カテゴリ判定基準分析方法
タイムスタンプ日時形式回答期間の算出のみ
Likert尺度5段階の順序カテゴリ度数分布 + 横棒グラフ + クロス集計
カテゴリ有限個の名義変数度数分布 + 横棒グラフ
自由記述テキスト長が長い / ユニーク値が多いキーワード分類 + 質的分析

ユーザーへの確認事項:

  • 各列がどのカテゴリに該当するか
  • Likert尺度の順序(ネガティブ→ポジティブ or 逆)
  • クロス集計に使用する属性列
  • 自由記述のキーワード分類ルール

ステップ3: data/exam_metadata.json 作成

ユーザーからのヒアリングを基にメタデータ JSON を作成する:

json
{
  "exam": {
    "name": "試験・調査の名称",
    "date": "YYYY-MM-DD",
    "date_display": "YYYY年MM月DD日(曜日)"
  },
  "survey": {
    "target": "対象者の説明",
    "target_total": 0,
    "respondents": 0,
    "response_rate": 0.0
  },
  "label_map": {
    "column_name": "日本語表示ラベル"
  }
}

label_map: CSV の全列名をキーとし、日本語表示ラベルを設定する。グラフのタイトル・凡例・軸ラベルで使用される。

ステップ4: index.qmd 構築

4-1. YAML ヘッダ

yaml
---
title: "レポートタイトル"
subtitle: "サブタイトル"
date: today
editor:
  render-on-save: true
---

4-2. setup ブロック

以下を含む setup コードブロックを作成する:

python
#| label: setup
#| include: false

import json
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
from pathlib import Path

matplotlib.rcParams["svg.fonttype"] = "none"
matplotlib.rcParams["figure.dpi"] = 150
matplotlib.rcParams["font.family"] = "Yu Gothic"

OUTPUT_DIR = Path("output")
FIGURES_DIR = OUTPUT_DIR / "figures"
TABLES_DIR = OUTPUT_DIR / "tables"
FIGURES_DIR.mkdir(parents=True, exist_ok=True)
TABLES_DIR.mkdir(parents=True, exist_ok=True)

4-3. ヘルパー関数

setup ブロック内に以下の4関数を定義する。実装は $SKILL_ROOT/scripts/helpers.py を参照してそのままコピーする:

bash
# ヘルパー関数の実装を確認
cat "$SKILL_ROOT/scripts/helpers.py"
関数用途
save_summary(series, name, label)度数分布表の CSV 保存
plot_horizontal_bar(series, title, order, name, ...)横棒グラフ(件数・割合ラベル付き)
plot_cross_tab(df, row_col, col_col, ...)クロス集計の積み上げ棒グラフ
save_table_svg(df, name, title, ...)DataFrame のテーブル SVG 化

カラーパレットも helpers.py に定義済み:

  • COLORS — 10色メインパレット
  • DIFFICULTY_CMAP — 5段階 Likert 用(ネガティブ→ポジティブ)

4-4. セクション構成

index.qmd の本文を以下の順序で構成する。各セクションは独立した Quarto コードブロックとする:

A. はじめに

  • 調査の概要説明テキスト
  • 試験・調査概要テーブル(save_table_svg() 使用)
  • アンケート概要(対象者数、回答率、回答期間)

B. 回答者の属性

  • 属性列ごとに save_summary() + plot_horizontal_bar()
  • 属性同士のクロス集計(plot_cross_tab()

C. 各設問の集計・可視化

  • Likert尺度: 順序定義 → save_summary()plot_horizontal_bar()plot_cross_tab()
  • カテゴリ: save_summary() + plot_horizontal_bar()(自由記述混合時は正規化関数を定義)

D. 自由記述の分析

  • キーワードマッチングによる分類関数を定義
  • 複数カテゴリ該当の処理(1回答 → 複数カテゴリ)
  • 「なし」「特になし」系の事前除外
  • 分類結果の横棒グラフ + 利用率スタック棒グラフ

E. 質的分析セクション(テーマ分析がある場合)

  • output/improvement_qualitative.csv を読み込み
  • テーマ別件数の横棒グラフ + 代表的引用一覧

F. まとめ

  • 各設問の主要所見を自動集計・出力(最頻値・割合を動的算出)

4-5. コードブロックの規約

code
#| label: fig-{topic}          # 図の場合
#| label: {topic}              # テキスト出力の場合
#| fig-cap: "キャプション"     # 図の場合
#| output: asis                # Markdown テキスト出力の場合
#| include: false              # setup ブロックのみ

ステップ5: pyproject.toml にスクリプトを追加

[project.scripts] に以下を追加(まだ存在しない場合):

toml
[project.scripts]
render = "run_commands:render"
preview = "run_commands:preview"

質的分析から PPTX を生成する場合:

toml
slides = "generate_theme_slides:main"

ステップ6: quarto render でPDF生成

bash
uv run render

エラー時のフィードバックループ: エラーが出たら修正して再度 render する。よくあるエラー:

  • KeyError: 列名が CSV と不一致 → df.columns で確認
  • FileNotFoundError: データファイルのパス誤り
  • フォントエラー: matplotlib-fontja 未インストール → uv sync

ステップ7: PPTX スライド生成(任意)

質的分析結果がある場合、$SKILL_ROOT/scripts/generate_theme_slides.py を参考にスライド生成スクリプトを作成する:

bash
# スクリプトの実装を確認
cat "$SKILL_ROOT/scripts/generate_theme_slides.py"

プロジェクトルートにコピーしてデータパスを調整する。前提ファイル:

  • output/improvement_qualitative.csv — 質的分析コーディング結果
  • output/summary_improvement_themes.csv — テーマ別集計

出力規約

ファイル命名

種類パス命名規則
度数分布 CSVoutput/summary_{topic}.csv列名に対応
クロス集計 CSVoutput/summary_{topic}_cross.csv行列列名を結合
横棒グラフ SVGoutput/figures/{topic}.svg列名に対応
テーブル SVGoutput/tables/{topic}.svgテーブル名に対応
ID付き全回答output/responses_with_id.csv固定名
自由記述抜粋output/free_text.csv固定名
PPTXoutput/{topic}.pptxテーマ名に対応

CSV フォーマット

  • エンコーディング: UTF-8 with BOM (encoding="utf-8-sig") — Excel互換

SVG 設定

  • matplotlib.rcParams["svg.fonttype"] = "none" — テキスト要素を保持
  • フォント: Yu Gothic(日本語対応)
  • DPI: 150

自由記述のキーワード分類パターン

python
def classify_responses(text):
    """自由記述を複数カテゴリに分類する."""
    text_lower = str(text).lower()
    categories = []
    if "キーワードA" in text or "keyword_a" in text_lower:
        categories.append("カテゴリA")
    if "キーワードB" in text:
        categories.append("カテゴリB")
    if not categories:
        categories.append("その他")
    return categories

分類時の注意:

  • str.lower() で英字を統一、日本語は原文のまま比較
  • 1回答が複数カテゴリに該当する場合は全て返す
  • 「なし」「特になし」系は専用リストで先に除外
  • 「その他」は末尾に配置

質的分析の CSV フォーマット

csv
id,テーマ,引用,代表的
R001,テーマA,引用テキスト,1
R001,テーマB,引用テキスト,0
R002,テーマA,引用テキスト,0
  • id: 回答者ID(R001形式)
  • テーマ: 分類先テーマ名
  • 引用: 該当テキスト
  • 代表的: 代表的引用は 1、それ以外は 0

注意事項

  • Likert尺度の順序は必ずユーザーに確認する
  • 日本語ラベルは label_map から取得する
  • 自由記述の分類ルールはデータ固有(汎用ルールはない)
  • quarto render 前に uv sync で依存関係を最新にする