0

タプル/ポイントのリストを指定して、指定された境界(距離)内にある各タプルをグループ化する方法を見つけようとしています。説明するのは難しいですが、短いコードで私が何を意味するのかを説明する必要があります...私は単に解決策を見つけることができず、問題を適切に説明する方法もわかりません。

例えば:

TPL = [(1, 1), (2, 1), (3, 2), (7, 5), (2, 7), (6, 4), (2, 3), (2, 6), (3, 1)]
Print GroupTPL(TPL, distance=1)
> [
>  [(2, 7), (2, 6)], 
>  [(6, 4), (7, 5)], 
>  [(3, 2), (3, 1), (2, 3), (1, 1), (2, 1)]
> ]

私が試したすべてのことは、がらくたです。だから、共有することを検討する理由さえありません。皆さんがいくつかのヒントやコツを手に入れたことを願っています。

4

3 に答える 3

3

ポイントをまとめたいときは、チェビシェフ距離を意図していると思います。

この場合、それを行う最も簡単な方法は、UnionFindデータ構造を使用することです。

これが私が使用した実装です:

class UnionFind:
    """Union-find data structure. Items must be hashable."""

    def __init__(self):
        """Create a new empty union-find structure."""
        self.weights = {}
        self.parents = {}

    def __getitem__(self, obj):
        """X[item] will return the token object of the set which contains `item`"""

        # check for previously unknown object
        if obj not in self.parents:
            self.parents[obj] = obj 
            self.weights[obj] = 1
            return obj 

        # find path of objects leading to the root
        path = [obj]
        root = self.parents[obj]
        while root != path[-1]:
            path.append(root)
            root = self.parents[root]

        # compress the path and return
        for ancestor in path:
            self.parents[ancestor] = root
        return root

    def union(self, obj1, obj2):
        """Merges sets containing obj1 and obj2."""
        roots = [self[obj1], self[obj2]]
        heavier = max([(self.weights[r],r) for r in roots])[1]
        for r in roots:
            if r != heavier:
                self.weights[heavier] += self.weights[r]
                self.parents[r] = heavier

次に、関数の記述groupTPLは簡単です。

def groupTPL(TPL, distance=1):
    U = UnionFind()

    for (i, x) in enumerate(TPL):
        for j in range(i + 1, len(TPL)):
            y = TPL[j]
            if max(abs(x[0] - y[0]), abs(x[1] - y[1])) <= distance:
                U.union(x, y)

    disjSets = {}
    for x in TPL:
        s = disjSets.get(U[x], set())
        s.add(x)
        disjSets[U[x]] = s

    return [list(x) for x in disjSets.values()]

セットで実行すると、次のようになります。

>>> groupTPL([(1, 1), (2, 1), (3, 2), (7, 5), (2, 7), (6, 4), (2, 3), (2, 6), (3, 1)])
[
 [(2, 7), (2, 6)], 
 [(6, 4), (7, 5)], 
 [(3, 2), (3, 1), (2, 3), (1, 1), (2, 1)]
]

ただし、この実装は単純ですが、それでもO(n^2)です。ポイントの数が非常に多くなる場合、効率的な実装ではkdツリーを使用します。

于 2013-02-01T14:54:50.217 に答える
1

私の答えは遅れています。しかし、これは短くて機能しています!!

from itertools import combinations

def groupTPL(inputlist):  
    ptdiff = lambda (p1,p2):(p1,p2,abs(p1[0]-p2[0])+ abs(p1[1]-p2[1]),sqrt((p2[1] - p1[1])**2 + (p2[0] - p1[0])**2 ))
    diffs=[ x for x in map(ptdiff, combinations(inputlist,2)) if x[2]==1 or x[3]==sqrt(2)]
    nk1=[]
    for x in diffs:
        if len(nk1)>0:
            for y in nk1:
                if x[0] in y or x[1] in y:
                    y.add(x[0])
                    y.add(x[1])
                else:
                    if set(x[0:2]) not in nk1:
                        nk1.append(set(x[0:2]))
        else:
            nk1.append(set(x[0:2]))
    return [list(x) for x in nk1]

print groupTPL([(1, 1), (2, 1), (3, 2), (7, 5), (2, 7), (6, 4), (2, 3), (2, 6), (3, 1)])

これにより、次のように出力されます::::

[[(3, 2), (3, 1), (2, 3), (1, 1), (2, 1)], [(6, 4), (7, 5)], [(2, 7), (2, 6)]]
于 2013-02-01T16:04:53.300 に答える
0

代替案を入力するだけです。これは、で指定されたUnion-Findコードよりもデフォルトでは高速ではありませんがmusically-ut、使用が簡単で、Cython3倍の高速化を実現します。それでも、デフォルトで高速になる場合があります。これは私の仕事ではなく、ここで見つかったものです:https ://github.com/MerlijnWajer/Simba/blob/master/Units/MMLCore/tpa.pas

Cythonコード: (Pythonで使用するcdefint...、およびint w、int hを削除します)

def group_pts(pts, int w, int h):
  cdef int t1, t2, c, ec, tc, l

  l = len(pts)-1
  if (l < 0): return False
  result = [list() for i in range(l+1)]
  c = 0
  ec = 0
  while ((l - ec) >= 0):
    result[c].append(pts[0])
    pts[0] = pts[l - ec]
    ec += 1
    tc = 1
    t1 = 0
    while (t1 < tc):
      t2 = 0
      while (t2 <= (l - ec)):
        if (abs(result[c][t1][0] - pts[t2][0]) <= w) and \
           (abs(result[c][t1][1] - pts[t2][1]) <= h):

          result[c].append(pts[t2])
          pts[t2] = pts[l - ec]
          ec += 1
          tc += 1
          t2 -= 1
        t2 += 1
      t1 += 1
    c += 1

  return result[0:c]

これはおそらく少し最適化することができますが、私はそうするために時間をかけていません。これにより、Union-Find構造があまり満足していない重複も可能になります。

これを処理するためにSciPyのkd-treeを使用することは興味深いかもしれません。それは間違いなく、より大きなデータセットの速度を上げるでしょう。

于 2013-05-30T04:42:31.273 に答える