Prüfen ob array in array ist

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Squipy
User
Beiträge: 39
Registriert: Sonntag 30. Juni 2019, 16:42

Hallo Zusammen,

als ich angefangen habe hielt ich es für einfach aber jetzt bin ich am verzweifeln.

Ich möchte prüfen ob ein np array in einem anderen enthalten ist. Das Problem ist, die Reihenfolge muss die selbe sein. So einfach wie unten funktionierts wohl leider nicht:

Code: Alles auswählen


a = np.array([1,2,3,4,5,6,7,8,9])
b = np.array([1,2])

print(a==b)
Ich habe zwar die np.isin() funktion gefunden, diese ignoriert allerdings die Reihenfolge

Code: Alles auswählen

a = np.array([1,2,3,4,5,6,7,8,9])
b = np.array([1,3])

print(np.isin(b,a))
>>[ True True ]
Hat sonst jemand eine effiziente Idee?
Besten Dank!
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Du warst nah dran:

Code: Alles auswählen

import numpy as np

a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
b = np.array([4, 5])

mask = np.isin(a, b)
print(mask)

print(a[mask])


[ True  True False False False False False False False]
[4 5]
Man muss nur die entstandenen Wahrheits Matrix benutzen um die gewünschten Werte aus dem ursprünglichen Array "auszustanzen"
Squipy
User
Beiträge: 39
Registriert: Sonntag 30. Juni 2019, 16:42

Danke Rogerb,
das hilft schonmal weiter. Was ich aber eigentlich will, ist über mehrere arrays iterieren und prüfen ob ein teilarray enthalten ist.

Mit einem Wert klappt das ja super:

Code: Alles auswählen

a = np.array([1,2,3,4,5,6,7,8,9])
b = np.array([1])

if b in a:
    doAnything =None
sobald aber b aus mehreren einträgen besteht erhalte ich einen error, dass das in Zukunft ein Error verursachen wird :D

Code: Alles auswählen

a = np.array([1,2,3,4,5,6,7,8,9])
b = np.array([1,2])

if b in a:
    doAnything =None
    
>>12: DeprecationWarning: elementwise comparison failed; this will raise an error in the future.
Benutzeravatar
snafu
User
Beiträge: 6867
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

isin() liefert ein Array mit Wahrheitswerten inwieweit einzelne Elemente enthalten sind. Will man wissen ob alle Elemente enthalten sind, dann braucht man all().

Code: Alles auswählen

a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
b = np.array([9, 1, 5])
c = np.array([9, 1, 5, 11])

print(np.isin(b, a).all())
print(np.isin(c, a).all())

# Auch ohne array() geht es
print(np.isin([2, 4, 6], a).all())
Folglich für ein bedingte Anweisung:

Code: Alles auswählen

if np.isin(b, a).all():
    # Do something
Ein "b in a" sollte man nicht verwenden, da es langsamer und auch deprecated ist.
Squipy
User
Beiträge: 39
Registriert: Sonntag 30. Juni 2019, 16:42

Das ignoriert aber leider wieder die Reihenfolge.
Das hier sollte False ergeben:

Code: Alles auswählen

a = np.array([1,2,3,4,5,6,7,8,9])
b = np.array([1,3])

print(np.isin(b, a).all())
>> True
Squipy
User
Beiträge: 39
Registriert: Sonntag 30. Juni 2019, 16:42

Habe es nun so gelöst

Code: Alles auswählen

FullArr = np.array([1,2,3,4,5,6,7,8,9])
partArr = np.array([0,2])


def CheckArrInArr(partArr,FullArr):
    checkList = np.isin(FullArr, partArr)
    checkList=np.where(checkList == True)
    checkList = np.diff(checkList)
    if checkList.size==0:
        return False    
    elif checkList.max()>1:
        return False
    else:
        return True

print(CheckArrInArr(partArr,FullArr)
Ob es elegant ist sei mal dahin gestellt...
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

@Squipy: Variablennamen schreibt man wie Funktionen klein_mit_unterstrich. checkList enthält schon Wahrheitswerte. Das nochmal mit True zu vergleichen, ist unnötig. Dann tut Dein Ansatz aus vielerlei Gründen nicht. Such mal 4,3. Wenn im vollen Array eine Zahl mehrfach vorkommt geht es auch nicht.
Squipy
User
Beiträge: 39
Registriert: Sonntag 30. Juni 2019, 16:42

Warum ich FullArr groß geschrieben habe weiß ich auch nicht, danke für den Hinweis.
dass es so nicht funktioniert musste ich aus den von dir genannten Gründen leider auch schon feststellen...

Ich komm einfach nicht drauf wie man es sonst lösen kann... Die Problemstellung kam mir zunächst recht simpel vor. -.-
Benutzeravatar
snafu
User
Beiträge: 6867
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Was ist denn der genaue Hintergrund? Suchst du Elemente aus einem bestimmten Bereich?

Dann kommst du zB so an die Elemente zwischen 5 und 8:

Code: Alles auswählen

a[(a >= 5) & (a <= 8)]
Squipy
User
Beiträge: 39
Registriert: Sonntag 30. Juni 2019, 16:42

Der Hintergrund ist, dass ich pürfen will ob ein Teilarray in einem beliebig großen array enthalten ist. Da es sich um Messdaten handelt, ist die Reihenfolge wichtig.


Nächster Versuch:

Code: Alles auswählen

def check_arr_in_arr(part_arr,full_arr):
    i = 0
    j = len(partArr)
    while j < len(full_arr):
        full_arr_check = full_arr[i:j]
        if np.array_equal(full_arr_check,part_arr):
            return True
        else:
            i+=1
            j+=1
    return False
Wobei das wohl nicht sehr effizient ist ...
Zuletzt geändert von Squipy am Samstag 30. November 2019, 11:33, insgesamt 2-mal geändert.
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

Du bist nicht allein mit deinem Problem. https://stackoverflow.com/questions/710 ... f-subarray
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Einen Versuch hab ich noch:

Wenn ich dich richtig verstehe, willst du prüfen, ob die Messdaten als zusammenhängender Bereich Teil des Ganzen sind.
Die Reigenfolge muss also stimmen und es darf auch keine Lücken geben indenen die Werte abweichen.

Dann würde ich den Teilarray über den Vergleichsarray schieben und bei Übereinstimmung True zurückgeben:

Code: Alles auswählen

def check_arr_in_arr(part_arr, full_arr):
    part_length = len(part_arr)
    full_length = len(full_arr)
    for i in range(full_length-part_length):
        if (part_arr == full_arr[i:i+part_length]).all():
            return True

    return False
Also das ist eigentlich deine Lösung nur ohne while-Schleife
Benutzeravatar
snafu
User
Beiträge: 6867
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Aber mit range() ist es ja eigentlich nicht im Sinne des Erfinders, wenn man schon NumPy benutzt. Der Ansatz aus dem Link war doch schon ganz gut. Man muss das nur noch etwas anpassen:

Code: Alles auswählen

from numpy.lib.stride_tricks import as_strided
import numpy as np

def rolling_window(arr, size):
    shape = arr.shape[:-1] + (arr.shape[-1] - size + 1, size)
    strides = arr.strides + (arr.strides[-1],)
    return as_strided(a, shape=shape, strides=strides)

def is_subarray(sub, arr):
    window = rolling_window(arr, len(sub))
    return (window == sub).all(axis=1).any()

a = np.array([1,2,3,4,5,6,7,8,9])
b = np.array([4,5,6])
print(is_subarray(b, a))
Benutzeravatar
snafu
User
Beiträge: 6867
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wenn man das immer auf Grundlage eines eindimensionalen Arrays macht, dann könnte man es noch etwas verkürzen:

Code: Alles auswählen

from numpy.lib.stride_tricks import as_strided

def is_subarray(sub, arr):
    shape = (len(arr) - len(sub) + 1, len(sub))
    window = as_strided(arr, shape, arr.strides * 2)
    return (window == sub).all(axis=1).any()
Hintergrundwissen zu Strides:
https://www.jessicayung.com/numpy-array ... d-strides/
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Stimmt, das ist in der Tat um einiges schneller
Antworten