避免查询局部异常值的 iterrows

问题描述

对于包含坐标列(例如“x”、“y”)的数据框,我想检查相关值“val”是否偏离本地(到坐标的距离here 或 here),构建 KDTree 并查询每一行的本地平均值。但是我想知道是否有更好的解决方案可以防止数据帧迭代导致更快的执行?

import pandas as pd
import numpy as np
from sklearn.neighbors import KDTree

xy = np.mgrid[0:10,0:10]
df = pd.DataFrame({'x':xy[0].ravel(),'y':xy[1].ravel(),'val':np.random.rand(100)})

tree = KDTree(df[['x','y']].values,metric='euclidean')

radius = 5
for i,row in df.iterrows():
    coords = row[['x','y']].values.reshape(1,-1)
    idx = tree.query_radius(coords,r=radius)[0]
    df.loc[i,'outlier'] = np.abs(row['val'] - df.iloc[idx]['val'].mean()) > df.iloc[idx]['val'].std()
df = df[df["outlier"] == False] #select df without outlier

解决方法

可能有办法避免我尚未弄清楚的全部循环,但是您可以应用的一个简单解决方案是将所需的值放入数组中,然后对这些数组执行矢量化操作。我做了一些测试,平均执行时间减少了 40%。

coords = df[['x','y']].apply(lambda row: row.values.reshape(1,-1),axis=1)
df.coords = coords
idx = coords.apply(lambda x: tree.query_radius(x,r=radius)[0])
means = idx.apply(lambda x: df.loc[x,'val'].mean())
df.means = means
stds = idx.apply(lambda x: df.loc[x,'val'].std())
df.stds = stds
df['outlier']=np.abs(df['val']-df.means)>df.stds