numpy.arrayで一意の行を見つける


199

で一意の行を見つける必要があります numpy.array

例えば:

>>> a # I have
array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])
>>> new_a # I want to get to
array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 0]])

セットを作成して配列をループできることはわかっていますが、効率的な純粋なnumpyソリューションを探しています。データ型をvoidに設定する方法はあると思いますがnumpy.unique、を使用することはできますが、それを機能させる方法を理解できませんでした。


11
パンダにはdataframe.drop_duplicates()メソッドがあります。stackoverflow.com/questions/12322779/pandas-unique-dataframeおよびpandas.pydata.org/pandas-docs/dev/generated/…を
codeape

ありがとうございます、パンダは使えません。
Akavall 2013


1
@アンディ・ヘイデン、タイトルにもかかわらず、それはこの質問の複製ではありません。codeapeのリンクは重複しています。
Wai Yip Tung

5
この機能は1.13にネイティブで追加され
Eric

回答:


115

NumPy 1.13以降、任意のN次元配列の一意の値を選択するための軸を選択することができます。一意の行を取得するには、次のようにします。

unique_rows = np.unique(original_array, axis=0)


12
この機能には注意してください。 重複する行が削除されnp.unique(list_cor, axis=0)配列を取得します。元の配列で一意の要素に配列をフィルターしません。参照してくださいここで ..例えば、
ブラッド・ソロモン

あなたが行の値の順序を無視して一意の行をしたい場合、あなたは列の元の配列をソートすることもできますが最初に指示:original_array.sort(axis=1)
mangecoeur

140

さらに別の可能な解決策

np.vstack({tuple(row) for row in a})

20
+1これは明確で短く、Pythonicです。速度が実際の問題でない限り、これらのタイプのソリューションは、この質問IMOに対する複雑で投票数の多い回答よりも優先されます。
Bill Cheatham 2014

3
優れた!中かっこまたはset()関数がうまく機能します。
Tian He

2
@Greg von Winckel順序を変更しないものではないものを提案できますか。
Laschet Jain、2017

はい、ただし単一のコマンドではありません:x = []; [x.append(tuple(r))for r in a if tuple(r)not in x]; a_unique = array(x);
グレッグフォンヴィンケル2017年

1
FutureWarningを回避するには、セットを次のようなリストに変換np.vstack(list({tuple(row) for row in AIPbiased[i, :, :]})) します。FutureWarning:スタックする配列は、リストやタプルなどの「シーケンス」タイプとして渡す必要があります。ジェネレーターなどの非シーケンス反復可能オブジェクトのサポートは、NumPy 1.16で非推奨になり、将来エラーが発生します。
Leermeester

111

構造化配列を使用する別のオプションは、void行全体を単一のアイテムに結合するタイプのビューを使用することです。

a = np.array([[1, 1, 1, 0, 0, 0],
              [0, 1, 1, 1, 0, 0],
              [0, 1, 1, 1, 0, 0],
              [1, 1, 1, 0, 0, 0],
              [1, 1, 1, 1, 1, 0]])

b = np.ascontiguousarray(a).view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))
_, idx = np.unique(b, return_index=True)

unique_a = a[idx]

>>> unique_a
array([[0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])

編集np.ascontiguousarray以下の@sebergの推奨事項を 追加。配列が隣接していない場合、これによりメソッドの速度が低下します。

編集 上記は、おそらく以下を実行することにより、明確さを犠牲にして、わずかに高速化できます。

unique_a = np.unique(b).view(a.dtype).reshape(-1, a.shape[1])

また、少なくとも私のシステムでは、パフォーマンスに関しては、lexsortメソッドよりもパフォーマンスが同等またはそれ以上です。

a = np.random.randint(2, size=(10000, 6))

%timeit np.unique(a.view(np.dtype((np.void, a.dtype.itemsize*a.shape[1])))).view(a.dtype).reshape(-1, a.shape[1])
100 loops, best of 3: 3.17 ms per loop

%timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]
100 loops, best of 3: 5.93 ms per loop

a = np.random.randint(2, size=(10000, 100))

%timeit np.unique(a.view(np.dtype((np.void, a.dtype.itemsize*a.shape[1])))).view(a.dtype).reshape(-1, a.shape[1])
10 loops, best of 3: 29.9 ms per loop

%timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]
10 loops, best of 3: 116 ms per loop

3
どうもありがとう。これは私が探していた答えです、このステップで何が起こっているのか説明できますb = a.view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))か?
Akavall 2013年

3
@Akavall np.void完全な行のバイト数とサイズのデータ​​型でデータのビューを作成しています。これは、np.uint8sの配列があり、それをnp.uint16s として表示した場合に得られるものと似ています。これは、2つごとの列を1つの列に結合しますが、より柔軟です。
Jaime

3
@ハイメ、np.ascontiguousarray一般的に安全であるようにまたは類似のものを追加できますか(私はそれが必要であるよりも少し制限的であることを知っていますが...)。ビューが期待どおりに機能するには、行が連続している必要あります。
seberg 2013年

2
@ConstantineEvansこれは最近の追加です。numpy1.6 np.uniqueでは、配列で実行しようとすると、np.voidそのタイプにマージソートが実装されていないことに関連するエラーが返されます。ただし、1.7では問題なく動作します。
Jaime

9
このメソッドを浮動小数点数に使用-0.すると+0.、要素-0.==+0.ごとの比較では(ieee float規格で指定されているように)等しいと比較されないキャッチがあることに注意してください。stackoverflow.com/questions/26782038/…を
tom10 2014年

29

一連のタプルまたは別の同様のデータ構造に変換することによるメモリ消費を回避したい場合は、numpyの構造化配列を利用できます。

トリックは、元の配列を、各項目が元の配列の行に対応する構造化配列として表示することです。これはコピーを作成せず、非常に効率的です。

簡単な例として:

import numpy as np

data = np.array([[1, 1, 1, 0, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [1, 1, 1, 0, 0, 0],
                 [1, 1, 1, 1, 1, 0]])

ncols = data.shape[1]
dtype = data.dtype.descr * ncols
struct = data.view(dtype)

uniq = np.unique(struct)
uniq = uniq.view(data.dtype).reshape(-1, ncols)
print uniq

何が起こっているのかを理解するには、中間結果を見てください。

構造化配列として見ると、配列の各要素は元の配列の行になります。(基本的に、タプルのリストと同様のデータ構造です。)

In [71]: struct
Out[71]:
array([[(1, 1, 1, 0, 0, 0)],
       [(0, 1, 1, 1, 0, 0)],
       [(0, 1, 1, 1, 0, 0)],
       [(1, 1, 1, 0, 0, 0)],
       [(1, 1, 1, 1, 1, 0)]],
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])

In [72]: struct[0]
Out[72]:
array([(1, 1, 1, 0, 0, 0)],
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])

を実行するnumpy.uniqueと、構造化配列が返されます。

In [73]: np.unique(struct)
Out[73]:
array([(0, 1, 1, 1, 0, 0), (1, 1, 1, 0, 0, 0), (1, 1, 1, 1, 1, 0)],
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])

次に、「通常の」配列として表示する必要があること(_最後の計算の結果をに格納するため、が表示されipythonます_.view...)。

In [74]: _.view(data.dtype)
Out[74]: array([0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0])

次に、2D配列に再形成します(-1numpyに正しい行数を計算し、列数を与えるように指示するプレースホルダーです):

In [75]: _.reshape(-1, ncols)
Out[75]:
array([[0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])

明らかに、もっと簡潔にしたい場合は、次のように書くことができます。

import numpy as np

def unique_rows(data):
    uniq = np.unique(data.view(data.dtype.descr * data.shape[1]))
    return uniq.view(data.dtype).reshape(-1, data.shape[1])

data = np.array([[1, 1, 1, 0, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [1, 1, 1, 0, 0, 0],
                 [1, 1, 1, 1, 1, 0]])
print unique_rows(data)

その結果:

[[0 1 1 1 0 0]
 [1 1 1 0 0 0]
 [1 1 1 1 1 0]]

これは実際には非常に遅く、タプルを使用するのと同じくらい遅いようです。このように構造化された配列のソートは、明らかに遅いようです。
cge 2013

3
@cge-より大きなサイズの配列で試してください。はい、numpy配列のソートはリストのソートよりも低速です。ただし、ndarrayを使用しているほとんどの場合、速度は主な考慮事項ではありません。メモリ使用量です。タプルのリストは、このソリューションよりもはるかに多くのメモリを使用します。十分なメモリがあり、配列がかなり大きい場合でも、タプルのリストに変換すると、速度の利点よりもオーバーヘッドが大きくなります。
ジョー・キントン2013

@cge-ああ、あなたがを使ってlexsortいることに気づかなかった。タプルのリストの使用について言及していると思いました。ええ、lexsortおそらくこの場合はより良いオプションです。私はそれを忘れてしまい、過度に複雑なソリューションに飛びつきました。
Joe Kington

20

np.unique私がそれを実行すると、np.random.random(100).reshape(10,10)すべての一意の個々の要素が返されますが、一意の行が必要なので、最初にそれらをタプルに入れる必要があります。

array = #your numpy array of lists
new_array = [tuple(row) for row in array]
uniques = np.unique(new_array)

これが、タイプを変更して必要なことを行う唯一の方法であり、タプルに変更するためのリストの反復が「ループしない」ことで問題ないかどうかはわかりません


5
+1これは明確で短く、Pythonicです。速度が実際の問題でない限り、これらのタイプのソリューションは、この質問IMOに対する複雑で投票数の多い回答よりも優先されます。
Bill Cheatham 2014

私はこれを受け入れられた解決策よりも好みます。< 100呼び出しごとにおそらく行があるだけなので、速度は私にとって問題ではありません。これは、行に対する一意の実行がどのように実行されるかを正確に説明します。
rayryeng 2015

4
これは実際には私のデータでuniquesは機能せず、一意の要素が含まれています。予想される形状を誤解している可能性arrayがあります-ここでより正確に教えていただけますか?
FooBar 2015

@ ryan-saxeこれはpythonicであるのが好きですが、返される行uniquesがソートされているため(これはの行とは異なるため)、これは良い解決策ではありませんarrayB = np.array([[1,2],[2,1]]); A = np.unique([tuple(row) for row in B]); print(A) = array([[1, 2],[1, 2]])
jmlarson 2016年

16

np.uniqueは、平坦化された配列をソートしてから、各項目が前の項目と等しいかどうかを調べます。これはフラット化せずに手動で行うことができます:

ind = np.lexsort(a.T)
a[ind[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]]

このメソッドはタプルを使用しないため、ここで説明する他のメソッドよりもはるかに高速で単純なはずです。

注:これの以前のバージョンでは、a [の直後にindがありませんでした。つまり、誤ったインデックスが使用されていました。また、Joe Kingtonは、これによりさまざまな中間コピー作成されることを強調してます。次のメソッドは、ソートされたコピーを作成し、そのビューを使用することにより、数を減らしています。

b = a[np.lexsort(a.T)]
b[np.concatenate(([True], np.any(b[1:] != b[:-1],axis=1)))]

これはより速く、より少ないメモリを使用します。

また、配列の次元数に関係なく、ndarray内の一意の行を検索する場合は、以下が機能します。

b = a[lexsort(a.reshape((a.shape[0],-1)).T)];
b[np.concatenate(([True], np.any(b[1:]!=b[:-1],axis=tuple(range(1,a.ndim)))))]

興味深い残りの問題は、任意の次元の配列の任意の軸に沿って並べ替え/一意にしたい場合です。

編集:

速度の違いを示すために、回答に記載されている3つの異なる方法をipythonでいくつかテストしました。では、あなたのこのバージョンは少し速いですが、正確なA、あまり差がありません。

In [87]: %timeit unique(a.view(dtype)).view('<i8')
10000 loops, best of 3: 48.4 us per loop

In [88]: %timeit ind = np.lexsort(a.T); a[np.concatenate(([True], np.any(a[ind[1:]]!= a[ind[:-1]], axis=1)))]
10000 loops, best of 3: 37.6 us per loop

In [89]: %timeit b = [tuple(row) for row in a]; np.unique(b)
10000 loops, best of 3: 41.6 us per loop

ただし、aが大きいほど、このバージョンははるかに高速になります。

In [96]: a = np.random.randint(0,2,size=(10000,6))

In [97]: %timeit unique(a.view(dtype)).view('<i8')
10 loops, best of 3: 24.4 ms per loop

In [98]: %timeit b = [tuple(row) for row in a]; np.unique(b)
10 loops, best of 3: 28.2 ms per loop

In [99]: %timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!= a[ind[:-1]],axis=1)))]
100 loops, best of 3: 3.25 ms per loop

非常に素晴らしい!ただし、補足として、いくつかの中間コピーを作成します。(例:a[ind[1:]]コピーなど)一方、RAMが不足するまで、ソリューションは通常、私のソリューションより2〜3倍高速です。
Joe Kington 2013

いい視点ね。結局のところ、a_sorted [1:]はa_sortedのコピーではないため、インデックスのみを使用して中間コピーを取り出そうとすると、メソッドのメモリ使用量が増え、配列のソートされたコピーを作成するよりも遅くなります。 。
cge 2013

dtypeあなたのタイミングは何ですか?間違いだと思います。私のシステムでnp.uniqueは、私の答えで説明されているように呼び出すことは、2つのフレーバーのいずれかを使用するよりもわずかに高速ですnp.lexsort。そして、一意を見つける配列が形をしている場合は、約5倍速くなります(10000, 100)np.uniqueいくつかの(マイナー)実行時間をトリムするために何を再実装することを決定した場合でも、すべての行を単一のオブジェクトに折りたたむとnp.any、特に列数が多い場合に、列の比較を呼び出さなくても比較が速くなります。
Jaime

@cge:おそらく、標準の「any」ではなく「np.any」を意味し、キーワード引数を取りません。
M.トーヤ

@Jaime- ジョーキントンが彼の回答で行ったように、私dtypea.dtype、つまり、表示されているデータのデータ型が正しいと信じています。多くの列がある場合、使用を高速化する別の(不完全な!)方法lexsortは、少数の列のみでソートすることです。どの列が完全にソートするのに十分な分散を提供するかを知る必要があるため、これはデータ固有です。たとえばa.shape = (60000, 500)、最初の3列で並べ替えますind = np.lexsort((a[:, 2], a[:, 1], a[:, 0]))。時間の節約はかなり大きなものですが、免責事項はすべてのケースに対応できるわけではありません。データによって異なります。
n1k31t4 2018年


9

私は速度の提案された代替案を比較しましたが、驚くべきことに、ボイドビューuniqueソリューションはnumpyの引数unique付きネイティブよりも少し高速であることがわかりましたaxis。スピードを求めているなら、

numpy.unique(
    a.view(numpy.dtype((numpy.void, a.dtype.itemsize*a.shape[1])))
    ).view(a.dtype).reshape(-1, a.shape[1])

ここに画像の説明を入力してください


プロットを再現するコード:

import numpy
import perfplot


def unique_void_view(a):
    return numpy.unique(
        a.view(numpy.dtype((numpy.void, a.dtype.itemsize*a.shape[1])))
        ).view(a.dtype).reshape(-1, a.shape[1])


def lexsort(a):
    ind = numpy.lexsort(a.T)
    return a[ind[
        numpy.concatenate((
            [True], numpy.any(a[ind[1:]] != a[ind[:-1]], axis=1)
            ))
        ]]


def vstack(a):
    return numpy.vstack({tuple(row) for row in a})


def unique_axis(a):
    return numpy.unique(a, axis=0)


perfplot.show(
    setup=lambda n: numpy.random.randint(2, size=(n, 20)),
    kernels=[unique_void_view, lexsort, vstack, unique_axis],
    n_range=[2**k for k in range(15)],
    logx=True,
    logy=True,
    xlabel='len(a)',
    equality_check=None
    )

1
非常に良い答え、1つのマイナーなポイント:vstack_dict、dictを使用しないでvstatck_setください。以来、vstack_dictパフォーマンスラインはあちこちグラフのために欠けている、それがちょうどでカバーされているように見えるvstack_set、彼らはとても似ていることから、パフォーマンスグラフ!
Akavall 2017

返信いただきありがとうございます。1つのvstackバリアントのみを含めるようにプロットを改善しました。
NicoSchlömer2017

8

線形代数またはベクトル空間の意味で浮動小数点配列を処理するものはなく、2つの行が「等しい」とは「some以内」を意味するため、これらの回答はどれも好きではありませんでした。許容範囲のしきい値を持つ1つの回答https://stackoverflow.com/a/26867764/500207は、しきい値を要素単位と10進数の両方と見なしました精度に設定しました。これは、いくつかのケースでは機能しますが、真のベクトル距離。

これが私のバージョンです:

from scipy.spatial.distance import squareform, pdist

def uniqueRows(arr, thresh=0.0, metric='euclidean'):
    "Returns subset of rows that are unique, in terms of Euclidean distance"
    distances = squareform(pdist(arr, metric=metric))
    idxset = {tuple(np.nonzero(v)[0]) for v in distances <= thresh}
    return arr[[x[0] for x in idxset]]

# With this, unique columns are super-easy:
def uniqueColumns(arr, *args, **kwargs):
    return uniqueRows(arr.T, *args, **kwargs)

上記のパブリックドメイン関数は、行の各ペアscipy.spatial.distance.pdist間のユークリッド(カスタマイズ可能)距離を見つけるために使用します。次に、それぞれの距離を古い値と比較して、互いの範囲内にある行を見つけ、それぞれから1行だけを返しますthreshthreshthreshクラスター。

示唆したように、距離metric必要がEuclidean-ができないpdistなど雑貨距離を計算することができるcityblock(マンハッタンノルム)とcosine(ベクトル間の角度ます。

thresh=0(デフォルト)の場合、「一意」と見なされるには、行がビット完全である必要があります。threshスケールされたマシン精度を使用するためのその他の適切な値、つまりthresh=np.spacing(1)*1e3


ベストアンサー。ありがとう。これは、これまでに書かれた(数学的に)最も一般的な答えです。行列をN次元空間のデータポイントまたはサンプルのセットと見なし、同じまたは類似したポイントのコレクションを見つけます(類似性はユークリッド距離または他の方法で定義されます)。これらのポイントは、重複するデータポイントまたは非常に近接している可能性があります。最後に、同じまたは類似したポイントのコレクションは、同じセットに属するポイント(上記の回答では最初のポイント)のいずれかに置き換えられます。これは、点群からの冗長性を減らすのに役立ちます。
Sanchit

@Sanchit aha、それは良い点です。「最初の」点(実際には、Pythonが点をに格納する方法に依存するため、事実上ランダムである可能性がありますset)を各threshサイズの近傍の代表として選択するのではなく、関数はユーザーなど、心に最も近い「中央値」やポイントを使用し、例えば、そのポイントを選択する方法を指定する
アーメドFasih

承知しました。間違いない。これはあなたのプログラムがやっていることなので、最初のポイントについて述べました。
Sanchit

ただの訂正ですthresh。-の順序付けされていない性質のために、各クラスターに対して選択される行はランダムになると上記で誤って述べましたset。もちろん、これは私の側の頭脳です。setストアはthresh-neighborhoodにあるインデックスのタプルを格納するので、これfindRows 実際には、各thresh-clusterの最初の行を返します。
Ahmed Fasih 2016

3

drop_duplicatesパンダから使用しないのはなぜですか:

>>> timeit pd.DataFrame(image.reshape(-1,3)).drop_duplicates().values
1 loops, best of 3: 3.08 s per loop

>>> timeit np.vstack({tuple(r) for r in image.reshape(-1,3)})
1 loops, best of 3: 51 s per loop

私は実際にこの答えが大好きです。もちろん、それは直接numpyを使用しませんが、私にとっては、高速でありながら理解しやすいものです。
noctilux 2017年

3

numpy_indexedパッケージは、(免責事項:私はその作者午前)素敵にハイメによって掲示ソリューションとテストインタフェースに加え、多くの機能をラップします:

import numpy_indexed as npi
new_a = npi.unique(a)  # unique elements over axis=0 (rows) by default

1

np.uniqueはタプルのリストが与えられると動作します:

>>> np.unique([(1, 1), (2, 2), (3, 3), (4, 4), (2, 2)])
Out[9]: 
array([[1, 1],
       [2, 2],
       [3, 3],
       [4, 4]])

リストのリストを使用すると、 TypeError: unhashable type: 'list'


私の場合は動作しないようです。各タプルは2つの浮動小数点数ではなく2つの文字列です
mjp

機能しません。タプルではなく要素のリストを返します
Mohanad Kaleia '10 / 07/10

1

このページの回答に基づいて、MATLABのunique(input,'rows')関数の機能を複製する関数を記述し、一意性をチェックするための許容誤差を受け入れる追加機能を追加しました。また、そのインデックスは、このような返しc = data[ia,:]data = c[ic,:]。矛盾やエラーがある場合は報告してください。

def unique_rows(data, prec=5):
    import numpy as np
    d_r = np.fix(data * 10 ** prec) / 10 ** prec + 0.0
    b = np.ascontiguousarray(d_r).view(np.dtype((np.void, d_r.dtype.itemsize * d_r.shape[1])))
    _, ia = np.unique(b, return_index=True)
    _, ic = np.unique(b, return_inverse=True)
    return np.unique(b).view(d_r.dtype).reshape(-1, d_r.shape[1]), ia, ic

1

@Jaimeの優れた回答を超えて、行を折りたたむ別の方法は、に等しいを使用することですa.strides[0]aC隣接であると想定)a.dtype.itemsize*a.shape[0]。さらにvoid(n)のショートカットですdtype((void,n))。私たちはついにこの最短バージョンにたどり着きました:

a[unique(a.view(void(a.strides[0])),1)[1]]

ために

[[0 1 1 1 0 0]
 [1 1 1 0 0 0]
 [1 1 1 1 1 0]]

0

3D以上の多次元のネストされた配列のような一般的な目的のために、これを試してください:

import numpy as np

def unique_nested_arrays(ar):
    origin_shape = ar.shape
    origin_dtype = ar.dtype
    ar = ar.reshape(origin_shape[0], np.prod(origin_shape[1:]))
    ar = np.ascontiguousarray(ar)
    unique_ar = np.unique(ar.view([('', origin_dtype)]*np.prod(origin_shape[1:])))
    return unique_ar.view(origin_dtype).reshape((unique_ar.shape[0], ) + origin_shape[1:])

2Dデータセットを満たす:

a = np.array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])
unique_nested_arrays(a)

与える:

array([[0, 1, 1, 1, 0, 0],
   [1, 1, 1, 0, 0, 0],
   [1, 1, 1, 1, 1, 0]])

しかし、次のような3D配列:

b = np.array([[[1, 1, 1], [0, 1, 1]],
              [[0, 1, 1], [1, 1, 1]],
              [[1, 1, 1], [0, 1, 1]],
              [[1, 1, 1], [1, 1, 1]]])
unique_nested_arrays(b)

与える:

array([[[0, 1, 1], [1, 1, 1]],
   [[1, 1, 1], [0, 1, 1]],
   [[1, 1, 1], [1, 1, 1]]])

unique return_indexJaimeと同じように使用すると、最後のreturn行が簡単になります。オリジナルarを右軸にインデックス付けします。
hpaulj

0

これらの答えはどれもうまくいきませんでした。私の一意の行には数字ではなく文字列が含まれていると想定しています。しかし、別のスレッドからのこの答えはうまくいきました:

ソース:https : //stackoverflow.com/a/38461043/5402386

.count()および.index()リストのメソッドを使用できます

coor = np.array([[10, 10], [12, 9], [10, 5], [12, 9]])
coor_tuple = [tuple(x) for x in coor]
unique_coor = sorted(set(coor_tuple), key=lambda x: coor_tuple.index(x))
unique_count = [coor_tuple.count(x) for x in unique_coor]
unique_index = [coor_tuple.index(x) for x in unique_coor]

0

実際にmxn数値numpy配列をmx 1 numpy文字列配列に変換できます。次の関数を使用してみてください。これは、numpy.uniqueと同じようにcountinverse_idxなどを提供します

import numpy as np

def uniqueRow(a):
    #This function turn m x n numpy array into m x 1 numpy array storing 
    #string, and so the np.unique can be used

    #Input: an m x n numpy array (a)
    #Output unique m' x n numpy array (unique), inverse_indx, and counts 

    s = np.chararray((a.shape[0],1))
    s[:] = '-'

    b = (a).astype(np.str)

    s2 = np.expand_dims(b[:,0],axis=1) + s + np.expand_dims(b[:,1],axis=1)

    n = a.shape[1] - 2    

    for i in range(0,n):
         s2 = s2 + s + np.expand_dims(b[:,i+2],axis=1)

    s3, idx, inv_, c = np.unique(s2,return_index = True,  return_inverse = True, return_counts = True)

    return a[idx], inv_, c

例:

A = np.array([[ 3.17   9.502  3.291],
  [ 9.984  2.773  6.852],
  [ 1.172  8.885  4.258],
  [ 9.73   7.518  3.227],
  [ 8.113  9.563  9.117],
  [ 9.984  2.773  6.852],
  [ 9.73   7.518  3.227]])

B, inv_, c = uniqueRow(A)

Results:

B:
[[ 1.172  8.885  4.258]
[ 3.17   9.502  3.291]
[ 8.113  9.563  9.117]
[ 9.73   7.518  3.227]
[ 9.984  2.773  6.852]]

inv_:
[3 4 1 0 2 4 0]

c:
[2 1 1 1 2]

-1

numpy行列全体をリストとして取得し、このリストから重複を削除して、最後に一意のリストをnumpy行列に戻します。

matrix_as_list=data.tolist() 
matrix_as_list:
[[1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 0, 0], [0, 1, 1, 1, 0, 0], [1, 1, 1, 0, 0, 0], [1, 1, 1, 1, 1, 0]]

uniq_list=list()
uniq_list.append(matrix_as_list[0])

[uniq_list.append(item) for item in matrix_as_list if item not in uniq_list]

unique_matrix=np.array(uniq_list)
unique_matrix:
array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 0]])

-3

最も簡単な解決策は、行を文字列にすることによって行を単一の項目にすることです。次に、各行を全体として、numpyを使用してその一意性を比較できます。このソリューションは一般化可能であり、他の組み合わせのために配列を再形成および転置する必要があるだけです。これは、提供された問題の解決策です。

import numpy as np

original = np.array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])

uniques, index = np.unique([str(i) for i in original], return_index=True)
cleaned = original[index]
print(cleaned)    

あげる:

 array([[0, 1, 1, 1, 0, 0],
        [1, 1, 1, 0, 0, 0],
        [1, 1, 1, 1, 1, 0]])

ノーベル賞をメールで送ってください


印刷オプションが異なるなど、非常に非効率的でエラーが発生しやすい。他のオプションが明らかに望ましいです。
マイケル

-3
import numpy as np
original = np.array([[1, 1, 1, 0, 0, 0],
                     [0, 1, 1, 1, 0, 0],
                     [0, 1, 1, 1, 0, 0],
                     [1, 1, 1, 0, 0, 0],
                     [1, 1, 1, 1, 1, 0]])
# create a view that the subarray as tuple and return unique indeies.
_, unique_index = np.unique(original.view(original.dtype.descr * original.shape[1]),
                            return_index=True)
# get unique set
print(original[unique_index])
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.