一、常规标准化
z-score
作为一种标准化方法,已经在各种数据处理中被使用,比如最为常见的机器学习,多种组学数据的标准化。
但是,z-score
标准化有其自身的限制,这些限制来自于:
- 异常值的存在
- 正太分布(方差齐性)的假说
当我们在处理各种组学数据时,常常由于观察值不多导致数据在进行正态性检验的时候,发现并不服从正太假说;有时候,还会受到异常值的影响。
我们先介绍常规的z-score
标准化方法:
z
i
=
x
i
−
μ
δ
z_i = \frac{x_i-\mu}{\delta}
zi=δxi−μ
其中,
μ
\mu
μ是均值;
x
i
x_i
xi表示样本观察值;
δ
\delta
δ表示所有样本观察值的标准差;
z
i
z_i
zi表示该样本点距离样本均值有多少个标准差,用来表示各原始数据在数据组中的相对位置。
一个常规的应用:
如果样本服从正态分布,当
∣
z
i
∣
>
2
|z_i|>2
∣zi∣>2时,该样本点即为异常点。它标示的是距离均值2个标准差范围的数据量有95%(正态分布的性质),有2.5%的数据会被标记为异常。
二、修正后的z-score
由于均值和标准差对于异常值都比较敏感,导致常规的z-score
方法出现偏差。因此,对其进行了修正:
Z
i
=
x
i
−
m
e
d
i
a
n
(
x
i
)
M
A
D
Z_i=\frac{x_i-median(x_i)}{MAD}
Zi=MADxi−median(xi)
其中,
x
i
x_i
xi是样本观察值,
m
e
d
i
a
n
(
x
i
)
median(x_i)
median(xi)是所有样本观察值的中位数,MAD(Median Absolute deviation)是中位数绝对偏差,定义如下:
M
A
D
=
m
e
d
i
a
n
∣
x
i
−
m
e
d
i
a
n
(
x
i
)
∣
MAD=median|x_i-median(x_i)|
MAD=median∣xi−median(xi)∣
标准差
的定义是与均值距离的平方和,对异常值更敏感,比如一个较大的样本值在样本内,则会直接影响到样本的标准差,而MAD
不会,它具有更好的鲁棒性
。
MAD与标准差的关系
MAD的用法类似于样本标准差,为了使用MAD作为一致估计量来估计标准差,我们可以有:
δ
=
k
∗
M
A
D
\delta=k*MAD
δ=k∗MAD
其中,
k
k
k只是一个常量因子,与样本分布有关,如果样本服从正态分布,
k
=
1.4826
k=1.4826
k=1.4826.
三、实践
例子:这里有一个数据集,包含2012年康涅狄格州学区SAT的学生参与率,我们的任务是找到低参与率的学校,可以看做一个异常检测任务。由于我们要找低参与率的学校,所以阈值是一个负数,这里我们设为-2。
ps: 对于较大的数据集,较大的绝对值z zz(通常为z = 3 z=3z=3)通常用作阈值。因为我们的数据集很小,z zz的大值可能导致没有数据被标记为异常。另外,我们在选择z$时比较保守,因为我们想帮助尽可能多的学校。
# 常规z-score
import scipy.stats as ss
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
import random
#用于展示检测结果
def plot_anomaly(score_data, threshold):
# Mask to plot values above and below threshold in different colors
score_data = score_data.copy().sort_values(ascending=False).values
ranks = np.linspace(1, len(score_data), len(score_data))
mask_outlier = (score_data < threshold)
plt.figure(dpi=150)
plt.plot(ranks[~mask_outlier], score_data[~mask_outlier],'o', color='b',label='OK schools')
plt.plot(ranks[mask_outlier], score_data[mask_outlier],'o', color='r', label='anomalies')
plt.axhline(threshold,color='r',label='threshold', alpha=0.5)
plt.legend(loc = 'lower left')
plt.title('Z-score vs. school district', fontweight='bold')
plt.xlabel('Ranked School district')
plt.ylabel('Z-score')
plt.show()
data = pd.read_csv('SAT_CT_District_Participation_2012.csv')
zscore_rate = ss.zscore(ct_test['Participation Rate'], ddof=0)#ddof是标准差计算中的自由度修正,默认为0,即标准差分母是n,而不是n-1
data=data.assign(zscore=zscore_rate)
plot_anomaly(data['zscore'], -2)
anomalies = data[(data['zscore'] < -2)]
anomalies
--------------------------------------------------------
# 修正z-score
def plot_anomaly(score_data, threshold):
# Mask to plot values above and below threshold in different colors
score_data = score_data.copy().sort_values(ascending=False).values
ranks = np.linspace(1, len(score_data), len(score_data))
mask_outlier = (score_data < threshold)
plt.figure(dpi=150)
plt.plot(ranks[~mask_outlier], score_data[~mask_outlier],'o', color='b',label='OK schools')
plt.plot(ranks[mask_outlier], score_data[mask_outlier],'o', color='r', label='anomalies')
plt.axhline(threshold,color='r',label='threshold', alpha=0.5)
plt.legend(loc = 'lower left')
plt.title('Z-score vs. school district', fontweight='bold')
plt.xlabel('Ranked School district')
plt.ylabel('Z-score')
plt.show()
#修正z-score方法
def modify_zscore(data,k=1.4826):
data_median=np.median(data)
dev_from_med=np.array(data)-data_median
MAD=np.median(np.abs(dev_from_med))
mod_zscore=dev_from_med/(k*MAD)#使用的是标准差的一致性估计
return mod_zscore,MAD
data = pd.read_csv('SAT_CT_District_Participation_2012.csv')
mod_zscore,MAD=modified_zscore(data['Participation Rate'])
data = data.assign(mod_zscore=mod_zscore)
plot_anomaly(data['mod_zscore'],-2)
anomalies = data[(data['zscore'] < -2)]
anomalies
效果比较:
我们可以发现,z-score方法识别出的异常点一共4项,而修正后的z-score方法识别结果除此之外,还识别出第55项0.47为低参与率。另外,通过计算,可以发现k ∗ M A D k*MADk∗MAD比样本标准差更小,也体现MAD统计量受异常点影响较小,具有更好的鲁棒性。