FutureWarning: perbandingan elemen gagal; mengembalikan skalar, tetapi di masa mendatang akan melakukan perbandingan elemen


100

Saya menggunakan Pandas 0.19.1di Python 3. Saya mendapatkan peringatan pada baris kode ini. Saya mencoba untuk mendapatkan daftar yang berisi semua nomor baris di mana string Peterada di kolom Unnamed: 5.

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

Ini menghasilkan Peringatan:

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

Apa FutureWarning ini dan haruskah saya mengabaikannya karena tampaknya berhasil.

Jawaban:


159

FutureWarning ini bukan dari Pandas, ini dari numpy dan bug juga memengaruhi matplotlib dan lainnya, berikut cara mereproduksi peringatan lebih dekat ke sumber masalah:

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

Cara lain untuk mereproduksi bug ini menggunakan operator sama dengan ganda:

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

Contoh Matplotlib yang terpengaruh oleh FutureWarning ini di bawah implementasi quiver plot: https://matplotlib.org/examples/pylab_examples/quiver_demo.html

Apa yang terjadi di sini?

Ada ketidaksepakatan antara Numpy dan python asli tentang apa yang harus terjadi ketika Anda membandingkan string dengan tipe numerik numpy. Perhatikan operan kiri adalah turf python, string primitif, dan operasi tengah adalah turf python, tetapi operan kanan adalah turf numpy. Haruskah Anda mengembalikan Scalar gaya Python atau ndarray gaya Numpy dari Boolean? Numpy mengatakan ndarray of bool, pengembang Pythonic tidak setuju. Kebuntuan klasik.

Haruskah itu perbandingan elemen atau Skalar jika item ada dalam array?

Jika kode atau pustaka Anda menggunakan operator inor ==untuk membandingkan string python dengan ndarrays numpy, mereka tidak kompatibel, jadi ketika Anda mencobanya, itu mengembalikan skalar, tetapi hanya untuk saat ini. Peringatan menunjukkan bahwa di masa mendatang perilaku ini mungkin berubah sehingga kode Anda akan menyembul ke seluruh karpet jika python / numpy memutuskan untuk mengadopsi gaya Numpy.

Laporan Bug yang dikirim:

Numpy dan Python mengalami kebuntuan, untuk saat ini operasi mengembalikan skalar, tetapi di masa mendatang mungkin berubah.

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

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

Dua solusi solusi:

Anda dapat mengunci versi python dan numpy Anda, mengabaikan peringatan dan mengharapkan perilakunya tidak berubah, atau mengubah operan kiri dan kanan dari ==dan inmenjadi dari jenis numpy atau jenis numerik python primitif.

Tekan peringatan secara global:

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

Tekan peringatan baris demi baris.

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

Tekan saja peringatan dengan nama, lalu beri komentar keras di sebelahnya yang menyebutkan versi python dan numpy saat ini, mengatakan kode ini rapuh dan memerlukan versi ini dan letakkan tautan ke sini. Tendang kaleng di jalan.

TLDR: pandas adalah Jedi; numpyadalah gubuk; dan pythonmerupakan kekaisaran galaksi. https://youtu.be/OZczsiCfQQk?t=3


1
Ugh. Jadi jika saya memiliki beberapa kuantitas thing(yang mungkin atau mungkin bukan tipe numpy; saya tidak tahu) dan saya ingin melihat apakah thing == 'some string'dan mendapatkan boolhasil yang sederhana , apa yang harus saya lakukan? np.atleast_1d(thing)[0] == 'some string'? Tapi itu tidak kuat untuk beberapa pelawak yang memasukkan 'some string'elemen pertama dari sebuah array. Saya rasa saya harus menguji jenisnya thingterlebih dahulu dan kemudian hanya melakukan ==pengujian apakah itu string (atau bukan objek numpy).
EL_DON

1
Sebenarnya, peringatan mendatang ini juga dimunculkan setiap kali Anda mencoba membandingkan numpy.ndarray dengan daftar kosong. Misalnya, mengeksekusi np.array([1, 2]) == []akan memunculkan peringatan juga.
1313e

2
Saya akan merasa or babysit your left and right operands to be from a common turf
terbantu

10
Ini adalah tingkat kualitas info yang luar biasa tentang masalah ini.
StephenBoesch

Jadi saya akan menyingkirkan peringatan pada kode ini: df.loc [df.cName == '', 'cName'] = '10004'. Dengan kata lain, apa yang setara pandas / numpy dengan python '' (string kosong)
Garet Jax

13

Saya mendapatkan kesalahan yang sama ketika saya mencoba mengatur index_colpembacaan file ke dalam Pandabingkai data:

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

Saya belum pernah menemui kesalahan seperti itu sebelumnya. Saya masih mencoba mencari tahu alasan di balik ini (menggunakan penjelasan @Eric Leschinski dan lainnya).

Bagaimanapun, pendekatan berikut memecahkan masalah untuk saat ini sampai saya menemukan alasannya:

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

Saya akan memperbarui ini segera setelah saya mengetahui alasan perilaku tersebut.


Saya memiliki masalah yang sama dengan read_csv(). Bagi saya seperti sesuatu yang pandasperlu diperbaiki.
Konstantin

1
Terima kasih! Menyelamatkan saya banyak pekerjaan - saya kira. pd__version__: 0.22.0; np.__version__: 1.15.4
Markus Dutschke

1
Masalah yang sama di sini, tampaknya beberapa panggilan numpy di dalam read_csvsaat menggunakan index_colparameter. Saya telah menguji dua penyiapan dengan hasil yang berbeda: 1. numpy versi 1.19.2, Pandas versi 1.1.2: FutureWarning: perbandingan elemen gagal ... 2. numpy versi 1.19.2, Pandas versi 1.1.3: TypeError: ufunc ' isnan 'tidak didukung ...
Carlos

9

Pengalaman saya terhadap pesan peringatan yang sama disebabkan oleh TypeError.

TypeError: perbandingan jenis tidak valid

Jadi, Anda mungkin ingin memeriksa tipe data file Unnamed: 5

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

Inilah cara saya mereplikasi pesan peringatan:

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

Semoga membantu.


1
Kode Anda memiliki banyak bagian bergerak yang tidak perlu untuk menggambarkan peringatan tersebut. Pandas memberkati Anda dengan TypeError ekstra tetapi itu adalah kontrol kerusakan dari Pandas, Peringatan sumber adalah ketidaksepakatan antara Numpy dan Python dan terjadi pada evaluasi df['num3'] == '3'.
Eric Leschinski

1
df.loc[df['num3'] == 3, 'num3'] = 4 # No ErrorBagian ini membantu saya. Terima kasih
jameslem

5

Tidak dapat mengalahkan jawaban Eric Leschinski yang sangat detail, tetapi berikut adalah solusi cepat untuk pertanyaan asli yang menurut saya belum disebutkan - letakkan string dalam daftar dan gunakan .isinsebagai ganti==

Sebagai contoh:

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

saya ingin tahu apakah saya bisa melakukan hal yang sama dengan sintaks ini -> if "-" di dfN ['Drate']. unique ()
lone_coder

3

Solusi cepat untuk ini adalah dengan menggunakan numpy.core.defchararray. Saya juga menghadapi pesan peringatan yang sama dan dapat menyelesaikannya menggunakan modul di atas.

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

2

Jawaban Eric menjelaskan bahwa masalahnya berasal dari membandingkan Seri Pandas (berisi larik NumPy) dengan string Python. Sayangnya, kedua solusi tersebut hanya menekan peringatan tersebut.

Untuk menulis kode yang tidak menyebabkan peringatan di tempat pertama, bandingkan string Anda secara eksplisit dengan setiap elemen Seri dan dapatkan bool terpisah untuk masing-masing. Misalnya, Anda dapat menggunakan mapdan fungsi anonim.

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

1

Jika array Anda tidak terlalu besar atau Anda tidak memiliki terlalu banyak, Anda mungkin bisa lolos dengan memaksa sisi kiri ==menjadi string:

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

Tapi ini ~ 1,5 kali lebih lambat jika df['Unnamed: 5']berupa string, 25-30 kali lebih lambat jika df['Unnamed: 5']array numpy kecil (panjang = 10), dan 150-160 kali lebih lambat jika itu adalah array numpy dengan panjang 100 (kali dirata-ratakan selama 500 percobaan) .

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

Hasil:

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
Mengawali di sebelah kiri ==dengan stradalah solusi yang baik bagi saya yang hampir tidak mengganggu kinerja pada 1,5 juta baris yang tidak akan menjadi lebih besar dari itu di masa mendatang.
David Erickson

0

Saya mendapat peringatan ini karena saya pikir kolom saya berisi string nol, tetapi saat memeriksa, itu berisi np.nan!

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

Mengubah kolom saya menjadi string kosong membantu :)


0

Saya telah membandingkan beberapa metode yang mungkin untuk melakukan ini, termasuk panda, beberapa metode numpy, dan metode pemahaman daftar.

Pertama, mari kita mulai dengan garis dasar:

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

Jadi, dasar kami adalah bahwa hitungannya harus benar 2, dan kami harus melakukannya50 us .

Sekarang, kami mencoba metode naif:

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

Dan di sini, kami mendapatkan jawaban yang salah ( NotImplemented != 2), itu membutuhkan waktu lama, dan itu memberi peringatan.

Jadi kami akan mencoba metode naif lainnya:

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

Sekali lagi, jawaban yang salah ( 0 != 2). Ini bahkan lebih berbahaya karena tidak ada peringatan berikutnya ( 0dapat disebarkan begitu saja 2).

Sekarang, mari kita coba pemahaman daftar:

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

Kami mendapatkan jawaban yang benar di sini, dan ini sangat cepat!

Kemungkinan lain, 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 ==

Lambat, tapi benar!

Dan terakhir, opsi yang akan saya gunakan: mentransmisikan numpyarray ke objecttipe:

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

Cepat dan tepat!


Jadi IIUC, untuk memperbaikinya 'x' in np.arange(5), Anda menyarankan untuk melakukan 'x' in np.arange(5).astype(object)(atau serupa :) 'x' == np.arange(5).astype(object). Baik? IMHO, ini adalah solusi paling elegan yang ditampilkan di sini, jadi saya bingung dengan kurangnya suara positif. Mungkin mengedit jawaban Anda untuk memulai dengan intinya, dan kemudian beralih ke analisis kinerja yang bagus?
Oren Milman

Terima kasih @Oren, saya akan mencobanya dan melihat di mana itu membuat saya.
ahagen

0

Saya memiliki kode ini yang menyebabkan kesalahan:

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

Saya mengubahnya menjadi ini:

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

untuk menghindari perbandingan, yaitu melontarkan peringatan - sebagaimana disebutkan di atas. Saya hanya harus menghindari pengecualian karena dfObj.locdalam perulangan for, mungkin ada cara untuk memberitahukannya agar tidak memeriksa baris yang telah diubah.


0

Dalam kasus saya, peringatan terjadi karena hanya tipe biasa dari pengindeksan boolean - karena rangkaian hanya memiliki np.nan. Demonstrasi (panda 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

Saya pikir dengan pandas 1.0 mereka benar-benar ingin Anda menggunakan 'string'tipe data baru yang memungkinkan pd.NAnilai:

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

Jangan suka saat mereka mengutak-atik fungsionalitas sehari-hari seperti pengindeksan boolean.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.