So bestimmen Sie, ob eine Pandas-Spalte einen bestimmten Wert enthält

154

Ich versuche festzustellen, ob es in einer Pandas-Spalte einen Eintrag gibt, der einen bestimmten Wert hat. Ich habe versucht, dies mit zu tun if x in df['id']. Ich dachte, das funktioniert, außer wenn ich einen Wert eingegeben habe, von dem ich wusste, dass er nicht in der Spalte enthalten ist 43 in df['id'], die immer noch zurückgegeben wird True. Wenn ich zu einem Datenrahmen untergebe, der nur Einträge enthält, die mit der fehlenden ID übereinstimmen, df[df['id'] == 43]sind offensichtlich keine Einträge darin. Wie bestimme ich, ob eine Spalte in einem Pandas-Datenrahmen einen bestimmten Wert enthält und warum funktioniert meine aktuelle Methode nicht? (Zu Ihrer Information, ich habe das gleiche Problem, wenn ich die Implementierung in dieser Antwort auf eine ähnliche Frage verwende).

Michael
quelle

Antworten:

181

in einer Serie prüft, ob der Wert im Index enthalten ist:

In [11]: s = pd.Series(list('abc'))

In [12]: s
Out[12]: 
0    a
1    b
2    c
dtype: object

In [13]: 1 in s
Out[13]: True

In [14]: 'a' in s
Out[14]: False

Eine Möglichkeit besteht darin, festzustellen, ob es sich um eindeutige Werte handelt:

In [21]: s.unique()
Out[21]: array(['a', 'b', 'c'], dtype=object)

In [22]: 'a' in s.unique()
Out[22]: True

oder ein Python-Set:

In [23]: set(s)
Out[23]: {'a', 'b', 'c'}

In [24]: 'a' in set(s)
Out[24]: True

Wie von @DSM hervorgehoben, ist es möglicherweise effizienter (insbesondere, wenn Sie dies nur für einen Wert tun), die Werte direkt zu verwenden:

In [31]: s.values
Out[31]: array(['a', 'b', 'c'], dtype=object)

In [32]: 'a' in s.values
Out[32]: True
Andy Hayden
quelle
2
Ich möchte nicht wissen, ob es unbedingt einzigartig ist, hauptsächlich möchte ich wissen, ob es dort ist.
Michael
24
Ich denke 'a' in s.valuessollte für lange Serien schneller sein.
DSM
4
@AndyHayden Weißt du, warum 'a' in sPandas lieber den Index als die Werte der Serie überprüft? In Wörterbüchern überprüfen sie Schlüssel, aber eine Pandas-Serie sollte sich eher wie eine Liste oder ein Array verhalten, oder?
Lei
3
Ausgehend von Pandas 0.24.0, verwendet s.valuesund df.valuesist stark entstellt. Sehen Sie das . Auch s.valuesist in einigen Fällen tatsächlich viel langsamer.
Qusai Alothman
1
@QusaiAlothman weder noch .to_numpyoder .arrayin einer Serie verfügbar, daher bin ich mir nicht ganz sicher, welche Alternative sie befürworten (ich lese nicht "sehr entmutigt"). Tatsächlich sagen sie, dass .values ​​möglicherweise kein numpy-Array zurückgeben, z. B. im Fall eines kategorialen ... aber das ist in Ordnung, da ines immer noch wie erwartet funktioniert (in der Tat effizienter als das Gegenstück zum numpy-Array)
Andy Hayden
27

Sie können auch pandas.Series.isin verwenden, obwohl es etwas länger ist als 'a' in s.values:

In [2]: s = pd.Series(list('abc'))

In [3]: s
Out[3]: 
0    a
1    b
2    c
dtype: object

In [3]: s.isin(['a'])
Out[3]: 
0    True
1    False
2    False
dtype: bool

In [4]: s[s.isin(['a'])].empty
Out[4]: False

In [5]: s[s.isin(['z'])].empty
Out[5]: True

Dieser Ansatz kann jedoch flexibler sein, wenn Sie für einen DataFrame mehrere Werte gleichzeitig abgleichen müssen (siehe DataFrame.isin ).

>>> df = DataFrame({'A': [1, 2, 3], 'B': [1, 4, 7]})
>>> df.isin({'A': [1, 3], 'B': [4, 7, 12]})
       A      B
0   True  False  # Note that B didn't match 1 here.
1  False   True
2   True   True
Fest
quelle
Sie können auch die Funktion DataFrame.any () verwenden:s.isin(['a']).any()
6.
17
found = df[df['Column'].str.contains('Text_to_search')]
print(found.count())

Das found.count()Testament enthält die Anzahl der Übereinstimmungen

Und wenn es 0 ist, bedeutet dies, dass in der Spalte keine Zeichenfolge gefunden wurde.

Shahir Ansari
quelle
2
arbeitete für mich, aber ich benutzte len (gefunden), um die Zählung zu erhalten
kztd
1
Ja, len (gefunden) ist eine etwas bessere Option.
Shahir Ansari
1
Dieser Ansatz funktionierte für mich, aber ich musste die Parameter na=Falseund regex=Falsemeinen Anwendungsfall einbeziehen
Mabyn
1
String.contains führt jedoch eine Teilstringsuche durch. Beispiel: Wenn ein Wert namens "head_hunter" vorhanden ist. Das Übergeben von "head" in str.contains stimmt überein und gibt True, was falsch ist.
Karthikeyan
@ karthikeyan Es ist nicht falsch. Hängt vom Kontext Ihrer Suche ab. Was ist, wenn Sie nach Adressen oder Produkten suchen? Sie benötigen alle Produkte, die der Beschreibung entsprechen.
Shahir Ansari
6

Ich habe ein paar einfache Tests gemacht:

In [10]: x = pd.Series(range(1000000))

In [13]: timeit 999999 in x.values
567 µs ± 25.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [15]: timeit x.isin([999999]).any()
9.54 ms ± 291 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [16]: timeit (x == 999999).any()
6.86 ms ± 107 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [17]: timeit 999999 in set(x)
79.8 ms ± 1.98 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [21]: timeit x.eq(999999).any()
7.03 ms ± 33.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [22]: timeit x.eq(9).any()
7.04 ms ± 60 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [24]: timeit 9 in x.values
666 µs ± 15.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Interessanterweise spielt es keine Rolle, ob Sie 9 oder 999999 nachschlagen. Es scheint, als würde die Verwendung der In-Syntax ungefähr genauso lange dauern (muss die binäre Suche verwenden).

In [24]: timeit 9 in x.values
666 µs ± 15.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [25]: timeit 9999 in x.values
647 µs ± 5.21 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [26]: timeit 999999 in x.values
642 µs ± 2.11 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [27]: timeit 99199 in x.values
644 µs ± 5.31 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [28]: timeit 1 in x.values
667 µs ± 20.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Die Verwendung von x.values ​​scheint am schnellsten zu sein, aber vielleicht gibt es bei Pandas einen eleganteren Weg?

Allen Wang
quelle
Es wäre großartig, wenn Sie die Reihenfolge der Ergebnisse vom kleinsten zum größten ändern würden. Gute Arbeit!
smm
4

Oder verwenden Sie Series.tolistoder Series.any:

>>> s = pd.Series(list('abc'))
>>> s
0    a
1    b
2    c
dtype: object
>>> 'a' in s.tolist()
True
>>> (s=='a').any()
True

Series.tolistmacht eine Liste über a Series, und die andere bekomme ich nur einen Booleschen Wert Seriesvon einem regulären Seriesund überprüfe dann, ob es irgendwelche Trues im Booleschen Wert gibt Series.

U10-Vorwärts
quelle
1

Einfacher Zustand:

if any(str(elem) in ['a','b'] for elem in df['column'].tolist()):
Eli B.
quelle
1

Verwenden

df[df['id']==x].index.tolist()

Wenn xes in vorhanden idist, wird die Liste der Indizes zurückgegeben, in denen es vorhanden ist, andernfalls wird eine leere Liste angezeigt.

Ramana Sriwidya
quelle
1

Ich schlage nicht vor, "Wert in Serie" zu verwenden, was zu vielen Fehlern führen kann. Weitere Informationen finden Sie in dieser Antwort: Verwendung im Operator mit Pandas-Serien

Vicky Ding
quelle
0

Angenommen, Ihr Datenrahmen sieht folgendermaßen aus:

Geben Sie hier die Bildbeschreibung ein

Jetzt möchten Sie überprüfen, ob der Dateiname "80900026941984" im Datenrahmen vorhanden ist oder nicht.

Sie können einfach schreiben:

if sum(df["filename"].astype("str").str.contains("80900026941984")) > 0:
    print("found")
Namrata Tolani
quelle