iPython: 为什么在 运行 with %%timeit 时 for 循环会抛出异常

iPython: why does for loop throw an exception when run with %%timeit

我正在尝试在 iPython 中进行一些分析,但我无法理解为什么下面的 for 循环在使用 %%timeit.

执行时会抛出异常

没有任何分析,循环工作正常。为什么循环在分析时抛出异常 and/or 如何修改循环使其不抛出异常?

In [1]: import numpy as np
   ...: import pandas as pd

In [2]: df = pd.DataFrame([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])

In [3]: df.columns = pd.MultiIndex.from_tuples(
   ...:     (("df1", "d"), ("df1", "g"), ("df2", "d"), ("df2", "g"))
   ...: )

In [4]: df
Out[4]: 
  df1     df2    
    d   g   d   g
0   1   2   3   4
1   5   6   7   8
2   9  10  11  12
3  13  14  15  16

In [5]: df1 = df.copy()

In [6]: for c in df.columns.levels[0]:
   ...:     d = df.stack().droplevel(0).loc["d", c]
   ...:     df[c, "lr"] = np.log(d.values / d.shift().values)
   ...: df = df.sort_index(axis=1)

In [7]: df
Out[7]: 
  df1               df2              
    d   g        lr   d   g        lr
0   1   2       NaN   3   4       NaN
1   5   6  1.609438   7   8  0.847298
2   9  10  0.587787  11  12  0.451985
3  13  14  0.367725  15  16  0.310155

In [8]: %%timeit
   ...: for c in df1.columns.levels[0]:
   ...:     d = df1.stack().droplevel(0).loc["d", c]
   ...:     df1[c, "lr"] = np.log(d.values / d.shift().values)
   ...: df1 = df1.sort_index(axis=1)

UnboundLocalError: local variable 'df1' referenced before assignment

我的会话中有一个数组:

In [80]: arr
Out[80]: 
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29])
In [81]: %%timeit
    ...: arr = arr.copy()
    ...: 
    ...: 
Traceback (most recent call last):
  File "<ipython-input-81-9a73362a3bde>", line 1, in <module>
    get_ipython().run_cell_magic('timeit', '', 'arr = arr.copy()\n\n')
  File "/usr/local/lib/python3.8/dist-packages/IPython/core/interactiveshell.py", line 2419, in run_cell_magic
    result = fn(*args, **kwargs)
  File "<decorator-gen-53>", line 2, in timeit
  File "/usr/local/lib/python3.8/dist-packages/IPython/core/magic.py", line 187, in <lambda>
    call = lambda f, *a, **k: f(*a, **k)
  File "/usr/local/lib/python3.8/dist-packages/IPython/core/magics/execution.py", line 1180, in timeit
    time_number = timer.timeit(number)
  File "/usr/local/lib/python3.8/dist-packages/IPython/core/magics/execution.py", line 169, in timeit
    timing = self.inner(it, self.timer)
  File "<magic-timeit>", line 1, in inner
UnboundLocalError: local variable 'arr' referenced before assignment

但分配给不同的名称是可以的:

In [82]: %%timeit
    ...: arr1 = arr.copy()
    ...: 
    ...: 
    ...: 

486 ns ± 14.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

我们在函数定义中遇到同样的错误:

In [84]: def foo():
    ...:     arr1 = arr.copy()
    ...: 
In [85]: foo()
In [86]: def foo():
    ...:     arr = arr.copy()
    ...: 
In [87]: 
In [87]: foo()
Traceback (most recent call last):
  File "<ipython-input-87-c19b6d9633cf>", line 1, in <module>
    foo()
  File "<ipython-input-86-f6fd187c7954>", line 2, in foo
    arr = arr.copy()
UnboundLocalError: local variable 'arr' referenced before assignment

timeit将代码包装在一个函数中,然后多次执行。