Numpy之随机抽样思维导图
注:为了节约行数,默认import numpy as np已经写在每段代码前,不再重复写入,如果有新的包引入,会在代码头部import:
import matplotlib.pyplot as plt
from scipy import stats
import seaborn as sns
前言
在本章中,我们会学习Numpy中随机抽样的相关方法,而由于Scipy库也是Python中科学计算不可或缺的一个模块,所以我们进行对比学习。
1、random.seed()方法
用于指定随机数生成时所用算法开始的整数值
numpy.random.seed(self, seed=None)
- 如果使用相同的seed( )值,则每次生成的随即数都相同
- 如果不设置这个值,则系统根据时间来自己选择这个值,生成自己的种子,此时每次生成的随机数因时间差异而不同
- 设置的seed()值仅一次有效
一般来说,设置成当天的日期为好,如:
>>> np.random.seed(20201125)
2、random.seed()方法实例
#案例1
>>> for i in range(5):
>>> print(np.random.random())
0.38797992474085063
0.27952815592665314
0.5933277494875425
0.5398467698311418
0.0075104331643769395
#案例2
>>> for i in range(5):
>>> np.random.seed(1)
>>> print(np.random.random())
0.417022004702574
0.417022004702574
0.417022004702574
0.417022004702574
0.417022004702574
#案例3
>>> np.random.seed(1)
>>> for i in range(5):
>>> print(np.random.random())
0.417022004702574
0.7203244934421581
0.00011437481734488664
0.30233257263183977
0.14675589081711304
案例1是为了说明当不使用seed()方法
时,产生的随机数可能会不同。案例2说明,如果在每次使用random()方法
前使用seed()方法
,那么产生的随机数会保持相同。案例3说明seed()方法
只临时生效一次,需在每次使用random()方法
前都使用seed()方法
,否则仍跟案例1情况相同。
一、离散型随机变量
1、二项分布
在概率论和统计学中,二项分布是n个独立的成功/失败试验中成功的次数的离散概率分布,其中每次试验的成功概率为p。这样的单次成功/失败试验又称为伯努利试验。实际上,当n=1时,二项分布就是伯努利分布。
二项分布的概率密度函数为:
1)在numpy中实现
numpy.random.binomial(n, p, size=None)
参数解释:
- n:二项分布的次数
- p:二项分布的成功概率
- size:我的理解是size表示进行二项分布的次数,比如size=10,那么就进行10次上面参数的二项分布
font = {'family' : 'SimHei',
'weight' : 'bold',
'size' : '16',
}
plt.rc('font', **font) # 步骤一(设置字体的更多属性)
plt.rc('axes', unicode_minus=False) # 步骤二(解决坐标轴负数的负号显示问题)
n = 10
p = 0.5
size = 50000
x = range(11)
t = np.random.binomial(n, p, size)
p = stats.binom.pmf(x, n, p)
fig, ax = plt.subplots(1, 1)
sns.distplot(t, bins=10, hist_kws={'density':True}, kde=False, label='Distplot from 50000 samples')
plt.title('二项分布')
plt.legend(bbox_to_anchor=(1.05, 1))
2)在scipy中实现
p = stats.binom.pmf(x, n, p)
stats.binom.pmf()方法
求得的是概率分布,第一个参数是用于储存概率的数据结构,第二个结构是二项分布中重复的次数,第三个参数是二项分布中成功的概率。
让我们把这两种方式通过两种不同的方式在一起显示出来:
fig, ax = plt.subplots(1, 1)
sns.distplot(t, bins=10, hist_kws={'density':True}, kde=False, label='Distplot from 50000 samples')
sns.scatterplot(x, p, color='purple')
sns.lineplot(x, p, color='purple', label='True mass density')
plt.title('二项分布')
plt.legend(bbox_to_anchor=(1.05, 1))
2、泊松分布
泊松分布的概率密度函数为:
泊松分布的参数λ是单位时间(或单位面积)内随机事件的平均发生次数。 泊松分布适合于描述单位时间内随机事件发生的次数。
1)在numpy中实现
numpy.random.poisson(lam=1.0, size=None)
lam表示在单位时间内某事发生的平均次数,而size依然是该试验重复的次数。
这里我们注意,泊松分布概率函数中的k在random.poisson()方法
中并没有体现,方法返回的是长度为50000的,λ为lam的试验数据,其依然可以通过seed()方法
固定随机情况
x = range(11)
lam = 2
size = 50000
t = np.random.poisson(lam, size)
sns.distplot(t, bins=10, hist_kws={'density':True}, kde=False, label='Distplot from 50000 samples')
#sns.scatterplot(x, p, color='purple')
#sns.lineplot(x, p, color='purple', label='True mass density')
plt.title('泊松分布')
plt.legend(bbox_to_anchor=(1.05, 1))
2)在scipy中实现
x = range(50)
fig, ax = plt.subplots()
for lam in [1, 2, 5, 10, 20]:
#在scipy中实现
p = stats.poisson.pmf(x, lam)
sns.lineplot(x, p, label='lam='+str(lam))
plt.title('不同lam的泊松分布')
plt.legend()
让我们把这两种方式通过两种不同的方式在一起显示出来:
fig, ax = plt.subplots(1, 1)
sns.distplot(t, bins=10, hist_kws={'density':True}, kde=False, label='Distplot from 50000 samples')
sns.scatterplot(x, p, color='purple')
sns.lineplot(x, p, color='purple', label='True mass density')
plt.title('泊松分布')
plt.legend(bbox_to_anchor=(1.05, 1))
3、超几何分布
超几何分布的概率密度函数为:
可以描述为产品抽样检查中经常遇到一类实际问题,假定在N件产品中有M件不合格品,即不合格率。在产品中随机抽n件做检查,发现x件不合格品的概率。
1)在numpy中实现
numpy.random.hypergeometric(ngood, nbad, nsample, size=None)
参数解释:
- ngood:目标物品的数量
- nbad:总体减去目标物品的数量
- nsample:要抽取的随机物品的数量
- size:试验总次数
20只动物里有7只是狗,无放回抽取12只狗的数量,重复50000次
np.random.seed(20201125)
ngood = 7
nbad = 13
nsample = 12
size = 50000
x = np.random.hypergeometric(ngood=ngood,nbad=nbad,nsample=nsample,size=size)
plt.title('狗的数量概率分布')
sns.distplot(x, bins=8, hist_kws={'density':True}, kde=False)
2)在scipy中实现
np.random.seed(20201125)
ngood = 7
nbad = 13
nsample = 12
size = 50000
plt.title('狗的数量概率分布')
x = range(11)
p = stats.hypergeom.pmf(k=range(11), M=ngood+nbad, n=ngood, N=nsample)
sns.scatterplot(x, p, color='purple')
sns.lineplot(x, p, color='purple')
其中M为总量,n为目标物品的数量,N为本次抽取的数量,需要注意的是,scipy的实现和numpy的实现在参数上有所不同,但是都能通过计算完全显示,比如M=ngood+nbad。
让我们把这两种方式通过两种不同的方式在一起显示出来:
np.random.seed(20201125)
ngood = 7
nbad = 13
nsample = 12
size = 50000
a = np.random.hypergeometric(ngood=ngood,nbad=nbad,nsample=nsample,size=size)
p = stats.hypergeom.pmf(k=x, M=20, n=7, N=12)
x = range(11)
fig, ax = plt.subplots(1, 1)
sns.distplot(a, bins=8, hist_kws={'density':True}, kde=False, label='numpy')
sns.scatterplot(x, p, color='purple')
sns.lineplot(x, p, color='purple', label='Scipy')
plt.title('超几何分布')
plt.legend(bbox_to_anchor=(1.5, 1))
二、连续型随机变量
1、均匀分布
均匀分布的概率密度函数为:
在概率论和统计学中,均匀分布也叫矩形分布,它是对称概率分布,在相同长度间隔的分布概率是等可能的。 均匀分布由两个参数a和b定义,它们是数轴上的最小值和最大值,通常缩写为U(a,b)。
1)在numpy中实现
numpy.random.uniform(low=0.0, high=1.0, size=None)
参数解释:
- low:最小值,默认值为0
- high:最大值,默认值为1
- size:随机重复次数
a = 0
b = 100
size = 50000000
np.random.seed(20201125)
x = np.random.uniform(a,b,size=size)
plt.title('50000000个样本的均匀分布')
plt.hist(x,bins=20)
plt.show()
我们再来看另一种方法:
numpy.random.rand(d0, d1, ..., dn)
将random.rand()方法
与random.uniform()方法
对比后可知,前者是特殊化的后者,范围被限定在0到1之间,但生成的数据都是浮点型:
>>> np.random.seed(20201125)
>>> x = np.random.rand(3,3)
>>> print(x)
[[0.80981593 0.03579724 0.20674657]
[0.94257697 0.62413889 0.01230949]
[0.31290955 0.05072421 0.47959837]]
>>> np.random.seed(20201125)
>>> x = np.random.uniform(0,1,size=(3,3))
>>> print(x)
[[0.80981593 0.03579724 0.20674657]
[0.94257697 0.62413889 0.01230949]
[0.31290955 0.05072421 0.47959837]]
那如果要指定生成整型数据呢,我们用到了下面的方法:
numpy.random.randint(low, high=None, size=None, dtype=int)
将random.randint()方法
与random.uniform()方法
对比后可知,前者是特殊化的后者,前者生成的数据是整型,而后者生成的数据是浮点型:
>>> a = 0
>>> b = 100
>>> np.random.seed(20201125)
>>> x = np.random.randint(a,b,size=(3,3))
>>> print(x)
[[91 91 3]
[77 88 13]
[40 52 28]]
>>> np.random.seed(20201125)
>>> x = np.random.uniform(a,b,size=(3,3))
>>> print(x)
[[80.98159305 3.57972415 20.67465728]
[94.25769694 62.41388859 1.2309494 ]
[31.2909554 5.07242105 47.95983712]]
我们还可以看到,就算使用seed()方法
设置相同的种子,但是生成的整型和浮点型的整数部分也是不相关的。
2)在scipy中实现
>>> a = 0
>>> b = 100
>>> x = stats.uniform.cdf(10,a,b)
>>> y = stats.uniform.cdf(50,a,b)
#输出的是10-50的数据占整体的比例
>>> print(y-x)
0.4
>>> x = stats.uniform.cdf(a,a,b)
>>> y = stats.uniform.cdf(b,a,b)
#输出的是0-100的数据占整体的比例
>>> print(y-x)
1.0
其中stats.uniform.cdf()方法
是求均匀分布的累积分布,其函数如下:
2、正态分布
一维正态分布概率密度函数为:
其均值为μ,标准差为σ
1)在numpy中实现
numpy.random.normal(loc=0.0, scale=1.0, size=None)
参数解释:
- loc:均值μ
- scale:标准差σ
- size:生成形状,为int型时表示长度
生成一个shape为2*4的服从正态分布的数组:
>>> np.random.seed(20201125)
#均值
>>> mu = 6
#标准差
>>> sigma = 0.1
#生成数据形状
>>> size = (2,4)
>>> x = np.random.normal(mu,sigma,size)
>>> print(x)
[[5.96965436 5.98736326 6.1735022 5.98482979]
[5.88968918 6.13679396 5.8181901 6.06004545]]
生成5万个服从该正态分布的数组:
np.random.seed(20201125)
mean = 0
std = 1
size = 50000
x = np.linspace(-3, 3, 100)
t = np.random.normal(mean, std, size)
fig, ax = plt.subplots(1, 1)
sns.distplot(t, bins=100, hist_kws={'density':True}, kde=False)
2)在scipy中实现
实现方法norm.pdf(x, loc, scale)
,其中x表示分布总体X <= x的概率和,loc表示均值μ,scale表示标准差σ:
>>> y = stats.norm.cdf(6.1,loc = 6,scale = 0.1) - stats.norm.cdf(5.9,loc = 6,scale = 0.1)
>>> print(y)
0.6826894921370843
>>> print((np.sum(x < 6.1) - np.sum(x < 5.9)) / size)
0.682262
3)标准正态分布
标准正态分布的均值为0,标准差为1,其概率密度函数为:
由于标准正态分布是一种特殊的正态分布,所以不展开叙述,仅介绍numpy中的标准正态分布实现方法:
numpy.random.randn(d0, d1, ..., dn)
其中参数可代表生成的数据的维度,也可以为int型变量,代表生成的一维数据的长度。
另外,在scipy中实现标准正态分布依然使用norm.pdf(x, loc, scale)
方法,只不过不指定loc和scale(默认值分别是0和1)。
3、指数分布
指数分布的概率密度函数为:
其中λ > 0是分布的一个参数,常被称为率参数(rate parameter)。即每单位时间内发生某事件的次数。
1)在numpy中实现
numpy.random.exponential(scale=1.0, size=None)
参数解释:
- scale:1/λ,保证非负
- size:生成的数据的维度,也可以为int型变量,代表生成的一维数据的长度
np.random.seed(20201125)
lam = 1
size = 50000
x = np.linspace(0, 10, 100)
t = np.random.exponential(1/lam, size)
sns.distplot(t, bins=100, hist_kws={'density':True}, kde=False)
plt.title('指数分布')
plt.legend(bbox_to_anchor=(2, 1))
2)在scipy中实现
x = np.linspace(0, 10, 100)
fig, ax = plt.subplots()
for scale in [0.2, 0.5, 1, 2, 5]:
p = stats.expon.pdf(x, scale=scale)
sns.lineplot(x, p, label='lam='+str(1/scale))
plt.title('不同lam的指数分布')
plt.legend()
三、其他随机函数
1、随机从序列中获取元素
用于随机从一维数组从随机抽取元素
numpy.random.choice(a, size=None, replace=True, p=None)
参数解释:
- a: 一维array或者整数,当为整数时生成np.arange(a)
- size:随机获取的次数
- replace:是否放回
- p:抽取概率
#从np.range(a)中随机获取元素 概率均等
>>> np.random.seed(20201125)
>>> x = np.random.choice(10,3)
>>> print(x)
[3 8 6]
#从np.range(a)中随机获取元素 概率指定
>>> np.random.seed(20201125)
>>> x = np.random.choice(10,3,p=[0.1,0.1,0,0,0,0,0,0,0,0.8])
>>> print(x)
[9 0 9]
#从np.range(a)中随机获取元素 概率指定且生成元素不重复
>>> np.random.seed(20201125)
>>> x = np.random.choice(10,3,replace = False,p=[0.1,0.1,0,0,0,0,0,0,0,0.8])
>>> print(x)
[9 0 1]
#从指定数据中随机获取元素 概率指定
>>> data = ['a','b','c']
>>> np.random.seed(20201125)
>>> x = np.random.choice(data,6,p=[0.5,0.4,0.1])
>>> print(x)
['b' 'a' 'a' 'c' 'b' 'a']
2、对数据集进行洗牌操作
用于打乱数组
numpy.random.shuffle(x)
参数解释:
- x:需要进行洗牌的数据结构
返回值为None
下面是简单的洗牌操作:
>>> np.random.seed(20201125)
>>> x = np.random.randint(0,100,10)
>>> print(x)
[91 91 3 77 88 13 40 52 28 19]
>>> np.random.seed(20201125)
>>> np.random.shuffle(x)
>>> print(x)
[52 3 88 13 91 91 19 40 28 77]
我们来洗一个二维数组:
我们可以看到,它将第2、3行调换了位置。
在官方的文档中,random.shuffle()方法
只能对第一维度进行洗牌,那么如果对于上面的数组,想要对其第二维度进行洗牌有什么办法呢?
我们可以用numpy的另一个洗牌方法:
numpy.random.Generator.shuffle(x, axis=0)
random.Generator.shuffle()方法
比random.shuffle()方法
多了一个可以指定洗牌维度的参数axis,我们调用一下试试:
这里注意它的使用方法是通过random.default_rng()去调用的。
四、作业
1、创建一个形为5×3的二维数组,以包含5到10之间的随机数。
【知识点:随机抽样】
如何创建随机二维数组?
#整型
>>> data = np.random.randint(5,10,(5,3))
>>> print(data)
[[9 7 8]
[5 7 7]
[8 8 9]
[6 7 6]
[9 8 9]]
#浮点型
>>> data = np.random.uniform(5,10,(5,3))
>>> print(data)
[[7.10146244 7.58977707 7.27101869]
[8.73973457 9.13760369 8.69965053]
[5.56770646 6.52635202 8.33992477]
[7.22468696 6.0879089 5.60673334]
[9.93335832 5.69551319 9.03317529]]
2、生成相应的数据
【知识点:随机抽样】
创建分别具有5000个数据的训练集(xi,y)和测试集(xi,y),其中xi在间隔(-10,10)上均匀随机分布。为了使回归问题“真实”,大的均匀噪声分布在[-0.2,0.2]已添加到所有训练样本中,同时测试数据保持无噪声。
版本1:
版本2: