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.

Kiem Nguyen
źródło
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
Andrzej
źródło
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

DACW
źródło
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.

Gordon Bean
źródło
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

piRSquared
źródło
, 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")
Kamil Sindi
źródło
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
Psidom
źródło
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
Groszek czerwony
źródło