4

面/頂点の特定のリストから最小、最大、平均を計算する必要があります。Numpy を使用してこのコンピューティングを最適化しようとしましたが、成功しませんでした。

これが私のテストケースです:

#!/usr/bin/python
# -*- coding: iso-8859-15 -*-
'''
Module Started 22 févr. 2013
@note: test case comparaison numpy vs python
@author: Python4D/damien
'''

import numpy as np
import time


def Fnumpy(vertices):
  np_vertices=np.array(vertices)
  _x=np_vertices[:,:,0]
  _y=np_vertices[:,:,1]
  _z=np_vertices[:,:,2]
  _min=[np.min(_x),np.min(_y),np.min(_z)]
  _max=[np.max(_x),np.max(_y),np.max(_z)]
  _mean=[np.mean(_x),np.mean(_y),np.mean(_z)]
  return _mean,_max,_min

def Fpython(vertices):
  list_x=[item[0] for sublist in vertices for item in sublist]
  list_y=[item[1] for sublist in vertices for item in sublist]
  list_z=[item[2] for sublist in vertices for item in sublist]
  taille=len(list_x)
  _mean=[sum(list_x)/taille,sum(list_y)/taille,sum(list_z)/taille]
  _max=[max(list_x),max(list_y),max(list_z)]
  _min=[min(list_x),min(list_y),min(list_z)]    
  return _mean,_max,_min

if __name__=="__main__":
  vertices=[[[1.1,2.2,3.3,4.4]]*4]*1000000
  _t=time.clock()
  print ">>NUMPY >>{} for {}s.".format(Fnumpy(vertices),time.clock()-_t)
  _t=time.clock()
  print ">>PYTHON>>{} for {}s.".format(Fpython(vertices),time.clock()-_t)

結果は次のとおりです。

でこぼこ:

([1.1000000000452519, 2.2000000000905038, 3.3000000001880174], [1.1000000000000001, 2.2000000000000002, 3.2999999999999998], [1.1000000000000001, 2.2000000000000002, 3.2999999999999998]) for 27.327068618s.

パイソン:

([1.100000000045252, 2.200000000090504, 3.3000000001880174], [1.1, 2.2, 3.3], [1.1, 2.2, 3.3]) 1.81366938593s.

Pure Python は Numpy よりも 15 倍高速です。

4

2 に答える 2

10

あなたが遅い理由は、メモリ内にnumpy配列を作成するという、Fnumpyによって実行されない追加のステップが含まれているためです。行を時間指定セクションの外にFpython移動すると、結果は大きく異なります。np_verticies=np.array(verticies)Fnumpy

>>NUMPY >>([1.1000000000452519, 2.2000000000905038, 3.3000000001880174], [1.1000000000000001, 2.2000000000000002, 3.2999999999999998], [1.1000000000000001, 2.2000000000000002, 3.2999999999999998]) for 0.500802s.
>>PYTHON>>([1.100000000045252, 2.200000000090504, 3.3000000001880174], [1.1, 2.2, 3.3], [1.1, 2.2, 3.3]) for 2.182239s.

作成時に numpy にデータ型のヒントを提供することで、割り当て手順を大幅に高速化することもできます。Numpy に float の配列があることを伝えると、np.array()呼び出しをタイミング ループに残したとしても、純粋な python バージョンよりも優先されます。

に変更np_vertices=np.array(vertices)してnp_vertices=np.array(vertices, dtype=np.float_)そのままにしておくと、Fnumpyさらに多くの作業を行う必要がありますが、Fnumpyバージョンは打ち負かされます。Fpython

>>NUMPY >>([1.1000000000452519, 2.2000000000905038, 3.3000000001880174], [1.1000000000000001, 2.2000000000000002, 3.2999999999999998], [1.1000000000000001, 2.2000000000000002, 3.2999999999999998]) for 1.586066s.
>>PYTHON>>([1.100000000045252, 2.200000000090504, 3.3000000001880174], [1.1, 2.2, 3.3], [1.1, 2.2, 3.3]) for 2.196787s.
于 2013-02-22T14:54:47.063 に答える
2

他の人がすでに指摘しているように、問題はリストから配列への変換です。そのための適切なnumpy関数を使用することで、Python を打ち負かすことができます。私はあなたのプログラムの主要部分を修正しました:

if __name__=="__main__":
  _t = time.clock()
  vertices_np = np.resize(np.array([ 1.1, 2.2, 3.3, 4.4 ], dtype=np.float64), 
                          (1000000, 4, 4))
  print "Creating numpy vertices: {}".format(time.clock() - _t)
  _t = time.clock()
  vertices=[[[1.1,2.2,3.3,4.4]]*4]*1000000
  print "Creating python vertices: {}".format(time.clock() - _t)
  _t=time.clock()
  print ">>NUMPY >>{} for {}s.".format(Fnumpy(vertices_np),time.clock()-_t)
  _t=time.clock()
  print ">>PYTHON>>{} for {}s.".format(Fpython(vertices),time.clock()-_t)

変更された主要部分でコードを実行すると、私のマシンでは次のようになります。

Creating numpy vertices: 0.6
Creating python vertices: 0.01
>>NUMPY >>([1.1000000000452519, 2.2000000000905038, 3.3000000001880174], 
[1.1000000000000001, 2.2000000000000002, 3.2999999999999998], [1.1000000000000001, 
2.2000000000000002, 3.2999999999999998]) for 0.5s.
>>PYTHON>>([1.100000000045252, 2.200000000090504, 3.3000000001880174], [1.1, 2.2, 3.3], 
[1.1, 2.2, 3.3]) for 1.91s.

配列の作成は、Numpy ツールを使用すると、Python のリスト乗算演算子 (0.6 秒対 0.01 秒) を使用してネストされたリストを作成するため、多少長くなりますが、約 1 倍の係数が得られます。4 は、コードの実行時関連部分です。行を置き換えると:

np_vertices=np.array(vertices)

np_vertices = np.asarray(vertices)

大きな配列のコピーを避けるために、私のマシンでは numpy 関数の実行時間は 0.37 秒にまで短縮され、純粋な Python バージョンよりも 5 倍以上速くなりました。

実際のコードでは、頂点の数が事前にわかっている場合は、 を介して適切な配列を事前に割り当ててからnp.empty()、適切なデータを入力して、numpy バ​​ージョンの関数に渡すことができます。

于 2013-02-23T09:19:17.870 に答える