IT이야기

FutureWarning: 요소별 비교에 실패했습니다.

cyworld 2021. 9. 25. 11:11
반응형

FutureWarning: 요소별 비교에 실패했습니다. 스칼라를 반환하지만 앞으로는 요소별 비교를 수행할 것입니다.


0.19.1Python 3에서 Pandas 사용 하고 있습니다. 이 코드 줄에 대한 경고가 표시됩니다. string Peter이 column 에 있는 모든 행 번호가 포함된 목록을 얻으려고 합니다 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은 무엇이며 작동하는 것 같으므로 무시해야 합니다.


이 FutureWarning은 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

퀴버 플롯 구현에서 이 FutureWarning의 영향을 받는 Matplotlib의 예: https://matplotlib.org/examples/pylab_examples/quiver_demo.html

무슨 일이야?

문자열을 numpy의 숫자 유형과 비교할 때 어떤 일이 발생해야 하는지에 대해 Numpy와 기본 Python 간에 불일치가 있습니다. 왼쪽 피연산자는 기본 문자열인 파이썬의 영역이고 중간 연산은 파이썬의 영역이지만 오른쪽 피연산자는 numpy의 영역입니다. Python 스타일의 Scalar 또는 Numpy 스타일의 부울 ndarray를 반환해야 합니까? Numpy는 bool의 ndarray를 말하고 Pythonic 개발자는 동의하지 않습니다. 클래식 스탠드오프.

항목이 배열에 있는 경우 요소별 비교 또는 스칼라여야 합니까?

코드나 라이브러리가 inor ==연산자를 사용하여 python 문자열을 numpy ndarrays와 비교하는 경우 호환되지 않으므로 시도하면 스칼라를 반환하지만 지금은 해당되지 않습니다. 경고는 python/numpy가 Numpy 스타일을 채택하기로 결정한 경우 코드가 카펫 전체에 토하도록 이 동작이 미래에 변경될 수 있음을 나타냅니다.

제출된 버그 보고서:

Numpy와 Python은 교착 상태에 있습니다. 현재 연산은 스칼라를 반환하지만 미래에는 변경될 수 있습니다.

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

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

두 가지 해결 방법:

어느 쪽이든, 파이썬과 NumPy와 버전을 잠 그려면 경고를 무시하고없는 변화에 행동을 기대, 또는 둘 다 왼쪽과 오른쪽 피연산자를 변환 ==하고 inNumPy와 유형 또는 원시 파이썬 숫자 유형에서 할 수 있습니다.

전역적으로 경고를 억제합니다.

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


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)

그러한 행동에 대한 이유를 파악하는 즉시 업데이트하겠습니다.


동일한 경고 메시지에 대한 내 경험은 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

도움이 되기를 바랍니다.


이에 대한 빠른 해결 방법은 를 사용하는 것 numpy.core.defchararray입니다. 나는 또한 동일한 경고 메시지에 직면했고 위의 모듈을 사용하여 해결할 수 있었습니다.

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

배열이 너무 크지 않거나 배열이 너무 많지 않은 경우 의 왼쪽을 강제 ==로 문자열로 만들 수 있습니다.

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

그러나 이것은 df['Unnamed: 5']문자열인 경우 ~1.5배 df['Unnamed: 5'], 작은 numpy 배열(길이 = 10)인 경우 25-30배 , 길이가 100인 numpy 배열인 경우 150-160배 느립니다(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

내 열에 null 문자열이 포함되어 있다고 생각했기 때문에 이 경고가 표시되었지만 확인 시 np.nan이 포함되어 있습니다!

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

내 열을 빈 문자열로 변경하면 도움이 되었습니다. :)


팬더, 여러 가지 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

따라서 우리의 기준은 개수가 정확해야 하며 250 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

빠르고 정확합니다!


오류를 일으키는이 코드가 있습니다.

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.locfor 루프 때문에 예외를 피해야 했습니다. 이미 변경된 행을 확인하지 않도록 지시하는 방법이 있을 수 있습니다.

ReferenceURL : https://stackoverflow.com/questions/40659212/futurewarning-elementwise-comparison-failed-returning-scalar-but-in-the-futur

반응형