3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Python / Pandas] DataFrameに対して`replace`で`None`に置き換えようとするとバグが発生する

Last updated at Posted at 2021-01-03

何が起きたか

pandasDataFrameにあるreplaceメソッドを使い、np.nanNoneに置換しようとしたらバグが発生した(ように見えた)

Environment

Google Colaboratory で実施

ソースコード

1. 置換前のDataFrame作成

動作確認用のDataFrameがこちら

import pandas as pd
import numpy as np

indexes = [
    datetime.datetime(2020, 1, 1, 11, 50),
    datetime.datetime(2020, 1, 1, 12, 50),
    datetime.datetime(2020, 1, 1, 12, 52),
    datetime.datetime(2020, 1, 1, 18, 50),
    datetime.datetime(2020, 1, 1, 19, 50),
    datetime.datetime(2020, 1, 1, 21, 50),
]
df = pd.DataFrame({
    'high': [1, np.nan, 3, np.nan, np.nan, 11],
    'close': [4, 5, 6, 7, np.nan, 2],
    'memo': ['sign', '', np.nan, 'sign2', np.nan, 'sign3'],
    'bool': [True, None, True, False, None, False],
    'stoploss': [True, None, True, False, None, False]
}, index=indexes)

df
->                    high   close   memo   bool	stoploss
2020-01-01 11:50:00   1.0    4.0     sign   True	True
2020-01-01 12:50:00   NaN    5.0            None	None
2020-01-01 12:52:00   3.0    6.0     NaN    True	True
2020-01-01 18:50:00   NaN    7.0     sign2  False	False
2020-01-01 19:50:00   NaN    NaN     NaN    None	None
2020-01-01 21:50:00   11.0   2.0     sign3  False	False

2. replace方法その1

バグが起こる方

df.replace(np.nan, None)
->                   high	close	memo	bool	stoploss
2020-01-01 11:50:00  1.0	4.0     sign	True	True
2020-01-01 12:50:00  1.0	5.0             True    True
2020-01-01 12:52:00  3.0	6.0             True	True
2020-01-01 18:50:00  3.0	7.0     sign2   False	False
2020-01-01 19:50:00  3.0	7.0     sign2   False   False
2020-01-01 21:50:00  11.0	2.0     sign3	False	False

...なんじゃこりゃ!!ヾノ。ÒдÓ)ノシ バンバン!!
np.nanだったところがNoneじゃなくて、直前の値で埋められてます
fillnaされたみたいになってます)

3. replace方法その2

大丈夫?な方

df.replace({np.nan: None})
->                    high   close   memo   bool	stoploss
2020-01-01 11:50:00   1      4       sign   True	True
2020-01-01 12:50:00   None   5	            None	None
2020-01-01 12:52:00   3      6       None   True	True
2020-01-01 18:50:00   None   7       sign2  False	False
2020-01-01 19:50:00   None   None    None   None	None
2020-01-01 21:50:00   11     2       sign3  False	False

期待通りではある(?
いや、気づいたけど、なんか、floatが、全部整数にされてる....
だいじょばないです(助けて)

...なんて一瞬(30分以上)焦りましたが、よく見てみたら中身はfloatのままでした

tmp_df = df.replace({np.nan: None})

tmp_df.values
-> array([[1.0, 4.0, 'sign', True, True],
       [None, 5.0, '', None, None],
       [3.0, 6.0, None, True, True],
       [None, 7.0, 'sign2', False, False],
       [None, None, None, None, None],
       [11.0, 2.0, 'sign3', False, False]], dtype=object)

ε-(´∀`*)ホッ

この書き方覚えとかないとね...( ..)φdf.replace({np.nan: None})

参考資料

一応、pandasの公式ドキュメントでもこの件は言及されています。
ただ、見つけるのにかなり時間がかかったので、今回記録しておくことにしました。

When value=None and to_replace is a scalar, list or tuple, replace uses the method parameter (default ‘pad’) to do the replacement. So this is why the ‘a’ values are being replaced by 10 in rows 1 and 2 and ‘b’ in row 4 in this case. The command s.replace('a', None) is actually equivalent to s.replace(to_replace='a', value=None, method='pad'):

日本語で書かれてたらもう少し早く気づけたかも...

その他関連資料

  • nan_to_num
    最新のnumpyにはnan_to_numというメソッドがあり、こちらでnp.nanを他の値に置き換えられるらしい
    もしかしたら、これなら今回のようなバグは起きないかも(試せていない)
    https://numpy.org/doc/stable/reference/generated/numpy.nan_to_num.html
  • 逆の操作をしようとした場合
    ちょっと関係あるのかわからないけれど、Nonenp.nanで埋めようとする場合も、別の問題が発生する模様

StackOverflow : Replace None with NaN in pandas dataframe

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?