FutureWarning: element bazlı karşılaştırma başarısız oldu; skaler döndürüyor, ancak gelecekte element bazlı karşılaştırma yapacak


100

0.19.1Python 3'te Pandalar kullanıyorum . Bu kod satırlarıyla ilgili bir uyarı alıyorum. PeterSütunda dizenin bulunduğu tüm satır numaralarını içeren bir liste almaya çalışıyorum Unnamed: 5.

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

Bir Uyarı oluşturur:

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

Bu Gelecek Uyarısı nedir ve işe yaradığı için onu görmezden gelmeliyim.

Yanıtlar:


159

Bu FutureWarning Pandas'tan değil, uyuşuktan geliyor ve hata ayrıca matplotlib ve diğerlerini de etkiliyor, işte uyarıyı sorunun kaynağına daha yakın bir şekilde nasıl yeniden oluşturacağınız:

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

Çift eşittir operatörünü kullanarak bu hatayı yeniden oluşturmanın başka bir yolu:

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

Quiver plot uygulaması altında bu FutureWarning'den etkilenen bir Matplotlib örneği: https://matplotlib.org/examples/pylab_examples/quiver_demo.html

Burada neler oluyor?

Bir dizeleri numpy'nin sayısal türleriyle karşılaştırdığınızda ne olması gerektiği konusunda Numpy ile yerel python arasında bir anlaşmazlık var. Soldaki işlenenin python'un çimi, ilkel bir dizge ve ortadaki işlem python'un çimi, ancak sağ işlenenin numpy'nin çimi olduğuna dikkat edin. Python stili Skalar mı yoksa Boolean'ın Numpy stili ndarray'ı mı döndürmelisiniz? Numpy bool ndarray diyor, Pythonic geliştiricileri aynı fikirde değil. Klasik soğukluk.

Dizide öğe varsa, öğe bazlı karşılaştırma mı yoksa Skaler mi olmalı?

Kodunuz veya kitaplığınız python dizesini numpy ndarray'larla karşılaştırmak için inveya ==operatörlerini kullanıyorsa, uyumlu değildirler, bu nedenle denediğinizde bir skaler döndürür, ancak şimdilik. Uyarı, gelecekte python / numpy Numpy stilini benimsemeye karar verirse, bu davranışın değişebileceğini ve kodunuzun halının her yerine kusabileceğini belirtir.

Gönderilen Hata raporları:

Numpy ve Python bir soğukluk içindedir, şimdilik işlem bir skaler döndürür, ancak gelecekte değişebilir.

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

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

İki geçici çözüm çözümü:

Ya, piton ve Numpy sürümünü kilitlemek uyarıları göz ardı ederek değil değişime davranışı beklemek veya her ikisi sağ ve sol işlenen dönüştürmek ==ve inbir numpy türü veya ilkel piton sayısal türünden olmak.

Uyarıyı genel olarak bastırın:

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

Uyarıyı satır satır gizleyin.

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

Uyarıyı ismiyle bastırın, ardından yanına python ve numpy'nin mevcut sürümünden bahseden yüksek sesle bir yorum koyun, bu kodun kırılgan olduğunu ve bu sürümleri gerektirdiğini ve buraya bir bağlantı koyun. Kutuyu yolun aşağısına at.

TLDR: pandas Jedi'lar; numpykulübelerdir; ve pythongalaktik imparatorluktur. https://youtu.be/OZczsiCfQQk?t=3


1
Ugh. Öyleyse, bir miktarım varsa thing(ki bu bir uyuşukluk türü olabilir veya olmayabilir; bilmiyorum) ve thing == 'some string'basit bir boolsonuç alıp almadığını görmek ve almak istersem, ne yapmalıyım? np.atleast_1d(thing)[0] == 'some string'? Ancak bu 'some string', bir dizinin ilk elemanını yerleştiren bir joker için sağlam değildir . Sanırım önce türünü test etmem thingve sonra ==testi yalnızca bir dizeyse (ya da uyuşmuş bir nesne değilse) yapmam gerekiyor.
EL_DON

1
Aslında, bir numpy.ndarray'i boş bir listeyle karşılaştırmaya çalıştığınızda bu gelecekteki uyarı da ortaya çıkar. Örneğin, yürütme np.array([1, 2]) == []de uyarıyı artıracaktır.
1313e

2
Bunu yapmanın bir örneğini görmeyi faydalı bulabilirim:or babysit your left and right operands to be from a common turf
HaPsantran

10
Bu, bu konuyla ilgili inanılmaz kalitede bir bilgidir.
StephenBoesch

Yani bu koddaki uyarıdan kurtulabilirim: df.loc [df.cName == '', 'cName'] = '10004'. Başka bir deyişle, pandalar /
uyuşuklar python'un

13

index_colOkumayı bir dosyanın Pandaveri çerçevesine yerleştirmeye çalıştığımda da aynı hatayı alıyorum :

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

Daha önce hiç böyle bir hatayla karşılaşmadım. Hala bunun arkasındaki nedeni bulmaya çalışıyorum (@Eric Leschinski açıklamasını ve diğerlerini kullanarak).

Her neyse, nedenini bulana kadar aşağıdaki yaklaşım sorunu şimdilik çözüyor:

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

Bu tür davranışların nedenini bulur bulmaz bunu güncelleyeceğim.


Aynı problemim var read_csv(). Bana pandasdüzeltilmesi gereken bir şey gibi görünüyor .
Konstantin

1
Teşekkürler! Beni çok işten kurtardı - sanırım. pd__version__: 0.22.0; np.__version__: 1.15.4
Markus Dutschke

1
Burada da aynı sorun, görünüşe göre parametre read_csvkullanılırken içeriden bir kaç numara arama index_col. İki kurulumu farklı sonuçlarla test ettim: 1. numpy sürüm 1.19.2, Pandas sürüm 1.1.2: FutureWarning: elementsel karşılaştırma başarısız oldu ... 2. numpy sürüm 1.19.2, Pandas sürüm 1.1.3: TypeError: ufunc ' isnan desteklenmiyor ...
Carlos

9

Aynı uyarı mesajıyla ilgili deneyimim TypeError'dan kaynaklandı.

TypeError: geçersiz tür karşılaştırması

Bu nedenle, veri türünü kontrol etmek isteyebilirsiniz. Unnamed: 5

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

Uyarı mesajını şu şekilde çoğaltabilirim:

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

Umarım yardımcı olur.


1
Uyarıyı göstermek için kodunuzda çok sayıda gereksiz hareketli parça vardır. Pandalar sizi bu ekstra TypeError ile şereflendirir ama bu Pandas'ın hasar kontrolüdür, Kaynak uyarısı Numpy ve Python arasındaki bir anlaşmazlıktır ve değerlendirilmesinde ortaya çıkar df['num3'] == '3'.
Eric Leschinski

1
df.loc[df['num3'] == 3, 'num3'] = 4 # No ErrorBu kısım bana yardımcı oluyor. Teşekkürler
jameslem

6

Eric Leschinski'nin müthiş ayrıntılı cevabını yenemezsiniz, ancak işte henüz bahsedilmediğini düşündüğüm orijinal soruya hızlı bir çözüm - dizeyi bir listeye koyun ve .isinyerine kullanın==

Örneğin:

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

dfN ['Drate'] içinde bu sözdizimiyle aynı şeyi yapıp yapamayacağımı merak ediyorum -> if "-". unique ()
lone_coder

3

Bunun için hızlı bir çözüm kullanmaktır numpy.core.defchararray. Ben de aynı uyarı mesajıyla karşılaştım ve yukarıdaki modülü kullanarak çözmeyi başardım.

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

2

Eric'in cevabı, sorunun bir Pandas Serisini (bir NumPy dizisi içeren) bir Python dizesiyle karşılaştırmaktan kaynaklandığını yararlı bir şekilde açıklıyor. Ne yazık ki, iki geçici çözümü de uyarıyı bastırıyor.

İlk etapta uyarıya neden olmayan bir kod yazmak için, dizenizi Serinin her bir öğesiyle açıkça karşılaştırın ve her biri için ayrı bir bool alın. Örneğin, mapanonim bir işlev kullanabilirsiniz.

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

1

Dizileriniz çok büyük değilse veya çok fazla diziye sahip değilseniz, dizinin sol tarafını ==bir dize olmaya zorlayarak kurtulabilirsiniz :

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

Ancak bu, df['Unnamed: 5']bir dizge ise ~ 1,5 kat daha yavaştır df['Unnamed: 5'], küçük bir uyuşuk diziyse 25-30 kat daha yavaştır (uzunluk = 10) ve uzunluğu 100 olan uyuşmuş bir diziyse 150-160 kat daha yavaştır (500 denemenin üzerinde ortalama süre) .

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

Sonuç:

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
Sol prefixing ==ile strbenim için iyi bir çözüm olduğunu gelecekte de daha büyük bir almazsınız 1,5 milyon satırlarda zorlukla yaralı performans.
David Erickson

0

Bu uyarıyı aldım çünkü sütunumun boş dizeler içerdiğini düşündüm, ancak kontrol edildiğinde np.nan içeriyordu!

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

Sütunumu boş dizelerle değiştirmek yardımcı oldu :)


0

Pandalar, birkaç uyuşuk yöntem ve bir liste anlama yöntemi dahil, bunu yapmak için mümkün olan birkaç yöntemi karşılaştırdım.

İlk olarak, bir temel ile başlayalım:

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

Öyleyse, temelimiz, sayımın doğru 2olması ve bununla ilgilenmemiz gerektiğidir 50 us.

Şimdi saf yöntemi deniyoruz:

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

Ve burada yanlış cevabı ( NotImplemented != 2) alıyoruz , uzun zaman alıyor ve uyarıyı veriyor.

Öyleyse başka bir saf yöntem deneyeceğiz:

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

Yine yanlış cevap ( 0 != 2). Bu daha da sinsi çünkü sonradan uyarılar yok ( 0aynı şekilde etrafta dolaştırılabilir 2).

Şimdi bir liste anlamayı deneyelim:

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

Doğru cevabı burada alıyoruz ve bu oldukça hızlı!

Başka bir olasılık 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 ==

Yavaş ama doğru!

Ve son olarak, kullanacağım seçenek: numpydiziyi objecttüre dönüştürmek:

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

Hızlı ve doğru!


Dolayısıyla, IIUC, düzeltmek için 'x' in np.arange(5)basitçe yapmayı 'x' in np.arange(5).astype(object)(veya benzer şekilde :) önerirsiniz 'x' == np.arange(5).astype(object). Sağ? IMHO, burada gösterilen en zarif çözüm bu, bu yüzden olumlu oyların olmaması kafamı karıştırıyor. Belki cevabınızı en alt satırdan başlayacak şekilde düzenledikten sonra güzel performans analizine geçebilirsiniz.
Ören Milman

Teşekkürler @Oren, bunu deneyeceğim ve beni nereye götürdüğünü göreceğim.
ahagen

0

Hataya neden olan bu koda sahiptim:

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

Ben şuna değiştirdim:

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

Yukarıda belirtildiği gibi uyarıyı veren karşılaştırmadan kaçınmak için. Sadece dfObj.locfor döngüsü nedeniyle istisnadan kaçınmak zorunda kaldım , belki de zaten değiştirdiği satırları kontrol etmemesini söylemenin bir yolu vardır.


0

Benim durumumda, uyarı sadece normal boole indeksleme türü nedeniyle oluştu - çünkü seride sadece np.nan vardı. Gösteri (pandalar 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

Pandalar 1.0 ile değerlere 'string'izin veren yeni veri türünü kullanmanızı gerçekten istediklerini düşünüyorum 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

Boole endeksleme gibi günlük işlevlerle hangi noktada uğraştıklarını sevmeyin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.