【问题标题】:Why is this Python script with Matplotlib so slow?为什么这个带有 Matplotlib 的 Python 脚本这么慢?
【发布时间】:2018-07-29 09:10:11
【问题描述】:

我正在尝试模拟抛硬币和利润并在 matplotlib 中绘制图表:

from random import choice
import matplotlib.pyplot as plt
import time

start_time = time.time()
num_of_graphs = 2000
tries = 2000
coins = [150, -100]
last_loss = 0


for a in range(num_of_graphs):
    profit = 0
    line = []
    for i in range(tries):
        profit = profit + choice(coins)
        if (profit < 0 and last_loss < i):
            last_loss = i
        line.append(profit)
    plt.plot(line)
plt.show()

print("--- %s seconds ---" % (time.time() - start_time))
print("No losses after " + str(last_loss) + " iterations")

最终结果是

--- 9.30498194695 seconds ---
No losses after 310 iterations

为什么运行这个脚本需要这么长时间?如果我将 num_of_graphs 更改为 10000,脚本永远不会完成。

你会如何优化它?

【问题讨论】:

  • 可能会有更好的答案,但我会做的第一件事是因为你知道line 会有多大,那就是使用 numpy 并预先分配你的数组。 line = np.zeros((2000,)) 在任一循环外,然后是 line[i] = profit 在第二个循环内。分配一次,然后继续重写。

标签: python performance matplotlib


【解决方案1】:

您对执行时间的衡量过于粗略。以下允许您测量模拟所需的时间,与绘图所需的时间分开:

它正在使用 numpy。

import matplotlib.pyplot as plt
import numpy as np
import time


def run_sims(num_sims, num_flips):
    start = time.time()
    sims = [np.random.choice(coins, num_flips).cumsum() for _ in range(num_sims)]
    end = time.time()
    print(f"sim time = {end-start}")
    return sims


def plot_sims(sims):
    start = time.time()
    for line in sims:
        plt.plot(line)
    end = time.time()
    print(f"plotting time = {end-start}")
    plt.show()


if __name__ == '__main__':

    start_time = time.time()
    num_sims = 2000
    num_flips = 2000
    coins = np.array([150, -100])

    plot_sims(run_sims(num_sims, num_flips))

结果:

sim time = 0.13962197303771973
plotting time = 6.621474981307983

如您所见,sim 时间大大减少(在我 2011 年的笔记本电脑上大约为 7 秒);绘图时间取决于 matplotlib。

【讨论】:

    【解决方案2】:

    matplotlib 随着脚本的进展越来越慢,因为它是 重新绘制您之前绘制的所有线条 - 甚至是 那些已经滚出屏幕的。

    这是之前由 Simon Gibbons 回答的 post 的答案。

    matplotlib 并未针对速度进行优化,而是针对其图形进行了优化。以下是一些为提高速度而开发的链接:

    有关性能的更多信息,您可以参考matplotlib cookbook

    【讨论】:

      【解决方案3】:

      为了更好地优化您的代码,我总是会尝试使用 numpy 或根据我的具体需要使用其他在后台使用 numpy 的库通过矢量化来替换循环。

      在这种情况下,您可以这样计算和绘制您的利润:

      import matplotlib.pyplot as plt
      import time
      import numpy as np
      
      start_time = time.time()
      num_of_graphs = 2000
      tries = 2000
      coins = [150, -100]
      
      # Create a 2-D array with random choices
      # rows for tries, columns for individual runs (graphs).
      coin_tosses = np.random.choice(coins, (tries, num_of_graphs))
      
      # Caculate 2-D array of profits by summing 
      # cumulatively over rows (trials).
      profits = coin_tosses.cumsum(axis=0)
      
      # Plot everything in one shot.
      plt.plot(profits)
      plt.show()
      
      print("--- %s seconds ---" % (time.time() - start_time))
      

      在我的配置中,这段代码占用了 aprox。运行 6.3 秒(6.2 绘图),而您的代码花了将近 15 秒。

      【讨论】:

        猜你喜欢
        • 2018-10-08
        • 2012-02-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-13
        • 2011-03-11
        • 1970-01-01
        相关资源
        最近更新 更多