- 技術 💻
樹形図とは?書き方と順列・組み合わせ・確率をPythonで検算
結論
樹形図(じゅけいず)は、起こりうる場合を、木の枝が分かれるように1段ずつ書き出して数える図です。英語では tree diagram と呼びます。並べ方(順列)なら枝は1段ごとに1本ずつ減り、選び方(組み合わせ)なら「前に出た文字より後ろ」だけを書くので枝はさらに減ります。
この記事でわかること
- 樹形図の書き方の手順と、書き漏れ・重複を防ぐ3つの決まり
- 順列・組み合わせ・重複順列の樹形図の形の違いと、確率の求め方の例
- Python の itertools で同じ数え上げをした結果と、Mermaid・Graphviz で樹形図を描く方法
この記事で実際に動かしたもの:Python 3.13 の itertools・math・fractions・random による数え上げと確率の計算、自作の「樹形図を文字で表示する」スクリプト、mermaid-cli 11.16.0 と Graphviz 2.43.0 による樹形図の描画(幅・高さ・時間の実測)です。
樹形図は、学校の算数・数学で「場合の数」や「確率」を求めるときに使う図です。一方で、プログラミングやデータ分析でも「木(ツリー)」の形はあちこちに出てきます。まず、A・B・C の3人が1列に並ぶ並び方を樹形図にすると、次のようになります(この図は Mermaid で描いています)。
flowchart LR
S((開始))
S --> N1[A]
N1 --> N2[B]
N2 --> N3[C]
N1 --> N4[C]
N4 --> N5[B]
S --> N6[B]
N6 --> N7[A]
N7 --> N8[C]
N6 --> N9[C]
N9 --> N10[A]
S --> N11[C]
N11 --> N12[A]
N12 --> N13[B]
N11 --> N14[B]
N14 --> N15[A]
左の「開始」から右の端まで、たどった道1本が「1通り」です。右の端(末端)が6個あるので、3人の並び方は6通りです。よく調べられることの答えを先にまとめます。
| 知りたいこと | 答え | 詳しい節 |
|---|---|---|
| 樹形図とは | 起こりうる場合を、枝分かれの形で1つ残らず書き出す図。末端の数が場合の数 | 樹形図とは |
| 樹形図の読み方・英語 | 「じゅけいず」。英語は tree diagram | 樹形図とは |
| 樹形図の書き方 | 名前を付ける→順番の決まりを決める→1段目→2段目以降→末端を数える | 樹形図の書き方 |
| 順列と組み合わせの樹形図の違い | 順列は AB と BA を別に数える。組み合わせは同じとみなし、前の文字より後ろだけを書く | 順列の樹形図/組み合わせの樹形図 |
| 樹形図で確率を求める | 当てはまる末端の数 ÷ 末端の総数(どの末端も同じ確からしさのとき) | 樹形図で確率を求める |
| 樹形図と表のどちらを使う | 2つの物の組(さいころ2個など)は表、3段以上や順番が大事なときは樹形図 | 樹形図・表・公式・プログラムの使い分け |
| 樹形図が大きすぎて書けない | 最初の枝1本分だけ書いて掛け算する。5人以上なら公式かプログラム | 樹形図の書き方のコツ/場合の数が増える速さ |
| 樹形図をパソコンで描く | Mermaid(flowchart LR)か Graphviz(rankdir=LR)。ノードの名前は道ごとに別にする | Mermaidで樹形図を描く/Graphvizで樹形図を描く |
確認環境:Ubuntu 24.04.5 LTS(2 CPU・メモリ 8GB)の上で、Python 3.13.18 の標準ライブラリ(itertools・math・fractions・random・tracemalloc・time)を使い、順列・組み合わせ・重複順列・円順列の数え上げ、確率の計算(分数で正確に)と100万回のシミュレーション、場合の数が増える速さとメモリ使用量を実測しました。樹形図を文字で表示する処理は自作の Python スクリプトです。図は、mermaid-cli 11.16.0(Mermaid 11.16.1)で SVG に描画して幅・高さを viewBox の値で測り、Graphviz 2.43.0 の dot で SVG と PNG を作って大きさと描画時間を測りました。木の形の IT での例として scikit-learn 1.9.1 の決定木の出力も載せています。外部のサービスには接続していません。itertools・math の仕様は Python 公式ドキュメント、Mermaid の書き方は Mermaid 公式ドキュメント、DOT 言語の決まりは Graphviz 公式ドキュメントで確かめました(確認日 2026年10月29日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「樹形図とは?書き方と順列・組み合わせ・確率をPythonで検算」
樹形図とは(意味・読み方と、場面別の意味)
この節では、樹形図の意味と読み方、そして「樹形図」「ツリー」という言葉が算数・生物・統計・IT でそれぞれ何を指すのかが分かります。
樹形図は、ある出来事で起こりうる場合を、1段目・2段目…と順に枝分かれさせて書き出し、全部の場合を1つ残らず数えるための図です。読み方は「じゅけいず」、英語では tree diagram です。根(出発点)から枝が分かれ、枝の先がさらに分かれていく形が木に似ているので、この名前が付いています。
樹形図で大事なのは、次の2点です。
- 根から末端までの1本の道が「1通り」にあたる。
- 末端(いちばん右か下の端)の数が、場合の数になる。
「樹形図」「ツリー」という言葉は、分野によって指すものが少しずつ違います。検索で別の分野の記事に当たって混乱しないよう、場面別に整理します。
| 場面 | 指すもの | 例 | この記事での扱い |
|---|---|---|---|
| ふだんの言葉 | 木の枝のように分かれていく図全般 | 家系図、組織図、トーナメント表 | 形の似た図として触れる |
| 算数・数学(場合の数・確率) | 起こりうる場合を全部書き出して数える図 | 3人の並び方、コインを3回投げたときの表裏 | この記事の中心 |
| 生物 | 生き物の進化の道すじを表す系統樹 | ヒトとチンパンジーの分かれ方 | 扱わない |
| 統計・データ分析 | 似たもの同士をまとめていくデンドログラム(樹状図) | 階層クラスタリングの結果 | 名前の違いだけ触れる |
| IT・プログラミング | 木構造(ツリー)。親が子を持つデータの形 | フォルダー構成、HTML の DOM、決定木 | 描き方・数え上げで関係する部分を扱う |
IT での「木」の例として、機械学習の決定木(データを条件で枝分かれさせて分類する手法)を scikit-learn で作り、文字で表示した実物を載せます。条件で枝が2つに分かれ、末端に答えが書かれている点は、算数の樹形図と同じ形です。
|--- 花弁幅 <= 0.80
| |--- class: 0
|--- 花弁幅 > 0.80
| |--- 花弁幅 <= 1.75
| | |--- class: 1
| |--- 花弁幅 > 1.75
| | |--- class: 2
算数の樹形図
目的は「全部の場合を数えること」
同じ段の枝は同じ観点(1人目・2人目…)
末端の数=場合の数
IT のツリー(木構造)
目的は「データの親子関係を表すこと」
段ごとに観点がそろうとは限らない
末端(葉)の数を数えると、樹形図と同じ計算になる場面がある
考えを分けて整理する「ロジックツリー」も木の形ですが、目的は課題の分解です。ロジックツリーの作り方は、関連記事「ロジックツリーの作り方と例|Why・How・Whatの違いとMECE切り口一覧」で扱っています。
樹形図の書き方(5つの手順)
この節では、紙に樹形図を書くときの手順を、4人のリレーの走る順番を例に1つずつ確かめられます。
樹形図は「名前を付ける」「書く順番の決まりを決める」「段ごとに枝を出す」の3つを守れば、書き漏れと重複がなくなります。例として、A・B・C・D の4人がリレーを走る順番が何通りあるかを求めます。
名前を付ける
人や物に、A・B・C・D や 1・2・3 のような短い名前を付ける。問題文に名前が無いときも自分で付ける。「赤玉1」「赤玉2」のように、同じ色でも区別して名前を付けると、確率の計算で間違えにくい。
書く順番の決まりを決める
アルファベット順・数の小さい順など、枝を書く順番を1つ決めて、すべての段で同じ決まりを使う。決まりがあると、抜けている枝に気づける。
1段目を書く
1段目は「第1走者」。A・B・C・D の4本の枝を、決めた順番で縦に並べる。1段目には何を書くのか(観点)を、図の上に小さく書いておく。
2段目以降を書く
A の右に「第2走者」の候補を書く。A はもう走ったので B・C・D の3本。その右に「第3走者」の2本、最後に「第4走者」の1本。同じ人を1本の道で2回書かない。
末端を数える
A から始まる末端は6個。B・C・D から始まる部分も同じ形なので、6 × 4 = 24通り。全部書き切ったら、末端の数を指で押さえながら数え直す。
A から始まる部分だけを、自作のスクリプトで文字の樹形図にすると、次の形です(└─ は最後の枝、├─ は続きがある枝)。
└─ A
├─ B
│ ├─ C
│ │ └─ D
│ └─ D
│ └─ C
├─ C
│ ├─ B
│ │ └─ D
│ └─ D
│ └─ B
└─ D
├─ B
│ └─ C
└─ C
└─ B
末端の数: 6
Python で4人の並び方をすべて書き出して数えると、樹形図の答えと一致しました。並びは、樹形図を上から読んだ順(辞書順)と同じです。
permutations ABCD: 24
ABCD ABDC ACBD ACDB ADBC ADCB BACD BADC ...
A始まり 6
条件付きの問題は全部書かずに済むことがある
「B が第2走者になる並び方は何通りか」のように条件が付くときは、条件に合う枝だけを書けば答えが出ます。1段目に B 以外の3人、2段目は B だけ、3段目と4段目は残りの2人です。Python で条件に合うものだけを取り出すと6通りでした。
B第2走者 6 ['ABCD', 'ABDC', 'CBAD', 'CBDA', 'DBAC', 'DBCA']
樹形図の書き方のコツと、書く前の見積もり
この節では、書き始める前に末端の数を掛け算で見積もる方法と、大きな樹形図を紙に収めるコツが分かります。
書き始める前に「各段の枝の数」を掛け算すると、末端の数が先に分かります。4人の並び方なら 4 × 3 × 2 × 1 = 24、コインを3回投げるなら 2 × 2 × 2 = 8 です。見積もりが 30 を超えるなら、全部を書くのはやめて、最初の枝1本分だけ書いて掛け算する方が速く、正確です。
見積もる
各段の枝の数を掛け算する。4人なら 4×3×2×1=24。
30を超えたら全部は書かない
1本分だけ書く
A から始まる部分だけ書き、同じ形が何組あるかを掛ける。
6 × 4 = 24
横向きに書く
根を左、末端を右に置く。末端が縦に並ぶので数えやすい。
紙は横長に使う
段の観点を書く
図の上に「1人目」「2人目」と書く。段ごとの意味がずれない。
途中で観点を変えない
「横向きに書く」は、パソコンで描くときも同じです。後の節で実測したとおり、Mermaid でも Graphviz でも、左から右へ(LR)描いた方が横幅が小さく収まりました。
- 同じ段に違う観点を混ぜない:1段目が「1人目」なら、1段目のすべての枝が「1人目」です。途中で「色」と「人」を混ぜると、数が合わなくなります。
- 途中で省略しない:「以下同様」と書いて省くのは、同じ形だと確かめた後だけにします。条件付きの問題では、枝ごとに形が違うことがあります。
- 末端に答えを書く:末端の右に「ABCD」「12」のように道全体を書いておくと、確率を求めるときに数えやすくなります。
順列の樹形図(並べ方:枝が1本ずつ減る)
この節では、順番を区別する「順列」の樹形図の形と、公式 nPr との関係が分かります。
順列は、選んだものを並べる順番まで区別する数え方です。AB と BA は別のものとして数えます。樹形図では、一度使ったものは同じ道でもう使えないので、段が進むごとに枝が1本ずつ減ります。
例として、1・2・3・4 のカードから2枚を続けて引き、引いた順に並べて2けたの整数を作ります。1段目(十の位)は4本、2段目(一の位)は残りの3本なので、4 × 3 = 12通りです。Python で全部を書き出した結果です。
from itertools import permutations
nums = [a * 10 + b for a, b in permutations([1, 2, 3, 4], 2)]
print(len(nums), nums)
12 [12, 13, 14, 21, 23, 24, 31, 32, 34, 41, 42, 43]
「n 個から r 個を選んで並べる」数を、公式では nPr と書きます。4P2 = 4 × 3 = 12、4P4 = 4 × 3 × 2 × 1 = 24 です。公式は、樹形図の各段の枝の数を掛け算したものを短く書いたものだと考えると、覚え違いが減ります。Python の math.perm(4, 2) も 12 を返しました。
先頭に置けないものがある順列
0・1・2・3 のカードから3枚で3けたの整数を作るときは、百の位に 0 を置けません。樹形図の1段目は 1・2・3 の3本だけで、2段目は 0 を含む残り3本、3段目は2本です。3 × 3 × 2 = 18通りになり、Python で「先頭が 0 のものを除く」と数えた結果も一致しました。
0123で3桁 18 24
右の 24 は、先頭の 0 を除く前の数です。1段目の枝の数を間違えると 24 と答えてしまうので、1段目を書く前に「この段に書けないものは無いか」を確かめるのが確実です。
組み合わせの樹形図(選び方:前の文字より後ろだけを書く)
この節では、順番を区別しない「組み合わせ」の樹形図の書き方と、順列との違いが分かります。
組み合わせは、選ぶだけで順番は区別しない数え方です。AB と BA は同じ1組です。樹形図では、2段目以降に「前の段の文字より後ろ(アルファベットで後)の文字」だけを書くと、同じ組を2回数えずに済みます。
A・B・C・D の4人から代表を2人選ぶ組み合わせを、自作のスクリプトで樹形図にしました。A の後ろは B・C・D、B の後ろは C・D、C の後ろは D だけで、D から始まる枝はありません。
├─ A
│ ├─ B
│ ├─ C
│ └─ D
├─ B
│ ├─ C
│ └─ D
└─ C
└─ D
末端の数: 6
同じ4人から「代表と副代表」を選ぶ場合は、役割が違うので順番を区別します。こちらは順列で12通りです。
4人から2人を選ぶ
見分ける問い:「選んだ2人を入れ替えたら、結果は変わるか」
代表・副代表 12 代表2人 6
組み合わせの数は、公式では nCr と書きます。4C2 = 4P2 ÷ 2! = 12 ÷ 2 = 6 です。2人の並べ方(2! = 2通り)で同じ組が2回ずつ数えられているので、2 で割ります。5人から掃除当番を3人選ぶなら 5C3 = 10 で、Python の combinations('ABCDE', 3) も10個を返しました。
組み合わせの樹形図の末端は、上から 3本+2本+1本=6 のように枝の数が段ごとにそろわないので、掛け算の見積もりが使えません。全部を書いて数えるか、公式を使います。
重複順列・重複組み合わせ・円順列の樹形図
この節では、同じものを何度も選べる場合や、輪に並ぶ場合に、樹形図の形がどう変わるかが分かります。
同じものを何度でも選べるときは、枝が減りません。コインを3回投げるときの表裏は、毎回「表」「裏」の2本ずつ枝が出るので 2 × 2 × 2 = 8通りです。これを重複順列と呼びます。自作のスクリプトで表示した樹形図です。
├─ 表
│ ├─ 表
│ │ ├─ 表
│ │ └─ 裏
│ └─ 裏
│ ├─ 表
│ └─ 裏
└─ 裏
├─ 表
│ ├─ 表
│ └─ 裏
└─ 裏
├─ 表
└─ 裏
末端の数: 8
樹形図の「枝の減り方」で、数え方の種類を見分けられます。Python の itertools には、それぞれに対応する関数があります。
| 数え方 | 樹形図の枝 | 例と結果 | Python |
|---|---|---|---|
| 順列 | 1段ごとに1本ずつ減る | ABCD から2人を並べる:12通り | permutations('ABCD', 2) |
| 組み合わせ | 前の文字より後ろだけ。段ごとに数がそろわない | ABCD から2人を選ぶ:6通り | combinations('ABCD', 2) |
| 重複順列 | 減らない(毎回同じ本数) | コイン3回:8通り | product('表裏', repeat=3) |
| 重複組み合わせ | 前の文字と同じか後ろ | ABC から重複ありで2つ:6通り(AA AB AC BB BC CC) | combinations_with_replacement('ABC', 2) |
同じものを含む順列(AABC)
A・A・B・C の4文字の並べ方は、A が2つあるので 4! ÷ 2! = 12通りです。ところが permutations('AABC') は24個を返しました。Python 公式ドキュメントには、permutations は要素を「値ではなく位置で」区別する、と書かれています。同じ値の並びを1つにまとめるには、set() で重複を除きます。
AABC 並べ方 12 permutationsの結果数 24
紙の樹形図でも同じことが起きます。1段目に A を2回書くと、同じ形の枝が2組できてしまいます。同じものが複数あるときは、1段目から「A・B・C」の3種類だけを書くのが正しい書き方です。
円順列(輪に並ぶ)
4人が丸いテーブルに座る並び方は、回して同じになるものを1つと数えるので (4 − 1)! = 6通りです。樹形図では「A の席を固定して、残りの3人を並べる」と考えると、3 × 2 × 1 の樹形図になります。Python で、24通りの並びを「A が先頭に来るよう回転した形」にそろえて数えると、6通りでした。
円順列 4人 6 ['ABCD', 'ABDC', 'ACBD', 'ACDB', 'ADBC', 'ADCB']
樹形図で確率を求める(カード・くじ引き・余事象)
この節では、樹形図を使った確率の求め方を、カード・くじ引き・コインの3つの例で、分数の計算とシミュレーションの両方で確かめられます。
確率は「当てはまる末端の数 ÷ 末端の総数」で求めます。ただし、これが成り立つのは、どの末端も同じ確からしさで起こるときだけです。樹形図を書くときに、物や人を1つずつ区別して名前を付けるのはこのためです。
例1:2けたの整数が奇数になる確率
1〜4 のカードから2枚を引いて作る2けたの整数12通りのうち、一の位が 1 か 3 のもの(13・21・23・31・41・43)は6通りです。確率は 6/12 = 1/2 です。Python の fractions で分数のまま計算しました。
from itertools import permutations
from fractions import Fraction as F
nums = [a * 10 + b for a, b in permutations([1, 2, 3, 4], 2)]
odd = [x for x in nums if x % 2]
print('奇数', len(odd), '/', len(nums), '=', F(len(odd), len(nums)))
奇数 6 / 12 = 1/2
例2:くじ引きは先に引く方が有利か
5本のうち当たりが2本のくじを、A が先に、B が後に1本ずつ引きます(引いたくじは戻さない)。当たりを「当1・当2」、外れを「外1・外2・外3」と区別して樹形図を書くと、1段目は5本、2段目は4本で、末端は 5 × 4 = 20通りです。
くじ 全 20 A当たり 2/5 B当たり 2/5 両方 1/10
A が当たる確率も、B が当たる確率も 2/5 で同じでした。念のため、乱数で100万回くじを引くシミュレーションもしました(乱数の種は 211)。
シミュレーション N=1000000 A 0.3994 B 0.4007 (理論 0.4000)
引く順番によって当たる確率は変わりません。B は A の結果によって当たりやすくも当たりにくくもなりますが、全部の場合をならすと 2/5 になります。樹形図で末端を全部数えると、この結果が目で確かめられます。
例3:「少なくとも1回」は余事象で求める
コインを3回投げて、少なくとも1回は表が出る確率を求めます。8通りの樹形図で「表が1回も出ない」のは「裏裏裏」の1通りだけなので、1 − 1/8 = 7/8 です。このように「そうならない場合」を引く考え方を余事象と呼びます。
少なくとも1回表 7/8 余事象 1- 1/8 = 7/8
少なくとも1回表 sim 0.8752 理論 0.8750
「少なくとも」「1回以上」という言葉が出たら、まず余事象を考えると、樹形図で数える末端がぐっと少なくなります。
確率の考え方を、さいころや正規分布などの「分布」として広げる内容は、関連記事「確率分布とは|種類一覧・平均と分散・選び方をPythonで実演」で扱っています。
樹形図・表・公式・プログラムの使い分け(判断表)
この節では、樹形図を使うべき問題と、表・公式・プログラムに切り替えた方がよい問題の見分け方が分かります。
2つのものの組み合わせは表、3段以上や順番が大事なものは樹形図、末端が数十を超えるものは公式かプログラム、が目安です。
さいころ2個は表の方が速い
大小2つのさいころを投げるときは、樹形図にすると1段目6本・2段目6本で末端が36個になります。縦に大、横に小をとった 6 × 6 の表なら、和が 7 になるマス(対角線の6マス)がひと目で見つかります。
区別する 36 1/6
「区別しない」と確率を間違える(実測)
2つのさいころを区別せずに「(1,6) と (6,1) は同じ」として数えると、出方は21通りになり、和が 7 は (1,6)・(2,5)・(3,4) の3通りで、確率は 3/21 = 1/7 と出てしまいます。正しくは 1/6 です。
区別しない数え方 21 和7 3 => 1/7 (誤り)
区別する 36 1/6
21通りの出方は、同じ確からしさではありません((1,1) は1通りでしか出ないのに、(1,6) は2通りの出方がある)。確率を求めるときは、見た目が同じでも、物を区別して数えるのが決まりです。
判断表
| 問題の形 | 向いている方法 | 理由 |
|---|---|---|
| 3人・3段くらいまでの並べ方 | 樹形図(全部書く) | 末端が10前後で、書いて数えるのが確実 |
| 4人の並べ方・条件付きの並べ方 | 樹形図(1本分だけ書いて掛け算) | 同じ形がくり返す。条件の枝だけ書ける |
| 2つのもの(さいころ2個・2人のじゃんけん) | 表 | 2段しかなく、表の方がマスで数えやすい |
| 選ぶだけ(代表を選ぶ・当番を選ぶ) | 樹形図(後ろの文字だけ)か nCr | 組み合わせの樹形図は形がそろわない |
| 「少なくとも1回」 | 余事象+樹形図 | 「1回もない」の末端だけ数えればよい |
| 5人以上の並べ方・10回以上の試行 | 公式(nPr・nCr) | 5人の並び方で末端120、紙に収まらない |
| 条件が複雑で公式が立てにくい | プログラム(itertools)で全部数える | 9人の並び方 362,880通りでも 3.6ミリ秒で数えられた |
| 答えを確かめたい | プログラムかシミュレーション | 手で数えた答えと照らし合わせられる |
Pythonのitertoolsで樹形図と同じ数え上げをする
この節では、Python の itertools を使って、樹形図の末端を全部書き出す方法と、樹形図そのものを文字で表示する方法が分かります。
itertools の permutations・combinations・product・combinations_with_replacement の4つは、樹形図を上から順に読んだ並び(辞書順)をそのまま返します。Python 公式ドキュメントでも、permutations は入力の順番にしたがって辞書順で出す、と説明されています。手で書いた樹形図の答え合わせに使えます。
from itertools import permutations, combinations, product, combinations_with_replacement
import math
print(len(list(permutations('ABCD')))) # 4人の並び方
print(' '.join(''.join(x) for x in permutations('ABCD', 2)))
print(' '.join(''.join(x) for x in combinations('ABCD', 2)))
print(' '.join(''.join(x) for x in product('表裏', repeat=3)))
print(' '.join(''.join(x) for x in combinations_with_replacement('ABC', 2)))
print(math.perm(4), math.perm(4, 2), math.comb(4, 2), math.comb(5, 3))
24
AB AC AD BA BC BD CA CB CD DA DB DC
AB AC AD BC BD CD
表表表 表表裏 表裏表 表裏裏 裏表表 裏表裏 裏裏表 裏裏裏
AA AB AC BB BC CC
24 12 6 10
math.perm と math.comb は Python 3.8 で追加された関数で、数だけが欲しいときは書き出すより速く求まります。
樹形図を文字で表示するスクリプト
数え上げた結果から木を組み立てて、樹形図の形で表示します。この記事に載せている文字の樹形図は、すべてこのスクリプトで出したものです。
from itertools import permutations
def build(seqs):
root = {}
for s in seqs:
node = root
for x in s:
node = node.setdefault(x, {})
return root
def show(node, prefix=''):
items = list(node.items())
for i, (k, child) in enumerate(items):
last = i == len(items) - 1
print(prefix + ('└─ ' if last else '├─ ') + k)
show(child, prefix + (' ' if last else '│ '))
def leaves(node):
return 1 if not node else sum(leaves(c) for c in node.values())
tree = build(permutations('ABC'))
show(tree)
print('末端の数:', leaves(tree))
├─ A
│ ├─ B
│ │ └─ C
│ └─ C
│ └─ B
├─ B
│ ├─ A
│ │ └─ C
│ └─ C
│ └─ A
└─ C
├─ A
│ └─ B
└─ B
└─ A
末端の数: 6
permutations('ABC') を combinations('ABCD', 2) や product('表裏', repeat=3) に変えるだけで、組み合わせ・重複順列の樹形図も表示できます。itertools のほかの関数もまとめて知りたいときは、関連記事「Python itertoolsの使い方|全関数の一覧と用途別コード例まとめ」で扱っています。
くじ引きのシミュレーション
確率の答えを乱数で確かめるときは、random の sample で「戻さずに引く」を再現できます。
import random
random.seed(211)
kuji = ['当1', '当2', '外1', '外2', '外3']
N = 1_000_000
ca = cb = 0
for _ in range(N):
x = random.sample(kuji, 2) # A が x[0]、B が x[1] を引く
ca += x[0].startswith('当')
cb += x[1].startswith('当')
print(f'A {ca/N:.4f} B {cb/N:.4f}')
100万回で約1秒でした(くじとコインのシミュレーション2つを合わせて、実行時間 1.27秒)。random の関数の使い分けは、関連記事「Python randomの使い方一覧|randint・choice・shuffle」で扱っています。
場合の数が増える速さ(樹形図はどこまで書けるか)
この節では、人数が増えると樹形図の末端がどれくらいの速さで増えるかと、プログラムで数えるときの時間・メモリを実測した結果が分かります。
並び方(n!)は、人数が1人増えるたびに末端が「人数倍」になります。コインのような重複順列(2のn乗)は毎回2倍、2人を選ぶ組み合わせ(nC2)はゆっくり増えます。Python で n=1〜11 の並び方をすべて書き出し、かかった時間を測りました。
| n | 並び方 n! | コイン n回 2のn乗 | 2人を選ぶ nC2 | 全部書き出す時間 |
|---|---|---|---|---|
| 3 | 6 | 8 | 3 | 0.001ミリ秒 |
| 4 | 24 | 16 | 6 | 0.001ミリ秒 |
| 5 | 120 | 32 | 10 | 0.002ミリ秒 |
| 6 | 720 | 64 | 15 | 0.008ミリ秒 |
| 7 | 5,040 | 128 | 21 | 0.060ミリ秒 |
| 8 | 40,320 | 256 | 28 | 0.435ミリ秒 |
| 9 | 362,880 | 512 | 36 | 3.616ミリ秒 |
| 10 | 3,628,800 | 1,024 | 45 | 40.811ミリ秒 |
| 11 | 39,916,800 | 2,048 | 55 | 487.781ミリ秒 |
時間は、collections.deque(permutations(range(n)), maxlen=0) で結果を捨てながら最後まで回したときの値です。n が1増えると時間もほぼ n 倍になり、10人で約0.04秒、11人で約0.5秒でした。
メモリにも差が出ます。結果を list() で全部ためると、tracemalloc で測ったピークは次のとおりでした。
数を数えるだけなら、list にためずに for で1つずつ回すと、メモリはほとんど使いません。数だけが要るなら math.perm・math.factorial で計算するのがいちばん速い方法です。
紙の樹形図で考えると、3人で末端6、4人で24、5人で120です。手で書いて確実に数えられるのは末端30前後までで、それを超えたら「1本分だけ書いて掛け算」か公式に切り替えます。数学の関数をまとめて知りたいときは、関連記事「Python mathモジュールの使い方|切り上げ・切り捨て・平方根と関数一覧」で扱っています。
Mermaidで樹形図を描く(幅を抑える書き方)
この節では、Markdown や Web ページで使える Mermaid で樹形図を描く書き方と、同じ名前のノードが合流してしまう落とし穴が分かります。
Mermaid では flowchart を使い、方向を LR(左から右)にし、ノードの名前(ID)を道ごとに別にします。表示する文字は角かっこの中に書きます。コインを2回投げる樹形図なら、次のとおりです。
flowchart LR
S((開始))
S --> N1[表]
N1 --> N2[表]
N1 --> N3[裏]
S --> N4[裏]
N4 --> N5[表]
N4 --> N6[裏]
コインを3回投げる樹形図を Mermaid で描くと、次のようになります。
flowchart LR
S((開始))
S --> N1[表]
N1 --> N2[表]
N2 --> N3[表]
N2 --> N4[裏]
N1 --> N5[裏]
N5 --> N6[表]
N5 --> N7[裏]
S --> N8[裏]
N8 --> N9[表]
N9 --> N10[表]
N9 --> N11[裏]
N8 --> N12[裏]
N12 --> N13[表]
N12 --> N14[裏]
同じ名前を使うと枝が合流する(実測)
次のように「表」「裏」をそのままノードの名前にすると、エラーは出ずに描画されますが、樹形図になりません。
flowchart LR
開始 --> 表
開始 --> 裏
表 --> 表
表 --> 裏
裏 --> 表
裏 --> 裏
mermaid-cli で SVG にして中のノードを数えると、正しい書き方(N1〜N6)では7個、この書き方では3個しかありませんでした。「表 --> 表」は同じノードへ戻る線になり、枝が合流した図になります。Mermaid では、同じ名前は同じノードとして扱われるためです。
| 書き方 | 終了コード | ノードの数 | 線の数 | 見た目 |
|---|---|---|---|---|
| 道ごとに別の名前(N1〜N6) | 0 | 7 | 6 | 正しい樹形図 |
| 「表」「裏」をそのまま名前に | 0 | 3 | 6 | 枝が合流し、自分に戻る線ができる |
図の大きさの実測
樹形図の大きさは末端の数で決まります。自作のスクリプトで Mermaid の文を作り、SVG の幅・高さを測りました。
| 樹形図 | 末端 | 幅×高さ(px) | 描画時間 |
|---|---|---|---|
| コイン2回 | 4 | 315×382 | - |
| 3人の並び方 | 6 | 428×590 | - |
| コイン3回 | 8 | 441×798 | 1.38秒 |
| 4人の並び方 | 24 | 549×2,462 | - |
| 5人の並び方 | 120 | 671×12,446 | 2.96秒 |
4人の並び方(末端24)で高さが約2,500px になり、画面1枚に収まらなくなりました。Mermaid で載せるのは末端10前後までにし、それより大きいものは「A から始まる部分だけ」を描くのが見やすい方法です。描画時間の多くは、mermaid-cli がブラウザを起動する時間です。
Mermaid の文字に丸かっこなどの記号を入れるときは、ダブルクォートで囲みます(よくある間違いの節にエラー原文を載せています)。Mermaid のほかの図の書き方は、関連記事「Mermaid記法一覧|全図種のコピペ用コードと描画結果まとめ」で扱っています。
Graphvizで樹形図を描く(PNG・SVGで保存する)
この節では、Graphviz の dot で樹形図を描き、画像として保存する方法と、Mermaid との違いが分かります。
Graphviz は、DOT 言語で書いた図を dot コマンドで PNG・SVG・PDF などに変換するツールです。樹形図では digraph(向きのある図)と -> を使い、rankdir=LR で左から右に描きます。Mermaid と同じく、ノードの名前は道ごとに別にし、表示する文字は label に書きます。
digraph T {
rankdir=LR;
node [shape=box, fontname="Noto Sans CJK JP"];
S [label="開始", shape=circle];
N1 [label="表"]; S -> N1;
N2 [label="表"]; N1 -> N2;
N3 [label="表"]; N2 -> N3;
N4 [label="裏"]; N2 -> N4;
N5 [label="裏"]; N1 -> N5;
N6 [label="表"]; N5 -> N6;
N7 [label="裏"]; N5 -> N7;
N8 [label="裏"]; S -> N8;
N9 [label="表"]; N8 -> N9;
N10 [label="表"]; N9 -> N10;
N11 [label="裏"]; N9 -> N11;
N12 [label="裏"]; N8 -> N12;
N13 [label="表"]; N12 -> N13;
N14 [label="裏"]; N12 -> N14;
}
dot -Tpng coin3.dot -o coin3.png
dot -Tsvg coin3.dot -o coin3.svg
この例では、開始の丸から2本、そこから2本ずつ、さらに2本ずつ枝が出て、右端に8個の末端が縦に並ぶ PNG(449×563px・29,411バイト)ができました。日本語は、fontname にパソコンに入っている日本語フォントの名前を指定すると表示されます。
Graphviz と Mermaid の実測比較
| 樹形図 | Graphviz(LR)の大きさ | Mermaid(LR)の大きさ | Graphviz の描画時間 |
|---|---|---|---|
| 3人の並び方(末端6) | 336×314 | 428×590 | - |
| コイン3回(末端8) | 336×422 | 441×798 | 0.02秒 |
| 4人の並び方(末端24) | 426×1,286 | 549×2,462 | - |
| 5人の並び方(末端120) | 516×6,470 | 671×12,446 | 0.06秒 |
大きさは SVG の viewBox の値(単位は Graphviz がポイント、Mermaid が px)です。同じ樹形図で、Graphviz の方が縦横ともに小さく、描画も速く終わりました。5人の並び方(ノード326個・線325本)でも 0.06秒です。
方向を変えると大きさが大きく変わります。4人の並び方を rankdir=TB(上から下)にすると 1,718×354 になり、LR の 426×1,286 より横に約4倍広がりました。末端は縦に並べた方が、ページの幅に収まります。
1Mermaid が向く場面
Markdown や Web ページ・Wiki にそのまま書いて表示したいとき。末端10前後までの小さな樹形図。
2Graphviz が向く場面
PNG・SVG・PDF の画像として保存し、資料や教材に貼りたいとき。末端が多い樹形図を小さく描きたいとき。
3どちらも共通
ノードの名前は道ごとに別にする。文の作成はプログラム(itertools)に任せると、書き間違いがない。
樹形図のよくある間違い・エラーと直し方
この節では、紙の樹形図で起きやすい間違いと、Python・Mermaid・Graphviz で出るエラーの原文と直し方が分かります。
紙の樹形図の間違い
| 症状 | 原因 | 直し方 |
|---|---|---|
| 数えるたびに答えが変わる | 枝を書く順番の決まりが無い | アルファベット順・小さい順に固定する |
| 組み合わせが順列の2倍になる | AB と BA を両方書いている | 2段目以降は前の文字より後ろだけを書く |
| 確率が 1/7 のような半端な値になる | 同じに見える物を区別していない | 赤1・赤2、大・小のように名前を付けて区別する |
| 同じものを含む並べ方が多すぎる | 1段目に同じ文字を2回書いている | 同じ文字は1段に1回だけ書く |
| 3けたの整数が多すぎる | 百の位に 0 を書いている | 1段目に書けないものを先に確かめる |
| 紙からはみ出す | 末端が30を超えている | 1本分だけ書いて掛け算する。公式に切り替える |
Python のつまずき
permutations の結果をそのまま print すると、中身ではなく次の表示になります。
<itertools.permutations object at 0x7f2357cb8720>
itertools の関数は、結果を1つずつ取り出す「イテレーター」を返すためです。中身を見るときは list() で包むか、for で回します。一度最後まで回したイテレーターは空になるので、2回使うときは list にしておきます。ただし、前の節のとおり10人の並び方を list にすると 466.3MB を使いました。
Mermaid のエラー
ノードの文字に丸かっこを入れると、次のエラーで描画が止まりました(mermaid-cli 11.16.0 の出力。後ろのスタックトレースは略)。
Error: Parse error on line 2:
...art LR S --> A[表(1回目)]
----------------------^
Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'
丸かっこは Mermaid では「丸い形のノード」の記号です。文字をダブルクォートで囲んで A["表(1回目)"] と書くと、終了コード 0 で描画できました。Mermaid 公式ドキュメントにも、扱いにくい文字は引用符で囲む方法が書かれています。
Graphviz のエラー
dot で出たエラーの原文です(いずれも終了コード 1)。
Error: e1.dot: syntax error in line 4 near '}'
Warning: syntax ambiguity - badly delimited number '1�' in line 3 of e2.dot splits into two tokens
Error: e2.dot: syntax error in line 3 near '回目'
Error: e3.dot: syntax error in line 1 near '--'
| エラー | 原因 | 直し方 |
|---|---|---|
| syntax error near '}' | N1 -> の先が書かれていない | 線の先のノード名を書く |
| syntax error near '回目' | label の中にダブルクォートをそのまま入れた | 中の引用符は \" と書く |
| syntax error near '--' | digraph の中で -- を使った | digraph は ->、graph は -- |
| 日本語が四角や記号になる | 指定したフォントが入っていない | fc-list で確かめた名前を fontname に書く |
Graphviz 公式ドキュメントには、digraph では ->、graph では -- を使うこと、引用符の中でエスケープできるのはダブルクォートだけであることが書かれています。
- 1名前を付けて区別した同じ色の玉・同じ形のさいころも、1つずつ別の名前にする
- 2書く順番の決まりを全部の段で守ったアルファベット順・小さい順など、1つに決める
- 3順列か組み合わせかを決めた入れ替えて結果が変わるなら順列、変わらないなら組み合わせ
- 4掛け算の見積もりと末端の数が合った合わなければ、書き漏れか重複がある
- 5図にするならノードの名前は道ごとに別にしたMermaid・Graphviz とも、同じ名前は1つのノードになる
樹形図のよくある質問
この節では、樹形図について検索されることの多い疑問に、短く答えます。
Q. 樹形図の読み方と英語は?
「じゅけいず」と読みます。英語では tree diagram です。
Q. 樹形図と樹状図は同じですか?
算数・数学で場合の数を数える図は「樹形図」と呼ぶのが一般的です。統計で似たもの同士をまとめていく図は「樹状図(デンドログラム)」と呼ばれ、目的が違います。形はどちらも枝分かれです。
Q. 樹形図は何年生で習いますか?
学校の算数・数学で、場合の数や確率を学ぶときに使います。学年や教科書での扱いは、学校の教科書で確かめるのが確実です。
Q. 樹形図と表はどちらを使えばよいですか?
さいころ2個のような「2つのものの組」は表、3段以上や順番が大事な問題は樹形図が向きます。迷ったら、末端の数を掛け算で見積もり、30を超えるなら公式も考えます。
Q. 順列と組み合わせの見分け方は?
選んだものを入れ替えたときに結果が変わるかで見分けます。代表と副代表、走る順番、整数の並びは順列、代表を2人選ぶ、当番を選ぶのは組み合わせです。
Q. 組み合わせの樹形図はどう書きますか?
2段目以降に、前の段の文字よりアルファベットで後ろの文字だけを書きます。A の後ろは B・C・D、B の後ろは C・D、という形です。
Q. 樹形図が大きくなりすぎて書けません。
最初の枝1本分(A から始まる部分)だけを書き、同じ形が何組あるかを掛けます。4人の並び方なら、A から始まる6通り × 4 = 24通りです。
Q. くじ引きは先に引いた方が有利ですか?
有利ではありません。5本中2本当たりのくじで、樹形図の20通りを全部数えると、先に引く人も後に引く人も当たる確率は 2/5 でした。100万回のシミュレーションでも 0.3994 と 0.4007 でした。
Q. 樹形図をパソコンで描くには?
Web ページや Markdown なら Mermaid の flowchart LR、画像として保存するなら Graphviz の dot が使えます。どちらもノードの名前を道ごとに別にするのがこつです。
Q. プログラムで樹形図の答えを確かめるには?
Python の itertools の permutations・combinations・product で全部を書き出し、len で数えます。数だけなら math.perm・math.comb で計算できます。
まとめ
この節では、樹形図の要点を5つにまとめます。
- 樹形図は、起こりうる場合を枝分かれで全部書き出す図で、根から末端までの道1本が1通り、末端の数が場合の数です。
- 名前を付ける・順番の決まりを守る・段の観点をそろえるの3つで、書き漏れと重複を防げます。
- 枝の減り方で数え方が分かります。順列は1本ずつ減り、組み合わせは前の文字より後ろだけ、重複順列は減りません。
- 確率は「当てはまる末端 ÷ 末端の総数」。物を区別して数えないと、さいころの和7が 1/7 のように誤った値になります。
- 末端30前後を超えたら、1本分+掛け算、公式、プログラムに切り替えます。図にするなら Mermaid・Graphviz とも LR で、ノード名は道ごとに別にします。
参考・出典
この節では、この記事で確かめた公式ドキュメントを示します(確認日 2026年10月29日)。
- Python 公式ドキュメント「itertools — 効率的なループ実行のためのイテレータ生成関数」:https://docs.python.org/ja/3/library/itertools.html
- Python 公式ドキュメント「math — 数学関数」(comb・perm は 3.8 で追加):https://docs.python.org/ja/3/library/math.html
- Python 公式ドキュメント「fractions — 有理数」:https://docs.python.org/ja/3/library/fractions.html
- Python 公式ドキュメント「random — 擬似乱数を生成する」:https://docs.python.org/ja/3/library/random.html
- Mermaid 公式ドキュメント「Flowcharts - Basic Syntax」:https://mermaid.js.org/syntax/flowchart.html
- Graphviz 公式ドキュメント「The DOT Language」:https://graphviz.org/doc/info/lang.html
- scikit-learn 公式ドキュメント「Decision Trees」:https://scikit-learn.org/stable/modules/tree.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「樹形図とは?書き方と順列・組み合わせ・確率をPythonで検算」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。