如何检测两组数据是否同分布?
一个模型中,很重要的技巧就是要确定训练集与测试集特征是否同分布,这也是机器学习的一个很重要的假设,但很多时候我们默认这个道理,却很难有方法来保证数据同分布。
T检验(Binary)
T检验是一种适合小样本的统计分析方法,通过比较不同数据的均值,研究两组数据是否存在差异。
我们参考《python科学计算第二版》:
https://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s/sv5QipNA6QPWgDC3R8DuAQ
单样本t检验
单样本t检验是样本均值与总体均值的比较问题。其中总体服从正态分布,从正态总体中抽样得到n个个体组成抽样样本,计算抽样样本均值和标准差,判断总体均值与抽样样本均值是否相同。
from scipy.stats import ttest_1samp
import numpy as np
print("Null Hypothesis:μ=μ0=30,α=0.05")
ages = [25,36,15,40,28,31,32,30,29,28,27,33,35]
t = (np.mean(ages)-30)/(np.std(ages,ddof=1)/np.sqrt(len(ages)))
ttest,pval = ttest_1samp(ages,30)
print(t,ttest)
if pval < 0.05:
print("Reject the Null Hypothesis.")
else:
print("Accept the Null Hypothesis.")
配对样本t检验
配对样本主要是同一实验前后效果的比较,或者同一样品用两种方法检验结果的比较。可以把配对样本的差作为变量,差值的总体均数为0,服从正态分布。
from scipy.stats import ttest_rel
s1 = [620.16,866.50,641.22,812.91,738.96,899.38,760.78,694.95,749.92,793.94]
s2 = [958.47,838.42,788.90,815.20,783.17,910.92,758.49,870.80,826.26,805.48]
print("Null Hypothesis:mean(s1)=mean(s2),α=0.05")
ttest,pval = ttest_rel(s1,s2)
if pval < 0.05:
print("Reject the Null Hypothesis.")
else:
print("Accept the Null Hypothesis.")
独立样本t检验
对于第三个问题独立样本t检验,比较两个样本所代表的两个总体均值是否存在显著差异。除了要求样本来自正态分布,还要求两个样本的总体方差相等“方差齐性”。
from scipy.stats import ttest_ind,norm,f
import numpy as np
def ftest(s1,s2):
'''F检验样本总体方差是否相等'''
print("Null Hypothesis:var(s1)=var(s2),α=0.05")
F = np.var(s1)/np.var(s2)
v1 = len(s1) - 1
v2 = len(s2) - 1
p_val = 1 - 2*abs(0.5-f.cdf(F,v1,v2))
print(p_val)
if p_val < 0.05:
print("Reject the Null Hypothesis.")
equal_var=False
else:
print("Accept the Null Hypothesis.")
equal_var=True
return equal_var
def ttest_ind_fun(s1,s2):
'''t检验独立样本所代表的两个总体均值是否存在差异'''
equal_var = ftest(s1,s2)
print("Null Hypothesis:mean(s1)=mean(s2),α=0.05")
ttest,pval = ttest_ind(s1,s2,equal_var=equal_var)
if pval < 0.05:
print("Reject the Null Hypothesis.")
else:
print("Accept the Null Hypothesis.")
return pval
np.random.seed(42)
s1 = norm.rvs(loc=1,scale=1.0,size=20)
s2 = norm.rvs(loc=1.5,scale=0.5,size=20)
s3 = norm.rvs(loc=1.5,scale=0.5,size=25)
ttest_ind_fun(s1,s2)
ttest_ind_fun(s2,s3)
KS检验(Numerical)
KS检验是一种统计检验方法,其通过比较两样本的频率分布、或者一个样本的频率分布与特定理论分布(如正态分布)之间的差异大小来推论两个分布是否来自同一分布。
KS检验与t-检验之类的其他方法不同是KS检验不需要知道数据的分布情况,可以算是一种非参数检验方法。当然这样方便的代价就是当检验的数据分布符合特定的分布事,KS检验的灵敏度没有相应的检验来的高。在样本量比较小的时候,KS检验最为非参数检验在分析两组数据之间是否不同时相当常用。
PS:t-检验的假设是检验的数据满足正态分布,否则对于小样本不满足正态分布的数据用t-检验就会造成较大的偏差,虽然对于大样本不满足正态分布的数据而言t-检验还是相当精确有效的手段。
判断是否符合正态分布
KS函数说明文档:https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.kstest.html
import numpy as np
import pandas as pd
from scipy import stats
data = [87,77,92,68,80,78,84,77,81,80,80,77,92,86,
76,80,81,75,77,72,81,72,84,86,80,68,77,87,
76,77,78,92,75,80,78]
# 样本数据,35位健康男性在未进食之前的血糖浓度
df = pd.DataFrame(data, columns =['value'])
e = df['value'].mean() # 计算均值
std = df['value'].std() # 计算标准差
stats.kstest(df['value'], 'norm', (e, std))
# .kstest方法:KS检验,参数分别是:待检验的数据,检验方法(这里设置成norm正态分布),均值与标准差
# 结果返回两个值:statistic → D值,pvalue → P值
# p值大于0.05,为正态分布
#KstestResult(statistic=0.1590180704824098, pvalue=0.3066297258358026)
# p值大于0.05,不拒绝原假设,因此上面的数据服从正态分布。
#且一般情况下, stats.kstest(df[‘value’], ‘norm’, (u, std))一条语句就得到p值的结果。
#from scipy import stats
#stats.kstest(rvs, cdf, args=(),…)
#其中rvs可以是数组、生成数组的函数或者scipy.stats里面理论分布的名字
#cdf可以与rvs一致。若rvs和cdf同是数组,则是比较两数组的分布是否一致;一个是数组,另一个是理论分布的名字,则是看样本是否否和理论分布
#args是一个元组,当rvs或者cds是理论分布时,这个参数用来存储理论分布的参数,如正态分布的mean和std。
KL Divergence
KL 散度是一种衡量两个概率分布的匹配程度的指标,两个分布差异越大,KL散度越大。注意如果要查看测试集特征是否与训练集相同,P代表训练集,Q代表测试集,这个公式对于P和Q并不是对称的。
计算公式为:
对于离散分布
对于连续分布
import numpy as np
import scipy.stats
# 随机生成两个离散型分布
x = [np.random.randint(1, 11) for i in range(10)]
print(x)
print(np.sum(x))
px = x / np.sum(x)
print(px)
y = [np.random.randint(1, 11) for i in range(10)]
print(y)
print(np.sum(y))
py = y / np.sum(y)
print(py)
# 利用scipy API进行计算
# scipy计算函数可以处理非归一化情况,因此这里使用
# scipy.stats.entropy(x, y)或scipy.stats.entropy(px, py)均可
KL = scipy.stats.entropy(x, y)
print(KL)
# 实现
KL = 0.0
for i in range(10):
KL += px[i] * np.log(px[i] / py[i])
# print(str(px[i]) + ' ' + str(py[i]) + ' ' + str(px[i] * np.log(px[i] / py[i])))
print(KL)
机器学习模型检测
用特征训练模型来分辨测试集与测试集,若模型效果好的话代表训练集和测试集存在较大差异,否则代表训练集和测试集分布比较相似。
具体做法是构建一个二分类模型,对训练集打上0,测试集打上1,然后shuffle一下进行训练,若分类效果好,代表训练集和测试集区分度很高,那么分布差异就较大。