2D配列(numpy.ndarray)の隣接要素をグループ化

今までのグルーピングテクニックを流用すれば,ループを使わずに高速処理できそう(後述).
ただ,どう考えても回答のやり方の方が簡単だし分かり易い.

Grouping adjacent equal elements of a 2D numpy array – StackOverflow

import numpy as np
from scipy.ndimage import label

a = np.array(
    [
        [12,12,14,14,11,11],
        [10,10,11,11,11,11],
        [10,14,14,10,11,13],
        [12,12,14,13,13,13]
    ]
)

values = np.unique(a.ravel())
offset = 0
result = np.zeros_like(a)
for v in values:
  labeled, num_features = label(a == v)
  result += labeled + offset*(labeled > 0)
  offset += num_features
print(result)

[[4 4 7 7 3 3]
[1 1 3 3 3 3]
[1 8 8 2 3 6]
[5 5 8 6 6 6]]

 

・ループを使わない方法(Numpyな方法) 
軸を合わして処理するのが面倒なので,方法論だけ.

u_a = np.unique(a)
a[..., np.newaxis] == u_a

array([[[False, False, True, False, False],
[False, False, True, False, False],
[False, False, False, False, True],
[False, False, False, False, True],
[False, True, False, False, False],
[False, True, False, False, False]],

   [[ True, False, False, False, False],
    [ True, False, False, False, False],
    [False,  True, False, False, False],
    [False,  True, False, False, False],
    [False,  True, False, False, False],
    [False,  True, False, False, False]],

   [[ True, False, False, False, False],
    [False, False, False, False,  True],
    [False, False, False, False,  True],
    [ True, False, False, False, False],
    [False,  True, False, False, False],
    [False, False, False,  True, False]],

   [[False, False,  True, False, False],
    [False, False,  True, False, False],
    [False, False, False, False,  True],
    [False, False, False,  True, False],
    [False, False, False,  True, False],
    [False, False, False,  True, False]]], dtype=bool)

ブロードキャストを用いれば,各ユニーク値のブーリアンが得られる.
例えば,

array([[[False, False, True, False, False],
[False, False, True, False, False],
[False, False, False, False, True],
[False, False, False, False, True],
[False, True, False, False, False],
[False, True, False, False, False]],

は1行目に対して,ユニーク値([10, 11, 12, 13, 14])と比較した結果.

「numpy.argwhere()」で

np.argwhere(a[..., np.newaxis] == u_a)

array([[0, 0, 2],
[0, 1, 2],
[0, 2, 4],
[0, 3, 4],
[0, 4, 1],
[0, 5, 1],
[1, 0, 0],
[1, 1, 0],
[1, 2, 1],
[1, 3, 1],
[1, 4, 1],
[1, 5, 1],
[2, 0, 0],
[2, 1, 4],
[2, 2, 4],
[2, 3, 0],
[2, 4, 1],
[2, 5, 3],
[3, 0, 2],
[3, 1, 2],
[3, 2, 4],
[3, 3, 3],
[3, 4, 3],
[3, 5, 3]])

インデックスを得て,3列目, 2列目,1列目の順でソートすれば,

ind = np.argwhere(a[..., np.newaxis] == u_a)
ind = ind[np.lexsort((ind[:, 1], ind[:, 0], ind[:, 2]))]
ind

array([[1, 0, 0],
[1, 1, 0],
[2, 0, 0],
[2, 3, 0],
[0, 4, 1],
[0, 5, 1],
[1, 2, 1],
[1, 3, 1],
[1, 4, 1],
[1, 5, 1],
[2, 4, 1],
[0, 0, 2],
[0, 1, 2],
[3, 0, 2],
[3, 1, 2],
[2, 5, 3],
[3, 3, 3],
[3, 4, 3],
[3, 5, 3],
[0, 2, 4],
[0, 3, 4],
[2, 1, 4],
[2, 2, 4],
[3, 2, 4]])

だいぶ,目的の形に近づく.

ind = np.argwhere(a[..., np.newaxis] == u_a)
ind = ind[np.lexsort((ind[:, 1], ind[:, 0], ind[:, 2]))]
x = np.concatenate((np.array([0, 0, 0]).reshape(1, -1), np.diff(ind, axis=0)))
indind = np.zeros_like(a)
indind[ind[:, 0], ind[:, 1]] = np.piecewise(x, [abs(x)<=1, ], [0, 1]).any(-1).cumsum()
indind

array([[4, 4, 8, 8, 2, 2],
[0, 0, 3, 3, 3, 3],
[0, 9, 9, 1, 3, 6],
[5, 5, 9, 7, 7, 7]])

このままでも,だいぶいいところまではいくけども,
ちゃんとした結果を求めるには,もうちょっとちゃんとしないといけない.
(まあ,こんなのに惜しいも何も無いけど)

今は行と列を一緒にして適当に処理しているけど,
行と列別々に差をみて,logical_andしてあげればいけそう.

 
 

import seaborn as sns

sns.heatmap(a, annot=True)

FireShot Capture 786 - Untitled28.ipynb - Colaboratory_ - https___colab.research.google.com_

広告
カテゴリー: 未分類 パーマリンク

2D配列(numpy.ndarray)の隣接要素をグループ化 への1件のフィードバック

  1. ピンバック: 2D配列(numpy.ndarray)の隣接要素をグループ化(クラスタ化) | 粉末@それは風のように (日記)

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください