1

私のコードの処理には約 2 時間かかります。ボトルネックは for ループと if ステートメントにあります (コード内のコメントを参照)。私はPythonの初心者です:)ネストされたforステートメントとifステートメントを置き換える効率的なPythonの方法を誰かが推奨できますか?

〜3000万行のテーブルがあり、各行には(x、y、z)値があります:

20.0 11.3 7
21.0 11.3 0
22.0 11.3 3
...

私の望む出力は、x、y、min(z)、count(min(z)) の形式のテーブルです。最後の列は、その (x,y) における最小の z 値の最終カウントです。例えば:

20.0 11.3 7 7
21.0 11.3 0 10
22.0 11.3 3 1
...

一意の座標は約 600 しかないため、出力テーブルは 600x4 になります。私のコード:

import numpy as np
file = open('input.txt','r');

coordset = set()
data = np.zeros((600,4))*np.nan
irow = 0 
ctr = 0 

for row in file:
    item = row.split()
    x = float(item[0])
    y = float(item[1])
    z = float(item[2])

    # build unique grid of coords
    if ((x,y)) not in coordset:
        data[irow][0] = x 
        data[irow][1] = y 
        data[irow][2] = z 
        irow = irow + 1     # grows up to 599 

    # lookup table of unique coords
    coordset.add((x,y))

    # BOTTLENECK. replace ifs? for?
    for i in range(0, irow):
        if data[i][0]==x and data[i][1]==y:
            if z > data[i][2]:
                continue
            elif z==data[i][2]:
                ctr = ctr + 1
                data[i][3]=ctr
            if z < data[i][2]:
                data[i][2] = z
                ctr = 1
                data[i][3]=ctr

編集:参考までに、@ Joowaniによるアプローチは1m26sで計算されます。私の最初のアプローチ、同じコンピューター、同じデータファイル、106m23s。 edit2: @Ophion と @Sibster の提案に感謝します。有用な回答を +1 するのに十分なクレジットがありません。

4

3 に答える 3

2

更新を行うたびにリスト (つまりデータ) を反復処理するため、ソリューションが遅いように見えます。より良いアプローチは、更新ごとに O(n) ではなく O(1) を取る辞書を使用することです。

辞書を使用した私の解決策は次のとおりです。

file = open('input.txt', 'r')

#coordinates
c = {}

for line in file:
    #items
    (x, y, z) = (float(n) for n in line.split())

    if (x, y) not in c:
        c[(x, y)] = [z, 1]
    elif c[(x, y)][0] > z:
        c[(x, y)][0], c[(x, y)][1] = z, 1
    elif c[(x, y)][0] == z:
        c[(x, y)][1] += 1

for key in c:
    print("{} {} {} {}".format(key[0], key[1], c[key][0], c[key][1]))
于 2013-08-19T07:13:23.913 に答える
0

numpy use でこれを行うにはnp.unique

def count_unique(arr):
    row_view=np.ascontiguousarray(a).view(np.dtype((np.void,a.dtype.itemsize * a.shape[1])))
    ua, uind = np.unique(row_view,return_inverse=True)
    unique_rows = ua.view(a.dtype).reshape(ua.shape + (-1,))
    count=np.bincount(uind)
    return np.hstack((unique_rows,count[:,None]))

まず、小さな配列をチェックしましょう:

a=np.random.rand(10,3)
a=np.around(a,0)

print a
[[ 0.  0.  0.]
 [ 0.  1.  1.]
 [ 0.  1.  0.]
 [ 1.  0.  0.]
 [ 0.  1.  1.]
 [ 1.  1.  0.]
 [ 1.  0.  1.]
 [ 1.  0.  1.]
 [ 1.  0.  0.]
 [ 0.  0.  0.]]

 print output
[[ 0.  0.  0.  2.]
 [ 0.  1.  0.  1.]
 [ 0.  1.  1.  2.]
 [ 1.  0.  0.  2.]
 [ 1.  0.  1.  2.]
 [ 1.  1.  0.  1.]]

 print np.sum(output[:,-1])
 10

いいね!次に、大きな配列を確認します。

a=np.random.rand(3E7,3)
a=np.around(a,1)

output=count_unique(a)
print output.shape
(1331, 4)  #Close as I can get to 600 unique elements.

print np.sum(output[:,-1])
30000000.0

私のマシンと 3GB のメモリで約 33 秒かかります。これをすべてメモリ内で行うと、大規模な配列がボトルネックになる可能性があります。参考までに、@ Joowani のソリューションには約 130 秒かかりましたが、numpy 配列から始めると、これは少しリンゴとオレンジの比較になります。マイレージは異なる場合があります。

データを numpy 配列として読み込むには、ここで質問を表示しますが、次のようになります。

arr=np.genfromtxt("./input.txt", delimiter=" ")

txt ファイルから大量のデータを読み込むにはpandas、そのリンクの例を使用することを強くお勧めします。

于 2013-08-19T13:11:50.790 に答える