web-dev-qa-db-ja.com

NumPy2D配列から重複する列と行を削除する

2D形状配列を使用して、経度と緯度のペアを格納しています。ある時点で、これらの2D配列の2つをマージしてから、重複したエントリを削除する必要があります。 numpy.uniqueに似た関数を探していましたが、運がありませんでした。私が考えていた実装は、非常に「最適化されていない」ように見えます。たとえば、配列をタプルのリストに変換し、setを使用して重複を削除してから、再度配列に変換しようとしています。

coordskeys = np.array(list(set([Tuple(x) for x in coordskeys])))

既存の解決策はありますか?それで私は車輪の再発明をしませんか?

明確にするために、私は探しています:

>>> a = np.array([[1, 1], [2, 3], [1, 1], [5, 4], [2, 3]])
>>> unique_rows(a)
array([[1, 1], [2, 3],[5, 4]])

ところで、タプルのリストだけを使用したかったのですが、リストが大きすぎて4Gb RAM + 4Gbスワップ(numpy配列の方がメモリ効率が高い)を消費しました。

20
Sergi

これが1つのアイデアです。少し手間がかかりますが、かなり高速になる可能性があります。 1dの場合を紹介し、それを2dに拡張する方法を説明します。次の関数は、1d配列の一意の要素を検索します。

import numpy as np
def unique(a):
    a = np.sort(a)
    b = np.diff(a)
    b = np.r_[1, b]
    return a[b != 0]

2Dに拡張するには、2つのことを変更する必要があります。自分で並べ替えを行う方法を理解する必要があります。並べ替えで重要なことは、2つの同じエントリが隣り合ってしまうことです。次に、行/列全体を比較するため、(b != 0).all(axis)のようなことを行う必要があります。それで始められるかどうか教えてください。

更新:ダグの助けを借りて、これは2Dの場合に機能するはずだと思います。

import numpy as np
def unique(a):
    order = np.lexsort(a.T)
    a = a[order]
    diff = np.diff(a, axis=0)
    ui = np.ones(len(a), 'bool')
    ui[1:] = (diff != 0).any(axis=1) 
    return a[ui]
17
Bi Rico

これでうまくいくはずです:

def unique_rows(a):
    a = np.ascontiguousarray(a)
    unique_a = np.unique(a.view([('', a.dtype)]*a.shape[1]))
    return unique_a.view(a.dtype).reshape((unique_a.shape[0], a.shape[1]))

例:

>>> a = np.array([[1, 1], [2, 3], [1, 1], [5, 4], [2, 3]])
>>> unique_rows(a)
array([[1, 1],
       [2, 3],
       [5, 4]])
31
user545424

私の方法は、2次元配列を1次元複素数配列に変換することです。ここで、実数部は1列目、虚数部は2列目です。次に、np.uniqueを使用します。ただし、これは2列でのみ機能します。

import numpy as np 
def unique2d(a):
    x, y = a.T
    b = x + y*1.0j 
    idx = np.unique(b,return_index=True)[1]
    return a[idx] 

例-

a = np.array([[1, 1], [2, 3], [1, 1], [5, 4], [2, 3]])
unique2d(a)
array([[1, 1],
       [2, 3],
       [5, 4]])
5
kidnakyo

numpy_indexed パッケージ(免責事項:私はその作者です)は、user545424によって投稿されたソリューションを、テスト済みの優れたインターフェイスに加えて、多くの関連機能でラップします。

import numpy_indexed as npi
npi.unique(coordskeys)
3
>>> import numpy as NP
>>> # create a 2D NumPy array with some duplicate rows
>>> A
    array([[1, 1, 1, 5, 7],
           [5, 4, 5, 4, 7],
           [7, 9, 4, 7, 8],
           [5, 4, 5, 4, 7],
           [1, 1, 1, 5, 7],
           [5, 4, 5, 4, 7],
           [7, 9, 4, 7, 8],
           [5, 4, 5, 4, 7],
           [7, 9, 4, 7, 8]])

>>> # first, sort the 2D NumPy array row-wise so dups will be contiguous
>>> # and rows are preserved
>>> a, b, c, d, e = A.T    # create the keys for to pass to lexsort
>>> ndx = NP.lexsort((a, b, c, d, e))
>>> ndx
    array([1, 3, 5, 7, 0, 4, 2, 6, 8])
>>> A = A[ndx,]

>>> # now diff by row
>>> A1 = NP.diff(A, axis=0)
>>> A1
    array([[0, 0, 0, 0, 0],
           [4, 3, 3, 0, 0],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 1, 0],
           [0, 0, 1, 0, 0],
           [2, 5, 0, 2, 1],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0]])

>>> # the index array holding the location of each duplicate row
>>> ndx = NP.any(A1, axis=1)  
>>> ndx
    array([False,  True, False,  True,  True,  True, False, False], dtype=bool)  

>>> # retrieve the duplicate rows:
>>> A[1:,:][ndx,]
    array([[7, 9, 4, 7, 8],
           [1, 1, 1, 5, 7],
           [5, 4, 5, 4, 7],
           [7, 9, 4, 7, 8]])
3
doug

numpy.uniqueを参照しているので、元の順序を維持する必要はありませんよね?セットに変換すると、重複が削除されてからリストに戻ることがよく使用されます。

>>> x = [(1, 1), (2, 3), (1, 1), (5, 4), (2, 3)]
>>> y = list(set(x))
>>> y
[(5, 4), (2, 3), (1, 1)]
>>> 
1
yosukesabai