PythonProgramozás

Egy 2D numpy tömb összes minimumának megkeresése.

2021. október 31. 15:00 - Madg

Egy 2D numpy tömb összes minimumának megkeresése.

 

A 2D-s tömböket pixelekből felépített digitális (szürkeárnyalatos) képként képzelhetjük el. Minden egyes pixelhez tartozik egy érték, amely a fényességet jelöli. Ezek az értékek egy mátrixban vannak ábrázolva, ahol a pixelek pozíciói a két tengelyre vannak leképezve. Ha meg akarjuk találni a legsötétebb pontokat, meg kell vizsgálnunk az egyes pontok szomszédait.


1. módszer:


Ezt úgy lehet elvégezni, hogy minden egyes cellára vonatkozóan minden egyes [i,j] cellán iterálva ellenőrizzük. Ha az összes szomszéd nagyobb, mint az aktuális cella, akkor az egy lokális minimum. Ez a megközelítés nem optimális, mivel a szomszédos cellákon redundáns számításokat kell elvégezni.

2. módszer: Az "és" operátor használata

 

Az első lépés a tömb globális maximumának hozzáadása a tömb környezetéhez, hogy amikor az elemenkénti vizsgálat eléri a tömb "szélét", az összehasonlítás működjön. Mivel az aktuális cellát az előző és a következő cellával hasonlítjuk össze, a tengelyek végén hibaüzenet keletkezne. A lokális minimum mindig kisebb lesz, mint a globális maximum, így az összehasonlításunk jól fog működni. Ezután végigmegyünk a tömb celláin, elvégezve az összehasonlítást. A redundáns számítások csökkentése érdekében logikai "és" műveletet használunk, így ha valamelyik feltétel nem teljesül, az algoritmus nem végzi el a további összehasonlítást.
A feltételeknek megfelelő elemek indexeit egy tuple listában gyűjtjük össze. Vegyük észre, hogy az eredeti tömb indexei különböznek a kibővített tömb indexeitől! Ezért az indexeket -1-gyel csökkentjük.

import numpy as np

data = np.array([[-210, 2, 0, -150],

[4, -1, -60, 10],

[0, 0, -110, 10],

[-50, -11, -2, 10]])

 

a = np.pad(data, (1, 1), mode='constant', constant_values=(np.amax(data), np.amax(data)))

loc_min = []

rows = a.shape[0]

cols = a.shape[1]

 

for ix in range(0, rows - 1):

for iy in range(0, cols - 1):

if a[ix, iy] < a[ix, iy + 1] and a[ix, iy] < a[ix, iy - 1] and \

a[ix, iy] < a[ix + 1, iy] and a[ix, iy] < a[ix + 1, iy - 1] and \

a[ix, iy] < a[ix + 1, iy + 1] and a[ix, iy] < a[ix - 1, iy] and \

a[ix, iy] < a[ix - 1, iy - 1] and a[ix, iy] < a[ix - 1, iy + 1]:

temp_pos = (ix-1, iy-1)

loc_min.append(temp_pos)

print(loc_min)

 

3. módszer: A scipy ndimage minimum szűrőjének használata

 

Szerencsére erre a feladatra is van egy scipy függvény:
A scipy.ndimage.minimum_filter(input, size=None, footprint=None, output=None, mode='reflect', cval=0.0, origin=0) egy boolean tömböt hoz létre, ahol a helyi minimumok 'True' értékűek. A 'size' paramétert használjuk, amely megadja a bemeneti tömbből minden egyes elem pozíciójában vett alakot, hogy meghatározzuk a szűrőfüggvény bemenetét. A footprint egy boolean tömb, amely (implicit módon) egy alakzatot határoz meg, de azt is, hogy az alakzaton belül mely elemek kerülnek átadásra a szűrőfüggvénynek. A mode paraméter határozza meg, hogy a bemeneti tömb hogyan bővüljön, amikor a szűrő átfed egy szegélyt. A bemeneti tömb dimenzióinak számával megegyező hosszúságú módok sorozatának átadásával minden tengely mentén különböző módok adhatók meg. Itt a 'konstans' paraméter van megadva, így a bemenet a határon túli összes értéket a 'cval' paraméter által megadott konstans értékkel tölti ki. A 'cval' értéke a globális maximumra van beállítva, így biztosítva, hogy a határon lévő lokális minimumok is megtalálhatók legyenek. A szűrők működésével kapcsolatos részletesebb információkért lásd a scipy dokumentációt. Ezután ellenőrizzük, hogy mely cellák "True" értékűek, így az összes helyi minimum indexe egy tömbben van.

import numpy as np

from scipy.ndimage.filters import minimum_filter

 

data = np.array([[2, 100, 1000, -5],

[-10, 9, 1800, 0],

[112, 10, 111, 100],

[50, 110, 50, 140]])

 

minima = (data == minimum_filter(data, 3, mode='constant', cval=0.0))

# print(data)

# print(minima)


res = np.where(1 == minima)

print(res)

 

Összefoglaló:

 

Mint fentebb láttuk, többféleképpen is megkereshetjük a helyi minimumokat egy numpy tömbben, de mint mindig, most is hasznos külső könyvtárakat használni ehhez a feladathoz.

Szólj hozzá!

Lokális minimumok 1D Numpy tömbökben

2021. október 10. 12:18 - Madg

Hogyan lehet megtalálni a lokális minimumokat az 1D NumPy tömbökben?

 

Egy függvény szélső helye az az x érték, amelynél a függvény értéke a legnagyobb vagy legkisebb egy adott intervallumban vagy a teljes értelmezési tartományban.
Az f(x)-nek akkor van lokális maximuma x0-ban, ha van olyan környezet, hogy ebben a környezetben bármely x-re f(x) ≥ f(x0). Van f(x) lokális minimuma x0-ban, ha van olyan környezet, hogy ebben a környezetben bármely x-re f(x) ≤ f(x0).
Egy f(x) függvénynek ugyanis több lokális szélsőértéke is lehet. Minden globális szélsőérték egyben lokális is, de fordítva természetesen ez nem igaz.
Ezeket az értékeket gyakran nevezik "csúcsoknak", mert ezek a függvény grafikonján megjelenő "hegyek" és "völgyek" csúcsai.
Ezeknek a pontoknak a gyakorlati alkalmazása alapvető fontosságú, például a képfeldolgozásban és a jelfeldolgozásban, például a földönkívüli üzenetek felderítésében! :)
Ebben a cikkben megnézünk néhány egyszerű módszert arra, hogyan találhatunk mélyedéseket egy numpy tömbben csak a numpy beépített függvényeivel, vagy a scipy könyvtár segítségével.

Az összes minimum egy 1D numpy tömbben.


A helyi minimumok olyan pontok, amelyeket mindkét oldalon nagyobb értékek vesznek körül.
Természetesen sokféleképpen megoldható a feladat, használhatsz tiszta numpy-t, végighaladhatsz az adatokon, vagy használhatod a scipy könyvtárat.
A Githubon találtam egy remek megoldást, Benjamin Schmidt munkáját, ami nagyon jól mutatja a lokális szélsőérték definícióját.


1. módszer: A numpy.where használatával

Kód:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace (0, 50, 1000)
y = 0.75 * np.sin(x)

peaks = np.where((y[1:-1] > y[0:-2]) * (y[1:-1] > y[2:]))[0] + 1
dips = np.where((y[1:-1] < y[0:-2]) * (y[1:-1] < y[2:]))[0] + 1


plt.plot (x, y)
plt.plot (x[peaks], y[peaks], 'o')
plt.plot (x[dips], y[dips], 'o')

plt.show()

 

A fentiekben egy listát készítünk az összes olyan indexről, ahol y[i] értéke nagyobb, mint mindkét szomszédja.
Nem ellenőrzi a végpontokat, amelyeknek csak egy-egy szomszédjuk van.
A plusz +1 a végén azért szükséges, mert a where az y[1:-1] szeleten belüli indexeket találja meg, nem pedig a teljes y tömböt. A [0] azért szükséges, mert a where egy tömbökből álló tuple-t ad vissza, ahol az első elem a kívánt tömb.
A matplotlib könyvtárat használjuk a grafikon elkészítéséhez.

2. módszer: A numpy.diff használata

 

A megoldás másik egyszerű megközelítése a numpy beépített függvényének, a "numpy.diff"-nek a használata.

Kód:

 

import numpy as np
# define an array

arr = np.array([1, 3, 7, 1, 2, 6, 0, 1, 6, 0, -2, -5, 18])

# What "numpy.diff" does, and what is the type of the result?

#print((np.diff(arr), type(np.diff(arr))))

# What "numpy.sign" does?

#print(np.sign(np.diff(arr)))


peaks = np.diff(np.sign(np.diff(arr)))

#print(peaks)

local_minima_pos = np.where(peaks == 2)[0] + 1
print(local_minima_pos)

 

Definiálunk egy 1D tömböt "arr", majd jön egy egysoros. Ebben először is kiszámítjuk az egyes elemek közötti különbségeket. (np.diff(arr). Ezután a "numpy.sign" függvényt használjuk ezen a tömbön, így megkapjuk a különbségek előjelét. (azaz: -1 vagy 1). Az egészet átadjuk egy másik "numpy.diff" függvénynek, amely +2 vagy -2 vagy 0 értéket ad vissza. 0 érték folyamatos csökkenést vagy növekedést, -2 érték maximumot, +2 érték pedig minimumot jelez. Most már megvannak a csúcsok, és a numpy.where megmondja a pozíciókat. (Figyeljük meg a +1-et a sor végén, ez azért van, mert a csúcsok tömb 0. eleme az arr tömb 0. és 1. eleme közötti különbség. A [0] azért szükséges, mert a "numpy.where" egy tömbökből álló tuple-t ad vissza, ahol az első elem az általunk kívánt tömb).

3. módszer: Megoldás scipy-vel:


Az utolsó példában azt szeretném bemutatni, hogy a scipy könyvtár segítségével hogyan oldható meg a probléma egyetlen sorban.

Kód:

import numpy as np

from scipy.signal import argrelextrema

 

x = np.linspace (0, 50, 100)

y = np.sin(x)

 

#print(y)

 

print(argrelextrema(y, np.less))

 

A következő bejegyzésben a 2D-s tömbök lokális minimumaival folyatatom.

 

 


 

 

Szólj hozzá!
süti beállítások módosítása