5

私はPythonでいくつかのコードを書いています(これまでのところ楽しみのために)。3D空間のすべてのポイントにいくつかのデータを格納します。私は基本的に、次のような高度な選択を可能にする任意のオブジェクトを格納する3Dマトリックスオブジェクトを求めています。

  • x = 1、y = 2、z=3の点を取得します。
  • y=2であるすべてのポイントを取得します。
  • 位置x=1、y = 2、z=3の3単位内のすべてのポイントを取得します。
  • point.getType()=="Foo"であるすべてのポイントを取得する

上記のすべてで、スペース内の元の位置とその時点で保存されたデータを取得するような出力を作成する必要があります。

どうやらnumpyは私が望むことを実行できるようですが、科学計算用に高度に最適化されているようで、上記のようにデータを取得する方法を考え出すことはこれまでのところ私にはわかりません。

より良い代替案はありますか、それとも私は頭をゴツゴツした壁に叩きつけることに戻るべきですか?:)

編集:最初の3つの回答で、私が含めるべきだと気付いた情報がいくつかあります。パフォーマンスについては心配していません。これは純粋に概念実証であり、優れたパフォーマンスよりもクリーンなコードを優先します。また、指定された3D空間のすべてのポイントのデータがあるので、スペアマトリックスは悪いと思いますか?

4

8 に答える 8

6

これが別の一般的なアプローチです

class Point( object ):
    def __init__( self, x, y, z, data ):
        self.x, self.y, self.z = x, y, z
        self.data = data
    def distFrom( self, x, y, z )
        return math.sqrt( (self.x-x)**2 + (self.y-y)**2 + (self.z-z)**2 )

database = [ Point(x,y,z,data), Point(x,y,z,data), ... ]

ユースケースを見てみましょう。

x=1、y=2、z=3 の点を取得します。

[ p for p in database if (p.x, p.y, p.z) == ( 1, 2, 3 ) ]

y=2 のすべてのポイントを取得します。

[ p for p in database if p.y == 2 ]

位置 x=1、y=2、z=3 の 3 単位内のすべてのポイントを取得します。

[ p for p in database if p.distFrom( 1, 2, 3 ) <= 3.0 ]

point.getType() == "Foo" であるすべてのポイントを取得する

[ p for p in database if type(p.data) == Foo ]
于 2009-05-26T15:30:30.423 に答える
3

ええと...本当にそのスペースを埋めることを期待しているなら、おそらく密集したマトリックスのような構造、基本的にはボクセルを使うのが最善でしょう。

あなたがそれを満たすことを期待しないならば、もう少し最適化された何かを調べてください。まず、このようなものによく使われる八分木を見ていきます。

于 2009-05-26T14:20:43.713 に答える
1

numpy の利点の 1 つは、非常に高速であることです。たとえば、8000x8000 の隣接行列のページランクの計算には数ミリ秒かかります。数値のみを受け入れますがnumpy.ndarray、数値/ID オブジェクトのマッピングを外部のハッシュ テーブル、つまり辞書 (高度に最適化されたデータ構造) に格納できます。

スライスは、Python でリストをスライスするのと同じくらい簡単です。

>>> from numpy import arange

>>> the_matrix = arange(64).reshape(4, 4, 4)
>>> print the_matrix[0][1][2]
    6
>>> print the_matrix[0][1]
    [4 5 6 7]
>>> print the_matrix[0]
    [[ 0  1  2  3]
    [ 4  5  6  7]
    [ 8  9 10 11]
    [12 13 14 15]]

必要な関数 (距離) をいくつかのコア マトリックスと id-object-mapping ハッシュにラップすると、短時間でアプリケーションを実行できます。

幸運を!

于 2009-05-26T14:50:21.453 に答える
0

標準ライブラリを使用した比較的単純なソリューションが必要な場合は、キーとしてx、y、zタプルを使用する辞書を使用することも別のソリューションです。

import math

#use indexing to get point at (1,2,3): points[(1,2,3)]
get_points(points, x=None, y=None, x=None):
    """returns dict of all points with given x,y and/or z values.  Call using keywords (eg get_points(points, x=3)"""
    filteredPoints = points.items()
    if x:
        filteredPoints = [p for p in filteredPoints if p[0][0] == x]
    if y:
        filteredPoints = [p for p in filteredPoints if p[0][1] == y]
    if z:
        filteredPoints = [p for p in filteredPoints if p[0][0] == x]
    return dict(filteredPoints)

get_point_with_type(points, type_):
    """returns dict of points with point.getType() == type_"""
    filteredPoints = points.items()
    return dict((position,data) for position,data in points.iterItems() if data.getType == type_)

get_points_in_radius(points,x,y,z,r):
    """Returns a dict of points within radius r of point (x,y,z)"""
    def get_dist(x1,y1,z1,x2,y2,z3):
        return math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2))
    return dict((position,data) for position,data in points.iterItems() if get_dist(x,y,z, *position) <= r))

また、Python参照により、返された辞書の「ポイント」を変更したり、元のポイントも変更したりすることができます(私は思います)。

于 2009-05-26T17:06:27.560 に答える
0

Binary Space Partitioning、Quadtree、Octree をいつ使用するか?

3D配列imoは価値がありません。特にあなたの世界が動的である場合。BSP、Quadtree、または Octtree のいずれかを決定する必要があります。BSP で十分でしょう。あなたの世界は 3D であるため、BSP を分割するときは線ではなく平面が必要です。

乾杯 !

編集

また、指定された 3D 空間のすべてのポイントのデータも取得するので、スペア マトリックスが悪いと思いますか?

データセットの大きさを常に知っていて、それが決して変わらない場合、つまり、さらにポイントが追加されて範囲外になる場合は、これで問題ないと思います。その場合、3d 配列のサイズを変更する必要があります。

于 2009-05-26T15:59:24.310 に答える
0

numpy でスライスして最初の 2 つのクエリを実行できます。

a = numpy.zeros((4, 4, 4))
a[1, 2, 3] # The point at x=1,y=2,z=3
a[:, 2, :] # All points where y=2

3 番目の場合、「半径 3 の球内で x=1、y=2、z=3 を中心とするすべての点を取得する」ことを意味する場合、それを行うカスタム関数を作成する必要があります。立方体が必要な場合は、スライスに進むことができます。

a[1:3, 1:3, 1:3] # The 2x2x2 array sliced from the center of 'a'

4 番目のクエリで、配列に格納されているデータがセル タイプのみの場合は、整数としてエンコードできます。

FOO = 1
BAR = 2
a = numpy.zeros((4, 4, 4), dtype="i")
a[1, 2, 3] = FOO
a[3, 2, 1] = BAR
def filter(a, type_code):
    coords = []
    for z in range(4):
        for y in range(4):
            for x in range(4):
                if a[x, y, z] == type_code:
                    coords.append((x, y, z))
    return coords
filter(a, FOO) # => [(1, 2, 3)]

numpy は、配列がメモリ内で小さくなり、C (またはcythonの方が優れています!) で簡単にアクセスでき、拡張されたスライス構文によりコードを記述する必要がなくなるため、必要なことを行うための優れたツールのように見えます。

于 2009-05-26T14:40:16.157 に答える
0

これがうまくいくかもしれないアプローチです。

各ポイントは 4 タプル (x、y、z、データ) であり、データベースは次のようになります。

database = [ (x,y,z,data), (x,y,z,data), ... ]

ユースケースを見てみましょう。

x=1、y=2、z=3 の点を取得します。

[ (x,y,z,data) for x,y,z,data in database if (x,y,z) == (1,2,3) ]

y=2 のすべてのポイントを取得します。

[ (x,y,z,data) for x,y,z,data in database if y == 2 ]

位置 x=1、y=2、z=3 の 3 単位内のすべてのポイントを取得します。

[ (x,y,z,data) for x,y,z,data in database if math.sqrt((x-1)**2+(y-2)**2+(z-3)**2)<=3.0 ]

point.getType() == "Foo" であるすべてのポイントを取得する

[ (x,y,z,data) for x,y,z,data in database if type(data) == Foo ]
于 2009-05-26T14:51:03.653 に答える
-1

システムの正確な構成に依存しますが、あなたが与えた例から、整数と離散点を使用しているため、Sparse Matrixデータ構造を検討するのがおそらく適切でしょう。

于 2009-05-26T14:27:14.277 に答える