powered by TechFeed
表示モード
Deep Dive

ChatGPTに3つのデータセットを分析させたら毎回同じ箇所で間違えた — コードは正しくても答えが2.4倍ズレる理由

9月3日、KDNuggetsが「I Asked ChatGPT to Analyze 3 Datasets. It Made the Same Mistakes Every Time」と題した記事を公開した。ChatGPTに「平均配送時間は?」と聞いたところ、返ってきた数字は正解の2.4倍小さい値だった。コードにバグは一切なく、エラーも出ない。それでも答えは間違っている——この実験レポートは、LLMをデータ分析に使う際に見落とされがちな構造的な問題を、3つの小規模データセットを通じて記録している。

9月3日、KDNuggetsが「I Asked ChatGPT to Analyze 3 Datasets. It Made the Same Mistakes Every Time」と題した記事を公開した。ChatGPTに「平均配送時間は?」と聞いたところ、返ってきた数字は正解の2.4倍小さい値だった。コードにバグは一切なく、エラーも出ない。それでも答えは間違っている——この実験レポートは、LLMをデータ分析に使う際に見落とされがちな構造的な問題を、3つの小規模データセットを通じて記録している。


実験の概要

使用したのは3つの小さなデータセット、記事内で「GPT-5.6 Terra」(高速応答モデル)・「GPT-5.6 Luna」(低速・高精度モデル)と呼ばれる2種類のモデル(※元記事内での呼称。2026年9月時点でOpenAIが公式発表したモデル名とは異なる可能性がある)、そしてPandasSciPyを使ったコード検証だ。ビジネスチームが普通の週に問いかけるような質問——「平均配送時間は?」「どの地域が最高のパフォーマンスか?」「このファイルのアスリート数は?」——を投げた。さらに、回答を別セッションに貼り付けて「役員向け資料に使うので数値を全部検証してくれ」と1回のレビューパスを依頼した。結果は後述するが、レビューが誤りを増やしたケースもあった。

なお、LLMがコードを「生成する」ことと「実行する」ことは本質的に異なる操作であり、後者が保証されない環境ではコードブロックの隣に書かれた数字が実際の計算結果とは無関係に生成されうる。この「コード生成と実行の混同問題」は本実験のミス2・ミス4の根底にある構造的課題でもある。また、LLMが事実と異なる内容を自信を持って出力するいわゆるHallucination(幻覚)問題が、数値データの文脈でどう現れるかを具体的に記録した事例としても本記事は参照価値がある。


ミス1(最重要):「注文から到着まで」を聞いたのに「出荷から到着まで」を答えた

shipment_tracking(40件の注文、各行にordered_dateshipped_datedelivered_dateを持つ)で「平均配送時間」を質問したところ、モデルが返したコードはこうだ。

df['delivery_days'] = (df['delivered_date'] - df['shipped_date']).dt.days
print(f"Avg delivery: {df['delivery_days'].mean():.1f} days")

出力: 2.6日

しかし顧客が体感する「待ち時間」は注文日から始まる。正しい計算はこちらだ。

order_to_door = (df['delivered_date'] - df['ordered_date']).dt.days
print(round(order_to_door.mean(), 2))

出力: 6.09日

正解の2.4倍小さい数字を答えとして出した。

このミスが最も厄介な理由は、コードにバグが一切ない点だ。Pandasとして完全に有効な引き算を実行しており、エラーも例外も型チェックも何も引っかからない。「どの2列を引いたか」を人間が読んで確認する以外に検出手段がない。ship-to-doorはウェアハウスの効率指標であり、order-to-doorは顧客の待ち時間だ。聞いたのは後者なのに、前者の数字がサマリーの冒頭に書かれて会議に持ち込まれる。


ミス2:コードが実行されていないのに数字が書かれた

同じshipment_trackingの回答の末尾に次のような注記があった。

Heads up: Only 22 of 50 orders have delivery dates yet (28 still in transit/pending).

ファイルの行数は40だ。

print(len(df), df['delivered_date'].notna().sum(), df['delivered_date'].isna().sum())
# 出力: 40  22  18

22は正しい。50と28はどのコードも計算も出力も行っていない数字だ。しかも50−22=28と内部的に一致しているため、頭の中で暗算した読者は気づかない。

regional_sales(59行、8地域、2007〜2025年の売上データ)では被害がさらに大きかった。「最も成績の良い地域は?」と聞いたところ、APACを「**$3.68M、全地域売上の32%**」と報告した。

print(round(df.groupby('region_name')['sales'].sum()['apac'], 2))
# 出力: 3675.49

実際の合計は3675.49(単位なし)で、シェアは30.4%だ。金額を約1000倍に誇張し、存在しない通貨記号を付け、計算していないシェアを書いた。そのセッションのログを確認すると、コードを一切実行していなかった。Pandasのコードスニペットを表示し、その下に数字を書いただけだ。

コードを実行したLunaモデルの別の回答でも同様の問題が起きた。「APACはUS WestとUS Eastの合計より60%以上高い」と書いたが、実際の差は**2.8%**だった。同じ1文の中で、一方の比較は正確(32.2%と書いて実際も32.2%)、もう一方は完全な捏造だった。

コードブロック内の数字は計算されたもの、その周囲の文章の数字は書かれたものだ。この2つが一致することを保証する仕組みは何もない。


ミス3:未着の注文を除外して「配送が速くなっている」と結論

shipment_trackingで「配送は速くなっているか、遅くなっているか」と聞いたところ、「速くなっている、週1が3.2日・週3が1.0日」という回答が来た。両方の数字は実在する。結論は逆だ。

注文数 配送完了数 平均日数
1 15 12 3.17
2 15 7 2.29
3 10 3 1.00

ファイルは1月21日で終わる。週3の注文はデータ収録時点で3日しか経過していない。週3の10件中7件には配送日がない。「速い注文だけが完了して計測されている」のであり、遅い注文はまだ届いていないため除外されている。未解決注文の比率は週1の20%から週3の70%に上昇しているのが、このトリックの証拠だ。

これはアンケート調査や臨床試験の分野で知られる生存者バイアス(完了・観測できたものだけをサンプルに含めることで生じる系統的誤差)の一形態であり、時系列データの分析では特に注意が必要なパターンだ。同じファイルをLunaモデルに渡したところ、自発的に警告を出して「この改善は見かけ上のものだ」と開いた。同じ罠、同じデータ、反対の結論だ。


ミス4:226行の欠損を黙って除外して「身長は関係ない」と結論

olympics_athletes_events(352行、1行=1選手1競技)で「身長はメダル獲得に影響するか」と聞いた。返ってきた答えは「メダリストは0.3cm高いだけ、ほぼ関係ない」。

問題は、この比較が352行中126行だけを対象にしたことだ。身長が空欄の226行をPandasが無言で除外した。

print(round(df[df['height'].notna()]['medal'].notna().mean() * 100, 1))
print(round(df[df['height'].isna()]['medal'].notna().mean() * 100, 1))
# 出力: 54.0 / 23.0

身長が記録されている選手のメダル率は54%、記録されていない選手は23%だ。カイ二乗検定(2つのカテゴリ変数間の独立性を検定する統計手法)のp値は9e-09。「値が存在するかどうか」が「値そのもの」よりはるかに強くメダルを予測する。

原因は年代だ。2016年以前の302行のうち身長が記録されているのは76行だけで、メダル率は26.5%。2016年以降の50行は全員身長が記録されており、メダル率は80%。「身長が記録されていること」「最近の大会であること」「メダルを獲得していること」がほぼ同義になっているデータだ。「身長はメダルに影響するか」への正直な答えは「このファイルでは判断できない」であり、それを伝える方がステークホルダーには有益だ。


レビューパスで何が起きたか

各回答を別セッションに貼り付け、「役員向け資料に使うので全数値を検証せよ」と依頼した結果:

  • shipment_trackingのレビューは「50→40、28→18」の捏造数字を正しく修正した。しかしその直後に「3つの主要指標はすべて正確」と記して、ミス1(間違った列の引き算)とミス3(未着注文バイアス)にチェックマークを付けた。18件の未配送注文を数えたその結果を使えばミス3を発見できたはずなのに、2行下の主張に結びつけなかった。

  • olympics_athletes_eventsのレビューは実際には存在しないミスを「発見」し、正しかった答えを誤りに書き換えた。

検証スタンプが付いた回答が、元の誤りより多くの誤りを含んでいた。


まとめ:何を確認すべきか

記事が示す検出チェックリストは次の通りだ。

  • カラム名を読め:コードが動いていてもどの列を使ったかを確認する
  • コードが実際に実行されたか確認する:文章中の数字がコード出力に存在するか照合する
  • 集計前に欠損の意味を問う:欠損がランダムでないなら集計結果は歪む
  • 行数を確認する:「何行を対象に計算したか」が回答に書かれていない場合は自分で確認する

※編集部の考察:本実験はデータセット3件・特定モデル構成という限られた規模のものであり、ここで示されたミスパターンがすべてのLLM・すべてのデータ分析タスクに普遍的に当てはまるとは言えない。ただし、「コードの正しさ」と「答えの正しさ」が別問題になりうるという指摘は、LLMをデータパイプラインに組み込む際に設計上考慮すべき論点として一般性がある。

詳細はI Asked ChatGPT to Analyze 3 Datasets. It Made the Same Mistakes Every Timeを参照していただきたい。