Подтвердить что ты не робот

FutureWarning: элементарное сравнение не удалось; возвращающий скаляр, но в будущем будет выполнять элементное сравнение

Я использую Pandas 0.19.1 на Python 3. Я получаю предупреждение в этих строках кода. Я пытаюсь получить список, содержащий все номера строк, где строка Peter присутствует в столбце Unnamed: 5.

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

Внимание:

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

Что это за FutureWarning, и я должен игнорировать его, поскольку он работает.

4b9b3361

Ответ 1

Это предупреждение о будущем не от Pandas, оно от numpy, и ошибка также влияет на matplotlib и других, вот как воспроизвести предупреждение ближе к источнику проблемы:

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

Еще один способ воспроизвести эту ошибку с помощью оператора двойного равенства:

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

Пример Matplotlib, затронутого этим FutureWarning при реализации их колчана: https://matplotlib.org/examples/pylab_examples/quiver_demo.html

Что здесь происходит?

Существует разногласие между Numpy и собственным Python относительно того, что должно происходить, когда вы сравниваете строки с числовыми типами Numpy. Обратите внимание, что левый операнд - это python turf, примитивная строка, а средняя операция - это python turf, но правый операнд - numpy turf. Стоит ли возвращать Scalar в стиле Python или ndarray в стиле Numpy? Numpy говорит ndarray о bool, Pythonic разработчики не согласны. Классическое противостояние.

Должно ли это быть поэлементное сравнение или Скалярное, если элемент существует в массиве?

Если ваш код или библиотека используют операторы in или == для сравнения строки python с numy 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))   #returns False, without Warning

Подавлять предупреждение построчно.

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

Просто отключите предупреждение по имени, затем поместите громкий комментарий рядом с ним, упомянув текущую версию python и numpy, сказав, что этот код хрупкий и требует этих версий, и поместите ссылку здесь. Выбей банку вниз по дороге.

TLDR: pandas - джедай; numpy - хижины; и python - галактическая империя. https://youtu.be/OZczsiCfQQk?t=3

Ответ 2

Я получаю ту же ошибку, когда пытаюсь установить 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)

Я обновлю это, как только выясню причину такого поведения.

Ответ 3

Мой опыт в том же предупреждающем сообщении был вызван TypeError.

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

Надеюсь, что это поможет.

Ответ 4

Быстрый обходной путь для этого - использовать numpy.core.defchararray. Я также столкнулся с тем же предупреждающим сообщением и смог решить его, используя вышеуказанный модуль.

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

Ответ 5

Если ваши массивы не слишком велики или у вас их не слишком много, вам, возможно, удастся избежать использования левой части == в виде строки:

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

Но это ~ в 1,5 раза медленнее, если df['Unnamed: 5'] является строкой, в 25-30 раз медленнее, если df['Unnamed: 5'] является небольшим массивом (длина = 10), и в 150-160 раз медленнее, если это пустой массив с длиной 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

Ответ 6

Я получил это предупреждение, потому что я думал, что мой столбец содержит нулевые строки, но при проверке он содержал np.nan!

if df['column'] == '':

Помогло изменение моего столбца на пустые строки :)

Ответ 7

Я сравнил несколько методов, возможных для этого, включая панд, несколько простых методов и метод понимания списка.

Во-первых, давайте начнем с базовой линии:

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

Быстро и правильно!

Ответ 8

У меня был этот код, который вызывал ошибку:

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, возможно, есть способ сказать ему не проверять строки, которые он уже изменил.