Como selecionar linhas em um DataFrame entre dois valores, em Python Pandas?

99

Estou tentando modificar um DataFrame dfpara conter apenas linhas para as quais os valores na coluna closing_priceestão entre 99 e 101 e tentando fazer isso com o código abaixo.

No entanto, recebo o erro

ValueError: O valor verdadeiro de uma série é ambíguo. Use a.empty, a.bool (), a.item (), a.any () ou a.all ()

e estou me perguntando se existe uma maneira de fazer isso sem usar loops.

df = df[(99 <= df['closing_price'] <= 101)]
user131983
fonte
O problema aqui é que você não pode comparar um escalar com uma matriz, daí o erro, para comparações você tem que usar os operadores bit a bit e colocá-los entre parênteses devido à precedência do operador
EdChum
df.querye pd.evalparecem adequados para esse caso de uso. Para obter informações sobre a pd.eval()família de funções, seus recursos e casos de uso, visite Avaliação de Expressão Dinâmica em pandas usando pd.eval () .
cs95

Respostas:

103

Você deve usar ()para agrupar seu vetor booleano para remover ambigüidade.

df = df[(df['closing_price'] >= 99) & (df['closing_price'] <= 101)]
Jianxun Li
fonte
162

Considere também as séries entre :

df = df[df['closing_price'].between(99, 101)]
Parfait
fonte
5
A opção inclusive=Trueé usada por padrão em between, portanto, você pode consultar desta formadf = df[df['closing_price'].between(99, 101)]
Anton Ermakov
3
Esta é a melhor resposta! bom trabalho!
PEBKAC
Existe funcionalidade "não entre" nos pandas? Eu não estou encontrando.
dsugasa
2
@dsugasa, use o operador til com between.
Parfait
1
@dsugasa egdf = df[~df['closing_price'].between(99, 101)]
Jan33
22

existe uma alternativa melhor - use o método query () :

In [58]: df = pd.DataFrame({'closing_price': np.random.randint(95, 105, 10)})

In [59]: df
Out[59]:
   closing_price
0            104
1             99
2             98
3             95
4            103
5            101
6            101
7             99
8             95
9             96

In [60]: df.query('99 <= closing_price <= 101')
Out[60]:
   closing_price
1             99
5            101
6            101
7             99

ATUALIZAÇÃO: respondendo ao comentário:

Eu gosto da sintaxe aqui, mas caí ao tentar combiná-la com a expressão; df.query('(mean + 2 *sd) <= closing_price <=(mean + 2 *sd)')

In [161]: qry = "(closing_price.mean() - 2*closing_price.std())" +\
     ...:       " <= closing_price <= " + \
     ...:       "(closing_price.mean() + 2*closing_price.std())"
     ...:

In [162]: df.query(qry)
Out[162]:
   closing_price
0             97
1            101
2             97
3             95
4            100
5             99
6            100
7            101
8             99
9             95
MaxU
fonte
Eu gosto da sintaxe aqui, mas caí ao tentar combiná-la com a expressão; df.query ('(média + 2 * dp) <= preço_de_fecho <= (média + 2 * dp)')
mapeamento de
1
@mappingdom, o que é meane sd? Esses são nomes de coluna?
MaxU
não, eles são a média calculada e o desvio padrão armazenados como um flutuador
mapeamento de
@mappingdom, o que você quer dizer com "armazenado"?
MaxU
@mappingdom, atualizei minha postagem - é isso que você estava pedindo?
MaxU de
9

você também pode usar o .between()método

emp = pd.read_csv("C:\\py\\programs\\pandas_2\\pandas\\employees.csv")

emp[emp["Salary"].between(60000, 61000)]

Resultado

insira a descrição da imagem aqui

Riz.Khan
fonte
6
newdf = df.query('closing_price.mean() <= closing_price <= closing_price.std()')

ou

mean = closing_price.mean()
std = closing_price.std()

newdf = df.query('@mean <= closing_price <= @std')
crashMOGWAI
fonte
3

Se estiver lidando com vários valores e várias entradas, você também pode configurar uma função de aplicação como esta. Neste caso, filtrar um dataframe para localizações de GPS que caem dentro de certos intervalos.

def filter_values(lat,lon):
    if abs(lat - 33.77) < .01 and abs(lon - -118.16) < .01:
        return True
    elif abs(lat - 37.79) < .01 and abs(lon - -122.39) < .01:
        return True
    else:
        return False


df = df[df.apply(lambda x: filter_values(x['lat'],x['lon']),axis=1)]
pardal
fonte
1

Em vez disso

df = df[(99 <= df['closing_price'] <= 101)]

Você deveria usar isso

df = df[(df['closing_price']>=99 ) & (df['closing_price']<=101)]

Temos que usar os operadores lógicos bit a bit do NumPy |, &, ~, ^ para consultas compostas. Além disso, os parênteses são importantes para a precedência do operador.

Para mais informações, você pode visitar o link: Comparações, Máscaras e Lógica Booleana

Rushabh Agarwal
fonte