採用の説明資料や人事制度の見直し、統合報告書の準備のたびに、競合の有価証券報告書を開いて、従業員数や平均年収、女性管理職比率をExcelに書き写していないでしょうか。人の数字は書類の中で場所が散らばっているうえ、「単体か連結か」「どの算定方法か」で同じ名前の数字でも中身が変わります。転記した表だけが会議に回ると、その前提が抜け落ちます。
連載「分析編」の最終回は、自社と競合最大5社の人的資本の開示を一つの表に並べます。比較ボードの「人材」の表を読み、並べるときに崩れやすい前提(単体と連結、算定の基準、開示の年度、未開示)を、画面とコードの両方で確かめます。
画面の数値は、2026年10月29日にZENITH Codeの実データを取得して保存したデモです。トヨタ自動車(7203)を自社に見立て、同業5社と並べています。「自社」の札はデモ上の見本です。前回の分析④では、業績予想の修正の履歴を追いました。
私たち株式会社Crabgrassは、企業の財務データなどをAPIで提供するZENITH Codeを開発しています。本記事は自社サービスのデータを使うためのテンプレートを題材にした実装例です。
この記事のコードは、公開サンプル集のpeer-benchmarkテンプレート(執筆時点の版)と、company-deep-diveテンプレート(執筆時点の版)に対応しています。画面の仕組みの基本(ローカルのPythonサーバーとブラウザの役割分担)は、実践編で詳しく扱いました。
1. この回で読む画面と操作
| 操作 | 画面で変わるもの | 今回読むコード |
|---|---|---|
| 比較ボードで「比較データを取得」を押す | 「05 人材」の表に6社が並ぶ |
server.py の WORKFORCE_FIELDS・diversity_rows
|
| 会社名の下を見る | 人の数字の決算期(FY) |
model.mjs の latestFiling・companyMetrics
|
| 男性育休取得率の「†」を見る | 算定の基準の違い |
app.mjs の renderPeople
|
| 深掘りワークスペースで「人材と組織」を開く | 1社のセグメント別の人数、雇用形態別の賃金の差異、子会社の値 |
company-deep-dive の peopleSummary
|
| 「CSVで保存」を押す | 人の列も含む比較表のファイル | comparisonCsv |
2. 登録不要で試す
必要なものはPython 3.9以上とブラウザです。追加のパッケージはありません。
git clone https://github.com/Crab-grass/zenith-code-examples.git
cd zenith-code-examples
python3 templates/peer-benchmark/server.py
ブラウザで http://127.0.0.1:8790 を開き、目次の「05 人材」を押すと、この回の表に移ります。デモではAPIを呼ばないので、会員登録もAPIキーも要りません。終了するときは端末で Ctrl+C を押します。
深掘りワークスペースも同時に開くときは、ポートを変えて起動し、http://127.0.0.1:8791 を開きます。
python3 templates/company-deep-dive/server.py --port 8791
3. 人の数字はどの書類から来るか
表の数字は、各社の有価証券報告書の「従業員の状況」から来ています。2023年3月31日以後に終わる事業年度から、有価証券報告書に人的資本と多様性の記載が求められるようになり、女性管理職比率・男性の育児休業取得率・男女の賃金の差異も、同じ「従業員の状況」に載るようになりました。
ZENITH Codeでは、これを2つのAPIで取得します。比較ボードは1社につきそれぞれ1回ずつ呼びます。
| API | 主な項目 |
|---|---|
/stable/workforce |
従業員数(提出会社・連結)、平均年齢、平均勤続年数、平均年間給与、セグメント別の人数 |
/stable/diversity |
女性管理職比率、男性の育児休業取得率とその算定の基準、男女の賃金の差異(提出会社と主な子会社) |
ローカルのサーバーは、比較ボードに必要な項目だけを選んでブラウザに渡します。
WORKFORCE_FIELDS = FILING_FIELDS + ("employees", "consolidatedEmployees", "averageAge",
"averageTenureYears", "averageAnnualSalary")
DIVERSITY_FIELDS = ("femaleManagerRatio", "maleChildcareLeaveRatio", "maleChildcareLeaveBasis", "wageGapAll")
/stable/diversity は、提出会社の値のほかに、子会社ごとの値も返します。比較ボードは会社どうしを横に並べる画面なので、提出会社の値だけを残し、子会社の名前と値はブラウザに渡しません。
def diversity_rows(rows, expected):
out = _rows(rows, expected, FILING_FIELDS, 12)
for item, row in zip(out, rows):
item["sourceUrl"] = edinet_url(row.get("sourceUrl"))
company = row.get("reportingCompany")
# Subsidiary names and figures are not used and are not forwarded.
item["reportingCompany"] = _pick(company, DIVERSITY_FIELDS) if isinstance(company, dict) else None
return out
ここで大事なのは、表の多様性の3指標は、すべて提出会社(単体)の値だという点です。グループ全体の女性管理職比率ではありません。子会社の値は、1社を掘り下げる深掘りワークスペースのほうで見ます(7節)。
4. 最新の通期を1件だけ選ぶ
/stable/workforce と /stable/diversity は、書類ごとの行を複数返すことがあります。比較ボードは、その中から**最新の通期(FY)**の行を1件だけ選びます。
// Filing-based endpoints may hold several periods; keep the latest full year.
function latestFiling(rows, symbol) {
if (!Array.isArray(rows) || rows.length > 12) fail();
for (const row of rows)
if (!row || !sameSymbol(row.symbol, symbol) || !PERIOD.test(row.fiscalPeriod)) fail();
return rows.filter((row) => row.period === "FY").sort(latestFirst)[0] ?? null;
}
別の会社の行が混じっていれば全体を中止し、通期以外の行は使いません。選んだ行の決算期は、表の会社名の下に FY2026-03 の形で出ます。
この決算期は、収益性の表の決算期とは別に持っています。
peoplePeriod: w?.fiscalPeriod ?? company.diversity?.fiscalPeriod ?? null,
損益計算書は決算短信の時点で新しい期が入りますが、人の数字は有価証券報告書が出るまで前の期のままです。その間に取得すると、同じ会社で財務は新しい期、人材は前の期、ということが起こります。人材の決算期は、人材の表の会社名の下で確かめてください。
決算月が違えば、年度も違う
デモの6社はどれも3月決算で、人の数字もすべて FY2026-03 です。比較先に決算月の違う会社を入れると、同じ列に違う時点の数字が並びます。
深掘りワークスペースの保存データでは、トヨタ自動車が FY2026-03、ファーストリテイリング(8月決算)が FY2025-08、花王(12月決算)が FY2025-12 です。同じ日に取得しても、従業員の状況は最大で7か月ずれた時点の数字です。年収や女性管理職比率は年によって動くので、競合と並べる資料には、会社ごとの決算期を必ず残してください。
5. 単体か連結か
表の左の2列は、従業員数の範囲が違います。
| 列 | 範囲 |
|---|---|
| 従業員数(単体) | 有価証券報告書を出した会社だけ |
| 連結従業員数 | 連結子会社を含むグループ全体 |
そして、平均年齢・平均勤続年数・平均年間給与は、単体の従業員についての値です。グループ全体の平均ではありません。
デモのトヨタ自動車では、単体が73,133人、連結が390,927人です。表の平均年間給与1,006万円は、この73,133人についての値です。
単体と連結の差が大きいのは、持株会社の形をとる会社です。深掘りワークスペースの保存データで、ファーストリテイリング(FY2025-08)を見ると、単体の従業員数は1,572人、連結は59,522人です。平均年間給与1,251万円・平均年齢38.4歳・平均勤続年数5.8年は、1,572人の持株会社の社員についての値で、店舗や事業会社で働く人の数字ではありません。
競合が持株会社か事業会社かで、「平均年収」の列が表すものが変わります。比べる前に、単体と連結の人数の差を見ておくと、取り違えを防げます。
セグメント別の人数は深掘りで見る
深掘りワークスペースの「人材と組織」には、セグメント別の従業員数が、連結と単体で並びます。トヨタ自動車では次のとおりです。
| セグメント | 連結 | 単体 |
|---|---|---|
| 自動車事業 | 343,952 | 66,018 |
| 金融事業 | 16,222 | — |
| その他の事業 | 23,934 | 307 |
| 全社(共通) | 6,819 | 6,808 |
単体の金融事業が「—」なのは、単体の内訳に金融事業の人数がないためです。0人という値が入っているわけではありません。「全社(共通)」は、特定のセグメントに分類できない人数です。
6. 平均年収は「万円」に丸めて表示する
平均年間給与はAPIでは円で受け取り、表示の直前に丸めます。
// Salary: 万円 in Japanese, JPY millions in English.
export function salary(value, lang = "ja") {
value = finite(value);
if (value === null) return "—";
return lang === "ja" ? number(value / 1e4, lang, 0) : number(value / 1e6, lang, 2);
}
日本語では万円の整数、英語では百万円の小数2桁です。CSVには円のまま書き出します。
デモの6社の平均年間給与は、次のように読めます。
| 会社 | 平均年間給与(万円) | 平均年齢 | 平均勤続年数 |
|---|---|---|---|
| トヨタ自動車 | 1,006 | 40.5 | 15.1 |
| 本田技研工業 | 933 | 43.9 | 21.0 |
| スズキ | 828 | 41.5 | 18.5 |
| SUBARU | 764 | 40.0 | 15.7 |
| マツダ | 711 | 42.5 | 17.7 |
| 日産自動車 | 857 | 40.9 | 14.9 |
平均年間給与は、年齢・勤続年数・職種の構成で動きます。表は「その会社の単体の従業員の平均」で、同じ職種・同じ年齢の給与を比べたものではありません。採用の資料に使うときは、平均年齢と平均勤続年数を同じ行に残すと、読む人が構成の違いに気づけます。給与に何を含むかは、各社の有価証券報告書の注記で確かめてください。
7. 多様性の3指標は、定義を表の下に書く
女性管理職比率
管理職に占める女性の割合です。デモでは2.2%から11.3%の間に6社が並びます。どの役職から管理職に数えるかは、各社の役職の制度に合わせて会社が数えています。比率の差が大きいときは、管理職の範囲も確かめます。
男性育休取得率は、算定の基準が2種類ある
男性の育児休業取得率は、法律で公表の方法が2つ認められています。
| 基準 | 分子に数えるもの |
|---|---|
| 育児休業のみ | 育児休業等をした男性 |
| 育児目的休暇を含む | 育児休業等をした男性と、育児を目的とする休暇を取った男性 |
分母はどちらも、その年度に配偶者が出産した男性です。分子には前の年度に生まれた子のために休んだ人も入るので、100%を超えることがあります。デモの本田技研工業は116.8%です。
APIは、どちらの基準かを maleChildcareLeaveBasis で返します。比較ボードは、育児目的休暇を含む基準の値に「†」を付けています。
if (row.maleChildcareLeaveBasis === "childcare-leave-and-purpose-leave") leave.querySelector(".val").append(node("sup", "†"));
デモでは、本田技研工業(116.8%)とマツダ(67.1%)が育児目的休暇を含む基準、ほかの4社が育児休業のみの基準です。基準が違う値は、同じ物差しで測った数字ではありません。並べた表で大小を言うときは、基準のそろった会社どうしに限ってください。
男女の賃金の差異
男性の平均年間賃金を100%としたときの、女性の平均年間賃金の割合です。デモの6社は66.0%から84.7%の間です。
比較ボードは「全労働者」の値だけを出しますが、有価証券報告書には「正規雇用」「パート・有期」の区分もあります。深掘りワークスペースの保存データでは、トヨタ自動車の値は次のとおりです。
| 区分 | 女性の賃金の割合 |
|---|---|
| 全労働者 | 67.0% |
| 正規雇用 | 66.8% |
| パート・有期 | 59.7% |
この割合は、職種・役職・勤続年数の構成を調整した値ではありません。深掘りワークスペースは、画面の下にその旨を出しています。
子会社の値は深掘りで見る
深掘りワークスペースのサーバーは、比較ボードと違って子会社の値も残します。トヨタ自動車の保存データには、提出会社のほかに子会社9社の値が入っていて、「人材と組織」の表で一覧にできます。比較ボードの表は提出会社どうしの比較、子会社まで含めた姿は深掘りで、と使い分けます。
8. 未開示を0にしない
人の数字は、会社によって載っていない項目があります。従業員数が少ないなどの理由で法律上の公表の対象になっていない指標は、有価証券報告書に記載がないことがあります。
比較ボードは、値が数値でなければ null として扱い、表には「—」を出します。
employees: pick(w, "employees"),
consolidatedEmployees: pick(w, "consolidatedEmployees"),
averageAge: pick(w, "averageAge"),
averageTenureYears: pick(w, "averageTenureYears"),
averageAnnualSalary: pick(w, "averageAnnualSalary"),
femaleManagerRatio: pick(d, "femaleManagerRatio"),
maleChildcareLeaveRatio: pick(d, "maleChildcareLeaveRatio"),
maleChildcareLeaveBasis: typeof d?.maleChildcareLeaveBasis === "string" ? d.maleChildcareLeaveBasis : null,
wageGapAll: pick(d, "wageGapAll"),
人の項目がすべて null の会社は、会社名の下に「人的資本の開示データなし」と出します。
const empty = ["employees", "consolidatedEmployees", "averageAge", "averageTenureYears", "averageAnnualSalary", ...ratioKeys].every((k) => row[k] === null);
tr.append(companyHead(row, i, empty ? t("noPeople") : row.peoplePeriod ? `FY${row.peoplePeriod}` : ""));
「—」を0に置き換えると、女性管理職比率0%、男性育休取得率0%という、事実と違う数字が会議に出ます。グラフの棒も、値がないところは描きません。平均や順位を自分で計算するときも、「—」の会社は分母から外してください。
同じことは算定の基準にも言えます。深掘りワークスペースの保存データでは、花王(FY2025-12)の男性育休取得率は90.1%ですが、maleChildcareLeaveBasis は取得できていません。基準が分からない値は、どちらの基準の会社とも同じ物差しとは言えません。
9. 会議資料にする
「印刷・PDF」を押すと、A4横のレイアウトで印刷します。人材の表も、表の下の注記(単体の値であること、育休の算定方法、賃金の差異の定義)と一緒に印刷されます。注記を切り落として表だけを資料に貼らないようにしてください。
「CSVで保存」では、人の列も書き出します。
| 列 | 中身 |
|---|---|
peoplePeriod |
人の数字の決算期 |
employees・consolidatedEmployees
|
従業員数(単体・連結) |
averageAnnualSalary |
平均年間給与(円) |
femaleManagerRatio・maleChildcareLeaveRatio・wageGapAll
|
比率は小数(1.168 = 116.8%) |
maleChildcareLeaveBasis |
育休の算定基準(childcare-leave または childcare-leave-and-purpose-leave) |
値がないところは空欄です。表計算ソフトで集計するときに、空欄を0として足し込まないよう注意してください。
人の数字の出典は、「06 出典」の表の「人材」の列に、決算期と書類IDで出ています。書類IDからEDINETの原本を探せます。社内で共有するときはデータの表示ルールを確認してください。
10. 自社のコードで動かす
会員登録をしてAPIキーを作成し、--live を付けて起動し直します。
python3 templates/peer-benchmark/server.py --live
キーは端末の非表示入力で渡します。キーはローカルのPythonプロセスだけが持ち、ブラウザには送りません。
人の数字のために増えるリクエストはありません。「比較データを取得」の1社あたり6リクエストの中に、/stable/workforce と /stable/diversity が1回ずつ入っています。6社なら業種の分布の1リクエストを足して、合計37リクエストです。
人の数字は年に1回、有価証券報告書の提出で変わります。毎日取り直す必要はなく、競合の有価証券報告書が出そろう時期にまとめて取り直せば足ります。デモの3月決算の6社は、6月から8月に提出していました(11節)。
11. 小さな変更:提出日と育休の基準を、表の中に文字で書く
会社名の下の FY2026-03 だけでは、いつ出た書類の数字かまでは分かりません。また、「†」は小さく、表を資料に貼ると見落とされます。比べる前提を、表の中に文字で出してみます。
- 会社名の下に、人の数字を取った書類の提出日を出す
- 男性育休取得率の数字の下に、算定の基準を「育休のみ」「目的休暇を含む」と書く(基準が取得できなかった値には「基準は未取得」)
変更するのは app.mjs と style.css だけです。model.mjs・server.py・APIの呼び出し回数・CSVの列は変えません。提出日は、サーバーがもともとブラウザへ渡している submittedAt を使います。
1. 文言を足す(app.mjs の texts)。 ja と en のそれぞれ、yearsOld の行の前に足します。
filed: "提出", leaveBasis: { "childcare-leave": "育休のみ", "childcare-leave-and-purpose-leave": "目的休暇を含む" }, leaveBasisNone: "基準は未取得",
filed: "Filed", leaveBasis: { "childcare-leave": "leave only", "childcare-leave-and-purpose-leave": "incl. purpose leave" }, leaveBasisNone: "basis n/a",
表の下の注記の「(† 育児目的休暇を含む)」も、次のように書き換えます。
peopleFoot: "連結従業員数以外は提出会社(単体)の値です。男性育休取得率は会社により算定方法が異なり、100%を超えることがあります(数字の下に算定の基準を表示)。男女の賃金の差異は男性の賃金に対する女性の賃金の割合です。",
英語の peopleFoot も、(† includes childcare-purpose leave) を (the basis is shown under each value) に変えます。
2. 会社の元データを渡す(app.mjs の renderReport())。 提出日は companyMetrics の結果に入っていないので、会社ごとの元データも渡します。
renderPeople(rows, report.companies);
3. 提出日を出す(app.mjs の renderPeople())。 関数の引数に companies を足し、会社名のセルを作る行を次のように変えます。
function renderPeople(rows, companies) {
const head = companyHead(row, i, empty ? t("noPeople") : row.peoplePeriod ? `FY${row.peoplePeriod}` : "");
// The filing date of the workforce data, so a filing made later than the others is visible in the row.
const filedAt = companies[i].workforce?.submittedAt ?? companies[i].diversity?.submittedAt;
if (typeof filedAt === "string") head.append(node("span", `${t("filed")} ${filedAt.slice(0, 10)}`, { class: "co-meta" }));
tr.append(head);
4. 基準を文字で出す(同じ renderPeople())。 「†」を付けていた行を置き換えます。値がない会社には何も付けません。
// Spell out the basis instead of a dagger: the ratio depends heavily on it.
if (row.maleChildcareLeaveRatio !== null)
leave.querySelector(".val").append(node("small", t("leaveBasis")[row.maleChildcareLeaveBasis] ?? t("leaveBasisNone"), { class: "note basis" }));
5. 色を整える(style.css)。 .val small.note はネットキャッシュの注記用に緑色が付いているので、基準の文字は灰色にします。.val small.note の行の下に足します。
.val small.note.basis { color: var(--muted); }
保存して再読み込みし、本田技研工業とマツダの下に「目的休暇を含む」、ほかの4社に「育休のみ」が出れば完成です。計算の部分には触れていないので、リポジトリのテストは変更後もそのまま通ります。
node --test tests/peer-benchmark.test.mjs
提出日を出すと、デモの6社のうちスズキだけが 提出 2026-08-25 で、ほかの5社は6月の提出だと分かります。決算期は同じ FY2026-03 でも、書類の出た時期が違います。どの書類から取った数字かは、「06 出典」の表の書類ID(スズキは S100YYB1)で確かめられます。
12. 確認箇所
| 症状 | 確認箇所 |
|---|---|
| 平均年収が競合と大きく違って見える | 単体と連結の人数の差(持株会社ではないか)、平均年齢と勤続年数 |
| 男性育休取得率が100%を超える | 算定の基準。分母はその年度に配偶者が出産した男性、分子には前年度の出生分も入る |
| 育休取得率を並べて大小を言いたい | 基準が同じ会社どうしか。基準が未取得の値は比べない |
| 女性管理職比率がグループの数字と違う | 表は提出会社(単体)の値。子会社の値は深掘りで見る |
| 会社名の下の決算期がずれている | 決算月の違い、有価証券報告書の提出前に取得していないか |
| 「—」や「人的資本の開示データなし」が出る | 未開示・未取得。0には置き換えない |
| 提出日が出ない |
renderPeople に report.companies を渡したか |
表示を変える作業をAIに頼む場合も、計算やAPIの呼び出しに触れないことを明記すると、確認する範囲を絞れます。
peer-benchmarkテンプレートの「人材」の表を、次のように変えてください。
1. 会社名の下に、人の数字を取った書類の提出日(workforce の submittedAt、なければ diversity の submittedAt の先頭10文字)を「提出 YYYY-MM-DD」と出す。
2. 男性育休取得率の数字の下に、maleChildcareLeaveBasis に応じて「育休のみ」「目的休暇を含む」を小さく出す。基準がない値には「基準は未取得」と出し、値がない会社には何も出さない。今の「†」は外し、表の下の注記も合わせて直す。
app.mjs の renderPeople と renderReport、texts の ja と en、style.css だけを変更します。
model.mjs、server.py、CSVの列、APIの呼び出し回数は変更しないでください。
nullを0に変換しないでください。
変更箇所と、デモで確認する操作を説明してください。
13. 連載のまとめと、次の「運用編」
分析編では、2つのテンプレートを使って、競合と比べる画面を5回に分けて読みました。
| 回 | 題 | 主に使う画面 |
|---|---|---|
| ① | 同業他社ベンチマークを自動で作る――収益性と効率を業種の分布の中で見る | 比較ボード |
| ② | 競合がどの事業で稼いでいるか――セグメント情報を並べて比べる | 深掘り・比較ボード |
| ③ | 事業に回せるお金と使い道――財務体質とキャッシュフローを競合と比べる | 深掘り |
| ④ | 会社計画はどう変わってきたか――業績予想の修正の履歴を追う | 深掘り |
| ⑤ | 人と組織を競合と比べる――人的資本の開示を一つの表にする(この記事) | 比較ボード・深掘り |
5回を通して、同じ考え方を繰り返しました。
- 比べてよい条件(決算期、会計基準、単体か連結か、算定の基準)を、数字の横に必ず出す
- 条件がそろわない数字は計算せず「—」にし、0には置き換えない
- 画面に必要な項目だけをサーバーで選び、使わない値はブラウザに渡さない
ここまでの画面は、ボタンを押したときだけ取得する、1人で使う画面です。会社で使い続けるには、別の仕組みが要ります。
次の「運用編」では、次のことを扱います。
- 決まった時期に自動で取り直す(定期の更新)
- 競合や取引先の決算発表、業績予想の修正を通知する
- 社内で画面や表を共有するときの権限と、データの表示ルール
- APIキーを人やサーバーごとに分けて管理する
- AI(MCP)にZENITH Codeのデータを使わせる
分析編の画面を、毎月・毎四半期の業務の中で回す方法を書いていきます。


