Pandy Jak filtrować serię


98

Mam taką serię po wykonaniu funkcji Groupby („name”) i użyciu funkcji mean () w innej kolumnie

name
383      3.000000
663      1.000000
726      1.000000
737      9.000000
833      8.166667

Czy ktoś mógłby mi pokazać, jak odfiltrować wiersze z wartościami średnimi 1,000000? Dziękuję i bardzo doceniam twoją pomoc.


Jak byś przefiltrował serię według określonego warunku?

Odpowiedzi:


133
In [5]:

import pandas as pd

test = {
383:    3.000000,
663:    1.000000,
726:    1.000000,
737:    9.000000,
833:    8.166667
}

s = pd.Series(test)
s = s[s != 1]
s
Out[0]:
383    3.000000
737    9.000000
833    8.166667
dtype: float64

11
Wolę odpowiedzi poniżej, ponieważ można je łączyć (tj. Nie trzeba ich definiować, sa następnie dwukrotnie używać w wyrażeniu). Działa jednak tylko od pand 0.18.
IanS

Zobacz także porównania czasu w odpowiedzi piRSquared .
IanS

68

Od wersji pandy 0.18+ filtrowanie serii można również wykonać w sposób przedstawiony poniżej

test = {
383:    3.000000,
663:    1.000000,
726:    1.000000,
737:    9.000000,
833:    8.166667
}

pd.Series(test).where(lambda x : x!=1).dropna()

Zamówienie: http://pandas.pydata.org/pandas-docs/version/0.18.1/whatsnew.html#method-chaininng-improvements


3
O wiele ładniej z łączeniem metod (i przypomina mi Spark.)
Dylan Hogg,

To prawda, ale Spark robi w tym przypadku coś bardziej intuicyjnego: po prostu pozbywa się wierszy, które nie pasują do predykatu, co oznacza nieużywanie części „.dropna ()”, która wydawała mi się zbędna, dopóki nie przeczytam dokumentu.
Ugryzło

46

Jak zauważył DACW , istnieją ulepszenia dotyczące łączenia metod metod, które bardzo ładnie robią to, czego szukasz.

Zamiast używać .where, możesz przekazać swoją funkcję do .locindeksatora lub indeksatora serii []i uniknąć wywołania .dropna:

test = pd.Series({
383:    3.000000,
663:    1.000000,
726:    1.000000,
737:    9.000000,
833:    8.166667
})

test.loc[lambda x : x!=1]

test[lambda x: x!=1]

Podobne zachowanie jest obsługiwane w klasach DataFrame i NDFrame.


2
To moja ulubiona odpowiedź, a także wydaje się być najszybsza bez schodzenia do numpy (zobacz porównania czasowe).
IanS

22

Szybkim sposobem na zrobienie tego jest rekonstrukcja przy użyciu numpydo wycinania bazowych tablic. Zobacz czasy poniżej.

mask = s.values != 1
pd.Series(s.values[mask], s.index[mask])

0
383    3.000000
737    9.000000
833    8.166667
dtype: float64

naiwne wyczucie czasu

wprowadź opis obrazu tutaj


, Podoba mi się twoja metoda, chcę wiedzieć, co jeśli mam multmaski. Dzięki
Menglong Li

1
@MenglongLi zależy, powinieneś zadać pytanie. Najprawdopodobniej połączysz je z &. mask = mask1 & mask2
piRSquared

6

Innym sposobem jest najpierw konwersja do DataFrame i użycie metody zapytania (zakładając, że masz zainstalowany numexpr):

import pandas as pd

test = {
383:    3.000000,
663:    1.000000,
726:    1.000000,
737:    9.000000,
833:    8.166667
}

s = pd.Series(test)
s.to_frame(name='x').query("x != 1")

Nie sądzę, żeby to był dobry pomysł, aby przekazać warunek jako ciąg
SzymonPajzert

1
To dodaje cały narzut ramki danych i będzie bardzo powolne.
fantabolous

5

Jeśli lubisz operację łańcuchową, możesz również użyć compressfunkcji:

test = pd.Series({
383:    3.000000,
663:    1.000000,
726:    1.000000,
737:    9.000000,
833:    8.166667
})

test.compress(lambda x: x != 1)

# 383    3.000000
# 737    9.000000
# 833    8.166667
# dtype: float64

1

W moim przypadku miałem serię pand, w której wartościami są krotki znaków :

Out[67]
0    (H, H, H, H)
1    (H, H, H, T)
2    (H, H, T, H)
3    (H, H, T, T)
4    (H, T, H, H)

Dlatego mogłem użyć indeksowania do filtrowania serii, ale do utworzenia indeksu potrzebowałem apply. Mój warunek to „znajdź wszystkie krotki, które mają dokładnie jedno 'H'”.

series_of_tuples[series_of_tuples.apply(lambda x: x.count('H')==1)]

Przyznaję, że nie można go „łączyć w łańcuch” (tj. Zauważ, że powtarzamseries_of_tuples dwa razy; musisz przechowywać dowolną tymczasową serię w zmiennej, aby móc wywołać na niej (...)).

Mogą istnieć również inne metody (poza .apply(...)), które mogą działać elementarnie, aby utworzyć indeks boolowski.

Wiele innych odpowiedzi (w tym zaakceptowana odpowiedź) przy użyciu funkcji łańcuchowych, takich jak:

  • .compress()
  • .where()
  • .loc[]
  • []

Akceptują wywołania (lambdy), które są stosowane do serii , a nie do poszczególnych wartości w tych seriach!

Dlatego moja seria krotek zachowywała się dziwnie, gdy próbowałem użyć powyższego warunku / wywoływanej / lambda, z dowolną funkcją łańcuchową, taką jak .loc[]:

series_of_tuples.loc[lambda x: x.count('H')==1]

Powoduje błąd:

KeyError: „Poziom H musi być taki sam jak nazwa (brak)”

Byłem bardzo zdezorientowany, ale wydaje mi się, że używa series_of_tuples.count(...)funkcji Series.count , co nie jest tym, czego chciałem.

Przyznaję, że alternatywna struktura danych może być lepsza:

  • Typ danych kategorii?
  • Dataframe (każdy element krotki staje się kolumną)
  • Seria ciągów (po prostu połącz razem krotki):

Tworzy to serię ciągów (np. Przez konkatenację krotki; łączenie znaków w krotce w jednym ciągu)

series_of_tuples.apply(''.join)

Więc mogę wtedy użyć łańcuchaSeries.str.count

series_of_tuples.apply(''.join).str.count('H')==1
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.