Vorrei fornire due metodi in questa risposta, soluzione basata su "punteggio z" e soluzione basata su "IQR".
Il codice fornito in questa risposta funziona sia su numpyarray singolo dim che su array multipli numpy.
Importiamo prima alcuni moduli.
import collections
import numpy as np
import scipy.stats as stat
from scipy.stats import iqr
metodo basato sul punteggio z
Questo metodo verificherà se il numero non rientra nelle tre deviazioni standard. In base a questa regola, se il valore è outlier, il metodo restituirà true, in caso contrario restituirà false.
def sd_outlier(x, axis = None, bar = 3, side = 'both'):
assert side in ['gt', 'lt', 'both'], 'Side should be `gt`, `lt` or `both`.'
d_z = stat.zscore(x, axis = axis)
if side == 'gt':
return d_z > bar
elif side == 'lt':
return d_z < -bar
elif side == 'both':
return np.abs(d_z) > bar
Metodo basato su IQR
Questo metodo verificherà se il valore è minore q1 - 1.5 * iqro maggiore di q3 + 1.5 * iqr, che è simile al metodo di stampa di SPSS.
def q1(x, axis = None):
return np.percentile(x, 25, axis = axis)
def q3(x, axis = None):
return np.percentile(x, 75, axis = axis)
def iqr_outlier(x, axis = None, bar = 1.5, side = 'both'):
assert side in ['gt', 'lt', 'both'], 'Side should be `gt`, `lt` or `both`.'
d_iqr = iqr(x, axis = axis)
d_q1 = q1(x, axis = axis)
d_q3 = q3(x, axis = axis)
iqr_distance = np.multiply(d_iqr, bar)
stat_shape = list(x.shape)
if isinstance(axis, collections.Iterable):
for single_axis in axis:
stat_shape[single_axis] = 1
else:
stat_shape[axis] = 1
if side in ['gt', 'both']:
upper_range = d_q3 + iqr_distance
upper_outlier = np.greater(x - upper_range.reshape(stat_shape), 0)
if side in ['lt', 'both']:
lower_range = d_q1 - iqr_distance
lower_outlier = np.less(x - lower_range.reshape(stat_shape), 0)
if side == 'gt':
return upper_outlier
if side == 'lt':
return lower_outlier
if side == 'both':
return np.logical_or(upper_outlier, lower_outlier)
Infine, se vuoi filtrare i valori anomali, usa un numpyselettore.
Buona giornata.