4
2

More than 1 year has passed since last update.

[Python3 / pandas] elementwise comparison failed; が出るとき

Last updated at Posted at 2020-12-06

経緯

このwarningはたまにしか見かけないけれども、発生すると毎回解決に時間がかかってしまっている。
もっと理解を深め(なるべく即座に解決す)るため、事例を記録してみた。

概要

タイトルの通り。

FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparisonが、

  • どんな時に発生したか
  • どうやって解決したか

を記録したもの。


※ただし、pandasがメインターゲットです。
 numpyで発生している場合の対策は特に記載しません。

(numpyはそんなに使わないので...。numpyで同じ問題にぶつかったら追記するかもしれません。)

Environment

version
Python 3.8.1

事例

1. 'string' in np.array

ソースコードはstackoverflowより拝借いたしました...

import numpy as np
'x' in np.arange(5)

# 結果
<stdin>:1: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison

2. np.array同士の比較だが、一方が数値型でもう一方が文字列型

ソースコードはstackoverflowより拝借いたしました...

import numpy as np
np.arange(5) == np.arange(5).astype(str)

# 結果
<stdin>:1: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison

3. series == 'string'

私が実際に見かけた事例です。

import numpy as np
import pandas as pd
df = pd.DataFrame({
    'number': [1, np.nan, 3, np.nan, np.nan, 11],
    'memo': ['sign', '', np.nan, 'sign2', np.nan, 'sign3']
})
df
   number   memo
0     1.0   sign
1     NaN
2     3.0    NaN
3     NaN  sign2
4     NaN    NaN
5    11.0  sign3

df['number'] == 'sign'

# 結果
/usr/local/pyenv/versions/20200222/lib/python3.8/site-packages/pandas/core/ops/array_ops.py:253: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison

ただし、いろいろ試してみてわかったが、「3.」の事例をほんのちょっと変更するだけで、warningは発生しなくなった。
変更箇所はどこかというと、問題になっているseriesの中に、比較対象として合致する'sign'を入れておくのである。

import pandas as pd
import numpy as np
df = pd.DataFrame({
    'number': [1, 'sign', 3, np.nan, np.nan, 11], # <= 2個目の値を 'sign' にした
    'memo': ['sign', '', np.nan, 'sign2', np.nan, 'sign3']
})
df['number'] == 'sign'

# 結果
0    False
1     True
2    False
3    False
4    False
5    False

考察

上記1, 2, 3の結果と、stackoverflowのこの記事を見る限り、「numpy配列やseries」と「文字列」とを比較することで発生することは間違いなさそう。

ただ、上記「3.」の二つ目のソースコードを見るとわかるのだが、検出したい値が実際にseriesの中に入っていれば、このwarningは発生しない
この事実には、今回の記事を書いて初めて気が付いた。

対策については、やはりstackoverflowのこの記事頼りになってしまうが、以下のようになる。

対策

seriesと文字列の比較を行う際に、==inではなく、.isin(['string'])メソッドや.contains('string')メソッドを用いることで回避できる。

# Bad: warningが発生してしまう、ダメな書き方
df['number'] == 'sign'

# Good: warningが発生しない
df['number'].isin(['sign'])

# Error: contains を使おうとしたら、series(df['number'])内のデータが文字列型ではないのでエラーになった
df['number'].str.contains('sign')
--- error () ---
AttributeError: Can only use .str accessor with string values!

# Good: warningが発生しない
df.astype({'number': str})['number'].str.contains('sign')

考察の続き

『基本的にはこのwarningは普段出ないのだけど、ときどき出る』、ということが私には何度かありました。
調べてみると、その原因は『データの中に、期待している文字列が1つも含まれていないこと』であることがわかりました。

実際に大量のデータを扱う際、期待していた文字列が1つも含まれていないということは通常あり得るので、そんなときにこのwarningが発生してしまうのだと思います。

これで次からもっとスムーズにwarningが消せる気がする。
というより、この書き方さえ避けて.isin()を使えば、そもそも発生させないことができそう(^ワ^*)

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2