4

numpy.loadtxt関数内で使用する場合とスタンドアロンで使用する場合で、プロファイル/タイミングの数値が大きく異なる理由を理解しようとしています。

読み取り/プロファイルするデータの設定

  • 26 列 1000 行の 1 つのファイル。ファイル内の各項目はランダムな浮動小数点数です。
  • ファイルはスペースで区切られています
  • ファイルの 1 行目は、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 を使用して)プロファイルを作成%lrpunし、ipython で魔法を使用します。

>>> %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

コードを 1 回だけ実行する-n 1ように強制するように指定していたことに注意してください。ただし、これには十分ではありません。また、コードの評価が1 回だけ行われるように指定する必要があります。%timeitnumpy.loadtxt-n 1-r 1

したがって、への呼び出しは、への呼び出しを3 回%timeit効果的に評価していました。numpy.loadtxt最初の呼び出しは、実際にはすべてのファイルを読み取り、実行時間全体の大部分を占めます。に渡されたファイル ハンドルには読み取るデータがなかったので、次の 2 つの呼び出しには読み取るnumpy.loadtxtデータがありません。したがって、3 回の通話のうち 2 回は実際に行う作業がなく、ほとんど時間がかかりませんでした。

  1. %timeitから報告された時刻が何を意味するかに注意してください。

への呼び出しが%timeit出力の一部としてレポートする内容に注意してください。1 ループ、ベスト オブ 3 : ループあたり 30 us 私の 3 回の呼び出しのうち 2 回は効果的に機能しなかったため、これら 2 回の呼び出しのうちの 1 つが3 のうちのベストです

したがって、元の と の呼び出しを%timeit比較することで、空の/終了したファイル ハンドルを確認するのにかかる時間と、208k のデータ全体を実際に開いて読み取るのにかかる%lprun時間を効率的に比較できました。numpy.loadtxtnumpy.loadtxt

%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 ミリ秒はもう少し理にかなっています。これらの数値は十分に近いので、この比較的高速な操作を 1 回しか実行していないため、違いがあると推測しています。これらを効果的に比較するには、一連の実行の平均を取るのが最善です。

于 2013-03-08T17:01:10.933 に答える