Este FutureWarning no es de Pandas, es de numpy y el error también afecta a matplotlib y a otros, aquí se explica cómo reproducir la advertencia más cerca de la fuente del 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
Otra forma de reproducir este error usando el operador doble igual:
import numpy as np
np.arange(5) == np.arange(5).astype(str)
Un ejemplo de Matplotlib afectado por este FutureWarning bajo su implementación de diagrama de carcaj: https://matplotlib.org/examples/pylab_examples/quiver_demo.html
¿Que está pasando aqui?
Existe un desacuerdo entre Numpy y el pitón nativo sobre lo que debería suceder cuando se compara una cadena con los tipos numéricos de numpy. Observe que el operando de la izquierda es el territorio de Python, una cadena primitiva, y la operación del medio es el terreno de Python, pero el operando de la derecha es el terreno de Numpy. ¿Debería devolver un escalar de estilo Python o un ndarray de estilo Numpy de booleano? Numpy dice que ndarray de bool, los desarrolladores de Pythonic no están de acuerdo. Enfrentamiento clásico.
¿Debería ser una comparación por elementos o escalar si el elemento existe en la matriz?
Si su código o biblioteca usa los operadores in
o ==
para comparar la cadena de python con numerosos ndarrays, no son compatibles, por lo que cuando lo intenta, devuelve un escalar, pero solo por ahora. La Advertencia indica que en el futuro este comportamiento podría cambiar, por lo que su código vomita por toda la alfombra si python / numpy decide adoptar el estilo Numpy.
Informes de errores enviados:
Numpy y Python están en un punto muerto, por ahora la operación devuelve un escalar, pero en el futuro puede cambiar.
https://github.com/numpy/numpy/issues/6784
https://github.com/pandas-dev/pandas/issues/7830
Dos soluciones alternativas:
Bloquee su versión de python y numpy, ignore las advertencias y espere que el comportamiento no cambie, o convierta los operandos izquierdo y derecho de ==
y in
sean de un tipo numpy o un tipo numérico python primitivo.
Suprima la advertencia a nivel mundial:
import warnings
import numpy as np
warnings.simplefilter(action='ignore', category=FutureWarning)
print('x' in np.arange(5))
Suprima la advertencia línea por línea.
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))
Simplemente suprima la advertencia por su nombre, luego coloque un comentario fuerte junto a ella mencionando la versión actual de python y numpy, diciendo que este código es frágil y requiere estas versiones y coloque un enlace aquí. Patea la lata por el camino.
TLDR: pandas
son Jedi; numpy
son las chozas; y python
es el imperio galáctico. https://youtu.be/OZczsiCfQQk?t=3
thing
(que puede o no ser un tipo numpy; no lo sé) y quiero ver sithing == 'some string'
y obtener unbool
resultado simple , ¿qué debo hacer?np.atleast_1d(thing)[0] == 'some string'
? Pero eso no es robusto para que algún bromista ponga'some string'
el primer elemento de una matriz. Supongo que tengo que probar el tipo dething
primero y luego solo hacer la==
prueba si es una cadena (o no un objeto numpy).np.array([1, 2]) == []
generará la advertencia.or babysit your left and right operands to be from a common turf
Recibo el mismo error cuando intento configurar la
index_col
lectura de un archivo en elPanda
marco de datos de a: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 me había encontrado con un error de este tipo anteriormente. Todavía estoy tratando de averiguar la razón detrás de esto (usando la explicación de @Eric Leschinski y otros).
De todos modos, el siguiente enfoque resuelve el problema por ahora hasta que averigüe la razón:
df = pd.read_csv('my_file.tsv', sep='\t', header=0) ## not setting the index_col df.set_index(['0'], inplace=True)
Actualizaré esto tan pronto como descubra el motivo de tal comportamiento.
fuente
read_csv()
. Me parece que es algo quepandas
hay que arreglar.pd__version__: 0.22.0
;np.__version__: 1.15.4
read_csv
cuando se usa elindex_col
parámetro. He probado dos configuraciones con resultados diferentes: 1. numpy versión 1.19.2, Pandas versión 1.1.2: FutureWarning: la comparación de elementos falló ... 2. numpy versión 1.19.2, Pandas versión 1.1.3: TypeError: ufunc ' isnan 'no es compatible ...Mi experiencia con el mismo mensaje de advertencia fue causada por TypeError.
Por lo tanto, es posible que desee verificar el tipo de datos del
Unnamed: 5
for x in df['Unnamed: 5']: print(type(x)) # are they 'str' ?
Así es como puedo replicar el mensaje de advertencia:
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 eso ayude.
fuente
df['num3'] == '3'
.df.loc[df['num3'] == 3, 'num3'] = 4 # No Error
Esta parte me ayuda. GraciasNo se puede superar la respuesta asombrosamente detallada de Eric Leschinski, pero aquí hay una solución rápida a la pregunta original que no creo que se haya mencionado todavía: coloque la cadena en una lista y use en
.isin
lugar de==
Por ejemplo:
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"]
fuente
Una solución rápida para esto es usar
numpy.core.defchararray
. También enfrenté el mismo mensaje de advertencia y pude resolverlo usando el módulo anterior.import numpy.core.defchararray as npd resultdataset = npd.equal(dataset1, dataset2)
fuente
La respuesta de Eric explica de manera útil que el problema proviene de comparar una serie Pandas (que contiene una matriz NumPy) con una cadena de Python. Desafortunadamente, sus dos soluciones alternativas simplemente eliminan la advertencia.
Para escribir código que no cause la advertencia en primer lugar, compare explícitamente su cadena con cada elemento de la Serie y obtenga un bool separado para cada uno. Por ejemplo, podría utilizar
map
y una función anónima.myRows = df[df['Unnamed: 5'].map( lambda x: x == 'Peter' )].index.tolist()
fuente
Si sus matrices no son demasiado grandes o no tiene demasiadas, es posible que pueda salirse con la suya forzando el lado izquierdo de
==
a ser una cadena:myRows = df[str(df['Unnamed: 5']) == 'Peter'].index.tolist()
Pero esto es ~ 1.5 veces más lento si
df['Unnamed: 5']
es una cadena, 25-30 veces más lento sidf['Unnamed: 5']
es una pequeña matriz numpy (longitud = 10) y 150-160 veces más lenta si es una matriz numpy con longitud 100 (tiempos promediados en 500 intentos) .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
fuente
==
constr
fue una buena solución para mí que apenas afectó el rendimiento en 1,5 millones de filas que no serán más grandes que eso en el futuro.Recibí esta advertencia porque pensé que mi columna contenía cadenas nulas, pero al verificar, ¡contenía np.nan!
if df['column'] == '':
Cambiar mi columna a cadenas vacías ayudó :)
fuente
He comparado algunos de los métodos posibles para hacer esto, incluidos los pandas, varios métodos numpy y un método de comprensión de listas.
Primero, comencemos con una línea 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
Por lo tanto, nuestra línea de base es que el recuento debe ser correcto
2
y debemos tomar aproximadamente50 us
.Ahora, probamos el método ingenuo:
>>> 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.
Y aquí, obtenemos la respuesta incorrecta (
NotImplemented != 2
), nos lleva mucho tiempo y arroja la advertencia.Entonces probaremos otro método ingenuo:
>>> %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 ==
Nuevamente, la respuesta incorrecta (
0 != 2
). Esto es aún más insidioso porque no hay advertencias posteriores (0
se pueden transmitir de la misma manera2
).Ahora, intentemos una lista de comprensión:
>>> %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
Aquí obtenemos la respuesta correcta, ¡y es bastante rápido!
Otra posibilidad
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, pero correcto!
Y finalmente, la opción que voy a usar: convertir la
numpy
matriz alobject
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 y correcto!
fuente
'x' in np.arange(5)
, sugiere simplemente hacer'x' in np.arange(5).astype(object)
(o de manera similar :)'x' == np.arange(5).astype(object)
. ¿Derecho? En mi humilde opinión, esta es la solución más elegante que se muestra aquí, así que estoy confundido por la falta de votos a favor. ¿Quizás editar su respuesta para comenzar con el resultado final y luego pasar al análisis de rendimiento agradable?Tenía este código que estaba causando el error:
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
Lo cambié a esto:
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 la comparación, que arroja la advertencia, como se indicó anteriormente. Solo tuve que evitar la excepción debido a que
dfObj.loc
en el bucle for, tal vez haya una manera de decirle que no verifique las filas que ya ha cambiado.fuente
En mi caso, la advertencia se produjo solo por el tipo regular de indexación booleana, porque la serie solo tenía np.nan. Demostración (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
Creo que con pandas 1.0 realmente quieren que uses el nuevo
'string'
tipo de datos 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
No me encanta el momento en que jugaron con la funcionalidad diaria, como la indexación booleana.
fuente