AI で Excel や CSV を分析する locale
ローカル AI で Excel や CSV を分析するからといって、足し算をモデルに任せる必要はありません。このガイドでは作業を分担します。pandas がファイルを読み込んで計算し、二つ目のスクリプトが別の方法で再集計し、その後 Ollama で提供されるモデルが、検証済みの結果にコメントします。CSV 用の完全なコードと、Excel ワークブックに必要な変更点を掲載しています。実地で検証した内容と検証していない内容は、専用のセクションで正確に示しています。
#ローカル AI で Excel や CSV を分析する:計算するのは誰か、解釈するのは誰か
表を会話に貼り付けたくなるものです。回答は文章で返され、合計も正しそうに見えます。しかし、LLM はもっともらしいテキストを生成しているのであり、合計を書くときに計算を実行しているわけではありません。回答の中に、正しい数値と誤った数値を見分ける手がかりはありません。さらに、ファイルが長いほどモデルのコンテキストをあふれるおそれが高まり、明確なメッセージが出ないこともあります。
ここで提案する役割分担はシンプルです。同じ結果を再計算できるものはすべて、決定論的なツールに任せます。同じファイルと同じスクリプトからは同じ結果が得られ、その結果は検証できます。モデルには得意なことを任せます。つまり、結果を言葉にすること、確認すべき点を指摘すること、質問を提案することです。
- 読み込みと検証:pandas
- 列の有無、空のセル、数値の金額、想定形式の日付。スクリプトは推測せず、処理を停止します。
- 計算:pandas
- カテゴリ別の合計と構成比。faits.json ファイルに書き出されます。
- 検証:Python のみ
- 二つ目のスクリプトが pandas を使わずにソースファイルを読み直し、再集計します。差異が少しでもあれば、後続の処理はブロックされます。
- 解釈:ローカルモデル
- モデルが受け取るのは faits.json のみで、ファイルの行は受け取りません。モデルは数字を自分では一切書かずにコメントを作成します。
- 判断:あなた
- 合計が証明するのは総和であり、原因ではありません。モデルのコメントは、あくまで検討すべき手がかりです。
#text-to-SQL チュートリアルとの違い
私たちの経験とガイド付きルートを活かして、ローカルアシスタントを作り、AIを毎日の作業に取り入れましょう。
- 永久に利用できるオンラインスペース
- PDF + ファイル
- 30日間返金対応
QuelLLM では、すでにローカル環境での text-to-SQL チュートリアルを提供しています。どちらのガイドも LLM が結果を捏造するのを防ぎますが、LLM に与える役割は同じではありません。どちらを選ぶかは、主にニーズによって決まります。さまざまな質問をしたいのか、既知の計算を繰り返したいのかです。
- Text-to-SQL:モデルの役割
- フランス語の質問からクエリを作成します。その後、生成されたコードをデータベースが実行するため、読み取り専用ロールと SQL の検証が必要です。
- このガイド:モデルの役割
- コードは一切書かず、何も実行しません。計算はご自身で一度だけ記述し、その結果にモデルがコメントします。
- Text-to-SQL:選ぶべき場面
- データが PostgreSQL や MySQL にあり、質問が頻繁に変わる場合。
- このガイド:選ぶべき場面
- 定期的に同じ計算を行うエクスポートファイルまたはワークブック:月次の集計、カテゴリ別の内訳、支出の管理。
- このガイドの限界
- 新しい質問をするには、スクリプトの修正が必要です。これは、レビュー済みで再現可能な計算を得るための代償です。
#前提条件とサンプルファイル
- Ollama
- サービスが http://localhost:11434 で応答する必要があります。インストールガイドはページの末尾に記載しています。
- Python
- pandas 3 用の、Python 3.11 以降を使った仮想環境。
- 1つのモデル
- この例では qwen3.5:9b を使用します。Q4 で約 6.6 GB あり、RTX 3060 12GB に収まるサイズです。構造化出力のガイドと同じモデルですが、表形式データに対するコメントの品質については、ここでは評価していません。
- ダミーファイル
- まずは以下の小さなファイルから始めてください。合計を暗算で確認できるため、実際のデータを渡す前に、この構成が機能するかどうかを確かめられます。
これはフランスのエクスポートファイルでよく見られる形式です。列の区切りはセミコロン、小数点はカンマ、日付は日/月/年の順です。ご自身のファイルは、表示形式を変えてしまう Excel ではなく、テキストエディターで確認してください。
#ステップ 1:pandas で計算する
このスクリプトはファイルの形式を明示的に記述しており、疑わしい合計値を出力するよりも処理を停止することを優先します。2026年11月3日に参照したpandasのドキュメント(バージョン3.1.0)には、使用するパラメーターが記載されています。区切り文字を指定するsep、ヨーロッパ形式のデータに対応するdecimal、そしてon_bad_linesです。on_bad_linesのデフォルト値「error」は、不正な形式の行に対してエラーを発生させます。
二つの選択について説明が必要です。まず keep_default_na=False です。pandas のデフォルトのリストは、NA、N/A、null などを欠損値として扱います。そのため、「NA」というカテゴリが欠損値として読み込まれると、警告なしにグループ集計から消えてしまう可能性があります。次に、重複は数えますが、削除はしません。同じ日に同一の購入が二件あることは正当な場合もあり、この判断はご自身で行う必要があります。
サンプルファイルの場合、結果は手計算できます。A = 100 + 25 = 125、B = 50、合計は 175 です。出力は次の値と一致する必要があります。
#ステップ 2:別の方法で再集計する
決定論的な計算でも、区切り文字の誤り、列の読み違い、フィルターの指定漏れなどにより、完全に再現可能な形で誤ることがあります。そのため、この二つ目のスクリプトは pandas を信頼しません。標準モジュールの csv と decimal でソースファイルを読み直し、再集計して比較します。これは読み込みと加算の検証です。選択した計算がご自身の疑問に答えるものかどうかまでは示しません。
各ステップは && でつないでください。いずれかが失敗すると、次のステップは開始されません。そのため、検証で拒否された結果がモデルに渡ることはありません。
#ステップ 3:モデルに結果を解釈させる
モデルは faits.json の内容を受け取り、JSON スキーマに沿って回答します。これには、構造化出力のガイドで説明している Ollama の format パラメーターを使用します。このスキーマが定めるのは回答の形式であり、その正しさではありません。有効な安全策は別にあります。モデルは比較のために値を参照できますが、引用する際はキーで示さなければなりません。remplir 関数は、直接書かれた数値も、捏造されたキーもすべて拒否します。
このチェックですべてをカバーできるわけではありません。文字で書かれた数(「三倍」など)は検出できず、正しい値を使って組み立てられた誤った結論(たとえば、原因を確定したものとして提示する場合)も検出できません。転記された数値や捏造された数値はブロックしますが、人による確認は引き続き必要です。回答が拒否された場合は、手作業で修正しないでください。再実行するか指示を言い換えたうえで、拒否の記録を残してください。
集計値だけを送信することで、モデルが読み取れる内容も減ります。顧客名も、行に含まれる自由記述のテキストも渡されません。ただし、カテゴリのラベルは引き続き送信されるため、ファイルが外部から来たものである場合は、悪意のあるテキストが含まれている可能性があります。ここではモデルにツールがなく、テキストを生成することしかできないため、起こり得る被害は限定されますが、リスクがなくなるわけではありません。
#ステップ 4:Excel を分析する場合の変更点
.xlsxブックの場合、calculs.pyで変更するのは読み込み部分だけです。read_csvをread_excelに置き換え、パラメーターのsep、decimal、encoding、on_bad_linesを削除します。このブロックはExcelファイルでは実行していません。まず、合計値がわかっている小さなブックで試してください。
- エンジン
- ドキュメント 3.1.0 では、.xlsx には引き続きデフォルトで openpyxl が使われますが、この選択は将来のバージョンで calamine に変更される予定と告知されています。エンジンを明示しておけば、アップデート時に気づかないままエンジンが変わることを防げます。
- Feuille
- sheet_name のデフォルト値は 0 で、最初のシートを指します。None またはリストを指定すると、read_excel は単一の表ではなく表の辞書を返すため、上記のスクリプトを修正する必要があります。
- ヘッダー
- このスクリプトは、列名が最初の行にあることを前提としています。表の前にタイトルがある場合は、header パラメーターを使用するか、できればワークブックのコピーを整理してください。
- Dates
- 列に本物の Excel 日付が含まれている場合、スクリプトの日/月/年形式が適用されるとは限りません。faits.json の date_min と date_max を確認してください。
- 合計行
- シートの最下部に「Total」行があると、ひとつのカテゴリとして集計され、合計が倍になります。その場合、この行は faits.json にキーとして現れるため、このリストを確認してください。
ステップ 2 の検証は CSV を読み込みます。この検証を維持するには、Excel からシートをエクスポートし(名前を付けて保存、CSV UTF-8 形式)、python controle.py export.csv を実行してください。このエクスポートは pandas の読み込みエンジンではなく Excel を経由します。つまり別の読み込み経路であり、そこで生じる差異こそが確認したいものです。区切り文字を確認してください。スクリプトはセミコロンを想定しています。「1 250,00 €」のように表示形式付きでエクスポートされた金額は、見過ごされることなく検証の失敗を引き起こします。エクスポートするコピーではこの表示形式を解除してください。表示上の丸めを行う形式でも差異が生じることがあるため、同様に対処してください。
#検証済みの内容と、検証していない内容
30/10/2026 に、ダミーの CSV を pandas 3.0.2 で読み込んで集計し、検証の結果は A=125、B=50 でした。これが本ガイドにおける唯一の実地の証拠です。上記のサンプルファイルは読みやすさのためにこの合計値を踏襲していますが、公開したスクリプトの動作を証明するものではありません。
- 検証済み
- pandas 3.0.2 によるダミー CSV の読み込みと集計、合計は A=125、B=50(30/10/2026)。
- レビュー済み、未実行
- read_csv と read_excel のパラメーター。pandas 3.1.0 のドキュメント(03/11/2026 閲覧)に記載されています。このドキュメントは検証時のバージョンより新しいため、pip show pandas でお使いのバージョンを確認してください。
- 未確認
- 公開版の calculs.py、controle.py、interpreter.py の完全な実行、および出力される faits.json の値:記載の値は手計算によるものです。
- 未確認
- LLM の呼び出しすべて:コメントの品質、指示の遵守、拒否の頻度。そのため、回答例は掲載していません。
- 未確認
- 数式と CSV エクスポートを含む、Excel ファイルの読み込み全般。
測定を行っていないため、所要時間、エラー率、モデルの比較はここには記載していません。これらのスクリプトは、実際のデータに使う前にダミーファイルで試すためのベースとして扱ってください。意図的に失敗を起こすテストも有用です。faits.json の金額を変更すると、検証で結果が拒否されるはずです。また、数字を含むテキストを穴埋めの処理に渡すと、回答が拒否されるはずです。
#トラブルシューティング
- 「montant 列に数値以外のものが含まれています」
- 通貨記号、テキスト、または桁区切り文字が残っています。ファイルで桁区切り文字を使用している場合は、read_csv に thousands パラメーターを追加し、正しい文字を指定してください。フランスのファイルでは、多くの場合、目に見えないノーブレークスペースが使われています。その場合、検証スクリプトでも Decimal に渡す前に同じ文字を取り除く必要があります。
- ひとつの列しか読み込まれない、または列が見つからない
- 区切り文字が正しくありません。ファイルをテキストエディターで開き、calculs.pyのsepとcontrole.pyのdelimiterを修正してください。
- UnicodeDecodeError
- ファイルが UTF-8 ではありません。古い Windows のエクスポートは cp1252 であることが多いため、両方のスクリプトで encoding を変更し、カテゴリ名のアクセント記号を確認してください。
- 日付形式のエラー
- 日付が日/月/年の形式に従っていません。データを修正するか、format を調整してください。許容範囲の広い変換は、日と月の入れ替わりを隠してしまう可能性があるため、避けてください。
- 整合しない構成比
- 払い戻しやマイナスの金額がある場合、パーセントで表した構成比が 100 を超えたり、意味をなさなくなったりすることがあります。スクリプトはこれを警告しません。その場合は、faits.json からこれらの構成比を削除してください。
- 試行のたびに回答が拒否される
- 指示にもかかわらず、モデルが値を書き写しています。指示を言い換えるか別のモデルを試してください。ただし、ガードは外さないでください。
- Ollama 側の「Connection refused」
- サービスが起動していません。ollama list とアドレス http://localhost:11434 で確認してください。
#さらに詳しく
これらのガイドは、この構成をさらに発展させるものです。データがデータベースにある場合の text-to-SQL、format パラメータを使う構造化出力、外部から入手したファイルに隠された指示に関するリスクを扱っています。
ご意見、誤りのご指摘、補足はありますか?ぜひお知らせください。皆さんにとってより良いガイドにするために役立ちます。