はじめに
こんにちは。Juna1013です。
唐突ですが、みなさんは恋愛リアリティーショー(以下:恋リア)はお好きですか?恋リアは昨今注目を集めるネット番組をなっています。今回はそんな人気の恋リアをオートマンとして数理モデル化してシミュレーションしていこうと思います。
みなさん恋リアはお好きですか?
そもそも恋リアって何だろう?という方も多いと思います。恋リアとは恋愛リアリティ番組の略で、若い男女が集まって恋愛をする様子を追いかけるネット番組のことです。出演者たちは特定の家やリゾート地など、恋愛が発生しやすい環境で共同生活をしたり、デートやゲームなどのイベントに参加したりします。番組の進行は基本的に「誰が誰に恋をするか」や「カップルが成立するか」に沿って行われ、時には告白やカップル成立、脱落といった出来事もあります。視聴者は出演者の表情や心の声を通して恋の駆け引きや感情の変化を楽しみ、お気に入りの人物を応援することが多いです。
日本で代表的なものを挙げると、「今日、好きになりました。(以下:今日好き)」が最も人気で、10代後半の高校生や大学生が参加して恋愛模様を追う番組です。他には「テラスハウス」があり、これは20代前後の男女がシェアハウスで共同生活をしながら恋愛や人間関係を描くスタイルで、長年にわたって話題になりました。「あいのり」も有名で、複数の男女がバスで旅をしながら恋愛を進める形式です。最近ではSNSや配信プラットフォーム向けに制作された短期集中型の恋リアも増えており、若い世代に特に人気があります。
1. 恋リアの理論化
それでは、恋リアを数理モデル化していきましょう。
1.1 登場人物を「記号」とみなす
まず、出演者一人一人を**記号(symbol)**として扱います。例えば出演者が$A, B, C, D$の4人なら、システムに入力される文字と同じ扱いをします。このとき、登場人物の行動や意思決定の対象は「他の記号」に対応します。
- 記号集合:$Σ={A,B,C,D}$
- 各記号は自律的に選択(誰を好きになるか、告白するかなど)を行う
- 記号間の関係が状態遷移の条件になる
1.2 告白や選択行動を「状態遷移」として扱う
次に、恋愛行動(誰にアプローチするか、告白するかなど)を**状態遷移(state transition)**と考えます。ここで状態とは「各出演者が誰に対して恋愛感情を持っているか」の情報です。
- 状態集合 $S$ は「各出演者の現在の関心対象」を表す
- 遷移確率 $P(s_t+1∣s_t,a_t)$ は、ある時点の状態$s_t$と行動$a_t$に基づき次の状態$s_t+1$になる確率
- 例: $A$ が $B$ に告白する確率 $p$ によって、カップル成立の可能性が変化する
このモデルでは、行動は決定論ではなく確率的であり、同じ状況でも結果が変わることがあります。
1.3 カップル成立/ 不成立を「符号化された出力」とする
最後に、番組として視聴者に見える結果、つまりカップルが成立したかどうかを出力とみなします。これは情報理論でいう**符号化された出力(coded output)**です。
- 出力集合:$𝑂={成立,不成立}$
- 出力は状態に依存し、確率的に決定される
- 視聴者はこの出力を見て「誰が誰と結ばれるか」という情報を受け取る
1.4 確率的有限オートマン(PFA)としてのモデル化
上記をまとめると、恋リアは確率的有限オートマトン (Probabilistic Finite Automaton, PFA) として表現できます。
- 状態 S:出演者の恋愛状況の組み合わせ
- 入力記号 Σ:各出演者
- 出力 O:カップル成立 / 不成立
- 遷移確率 $P(s_t+1∣s_t,σ)$:告白や選択行動による状態変化の確率
このモデルの面白い点は、視聴者に見える結果は確率的であり、内部状態は隠されているという点です。つまり、恋リアは「隠れマルコフモデル(HMM)」的な性質も持っており、番組の編集や演出によって観測される情報(出力)が変化するということになります。
情報理論の視点
- エントロピー
- 「誰が誰を選ぶのか」の不確実性をエントロピーで定量化できる
- 例)異性5人の中から1人を選ぶ → 一様分布なら$H=log_25$ビット
- 符号化
- 各選択(Aさん → Bさん)を符号として扱う
- ハフマン符号や算術記号を使えば「人気の偏り」を圧縮できる
- 通信モデルとしての恋愛
- 「好意」 = 送信メッセージ
- 「相手が応答」 = デコード
- 片思い = 誤り(error)
- カップル成立 = 正しくデコード
モデル化の例
- 状態集合:{片思い, 相思相愛, フラれる, 保留}
- 遷移確率:各人の好意分析に基づき、次の状態へ移る
- 終了条件:ペアリングが確定したらそのシーズン終了
実装のためのモデリング
登場人物の定義
- 名前
- 好みの確率分布(誰を選ぶかの確率)
- 状態(フリー、ペア成立など)
シミュレーションのステップ
- 全員が「告白先」を選ぶ(確率分布からサンプリング)
- 各告白の結果を判定(相思相愛か、片思いか)
- エントロピー計算で「混純度」を数値化
- 状態を更新し、次のラウンドへ
シミュレーション例
import random
import math
from collections import Counter
# 参加者の定義
class Person:
def __init__(self, name, preferences):
"""
name: str
preferences: dict {相手名: 確率}
"""
self.name = name
self.preferences = preferences
self.choice = None
self.partner = None
def choose(self):
# 確率分布に従って告白先を選ぶ
names = list(self.oreferences.keys())
probs = list(self.preferences.values())
self.choice = random.choices(names, weights=probs, k=1)[0]
return self.choice
# 情報理論の関数
def entropy(distribution):
# 分布のエントロピー計算
H = 0
for p in distribution.values():
if p > 0:
H -= p * math.log2(p)
return H
# シミュレーション本体
def simulate_round(people):
# 1. 全員が選ぶ
choices = {}
for p in people:
target = p.choose()
choices[p.name] = target
# 2. 結果判定
couples = []
for p in people:
target = choices[p.name]
# 相思相愛かどうか
if choices.get(target) == p.name and p.name < target:
# 名前の順で重複回避
couples.append((p.name, target))
# 3. エントロピー計算
dist = Counter(choices.values())
total = sum(dist.values())
distribution = {k: v/total for k,v in dist.items()}
H = entropy(distribution)
return choices, couples, H
# 実行例
prople = [
Person("A", {"B": 0.6, "C": 0.4}),
Person("B", {"A": 0.3, "C": 0.7}),
Person("C", {"A": 0.5, "B": 0.5})
]
for round in range(5):
choices, couples, H = simulate_round(prople)
print(f"Round {round+1}")
print("Choices:", choices)
print("Couples:", couples)
print(f"Entropy: {H:.3f} bits")
print("-" * 30)
順を追って解説していきます。
1. ライブラリ
import random
import math
from collections import Counter
-
random
:確率に従って告白先をランダムに選ぶために使用。random.choices
を使う -
math
:対数(log2)を使ってエントロピーを計算するために使用。 -
Counter
:誰が誰に告白したかの分布:誰が誰に告白したかの分布(ヒストグラム)を数えるために使用。
2. Personクラス(参加者の定義)
class Person:
def __init__(self, name, preferences):
self.name = name
self.preferences = preferences
self.choice = None
self.partner = None
-
name
:参加者の名前(例:"A")。 -
preferences
:誰に告白するかの確率分布(辞書)。例:{"B": 0.6, "C": 0.4}
→ Bに60%, Cに40%の確率で告白。 -
choice
:そのラウンドで実際に選んだ相手。 -
partner
:成功したカップルの相手(現時点では未使用だが、拡張可能)。
def choose(self):
names = list(self.preferences.keys())
probs = list(self.preferences.values())
self.choice = random.choices(names, weights=probs, k=1)[0]
return self.choice
-
random.choices
で確率分布preferences
に従って告白先を決める。 -
k=1
なので、必ず1人を選ぶ。
3. 情報理論:エントロピー計算
def entropy(distribution):
H = 0
for p in distribution.values():
if p > 0:
H -= p * math.log2(p)
return H
-
エントロピーH:以下のように定義される
$$H = -i \sum p_i \log_2 p_i$$ -
distribution
は告白先の分布(例:{"A":0.33, "B":0.67})。 -
値が大きいほど「選択がバラけている=不確実性が高い」。
-
値が小さいほど「選択が集中している=予測しやすい」。
4. シミュレーション本体
def simulate_round(people):
# 1. 全員が選ぶ
choices = {}
for p in people:
target = p.choose()
choices[p.name] = target
- 各参加者が確率的に告白先を選ぶ。
-
choices
には{告白者: 告白相手}
が入る。
# 2. 結果判定
couples = []
for p in people:
target = choices[p.name]
if choices.get(target) == p.name and p.name < target:
couples.append((p.name, target))
- 相思相愛の条件:
- pがtargetを選び、かつ targetもpを選んでいる。
-
p.name < target
で文字列順に並べ、同じペアを重複して追加しないようにする。
# 3. エントロピー計算
dist = Counter(choices.values())
total = sum(dist.values())
distribution = {k: v/total for k,v in dist.items()}
H = entropy(distribution)
- 誰が人気だったかの分布を Counter で集計。
- 正規化して確率分布に変換。
-
entropy
で「告白の不確実性」を計算。
5. 実行例
people = [
Person("A", {"B": 0.6, "C": 0.4}),
Person("B", {"A": 0.3, "C": 0.7}),
Person("C", {"A": 0.5, "B": 0.5})
]
- Aは「Bに行く確率60%、Cに40%」
- Bは「Aに30%、Cに70%」
- Cは「Aに50%、Bに50%」
for round in range(5):
choices, couples, H = simulate_round(people)
print(f"Round {round+1}")
print("Choices:", choices)
print("Couples:", couples)
print(f"Entropy: {H:.3f} bits")
print("-" * 30)
- 5ラウンド繰り返し、毎回の告白状況とカップル成立状況、そして情報理論的な「選択の不確実性 H」を表示。
結果から得られる推測
エントロピーが高いと選択がばらけており、展開が読めないことを示唆します。また、エントロピーが低いと人気が集中していて結果が予測可能な王道展開になります。加えて、相思相愛率を計算することで、番組の盛り上がりを定量化することができます。
おわりに
今回は恋リアのざっくりとした全体の流れだけを抑えてモデル化してみました。次はパラメータをもっと増やしてできるだけ実際の恋リアに近づけていけたらなと思います。