Diese FutureWarning stammt nicht von Pandas, sondern von Numpy. Der Fehler betrifft auch Matplotlib und andere. So reproduzieren Sie die Warnung näher an der Ursache des Problems:
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
Eine andere Möglichkeit, diesen Fehler mit dem Operator double equals zu reproduzieren:
import numpy as np
np.arange(5) == np.arange(5).astype(str)
Ein Beispiel für Matplotlib, das von dieser FutureWarning im Rahmen der Implementierung des Köcherplots betroffen ist: https://matplotlib.org/examples/pylab_examples/quiver_demo.html
Was ist hier los?
Es gibt eine Meinungsverschiedenheit zwischen Numpy und nativem Python darüber, was passieren soll, wenn Sie eine Zeichenfolge mit den numerischen Typen von numpy vergleichen. Beachten Sie, dass der linke Operand Pythons Rasen ist, eine primitive Zeichenfolge, und die mittlere Operation ist Pythons Rasen, aber der rechte Operand ist Numpys Rasen. Sollten Sie einen Skalar im Python-Stil oder einen Ndarray im Bumpean-Stil im Numpy-Stil zurückgeben? Numpy sagt ndarray von bool, Pythonic-Entwickler sind anderer Meinung. Klassischer Abstandshalter.
Sollte es ein elementweiser Vergleich oder ein Skalar sein, wenn ein Element im Array vorhanden ist?
Wenn Ihr Code oder Ihre Bibliothek die Operatoren in
oder verwendet ==
, um Python-Zeichenfolgen mit numpy ndarrays zu vergleichen, sind sie nicht kompatibel. Wenn Sie es also versuchen, wird ein Skalar zurückgegeben, jedoch nur für den Moment. Die Warnung weist darauf hin, dass sich dieses Verhalten in Zukunft möglicherweise ändern wird, sodass Ihr Code über den gesamten Teppich kotzt, wenn Python / Numpy sich für den Numpy-Stil entscheidet.
Eingereichte Fehlerberichte:
Numpy und Python befinden sich in einer Pattsituation. Derzeit gibt die Operation einen Skalar zurück, der sich jedoch in Zukunft möglicherweise ändern wird.
https://github.com/numpy/numpy/issues/6784
https://github.com/pandas-dev/pandas/issues/7830
Zwei Problemumgehungslösungen:
Entweder Lockdown Ihre Version von Python und numpy, die Warnungen ignorieren und das Verhalten nicht ändern erwarten, oder konvertieren beide linken und rechten Operanden ==
und in
von einem numpy Typ oder primitive Python numerischen Typ zu sein.
Unterdrücken Sie die Warnung global:
import warnings
import numpy as np
warnings.simplefilter(action='ignore', category=FutureWarning)
print('x' in np.arange(5))
Unterdrücken Sie die Warnung zeilenweise.
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))
Unterdrücken Sie einfach die Warnung mit Namen und setzen Sie einen lauten Kommentar daneben, in dem die aktuelle Version von Python und Numpy erwähnt wird. Dieser Code ist spröde und erfordert diese Versionen. Fügen Sie hier einen Link hinzu. Treten Sie die Dose die Straße hinunter.
TLDR: pandas
sind Jedi; numpy
sind die Hütten; und python
ist das galaktische Reich. https://youtu.be/OZczsiCfQQk?t=3
thing
(die ein numpy-Typ sein kann oder nicht; ich weiß es nicht) und sehen möchte, obthing == 'some string'
ich ein einfachesbool
Ergebnis erhalte ?np.atleast_1d(thing)[0] == 'some string'
? Aber das ist nicht robust für einen Joker, der'some string'
das erste Element eines Arrays einfügt. Ich denke, ich muss zuerst den Typ testenthing
und dann nur dann==
testen, wenn es sich um eine Zeichenfolge handelt (oder nicht um ein numpy-Objekt).np.array([1, 2]) == []
wird auch die Warnung ausgelöst.or babysit your left and right operands to be from a common turf
Ich erhalte den gleichen Fehler, wenn ich versuche, das
index_col
Lesen einer Datei in den Datenrahmen eines zu setzenPanda
: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])
Ich bin noch nie auf einen solchen Fehler gestoßen. Ich versuche immer noch, den Grund dafür herauszufinden (unter Verwendung der Erklärung von @Eric Leschinski und anderer).
Wie auch immer, der folgende Ansatz löst das Problem vorerst, bis ich den Grund herausgefunden habe:
df = pd.read_csv('my_file.tsv', sep='\t', header=0) ## not setting the index_col df.set_index(['0'], inplace=True)
Ich werde dies aktualisieren, sobald ich den Grund für ein solches Verhalten herausgefunden habe.
quelle
read_csv()
. Sieht für mich nach etwas aus,pandas
das repariert werden muss.pd__version__: 0.22.0
;;np.__version__: 1.15.4
read_csv
wennindex_col
Parameter verwendet werden. Ich habe zwei Setups mit unterschiedlichen Ergebnissen getestet: 1. numpy Version 1.19.2, Pandas Version 1.1.2: FutureWarning: Elementweiser Vergleich fehlgeschlagen ... 2. numpy Version 1.19.2, Pandas Version 1.1.3: TypeError: ufunc ' isnan 'nicht unterstützt ...Meine Erfahrung mit derselben Warnmeldung wurde von TypeError verursacht.
Vielleicht möchten Sie den Datentyp des überprüfen
Unnamed: 5
for x in df['Unnamed: 5']: print(type(x)) # are they 'str' ?
So kann ich die Warnmeldung replizieren:
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
Ich hoffe es hilft.
quelle
df['num3'] == '3'
.df.loc[df['num3'] == 3, 'num3'] = 4 # No Error
Dieser Teil hilft mir. DankeDie unglaublich detaillierte Antwort von Eric Leschinski ist nicht zu übertreffen, aber hier ist eine kurze Lösung für die ursprüngliche Frage, von der ich glaube, dass sie noch nicht erwähnt wurde - setzen Sie die Zeichenfolge in eine Liste und verwenden Sie sie
.isin
stattdessen==
Zum Beispiel:
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"]
quelle
Eine schnelle Problemumgehung hierfür ist die Verwendung
numpy.core.defchararray
. Ich hatte auch die gleiche Warnmeldung und konnte sie mit dem obigen Modul beheben.import numpy.core.defchararray as npd resultdataset = npd.equal(dataset1, dataset2)
quelle
Erics Antwort erklärt hilfreich, dass das Problem darin besteht, eine Pandas-Serie (die ein NumPy-Array enthält) mit einer Python-Zeichenfolge zu vergleichen. Leider unterdrücken seine beiden Problemumgehungen nur die Warnung.
Um Code zu schreiben, der die Warnung überhaupt nicht verursacht, vergleichen Sie Ihre Zeichenfolge explizit mit jedem Element der Serie und erhalten Sie für jedes Element einen eigenen Bool. Zum Beispiel könnten Sie
map
eine anonyme Funktion verwenden.myRows = df[df['Unnamed: 5'].map( lambda x: x == 'Peter' )].index.tolist()
quelle
Wenn Ihre Arrays nicht zu groß sind oder Sie nicht zu viele davon haben, können Sie möglicherweise davonkommen, indem Sie die linke Seite
==
dazu zwingen , eine Zeichenfolge zu sein:myRows = df[str(df['Unnamed: 5']) == 'Peter'].index.tolist()
Dies ist jedoch ~ 1,5-mal langsamer, wenn
df['Unnamed: 5']
es sich um eine Zeichenfolge handelt, 25-30-mal langsamer, wenndf['Unnamed: 5']
es sich um ein kleines Numpy-Array handelt (Länge = 10), und 150-160-mal langsamer, wenn es sich um ein Numpy-Array mit einer Länge von 100 handelt (Zeiten gemittelt über 500 Versuche). .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)))
Ergebnis:
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
quelle
==
mitstr
war für mich eine gute Lösung, die die Leistung in 1,5 Millionen Zeilen kaum beeinträchtigte, die in Zukunft nicht größer werden.Ich habe diese Warnung erhalten, weil ich dachte, meine Spalte enthält Nullzeichenfolgen, aber beim Überprüfen enthielt sie np.nan!
if df['column'] == '':
Das Ändern meiner Spalte in leere Zeichenfolgen hat geholfen :)
quelle
Ich habe einige der dafür möglichen Methoden verglichen, darunter Pandas, mehrere Numpy-Methoden und eine Listenverständnismethode.
Beginnen wir zunächst mit einer Grundlinie:
>>> 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
Unsere Grundlinie ist also, dass die Zählung korrekt sein
2
sollte und wir ungefähr nehmen sollten50 us
.Nun versuchen wir die naive Methode:
>>> 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.
Und hier bekommen wir die falsche Antwort (
NotImplemented != 2
), es dauert lange und es wird die Warnung ausgegeben.Also werden wir eine andere naive Methode ausprobieren:
>>> %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 ==
Wieder die falsche Antwort (
0 != 2
). Dies ist umso heimtückischer, als es keine nachfolgenden Warnungen gibt (0
kann genauso weitergegeben werden2
).Versuchen wir nun ein Listenverständnis:
>>> %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
Wir bekommen hier die richtige Antwort und es geht ziemlich schnell!
Eine andere Möglichkeit
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 ==
Langsam aber richtig!
Und schließlich die Option, die ich verwenden werde: Umwandeln des
numpy
Arrays in denobject
Typ:>>> 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
Schnell und richtig!
quelle
'x' in np.arange(5)
, schlagen Sie IIUC vor, einfach zu tun'x' in np.arange(5).astype(object)
(oder ähnlich :)'x' == np.arange(5).astype(object)
. Richtig? IMHO, dies ist die eleganteste Problemumgehung, die hier gezeigt wird, daher bin ich durch das Fehlen von Upvotes verwirrt. Bearbeiten Sie möglicherweise Ihre Antwort, um mit dem Endergebnis zu beginnen, und fahren Sie dann mit der netten Leistungsanalyse fort?Ich hatte diesen Code, der den Fehler verursachte:
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
Ich habe es so geändert:
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
um den Vergleich zu vermeiden, der die Warnung auslöst - wie oben angegeben. Ich musste die Ausnahme nur wegen
dfObj.loc
der for-Schleife vermeiden. Vielleicht gibt es eine Möglichkeit, sie anzuweisen, die bereits geänderten Zeilen nicht zu überprüfen.quelle
In meinem Fall trat die Warnung nur aufgrund der regulären Art der booleschen Indizierung auf - weil die Serie nur np.nan hatte. Demonstration (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
Ich denke, mit pandas 1.0 möchten sie wirklich, dass Sie den neuen
'string'
Datentyp verwenden, derpd.NA
Werte zulässt :>>> 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
Lieben Sie nicht, an welchem Punkt sie an alltäglichen Funktionen wie der booleschen Indizierung herumgebastelt haben.
quelle