0

私のコードを検討してください

a,b,c = np.loadtxt ('test.dat', dtype='double', unpack=True)

a、b、および c は同じ配列長です。

for i in range(len(a)):

   q[i] = 3*10**5*c[i]/100
   x[i] = q[i]*math.sin(a)*math.cos(b)
   y[i] = q[i]*math.sin(a)*math.sin(b)
   z[i] = q[i]*math.cos(a)

この方程式 (xi-xj)+(yi-yj)+(zi-zj) = r を反復するために、x、y、z の 2 点の差のすべての組み合わせを見つけようとしています。

この組み合わせコードを使用します

for combinations in it.combinations(x,2):
   xdist =  (combinations[0] - combinations[1])
for combinations in it.combinations(y,2):
   ydist =  (combinations[0] - combinations[1])
for combinations in it.combinations(z,2):
   zdist =  (combinations[0] - combinations[1])

r = (xdist + ydist +zdist) 

これは、私が持っている大きなファイルのpythonには長い時間がかかります。できればネストされたループを使用してrの配列を取得するより高速な方法があるかどうか疑問に思っていますか?

そのような

if i in range(?):
     if j in range(?):
4

3 に答える 3

3

どうやら numpy を使用しているようなので、実際に numpy を使用してみましょう。それははるかに高速になります。numpy を使用するときに python ループを完全に回避し、代わりにそのベクトル化された配列操作を使用すると、ほとんどの場合、高速になり、通常は読みやすくなります。

a, b, c = np.loadtxt('test.dat', dtype='double', unpack=True)

q = 3e5 * c / 100  # why not just 3e3 * c?
x = q * np.sin(a) * np.cos(b)
y = q * np.sin(a) * np.sin(b)
z = q * np.cos(a)

さて、この後のサンプル コードは、おそらくやりたいことを実行しませんxdist = ...。毎回の言い方に注意してください。その変数を上書きしていて、何もしていません。ただし、ポイントの各ペア間の二乗ユークリッド距離が必要であると仮定し、 th とth のポイント間の距離に等しい行列distsを作成します。dists[i, j]ij

scipy が利用可能な場合の簡単な方法:

# stack the points into a num_pts x 3 matrix
pts = np.hstack([thing.reshape((-1, 1)) for thing in (x, y, z)])

# get squared euclidean distances in a matrix
dists = scipy.spatial.squareform(scipy.spatial.pdist(pts, 'sqeuclidean'))

リストが膨大な場合は、squareform を使用しない方がメモリ効率が高くなりますが、特定の距離のペアを見つけるのが少し難しい圧縮された形式になります。

scipy を使用できない/使用したくない場合は、少し難しくなります。

pts = np.hstack([thing.reshape((-1, 1)) for thing in (x, y, z)])
sqnorms = np.sum(pts ** 2, axis=1)
dists = sqnorms.reshape((-1, 1)) - 2 * np.dot(pts, pts.T) + sqnorms

これは基本的に式 (a - b)^2 = a^2 - 2 ab + b^2 を実装しますが、すべてベクトルに似ています。

于 2013-02-22T22:12:28.793 に答える
0

完全な解決策を掲載していないことをお詫びしますが、呼び出されるたびに新しいタプルが作成されるため、range() の呼び出しをネストしないでください。range() を 1 回呼び出して結果を保存するか、代わりにループ カウンターを使用することをお勧めします。

たとえば、次の代わりに:

max = 50

for number in range (0, 50):

    doSomething(number)

...次のようにします。

max = 50
current = 0

while current < max:

    doSomething(number)
    current += 1
于 2013-02-22T20:51:01.830 に答える
0

さて、あなたの計算の複雑さはかなり高いです。rまた、すべての値を 1 つのリストに格納する場合は、大量のメモリが必要です。多くの場合、リストは必要なく、ジェネレーターで値を処理したい場合に十分な場合があります。

次のコードを検討してください。

def calculate(x, y, z):
    for xi, xj in combinations(x, 2):
        for yi, yj in combinations(y, 2):
            for zi, zj in combinations(z, 2):
                yield (xi - xj) + (yi - yj) + (zi - zj)

next()これは、ジェネレーターのメソッドを呼び出すたびに 1 つの値のみを計算するジェネレーターを返します。

gen = calculate(xrange(10), xrange(10, 20), xrange(20, 30))
gen.next() # returns -3
gen.next() # returns -4 and so on
于 2013-02-22T21:50:03.760 に答える