Este FutureWarning não é do Pandas, é do numpy e o bug também afeta matplotlib e outros. Veja como reproduzir o aviso mais próximo da origem do problema:
import numpy as np
print(np.__version__)
'x' in np.arange(5)
FutureWarning: elementwise comparison failed; returning scalar instead, but in the
future will perform elementwise comparison
False
Outra maneira de reproduzir esse bug usando o operador double equals:
import numpy as np
np.arange(5) == np.arange(5).astype(str)
Um exemplo de Matplotlib afetado por este FutureWarning em sua implementação de plot de quiver: https://matplotlib.org/examples/pylab_examples/quiver_demo.html
O que está acontecendo aqui?
Há uma discordância entre o Numpy e o python nativo sobre o que deve acontecer quando você compara strings com os tipos numéricos de numpy. Observe que o operando esquerdo é turf de python, uma string primitiva, e a operação do meio é turf de python, mas o operando direito é turf de numpy. Você deve retornar um escalar de estilo Python ou um ndarray de estilo Numpy de booleano? Numpy diz ndarray de bool, os desenvolvedores Pythonic discordam. Impasse clássico.
Deve ser uma comparação elementar ou escalar se o item existir na matriz?
Se o seu código ou biblioteca estiver usando os operadores in
ou ==
para comparar a string python com ndarrays numpy, eles não são compatíveis, então, se você tentar, ele retornará um escalar, mas apenas por enquanto. O Aviso indica que, no futuro, esse comportamento pode mudar, então seu código vomita no carpete se python / numpy decidir adotar o estilo Numpy.
Relatórios de bug enviados:
Numpy e Python estão em um impasse, por enquanto a operação retorna um escalar, mas no futuro isso pode mudar.
https://github.com/numpy/numpy/issues/6784
https://github.com/pandas-dev/pandas/issues/7830
Duas soluções alternativas:
Bloqueie sua versão de python e numpy, ignore os avisos e espere que o comportamento não mude ou converta os operandos esquerdo e direito de ==
e in
para um tipo numpy ou tipo numérico python primitivo.
Suprima o aviso globalmente:
import warnings
import numpy as np
warnings.simplefilter(action='ignore', category=FutureWarning)
print('x' in np.arange(5))
Suprima o aviso linha a linha.
import warnings
import numpy as np
with warnings.catch_warnings():
warnings.simplefilter(action='ignore', category=FutureWarning)
print('x' in np.arange(2))
print('x' in np.arange(10))
Apenas suprima o aviso pelo nome, coloque um comentário alto ao lado dele mencionando a versão atual do python e numpy, dizendo que este código é frágil e requer essas versões e coloque um link para aqui. Chute a lata pela estrada.
TLDR: pandas
são Jedi; numpy
são as cabanas; e python
é o império galáctico. https://youtu.be/OZczsiCfQQk?t=3
thing
(que pode ou não ser um tipo entorpecido; não sei) e quero ver sething == 'some string'
e obter umbool
resultado simples , o que devo fazer?np.atleast_1d(thing)[0] == 'some string'
? Mas isso não é robusto para algum curinga colocando'some string'
o primeiro elemento de um array. Acho que tenho que testar o tipo dething
primeiro e só fazer o==
teste se for uma string (ou não um objeto entorpecido).np.array([1, 2]) == []
gerará o aviso.or babysit your left and right operands to be from a common turf
Eu recebo o mesmo erro quando tento definir a
index_col
leitura de um arquivo em umPanda
data-frame de:df = pd.read_csv('my_file.tsv', sep='\t', header=0, index_col=['0']) ## or same with the following df = pd.read_csv('my_file.tsv', sep='\t', header=0, index_col=[0])
Nunca encontrei tal erro anteriormente. Ainda estou tentando descobrir a razão por trás disso (usando a explicação de @Eric Leschinski e outras).
De qualquer forma, a abordagem a seguir resolve o problema por enquanto, até que eu descubra o motivo:
df = pd.read_csv('my_file.tsv', sep='\t', header=0) ## not setting the index_col df.set_index(['0'], inplace=True)
Vou atualizar isso assim que descobrir o motivo de tal comportamento.
fonte
read_csv()
. Parece-me algo quepandas
precisa ser consertado.pd__version__: 0.22.0
;np.__version__: 1.15.4
read_csv
ao usar oindex_col
parâmetro. Testei duas configurações com resultados diferentes: 1. numpy versão 1.19.2, Pandas versão 1.1.2: FutureWarning: falha na comparação elementwise ... 2. numpy versão 1.19.2, Pandas versão 1.1.3: TypeError: ufunc ' isnan 'não suportado ...Minha experiência com a mesma mensagem de aviso foi causada por TypeError.
Então, você pode querer verificar o tipo de dados do
Unnamed: 5
for x in df['Unnamed: 5']: print(type(x)) # are they 'str' ?
Aqui está como posso replicar a mensagem de aviso:
import pandas as pd import numpy as np df = pd.DataFrame(np.random.randn(3, 2), columns=['num1', 'num2']) df['num3'] = 3 df.loc[df['num3'] == '3', 'num3'] = 4 # TypeError and the Warning df.loc[df['num3'] == 3, 'num3'] = 4 # No Error
Espero que ajude.
fonte
df['num3'] == '3'
.df.loc[df['num3'] == 3, 'num3'] = 4 # No Error
Essa parte me ajuda. ObrigadoImpossível superar a resposta incrivelmente detalhada de Eric Leschinski, mas aqui está uma rápida solução alternativa para a pergunta original que eu acho que ainda não foi mencionada - coloque a string em uma lista e use em
.isin
vez de==
Por exemplo:
import pandas as pd import numpy as np df = pd.DataFrame({"Name": ["Peter", "Joe"], "Number": [1, 2]}) # Raises warning using == to compare different types: df.loc[df["Number"] == "2", "Number"] # No warning using .isin: df.loc[df["Number"].isin(["2"]), "Number"]
fonte
Uma solução rápida para isso é usar
numpy.core.defchararray
. Também enfrentei a mesma mensagem de aviso e consegui resolvê-la usando o módulo acima.import numpy.core.defchararray as npd resultdataset = npd.equal(dataset1, dataset2)
fonte
A resposta de Eric explica de forma útil que o problema vem da comparação de uma série Pandas (contendo uma matriz NumPy) com uma string Python. Infelizmente, suas duas soluções alternativas apenas suprimem o aviso.
Para escrever código que não causa o aviso em primeiro lugar, compare explicitamente sua string com cada elemento da Série e obtenha um bool separado para cada um. Por exemplo, você pode usar
map
e uma função anônima.myRows = df[df['Unnamed: 5'].map( lambda x: x == 'Peter' )].index.tolist()
fonte
Se seus arrays não forem muito grandes ou se você não tiver muitos deles, você pode conseguir forçar o lado esquerdo de
==
a ser uma string:myRows = df[str(df['Unnamed: 5']) == 'Peter'].index.tolist()
Mas isso é cerca de 1,5 vezes mais lento se
df['Unnamed: 5']
for uma string, 25-30 vezes mais lento sedf['Unnamed: 5']
for uma pequena matriz numpy (comprimento = 10) e 150-160 vezes mais lento se for uma matriz numpy com comprimento 100 (tempos em média acima de 500 tentativas) .a = linspace(0, 5, 10) b = linspace(0, 50, 100) n = 500 string1 = 'Peter' string2 = 'blargh' times_a = zeros(n) times_str_a = zeros(n) times_s = zeros(n) times_str_s = zeros(n) times_b = zeros(n) times_str_b = zeros(n) for i in range(n): t0 = time.time() tmp1 = a == string1 t1 = time.time() tmp2 = str(a) == string1 t2 = time.time() tmp3 = string2 == string1 t3 = time.time() tmp4 = str(string2) == string1 t4 = time.time() tmp5 = b == string1 t5 = time.time() tmp6 = str(b) == string1 t6 = time.time() times_a[i] = t1 - t0 times_str_a[i] = t2 - t1 times_s[i] = t3 - t2 times_str_s[i] = t4 - t3 times_b[i] = t5 - t4 times_str_b[i] = t6 - t5 print('Small array:') print('Time to compare without str conversion: {} s. With str conversion: {} s'.format(mean(times_a), mean(times_str_a))) print('Ratio of time with/without string conversion: {}'.format(mean(times_str_a)/mean(times_a))) print('\nBig array') print('Time to compare without str conversion: {} s. With str conversion: {} s'.format(mean(times_b), mean(times_str_b))) print(mean(times_str_b)/mean(times_b)) print('\nString') print('Time to compare without str conversion: {} s. With str conversion: {} s'.format(mean(times_s), mean(times_str_s))) print('Ratio of time with/without string conversion: {}'.format(mean(times_str_s)/mean(times_s)))
Resultado:
Small array: Time to compare without str conversion: 6.58464431763e-06 s. With str conversion: 0.000173756599426 s Ratio of time with/without string conversion: 26.3881526541 Big array Time to compare without str conversion: 5.44309616089e-06 s. With str conversion: 0.000870866775513 s 159.99474375821288 String Time to compare without str conversion: 5.89370727539e-07 s. With str conversion: 8.30173492432e-07 s Ratio of time with/without string conversion: 1.40857605178
fonte
==
comstr
foi uma boa solução para mim que mal prejudicou o desempenho em 1,5 milhão de linhas que não ficarão maiores que isso no futuro.No meu caso, o aviso ocorreu apenas por causa do tipo regular de indexação booleana - porque a série tinha apenas np.nan. Demonstração (pandas 1.0.3):
>>> import pandas as pd >>> import numpy as np >>> pd.Series([np.nan, 'Hi']) == 'Hi' 0 False 1 True >>> pd.Series([np.nan, np.nan]) == 'Hi' ~/anaconda3/envs/ms3/lib/python3.7/site-packages/pandas/core/ops/array_ops.py:255: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison res_values = method(rvalues) 0 False 1 False
Acho que com o pandas 1.0 eles realmente querem que você use o novo
'string'
tipo de dados que permitepd.NA
valores:>>> pd.Series([pd.NA, pd.NA]) == 'Hi' 0 False 1 False >>> pd.Series([np.nan, np.nan], dtype='string') == 'Hi' 0 <NA> 1 <NA> >>> (pd.Series([np.nan, np.nan], dtype='string') == 'Hi').fillna(False) 0 False 1 False
Não adoro quando eles mexem nas funcionalidades do dia a dia, como a indexação booleana.
fonte
Recebi este aviso porque pensei que minha coluna continha strings nulas, mas, ao verificar, ela continha np.nan!
if df['column'] == '':
Mudar minha coluna para strings vazias ajudou :)
fonte
Eu comparei alguns dos métodos possíveis para fazer isso, incluindo pandas, vários métodos numpy e um método de compreensão de lista.
Primeiro, vamos começar com uma linha de base:
>>> import numpy as np >>> import operator >>> import pandas as pd >>> x = [1, 2, 1, 2] >>> %time count = np.sum(np.equal(1, x)) >>> print("Count {} using numpy equal with ints".format(count)) CPU times: user 52 µs, sys: 0 ns, total: 52 µs Wall time: 56 µs Count 2 using numpy equal with ints
Portanto, nossa linha de base é que a contagem deve estar correta
2
e devemos levar cerca de50 us
.Agora, tentamos o método ingênuo:
>>> x = ['s', 'b', 's', 'b'] >>> %time count = np.sum(np.equal('s', x)) >>> print("Count {} using numpy equal".format(count)) CPU times: user 145 µs, sys: 24 µs, total: 169 µs Wall time: 158 µs Count NotImplemented using numpy equal /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/ipykernel_launcher.py:1: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison """Entry point for launching an IPython kernel.
E aqui, obtemos a resposta errada (
NotImplemented != 2
), leva muito tempo e lança o aviso.Então, vamos tentar outro método ingênuo:
>>> %time count = np.sum(x == 's') >>> print("Count {} using ==".format(count)) CPU times: user 46 µs, sys: 1 µs, total: 47 µs Wall time: 50.1 µs Count 0 using ==
Novamente, a resposta errada (
0 != 2
). Isso é ainda mais insidioso porque não há avisos subsequentes (0
pode ser transmitido como2
).Agora, vamos tentar uma compreensão de lista:
>>> %time count = np.sum([operator.eq(_x, 's') for _x in x]) >>> print("Count {} using list comprehension".format(count)) CPU times: user 55 µs, sys: 1 µs, total: 56 µs Wall time: 60.3 µs Count 2 using list comprehension
Temos a resposta certa aqui, e é muito rápido!
Outra possibilidade
pandas
:>>> y = pd.Series(x) >>> %time count = np.sum(y == 's') >>> print("Count {} using pandas ==".format(count)) CPU times: user 453 µs, sys: 31 µs, total: 484 µs Wall time: 463 µs Count 2 using pandas ==
Lento, mas correto!
E, finalmente, a opção que vou usar: converter a
numpy
matriz para oobject
tipo:>>> x = np.array(['s', 'b', 's', 'b']).astype(object) >>> %time count = np.sum(np.equal('s', x)) >>> print("Count {} using numpy equal".format(count)) CPU times: user 50 µs, sys: 1 µs, total: 51 µs Wall time: 55.1 µs Count 2 using numpy equal
Rápido e correto!
fonte
'x' in np.arange(5)
, você sugere simplesmente fazer'x' in np.arange(5).astype(object)
(ou similarmente :)'x' == np.arange(5).astype(object)
. Direito? IMHO, esta é a solução alternativa mais elegante mostrada aqui, por isso estou confuso com a falta de votos positivos. Talvez editar sua resposta para começar com o resultado final e, em seguida, passar para a análise de desempenho agradável?Eu tinha este código que estava causando o erro:
for t in dfObj['time']: if type(t) == str: the_date = dateutil.parser.parse(t) loc_dt_int = int(the_date.timestamp()) dfObj.loc[t == dfObj.time, 'time'] = loc_dt_int
Eu mudei para isto:
for t in dfObj['time']: try: the_date = dateutil.parser.parse(t) loc_dt_int = int(the_date.timestamp()) dfObj.loc[t == dfObj.time, 'time'] = loc_dt_int except Exception as e: print(e) continue
para evitar a comparação, que está lançando o aviso - como afirmado acima. Eu só tive que evitar a exceção por causa do
dfObj.loc
loop for, talvez haja uma maneira de dizer a ele para não verificar as linhas que já foram alteradas.fonte