web-dev-qa-db-fra.com

FutureWarning: la comparaison élémentaire a échoué; retour scalaire, mais à l'avenir effectuera une comparaison élémentaire

J'utilise Pandas 0.19.1 sur Python 3. Je reçois un avertissement sur ces lignes de code. J'essaie d'obtenir une liste contenant tous les numéros de ligne où la chaîne Peter est présente dans la colonne Unnamed: 5.

df = pd.read_Excel(xls_path)
myRows = df[df['Unnamed: 5'] == 'Peter'].index.tolist()

Attention:

"\Python36\lib\site-packages\pandas\core\ops.py:792: FutureWarning: elementwise 
comparison failed; returning scalar, but in the future will perform 
elementwise comparison 
result = getattr(x, name)(y)"

Quelle est cette FutureWarning et devrais-je l'ignorer car cela semble fonctionner. 

26
Arturo

Ce FutureWarning n'est pas de Pandas, mais de numpy et le bogue affecte également matplotlib et d'autres. Voici comment reproduire l'avertissement plus près de la source du problème:

import numpy as np
print(np.__version__)   # Numpy version '1.12.0'
'x' in np.arange(5)       #Future warning thrown here

FutureWarning: elementwise comparison failed; returning scalar instead, but in the 
future will perform elementwise comparison
False

Une autre façon de reproduire ce bogue en utilisant l'opérateur double égal:

import numpy as np
np.arange(5) == np.arange(5).astype(str)    #FutureWarning thrown here

Un exemple de Matplotlib affecté par ce FutureWarning dans son implémentation de quiver plot: https://matplotlib.org/examples/pylab_examples/quiver_demo.html

Que se passe t-il ici?

Il y a un désaccord entre Numpy et Python natif sur ce qui devrait se passer lorsque vous comparez une chaîne à des types numériques. Notez que l'opérande de gauche est le turf de python, une chaîne primitive, et que l'opération du milieu est le turf de python, alors que l'opérande de droite est le turf de numpy. Devez-vous renvoyer un scalaire de style Python ou un ndarray de booléens de style Numpy? Numpy dit que ndarray of bool, les développeurs Pythonic ne sont pas d’accord. Impasse classique.

Devrait-il s'agir d'une comparaison élémentaire ou de Scalar si l'élément existe dans le tableau? 

Si votre code ou votre bibliothèque utilise les opérateurs in ou == pour comparer une chaîne python à numpy ndarrays, ils ne sont pas compatibles. Par conséquent, si vous l'essayez, il renvoie un scalaire, mais uniquement pour l'instant. L'avertissement indique qu'à l'avenir, ce comportement pourrait changer, de sorte que votre code se répand sur le tapis si python/numpy décide d'adopter le style Numpy. 

Rapports de bogues soumis:

Numpy et Python sont dans une impasse, pour le moment l'opération renvoie un scalaire, mais peut changer à l'avenir.

https://github.com/numpy/numpy/issues/6784

https://github.com/pandas-dev/pandas/issues/7830

Deux solutions de contournement:

Soit verrouillez votre version de python et numpy et ignorez les avertissements, ou veillez à ce que vos opérandes gauche et droit appartiennent à un terrain commun.

Supprimer l'avertissement globalement:

import warnings
import numpy as np
warnings.simplefilter(action='ignore', category=FutureWarning)
print('x' in np.arange(5))   #returns False, without Warning

Supprimer l'avertissement ligne par ligne.

import warnings
import numpy as np

with warnings.catch_warnings():
    warnings.simplefilter(action='ignore', category=FutureWarning)
    print('x' in np.arange(2))   #returns False, warning is suppressed

print('x' in np.arange(10))   #returns False, Throws FutureWarning

Supprimez simplement l'avertissement par son nom, puis mettez un commentaire fort à côté de celui-ci, mentionnant la version actuelle de python et numpy, indiquant que ce code est fragile et nécessite ces versions et place un lien vers cet emplacement. Kick la canette sur la route.

39
Eric Leschinski

Mon expérience avec le même message d'avertissement a été provoquée par TypeError.

TypeError: comparaison de type non valide

Donc, vous voudrez peut-être vérifier le type de données du Unnamed: 5

for x in df['Unnamed: 5']:
  print(type(x))  # are they 'str' ?

Voici comment je peux répliquer le message d'avertissement: 

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

J'espère que ça aide.

1
yhd.leung

La même erreur se produit lorsque j'essaie de définir le index_col lisant un fichier dans un cadre de données Panda:

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])

Je n'ai jamais rencontré une telle erreur auparavant. J'essaie encore de comprendre la raison derrière cela (en utilisant l'explication de @Eric Leschinski et d'autres).

Quoi qu'il en soit, l'approche suivante résout le problème pour l'instant jusqu'à ce que je comprenne la raison:

df = pd.read_csv('my_file.tsv', sep='\t', header=0)  ## not setting the index_col
df.set_index(['0'], inplace=True)

Je mettrai à jour cela dès que je comprendrai la raison d'un tel comportement. 

1
Dataman

Si vos tableaux ne sont pas trop grands ou si vous n'en avez pas beaucoup, vous pourrez peut-être vous permettre de forcer le côté gauche de == à être une chaîne:

myRows = df[str(df['Unnamed: 5']) == 'Peter'].index.tolist()

Mais cela est environ 1,5 fois plus lent si df['Unnamed: 5'] est une chaîne, 25-30 fois plus lente si df['Unnamed: 5'] est un petit tableau numpy (longueur = 10) et 150 à 160 fois plus lent s'il s'agit d'un tableau numpy de longueur 100 essais).

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

Résultat:

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
0
EL_DON

Une solution rapide consiste à utiliser numpy.core.defchararray. J'ai également été confronté au même message d'avertissement et j'ai pu le résoudre en utilisant le module ci-dessus.

import numpy.core.defchararray as npd
resultdataset = npd.equal(dataset1, dataset2)
0
Jeet23