To FutureWarning nie pochodzi z Pand, jest z numpy, a błąd dotyczy również matplotlib i innych, oto jak odtworzyć ostrzeżenie bliżej źródła problemu:
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
Inny sposób odtworzenia tego błędu przy użyciu operatora double równa się:
import numpy as np
np.arange(5) == np.arange(5).astype(str)
Przykład Matplotlib, na który wpłynęło to FutureWarning w ramach implementacji wątku kołczanowego: https://matplotlib.org/examples/pylab_examples/quiver_demo.html
Co tu się dzieje?
Między Numpy a natywnym Pythonem nie ma zgody co do tego, co powinno się stać, gdy porównujesz łańcuchy z typami liczbowymi numpy. Zwróć uwagę, że lewy operand to obszar Pythona, prymitywny łańcuch, a operacja środkowa to obszar Pythona, ale prawy operand to obszar numpy'ego. Czy należy zwrócić tablicę skalarną w stylu Pythona czy tablicę logiczną w stylu Numpy? Numpy mówi ndarray of bool, programiści Pythonic nie zgadzają się z tym. Klasyczny dystans.
Czy powinno to być porównanie elementarne czy skalarne, jeśli element istnieje w tablicy?
Jeśli Twój kod lub biblioteka używają operatorów in
lub ==
do porównywania ciągu znaków Pythona z numpy ndarrays, nie są one zgodne, więc jeśli spróbujesz, zwraca wartość skalarną, ale tylko na razie. Ostrzeżenie wskazuje, że w przyszłości to zachowanie może się zmienić, więc twój kod rzyga po całym dywanie, jeśli python / numpy zdecydują się na przyjęcie stylu Numpy.
Zgłoszone raporty o błędach:
Numpy i Python są w impasie, na razie operacja zwraca skalar, ale w przyszłości może się to zmienić.
https://github.com/numpy/numpy/issues/6784
https://github.com/pandas-dev/pandas/issues/7830
Dwa rozwiązania obejścia:
Albo zablokuj swoją wersję języka Python i numpy, zignoruj ostrzeżenia i spodziewaj się, że zachowanie się nie zmieni, lub przekonwertuj lewy i prawy operand z ==
i in
będą z typu numpy lub prymitywnego typu liczbowego Python.
Pomiń ostrzeżenie globalnie:
import warnings
import numpy as np
warnings.simplefilter(action='ignore', category=FutureWarning)
print('x' in np.arange(5))
Pomiń ostrzeżenie wiersz po wierszu.
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))
Po prostu stłum ostrzeżenie według nazwy, a następnie umieść głośny komentarz obok niego, wspominając o aktualnej wersji Pythona i numpy, mówiąc, że ten kod jest kruchy i wymaga tych wersji, i umieść link do tutaj. Kopnij puszkę w dół drogi.
TLDR: pandas
są Jedi; numpy
są chaty; i python
jest imperium galaktycznym. https://youtu.be/OZczsiCfQQk?t=3
thing
(która może, ale nie musi być typem odrętwienia, nie wiem) i chcę zobaczyć, czything == 'some string'
uzyskać prostybool
wynik, co powinienem zrobić?np.atleast_1d(thing)[0] == 'some string'
? Ale to nie jest solidne dla jakiegoś jokera, który umieściłby'some string'
pierwszy element tablicy. Myślę, że muszęthing
najpierw przetestować typ, a następnie wykonać==
test tylko wtedy, gdy jest to ciąg znaków (lub nie obiekt numpy).np.array([1, 2]) == []
również podniesie ostrzeżenie.or babysit your left and right operands to be from a common turf
Otrzymuję ten sam błąd, gdy próbuję ustawić
index_col
odczyt pliku doPanda
ramki danych: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])
Nigdy wcześniej nie spotkałem się z takim błędem. Nadal próbuję znaleźć przyczynę tego (używając wyjaśnienia @Eric Leschinski i innych).
W każdym razie następujące podejście na razie rozwiązuje problem, dopóki nie znajdę przyczyny:
df = pd.read_csv('my_file.tsv', sep='\t', header=0) ## not setting the index_col df.set_index(['0'], inplace=True)
Zaktualizuję to, gdy tylko znajdę przyczynę takiego zachowania.
źródło
read_csv()
. Wydaje mi się, że cośpandas
trzeba naprawić.pd__version__: 0.22.0
;np.__version__: 1.15.4
read_csv
podczas używaniaindex_col
parametru. Przetestowałem dwie konfiguracje z różnymi wynikami: 1. numpy wersja 1.19.2, Pandas wersja 1.1.2: FutureWarning: porównanie elementwise nie powiodło się ... 2. numpy wersja 1.19.2, Pandas wersja 1.1.3: TypeError: ufunc ' isnan 'nie jest obsługiwany ...Moje doświadczenie z tym samym komunikatem ostrzegawczym zostało spowodowane przez TypeError.
Więc możesz chcieć sprawdzić typ danych
Unnamed: 5
for x in df['Unnamed: 5']: print(type(x)) # are they 'str' ?
Oto, jak mogę powtórzyć komunikat ostrzegawczy:
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
Mam nadzieję, że to pomoże.
źródło
df['num3'] == '3'
.df.loc[df['num3'] == 3, 'num3'] = 4 # No Error
Ta część mi pomaga. DziękiNie mogę przebić niesamowicie szczegółowej odpowiedzi Erica Leschinskiego, ale oto szybkie obejście pierwotnego pytania, o którym nie sądzę, że zostało jeszcze wspomniane - umieść ciąg na liście i użyj
.isin
zamiast==
Na przykład:
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"]
źródło
Szybkim obejściem tego jest użycie
numpy.core.defchararray
. Napotkałem również ten sam komunikat ostrzegawczy i udało mi się go rozwiązać za pomocą powyższego modułu.import numpy.core.defchararray as npd resultdataset = npd.equal(dataset1, dataset2)
źródło
Odpowiedź Erica w pomocny sposób wyjaśnia, że problem wynika z porównania serii Pandas (zawierającej tablicę NumPy) z ciągiem znaków Pythona. Niestety, oba jego obejścia tylko pomijają ostrzeżenie.
Aby napisać kod, który nie powoduje ostrzeżenia w pierwszej kolejności, jawnie porównaj swój ciąg z każdym elementem Series i uzyskaj oddzielną wartość bool dla każdego. Na przykład możesz użyć
map
i anonimowej funkcji.myRows = df[df['Unnamed: 5'].map( lambda x: x == 'Peter' )].index.tolist()
źródło
Jeśli twoje tablice nie są zbyt duże lub nie masz ich zbyt wiele, możesz być w stanie wymusić na lewej stronie
==
ciąg znaków:myRows = df[str(df['Unnamed: 5']) == 'Peter'].index.tolist()
Ale to jest ~ 1,5 raza wolniej, jeśli
df['Unnamed: 5']
jest ciągiem, 25-30 razy wolniej, jeślidf['Unnamed: 5']
jest to mała tablica numpy (długość = 10) i 150-160 razy wolniej, jeśli jest to tablica numpy o długości 100 (razy uśredniona z 500 prób) .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)))
Wynik:
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
źródło
==
zstr
był dla mnie dobrym rozwiązaniem, które ledwo wpłynęło na wydajność 1,5 miliona wierszy, które nie będą większe niż w przyszłości.W moim przypadku ostrzeżenie wystąpiło właśnie z powodu zwykłego typu indeksowania boolowskiego - bo seria miała tylko np.nan. Demonstracja (pandy 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
Myślę, że w pandach 1.0 naprawdę chcą, abyś używał nowego
'string'
typu danych, który pozwala napd.NA
wartości:>>> 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
Nie podoba mi się, w którym momencie majstrowali przy codziennych funkcjach, takich jak indeksowanie logiczne.
źródło
Otrzymałem to ostrzeżenie, ponieważ myślałem, że moja kolumna zawiera ciągi zerowe, ale po sprawdzeniu zawierała np.nan!
if df['column'] == '':
Pomogła zmiana mojej kolumny na puste ciągi :)
źródło
Porównałem kilka możliwych metod, w tym pandy, kilka metod numpy i metodę rozumienia listy.
Najpierw zacznijmy od linii bazowej:
>>> 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
Tak więc naszym punktem odniesienia jest to, że liczba powinna być poprawna
2
i powinniśmy się zająć50 us
.Teraz próbujemy naiwnej metody:
>>> 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.
I tutaj otrzymujemy złą odpowiedź (
NotImplemented != 2
), zajmuje nam to dużo czasu i rzuca ostrzeżenie.Spróbujemy więc innej naiwnej metody:
>>> %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 ==
Znowu zła odpowiedź (
0 != 2
). Jest to jeszcze bardziej podstępne, ponieważ nie ma kolejnych ostrzeżeń (0
można je przekazać tak samo2
).Teraz spróbujmy zrozumieć listę:
>>> %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
Mamy tutaj właściwą odpowiedź i jest to dość szybkie!
Inna możliwość
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 ==
Powolne, ale poprawne!
I na koniec opcja, której zamierzam użyć: rzutowanie
numpy
tablicy naobject
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
Szybko i poprawnie!
źródło
'x' in np.arange(5)
, sugerujesz po prostu zrobienie'x' in np.arange(5).astype(object)
(lub podobnie :)'x' == np.arange(5).astype(object)
. Dobrze? IMHO, jest to najbardziej eleganckie obejście pokazane tutaj, więc jestem zdezorientowany brakiem głosów za. Może edytuj swoją odpowiedź, aby rozpocząć od dolnej linii, a następnie przejdź do ładnej analizy wydajności?Miałem ten kod, który powodował błąd:
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
Zmieniłem to na to:
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
aby uniknąć porównania, które rzuca ostrzeżenie - jak wspomniano powyżej. Musiałem tylko uniknąć wyjątku z powodu
dfObj.loc
pętli for, być może jest sposób, aby powiedzieć mu, aby nie sprawdzał wierszy, które już zmienił.źródło