Como selecionar linhas de um com DataFrame
base em valores em alguma coluna no Python Pandas?
No SQL, eu usaria:
SELECT *
FROM table
WHERE colume_name = some_value
Tentei examinar a documentação dos pandas, mas não encontrei a resposta imediatamente.
Respostas:
Para selecionar linhas cujo valor da coluna seja igual a um escalar
some_value
, use==
:Para selecionar linhas cujo valor da coluna está em uma iterável
some_values
, useisin
:Combine várias condições com
&
:Observe os parênteses. Devido às regras de precedência do operador do Python ,
&
vincula mais firmemente que<=
e>=
. Assim, os parênteses no último exemplo são necessários. Sem parêntesesé analisado como
que resulta em um valor de verdade de uma série é um erro ambíguo .
Para selecionar linhas cujo valor da coluna não seja igual
some_value
, use!=
:isin
retorna um booleano série, então para selecionar linhas cujo valor é não emsome_values
, negar a Série boolean usando~
:Por exemplo,
rendimentos
Se você tiver vários valores que deseja incluir, coloque-os em uma lista (ou, mais geralmente, em qualquer iterável) e use
isin
:rendimentos
Observe, no entanto, que se você deseja fazer isso várias vezes, é mais eficiente criar um índice primeiro e depois usar
df.loc
:rendimentos
ou, para incluir vários valores do índice, use
df.index.isin
:rendimentos
fonte
df.where(condition)
, a condição deve ter a mesma forma quedf
.df[df['column_name'] == some_value]
obras, por que precisamos adicionar.loc
aqui?Existem várias maneiras de selecionar linhas de um quadro de dados do pandas:
df[df['col'] == value
])df.iloc[...]
)df.xs(...)
)df.query(...)
APIAbaixo, mostro exemplos de cada um, com conselhos sobre quando usar determinadas técnicas. Suponha que nosso critério seja a coluna
'A'
=='foo'
(Observação sobre desempenho: para cada tipo de base, podemos simplificar as coisas usando a API do pandas ou podemos nos aventurar fora da API, geralmente
numpy
, e acelerar as coisas.)Configuração
A primeira coisa que precisamos é identificar uma condição que atuará como nosso critério para selecionar linhas. Começaremos com o caso do OP
column_name == some_value
e incluiremos outros casos de uso comuns.Empréstimos de @unutbu:
1. Indexação booleana
... A indexação booleana exige que o valor verdadeiro da
'A'
coluna de cada linha seja igual a e'foo'
, em seguida, use esses valores verdadeiros para identificar quais linhas manter. Normalmente, nomearíamos essa série, uma matriz de valores de verdademask
,. Faremos isso aqui também.Podemos então usar essa máscara para cortar ou indexar o quadro de dados
Essa é uma das maneiras mais simples de realizar essa tarefa e, se o desempenho ou a intuição não forem um problema, esse deve ser o método escolhido. No entanto, se o desempenho for uma preocupação, convém considerar uma maneira alternativa de criar o
mask
.2. Indexação posicional
A indexação posicional (
df.iloc[...]
) tem seus casos de uso, mas este não é um deles. Para identificar onde dividir, primeiro precisamos executar a mesma análise booleana que fizemos acima. Isso nos deixa executando uma etapa extra para realizar a mesma tarefa.3. Indexação de etiquetas
A indexação de etiquetas pode ser muito útil, mas, neste caso, estamos trabalhando novamente sem nenhum benefício
4.
df.query()
APIpd.DataFrame.query
é uma maneira muito elegante / intuitiva de executar essa tarefa, mas geralmente é mais lenta. No entanto , se você prestar atenção aos horários abaixo, para dados grandes, a consulta é muito eficiente. Mais do que a abordagem padrão e de magnitude semelhante à minha melhor sugestão.Minha preferência é usar o
Boolean
mask
As melhorias reais podem ser feitas modificando a forma como criamos o nosso
Boolean
mask
.mask
alternativa 1Use a
numpy
matriz subjacente e renuncie à sobrecarga de criar outrapd.Series
Mostrarei testes de tempo mais completos no final, mas dê uma olhada nos ganhos de desempenho que obtemos usando o quadro de dados de amostra. Primeiro, analisamos a diferença na criação do
mask
Avaliar o
mask
com anumpy
matriz é ~ 30 vezes mais rápido. Isso se deve em parte ànumpy
avaliação frequentemente mais rápida. Também se deve em parte à falta de sobrecarga necessária para criar um índice e umpd.Series
objeto correspondente .A seguir, veremos o momento para fatiar com um
mask
versus o outro.Os ganhos de desempenho não são tão pronunciados. Vamos ver se isso se sustenta em testes mais robustos.
mask
alternativa 2Poderíamos ter reconstruído o quadro de dados também. Há uma grande ressalva ao reconstruir um quadro de dados - você deve cuidar disso
dtypes
ao fazer isso!Em vez de
df[mask]
fazermos issoSe o quadro de dados for do tipo misto, como é o nosso exemplo, quando obtermos
df.values
a matriz resultante fordtype
object
e, consequentemente, todas as colunas do novo quadro de dados serão dedtype
object
. Exigindo, assim,astype(df.dtypes)
e eliminando possíveis ganhos de desempenho.No entanto, se o quadro de dados não for do tipo misto, essa é uma maneira muito útil de fazê-lo.
Dado
Versus
Reduzimos o tempo pela metade.
mask
alternativa 3 O@unutbu também nos mostra como usar
pd.Series.isin
para contabilizar cada elemento dedf['A']
estar em um conjunto de valores. Isso avalia o mesmo se nosso conjunto de valores é um conjunto de um valor, a saber'foo'
. Mas também generaliza para incluir conjuntos maiores de valores, se necessário. Acontece que isso ainda é muito rápido, mesmo que seja uma solução mais geral. A única perda real está na intuição para aqueles que não estão familiarizados com o conceito.No entanto, como antes, podemos utilizar
numpy
para melhorar o desempenho sem sacrificar praticamente nada. Vamos usarnp.in1d
Cronometragem
Vou incluir outros conceitos mencionados em outras postagens e também para referência.
Código Abaixo
Cada coluna nesta tabela representa um quadro de dados de comprimento diferente, sobre o qual testamos cada função. Cada coluna mostra o tempo relativo gasto, com a função mais rápida com um índice base de
1.0
.Você notará que os tempos mais rápidos parecem ser compartilhados entre
mask_with_values
emask_with_in1d
Funções
Teste
Momento especial
Analisando o caso especial em que temos um único não-objeto
dtype
para todo o quadro de dados. Código AbaixoAcontece que a reconstrução não vale a pena além de algumas centenas de linhas.
Funções
Teste
fonte
.iloc(numpy.where(..))
compara nesse esquema? ii) você esperaria que as classificações fossem as mesmas ao usar várias condições?pd.Series.isin
, observe que ele é usadonp.in1d
em um cenário específico, usa khash em outros e aplica implicitamente uma compensação entre o custo do hash e o desempenho em situações específicas. Esta resposta tem mais detalhes.[{P|EXP}TIME]
- e[{C|P|EXP}SPACE]
- os custos de utilização do acima formas propostas de bloco-sintaxe (processamento de cima para baixo todo o dataframes de uma vez) crescer , nomeadamente quando dimensionado para algumas~1E6, ~1E9, ~1E12
contagens de linha? Obrigado por nos mostrar toda a imagem, senhor. As leituras quantitativas de benchmark com[min, Avg, MAX, StDev]
são sempre bem-vindas, pois os valoresmin
eMAX
acompanham oMean/StDev
alívio do lote.tl; dr
Os pandas equivalentes a
é
Várias condições:
ou
Exemplo de código
No código acima, é a linha
df[df.foo == 222]
que fornece as linhas com base no valor da coluna,222
neste caso.Várias condições também são possíveis:
Mas nesse ponto, eu recomendaria usar a função de consulta , pois é menos detalhada e produz o mesmo resultado:
fonte
query
é a única resposta aqui que é compatível com o encadeamento de métodos. Parece que são os pandas analógicosfilter
no dplyr.[
não de colchetes(
do lado de fora.|
era para AND, mas é claro que é operador de OR ... #df[condition1][condition2]
df.query('`my col` == 124')
Acho que a sintaxe das respostas anteriores é redundante e difícil de lembrar. O Pandas introduziu o
query()
método na v0.13 e eu prefiro muito. Para sua pergunta, você poderia fazerdf.query('col == val')
Reproduzido de http://pandas.pydata.org/pandas-docs/version/0.17.0/indexing.html#indexing-query
Você também pode acessar variáveis no ambiente anexando um
@
.fonte
numexpr
instalado.Mais flexibilidade usando
.query
compandas >= 0.25.0
:Resposta atualizada de agosto de 2019
Como
pandas >= 0.25.0
podemos usar oquery
método para filtrar quadros de dados com métodos pandas e até nomes de colunas que possuem espaços. Normalmente, os espaços nos nomes das colunas causariam um erro, mas agora podemos resolver isso usando um backtick (`), veja GitHub :Usando
.query
com o métodostr.endswith
:Resultado
Também podemos usar variáveis locais prefixando-a com um
@
em nossa consulta:Resultado
fonte
Resultados mais rápidos podem ser obtidos usando numpy.where .
Por exemplo, com a configuração do unubtu -
Comparações de tempo:
fonte
Aqui está um exemplo simples
fonte
Para selecionar apenas colunas específicas de várias colunas para um determinado valor em pandas:
Opções:
ou
fonte
Para anexar a esta famosa questão (embora um pouco tarde demais): Você também pode
df.groupby('column_name').get_group('column_desired_value').reset_index()
fazer um novo quadro de dados com a coluna especificada com um valor específico. Por exemploExecute isto dá:
fonte
get_group()
retornará automaticamente um quadro de dados. Além disso, você pode apenas dizer "drop = True" como um parâmetro dereset_index()
. Em outras palavras, pode ser reduzido para:b_is_two_dataframe = df.groupby('B').get_group('two').reset_index(drop=True)
Você também pode usar .apply:
Na verdade, funciona em linha (isto é, aplica a função a cada linha).
A saída é
Os resultados são os mesmos que os mencionados em @unutbu
fonte