4

我试图理解为什么numpy.loadtxt在函数中使用和独立使用时我会得到非常不同的分析/计时数字。

设置要读取/配置文件的数据

  • 1个26列1000行的文件,文件中的每一项都是随机浮点数
  • 文件是空格分隔的
  • 文件中的第一行是一个空格分隔的标题,有 26 个列名
  • 有关如何生成此数据的代码,请参见下文

单独分析 numpy.loadtxt

假设我有一个名为“test.out”的文件,具有上述属性:

>>> f = open('test.out', 'r');f.readline()
'a b c d e f g h i j k l m n o p q r s t u v w x y z\n'
>>> %timeit -n 1 np.loadtxt(f, unpack=True)
1 loops, best of 3: 30 us per loop

在函数内部分析 numpy.loadtxt

现在我想numpy.loadtxt分析一个函数内部(使用line_profiler)和%lrpunipython中的魔法:

>>> %lprun -f file_to_numpy_ordered_dict file_to_numpy_ordered_dict('test.out')
Timer unit: 1e-06 s

Function: file_to_numpy_ordered_dict at line 88
Total time: 0.085642 s

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    88                                           def file_to_numpy_ordered_dict(filename):
    89                                               """
    90                                               Read a space-separated-value file as a dict of columns, keyed by
    91                                               column header where each column (dict value) is a numpy array.
    92                                               """
    93                                           
    94         1          430    430.0      0.5      with open(filename, 'r') as file_obj:
    95         1          363    363.0      0.4          headers = file_obj.readline().split()
    96                                           
    97                                                   # unpack=True b/c want data organized as column based arrays, not rows
    98         1        84634  84634.0     98.8          arrs = np.loadtxt(file_obj, unpack=True)
    99                                           
   100         1           66     66.0      0.1      ret_dict = collections.OrderedDict()
   101        27           34      1.3      0.0      for ii, colname in enumerate(headers):
   102        26          114      4.4      0.1          ret_dict[colname] = arrs[ii]
   103                                           
   104         1            1      1.0      0.0      return ret_dict

为什么?

为什么单独调用 numpy.loadtxt 只需要 30us 而在这个函数中调用它大约需要 0.085 秒?我觉得我在这里遗漏了一些明显的东西,但看起来函数在每个场景中被调用的参数完全相同,等等。

这是因为我正在使用%timeit和而产生的一些奇怪的区别%lprun吗?也许由于某种原因无法比较这些数据?

随机数据创建的详细信息

  • 使用以下代码生成文件数据: def generate_test_data(column_names, row_count, filename): """ 生成大小为 (row_count, len(column_names)) 的随机测试数据文件

    column_names - List of column name strings to use as header row
    row_count - Number of rows of data to generate
    filename - Name of file to write test data to
    """
    
    col_count = len(column_names)
    rand_arr = np.random.rand(row_count, col_count)
    header_line = ' '.join(column_names)
    np.savetxt(filename, rand_arr, delimiter=' ', fmt='%1.5f',
                  header=header_line, comments='')
    
4

1 回答 1

3

仅供参考,这个问题的“答案”与我如何numpy.loadtxt进行分析有关,而不是在函数中对变慢或变快的实际调用。

  1. 请注意以下参数%timeit

    -n:循环执行给定语句的次数。如果未给出该值,则选择拟合值。

    -r:重复循环迭代次数并取最佳结果。默认值:3

请注意,我指定-n 1强制%timeit只运行numpy.loadtxt代码 1 次。然而,-n 1这还不够。您还必须指定-r 1强制代码的评估只发生一次

所以,我的电话%timeit有效地评估了numpy.loadtxt3 次电话。第一次调用实际上会读取所有文件并占用总运行时间的大部分。接下来的两个调用将没有数据要读取,因为传递给的文件句柄numpy.loadtxt没有数据要读取。因此,三分之二的电话没有任何实际工作要做,几乎不花时间

  1. 小心报告的时间是什么%timeit意思。

%timeit请注意作为其输出的一部分报告的调用,1 个循环,最好的 3:每个循环 30 us。由于我的三个电话中的两个有效地没有工作,这两个电话之一将是最好的 3

因此,通过比较我的原始调用%timeit%lprun我有效地比较了numpy.loadtxt查看空/已完成文件句柄所需的时间以及numpy.loadtxt真正打开和读取完整 208k 数据所需的时间。

当使用正确的论点%timeit更有意义时,真正的时间安排:

>>> f = open('test.out', 'r');f.readline()
'a b c d e f g h i j k l m n o p q r s t u v w x y z\n'
>>> %timeit -n 1 -r 1 np.loadtxt(f, unpack=True)
1 loops, best of 1: 31.1 ms per loop


Function: file_to_numpy_ordered_dict at line 88
Total time: 0.083706 s

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    88                                           def file_to_numpy_ordered_dict(filename):
    89                                               """
    90                                               Read a space-separated-value file as a dict of columns, keyed by
    91                                               column header where each column (dict value) is a numpy array.
    92                                               """
    93                                           
    94         1          583    583.0      0.7      with open(filename, 'r') as file_obj:
    95         1          313    313.0      0.4          headers = file_obj.readline().split()
    96                                           
    97                                                   # unpack=True b/c want data organized as column based arrays, not rows
    98         1        82417  82417.0     98.5          arrs = np.loadtxt(file_obj, unpack=True)
    99                                           
   100         1          226    226.0      0.3      ret_dict = collections.OrderedDict()
   101        27           35      1.3      0.0      for ii, colname in enumerate(headers):
   102        26          131      5.0      0.2          ret_dict[colname] = arrs[ii]
   103                                           
   104         1            1      1.0      0.0      return ret_dict

31 毫秒与 83 毫秒更有意义。这些数字足够接近,我假设差异仅仅是因为我只运行了一次这种相对快速的操作。为了有效地比较这些,最好取一堆运行的平均值。

于 2013-03-08T17:01:10.933 回答