Cygwinのpythonだと問題なかったプログラムで、
Macだと SettingWithCopyWarning の警告が出た。
何でCygwinだと稽古が出なかったのかは不明だけど。
SettingWithCopyWarning は出ないようにした方が良さそうだ、
という話。
外のcsvの内容をpandasに読ませたのは良いけど、
そのままの文字列では不都合なので要素の中身を加工しようとして、
アクセサを使ってこんな風に書くと。
1 2 |
df.no = df.no.str.replace(u'トラリピ#', u'') df.name = df.name.str.replace(u'/', u'') |
警告が出てくる。
結果を見たところ、意図した通りに動作はしているけれど、大変気持悪い。
1 2 3 4 5 6 7 |
** replace Japanese Charactor and Code /usr/local/lib/python2.7/site-packages/pandas/core/generic.py:1974: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy self[name] = value |
この原因は、pandasの便利機能を使って要素の選択を行う際に、
中で二度呼びされる…うんぬん。で、予期しない結果になるかも知れないよ、とのこと。
So, why does this show the SettingWithCopy warning / and possibly not work when you do chained indexing and assignment:
dfmi[‘one’][‘second’] = value
Since the chained indexing is 2 calls, it is possible that either call may return a copy of the data because of the way it is sliced. Thus when setting, you are actually setting a copy, and not the original frame data. It is impossible for pandas to figure this out because their are 2 separate python operations that are not connected.
The SettingWithCopy warning is a ‘heuristic’ to detect this (meaning it tends to catch most cases but is simply a lightweight check). Figuring this out for real is way complicated.
The .loc operation is a single python operation, and thus can select a slice (which still may be a copy), but allows pandas to assign that slice back into the frame after it is modified, thus setting the values as you would think.
The reason for having the SettingWithCopy warning is this. Sometimes when you slice an array you will simply get a view back, which means you can set it no problem. However, even a single dtyped array can generate a copy if it is sliced in a particular way. A multi-dtyped DataFrame (meaning it has say float and object data), will almost always yield a copy. Whether a view is created is dependent on the memory layout of the array.
pandasの実装を気にして使っていられないし、
予想外の箇所でこのエラーに遭遇することもある。
なので、アクセサを避けて、言われた通りの使い方をしてみる。
1 2 |
df.loc[:]['no'] = df.loc[:]['no'].str.replace(u'トラリピ#', u'') df.loc[:]['name'] = df.loc[:]['name'].str.replace(u'/', u'') |
ところが、このままでは警告は消えない。
データのクレンジング作業途中でindexに欠番があったりすると、
そのままでは、さくっと差し替えることも、ちょっと面倒。
あぁ、同じことを言ってる人がいる。
http://stackoverflow.com/questions/25698710/replace-all-occurrences-of-a-string-in-a-pandas-dataframe-python
アクセサを使わないで全体に正規表現で置換をかけると、
SettingWithCopyは出ない。
Columで限定できてないけど、これでOK。
1 2 |
df = df.replace({u'トラリピ#':u'', u'指値':u'0', u'([A-Z][A-Z][A-Z])/([A-Z][A-Z][A-Z])':u'\\1\\2'}, regex=True) |
しかも、 encode(‘cp932’) しなくても文字列置換ができた。
この変のAPIの動きは、最近のバージョンで変更になったみたいなので、
要注意。
せっかく便利なアクセサなのに、かえって混乱してしまった。
今後、また仕様が変わるのかも。