FutureWarning: không thể so sánh theo phần tử; trả về vô hướng, nhưng trong tương lai sẽ thực hiện so sánh từng phần tử


100

Tôi đang sử dụng Pandas 0.19.1trên Python 3. Tôi nhận được cảnh báo về những dòng mã này. Tôi đang cố gắng lấy một danh sách chứa tất cả các số hàng mà chuỗi Petercó ở cột Unnamed: 5.

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

Nó tạo ra một Cảnh báo:

"\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 này là gì và tôi có nên bỏ qua nó không vì nó có vẻ hoạt động.

Câu trả lời:


159

FutureWarning này không phải từ Pandas, mà là từ numpy và lỗi này cũng ảnh hưởng đến matplotlib và các loại khác, đây là cách tạo lại cảnh báo gần nguồn gốc của sự cố:

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

Một cách khác để tái tạo lỗi này bằng cách sử dụng toán tử dấu bằng kép:

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

Một ví dụ về Matplotlib bị ảnh hưởng bởi FutureWarning này trong quá trình triển khai âm mưu rung chuyển của họ: https://matplotlib.org/examples/pylab_examples/quiver_demo.html

Những gì đang xảy ra ở đây?

Có sự bất đồng giữa Numpy và native python về điều gì sẽ xảy ra khi bạn so sánh chuỗi với kiểu số của numpy. Lưu ý toán hạng bên trái là sân của python, một chuỗi nguyên thủy và phép toán ở giữa là sân của python, nhưng toán hạng bên phải là sân của numpy. Bạn nên trả lại Scalar kiểu Python hay một ndarray kiểu Numpy của Boolean? Numpy nói ndarray of bool, các nhà phát triển Pythonic không đồng ý. Cổ điển bế tắc.

Nó có nên là so sánh theo từng phần tử hoặc Scalar nếu mục tồn tại trong mảng không?

Nếu mã hoặc thư viện của bạn đang sử dụng toán tử inor ==để so sánh chuỗi python với ndarrays numpy, chúng không tương thích, vì vậy nếu bạn thử nó, nó sẽ trả về một đại lượng vô hướng, nhưng chỉ hiện tại. Cảnh báo cho biết rằng trong tương lai, hành vi này có thể thay đổi, vì vậy mã của bạn sẽ kêu rắc rắc trên thảm nếu python / numpy quyết định áp dụng kiểu Numpy.

Đã gửi báo cáo lỗi:

Numpy và Python đang gặp khó khăn, hiện tại phép toán trả về một đại lượng vô hướng, nhưng trong tương lai, nó có thể thay đổi.

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

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

Hai giải pháp thay thế:

Khóa phiên bản python và numpy của bạn, bỏ qua các cảnh báo và mong muốn hành vi không thay đổi hoặc chuyển đổi cả hai toán hạng trái và phải của ==inthành từ kiểu numpy hoặc kiểu số python nguyên thủy.

Ngăn chặn cảnh báo trên toàn cầu:

import warnings
import numpy as np
warnings.simplefilter(action='ignore', category=FutureWarning)
print('x' in np.arange(5))   #returns False, without Warning

Loại bỏ cảnh báo trên cơ sở từng dòng.

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

Chỉ cần ngăn chặn cảnh báo bằng tên, sau đó đặt một bình luận lớn bên cạnh nó đề cập đến phiên bản hiện tại của python và numpy, nói rằng mã này rất dễ hỏng và yêu cầu các phiên bản này và đặt một liên kết đến đây. Đá cái lon xuống đường.

TLDR: pandas là Jedi; numpylà những túp lều; và pythonlà đế chế thiên hà. https://youtu.be/OZczsiCfQQk?t=3


1
Ặc. Vì vậy, nếu tôi có một số lượng thing(có thể có hoặc có thể không thuộc loại numpy; tôi không biết) và tôi muốn xem nếu thing == 'some string'và nhận được một boolkết quả đơn giản , tôi phải làm gì? np.atleast_1d(thing)[0] == 'some string'? Nhưng điều đó không mạnh mẽ đối với một số joker đưa 'some string'vào phần tử đầu tiên của một mảng. Tôi đoán tôi phải kiểm tra loại thingđầu tiên và sau đó chỉ thực hiện ==kiểm tra nếu đó là một chuỗi (hoặc không phải là một đối tượng numpy).
EL_DON

1
Trên thực tế, cảnh báo trong tương lai này cũng được đưa ra bất cứ khi nào bạn cố gắng so sánh numpy.ndarray với một danh sách trống. Ví dụ: việc thực thi np.array([1, 2]) == []cũng sẽ nâng cao cảnh báo.
1313e

2
Tôi sẽ thấy hữu ích khi xem một ví dụ về việc này:or babysit your left and right operands to be from a common turf
HaPsantran

10
Đây là mức thông tin chất lượng đáng kinh ngạc về vấn đề này.
StephenBoesch

Vì vậy, tôi sẽ loại bỏ cảnh báo trên mã này: df.loc [df.cName == '', 'cName'] = '10004'. Nói cách khác, gấu trúc / numpy tương đương với trăn là gì '' (chuỗi trống)
Garet Jax

13

Tôi gặp lỗi tương tự khi cố gắng đặt việc index_colđọc tệp thành Pandakhung dữ liệu của:

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

Tôi chưa bao giờ gặp lỗi như vậy trước đây. Tôi vẫn đang cố gắng tìm ra lý do đằng sau điều này (sử dụng lời giải thích của @Eric Leschinski và những người khác).

Nhưng dù sao, cách tiếp cận sau đây giải quyết được vấn đề cho đến khi tôi tìm ra lý do:

df = pd.read_csv('my_file.tsv', sep='\t', header=0)  ## not setting the index_col
df.set_index(['0'], inplace=True)

Tôi sẽ cập nhật điều này ngay khi tôi tìm ra lý do cho hành vi như vậy.


Tôi có cùng một vấn đề với read_csv(). Đối với tôi, có vẻ như một cái gì đó pandascần phải sửa chữa.
Konstantin

1
Cảm ơn! Đã tiết kiệm cho tôi rất nhiều việc - tôi đoán vậy. pd__version__: 0.22.0; np.__version__: 1.15.4
Markus Dutschke

1
Vấn đề tương tự ở đây, dường như một số cuộc gọi phức tạp bên trong read_csvkhi sử dụng index_coltham số. Tôi đã kiểm tra hai thiết lập với các kết quả khác nhau: 1. phiên bản numpy 1.19.2, phiên bản Pandas 1.1.2: FutureWarning: so sánh phần tử không thành công ... 2. phiên bản numpy 1.19.2, phiên bản Pandas 1.1.3: TypeError: ufunc ' isnan 'không được hỗ trợ ...
Carlos

9

Trải nghiệm của tôi đối với thông báo cảnh báo tương tự là do TypeError.

TypeError: so sánh kiểu không hợp lệ

Vì vậy, bạn có thể muốn kiểm tra kiểu dữ liệu của Unnamed: 5

for x in df['Unnamed: 5']:
  print(type(x))  # are they 'str' ?

Đây là cách tôi có thể sao chép thông báo cảnh báo:

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

Hy vọng nó giúp.


1
Mã của bạn có rất nhiều phần chuyển động không cần thiết để minh họa cảnh báo. Pandas ban ơn cho bạn với TypeError bổ sung đó nhưng đó là kiểm soát thiệt hại từ Pandas, Cảnh báo nguồn là sự bất đồng giữa Numpy và Python và xảy ra khi đánh giá df['num3'] == '3'.
Eric Leschinski

1
df.loc[df['num3'] == 3, 'num3'] = 4 # No ErrorPhần này giúp tôi. Cảm ơn
jameslem

6

Không thể đánh bại câu trả lời chi tiết đáng kinh ngạc của Eric Leschinski, nhưng đây là một giải pháp nhanh chóng cho câu hỏi ban đầu mà tôi nghĩ là chưa được đề cập đến - đặt chuỗi vào danh sách và sử dụng .isinthay vì==

Ví dụ:

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

tôi tự hỏi nếu tôi có thể làm tương tự với cú pháp này -> nếu "-" trong DFN [ 'Drate'] duy nhất ().
lone_coder

3

Một giải pháp nhanh chóng cho điều này là sử dụng numpy.core.defchararray. Tôi cũng gặp phải thông báo cảnh báo tương tự và có thể giải quyết nó bằng cách sử dụng mô-đun trên.

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

2

Câu trả lời của Eric giải thích một cách hữu ích rằng rắc rối đến từ việc so sánh Chuỗi Pandas (chứa mảng NumPy) với chuỗi Python. Thật không may, hai cách giải quyết của anh ấy đều chỉ ngăn chặn cảnh báo.

Để viết mã không gây ra cảnh báo ngay từ đầu, hãy so sánh rõ ràng chuỗi của bạn với từng phần tử của Chuỗi và nhận bool riêng cho từng phần tử. Ví dụ, bạn có thể sử dụng mapvà một chức năng ẩn danh.

myRows = df[df['Unnamed: 5'].map( lambda x: x == 'Peter' )].index.tolist()

1

Nếu các mảng của bạn không quá lớn hoặc bạn không có quá nhiều trong số chúng, bạn có thể bỏ qua việc buộc phía bên trái của ==là một chuỗi:

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

Nhưng điều này chậm hơn ~ 1,5 lần nếu df['Unnamed: 5']là một chuỗi, chậm hơn 25-30 lần nếu df['Unnamed: 5']là một mảng nhỏ (độ dài = 10) và chậm hơn 150-160 lần nếu đó là một mảng nhiều hạt có độ dài 100 (lần tính trung bình trong 500 lần thử nghiệm) .

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

Kết quả:

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

1
Tiền tố bên trái của ==với strlà một giải pháp tốt cho tôi mà hầu như không ảnh hưởng đến hiệu suất trên 1,5 triệu hàng sẽ không lớn hơn thế trong tương lai.
David Erickson

0

Tôi nhận được cảnh báo này vì tôi nghĩ rằng cột của mình chứa chuỗi null, nhưng khi kiểm tra, nó chứa np.nan!

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

Thay đổi cột của tôi thành chuỗi trống đã giúp :)


0

Tôi đã so sánh một số phương pháp có thể để thực hiện việc này, bao gồm pandas, một số phương pháp numpy và phương pháp hiểu danh sách.

Đầu tiên, hãy bắt đầu với đường cơ sở:

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

Vì vậy, cơ sở của chúng tôi là số lượng phải chính xác 2và chúng tôi nên thực hiện 50 us.

Bây giờ, chúng tôi thử phương pháp ngây thơ:

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

Và ở đây, chúng tôi nhận được câu trả lời sai ( NotImplemented != 2), chúng tôi mất nhiều thời gian và nó đưa ra cảnh báo.

Vì vậy, chúng tôi sẽ thử một phương pháp ngây thơ khác:

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

Một lần nữa, câu trả lời sai ( 0 != 2). Điều này thậm chí còn xảo quyệt hơn vì không có cảnh báo tiếp theo ( 0có thể được thông qua giống như vậy 2).

Bây giờ, chúng ta hãy thử hiểu danh sách:

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

Chúng tôi nhận được câu trả lời đúng ở đây và nó khá nhanh!

Một khả năng khác, 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 ==

Chậm, nhưng chính xác!

Và cuối cùng, tùy chọn tôi sẽ sử dụng: truyền numpymảng thành objectkiểu:

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

Nhanh chóng và chính xác!


Vì vậy, IIUC, để khắc phục 'x' in np.arange(5), bạn đề nghị chỉ cần làm 'x' in np.arange(5).astype(object)(hoặc tương tự 'x' == np.arange(5).astype(object):). Đúng? IMHO, đây là cách giải quyết tốt nhất được hiển thị ở đây, vì vậy tôi bối rối vì thiếu số phiếu ủng hộ. Có thể chỉnh sửa câu trả lời của bạn để bắt đầu với điểm mấu chốt, và sau đó chuyển sang phần phân tích hiệu suất tốt?
Oren Milman

Cảm ơn @Oren, tôi sẽ thử nó và xem nó đưa tôi đến đâu.
ahagen

0

Tôi có mã này gây ra lỗi:

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

Tôi đã thay đổi nó thành thế này:

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

để tránh sự so sánh, đó là ném cảnh báo - như đã nêu ở trên. Tôi chỉ phải tránh ngoại lệ vì dfObj.loctrong vòng lặp for, có lẽ có một cách để bảo nó không kiểm tra các hàng mà nó đã thay đổi.


0

Trong trường hợp của tôi, cảnh báo xảy ra chỉ vì kiểu lập chỉ mục boolean thông thường - vì chuỗi chỉ có np.nan. Trình diễn (gấu trúc 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

Tôi nghĩ rằng với pandas 1.0, họ thực sự muốn bạn sử dụng 'string'kiểu dữ liệu mới cho phép các pd.NAgiá trị:

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

Đừng thích việc họ mày mò các chức năng hàng ngày như lập chỉ mục boolean.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.