Pandas Як відфільтрувати серію


94

У мене є така серія після того, як я зробив groupby ('name') і використав функцію mean () в іншому стовпці

name
383      3.000000
663      1.000000
726      1.000000
737      9.000000
833      8.166667

Чи може хто-небудь показати мені, як відфільтрувати рядки із середніми значеннями 1000000? Дякую і дуже вдячний за вашу допомогу.


Ну, як би ви відфільтрували серію за заданою умовою?

Відповіді:


127
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

10
Я віддаю перевагу наведеним нижче відповідям, оскільки їх можна прив’язати ланцюжком (тобто не потрібно визначати, sа потім двічі використовувати їх у виразі). Працює лише з пандами 0,18.
IanS

Також див. Порівняння часу у відповіді piRSquared .
IanS

63

З версії pandas 0.18+ фільтрування серії також можна виконати, як показано нижче

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()

Оформити замовлення: http://pandas.pydata.org/pandas-docs/version/0.18.1/whatsnew.html#method-chaininng-improvements


3
Набагато приємніше з ланцюжком методів (і нагадує мені про Іскру.)
Ділан Хогг

Правда, але Spark у цьому випадку робить щось більш інтуїтивне: він просто позбавляється від рядків, які не відповідають предикату, це означає не використовувати частину ".dropna ()", яка здавалася мені явно зайвою, поки я не прочитав документ.
Покусало

44

Як зазначає DACW, у пандах 0.18.1 є покращення, пов’язані з методами, які дуже добре роблять те, що ви шукаєте.

Замість використання .where, ви можете передати свою функцію .locіндексатору або індексатору серії []та уникнути виклику .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]

Подібна поведінка підтримується в класах DataFrame та NDFrame.


2
Це моя улюблена відповідь, і вона також здається найшвидшою, не переходячи до numpy (див. Порівняння часу).
IanS

21

Швидкий спосіб зробити це - реконструювати за допомогою numpyнарізки базових масивів. Дивіться терміни нижче.

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

0
383    3.000000
737    9.000000
833    8.166667
dtype: float64

наївні терміни

введіть тут опис зображення


, Мені подобається ваш метод, я хочу знати, що робити, якщо я маю мультимаски. Thx
Menglong Li

1
@MenglongLi залежить, вам слід задати питання. Швидше за все, ви б поєднали їх із &. mask = mask1 & mask2
piRSquared

6

Інший спосіб - це спочатку перетворити на DataFrame і використовувати метод запиту (за умови, що у вас встановлений 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")

Я не думаю, що це гарна ідея передавати умову як рядок
SzymonPajzert

1
Це додає всі накладні витрати на фрейм даних і буде дуже повільним.
фантастично

5

Якщо вам подобається ланцюгова операція, ви також можете використовувати compressфункцію:

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

У моєму випадку у мене була серія panda, де значеннями є кортежі символів :

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)

Тому я міг використовувати індексацію для фільтрування серії, але для створення індексу, який мені потрібен apply. Мій умова - "знайти всі кортежі, які мають рівно одне" H "".

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

Я визнаю, що це не "придатне для створення" (тобто зауважте, я повторюю series_of_tuplesдвічі; ви повинні зберігати будь-які тимчасові ряди у змінних, щоб ви могли викликати застосувати (...) на них).

Можуть бути й інші методи (крім .apply(...)), які можуть діяти поелементно, щоб отримати булев індекс.

Багато інших відповідей (включаючи прийняту відповідь) з використанням таких функцій, як:

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

Вони приймають виклики (лямбди), які застосовуються до Серії , а не до окремих значень у цій серії!

Тому моя серія кортежів поводилася дивно, коли я намагався використати мій вищезгаданий умова / викликається / лямбда, з будь-якою з функцій, які можна застосувати, наприклад .loc[]:

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

Видає помилку:

KeyError: 'Рівень H повинен збігатися з ім'ям (немає)

Я був дуже збентежений, але це , здається, використовує Series.count series_of_tuples.count(...)функцію , яка не те , що я хотів.

Я визнаю, що альтернативна структура даних може бути кращою:

  • Тип даних категорії?
  • Кадр даних (кожен елемент кортежу стає стовпцем)
  • Серія рядків (просто об'єднайте кортежі разом):

Це створює серію рядків (тобто шляхом об'єднання кортежу; об'єднання символів у кортежі в одному рядку)

series_of_tuples.apply(''.join)

Тож я можу тоді скористатися ланцюжкомSeries.str.count

series_of_tuples.apply(''.join).str.count('H')==1
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.