FutureWarning:要素ごとの比較に失敗しました。スカラーを返しますが、将来的には要素ごとの比較を実行します


108

Python3でPandas0.19.1を使用しています。これらのコード行で警告が表示されます。文字列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とは何ですか。機能しているように見えるので、無視する必要があります。

回答:


171

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

double equals演算子を使用してこのバグを再現する別の方法:

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の間には意見の相違があります。左側のオペランドはPythonのターフ、プリミティブ文字列であり、中央の演算はpythonのターフですが、右側のオペランドはnumpyのターフであることに注意してください。PythonスタイルのScalarまたはNumpyスタイルのブール値のndarrayを返す必要がありますか?Numpyは、ブール値のndarrayを言い、Pythonic開発者は同意しません。古典的なスタンドオフ。

項目が配列に存在する場合、要素ごとの比較またはスカラーである必要がありますか?

コードまたはライブラリがinor==演算子を使用してPython文字列をnumpyndarraysと比較している場合、それらは互換性がないため、試してみるとスカラーが返されますが、現時点ではのみです。警告は、将来この動作が変更される可能性があることを示しているため、python / numpyがNumpyスタイルを採用することを決定した場合、コードはカーペット全体に広がります。

提出されたバグレポート:

NumpyとPythonはスタンドオフにあり、今のところ操作はスカラーを返しますが、将来的には変更される可能性があります。

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

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

2つの回避策:

どちらか、Pythonとnumpyののバージョンをロックダウン警告を無視していない変化に行動を期待する、または両方の左と右のオペランドを変換==し、innumpyのタイプまたはプリミティブの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


1
うーん。それで、私がいくらかの量を持っていてthing(それはnumpyタイプであるかもしれないしそうでないかもしれません;私は知りません)、そして私が見てthing == 'some string'そして簡単なbool結果を得たいならば、私は何をすべきですか?np.atleast_1d(thing)[0] == 'some string'?しかし、これ'some string'は、配列の最初の要素を配置するジョーカーにとっては堅牢ではありません。thing最初にタイプをテストしてから==、それが文字列である(またはnumpyオブジェクトではない)場合にのみテストを実行する必要があると思います。
EL_DON 2018

1
実際、numpy.ndarrayを空のリストと比較しようとすると、この将来の警告も発生します。たとえば、実行するnp.array([1, 2]) == []と警告も発生します。
1313E

2
これを行う例を見ると役に立ちます。or babysit your left and right operands to be from a common turf
HaPsantran19年

11
これは、この問題に関する驚くべきレベルの品質情報です。
StephenBoesch

だから私はこのコードの警告を取り除くでしょう:df.loc [df.cName == ''、 'cName'] = '10004'。言い換えれば、pythonの ''(空の文字列)に相当するpandas / numpyは何
ですか

13

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

私はこれまでそのようなエラーに遭遇したことがありません。私はまだこれの背後にある理由を理解しようとしています(@EricLeschinskiの説明などを使用して)。

とにかく、私が理由を理解するまで、次のアプローチは今のところ問題を解決します:

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

そのような動作の理由がわかり次第、これを更新します。


私はと同じ問題を抱えていread_csv()ます。私pandasには修正が必要なもののように見えます。
コンスタンチン

1
ありがとう!多くの作業を節約できたと思います。pd__version__: 0.22.0; np.__version__: 1.15.4
MarkusDutschke19年

1
ここでも同じ問題があります。パラメータread_csvを使用index_colすると、内部でいくつかの厄介な呼び出しが発生するようです。異なる結果で2つのセットアップをテストしました:1。numpyバージョン1.19.2、Pandasバージョン1.1.2:FutureWarning:要素ごとの比較に失敗しました... 2. numpyバージョン1.19.2、Pandasバージョン1.1.3:TypeError:ufunc ' ISNAN」はサポートされません...
カルロス

9

同じ警告メッセージに対する私の経験は、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

それが役に立てば幸い。


1
コードには、警告を説明するために不要な可動部分がたくさんあります。Pandasはその余分なTypeErrorであなたを優雅にします​​が、それはPandasからのダメージコントロールです。ソース警告はNumpyとPythonの間の不一致であり、の評価時に発生しdf['num3'] == '3'ます。
Eric Leschinski 2017年

1
df.loc[df['num3'] == 3, 'num3'] = 4 # No Errorこの部分は私を助けます。おかげで
jameslem

9

Eric Leschinskiの非常に詳細な回答に勝るものはありませんが、まだ言及されていないと思われる元の質問に対する簡単な回避策を次に示します。文字列をリストに入れて、.isin代わりに使用してください。==

例えば:

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」]ユニーク()
lone_coder

3

このための簡単な回避策は、を使用することnumpy.core.defchararrayです。私も同じ警告メッセージに直面し、上記のモジュールを使用してそれを解決することができました。

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

2

エリックの答えは、問題がパンダシリーズ(NumPy配列を含む)をPython文字列と比較することから来ることを説明しています。残念ながら、彼の2つの回避策は、どちらも警告を抑制するだけです。

そもそも警告を引き起こさないコードを書くには、文字列をシリーズの各要素と明示的に比較し、それぞれに個別のブール値を取得します。たとえばmap、匿名関数を使用できます。

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

1

配列が大きすぎないか、配列が多すぎない場合は、の左側を==文字列にすることで解決できる可能性があります。

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

1
==withの左側に接頭辞を付けるstrことは、将来それより大きくなることのない150万行のパフォーマンスをほとんど損なうことのない良い解決策でした。
DavidErickson20年

1

私の場合、警告は通常のタイプのブールインデックスが原因で発生しました。これは、シリーズにnp.nanしかないためです。デモンストレーション(パンダ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

pandas 1.0'string'では、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

ブールインデックスなどの毎日の機能をいじくり回した時点が気に入らないでください。


0

列にnull文字列が含まれていると思ったため、この警告が表示されましたが、確認すると、np.nanが含まれていました。

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

列を空の文字列に変更すると役に立ちました:)


0

パンダ、いくつかの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

したがって、私たちのベースラインは、カウントが正しい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

速くて正しい!


したがって、IIUCを修正するには'x' in np.arange(5)、単に実行することをお勧めします'x' in np.arange(5).astype(object)(または同様に:) 'x' == np.arange(5).astype(object)。正しい?私見、これはここに示されている最もエレガントな回避策であるため、賛成票がないことに混乱しています。たぶん、あなたの答えを編集して、収益から始めて、それから素晴らしいパフォーマンス分析に移りますか?
OrenMilman20年

@Orenに感謝します、私はそれを試して、それが私をどこに連れて行くかを見ます。
ahagen

0

私はエラーを引き起こしていたこのコードを持っていました:

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ループであるため、例外を回避する必要がありました。すでに変更されている行をチェックしないように指示する方法があるかもしれません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.