困っていること
データフレームの各列に対して分布から外れるデータを除去した形で返したくて、自作で関数を作りました。所望の動作はするのですが、冗長な感じが抜けず、もっとスマートなコードにしたいと考えています。おそらく、lambda, map(), apply(), applymap()などを使って、やることになるのかなとも思うのですが、なかなか書けません。どなたか、もっとシンプルにスマートなコードを書く方法を教えていただけないでしょうか?お手数ですが、よろしくお願いします。
想定していること
私がやりたいのは、「同一のカラムの中にある全データに対して分布を取り(行方向ではない)、その分布から外れるデータの箇所をNANに置換して返す」というものです。以下の場合だと、カラムAのインデックス1に数値1000が入っていますが、数値1000はカラムA全体のデータ分布からある一定の条件を持って外れているのでその部分をNANにする、という処理を行いたいです。他のカラム(B列,C列,,,)も同様の処理を行いたい。
### 動作を再現できるデータフレーム疑似生成 ### import numpy as np import pandas as pd import random mu, sigma = 0, (10-i)+1 data = np.array([[random.gauss(mu, sigma) for _ in range(500)],[random.gauss(mu, sigma) for _ in range(500)]]) df=pd.DataFrame(data.T,columns=["A","B"]) df.loc[1,"A"]=1000 df.loc[3,"B"]=-1000 A B 0 -5.215559 15.548085 1 1000.000000 7.173219 2 -8.806023 0.233582 3 -17.739273 -1000.000000 4 3.270542 6.586852 ... ... ... 495 18.536944 23.445213 496 0.197173 8.680920 497 -8.324104 -4.110047 498 1.917041 -8.685127 499 -8.054887 -11.455291
↓↓↓↓↓↓ 変換後に期待している出力
A B 0 -5.215559 15.548085 1 NAN 7.173219 2 -8.806023 0.233582 3 -17.739273 NAN 4 3.270542 6.586852 ... ... ... 495 18.536944 23.445213 496 0.197173 8.680920 497 -8.324104 -4.110047 498 1.917041 -8.685127 499 -8.054887 -11.455291
私が書いた自作コード
def remove_outlier(dataframe): results_all=[] for c in dataframe.columns: q1 = dataframe[c].quantile(0.3) q3 = dataframe[c].quantile(0.7) iqr = q3 - q1 fence_low = q1-2*iqr fence_high = q3+2*iqr result=[] for i,k in zip(range(len(dataframe)),[(dataframe[c] > fence_low) & (dataframe[c] < fence_high)][0].values): if k==False: result.append(np.nan) else: result.append(dataframe[c][i]) results_all.append(result) new_df=pd.DataFrame(np.array(results_all).T) new_df.columns = dataframe.columns return new_df
再度:追記
import numpy as np import pandas as pd import random ### 想定しているデータフレーム def dataset(): mu, sigma = 0, (10-i)+1 data = np.array([[random.gauss(mu, sigma) for _ in range(500)],[random.gauss(mu, sigma) for _ in range(500)]]) dataframe=pd.DataFrame(data.T,columns=["A","B"]) dataframe.loc[1,"A"]=1000 dataframe.loc[3,"B"]=-1000 return dataframe df=dataset() print(df.head(5)) A B 0 -16.397471 -15.766524 1 1000.000000 -2.913148 2 20.302729 -6.395709 3 -6.314884 -1000.000000 4 -5.692132 -2.014456 ### 外れている値をNANへ変換する自作関数 def remove_outlier(dataframe): results_all=[] for c in dataframe.columns: q1 = dataframe[c].quantile(0.3) q3 = dataframe[c].quantile(0.7) iqr = q3 - q1 fence_low = q1-2*iqr fence_high = q3+2*iqr result=[] for i,k in zip(range(len(dataframe)),[(dataframe[c] > fence_low) & (dataframe[c] < fence_high)][0].values): if k==False: result.append(np.nan) else: result.append(dataframe[c][i]) results_all.append(result) new_df=pd.DataFrame(np.array(results_all).T) new_df.columns = dataframe.columns return new_df ### 自作関数処理した結果を表示したもの(期待している出力) print(remove_outlier(df).head(5)) A B 0 -16.397471 -15.766524 1 NaN -2.913148 2 20.302729 -6.395709 3 -6.314884 NaN 4 -5.692132 -2.014456
回答1件
あなたの回答
tips
プレビュー