You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python代码故障排查、优化及Matplotlib绘图改进求助

Phi近似程序问题排查、性能优化与绘图改进

问题描述

合并两个Phi值近似程序后,运行15分钟无输出,终止后报错。需排查代码问题、优化性能并改进Matplotlib绘图方案。

问题排查

1. 函数重复定义

代码中approximate_phi_progression被定义两次,第一次函数逻辑混乱且存在严重性能问题,第二次是正确的蒙特卡洛近似逻辑,但第一次定义会导致Method2的计算完全错误。

2. 递归函数栈溢出与计算量爆炸

第一次定义的函数中,onephi是递归函数,elif onephi() == 1会触发无限递归,极易导致栈溢出;同时嵌套循环层级过多:

  • 外层100次trial循环
  • 每个trial调用approximate_phi_progression,内部循环10000次point
  • 每次point内又循环100次trial,每个trial再循环10000次调用onephi
    总计算量达10^12次操作,完全无法在合理时间内完成。

3. 变量作用域错误

第一次定义approximate_phi_progression时,提前使用了未赋值的num_trials和num_points_per_trial,会触发NameError。

4. 数据结构错误

Method2的phi_progression每次将整个phi_approximation列表追加进去,导致最终数据是多层嵌套列表,后续绘图时维度不匹配。

性能优化

1. 重构Method2逻辑,移除无效递归

将onephi改为非递归实现,避免栈溢出(原递归逻辑等价于生成符合黄金分割概率的0/1值,可直接推导公式简化):

def onephi():
    true_phi_inv = (math.sqrt(5)-1)/2  # 黄金分割倒数≈0.618
    return 1 if random.random() < true_phi_inv else 0

2. 简化嵌套循环,减少计算量

重新梳理Method2的计算流程,避免不必要的嵌套:

def approximate_phi_method2(num_trials_per_run, runs_per_trial):
    phi_progression = []
    for _ in range(num_trials_per_run):
        c = sum(onephi() for _ in range(runs_per_trial))
        phi = runs_per_trial / c if c != 0 else math.nan  # 避免除以0
        phi_progression.append(phi)
    return phi_progression

# 生成Method2数据
method2_progressions = [approximate_phi_method2(num_trials, num_points_per_trial) for _ in range(num_trials)]

3. 使用numpy向量化加速

将循环替换为numpy数组操作,大幅提升计算速度:

import numpy as np

def approximate_phi_method2_numpy(num_trials_per_run, runs_per_trial):
    phi_progression = []
    true_phi_inv = (np.sqrt(5)-1)/2
    for _ in range(num_trials_per_run):
        rand_vals = np.random.rand(runs_per_trial)
        c = np.sum(rand_vals < true_phi_inv)
        phi = runs_per_trial / c if c !=0 else np.nan
        phi_progression.append(phi)
    return phi_progression

4. 提前初始化变量与列表

避免在循环内重复定义函数、初始化列表,减少内存开销与动态扩容耗时。

Matplotlib绘图优化

1. 简化图例,避免重复标签

只在第一次绘制某类曲线时添加标签,后续绘制时省略:

plt.figure(figsize=(12, 6))

# 绘制Method1曲线
for idx, trial_progression in enumerate(method1_progressions):
    x = np.arange(num_trials, num_points_per_trial+1, num_trials)
    plt.plot(x, trial_progression, alpha=0.3, color="red", label='Method 1' if idx==0 else "")

# 绘制Method2曲线
for idx, trial_progression in enumerate(method2_progressions):
    x = np.arange(1, num_trials+1)
    plt.plot(x, trial_progression, alpha=0.3, color="blue", label='Method 2' if idx==0 else "")

2. 添加真实Phi值参考线

让近似效果对比更直观:

true_phi = (1 + np.sqrt(5))/2
plt.axhline(y=true_phi, color='green', linestyle='--', label='True Phi')

3. 绘制统计趋势线

用均值±标准差展示整体近似效果,避免100条线过于杂乱:

# Method1统计量
method1_mean = np.mean(method1_progressions, axis=0)
method1_std = np.std(method1_progressions, axis=0)
x1 = np.arange(num_trials, num_points_per_trial+1, num_trials)
plt.plot(x1, method1_mean, color='darkred', linewidth=2, label='Method 1 Mean')
plt.fill_between(x1, method1_mean-method1_std, method1_mean+method1_std, color='red', alpha=0.1)

# Method2统计量
method2_mean = np.mean(method2_progressions, axis=0)
method2_std = np.std(method2_progressions, axis=0)
x2 = np.arange(1, num_trials+1)
plt.plot(x2, method2_mean, color='darkblue', linewidth=2, label='Method 2 Mean')
plt.fill_between(x2, method2_mean-method2_std, method2_mean+method2_std, color='blue', alpha=0.1)

4. 优化图表样式

plt.title('Phi Value Approximation Comparison', fontsize=14)
plt.xlabel('Number of Trials/Points', fontsize=12)
plt.ylabel('Approximated Phi', fontsize=12)
plt.legend(loc='upper right')
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()

完整优化后代码

import random
import math
import numpy as np
import matplotlib.pyplot as plt

# Method1:基于圆的蒙特卡洛近似
def approximate_phi_progression(num_points, track_interval=100):
    inside_circle = 0
    phi_progression = []
    for point in range(1, num_points + 1):
        x = random.uniform(0, 1)
        y = random.uniform(0, 1)
        if x**2 + y**2 <= 1:
            inside_circle += 1
        if point % track_interval == 0:
            phi_squared_approximation = (5/6) * (4 * inside_circle / point)
            phi_approximation = math.sqrt(phi_squared_approximation)
            phi_progression.append(phi_approximation)
    return phi_progression

# Method2:基于黄金分割概率的向量化实现
def approximate_phi_method2_numpy(num_trials_per_run, runs_per_trial):
    phi_progression = []
    true_phi_inv = (np.sqrt(5)-1)/2  # 黄金分割倒数≈0.618
    for _ in range(num_trials_per_run):
        rand_vals = np.random.rand(runs_per_trial)
        c = np.sum(rand_vals < true_phi_inv)
        phi = runs_per_trial / c if c !=0 else np.nan
        phi_progression.append(phi)
    return phi_progression

# 参数设置
num_trials = 100
num_points_per_trial = 10000

# 生成数据
method1_progressions = [approximate_phi_progression(num_points_per_trial) for _ in range(num_trials)]
method2_progressions = [approximate_phi_method2_numpy(num_trials, num_points_per_trial) for _ in range(num_trials)]

# 绘图
plt.figure(figsize=(12, 6))
true_phi = (1 + np.sqrt(5))/2

# Method1统计趋势
x1 = np.arange(num_trials, num_points_per_trial+1, num_trials)
method1_mean = np.mean(method1_progressions, axis=0)
method1_std = np.std(method1_progressions, axis=0)
plt.plot(x1, method1_mean, color='darkred', linewidth=2, label='Method 1 Mean')
plt.fill_between(x1, method1_mean-method1_std, method1_mean+method1_std, color='red', alpha=0.1)

# Method2统计趋势
x2 = np.arange(1, num_trials+1)
method2_mean = np.mean(method2_progressions, axis=0)
method2_std = np.std(method2_progressions, axis=0)
plt.plot(x2, method2_mean, color='darkblue', linewidth=2, label='Method 2 Mean')
plt.fill_between(x2, method2_mean-method2_std, method2_mean+method2_std, color='blue', alpha=0.1)

# 添加真实Phi参考线
plt.axhline(y=true_phi, color='green', linestyle='--', label='True Phi')

# 图表样式设置
plt.title('Phi Value Approximation Comparison', fontsize=14)
plt.xlabel('Number of Trials/Points', fontsize=12)
plt.ylabel('Approximated Phi', fontsize=12)
plt.legend(loc='upper right')
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()

内容的提问来源于stack exchange,提问作者user23380519

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 07:35:59