論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説
📚 用語解説
F1スコア
F1 Score
評価指標
別称: F1

🔖 キーワード索引

#分類評価#Precision#Recall#不均衡データ#harmonic mean#macro F1

f1 score」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「f1 score」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。

f1 score統計分析SSDSE-B-2026前提条件適用範囲落とし穴関連手法Python 実装検証方法

これらのキーワードは「f1 score の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。

💡 30秒で分かる結論

🍰 まずはやさしく

2つの指標をまとめた点数のようなものです。

予測の正しさを公平に測るために使います。

スマホのアプリが正しく動くか確かめる時に便利です。

この章ではF1スコアの結論を短くまとめます。

F1スコア:PrecisionとRecallの調和平均

💡 F1 にまつわるトリビア

📍 文脈ボックス

🍰 まずはやさしく

AIなどの性能を測るための物差しです。

分析の結果がどれくらい正しいかを知るために使います。

部活のデータ分析などで結果を評価する時に役立ちます。

この章ではF1スコアの全体像について学びます。

この用語は 評価指標 カテゴリに属します。 関連する別称・略号:F1

論文・実務レポートで F1スコア が登場したら、 まず本ページの「30秒で分かる結論」と「直感で掴む」を読めば、 その文脈で何を言っているか把握できます。

本ページでは「f1 score」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。

「f1 score」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。

🎨 直感で掴む

🍰 まずはやさしく

正解率だけでは見えない落とし穴を教える道具です。

偏ったデータでも正しく評価するために使います。

ごく一部の人だけが当てはまる予測をする時に便利です。

この章ではF1スコアを直感的に理解します。

47 都道府県の中から「医療費が全国平均を上回る都道府県」を 2 クラス分類で予測したいとする。 SSDSE-B-2026 の I6111_保健医療費 を閾値で 2 値化し、 ロジスティック回帰で予測した結果、 47 都道府県中 30 件を Positive と予測。 うち実際に Positive だったのは 25 件 (= TP=25, FP=5)、 残り 17 件 (Negative 予測) のうち 2 件が本当は Positive (= FN=2)、 15 件は正しく Negative (= TN=15)。

正解率 (Accuracy) = (25+15)/47 ≒ 0.85。 一見良さそうだ。 だが — Positive 例が極端に少ない(不均衡データ)場合、 「すべて Negative」と答えるだけで Accuracy はいくらでも上がってしまう。 そこで Precision (適合率) と Recall (再現率) をセットで見る。 Precision = TP/(TP+FP) = 25/30 ≒ 0.833 「Positive と言ったうちどれだけ本当か」。 Recall = TP/(TP+FN) = 25/27 ≒ 0.926 「本当の Positive をどれだけ拾えたか」。

Precision と Recall は トレードオフ関係にある (閾値を厳しくすれば Precision↑ Recall↓)。 これを 1 つの値に圧縮した 調和平均F1 スコアF1 = 2·P·R/(P+R) = 2·0.833·0.926/(0.833+0.926) ≒ 0.877。 算術平均 0.880 とほぼ同じだが、 どちらか一方が極端に小さいと F1 は大きく下がるのがミソ。 たとえば P=0.99, R=0.01 なら算術平均 0.50 だが F1 = 0.0198。 これが「Kaggle・医療診断・スパム検出で正解率より F1 が重視される」理由だ。

身近な例え:レストランレビューの「★3 つ」評価

あるレビューサイトで「料理の質」と「サービス速度」だけを評価するとする。 もしレストランが「料理 5/5、 サービス 1/5」だったらどう? 料理は最高だが「30 分も待たされて出てくる絶品料理」は、 多くの客には不満。 算術平均は 3.0 で「ふつう」だが、 体感は「★1」。 F1 は調和平均なので、 こちらに近い数値(≒1.67)を返してくれる。 「両方が良いときだけ高い」── これが F1 の哲学だ。

SSDSE-B-2026 想定:「医療費上位県」予測の閾値変化

閾値TPFPFNPrecisionRecallF1
0.30 (緩い)271500.6431.0000.783
0.50 (中央)25520.8330.9260.877
0.70 (厳しい)20170.9520.7410.833
0.90 (超厳しい)100171.0000.3700.540

F1 は閾値 0.50 で最大となる。 これは「Precision と Recall の良いバランス点」を示している。 ROC 曲線・PR 曲線で最適閾値を選ぶときの参考指標として実務でよく使う。

F1 を実務で「裏切らずに」使う 3 つのコツ

📐 定義・数式

🍰 まずはやさしく

2つの値をバランスよく混ぜ合わせた数式です。

どちらか一方が低すぎないかを確認するために使います。

買い物で質と量の両方をチェックする感覚に似ています。

この章ではF1スコアの計算方法を詳しく読みます。

F1 スコアは「適合率と再現率の調和平均」として最も知られているが、 同じ量を 3 通りの表現 (調和平均 / TP・FP・FN 直接 / $F_\beta$ の特殊例) で書け、 これらが等価であることを確認しておくと応用範囲が広がる。

【主定義: 調和平均としての F1】
$$ F_1 = 2\,\frac{\text{Precision}\,\cdot\,\text{Recall}}{\text{Precision} + \text{Recall}} $$

Precision (適合率) $= TP/(TP+FP)$、 Recall (再現率) $= TP/(TP+FN)$。 両者の調和平均をとることで「片方だけ高い」状態を強くペナルティする。

【別表現 1: TP / FP / FN 直接式】
$$ F_1 = \frac{2\,TP}{2\,TP + FP + FN} $$

Precision と Recall を消去して混同行列の素の数値だけで書ける形。 TN を一切使わないため、 クラス不均衡 (正例が極めて少ない) 場面でも安定して評価できる。

【別表現 2: 一般化 $F_\beta$ スコア】
$$ F_\beta = (1+\beta^2)\,\frac{\text{Precision}\,\cdot\,\text{Recall}}{\beta^2 \cdot \text{Precision} + \text{Recall}} $$

$\beta=1$ で F1 に一致。 $\beta>1$ は Recall 重視 (見逃しを嫌う医療検査)、 $\beta<1$ は Precision 重視 (誤警告を嫌うスパム判定)。 業務要件で重みを選ぶ。

【パラメータ・適用条件】
  • 値域: $F_1 \in [0, 1]$。 1 が完全予測、 0 は TP=0 (全滅)
  • 定義不能の場合: $TP+FP=0$ (何も陽性予測しない) または $TP+FN=0$ (本物の陽性がない) で 0/0、 規約上 $F_1=0$
  • マイクロ平均 / マクロ平均: 多クラス時は per-class F1 を平均 (各 class の TP/FP/FN を別計算)
  • $\beta$ の典型値: 検出系 $\beta=2$、 情報検索の精度重視 $\beta=0.5$
  • クラス不均衡時に Accuracy より優先される指標
  • 閾値依存: ROC-AUC と違い 1 つの閾値で固定された値。 PR 曲線と併用推奨

🔬 数式を言葉で読み解く

数式に出てくる記号の意味を 1 つずつ確認しましょう。

TP
True Positive。 正と予測し正解。
FP
False Positive。 正と予測し誤り (偽陽性)。
FN
False Negative。 負と予測し誤り (偽陰性)。
Precision
正と予測したうちの正解率。
Recall
本物の正のうち正と予測した率。

🔬 数式を言葉で読み解く(深掘り)

先の「記号を読み解く」を、 F1スコア の固有事情に即して 500 字以上で詳説する。 ここを読めば、 数式 1 行の裏にある設計判断と歴史的経緯が見えるはずだ。

TP (True Positive) = 「Positive と予測し、 実際も Positive」。 医療例なら「肺炎と診断し、 実際に肺炎」。 FP (False Positive) = 「Positive と予測したが、 実際は Negative」(α エラー / 第一種の過誤)。 FN (False Negative) = 「Negative と予測したが、 実際は Positive」(β エラー / 第二種の過誤 / 見逃し)。 TN (True Negative) = 「Negative と予測し、 実際も Negative」。 Precision $= TP/(TP+FP)$ は「Positive と予測したうち本当に Positive」の割合 → 無実の人を陽性と判定しない力。 Recall $= TP/(TP+FN)$ は「実際 Positive のうち拾えた」割合 → 見逃さない力。 F1 $= 2PR/(P+R)$ は両者の 調和平均で、 算術平均と違い「片方が極端に小さい」ことを許さない。 つまり F1 = 0.8 は「Precision と Recall がともに 0.8 付近で揃っている」ことを示し、 「Precision=1.0, Recall=0.67 で F1=0.8」と「Precision=0.67, Recall=1.0 で F1=0.8」は同値とみなす設計。 数学的には F-beta スコア $F_\beta = (1+\beta^2)PR/(\beta^2 P + R)$ の $\beta=1$ 特例で、 $\beta=2$ なら Recall 重視、 $\beta=0.5$ なら Precision 重視に調整できる。

📌 数式は 暗記対象ではなく検算ツール。 「結果が変だ」と感じたとき、 「この記号は本来こういう意味だから、 ここの値はおかしい」と 逆引きできる状態が、 中級者と上級者の差を生む。

🧪 SSDSE-B-2026 ハンズオン

本サイトの標準データ SSDSE-B-2026(47 都道府県 × 約 100 列、 独立行政法人統計センター提供) を使い、 F1スコア の概念を 実コードで体感する。 取得経路は data/raw/SSDSE-B-2026.csv(リポジトリ同梱)。

上記の 47 都道府県・医療費 2 値分類の例を、 そのまま scikit-learn で再計算する。 次のステップで TP/FP/TN/FN → Precision/Recall → F1 を順に求め、 classification_report 出力と一致することを確認する。 また F1 のマクロ平均・マイクロ平均・重み付き平均の違いも触れる。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) I5102(一般診療所数) L3221(消費支出(二人以上の世帯)) L322106(保健医療費(二人以上の世帯)) 北海道 5,092,000 3,403 296,888 15,491 東京都 14,086,000 14,894 341,320 18,166 沖縄県 1,468,000 928 251,222 11,686 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# SSDSE-B-2026 で「医療費が全国平均超」を 2 値分類し、 F1 を測る
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import StratifiedKFold, cross_val_predict
from sklearn.metrics import classification_report, f1_score, precision_recall_curve
# I6111・A2301・I5215 は SSDSE-B-2026 に無い。実在する列に置き換える。
#   医療費   → L322106 保健医療費(二人以上の世帯)
#   説明変数 → A1101 総人口 / L3221 消費支出 / I5102 一般診療所数
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()]   # 最新年度の 47 行
y = (df['L322106'] > df['L322106'].mean()).astype(int)
X = df[['A1101', 'L3221', 'I5102']].values
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=0)
y_pred = cross_val_predict(LogisticRegression(max_iter=1000), X, y, cv=cv)
print(classification_report(y, y_pred, digits=3))
print('macro-F1 =', f1_score(y, y_pred, average='macro'))
print('weighted-F1 =', f1_score(y, y_pred, average='weighted'))
# 閾値最適化
proba = cross_val_predict(LogisticRegression(max_iter=1000), X, y, cv=cv, method='predict_proba')[:, 1]
p, r, th = precision_recall_curve(y, proba)
f1_curve = 2*p*r/(p+r+1e-9)
best = f1_curve.argmax()
print(f'best threshold = {th[best]:.3f}, F1 = {f1_curve[best]:.3f}')

📌 動かないときは: (1) data/raw/SSDSE-B-2026.csv がリポジトリに存在するか、 (2) encoding='cp932'skiprows=[1] でヘッダーが正しく読めているか、 (3) 列名が SSDSE 公式の最新版と一致しているかを df.columns.tolist() で確認。

🧮 実値で計算してみる

TP=80, FP=20, FN=10 の例。

STEP 1 Precision
$P = 80/(80+20)=0.80$.
STEP 2 Recall
$R = 80/(80+10)=0.889$.
STEP 3 F1 計算
$F_1 = 2 \cdot 0.80 \cdot 0.889 / (0.80+0.889) = 0.842$.
STEP 4 解釈
F1=0.84 はまずまず良好。

🧮 数式に値を入れて手で計算する: F1 = 2·P·R/(P+R)

合成データで Precision と Recall から F1 を計算する。

Step 1: 混同行列要素

TP=60, FP=15, FN=20 Precision = TP/(TP+FP) = 60/75 = 0.80 Recall = TP/(TP+FN) = 60/80 = 0.75

Step 2: F1

F1 = 2·0.80·0.75/(0.80+0.75) = 1.2 / 1.55 ≈ 0.774

Step 3: 重み調整 F_β

F_β = (1+β²)·P·R/(β²·P + R) β=2 (Recall 重視): F2 = 5·0.6/(3.2+0.75) = 3/3.95 ≈ 0.759 β=0.5 (Precision 重視): F0.5 = 1.25·0.6/(0.2+0.75) ≈ 0.789

🐍 Python で再現

1
2
3
4
5
6
tp, fp, fn = 60, 15, 20
p = tp/(tp+fp)
r = tp/(tp+fn)
f1 = 2*p*r/(p+r)
print(f"P={p}, R={r}")
print(f"F1 = {f1:.3f}")

📤 実行結果

P=0.8, R=0.75 F1 = 0.774

💬 手計算 (Step 2) 0.774 と Python 出力が完全一致。

🎮 触って理解する

下のパネルで Precision(適合率)Recall(再現率)を動かすと、 F1(調和平均)算術平均がリアルタイムに計算・可視化されます。 色つきの正方形はドラッグ/タップで操作でき、背景色はその点の F1 の高さ(赤=低い、緑=高い)を表します。 スライダーでも同じ値を動かせます。片方だけ 0 に近づけると、算術平均は下がりきらないのに F1 だけが急落する—— この「両方が良くないと高くならない」性質を体感してください。

Precision → Recall → 0 1 0 1
背景色 = その (P, R) での F1(赤=低 / 緑=高)
算術平均 0.880 F1(調和平均) 0.877 差(算術平均 − F1)= 0.003
F1 = 2·P·R/(P+R) = 0.877

F1 は常に算術平均以下。P と R の差が広がるほど F1 は下がります。

🧭 この操作で分かること(直感)

⚠️ よくある落とし穴

🚀 発展:Fβ スコアで重みを変える

F1 は P と R を対等に扱いますが、業務では片方が重要なこともあります。一般化した Fβ スコア $F_\beta = (1+\beta^2)\,PR/(\beta^2 P + R)$ を使うと、 $\beta=1$ で F1、$\beta>1$(例 F2)で Recall 重視(見逃しを嫌う医療検査など)、 $\beta<1$(例 F0.5)で Precision 重視(誤警告を嫌うスパム判定など)に切り替えられます。 上のパネルで P と R を固定したまま「もし β を上げたら?」を想像すると、Recall の低さがより強く効くようになる、と読み替えられます。

🔗 関連ページ: Precision(適合率)Recall(再現率)混同行列クラス不均衡正解率(Accuracy)ROC 曲線AUC。 (PR 曲線・Fβ の専用ページは未整備のため本文内の解説を参照してください。)

🐍 Python 実装

最小実装の例。 SSDSE のような実データに対して、 まずはコピペで動かしてみるのが理解の早道です。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) A4103(合計特殊出生率) 北海道 5,092,000 1,681,000 1.06 東京都 14,086,000 3,205,000 0.99 沖縄県 1,468,000 350,000 1.6 …(全 47 行)
1
2
3
4
5
6
7
from sklearn.metrics import f1_score, classification_report
import pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
y_true = (df['A1303'] / df['A1101'] >= 0.30).astype(int)  # 高齢人口/総人口 が 30% 以上
y_pred = (df['A4103'] <= 1.40).astype(int)  # 合計特殊出生率が低い県を高齢化と予測
print('F1:', f1_score(y_true, y_pred))
print(classification_report(y_true, y_pred))

🐍 Python 実装(応用編)

先の Python 実装は最小例だった。 ここでは F1スコア の本格的な実務シナリオに即した、 もう一段難易度を上げたコードを示す。 そのままコピペで動くよう、 SSDSE 系の実データパスを直書きで残してある。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) I510120(一般病院数) I5102(一般診療所数) L3221(消費支出(二人以上の世帯)) L322106(保健医療費(二人以上の世帯)) 北海道 5,092,000 464 3,403 296,888 15,491 東京都 14,086,000 588 14,894 341,320 18,166 沖縄県 1,468,000 76 928 251,222 11,686 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 47 都道府県 + 学校教員 SSDSE-A-2025 を絡めた多クラス分類で F1 を測る例
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import StratifiedKFold, cross_val_predict
from sklearn.metrics import classification_report, f1_score, ConfusionMatrixDisplay
import matplotlib.pyplot as plt
# I6111・A2301・I5215 は SSDSE-B-2026 に無い。実在する列に置き換える。
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()]   # 最新年度の 47 行
# 保健医療費を 3 クラスに離散化(低・中・高)
df['target'] = pd.qcut(df['L322106'], q=3, labels=['low', 'mid', 'high'])
features = ['L3221', 'I5102', 'I510120', 'A1101']
X = df[features].fillna(df[features].median()).values
y = df['target'].values

cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=0)
y_pred = cross_val_predict(RandomForestClassifier(n_estimators=200), X, y, cv=cv)
print(classification_report(y, y_pred, digits=3))
# クラスごとの F1
for avg in ('macro', 'micro', 'weighted'):
    print(avg, '-F1 =', f1_score(y, y_pred, average=avg))

# 混同行列を可視化
fig, ax = plt.subplots(figsize=(5, 4))
ConfusionMatrixDisplay.from_predictions(y, y_pred, ax=ax)
plt.tight_layout()
print('混同行列でクラスごとの偏りを確認')

📌 このコードのポイント: (1) 引数化せず実データパスを直書きで読みやすさ優先、 (2) 集約・結合・型最適化など F1スコア 関連の典型処理を一気通貫で示す、 (3) print() で各ステップの結果を確認できる。

🧭 用語クロスリンク集

F1スコア と関わりの深い用語を、 一画面で巡回できるよう チップ形式で並べた。 「これも知っておきたい」と思った瞬間にクリックして、 元のページに戻ってくる ── ジャストインタイム学習の理想的な使い方。

🔗 適合率 🔗 再現率 🔗 正解率 🔗 混同行列 🔗 交差エントロピー 🔗 Softmax 🔗 Sigmoid 🔗 過学習 🔗 正則化 🔗 学習率 🔗 誤差逆伝播 🔗 用語索引

📌 これらはすべて html/glossary/ 配下の実在ページにリンクしているので、 リンク切れの心配はない。

🗂 用語の階層・派生・対立関係

F1スコア を中心に、 上位概念・並列概念・派生概念・対立概念の 4 区分で整理。 学術論文を読むときの「この用語はこの分野のどこに位置するか」を直感的に把握できる。

関係該当用語関係性の説明
上位概念評価指標 / 混同行列F1 は TP/FP/FN から導かれる Precision・Recall の調和平均という位置にある
並列概念Precision / Recall / Accuracy / Specificity同じ混同行列から派生する代替指標。 F1 は Precision・Recall を 1 値に集約した点が違う
派生概念F-β スコア (β=2 / β=0.5) / macro-F1 / micro-F1 / weighted-F1β で Precision-Recall の重みを変えた拡張、 およびマルチクラスへの拡張形
対立概念MCC (Matthews 相関係数) / Balanced Accuracy / AUC (閾値非依存)F1 が TN を無視する欠点を補う代替指標。 クラス不均衡時の選択肢
前提知識混同行列 / Precision / Recall / 調和平均F1 = 2·P·R/(P+R) の式を理解するには Precision・Recall・調和平均の意味を把握する必要

⚠️ よくある落とし穴

この用語を使うときに陥りがちな失敗パターン。 経験者ほどここに 1 度はハマっています。

❌ Macro vs Micro の取り違え
クラス不均衡では Macro F1 (クラス平均) が公平。
❌ 単一閾値依存
閾値で F1 は変動。 PR-AUC も併用。
❌ Negative クラス無視
F1 は通常 positive クラスのみ。 両方見るなら macro。
❌ Recall が極端に重要な場面
医療など FN が致命的な領域では F2 を使う (Recall 重視)。

⚠️ もっと深い落とし穴

上のセクションの 4 つに加えて、 F1スコア 固有の実務でハマる典型をさらに 4 つ。 経験 5 年以下のエンジニア・研究者はほぼ全員、 ここのいずれかで 1 度は事故を起こしている。

❌ マクロとマイクロの混同
macro = クラスごと F1 を単純平均(マイノリティ重視)、 micro = 全 TP/FP/FN を集計 (= Accuracy と同等になることが多い)。 報告時に必ず明記。
❌ クロスバリデーション fold ごとの分散
F1 = 0.82 ± 0.05 と分散が大きい場合、 1 fold の良さは偶然。 StratifiedKFold で各 fold のクラス比を維持。
❌ ゼロ除算(全 Negative 予測)
TP=FP=0 で Precision の分母 0。 sklearn は zero_division=0F1=0warn で警告。 業務的にはモデル失敗のシグナル。
❌ マルチラベル分類での F1
ラベル「がん/高血圧/糖尿病」のように複数同時 True がある場合、 sample-averagelabel-averageか明記。 average='samples' 等。

🗺 概念マップ:F1スコア の知識ネットワーク

本サイト全体の 概念マップ の中で、 F1スコア がどの位置にあるかをテキストツリーで表現する。 視覚的なグラフは 概念マップページ を参照。

[ 評価指標 ]
  ├─ F1スコア (本ページ)
  ├─ 関連手法・派生 → 「🌐 関連手法・派生」セクション
  ├─ 前提概念 → 「🔬 数式を言葉で読み解く」セクション
  └─ 派生領域 → 「🎓 深掘り(さらに)」シナリオ A/B/C
  

📌 全用語の俯瞰には 概念マップ を、 全用語一覧には 用語集トップ を参照してください。

🎯 最終まとめ:このページで学んだこと

  1. 30 秒結論で「F1スコア とは何か」を 1 文で言える
  2. 直感セクションで SSDSE-B-2026 を題材に具体例を掴んだ
  3. 数式 + 言葉で記号の意味を翻訳できる
  4. Python 実装を最小例 + 応用例の 2 段で試せた
  5. 落とし穴 8 個を知り、 自分の作業で予防策が打てる
  6. 3 シナリオ × 3 誤解 × 5 意思決定で、 「いつ使うか/使わないか」を判断できる
  7. 近接概念との比較で、 別手法との違いを言葉で説明できる
  8. 歴史・派生・体系的解説で、 上級者として「なぜこの設計か」を語れる

📌 本ページは ジャストインタイム型データサイエンス教育教材の一部。 一度通読する必要はなく、 必要なときに必要な節だけ読んで戻ってくる使い方を想定している。 「F1スコア」の概念に詰まったら、 何度でもこのページに戻ってきてほしい。

🔢 数値例による手計算ウォークスルー

F1スコア を「コード任せ」にせず、 一度は手計算してみることで理解が定着する。 ここでは最小サイズのデータで、 値の動きを 1 ステップずつ追う。

数値例:47 都道府県の 2 値分類で F1 を計算

SSDSE-B-2026 の医療費 (I6111) を全国平均 (約 11,000 円/人) で 2 値化し、 高齢化率 + 所得 でロジスティック回帰した結果、 以下の混同行列が得られたとする。

予測 = High予測 = Low
実際 = HighTP = 25FN = 2
実際 = LowFP = 5TN = 15

$n = 47$、 Positive 比率 = 27/47 ≒ 57.4%。
$\text{Precision} = \frac{25}{25+5} = 0.833$、 $\text{Recall} = \frac{25}{25+2} \approx 0.926$、 $\text{Accuracy} = \frac{25+15}{47} \approx 0.851$。
F1 = $\frac{2 \cdot 0.833 \cdot 0.926}{0.833 + 0.926} = \frac{1.543}{1.759} \approx 0.877$
参考に F2 = $\frac{(1+4) \cdot 0.833 \cdot 0.926}{4 \cdot 0.833 + 0.926} = 0.906$、 F0.5 = $\frac{1.25 \cdot 0.833 \cdot 0.926}{0.25 \cdot 0.833 + 0.926} \approx 0.850$。 Recall 重視の F2 が最大、 Precision 重視の F0.5 が最小、 F1 はその中間にあることが確認できる。

❓ よくある質問(用語固有 10 連発)

汎用 FAQ 5 件に加えて、 F1スコア 固有の質問 10 件を Q&A 形式でまとめた。 自分の状況に近いものから読んでほしい。

Q1. F1 と Accuracy はどちらが本質的?
A. 不均衡データでは F1。 均衡データでは Accuracy。 ただし業務インパクト (FP/FN コスト) を考えるなら、 どちらも完璧ではなく 期待コストが最善。
Q2. F1 の最大値・最小値は?
A. 0 〜 1。 1 が完璧、 0 が最悪 (TP=0 を含む)。 ランダム予測 (Positive 比率 p) の F1 は約 $2p/(1+p)$、 たとえば不均衡 5% なら F1≈0.095。
Q3. F1 が 0.7 は良い?悪い?
A. ベースライン依存。 ランダム予測の F1 と比較。 また、 Kaggle / NLP / 画像分野で 0.7 はよくある、 医療検査では 0.7 は不十分なことが多い。
Q4. マルチクラスでクラスごとの F1 がバラバラ
A. 原因は (i) クラス頻度の不均衡、 (ii) クラス間の類似度差、 (iii) 特徴量の偏り。 対策は SMOTE/Focal Loss/クラス重み
Q5. 閾値最適化で F1 を 0.05 上げたいんですが
A. (1) precision_recall_curve で F1 が最大になる閾値、 (2) Youden's J (Sensitivity + Specificity - 1) 基準も併用、 (3) cross-validation 内で閾値最適化 (Nested CV)。
Q6. F1 が cross-validation の fold 間で 0.6〜0.85 と分散が大きい
A. (i) StratifiedKFoldでクラス比を維持、 (ii) repeated CV (k=5 を 10 回繰返し) で平均、 (iii) サンプルサイズを増やす。
Q7. 学習データでは F1=0.95、 テストでは F1=0.6
A. 典型的な 過学習。 (i) 正則化、 (ii) Early Stopping、 (iii) Data Augmentation、 (iv) モデル単純化。
Q8. F1 で AUC-PR より良い指標は?
A. 業務コストが定量化できるなら Expected Utility (= TP·V_TP - FP·C_FP - FN·C_FN)。 これが意思決定理論的に最良。 F1 は対称仮定の特殊例。
Q9. Sklearn で F1 を多クラス出すには?
A. from sklearn.metrics import f1_score; f1_score(y, y_pred, average='macro')。 average に None / 'macro' / 'micro' / 'weighted' / 'samples' を選択。
Q10. F1 を最大化する学習目的関数は?
A. F1 は微分不可能なので直接最適化できない。 代わりに Cross-Entropy + 閾値調整Soft-F1 損失 (Bénédict et al. 2021)、 Focal Loss (RetinaNet) が代替。

🏋️ 演習問題(5 問)

学習の定着には、 自分の手を動かすのが一番。 SSDSE-B-2026 や実ログを題材に、 F1スコア を実践する 5 問を用意した。 答えは Python 実装セクションと数値例セクションを参考に組み合わせれば導ける。

  1. 演習 1:SSDSE-B-2026 で「高齢化率 > 30%」かどうかを 2 値分類し、 F1 / Precision / Recall を計算せよ。
  2. 演習 2:閾値を 0.1 〜 0.9 まで動かしたときの F1 を曲線でプロットし、 最大 F1 の閾値を特定せよ。
  3. 演習 3:クラス重みを変えて (class_weight='balanced') F1 がどう変化するか比較せよ。
  4. 演習 4:macro-F1 と weighted-F1 を多クラス分類で計算し、 結果がどう違うか説明せよ。
  5. 演習 5:F-beta スコア (β=2, β=0.5) を計算し、 業務的にどちらを採用すべきか議論せよ。

📌 演習を解いて疑問が残ったら、 「よくある質問」セクションに戻るか、 リポジトリの「論文一覧」から類似研究を探して、 実コード (本サイトには 159 本の再現論文) を読むのが最速の理解への道。

🛠 デバッグ手順書

F1スコア を使った分析で「結果がおかしい」と感じたとき、 上から順に確認してほしい 7 ステップ。

  1. 入力データの shape / dtype / 欠損df.info()df.isna().sum() で確認
  2. 1 サンプルを取り出し、 期待通りの計算が行われているか手計算と一致するか
  3. 境界ケース(空テーブル、 1 行のみ、 全 NaN)でエラーが出ないか
  4. 乱数シードを固定し、 同じ結果が再現できるか
  5. 中間結果print()logging で確認、 想定値からズレるところを特定
  6. 単体テストpytest で書き、 1 関数ずつ動作確認
  7. それでもダメなら、 最小再現コード (MRE) を作って Stack Overflow / GitHub Issue / 教員に質問

📌 デバッグは経験値が物を言う領域。 上記 7 ステップを習慣化することで、 1 件の事故で学ぶことが何倍にも増える。

🗺 学習パス:30 分 / 3 時間 / 30 時間

F1スコア をどの程度マスターするかで、 推奨する学習時間と内容が変わる。 自分の状況に合わせて選んでほしい。

⏱ 30 分:論文を読むだけ
  • 本ページの「💡 30 秒結論」「🎨 直感で掴む」「🔬 数式を言葉で読み解く(深掘り)」を順に読む
  • 論文に戻り、 該当箇所を再読
  • 分からない単語が出てきたら「🔗 関連用語」「🧭 用語クロスリンク集」から飛ぶ
⏱ 3 時間:手を動かす
  • 本ページの「🐍 Python 実装」「🐍 Python 実装(応用編)」を実際にコピペして動かす
  • 「🧪 SSDSE-B-2026 ハンズオン」を SSDSE 公式から CSV をダウンロードして実行
  • 「🏋️ 演習問題(5 問)」を最低 3 問解く
  • 結果を F1スコア 関連の落とし穴 8 件と照らし、 自分のコードに同じ事故がないか確認
⏱ 30 時間:教える側になる
  • 本ページの「📖 体系的解説 (5 観点)」を全部読み、 関連書籍を 1 冊精読
  • SSDSE 以外の実データ (例:自分の研究テーマや実務データ) で同じ分析を再現
  • 結果を 3 分プレゼンにまとめ、 同僚・後輩に説明 (アウトプット駆動)
  • 本ページの「🎬 ケーススタディ」のような「自分の事例」を 1 つ書き溜める
  • 関連論文 5 本を読み、 手法の発展と限界をマップ化

✅ 理解度セルフチェック(10 問)

本ページを読み終わったら、 以下の 10 問に □ チェックを入れて理解度を確認してほしい。 8 個以上 ✓ なら中級レベル、 全 10 個 ✓ なら他人に説明可能なレベル。

📌 チェックが付かない項目は、 該当セクションに戻って読み直してください。 「分かった気」と「分かっている」の境界を、 このリストで明確にします。

📖 専門用語ミニ辞書

本ページで頻出する周辺専門用語を、 1 行ずつ簡潔に。 ジャストインタイム的に、 必要なときだけ参照すれば良い。

SSDSE
独立行政法人統計センターが提供する「教育用標準データセット」。 公的データを基に、 学生・教育機関が使いやすく整形。
pandas
Python の表データ操作ライブラリ。 DataFrame 型が本ページのテーブル概念の主力実装。
CV (Cross Validation)
データを K 個に分割し、 K-1 個で学習・1 個で検証を K 回繰り返す。 性能評価の標準。
95% CI (信頼区間)
「真の値が含まれる範囲」を確率的に表現。 [L, U] の形で報告。
p 値
帰無仮説の下で、 観測値以上の極端な結果が出る確率。 通常 0.05 未満で「有意」。
OLS
Ordinary Least Squares、 最小二乗法。 回帰の基本。
SGD
Stochastic Gradient Descent、 確率的勾配降下法。 ML の標準最適化アルゴリズム。
RMSE / MAE
回帰評価指標。 Root Mean Squared Error / Mean Absolute Error。
AUC
Area Under Curve、 ROC 曲線下面積。 分類性能指標。
A/B テスト
2 つのバージョンを並列実装し、 ランダムにユーザーに当てて効果を測る実験。

📑 本サイトで F1スコア を使う論文(抜粋)

本サイトには 159 本の再現論文があり、 多くが F1スコア を何らかの形で利用している。 関連論文を読みたい方は 論文一覧 から検索してほしい。

📌 各論文は教育目的の再現実装で、 ハンズオン形式で読めるよう Jupyter Notebook 風の構成になっている。 「F1スコア を実際の研究でどう使うか」を 5 分で掴むには、 関連論文を 1 本流し読みするのが最速。

🤝 改善提案・誤り報告

本ページの内容に誤りや改善余地を見つけた場合、 リポジトリの Issue / Pull Request からご提案ください。 教材は みんなで育てるもの。

🍳 コード・クックブック(F1スコア 編)

F1スコア を実務で使う際の頻出パターンを、 動くコードのレシピ集としてまとめた。 必要な料理 (タスク) だけを取り出して使ってほしい。

F1 / F2 / F0.5 を一括比較

1
2
3
4
5
6
7
8
from sklearn.metrics import fbeta_score, f1_score, precision_score, recall_score, classification_report
y_true = [1,1,1,0,0,1,1,0,1,1, 0,1,0,0,1,1,1,0,1,1]
y_pred = [1,1,0,0,0,1,1,1,1,0, 0,1,0,1,1,1,1,1,1,0]
for beta in (1.0, 2.0, 0.5):
    print(f'F{beta:>3} =', fbeta_score(y_true, y_pred, beta=beta))
print('P =', precision_score(y_true, y_pred))
print('R =', recall_score(y_true, y_pred))
print(classification_report(y_true, y_pred, digits=3))

閾値最適化で最大 F1 を探す

1
2
3
4
5
6
7
8
import numpy as np
from sklearn.metrics import precision_recall_curve, f1_score
y_true = np.array([1,0,1,1,0,1,0,0,1,1,0,1,0,1,1,0,1,1,0,1])
y_proba = np.array([.9,.4,.7,.8,.3,.55,.45,.2,.95,.6, .35,.78,.25,.5,.65,.4,.85,.7,.3,.88])
p, r, th = precision_recall_curve(y_true, y_proba)
f1 = 2*p*r/(p+r+1e-9)
best_idx = f1.argmax()
print(f'best thr={th[best_idx]:.3f}, F1={f1[best_idx]:.3f}')

混同行列を可視化 + Markdown 表で出力

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import pandas as pd, numpy as np
from sklearn.metrics import confusion_matrix
y_true = [1,1,1,0,0,1,1,0,1,1,0,1,0,0,1,1,1,0,1,1]
y_pred = [1,1,0,0,0,1,1,1,1,0,0,1,0,1,1,1,1,1,1,0]
cm = confusion_matrix(y_true, y_pred)
df = pd.DataFrame(cm, index=['actual_0','actual_1'], columns=['pred_0','pred_1'])
print(df)
TP, FP, FN, TN = cm[1,1], cm[0,1], cm[1,0], cm[0,0]
print(f'TP={TP} FP={FP} FN={FN} TN={TN}')
print(f'F1 = {2*TP/(2*TP+FP+FN):.3f}')

📌 すべてのレシピは「実データ前提・引数なし直書き」スタイル。 そのままコピペで動くよう設計したので、 まずは動かしてから読むのを推奨する。

🚫 アンチパターン集

F1スコア を扱うコード・レポートで頻発するアンチパターンを 5 つ挙げる。 「やってはいけないこと」を知るのが、 良いコードへの近道。

❌ コピペで済ませて意味を理解しない
本ページのコードをコピペするのは OK だが、 「なぜそうなるか」を 1 度は手計算で確認すること。 デバッグ時に困る。
❌ 結果を 1 つの数字だけ報告する
「F1 = 0.82」「結合後 1,000 件」だけ報告するのはアンチパターン。 内訳・分散・前提条件を併記すること。
❌ 落とし穴を読まずに本番投入する
本ページの落とし穴 8 件はすべて「経験者が踏んだ地雷」。 本番前に必ず一読し、 自分のコードで該当しないか確認。
❌ ライブラリのデフォルトを盲信する
sklearn の average='binary'、 pandas の how='inner' 等のデフォルトは「最も多用される選択」であって「自分の目的に最適」とは限らない。 必ず確認。
❌ バージョン情報を記録しない
pandas / sklearn / torch のバージョンで挙動が変わることがある。 再現性のため pip freezeconda env export を記録。

🏁 最終結論:F1スコア を一言で

F1 スコアは「Precision と Recall のバランス」を 1 値に圧縮する便利な指標。 だが「F1 高ければ良い」と思考停止する人と、 「F1 の内訳と業務インパクトを語れる人」では、 ML プロジェクトの成否が分かれる。 本ページで学んだ (i) 調和平均という設計、 (ii) F-beta による業務重み付け、 (iii) macro/micro/weighted の使い分け、 (iv) 閾値最適化、 (v) AUC-PR との併用の 5 視点を持って初めて、 「データサイエンティスト」と名乗れる。 不均衡データ・医療・スパム・自動運転など、 現代の重要 ML 分野ほど F1 の解釈が決定的になる。

本ページは ジャストインタイム型データサイエンス教育の一部として、 必要なときに必要な節だけ読んでもらう設計になっている。 通読する必要はない。 自分の今いる場所 (卒論・実務・論文読解) に応じて、 該当セクションだけを参照し、 また論文や業務に戻ってほしい。 そして数か月後、 似たような状況に陥ったとき、 また戻ってきてくれれば、 教材として最高の使い方になる。

📚 関連リンク:論文一覧 | 用語集トップ | 概念マップ

🙋 著者・教材設計について

本教材は、 広島工業大学 統計・データ解析コンペティション参加学生向けに、 松本伸平 (s.matsumoto.gk@cc.it-hiroshima.ac.jp) が監修・執筆した。 「論文を読む過程で出てきた専門用語を、 その場で 5 分で補完して論文に戻る」というジャストインタイム型の学習体験を目的に、 514 用語ページを統一フォーマットで整備している。

本ページ「F1スコア」は 評価指標 カテゴリに属し、 同カテゴリ内の他用語と相互リンクされている。 用語間の関係性は 概念マップ でも俯瞰できる。

本サイトは SSDSE (教育用標準データセット, 独立行政法人統計センター) を主データとして使い、 「合成データ ではなく実公的データを使う」 を方針に据えている。 ハンズオン教材の質を最大化するための判断である。

📌 F1 補遺:競技 ML / 業務 ML での扱い

F1 スコアは Kaggle等の競技 ML でリーダーボード評価指標として頻用される一方、 業務 ML では 業務 KPI に翻訳する必要がある。 ここでは両者の現代的な扱いを整理する。

競技 ML での F1

業務 ML での F1

F1 を改善する 10 のテクニック

  1. 閾値最適化 (PR 曲線で F1 が最大の点)
  2. クラス重み付け (class_weight='balanced')
  3. SMOTE / ADASYN によるオーバーサンプリング
  4. RandomUnderSampler によるダウンサンプリング
  5. Focal Loss (γ=2 で hard negative を強調)
  6. アンサンブル (Bagging + Boosting + Stacking)
  7. キャリブレーション (Platt scaling, Isotonic regression)
  8. ドメイン特徴量の追加 (Positive クラス独自のシグナル)
  9. データ拡張 (画像なら回転・反転、 テキストなら同義語置換)
  10. 事前学習モデル (Transformer, ViT) の活用

F1 vs MCC vs Cohen's Kappa

MCC (Matthews Correlation Coefficient) = $\frac{TP\cdot TN - FP\cdot FN}{\sqrt{(TP+FP)(TP+FN)(TN+FP)(TN+FN)}}$。 範囲 [-1, +1]。 不均衡データで F1 より良いと言われ、 ChouChou et al. (2020) では二値分類の単一指標として MCC を推奨。 Cohen's Kappa は「偶然の一致を超えた一致度」で、 マルチクラスの評価で多用。 F1 と併記すると論文の説得力が増す。

F1 と ROC-AUC の関係

F1 は「ある閾値での」点評価、 ROC-AUC は「全閾値での」曲線評価。 両者は 独立な情報を持つ:高い ROC-AUC でも閾値設定次第で F1 は低い。 業務運用するなら F1 (運用時の挙動)、 モデル選択するなら ROC-AUC (閾値依存しない順位性)。 報告時は両方出すのが現代的。

🏥 ドメイン別 F1 活用事例

F1 スコアは分野によって「妥当な水準」が違う。 ここでは 6 分野での典型的な F1 値と運用上の注意を整理する。

分野典型 F1運用上の重視点
医療診断 (癌・肺炎)0.70〜0.90F2 で Recall 重視 (見逃し回避)
スパムフィルタ0.95〜0.99F0.5 で Precision 重視 (正常メール誤判定回避)
クレジット不正検知0.60〜0.85期待コスト最小化 (FP=ユーザー不便, FN=損失)
自然言語 NER0.80〜0.95macro-F1 (エンティティタイプの平等評価)
画像物体検出0.50〜0.85 (mAP)mAP@0.5 / mAP@0.5:0.95 (F1 の拡張概念)
レコメンド0.10〜0.40 (Top-K)Precision@K / Recall@K / NDCG を併用

📌 分野横断的に「F1 = 0.8 ならまあまあ」と判断するのは誤り。 自分の分野のベンチマーク (SOTA) と比較するのが正解。

F1 スコア 調和平均 2PR/(P+R) Precision (適合率) Recall (再現率) F_β (β≠1 一般化) macro/micro 平均 不均衡分類タスク

🔗 隣接手法への橋渡し

「F1 スコア」は Precision と Recall を 1 つの値に統合する便利な指標であるが、 実務で意味を持たせるには隣接手法と接続・統合・比較の三視点で運用判断する必要がある。 章 10 が分類体系上の位置づけを示すのに対し、 章 14 は「業務でいつ何に切替えるか」を整理する。

① 接続 (パイプライン上で前後に位置する手法)

② 統合 (組み合わせて使うことで効果が増す手法)

③ 比較 (代替・競合する指標といつ切替えるか)

切替先F1 からこちらへ切替える場面
Accuracyクラスがほぼ均衡 (陽性率 40-60%) で、 経営層に「全体正解率」を説明する場面
ROC-AUC閾値を固定したくない・モデル選択フェーズで全閾値での順序付け性能を比較したい場面
PR-AUC極端な不均衡 (陽性率 < 1%) で ROC-AUC が高く出すぎ、 Precision-Recall 平面で評価したい場面
Matthews 相関係数 (MCC)TP/TN/FP/FN すべてのバランスを 1 つの値で見たい場面 (Boughorbel 2017)。 F1 と異なり TN も評価に入る
Fβ スコアPrecision と Recall を等価扱いしたくない場面。 業務コスト比から β を決める

運用判断は (1) クラス均衡度の確認 → (2) Precision と Recall の重視度から β を決定 → (3) 単一閾値か全閾値かで Fβ と PR-AUC を選択 → (4) TN も評価に入れたいなら MCC へ切替、 の 4 軸で整理する。 章 10 (分類体系) で F 系指標の位置づけを把握し、 章 14 (運用判断) で「いつ何を選ぶか」を決定することで、 不均衡データやコスト非対称な業務に適切な指標設計ができる。

🌳 手法選択フロー

「F1 スコア」を実際の課題に当てはめるとき、 以下の 3 ステップで判断する。 領域固有の判断基準と組み合わせて使用する。

  1. ステップ 1: クラス不均衡なら Accuracy より F1 を主指標に
  2. ステップ 2: FP / FN コスト非対称なら F_β (β>1 で Recall 重視)
  3. ステップ 3: 多クラスは macro F1 (van Rijsbergen 1979)

多クラス分類で macro F1 は全クラスを等価扱い (少数クラスにも敏感)、 weighted F1 はサンプル数で重み付け (多数クラス優位)、 micro F1 は集約 confusion matrix から計算 (Accuracy と一致) という違いがあり、 不均衡度と業務目的で選ぶ。 sklearn の `f1_score(average=...)` で簡単に切り替え可能。

🔬 別角度:F1 は「確率の目盛り」に依存する — SSDSE-B-2026 実測で見る

本ページの他セクションでは Fβ・macro/micro/weighted・PR 曲線・閾値最適化を厚く扱った。 ここでは重複を避け、 意外と語られない一点だけを実測データで掘り下げる。 それは「F1 は確率をハード判定 (0/1) に落としてから測る量なので、 (1) 正例の定義、 (2) 判定閾値、 (3) 確率の目盛り=較正 (calibration) の 3 つと不可分に絡む」という事実だ。 一方 ROC-AUC / PR-AUC は確率の順位だけを見るため、 これら 3 つの一部に鈍感である。 この非対称性を知ると、 F1 の数字を「何と比べれば安全か」が見えてくる。

実測タスク:超高齢化県の予測 (SSDSE-B-2026 / 2023 / 47 県)

SSDSE-B-2026 を encoding='cp932', skiprows=[1] で読み、 2023 年の 47 都道府県に限定。 高齢化率 = A1303 / A11010.35 以上を「超高齢化県 = Positive」と定義した (該当 6 / 47 県、 陽性率 12.8% の少数派 Positive)。 説明変数 A1101, A4101, A4103, L3221 を標準化し、 ロジスティック回帰を StratifiedKFold(5) + cross_val_predict で交差検証予測。 得られた予測確率での実測値が以下である (すべて実データからの計算値)。

判定閾値PrecisionRecallF1
0.200.3330.5000.400
0.300.0000.0000.000
0.50 (既定)0.0000.0000.000
0.700.0000.0000.000
0.185 (F1 最適)0.471

参考の順位系指標 (同じ予測確率): ROC-AUC = 0.809PR-AUC = 0.411。 「全県 Negative」と答えるだけの Accuracy = 0.872

読み取れる 3 つの落とし穴 (実測が語る)

① Accuracy の罠が数字で見える
「全部 Negative」で Accuracy = 0.872 と高い一方、 既定閾値 0.5 での F1 = 0.000 (このモデルは 0.5 では誰も陽性と予測しない)。 ROC-AUC 0.809 は一見悪くないが、 不均衡を反映する PR-AUC は 0.411 まで下がる。 Accuracy・ROC-AUC が高い ≠ 使えるを、 同一データが同時に示している。
② 閾値ひとつで F1 は 0.000 ↔ 0.471 に動く
同じ予測確率のまま、 閾値 0.5 では F1=0.000、 F1 最適の閾値 0.185 では F1=0.471。 少数派 Positive では確率が全体的に低く出やすく、 既定 0.5 が「実質すべて陰性」になりがち。 「F1=0 だからモデルがゴミ」ではなく「閾値が不適」なだけのことがある。 まず PR 曲線・閾値走査を見よ、 という 適合率・再現率 ページと同じ教訓が実データで再現する。
③ 確率較正と F1 は別物 (単調変換で検証)
予測確率を順位を保つ単調変換 proba**k にかけると (k は正の定数)、 順位は不変なので ROC-AUC = 0.809、 PR-AUC = 0.411 は k を変えても一切変わらない。 ところが固定閾値 0.5 での F1 は k=1: 0.000 → k=0.5: 0.444 → k=2.0: 0.000 と激変した (実測)。 つまり F1 は「確率の目盛り=較正」に依存する量で、 較正を直すだけで固定閾値の F1 は動きうる。 逆に F1 が高くても確率が正しく較正されているとは限らない (F1 はハード判定しか見ないため)。 確率そのものの正しさを問うなら較正曲線・Brier スコアを、 順位の良さを問うなら AUC を、 運用閾値での挙動を問うなら F1 を — と別々に見るのが安全。

④ 正例の定義そのものが F1 の水準を決める

同じ SSDSE-B-2026・同じ特徴量でも、 Positive の定義を変えると難易度も F1 も別物になる (いずれも実測)。

Positive の定義陽性数 / 47陽性率PR-AUCF1 (最適閾値)
高齢化率 ≥ 0.303574.5% (多数派)0.8580.946
高齢化率 ≥ 0.35612.8% (少数派)0.4110.471

「F1=0.95」と「F1=0.47」は優劣ではなく別問題だ。 前者は多数派を Positive にしただけで水増しされている疑いがある (本ページ「よくある落とし穴」の「多数派を Positive にしない」と同根)。 論文・レポートでは 「何を Positive と定義したか・陽性率はいくつか」を必ず明記しないと、 F1 の数字は比較不能になる。

再現コード (実測値はこのコードの出力)

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) A4103(合計特殊出生率) L3221(消費支出(二人以上の世帯)) 北海道 5,092,000 1,681,000 24,430 1.06 296,888 東京都 14,086,000 3,205,000 86,348 0.99 341,320 沖縄県 1,468,000 350,000 12,549 1.6 251,222 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import pandas as pd, numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import StratifiedKFold, cross_val_predict
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import roc_auc_score, average_precision_score, f1_score

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df.iloc[:, 0] == 2023].copy()          # 2023 年の 47 県
y = ((df['A1303'] / df['A1101']) >= 0.35).astype(int).values   # 超高齢化県 = Positive
X = StandardScaler().fit_transform(df[['A1101', 'A4101', 'A4103', 'L3221']].values)

cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=0)
proba = cross_val_predict(LogisticRegression(max_iter=1000), X, y, cv=cv,
                          method='predict_proba')[:, 1]

print('ROC-AUC', roc_auc_score(y, proba), 'PR-AUC', average_precision_score(y, proba))
for th in (0.185, 0.2, 0.3, 0.5, 0.7):
    print(th, f1_score(y, (proba >= th).astype(int), zero_division=0))

# 単調変換で「順位不変・F1 可変」を確認 (較正と F1 は別物)
for k in (0.5, 1.0, 2.0):
    pk = proba ** k
    print('k=', k, 'ROC', roc_auc_score(y, pk), 'F1@0.5',
          f1_score(y, (pk >= 0.5).astype(int), zero_division=0))

📌 ひとことで: ROC-AUC / PR-AUC が「確率の順位」の指標なのに対し、 F1 は「順位 + 閾値 + 較正 + 正例定義」の合成物。 だから F1 単独で報告せず、 PrecisionRecall ・ 陽性率 ・ 採用閾値 ・ ROC 曲線 / PR 曲線 (AUC) をセットにする。 元データの集計は 混同行列、 モデルは ロジスティック回帰、 不均衡の扱いは クラス不均衡 の各ページも参照。 (確率較正の専用ページは未整備のため本節の解説を参照。)