【问题标题】:Difference in profiling results for numpy.loadtxtnumpy.loadtxt 的分析结果差异
【发布时间】:2013-03-09 03:52:52
【问题描述】:

我试图了解为什么在函数中和独立使用 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)和ipython中的%lrpun魔法:

>>> %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, 文件名): """ 生成大小为(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='')
    

【问题讨论】:

  • 实际上,我认为这是我传递给%timeit 的参数的问题。我错误地假设 -n 1 只会调用该函数一次,但 -n 用于在循环中执行 n 次。所以,我需要额外的参数-r 1 来重复 loop 一次。否则,%timeit 将返回 3 个调用中最好的一个,这意味着 3 个调用中的 2 个不必读取任何数据,因为文件是在第一次调用时读取的。因此,最快的迭代显然是 numpy.loadtxt 没有读取数据的迭代。
  • %timeit真实 时间应该是:每循环 32.4 毫秒,这更有意义。
  • 所以,正如我所料,我似乎回答了这个问题,但遗漏了一些明显的东西。我应该关闭它还是发布 cmets 作为答案?这种事情的标准是什么?
  • 只需添加您的解决方案作为答案(甚至还有一个徽章!)。

标签: python numpy


【解决方案1】:

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

  1. 注意%timeit 的参数:

    -n:循环执行给定语句的次数。如果这个值 没有给出,选择一个拟合值。

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

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

所以,我对%timeit 的调用有效地评估了对numpy.loadtxt 的调用3 次。第一次调用实际上会读取所有文件并占用总运行时间的大部分。接下来的两个调用将没有要读取的数据,因为传递给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 毫秒 vs 83 毫秒 更有意义。这些数字足够接近,我假设差异仅仅是因为我只运行了一次这种相对快速的操作。为了有效地比较这些,最好取一组运行的平均值。

【讨论】:

  • 很好的解释,顺便提了一个写得很好的问题!
猜你喜欢
  • 2016-02-20
  • 1970-01-01
  • 1970-01-01
  • 2016-05-16
  • 2014-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多