掌握大规模数据集随机样本划分的生成方法和判别方法
(一)生成服从已知分布的N个随机数,验证N对样本分布函数与理论分布函数之间误差的影响,可以在2个分布上进行验证;
(二)尝试对N个随机数进行不同的数据划分,在各个数据块上验证样本分布函数与理论分布函数之间的误差,检验哪种数据划分能够保证在数据块上都能得到理想的样本分布函数和理论分布函数的拟合效果。
首先,我们实验的总体思路生成N个服从某个分布的随机数X,然后将X按照从小到大的顺序重现编码(即将X排序),得到X’,然后利用函数
F ( x ) = { 1 i f x > x ( N ) 0 x < x ( 1 ) k / N x ( k ) < x < x ( k + 1 ) F(x)= \begin{cases} 1& if \ x>x_{(N)}\\ 0& x
将这些数据表示为离散的概率分布函数,然后再与理论的概率分布函数进行比较
本次实验我们采用KL散度(相对熵)来衡量两个离散的概率分布的相似性,以此来量化不同N生成的经验分布函数对理论分布函数的好坏,KL散度越小(越接近0),说明这两个概率分布越相似
import scipy.stats
def KL_divergence(p,q):
return scipy.stats.entropy(p, q)
我们生成N个服从高斯分布(μ=200
,σ=25
)的随机数,并确定随机数值域的上下界,再对这些数据进行经验函数的映射,得到经验分布函数的step
图,再与通过公式计算得到的高斯分布的理论分布函数进行对比
def plot_gaussian_(mu,sigma,N):
# 生成服从高斯分布的随机数
X = np.random.normal(mu, sigma, size=N)
X = sorted(X)
min_x = X[0]
max_x = X[-1]# 随机数的上界
# 经验分布函数
def F(y):
def search(target):
'''''二分查找target的K值'''
left = 0
right = N-1
while left <= right:
mid = int((left+right)/2)
if X[mid] > target:
right = mid-1
elif X[mid]<=target:
left = mid+1
return left
if y < min_x:
return 0
elif y > max_x:
return 1
else:
return search(y)/N
# 绘制[0-max_x+20]范围内的经验分布函数和理论分布函数的曲线
x_list=np.linspace(0,max_x+20,1000)
expe_value=np.array([F(x) for x in x_list])# 经验
theo_value = ((1 / (np.sqrt(2 * np.pi) * sigma)) *
np.exp(-0.5 * (1 / sigma * (x_list - mu))**2))# 理论
theo_value = theo_value.cumsum()
theo_value /= theo_value[-1]
plt.step(x_list,expe_value,label='Empirical')
plt.step(x_list,list(reversed(expe_value)),label='Reversed emp')
plt.plot(x_list,theo_value, 'k--', linewidth=1.5,label='Theoretical')
# 设置
KL=KL_divergence(expe_value,theo_value)
# 设置
plt.grid(True)
plt.legend(loc='right')
plt.title('Gasussian distribution (N={},KL={})'.format(str(N),str(KL)))
plt.xlabel('x')
plt.ylabel('Likelihood')
绘制不同N对应的经验分布函数与理论分布函数的对比图,每个子图的标题包含了当前N的数量下,KL散度的大小
# 从标准高斯分布中随机抽N个样本(生成N个随机数)
mu = 100
sigma = 25
plt.figure(figsize=[20,12])
plt.subplot(2,2,1)
plot_gaussian_(mu,sigma,N=20)
# --------------------------------------------
plt.subplot(2,2,2)
plot_gaussian_(mu,sigma,N=50)
# --------------------------------------------
plt.subplot(2,2,3)
plot_gaussian_(mu,sigma,N=100)
# --------------------------------------------
plt.subplot(2,2,4)
plot_gaussian_(mu,sigma,N=10000)
plt.suptitle('Gaussian distribution',fontsize=25)
从图1我们可以很容易看出,当生成的随机数个数N由20逐渐增大到10000的时候,KL散度由2.6e-2减小到3.59e-5,这说明随着样本数量N的增大,经验分布函数与理论分布函数越来越相似
我们生成N个服从指数分布(scal
e=50000
)的随机数,并确定随机数值域的上下界,再对这些数据进行经验函数的映射,得到经验分布函数的step图,再与通过公式计算得到的指数分布的理论分布函数进行对比
import math
def plot_exp_(scale,N):
# 生成服从高斯分布的随机数
#X = np.random.normal(mu, sigma, size=N)
X = np.random.exponential(scale=scale, size=N)
X = sorted(X)
min_x = X[0]
max_x = X[-1]# 随机数的上界
# 经验分布函数
def F(y):
def search(target):
'''''二分查找target的K值'''
left = 0
right = N-1
while left <= right:
mid = int((left+right)/2)
if X[mid] > target:
right = mid-1
elif X[mid]<=target:
left = mid+1
return left
if y < min_x:
return 0
elif y > max_x:
return 1
else:
return search(y)/N
# 绘制[0-max_x+20]范围内的经验分布函数和理论分布函数的曲线
x_list=np.linspace(0,max_x+20,1000)
expe_value=np.array([F(x) for x in x_list])# 经验
# 理论
r=1/scale
theo_value = r*math.e**(-r*x_list)
theo_value = theo_value.cumsum()
theo_value /= theo_value[-1]
plt.step(x_list,expe_value,label='Empirical')
plt.step(x_list,list(reversed(expe_value)),label='Reversed emp')
plt.plot(x_list,theo_value, 'k--', linewidth=1.5,label='Theoretical')
# 设置
KL=KL_divergence(expe_value,theo_value)
# 设置
plt.grid(True)
plt.legend(loc='right')
plt.title('exponential distribution (N={},KL={})'.format(str(N),str(KL)))
plt.xlabel('x')
plt.ylabel('Likelihood')
绘制不同N对应的经验分布函数与理论分布函数的对比图,每个子图的标题包含了当前N的数量下,KL散度的大小
scale=50000
plt.figure(figsize=[20,12])
plt.subplot(2,2,1)
plot_exp_(scale,N=20)
# --------------------------------------------
plt.subplot(2,2,2)
plot_exp_(scale,N=50)
# --------------------------------------------
plt.subplot(2,2,3)
plot_exp_(scale,N=100)
# --------------------------------------------
plt.subplot(2,2,4)
plot_exp_(scale,N=10000)
plt.suptitle('exponential distribution',fontsize=25)
从图2我们可以很容易看出, 当生成的随机数个数N由20逐渐增大到10000的时候,KL散度由3.54e-3减小到3.34e-5,这说明随着样本数量N的增大,经验分布函数与理论分布函数越来越相似
我们生成N个服从均匀分布(low
=0
,high
=100
)的随机数,并确定随机数值域的上下界,再对这些数据进行经验函数的映射,得到经验分布函数的step图,再与通过公式计算得到的均匀分布的理论分布函数进行对比
import math
def plot_uniform_(a,b,N):
# 生成服从高斯分布的随机数
#X = np.random.normal(mu, sigma, size=N)
X = np.random.uniform(a,b,size=N)
X = sorted(X)
min_x = X[0]
max_x = X[-1]# 随机数的上界
# 经验分布函数
def F(y):
def search(target):
'''''二分查找target的K值'''
left = 0
right = N-1
while left <= right:
mid = int((left+right)/2)
if X[mid] > target:
right = mid-1
elif X[mid]<=target:
left = mid+1
return left
if y < min_x:
return 0
elif y > max_x:
return 1
else:
return search(y)/N
# 绘制[0-max_x+20]范围内的经验分布函数和理论分布函数的曲线
x_list=np.linspace(0,max_x+20,1000)
expe_value=np.array([F(x) for x in x_list])# 经验
# 理论
theo_value = np.array([1/(b-a) if (x > a and x < b) else 0 for x in x_list])
theo_value = theo_value.cumsum()
theo_value /= theo_value[-1]
plt.step(x_list,expe_value,label='Empirical')
plt.step(x_list,list(reversed(expe_value)),label='Reversed emp')
plt.plot(x_list,theo_value, 'k--', linewidth=1.5,label='Theoretical')
# 设置
KL=KL_divergence(expe_value,theo_value)
# 设置
plt.grid(True)
plt.legend(loc='right')
plt.title('uniform distribution (N={},KL={})'.format(str(N),str(KL)))
plt.xlabel('x')
plt.ylabel('Likelihood')
绘制不同N对应的经验分布函数与理论分布函数的对比图,每个子图的标题包含了当前N的数量下,KL散度的大小
a,b=0,100
plt.figure(figsize=[20,12])
plt.subplot(2,2,1)
plot_uniform_(a,b,N=20)
# --------------------------------------------
plt.subplot(2,2,2)
plot_uniform_(a,b,N=50)
# --------------------------------------------
plt.subplot(2,2,3)
plot_uniform_(a,b,N=100)
# --------------------------------------------
plt.subplot(2,2,4)
plot_uniform_(a,b,N=10000)
plt.suptitle('uniform distribution',fontsize=25)
从图3我们可以很容易看出, 当生成的随机数个数N由20逐渐增大到10000的时候,KL散度由1.75e-2减小到9.40e-6,这说明随着样本数量N的增大,经验分布函数与理论分布函数越来越相似
对于数据块总体的生成,我们打算生成服从高斯分布的N个随机数作为大数据块的总体
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
def generate_data(N,**kwargs):
dicts=kwargs
types=dicts['types']
if types == 'Gaussian':
mu=dicts['mu']
sigma=dicts['sigma']
return np.random.normal(mu,sigma,size=N)
elif types == 'exponential':
scale=dicts['scale']
return np.random.exponential(scale=scale,size=N)
elif types == 'uniform':
a=dicts['a']
b=dicts['b']
return np.random.uniform(low=a,high=b,size=N)
else:
return None
N=2500
data_gassuain=generate_data(N,types='Gaussian',mu=100,sigma=25)
# data_gassuain=np.sort(data_gassuain)
HDFS数据块划分原理如下列的代码所示,我们将总体数据切分为K块(HDFS数据块的个数为K)作为HDFS数据块,另外,在每个HDFS数据块内部,我们再将数据块分割为M块,方便RSP数据块的产生
'''''HDFS数据块按顺序划分'''
K=50# 100个HDFS数据块
M=50
# 按顺序切成K份
HDFS=np.array(np.split(data_gassuain,K))
for i in range(HDFS.shape[0]):
np.random.shuffle(HDFS[i])
HDFS_list=[np.split(D_k,M) for D_k in HDFS]
print(HDFS.shape)
RSP数据块划分,对于RSP数据块Dkm(RSP数据块共有M块),选取所有HDFS数据块中对应第m位置的那份数据块,组合成第m个RSP数据块,这里我们将每个RSP数据块和HDFS数据块的大小设置为相等,方便控制N的大小对理论分布函数和经验分布函数的影响,从而更好的探索RSP数据块和HDFS数据块的优劣
RSP=[[D_K[m] for D_K in HDFS_list] for m in range(M)]
for idx,RSP_ in enumerate(RSP):
tmp_RSP=RSP_[0]
for i in range(1,len(RSP_)):
tmp_RSP=np.hstack((tmp_RSP,RSP_[i]))
RSP[idx]=tmp_RSP
RSP=np.array(RSP)
print(RSP.shape)
即直接生成N个服从正态分布的随机数
通过直方图数据分布的直方图,我们可以发现RSP数据块的分布与正态分布更相似
经验分布函数与理论分布函数的对比图
N=50时,RSP的KL散度为2.87e-3,HDFS的KL散度为1.29e-2,这说明RSP的经验分布函数对理论分布函数的拟合效果要更好
通过数据分布的直方图,我们可以发现RSP数据块和HDFS数据块的分布与正态分布都较为相似,推测这是因为数据的规模相对较大,且HDFS数据块也是从一堆随机的数据中连续切段的,内部的随机性较强,与正态分布相似是合理的
经验分布函数与理论分布函数的对比图
N=100时,RSP的KL散度为1.69e-3,HDFS的KL散度为3.33e-3,这说明RSP的经验分布函数对理论分布函数的拟合效果要更好
通过数据分布的直方图,我们可以发现RSP数据块和HDFS数据块的分布与正态分布都较为相似,推测这是因为数据的规模相对较大,且HDFS数据块也是从一堆随机的数据中连续切段的,内部的随机性较强,与正态分布相似是合理的
经验分布函数与理论分布函数的对比图
HDFS
N=1000时,RSP的KL散度为4.90e-4,HDFS的KL散度为9.45e-4,这说明RSP的经验分布函数对理论分布函数的拟合效果要更好
由于未经过排序的数据总体不能明显的看出RSP数据块相对HDFS数据块的优势(每个数据子块的概率分布都与总体类似),所以我们将数据块进行排序
通过数据分布的直方图,我们可以发现RSP数据块与正态分布较为相似
经验分布函数与理论分布函数的对比图
N=50时,RSP的KL散度为4.73e-3,HDFS的KL散度为1.76e-1,这说明RSP的经验分布函数对理论分布函数的拟合效果要更好
经验分布函数与理论分布函数的对比图
N=100时,RSP的KL散度为1.18e-3,HDFS的KL散度为2.05e-1,这说明RSP的经验分布函数对理论分布函数的拟合效果要更好
经验分布函数与理论分布函数的对比图
N=1000时,RSP的KL散度为4.05e-5,HDFS的KL散度为3.48e-1,这说明RSP的经验分布函数对理论分布函数的拟合效果要更好