好友
阅读权限10
听众
最后登录1970-1-1
|
本帖最后由 LuLuWuWei1120 于 2026-8-19 11:27 编辑
---
📝 说明
本模型的理论基础来源附件中文章《人类两性博弈》,由《自私的基因》中内容进一步建模,目的为:使研究对象由普遍两性生物博弈转向人类博弈。
《人类两性博弈》文章为本人与ai探讨后ai的总结化表述,我希望任何人都可以阅读一下其中的无建模部分(即非对男女各种策略推导的部分),有利于理解男女双方观念及根源,并且在恋爱关系中减少自身损失。另外,本人非专业人士,无相关经验,无法给出关于男女双方的的任何建设性结论。有错误或不准确的之处是可能的,请理性思考,明辨是非,批判吸收。
模拟内容并不考虑任何情感因素,请勿盲目代入现实,将本文作为纯粹的智慧生物利益博弈即可(情感因素难以抽象化,人各有情)。
模拟程序为ai独立实现(本人目前并无时间写代码)。
亲密关系策略演化博弈模型
一个基于个体演化博弈论的计算机模拟框架,用于研究亲密关系中忠诚、薄情、变化型、欺骗型策略在群体中的动态演化。本项目完全复现了《人类两性博弈》中描述的概念,并可用于探索不同初始条件、收益参数下的社会演化路径。
📖 项目简介
本模拟程序构建了一个离散世代、随机配对、适应度驱动的演化环境。每个个体携带以下属性:
· 性别(男/女)
· 策略(Lc, Lk, U, V, D)
· 生育期望(S 或 N)
个体在每一代中随机配对,依据双方策略和期望发生资源转移、生育、检查与欺骗识别,累积适应度。随后按适应度比例选择父母,产生下一代,并允许突变。
该模型旨在从生物投资不对称和进化恐惧出发,分析信任、欺骗、忠诚、躺平等社会现象背后的博弈论根源。
🧠 理论背景
模型基于以下核心理论假设(详见理论文档):
· 亲代投资不对称:女性是高投入锁定者(卵子稀缺、妊娠、哺乳),男性是低投入即走者。
· 女性进化恐惧(被弃恐惧):女性担心生育后失去男性支持,故倾向于筛选长期投资承诺。
· 男性进化恐惧(被欺恐惧):男性担心抚养非亲生后代,故倾向于筛选亲子确定性。
· 人类演化两大突变:隐蔽排卵 + 隐性发情,迫使人类走向配对绑定,使忠贞成为交易筹码。
· 现代环境颠覆:女性经济独立和避孕技术使“资源换忠贞”协议失效,催生多元化策略。
🎯 策略集合
策略代号 名称 说明
Lc 随意型忠诚 默认信任,零验证成本,适合高信任环境
Lk 检查型忠诚 忠诚但附加验证程序(体检、孕检、财务透明),防御欺骗
U 薄情 低投入、短期存在,拒绝长期绑定
V 变化型 根据对方展示策略动态切换(遇L则L,遇U则U)
D 欺骗型 伪装为L以骗取对方核心投资,事后撤离
生育期望:
· S(期望有子):以基因传递为终极目标,愿接受验证。
· N(期望无子):以生存舒适度为终极目标,排斥长期绑定与生育成本。
⚙️ 核心参数
运行时可自定义的参数包括:
参数 含义 默认值
POP_SIZE 种群总大小(男女各半) 2000
NUM_GENERATIONS 演化代数 200
MUTATION_RATE 策略/期望突变概率 0.01
V_GENE 每个后代的基因收益 10.0
C_FEMALE_BIRTH 女性生育成本 5.0
I_M_L 男性忠诚投入(资源转移) 3.0
I_M_D 男性欺骗伪装成本 1.0
S_M 忠诚男性的额外抚养支持 2.0
C_K 检查型忠诚的验证成本 2.0
初始策略分布 五类策略在男/女中的初始概率 均匀(各20%)
S/N 初始比例 男/女期望生育的比例 各50%
🚀 运行方式
环境要求
· Python
· 无需额外第三方库(仅使用标准库 random, csv, math, sys, collections)
快速启动
python simulation.py
程序启动后,您将看到交互式菜单:
========== 亲密关系策略演化模型(高性能版) ==========
请选择运行模式:
1. 自定义配置
2. 默认配置(200代,均匀初始)
3. 完全随机(500~2000代,所有参数随机)
· 选项1:逐步输入种群大小、代数、突变率、收益参数、初始策略概率、S/N比例。
· 选项2:使用预设默认值快速运行。
· 选项3:一键运行,所有参数(包括收益参数)均在合理范围内随机生成,代数范围500~2000,适合探索性实验。
输出
模拟结束后,当前目录下会生成 simulation_results.csv,包含每代的统计信息:
· generation:代数
· avg_fitness:种群平均适应度
· S_ratio:总体S期望比例
· male_ratio, female_ratio:实际性别比例(自然演化)
· M_LC, M_LK, M_U, M_V, M_D:男性各策略频率
· F_LC, F_LK, F_U, F_V, F_D:女性各策略频率
📊 结果解读与理论验证
典型演化模式(示例)
模式一:完整循环(“完美循环”)
当初始条件中欺骗型(D)形成有效集群时,系统会依次经历:
- D扩张 → 2. Lk防御崛起 → 3. U“躺平”替代 → 4. Lc回归重建信任。
此模式完整复现了理论中的四大循环。
模式二:U主导稳态(“低信任均衡”)
若初始D比例不足或Lc较早被U替代,系统可能锁定在U占主导的状态,Lc和Lk均无法大规模复兴,D也因失去寄生宿主而长期低迷。这是路径依赖的典型案例。
模式三:其他路径
因随机种子、初始参数不同,还可能观察到双欺骗共振、S/N潮汐、长周期振荡等。
所有结果均由群体选择压力自然涌现,无任何预设脚本干预。
🔬 模型逻辑要点
· 收益计算:完全依据理论设定,包括资源转移、生育成本、检查成本、基因收益等。
· 欺骗与检查:Lk能识破D(无论性别),一旦识破则无生育,双方承担各自成本。
· V策略响应:V根据对方展示的策略切换行为(遇L则L,遇U则U),但自身期望不影响行为。
· 性别比例演化:下一代性别随机决定,不强制男女等量,允许性别比例受选择压力漂移。
· 适应度选择:采用指数权重轮盘赌,避免负适应度问题。
纯代码部分:
[Python] 纯文本查看 复制代码 #!/usr/bin/env python3
"""
亲密关系策略演化博弈模型(高性能版)
策略编码:0=Lc, 1=Lk, 2=U, 3=V, 4=D
期望编码:0=S, 1=N
随机模式:种群500~4000,代数500~2000,其他参数在合理区间随机
"""
import random
import csv
import math
import sys
from collections import defaultdict
# ==================== 常量编码 ====================
LC, LK, U, V, D = 0, 1, 2, 3, 4
S_EXP, N_EXP = 0, 1
# ==================== 默认参数 ====================
DEFAULT_POP_SIZE = 2000
DEFAULT_NUM_GENERATIONS = 200
DEFAULT_MUTATION_RATE = 0.01
DEFAULT_V_GENE = 10.0
DEFAULT_C_FEMALE_BIRTH = 5.0
DEFAULT_I_M_L = 3.0
DEFAULT_I_M_D = 1.0
DEFAULT_S_M = 2.0
DEFAULT_C_K = 2.0
DEFAULT_MALE_STRAT_PROBS = [0.2, 0.2, 0.2, 0.2, 0.2]
DEFAULT_FEMALE_STRAT_PROBS = [0.2, 0.2, 0.2, 0.2, 0.2]
DEFAULT_MALE_S_PROB = 0.5
DEFAULT_FEMALE_S_PROB = 0.5
# ==================== 个体类 ====================
class Individual:
__slots__ = ('gender', 'strategy', 'expect', 'fitness')
def __init__(self, gender, strategy, expect):
self.gender = gender # 0=男性, 1=女性
self.strategy = strategy # 0~4
self.expect = expect # 0=S, 1=N
self.fitness = 0.0
# ==================== 核心演化函数 ====================
def evolve_generation(pop, gen, params):
v_gene = params['V_gene']
c_female = params['C_female_birth']
i_m_l = params['I_m_L']
i_m_d = params['I_m_D']
s_m = params['S_m']
c_k = params['C_k']
mu = params['mutation_rate']
n = len(pop)
target_size = n
half = n // 2
shuffled = pop[:]
random.shuffle(shuffled)
pairs = [(shuffled[i], shuffled[i+half]) for i in range(half)]
for a, b in pairs:
if a.gender == 0 and b.gender == 1:
m, f = a, b
elif a.gender == 1 and b.gender == 0:
m, f = b, a
else:
continue
f_show = LC if f.strategy == D else f.strategy
if m.strategy == V:
m_behavior = LC if (f_show == LC or f_show == LK) else U
elif m.strategy == LC or m.strategy == LK:
m_behavior = LC
elif m.strategy == D:
m_behavior = D
else:
m_behavior = U
if m_behavior == LC:
I_m = i_m_l
elif m_behavior == D:
I_m = i_m_d
else:
I_m = 0.0
S_m_actual = s_m if (m_behavior == LC and m.expect == S_EXP and f.expect == S_EXP) else 0.0
if (m.strategy == LK and f.strategy == D) or (f.strategy == LK and m.strategy == D):
m_fit = -I_m - (c_k if m.strategy == LK else 0.0)
f_fit = I_m - (c_k if f.strategy == LK else 0.0)
m.fitness += m_fit
f.fitness += f_fit
continue
offspring = (m.expect == S_EXP and f.expect == S_EXP)
m_gene = v_gene if offspring and not (f.strategy == D and f.expect == S_EXP) else 0.0
f_gene = v_gene if offspring else 0.0
m_fit = m_gene - I_m - S_m_actual - (c_k if m.strategy == LK else 0.0)
f_fit = f_gene + I_m + S_m_actual - (c_female if offspring else 0.0) - (c_k if f.strategy == LK else 0.0)
m.fitness += m_fit
f.fitness += f_fit
# ---- 统计 ----
stats = {
'generation': gen,
'avg_fitness': 0.0,
'S_ratio': 0.0,
'male_ratio': 0.0,
'female_ratio': 0.0,
'M_LC': 0.0, 'M_LK': 0.0, 'M_U': 0.0, 'M_V': 0.0, 'M_D': 0.0,
'F_LC': 0.0, 'F_LK': 0.0, 'F_U': 0.0, 'F_V': 0.0, 'F_D': 0.0,
}
count = {'M': [0]*5, 'F': [0]*5}
s_count = 0
fit_sum = 0.0
male_count = 0
for ind in pop:
if ind.gender == 0:
male_count += 1
count['M'][ind.strategy] += 1
else:
count['F'][ind.strategy] += 1
if ind.expect == S_EXP:
s_count += 1
fit_sum += ind.fitness
stats['avg_fitness'] = fit_sum / n
stats['S_ratio'] = s_count / n
stats['male_ratio'] = male_count / n
stats['female_ratio'] = 1 - stats['male_ratio']
for g in ['M', 'F']:
for i, s_name in enumerate(['LC', 'LK', 'U', 'V', 'D']):
stats[f'{g}_{s_name}'] = count[g][i] / n
# ---- 选择繁殖 ----
weights = [math.exp(max(-10, min(10, ind.fitness))) for ind in pop]
total_w = sum(weights)
if total_w == 0:
probs = [1.0 / n] * n
else:
probs = [w / total_w for w in weights]
parent_indices = random.choices(range(n), weights=probs, k=2 * target_size)
new_pop = []
strat_pool = [LC, LK, U, V, D]
for i in range(0, 2 * target_size, 2):
idx1 = parent_indices[i]
idx2 = parent_indices[i+1]
if idx1 == idx2:
idx2 = random.randrange(n)
p1 = pop[idx1]
p2 = pop[idx2]
if random.random() < 0.5:
strat = p1.strategy
else:
strat = p2.strategy
if random.random() < 0.5:
expect = p1.expect
else:
expect = p2.expect
gender = 0 if random.random() < 0.5 else 1
if gender == 0 and strat == D:
expect = S_EXP
if random.random() < mu:
strat = random.choice(strat_pool)
if gender == 0 and strat == D:
expect = S_EXP
if random.random() < mu:
expect = N_EXP if expect == S_EXP else S_EXP
if gender == 0 and strat == D:
expect = S_EXP
child = Individual(gender, strat, expect)
child.fitness = 0.0
new_pop.append(child)
return new_pop, stats
# ==================== 种群生成 ====================
def generate_population(size, male_strat_probs, female_strat_probs, male_s_prob, female_s_prob):
pop = []
num_males = size // 2
num_females = size - num_males
for _ in range(num_males):
strat = random.choices([LC, LK, U, V, D], weights=male_strat_probs, k=1)[0]
expect = S_EXP if random.random() < male_s_prob else N_EXP
if strat == D:
expect = S_EXP
pop.append(Individual(0, strat, expect))
for _ in range(num_females):
strat = random.choices([LC, LK, U, V, D], weights=female_strat_probs, k=1)[0]
expect = S_EXP if random.random() < female_s_prob else N_EXP
pop.append(Individual(1, strat, expect))
random.shuffle(pop)
return pop
def generate_random_population(size):
pop = []
num_males = size // 2
num_females = size - num_males
for _ in range(num_males):
strat = random.choice([LC, LK, U, V, D])
expect = S_EXP if random.random() < 0.5 else N_EXP
if strat == D:
expect = S_EXP
pop.append(Individual(0, strat, expect))
for _ in range(num_females):
strat = random.choice([LC, LK, U, V, D])
expect = S_EXP if random.random() < 0.5 else N_EXP
pop.append(Individual(1, strat, expect))
random.shuffle(pop)
return pop
# ==================== 模拟主循环 ====================
def run_simulation(params):
pop_size = params['pop_size']
num_gens = params['num_generations']
random_init = params.get('random_init', False)
if random_init:
pop = generate_random_population(pop_size)
print("使用完全随机初始种群")
else:
pop = generate_population(
pop_size,
params['male_strat_probs'],
params['female_strat_probs'],
params['male_s_prob'],
params['female_s_prob']
)
records = []
print("进度:", end='', flush=True)
for gen in range(num_gens):
pop, stats = evolve_generation(pop, gen, params)
records.append(stats)
if gen % 20 == 0:
print(f"\nGen {gen}: avg_f={stats['avg_fitness']:.3f}, S={stats['S_ratio']:.3f}, M_ratio={stats['male_ratio']:.3f}")
else:
print('.', end='', flush=True)
print("\n模拟完成。")
return records
def save_records(records, filename="simulation_results.csv"):
if not records:
return
fieldnames = list(records[0].keys())
with open(filename, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for rec in records:
writer.writerow(rec)
print(f"Results saved to {filename}")
# ==================== 交互配置 ====================
def get_float(prompt, default):
while True:
try:
val = input(f"{prompt} (default {default}): ")
if val.strip() == '':
return default
return float(val)
except ValueError:
print("请输入数字")
def get_int(prompt, default):
while True:
try:
val = input(f"{prompt} (default {default}): ")
if val.strip() == '':
return default
return int(val)
except ValueError:
print("请输入整数")
def get_prob_list(prompt, default, length=5):
print(f"{prompt} (输入5个空格分隔的概率,总和为1,默认: {' '.join(map(str, default))})")
while True:
line = input().strip()
if line == '':
return default[:]
parts = line.split()
if len(parts) != length:
print(f"需要输入{length}个数字")
continue
try:
probs = [float(p) for p in parts]
if abs(sum(probs) - 1.0) > 0.001:
print("概率之和不等于1,请重新输入")
continue
return probs
except ValueError:
print("请输入有效数字")
def random_param(min_val, max_val, is_int=False):
if is_int:
return random.randint(int(min_val), int(max_val))
else:
return random.uniform(min_val, max_val)
def generate_random_params():
pop_size = random_param(500, 4000, True)
if pop_size % 2 != 0:
pop_size += 1
return {
'pop_size': pop_size,
'num_generations': random_param(500, 2000, True), # 改为500~2000代
'mutation_rate': random_param(0.003, 0.03),
'V_gene': random_param(5, 15),
'C_female_birth': random_param(2, 8),
'I_m_L': random_param(1, 5),
'I_m_D': random_param(0.3, 2),
'S_m': random_param(0.5, 4),
'C_k': random_param(0.5, 3),
'random_init': True,
}
def interactive_config():
print("========== 亲密关系策略演化模型(高性能版) ==========")
print("请选择运行模式:")
print("1. 自定义配置")
print("2. 默认配置(200代)")
print("3. 完全随机(500~2000代)")
choice = input("输入 1, 2 或 3: ").strip()
if choice == '3':
params = generate_random_params()
print("\n随机生成的参数:")
for k, v in params.items():
if k != 'random_init':
print(f" {k}: {v:.3f}" if isinstance(v, float) else f" {k}: {v}")
return params
elif choice == '2':
return {
'pop_size': DEFAULT_POP_SIZE,
'num_generations': DEFAULT_NUM_GENERATIONS,
'mutation_rate': DEFAULT_MUTATION_RATE,
'V_gene': DEFAULT_V_GENE,
'C_female_birth': DEFAULT_C_FEMALE_BIRTH,
'I_m_L': DEFAULT_I_M_L,
'I_m_D': DEFAULT_I_M_D,
'S_m': DEFAULT_S_M,
'C_k': DEFAULT_C_K,
'male_strat_probs': DEFAULT_MALE_STRAT_PROBS[:],
'female_strat_probs': DEFAULT_FEMALE_STRAT_PROBS[:],
'male_s_prob': DEFAULT_MALE_S_PROB,
'female_s_prob': DEFAULT_FEMALE_S_PROB,
'random_init': False,
}
else:
print("\n--- 基本参数 ---")
pop_size = get_int("种群总大小", DEFAULT_POP_SIZE)
if pop_size % 2 != 0:
pop_size += 1
print(f"调整为偶数: {pop_size}")
num_gens = get_int("演化代数", DEFAULT_NUM_GENERATIONS)
mu = get_float("突变率", DEFAULT_MUTATION_RATE)
print("\n--- 收益参数 ---")
V = get_float("后代基因价值 V", DEFAULT_V_GENE)
Cfb = get_float("女性生育成本 C_f", DEFAULT_C_FEMALE_BIRTH)
I_L = get_float("男性忠诚投入 I_m_L", DEFAULT_I_M_L)
I_D = get_float("男性欺骗伪装成本 I_m_D", DEFAULT_I_M_D)
S = get_float("男性忠诚抚养支持 S_m", DEFAULT_S_M)
Ck = get_float("检查成本 C_k", DEFAULT_C_K)
print("\n--- 初始策略分布 ---")
print("男性策略概率 [Lc, Lk, U, V, D]:")
male_probs = get_prob_list("", DEFAULT_MALE_STRAT_PROBS)
print("女性策略概率 [Lc, Lk, U, V, D]:")
female_probs = get_prob_list("", DEFAULT_FEMALE_STRAT_PROBS)
male_s = get_float("男性中 S 期望比例", DEFAULT_MALE_S_PROB)
female_s = get_float("女性中 S 期望比例", DEFAULT_FEMALE_S_PROB)
return {
'pop_size': pop_size,
'num_generations': num_gens,
'mutation_rate': mu,
'V_gene': V,
'C_female_birth': Cfb,
'I_m_L': I_L,
'I_m_D': I_D,
'S_m': S,
'C_k': Ck,
'male_strat_probs': male_probs,
'female_strat_probs': female_probs,
'male_s_prob': male_s,
'female_s_prob': female_s,
'random_init': False,
}
def main():
params = interactive_config()
print("\n开始模拟...")
records = run_simulation(params)
save_records(records, "simulation_results.csv")
print("模拟完成。结果已保存至 simulation_results.csv")
if __name__ == "__main__":
main()
此模拟对初始条件较为敏感,几次模拟的结果可能完全不同,但往往也符合理论推理。有兴趣的话,可自行写脚本,进行上百次千代级的模拟,将理论文件和日志csv文件丢给ai,可能可以从从统计学意义上得到社会两性问题上,总体的趋势吧。
附件:
https://wwbdi.lanzouu.com/irCIf42hnypg
|
免费评分
-
查看全部评分
|