Jak ustalić, czy kolumna Pandas zawiera określoną wartość

156

Próbuję ustalić, czy w kolumnie Pandy znajduje się wpis, który ma określoną wartość. Próbowałem to zrobić if x in df['id']. Myślałem, że to działa, z wyjątkiem sytuacji, gdy podałem mu wartość, o której wiedziałem, że nie ma w kolumnie 43 in df['id'], nadal zwracała True. Kiedy podzbiorę na ramkę danych zawierającą tylko wpisy pasujące do brakującego identyfikatora df[df['id'] == 43], oczywiście nie ma w niej żadnych wpisów. Jak ustalić, czy kolumna w ramce danych Pandas zawiera określoną wartość i dlaczego moja obecna metoda nie działa? (FYI, mam ten sam problem, gdy używam implementacji w tej odpowiedzi na podobne pytanie).

Michael
źródło

Odpowiedzi:

183

in of a Series sprawdza, czy wartość znajduje się w indeksie:

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

Jedną z opcji jest sprawdzenie, czy ma on unikalne wartości:

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

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

lub zestaw Pythona:

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

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

Jak wskazał @DSM, bardziej wydajne może być (szczególnie jeśli robisz to tylko dla jednej wartości), aby po prostu użyć bezpośrednio na wartościach:

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

In [32]: 'a' in s.values
Out[32]: True
Andy Hayden
źródło
2
Nie chcę wiedzieć, czy koniecznie jest wyjątkowy, przede wszystkim chcę wiedzieć, czy tam jest.
Michael
24
Myślę, że 'a' in s.valuespowinno być szybsze w długich seriach.
DSM
4
@AndyHayden Czy wiesz, dlaczego 'a' in spandy wolą sprawdzać indeks, a nie wartości serii? W słownikach sprawdzają klucze, ale seria pandy powinna zachowywać się bardziej jak lista lub tablica, prawda?
Lei
3
Począwszy od pandy 0.24.0, używanie s.valuesi df.valuesjest wysoce zniechęcone. Zobacz to . W s.valuesniektórych przypadkach jest znacznie wolniejszy.
Qusai Alothman
1
@QusaiAlothman ani .to_numpyczy .arraysą dostępne w serialu, więc nie jestem do końca pewien, co oni opowiadają alternatywa (nie czytam „odradza”). W rzeczywistości mówią, że .values ​​może nie zwracać tablicy numpy, np. W przypadku kategorialnego ... ale to jest w porządku, ponieważ innadal będzie działać zgodnie z oczekiwaniami (a nawet bardziej wydajnie, że jest to odpowiednik tablicy numpy)
Andy Hayden
27

Możesz również użyć pandas.Series.isin, chociaż jest trochę dłuższy niż '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

Ale to podejście może być bardziej elastyczne, jeśli musisz dopasować wiele wartości naraz dla ramki DataFrame (zobacz 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
ffeast
źródło
Możesz również użyć funkcji DataFrame.any () :s.isin(['a']).any()
thando
17
found = df[df['Column'].str.contains('Text_to_search')]
print(found.count())

found.count()wola zawiera liczbę meczów

A jeśli jest 0, oznacza to, że w kolumnie nie znaleziono ciągu.

Shahir Ansari
źródło
2
zadziałało dla mnie, ale użyłem len (znaleziono), aby uzyskać liczbę
kztd
1
Tak, len (znaleziono) jest nieco lepszą opcją.
Shahir Ansari
1
To podejście zadziałało dla mnie, ale musiałem uwzględnić parametry na=Falsei regex=Falsedla mojego przypadku użycia, jak wyjaśniono tutaj: pandas.pydata.org/pandas-docs/stable/reference/api/ ...
Mabyn
1
Ale string.contains wyszukuje podciąg. Na przykład: jeśli występuje wartość o nazwie „head_hunter”. Przekazanie „głowy” w str. Zawiera dopasowania i podaje wartość True, która jest błędna.
karthikeyan
@karthikeyan Nie jest źle. Zależy od kontekstu wyszukiwania. A co jeśli szukasz adresów lub produktów. Będziesz potrzebował wszystkich produktów, które pasują do opisu.
Shahir Ansari
6

Zrobiłem kilka prostych testów:

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)

Co ciekawe, nie ma znaczenia, czy spojrzysz na 9 czy 999999, wygląda na to, że użycie w składni zajmuje mniej więcej tyle samo czasu (musi być używane wyszukiwanie binarne)

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)

Wydaje się, że użycie x.values ​​jest najszybsze, ale może w pandach istnieje bardziej elegancki sposób?

Allen Wang
źródło
Byłoby wspaniale, gdybyś zmienił kolejność wyników z najmniejszego na największy. Dobra robota!
smm
4

Lub użyj Series.tolistlub 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.tolisttworzy listę o a Series, a drugą otrzymuję po prostu wartość logiczną Seriesze zwykłego Series, a następnie sprawdzam, czy są jakieś Trues w zmiennej boolowskiej Series.

U10-Forward
źródło
1

Prosty stan:

if any(str(elem) in ['a','b'] for elem in df['column'].tolist()):
Eli B.
źródło
1

Posługiwać się

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

Jeśli xjest obecny w, idto zwróci listę indeksów, w których jest obecny, w przeciwnym razie wyświetli pustą listę.

Ramana Sriwidya
źródło
1

Nie sugeruję używania „wartości w serii”, co może prowadzić do wielu błędów. Zapoznaj się z tą odpowiedzią, aby uzyskać szczegółowe informacje: Używanie operatora z seriami Pandas

Vicky Ding
źródło
0

Załóżmy, że twoja ramka danych wygląda następująco:

wprowadź opis obrazu tutaj

Teraz chcesz sprawdzić, czy nazwa pliku „80900026941984” jest obecna w ramce danych, czy nie.

Możesz po prostu napisać:

if sum(df["filename"].astype("str").str.contains("80900026941984")) > 0:
    print("found")
Namrata Tolani
źródło