"""#30 空欄3・4:年金額改定の年表の並べと積み上げ。入力=Issue #30 本文の年表(検証官 合格)。金額は raw/ の厚労省 PDF p1 から機械的に読む(外部照合)。""" import glob, os, re, pypdf from math import prod R = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "raw") # 年度: (物価%, 名目手取り賃金%, 調整率表示%, スライド, 決め手, 改定率 新規%, 改定率 既裁定%) T = [ ("H27", 2.7, 2.3, -0.9, "発動", "賃金(+特例水準の解消▲0.5)", 0.9, 0.9), ("H28", 0.8, -0.2, -0.7, "調整なし", "スライドなし(据え置き)", 0.0, 0.0), ("H29", -0.1, -1.1, -0.5, "調整なし", "物価", -0.1, -0.1), ("H30", 0.5, -0.4, -0.3, "調整なし・繰越▲0.3", "スライドなし(据え置き)", 0.0, 0.0), ("R1", 1.0, 0.6, -0.2, "発動(繰越▲0.3を含め調整)", "賃金", 0.1, 0.1), ("R2", 0.5, 0.3, -0.1, "発動", "賃金", 0.2, 0.2), ("R3", 0.0, -0.1, -0.1, "調整なし・繰越▲0.1", "賃金", -0.1, -0.1), ("R4", -0.2, -0.4, -0.3, "調整なし(繰越▲0.1+当年▲0.2)", "賃金", -0.4, -0.4), ("R5", 2.5, 2.8, -0.3, "発動(繰越▲0.3を含め▲0.6)", "新規=賃金/既裁定=物価", 2.2, 1.9), ("R6", 3.2, 3.1, -0.4, "発動", "賃金", 2.7, 2.7), ("R7", 2.7, 2.3, -0.4, "発動", "賃金", 1.9, 1.9), ("R8", 3.2, 2.1, -0.2, "発動(厚年▲0.1)", "賃金", 1.9, 1.9), # 基礎年金。厚年(報酬比例)は2.0 ] out = []; P = out.append P("## 1. 年度ごとの表(%)") P("| 年度 | 物価 | 名目手取り賃金 | 調整率(表示) | スライド | 決め手 | 改定率(新規裁定者) | 改定率(既裁定者) |") P("|---|---|---|---|---|---|---|---|") for y, p, w, a, s, d, n, e in T: P(f"| {y} | {p} | {w} | {a} | {s} | {d} | {n} | {e} |") P("- 発動の年:" + "・".join(y for y, *r in T if r[3].startswith("発動")) + f"({sum(1 for t in T if t[4].startswith('発動'))}回。報道発表 R7 p3「計6回」+R8=7回と一致)") P("- 決め手の内訳:物価 %d/賃金 %d/新規賃金・既裁定物価 %d/据え置き %d" % tuple(sum(1 for t in T if t[5].startswith(k)) for k in ("物価", "賃金", "新規", "スライドなし"))) P("- R8 は基礎年金 1.9%・厚生年金(報酬比例部分)2.0%。下の積み上げは基礎年金の率(国民年金の満額の月額で照合するため)。") P("- H27 の改定率 0.9 = 賃金 2.3 − 調整 0.9 − 特例水準の解消 0.5(年金部会資料 p19)。") # 検算:改定率 ≈ 決め手 − 調整(加算) P("\n## 検算(表の中の整合)") chk = {"H27": 2.3 - 0.9 - 0.5, "R1": 0.6 - 0.2 - 0.3, "R2": 0.3 - 0.1, "R5新規": 2.8 - 0.6, "R5既": 2.5 - 0.6, "R6": 3.1 - 0.4, "R7": 2.3 - 0.4, "R8基礎": 2.1 - 0.2} for k, v in chk.items(): P(f"- {k}: {v:.1f}") # 積み上げ def cum(rates): return prod(1 + r / 100 for r in rates) def rows(sl): return [t for t in T if sl(t[0])] P("\n## 2. 積み上げ(各年の率を掛け合わせる。%=(積−1)×100)") def pct(x): return (x - 1) * 100 wins = {"H27〜R8(12年度分)": lambda y: True, "H28〜R8(11年度分)": lambda y: y != "H27"} P("| 期間 | 物価変動率の累積 | 年金の改定率の累積(新規裁定者) | 年金の改定率の累積(既裁定者) | 新規−物価(pt) | 既裁定−物価(pt) |") P("|---|---|---|---|---|---|") res = {} for nm, f in wins.items(): rr = rows(f) c_p = cum([t[1] for t in rr]); c_n = cum([t[6] for t in rr]); c_e = cum([t[7] for t in rr]) res[nm] = (c_p, c_n, c_e) P(f"| {nm} | {pct(c_p):.2f}%({c_p:.4f}倍) | {pct(c_n):.2f}%({c_n:.4f}倍) | {pct(c_e):.2f}%({c_e:.4f}倍) | {pct(c_n)-pct(c_p):.2f} | {pct(c_e)-pct(c_p):.2f} |") P("- 参考(単純合計、掛け合わせない)H28〜R8:物価 " + f"{sum(t[1] for t in rows(wins['H28〜R8(11年度分)'])):.1f}" + "%、新規 " + f"{sum(t[6] for t in rows(wins['H28〜R8(11年度分)'])):.1f}" + "%、既裁定 " + f"{sum(t[7] for t in rows(wins['H28〜R8(11年度分)'])):.1f}%") P(f"- R8 が厚生年金(報酬比例部分 2.0%)の場合、H28〜R8 の新規裁定者の累積は {pct(cum([t[6] if t[0]!='R8' else 2.0 for t in rows(wins['H28〜R8(11年度分)'])])):.2f}%(基礎年金 {pct(res['H28〜R8(11年度分)'][1]):.2f}%)") # 年ごとの累積の並び P("\n年ごとの累積(H28を起点=1.0000、新規裁定者/既裁定者/物価):") c = [1, 1, 1] for t in T[1:]: c = [c[0] * (1 + t[6] / 100), c[1] * (1 + t[7] / 100), c[2] * (1 + t[1] / 100)] P(f"- {t[0]}:新規 {c[0]:.4f}/既裁定 {c[1]:.4f}/物価 {c[2]:.4f}") # 外部照合:国民年金満額の月額 P("\n## 3. 外部照合:厚労省 報道発表 p1 の国民年金(老齢基礎年金 満額1人分)の月額と、改定率の累積") def amounts(pat): f = sorted(glob.glob(os.path.join(R, pat)))[0] t = pypdf.PdfReader(f).pages[0].extract_text().replace(" ", "").replace("\n", "") i = t.find("満額):1人分)") nums = re.findall(r"([\d,]{5,7})円", t[i:i + 120]) return [int(x.replace(",", "")) for x in nums[:2]], f A = {} for y, pat in [("H28", "mhlw_年金額改定_H28_*"), ("H29", "mhlw_年金額改定_H29_*"), ("H30", "mhlw_年金額改定_H30_*"), ("R1", "mhlw_年金額改定_H31R1_*"), ("R2", "mhlw_年金額改定_R2_*"), ("R3", "mhlw_年金額改定_R3_*"), ("R4", "mhlw_年金額改定_R4_*"), ("R5", "mhlw_年金額改定_R5_*"), ("R6", "mhlw_年金額改定_R6_*"), ("R7", "mhlw_年金額改定_R7_*"), ("R8", "mhlw_令和8年度*")]: A[y] = amounts(pat)[0] A["H30"] = (A["H29"][1], A["H30"][0]) # H30 の報道発表は当年度の1列だけ(64,941)。前年度欄は H29 の当年度欄を使う prev = None P("| 年度 | 前年度(月額) | 当年度(月額) | 月額の増減率 | 表の改定率(新規) | 差(pt) |") P("|---|---|---|---|---|---|") for t in T[1:]: a0, a1 = A[t[0]] if a0 is None: continue g = (a1 / a0 - 1) * 100 P(f"| {t[0]} | {a0:,} | {a1:,} | {g:.3f}% | {t[6]} | {g - t[6]:+.3f} |") base = A["H28"][0]; end = A["R8"][1] c_n = res["H28〜R8(11年度分)"][1] P(f"\n月額のつながり:H27年度の月額 {base:,}円(H28 p1の前年度欄)→ R8年度 {end:,}円 = {(end/base-1)*100:.2f}%(新規裁定者・基礎年金)。改定率の累積(H28〜R8){pct(c_n):.2f}%との差 {((end/base-1)*100 - pct(c_n)):+.2f}pt。") P(f"既裁定者(H28〜R8)の月額 65,008→70,408 = {(70408/65008-1)*100:.2f}%。改定率の累積(既裁定者){pct(res['H28〜R8(11年度分)'][2]):.2f}%との差 {((70408/65008-1)*100 - pct(res['H28〜R8(11年度分)'][2])):+.2f}pt(R4までは新規と同じ月額)") P("年度ごとの月額の連鎖(前年度欄=前の年度の当年度欄)が全年で一致するか:" + str(all(A[T[i][0]][0] == A[T[i-1][0]][1] for i in range(2, len(T))) if True else "")) for y0, y1 in zip([t[0] for t in T[1:-1]], [t[0] for t in T[2:]]): if A[y1][0] != A[y0][1]: P(f" ・連鎖が切れる:{y0}の当年度欄 {A[y0][1]:,} ≠ {y1}の前年度欄 {A[y1][0]:,}") # 既裁定:R5 以降の昭和31年4月1日以前生まれの月額(脚注) P("\n既裁定者の月額(報道発表 p1 の脚注。R5=既裁定者(68歳以上)、R6〜R8=昭和31年4月1日以前生まれ):R4 64,816 → R5 66,050 → R6 67,808 → R7 69,108 → R8 70,408") ex = [64816, 66050, 67808, 69108, 70408] P(f"月額の増減率(R4→R8)={(ex[-1]/ex[0]-1)*100:.2f}%。改定率の累積(R5〜R8、既裁定者)={pct(cum([t[7] for t in T[8:]])):.2f}%、(新規裁定者)={pct(cum([t[6] for t in T[8:]])):.2f}%、新規裁定者の月額(64,816→70,608)={(70608/64816-1)*100:.2f}%") P("年ごとの既裁定者の月額の増減率:" + ", ".join(f"{a}→{b}: {(b/a-1)*100:.2f}%" for a, b in zip(ex, ex[1:]))) print("\n".join(out)) open("out_計算結果_2026-09-30.md", "w").write("\n".join(out))