Это FutureWarning не от Pandas, это от numpy, и ошибка также влияет на matplotlib и другие, вот как воспроизвести предупреждение ближе к источнику проблемы:
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
Другой способ воспроизвести эту ошибку с помощью оператора двойного равенства:
import numpy as np
np.arange(5) == np.arange(5).astype(str)
Пример Matplotlib, на который распространяется это FutureWarning, в их реализации сюжета колчана: https://matplotlib.org/examples/pylab_examples/quiver_demo.html
Что тут происходит?
Существует разногласие между Numpy и собственным питоном по поводу того, что должно произойти, когда вы сравниваете строки с числовыми типами numpy. Обратите внимание, что левый операнд - это область Python, примитивная строка, а средняя операция - это область Python, но правый операнд - это область numpy. Следует ли возвращать Scalar в стиле Python или ndarray в стиле Numpy для Boolean? Numpy говорит, что ndarray от bool, разработчики Pythonic не согласны. Классическое противостояние.
Должно ли это быть поэлементное сравнение или скалярное, если элемент существует в массиве?
Если в вашем коде или библиотеке используются операторы in
или ==
для сравнения строки Python с numpy ndarrays, они несовместимы, поэтому, если вы попробуете, он вернет скаляр, но только на данный момент. Предупреждение указывает, что в будущем это поведение может измениться, поэтому ваш код будет рвать по всему ковру, если python / numpy решит принять стиль Numpy.
Отправленные отчеты об ошибках:
Numpy и Python находятся в противостоянии, пока операция возвращает скаляр, но в будущем это может измениться.
https://github.com/numpy/numpy/issues/6784
https://github.com/pandas-dev/pandas/issues/7830
Два обходных решения:
Либо заблокируйте свою версию python и numpy, игнорируйте предупреждения и ожидайте, что поведение не изменится, либо преобразуйте левый и правый операнды ==
и in
должны быть из типа numpy или примитивного числового типа python.
Подавить предупреждение глобально:
import warnings
import numpy as np
warnings.simplefilter(action='ignore', category=FutureWarning)
print('x' in np.arange(5))
Подавлять предупреждение построчно.
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))
Просто подавите предупреждение по имени, затем поставьте рядом с ним громкий комментарий, в котором упоминается текущая версия python и numpy, говоря, что этот код хрупкий и требует этих версий, и поместите ссылку здесь. Выбей консервную банку по дороге.
TL pandas
; DR: джедаи; numpy
хижины; и python
это галактическая империя. https://youtu.be/OZczsiCfQQk?t=3
thing
(которое может быть или не быть типом numpy; я не знаю), и я хочу посмотреть,thing == 'some string'
получится ли и получить простойbool
результат, что мне делать?np.atleast_1d(thing)[0] == 'some string'
? Но это ненадежно для какого-нибудь шутника, вставляющего'some string'
первый элемент массива. Я думаю, мне нужноthing
сначала проверить тип, а затем выполнить==
тест только в том случае, если это строка (или не объект numpy).np.array([1, 2]) == []
также вызовет предупреждение.or babysit your left and right operands to be from a common turf
Я получаю ту же ошибку, когда пытаюсь установить
index_col
чтение файла во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])
Раньше с такой ошибкой не сталкивался. Я все еще пытаюсь выяснить причину этого (используя объяснение @Eric Leschinski и другие).
Во всяком случае, следующий подход решает проблему на данный момент, пока я не выясню причину:
df = pd.read_csv('my_file.tsv', sep='\t', header=0) ## not setting the index_col df.set_index(['0'], inplace=True)
Я обновлю это, как только выясню причину такого поведения.
источник
read_csv()
. Мне кажется, чтоpandas
нужно исправить.pd__version__: 0.22.0
;np.__version__: 1.15.4
read_csv
при использованииindex_col
параметра. Я тестировал две настройки с разными результатами: 1. numpy версии 1.19.2, Pandas версии 1.1.2: FutureWarning: поэлементное сравнение не удалось ... 2. numpy версии 1.19.2, Pandas версии 1.1.3: TypeError: ufunc ' isnan 'не поддерживается ...По моему опыту, такое же предупреждающее сообщение было вызвано TypeError.
Итак, вы можете проверить тип данных
Unnamed: 5
for x in df['Unnamed: 5']: print(type(x)) # are they 'str' ?
Вот как я могу воспроизвести предупреждающее сообщение:
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
Надеюсь, это поможет.
источник
df['num3'] == '3'
.df.loc[df['num3'] == 3, 'num3'] = 4 # No Error
Эта часть мне помогает. СпасибоНе могу победить потрясающе подробный ответ Эрика Лещинского, но вот быстрый способ решения исходного вопроса, который, я думаю, еще не упоминался - поместите строку в список и используйте
.isin
вместо==
Например:
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"]
источник
Быстрый обходной путь - использовать
numpy.core.defchararray
. Я также столкнулся с тем же предупреждающим сообщением и смог решить его с помощью вышеуказанного модуля.import numpy.core.defchararray as npd resultdataset = npd.equal(dataset1, dataset2)
источник
Ответ Эрика услужливо объясняет, что проблема возникает из-за сравнения серии Pandas (содержащей массив NumPy) со строкой Python. К сожалению, оба его обходных пути просто подавляют предупреждение.
Чтобы написать код, который вообще не вызывает предупреждения, явно сравните свою строку с каждым элементом серии и получите для каждого отдельный bool. Например, вы можете использовать
map
и анонимную функцию.myRows = df[df['Unnamed: 5'].map( lambda x: x == 'Peter' )].index.tolist()
источник
Если ваши массивы не слишком велики или у вас их не слишком много, вы можете уйти, заставив левую часть
==
быть строкой:myRows = df[str(df['Unnamed: 5']) == 'Peter'].index.tolist()
Но это примерно в 1,5 раза медленнее, если
df['Unnamed: 5']
это строка, в 25-30 раз медленнее, еслиdf['Unnamed: 5']
это небольшой массив numpy (длина = 10), и в 150-160 раз медленнее, если это массив numpy длиной 100 (в среднем по 500 попыткам) .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)))
Результат:
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
источник
==
с помощьюstr
было для меня хорошим решением, которое почти не повлияло на производительность на 1,5 миллиона строк, которые в будущем не станут больше.Я получил это предупреждение, потому что думал, что мой столбец содержит пустые строки, но при проверке он содержал np.nan!
if df['column'] == '':
Помогло изменение моего столбца на пустые строки :)
источник
Я сравнил несколько возможных для этого методов, включая pandas, несколько методов numpy и метод понимания списка.
Во-первых, давайте начнем с базовой линии:
>>> 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
Итак, наша исходная позиция - подсчет должен быть правильным
2
, и мы должны принять меры50 us
.Теперь попробуем наивный метод:
>>> 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.
И здесь мы получаем неправильный ответ (
NotImplemented != 2
), это занимает у нас много времени и выдает предупреждение.Итак, попробуем другой наивный метод:
>>> %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 ==
Опять неправильный ответ (
0 != 2
). Это еще более коварно, потому что нет никаких последующих предупреждений (0
их можно передавать точно так же2
).Теперь попробуем составить список:
>>> %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
Здесь мы получаем правильный ответ, и это довольно быстро!
Другая возможность
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 ==
Медленно, но правильно!
И, наконец, вариант, который я собираюсь использовать: приведение
numpy
массива кobject
типу:>>> 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
Быстро и правильно!
источник
'x' in np.arange(5)
, вы предлагаете просто сделать'x' in np.arange(5).astype(object)
(или аналогично :)'x' == np.arange(5).astype(object)
. Правильно? ИМХО, это самый элегантный обходной путь, показанный здесь, поэтому меня смущает отсутствие голосов. Может быть, отредактируйте свой ответ, чтобы начать с нижней строки, а затем перейти к хорошему анализу производительности?У меня был этот код, который вызывал ошибку:
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
Я изменил его на это:
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
чтобы избежать сравнения, которое вызывает предупреждение - как указано выше. Мне нужно было избежать исключения только из
dfObj.loc
-за цикла for, возможно, есть способ запретить ему проверять строки, которые он уже изменил.источник
В моем случае предупреждение возникло только из-за обычного типа логической индексации - потому что в серии был только np.nan. Демонстрация (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
Я думаю, что с pandas 1.0 они действительно хотят, чтобы вы использовали новый
'string'
тип данных, который допускаетpd.NA
значения:>>> 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
Не люблю, когда они возились с повседневными функциями, такими как логическое индексирование.
источник