
こんにちは、monachan_papaです。
今回は私の推しのちんどん屋さんについての検証をPythonでしてみたいと思います。
何をするかというと、、、、

ちんどん屋さんの出動メンバ組合せ
ちんどん屋さんはたいてい3人だったり、4人だったりのチームで街頭宣伝や賑やかしをするのが古くからのスタイルであり、スタンダードです。
私の推しのちんどん屋さんも同じく、このスタイルをとっています。
そして、推しのちんどん屋さんは、何と!
総勢10名のメンバ(ただし、メインのゴールデンメンバは7名)を擁しておられます。つまり、この中から数名選抜し出動するというわけなんです。
この選抜メンバが誰かな?!というのが、毎回楽しみであります!
今日、ふと思ったことがあります。
- 選抜メンバの組合せ総数はどれだけだろう?
- 今までどんな組合せで何通り見てきたのだろうか?
- まだ見たことのない組合せは?
このマニアックで素敵すぎる疑問を解決するために、私は立ち上がった!
さて、解決のための前提条件、検証方法を以下に挙げます。
- 今まで見てきた組合せはすべて記憶しているし、データとしても持っている。
- メインのゴールデンメンバ7名から3名を選抜する組み合わせを本検証とする。
以下のように進みます。では、いってみましょう!
組合せとは?
組合せといったら、高校数学に出てくる順列、組合せが真っ先に出てくるかと思います。
まずは、簡単に定義をはっきりさせましょう。下表に示します。
順列 | 組合せ |
---|---|
nPk | nCk |
異なるn個からk個選び並べる | 異なるn個からk個選び並べる |
順番を考慮する! | 順番は関係ねぇ! |
懐かしい人もいるでしょうね。
組合せで最重要なのは順番は関係ねぇ!ということです。
例えば、A、B、C、Dから3つ選ぶとき、ABC、ACB、BAC、BCA、CAB、CBAは同じということです。
組合せの算出方法
さあ、やっとこさ、Pythonの出番です!
組合せ算出にとても便利なライブラリがあるんです。
itertoolsモジュールというのものが標準で入っていて、この中のcombinations関数を使えば、楽勝で片付けることができるのです。
とりあえず、importしましょう!
import itertools
怒られなかったら、うまくいっているハズです!
itertools.combinations関数について
関数の説明をします。
itertools.combinaitons(引数1, 引数2)
- 引数1: リストなどのイテレータを指定
- 引数2: 選択する要素数
めちゃくちゃ簡単です!
ではそっそく、引数1のイテレータを準備しましょう。
ゴールデンメンバの7名、ついに来た!!
names = 'うっしー 駒子 ワッキー マーサ スージー 公乃 すずこ'.split()
names
▼出力結果
['うっしー', '駒子', 'ワッキー', 'マーサ', 'スージー', '公乃', 'すずこ']
しっかり、7名いらっしゃいました!
この中から3名選抜するわけなので、引数2は3となります。
組合せ総数と全通りの表示
ガンガンいきますぜ!組合せ総数と、出動メンバの全通りを表示します。

関数の戻り値は、リスト型に変換するのがポイントです!
com = list(itertools.combinations(names, 3))
print(f'組合せ総数: {len(com)}通り')
com
▼出力結果
組合せ総数: 35通り
[('うっしー', '駒子', 'ワッキー'),
('うっしー', '駒子', 'マーサ'),
('うっしー', '駒子', 'スージー'),
('うっしー', '駒子', '公乃'),
('うっしー', '駒子', 'すずこ'),
('うっしー', 'ワッキー', 'マーサ'),
('うっしー', 'ワッキー', 'スージー'),
('うっしー', 'ワッキー', '公乃'),
('うっしー', 'ワッキー', 'すずこ'),
('うっしー', 'マーサ', 'スージー'),
('うっしー', 'マーサ', '公乃'),
('うっしー', 'マーサ', 'すずこ'),
('うっしー', 'スージー', '公乃'),
('うっしー', 'スージー', 'すずこ'),
('うっしー', '公乃', 'すずこ'),
('駒子', 'ワッキー', 'マーサ'),
('駒子', 'ワッキー', 'スージー'),
('駒子', 'ワッキー', '公乃'),
('駒子', 'ワッキー', 'すずこ'),
('駒子', 'マーサ', 'スージー'),
('駒子', 'マーサ', '公乃'),
('駒子', 'マーサ', 'すずこ'),
('駒子', 'スージー', '公乃'),
('駒子', 'スージー', 'すずこ'),
('駒子', '公乃', 'すずこ'),
('ワッキー', 'マーサ', 'スージー'),
('ワッキー', 'マーサ', '公乃'),
('ワッキー', 'マーサ', 'すずこ'),
('ワッキー', 'スージー', '公乃'),
('ワッキー', 'スージー', 'すずこ'),
('ワッキー', '公乃', 'すずこ'),
('マーサ', 'スージー', '公乃'),
('マーサ', 'スージー', 'すずこ'),
('マーサ', '公乃', 'すずこ'),
('スージー', '公乃', 'すずこ')]
35通り。
この数字は世の中が良くなれば実際、一年間で現実的に部隊編成可能な数字だと思います。 ちんどん屋さんのスケジュールとか諸々の調整がもし、うまくいったら不可能ではない数字です。
また、各メンバは35回のうち、15回出動すれば実現可能なことが分かります。
そして、私も最終的にすべての選抜メンバ組合せ、いつかコンプリートできるかと思うと夢が膨らみます!
余談ですが、もしこれがフルメンバ10名から3名選抜となると、不可能な数字なんです。
120通りになるんですよ!さすがに無理でしょう。
見果てぬ夢、「組合せの差分」をとって現実に近づけろ!
では、最後の検証です!見果てぬ夢は、分析しまくるしかない。
私はあとどれだけの選抜メンバに遭遇していないのか?まず、それを知らねばなるまい。
以下、ゴールデンメンバ7人から3人選抜した場合限定の私が出会った記録のデータです。
4人選抜時とか入れたらコンプリートに近づきますが、小生も男です!
男らしく対象外とします!すべて3人選抜時限定です!
exp = [
['マーサ', 'スージー', 'すずこ'],
['ワッキー', '公乃', 'すずこ'],
['駒子', 'ワッキー', 'すずこ'],
['うっしー', 'スージー', 'すずこ'],
['うっしー', '駒子', 'スージー'],
['駒子', 'マーサ', '公乃'],
['駒子', '公乃', 'すずこ'],
['駒子', 'スージー', 'すずこ'],
['うっしー', '駒子', 'マーサ'],
['うっしー', '駒子', 'スージー'],
['うっしー', 'ワッキー', '公乃'],
['駒子', 'ワッキー', 'スージー'],
]
print(f'私が遭遇した3人選抜一覧数: {len(exp)}')
▼出力結果
私が遭遇した3人選抜一覧数: 12
さて、私がまだ遭遇していない選抜メンバは、単純に 35-12=23 というわけにはいきません。
総組合せから、私のデータを引くことに変わりはありません。しかし、まずは、、、

データの正規化をしないといけません!
そして、解を導き出すために、集合演算の差集合を利用する。そのための正規化をします。
まずは私が遭遇した3人選抜一覧。差集合をとるためには、いくつか問題点があります。
以下のように対応すれば実現ができます!
- リストの中の各リストの要素を昇順ソートする(正しく差分がとれないため)
- リストの中の各リストをタプル化する(タプル化しないと、集合型にできないため)
- set関数で集合型に変換(重複項目が現在あるが、このとき排除できる)
では、一気に片付けましょう!
exp_ = [tuple(sorted(e)) for e in exp]
exp_ = set(exp_)
print(f'私が遭遇した3人選抜一覧数: {len(exp_)}')
exp_
▼出力結果
私が遭遇した3人選抜一覧数: 11
{('うっしー', 'すずこ', 'スージー'),
('うっしー', 'スージー', '駒子'),
('うっしー', 'マーサ', '駒子'),
('うっしー', 'ワッキー', '公乃'),
('すずこ', 'スージー', 'マーサ'),
('すずこ', 'スージー', '駒子'),
('すずこ', 'ワッキー', '公乃'),
('すずこ', 'ワッキー', '駒子'),
('すずこ', '公乃', '駒子'),
('スージー', 'ワッキー', '駒子'),
('マーサ', '公乃', '駒子')}
重複項目が1項目ありましたね。同じ組合せで遭遇したことがあったということはラッキーですが、ここでは正しく分析するためにグッと我慢します!
型変換もうまくいきました。
つづいて、同様に一番初めに用意した総組合せの方も正規化をします。
正規化はたった1行でいきます!内包表記はとても便利ですね。
ここでのポイントは、、、、

ソートをかけることにより、もともとタプルだったものがリスト化されてしまうで、またタプルに戻してあげましょう!
com_ = {tuple(sorted(c)) for c in com}
print(f'組合せ総数: {len(com)}通り')
com_
組合せ総数: 35通り
{('うっしー', 'すずこ', 'スージー'),
('うっしー', 'すずこ', 'マーサ'),
('うっしー', 'すずこ', 'ワッキー'),
('うっしー', 'すずこ', '公乃'),
('うっしー', 'すずこ', '駒子'),
('うっしー', 'スージー', 'マーサ'),
('うっしー', 'スージー', 'ワッキー'),
('うっしー', 'スージー', '公乃'),
('うっしー', 'スージー', '駒子'),
('うっしー', 'マーサ', 'ワッキー'),
('うっしー', 'マーサ', '公乃'),
('うっしー', 'マーサ', '駒子'),
('うっしー', 'ワッキー', '公乃'),
('うっしー', 'ワッキー', '駒子'),
('うっしー', '公乃', '駒子'),
('すずこ', 'スージー', 'マーサ'),
('すずこ', 'スージー', 'ワッキー'),
('すずこ', 'スージー', '公乃'),
('すずこ', 'スージー', '駒子'),
('すずこ', 'マーサ', 'ワッキー'),
('すずこ', 'マーサ', '公乃'),
('すずこ', 'マーサ', '駒子'),
('すずこ', 'ワッキー', '公乃'),
('すずこ', 'ワッキー', '駒子'),
('すずこ', '公乃', '駒子'),
('スージー', 'マーサ', 'ワッキー'),
('スージー', 'マーサ', '公乃'),
('スージー', 'マーサ', '駒子'),
('スージー', 'ワッキー', '公乃'),
('スージー', 'ワッキー', '駒子'),
('スージー', '公乃', '駒子'),
('マーサ', 'ワッキー', '公乃'),
('マーサ', 'ワッキー', '駒子'),
('マーサ', '公乃', '駒子'),
('ワッキー', '公乃', '駒子')}
さあ、準備がすべて整いました!
いけ〜!
ret = com_ - exp_
print(f'まだ遭遇していない組合せ数: {len(ret)}通り')
ret
▼出力結果
まだ遭遇していない組合せ数: 24通り
{('うっしー', 'すずこ', 'マーサ'),
('うっしー', 'すずこ', 'ワッキー'),
('うっしー', 'すずこ', '公乃'),
('うっしー', 'すずこ', '駒子'),
('うっしー', 'スージー', 'マーサ'),
('うっしー', 'スージー', 'ワッキー'),
('うっしー', 'スージー', '公乃'),
('うっしー', 'マーサ', 'ワッキー'),
('うっしー', 'マーサ', '公乃'),
('うっしー', 'ワッキー', '駒子'),
('うっしー', '公乃', '駒子'),
('すずこ', 'スージー', 'ワッキー'),
('すずこ', 'スージー', '公乃'),
('すずこ', 'マーサ', 'ワッキー'),
('すずこ', 'マーサ', '公乃'),
('すずこ', 'マーサ', '駒子'),
('スージー', 'マーサ', 'ワッキー'),
('スージー', 'マーサ', '公乃'),
('スージー', 'マーサ', '駒子'),
('スージー', 'ワッキー', '公乃'),
('スージー', '公乃', '駒子'),
('マーサ', 'ワッキー', '公乃'),
('マーサ', 'ワッキー', '駒子'),
('ワッキー', '公乃', '駒子')}
まだ見ぬ24通り。
うむ!まだまだ先は長いが、頑張ろう。
そして、ちんどん追っかけ歴も4年目に突入してきたので、色んなデータが蓄積されてきました。
こうやって、振り返ると感慨深いものがあるなあと思った、秋の夜。

コメント