

私は現在Pandasのデータフレームにおきまして、全ての行を繰り返して値の変更を行おうとしています。(今回は値から％を取り除こうとしています。)

その際に、下記のような警告文が出てしまいます。また、この警告文が出ると処理に大きな時間がかかります。  
下記の警告文のサイトへと移動し、dataframe._setitem_with_indexerを使用したのですが、エラーや同様の警告文となり変更することができません。

df.ilocなどを使用し同じ列名に代入するときの正しい文法を教えていただければ幸いです。  
左辺と右辺が異なる場合はエラーや警告文は出ませんでした。

> SettingWithCopyWarning:  
>  A value is trying to be set on a copy of a slice from a DataFrame  
>  See the caveats in the documentation: <http://pandas.pydata.org/pandas-
> docs/stable/indexing.html#indexing-view-versus-copy>

・変更前のコード

[code]

    for i in range(len(df)):
       df['column'].iloc[i] = (df['column'].iloc[i].split('%'))[0]
    
[/code]

・変更後のコード

[code]

    for i in range(len(df)):
        df['column'].iloc._setitem_with_indexer(i, (df['column'].iloc[i].split('%'))[0])
    
[/code]


CC BY-SA 4.0
2018-07-14T14:34:01.020
46614
2018-07-15T01:13:41.950
28490
question
python3 pandas
Pandasの繰り返し文での代入について

[code]

    import pandas as pd
    df = pd.DataFrame([["abc%def",15],["efg%ghi",22]],columns =["column","num"])
    
[/code]

をサンプルデータとします。  
目的を満たす簡便な方法としては次のような記述が挙げられます。

[code]

    df["column"]=df["column"].apply(lambda s:s.split("%")[0])
    
[/code]

おおよそギガバイト級のデータを扱わない限り上記の記述で十分だと思います。  
もう少しテクニカルな記述としては、numpyのvectorizeを使う手段があります。  
こっちのほうが上記よりちょっと早いです。

[code]

    import numpy as np
    f = np.vectorize(lambda s:s.split("%")[0])
    df["column"] = f(df["column"])
    
[/code]

もっと早くする方法としては、cythonやnumbaといったライブラリを使用して静的型付けを行い、コンパイルを行う方法がありますが、numbaのほうはstring型を最適化できないようなので特殊な処理が必要となるようです。cythonについては私も理解が不十分なので紹介に留めます。

下記に参考にしたサイトを記述します。  
<https://pandas.pydata.org/pandas-docs/stable/enhancingperf.html>


CC BY-SA 4.0
2018-07-15T00:13:57.280
46622
2018-07-15T00:13:57.280
25980
46614
answer


`SettingWithCopyWarning`というのは、次のようにすると、まず`df['column']`を計算して、それを使って`iloc[i]`を計算するので、処理に大きな時間がかかるという警告です。

[code]

    df['column'].iloc[i]
    
[/code]

次のように書くと計算が1回で済むから早くなります。

[code]

    df.loc[i, 'column'] 
    
[/code]

今回の問題はそれだけではないですね。Pandasを使うときに`for`を使うと計算が非常に遅くなります。この場合だと次のように`str`アクセサを使うことで、データの各要素に対して文字列メソッドを適用することができるので、簡単にかけて高速に処理できます。

[code]

    df['column'] = df['column'].str.split('%')[0]
    
[/code]

また、%が右側についているので数値にできないという場合がよくあるのですが、その場合は`rstrip`が使えるので簡単にかけて処理も速いです。

[code]

    df['column'] = df['column'].str.rstrip('%')
    
[/code]


CC BY-SA 4.0
2018-07-15T01:06:13.360
46623
2018-07-15T01:13:41.950
2018-07-15T01:13:41.950
15171
15171
46614
answer