Панды Как отфильтровать серию

94

У меня есть такая серия после выполнения groupby ('name') и использования функции mean () в другом столбце

name
383      3.000000
663      1.000000
726      1.000000
737      9.000000
833      8.166667

Может ли кто-нибудь показать мне, как отфильтровать строки со средними значениями 1 000 000? Спасибо, и я очень ценю вашу помощь.

Кием Нгуен
источник
Как бы вы отфильтровали серию по заданному условию?

Ответы:

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а затем использовать его дважды в выражении). Хотя работает только с pandas 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

DACW
источник
3
Намного приятнее с цепочкой методов (и напоминает мне Spark.)
Дилан Хогг,
Верно, но в этом случае Spark делает что-то более интуитивное: он просто избавляется от строк, которые не соответствуют предикату, что означает отказ от использования части «.dropna ()», которая казалась мне явно излишней, пока я не прочитал документ.
Укусил
44

Как отметил DACW , в pandas 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
Это мой любимый ответ, и он также кажется самым быстрым, не опускаясь до числа (см. Сравнение времени).
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

наивное время

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

PiRSquared
источник
, Мне нравится ваш метод, я хочу знать, что, если у меня есть мульти-маски. Thx
Menglong Li
1
@MenglongLi зависит, вы должны задать вопрос. Скорее всего, вы бы сочетали их с &. mask = mask1 & mask2
piRSquared 07
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
Это добавляет все накладные расходы на фрейм данных и будет очень медленным.
fantabolous
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

В моем случае у меня была серия панд, где значения представляют собой кортежи символов :

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

Также могут быть другие методы (помимо .apply(...)), которые могут работать поэлементно для создания логического индекса.

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

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

Они принимают вызовы (лямбды), которые применяются к серии , а не к отдельным значениям в этой серии!

Поэтому моя серия кортежей вела себя странно, когда я пытался использовать указанное выше условие / callable / lambda с любой из цепных функций, например .loc[]:

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

Выдает ошибку:

KeyError: "Уровень H должен совпадать с именем (None)"

Я был очень сбит с толку, но похоже, что он использует функцию Series.countseries_of_tuples.count(...) , а это не то, что я хотел.

Я допускаю, что альтернативная структура данных может быть лучше:

  • Тип данных категории?
  • Dataframe (каждый элемент кортежа становится столбцом)
  • Серия строк (просто объедините кортежи вместе):

Это создает серию строк (т.е. путем объединения кортежа; объединения символов в кортеже в одну строку)

series_of_tuples.apply(''.join)

Тогда я могу использовать цепочкуSeries.str.count

series_of_tuples.apply(''.join).str.count('H')==1
Красный горошек
источник