Python之scipy模块
一 簡單介紹
作為標準科學計算程序庫,SciPy類似于Matlab的工具箱,它是Python科學計算程序的核心包,它用于有效地計算NumPy矩陣,與NumPy矩陣協同工作。
SciPy庫由一些特定功能的子模塊構成,如下表所示:
模塊 | 功能 |
cluster | 矢量量化 / K-均值 |
constants | 物理和數學常數 |
fftpack | 傅里葉變換 |
integrate | 積分程序 |
interpolate | 插值 |
io | 數據輸入輸出 |
linalg | 線性代數程序 |
ndimage | n維圖像包 |
odr | 正交距離回歸 |
optimize | 優化 |
signal | 信號處理 |
sparse | 稀疏矩陣 |
spatial | 空間數據結構和算法 |
special | 任何特殊數學函數 |
stats | 統計 |
import numpy as np from scipy
import stats
以上代碼表示從SciPy模塊中導入stats子模塊,SciPy的其他子模塊導入方式與之相同,限于機器學習研究領域及篇幅限制,本章將重點介紹linalg、optimize、interpolate及stats模塊。
>>> from scipy import linalg
>>> arr = np.array([[1, 2], [3, 4]])
>>> linalg.det(arr) -2.0
>>> arr = np.array([[3, 2],[6, 4]])
>>> linalg.det(arr) 0.0
>>> linalg.det(np.ones((3, 4)))
#無論行列式還是逆矩陣只適用于n階矩陣的求解
Traceback (most recent call last):
...
ValueError: expected square matrix
scipy.linalg.inv()函數計算方陣的逆,示例代碼:
>>> arr = np.array([[1, 2], [3, 4]])
>>> iarr = linalg.inv(arr)
>>> iarr array([[-2. , 1. ], [ 1.5, -0.5]])
>>>np.allclose(np.dot(arr, iarr), np.eye(2))
#numpy.allclose()函數用于比較兩方陣所有對應元素值,如果完全相同返回真(True),否則返回假(False)
True
以下計算奇異陣(行列式為0)的逆,其結果將會報錯(LinAlgError),示例代碼:
>>>arr = np.array([[3, 2], [6, 4]])
>>>linalg.inv(arr)
Traceback (most recent call last):
...
...LinAlgError: singular matrix
scipy.linalg.norm()函數計算方陣的范數,示例代碼:
>>>A = np.matrix(np.random.random((2, 2)))
>>>A >>>linalg.norm(A) #默認2范數
>>>linalg.norm(A, 1) #1范數
>>>linalg.norm(A, np.inf) #無窮范數
(2)解線性方程組
在一些矩陣公式中經常會出現類似于A-1B的運算,它們都可以用solve(A, B)計算,這要比直接逆矩陣然后做矩陣乘法更快捷一些,下面的程序比較solve()和逆矩陣的運算速度,示例代碼:
>>> import numpy as np
>>> from scipy import linalg
>>> m, n = 500, 50
>>> A = np.random.rand(m, m)
>>> B = np.random.rand(m, n)
>>> X1 = linalg.solve(A, B)
>>> X2 = np.dot(linalg.inv(A), B)
>>> print(np.allclose(X1, X2))
>>> %timeit linalg.solve(A, B) 13.3 ms ± 834 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)
>>> %timeit np.dot(linalg.inv(A), B) 22.4 ms ± 1.48 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
(3) 特征值和特征向量
下面以二維平面上的線性變換矩陣為例,演示特征值和特征向量的幾何含義。通過linalg.eig(A)計算矩陣A的兩個特征值evalues和特征向量evectors,在evectors中,每一列是一個特征向量。示例代碼:
>>> A = np.array([[1, -0.3], [-0.1, 0.9]])
>>> evalues, evectors = linalg.eig(A)
2.2 擬合與求解optimize模塊
(1)擬合 curve_fit()函數
以下示例中,我們首先從已知函數中生成一些帶有噪聲的數據,然后使用curve_fit()函數擬合這些噪聲數據。示例中的已知函數我們使用一個簡單的線性方程式,即f(x)=ax+b。示例代碼:
import numpy as np from scipy.optimize
import curve_fit
import matplotlib.pyplot as plt
#創建函數模型用來生成數據
def func(x, a, b): return a*x + b #生成干凈數據
x = np.linspace(0, 10, 100)
y = func(x, 1, 2) #對原始數據添加噪聲
yn = y + 0.9 * np.random.normal(size=len(x))
#使用curve_fit函數擬合噪聲數據
popt, pcov = curve_fit(func, x, yn) #輸出給定函數模型func的最優參數
print(popt)
結果為:
[ 0.99734363 1.96064258]
如果有一個很好的擬合效果,popt返回的是給定模型的最優參數。我們可以使用pcov的值檢測擬合的質量,其對角線元素值代表著每個參數的方差。
>>>print(pcov)
[[ 0.00105056 -0.00525282]
[-0.00525282 0.03519569]]
通過以下代碼繪制出了擬合曲線與實際曲線的差異,示例代碼:
yfit = func(x,popt[0],popt[1])
plt.plot(x, y, color="green",label = "actual data")
plt.plot(x, yn, "o", label = "actual data with noise")
plt.plot(x, yfit,color="yellow", label = "fitting data")
plt.legend(loc = "best")
plt.show()
下面做進一步研究,我們可以通過最小二乘擬合高斯分布(Gaussian profile),一種非線性函數:α*exp(-(x-μ)2/2σ2)
在這里,α表示一個標量,μ是期望值,而σ是標準差。示例代碼:
import numpy as np from scipy.optimize
import curve_fit
import matplotlib.pyplot as plt
#創建一個函數模型用來生成數據
def func(x, a, b, c): return (a*np.exp(-(x-b)**2/2*c**2))
#生成原始數據
x = np.linspace(0, 10, 100)
y = func(x, 1, 5, 2)
#對原始數據增加噪聲 yn = y + 0.2*np.random.normal(size=len(x))
#使用curve_fit函數擬合噪聲數據 popt, pcov = curve_fit(func, x, yn)
#popt返回最擬合給定的函數模型func的參數值,如popt[0]=a,popt[1]=b,popt[2]=3
print(popt)
結果為:
[-0.49627942 2.78765808 28.76127826]
通過以下代碼繪制出了擬合曲線與實際曲線的差異,示例代碼:
p0=[1.2,4,3] #初步猜測參數,如果沒有,默認全為1,即[1,1,1]
popt, pcov = curve_fit(func, x, yn,p0=p0)
#popt返回最擬合給定的函數模型func的參數值,如popt[0]=a,popt[1]=b,popt[2]=3 print(popt)
yfit = func(x,popt[0],popt[1],popt[2])
plt.plot(x, y, color="green",label = "actual data")
plt.plot(x, yn, "o", label = "actual data with noise")
plt.plot(x, yfit, color="yellow", label = "fitting data")
plt.legend(loc = "best")
plt.show()
結果如下圖所示:

隨著研究的深入,我們可以擬合一個多重高斯分布的一維數據集。現在將這個函數擴展為包含兩個不同輸入值的高斯分布函數。這是一個擬合線性光譜的經典實例,示例代碼如下:
import numpy as np from scipy.optimize
import curve_fit
import matplotlib.pyplot as plt
def func(x, a0, b0, c0, a1, b1, c1):
return a0*np.exp(-(x - b0) ** 2/(2 * c0 ** 2)) + a1 * np.exp(-(x-b1) ** 2/(2 * c1 ** 2))
#生成原始數據
x = np.linspace(0, 20, 200)
y = func(x, 1, 3, 1, -2, 15, 0.5)
#對原始數據增加噪聲
yn = y + 0.9 * np.random.normal(size=len(x))
#如果要擬合一個更加復雜的函數,提供一些估值假設對擬合效果更好
guesses = [1, 3, 1, 1, 15, 1]
#使用curve_fit函數擬合噪聲數據
popt, pcov = curve_fit(func, x, yn, p0=guesses)
#popt返回最擬合給定的函數模型func的參數值,如popt[0]=a,popt[1]=b,popt[2]=3
print(popt) yfit = func(x,popt[0],popt[1],popt[2],popt[3],popt[4],popt[5]) plt.plot(x, y, color="green",label = "actual data") plt.plot(x, yn, "o", label = "actual data with noise") plt.plot(x, yfit, color="yellow", label = "fitting data") plt.legend(loc = "best") plt.show()
結果如下圖所示:


import matplotlib.pylab as plt
import numpy as np from scipy
import optimize # 從scipy庫引入optimize模塊 X = np.array([ 8.19, 2.72, 6.39, 8.71, 4.7, 2.66, 3.78 ])
Y = np.array([ 7.01, 2.78, 6.47, 6.71, 4.1, 4.23, 4.05 ])
def residuals(p): #計算以p為參數的直線和原始數據之間的誤差
k, b = p
return Y-(k*X+b)
# leastsq()使得residuals()的輸出數組的平方和最小,參數的初始值為[1, 0]
r = optimize.leastsq(residuals, [1,0])
k, b = r[0] print("k=", k, "b=", b)
結果為:
k = 0.613495349193 b = 1.79409254326
可以通過通過繪圖對比真實數據和擬合數據的誤差,示例代碼;
plt.plot(X, Y, "o", label = "actual data")
plt.plot(X, k*X+b, label = "fitting data")
plt.legend(loc = "best")
plt.show()
結果為:
繪圖中的圓點表示真實數據點,實線表示擬合曲線,由此看出擬合參數得到的函數和真實數據大體一致。接下來,用leastsq()對正弦波數據進行擬合,示例代碼:
import numpy as np from scipy.optimize
import leastsq # 從scipy庫的optimize模塊引入leastsq函數
import matplotlib.pyplot as plt # 引入繪圖模塊pylab,并重命名為pl
def func(x, p):
""" 數據擬合所用的函數: A*sin(2*pi*k*x + theta) """
A, k, theta = p
return A*np.sin(2*np.pi*k*x+theta) def residuals(p, y, x):
""" 實驗數據x, y和擬合函數之間的差,p為擬合需要找到的系數 """
return y - func(x, p)
x = np.linspace(0, -2*np.pi, 100)
A, k, theta = 10, 0.34, np.pi/6
# 真實數據的函數參數 y0 = func(x, [A, k, theta])
# 真實數據 y1 = y0 + 2 * np.random.randn(len(x))
# 加入噪聲之后的實驗數據,噪聲是服從標準正態分布的隨機量
p0 = [7, 0.2, 0]
# 第一次猜測的函數擬合參數
# 調用leastsq進行數據擬合
# residuals為計算誤差的函數
# p0為擬合參數的初始值 # args為需要擬合的實驗數據
plsq = leastsq(residuals, p0, args=(y1, x))
print ("actual parameter:", [A, k, theta])
# 真實參數
print ("fitting parameter", plsq[0])
# 實驗數據擬合后的參數
plt.plot(x, y0, label="actual data")
# 繪制真實數據
plt.plot(x, y1, label="experimental data with noise")
# 帶噪聲的實驗數據
plt.plot(x, func(x, plsq[0]), label="fitting data")
# 擬合數據 plt.legend()
plt.show()
>>>actual parameter: [10, 0.34, 0.5235987755982988]
>>>fitting parameter [ 10.12646889 0.33767587 0.48944317]
(3)標量函數極值求解fmin()函數
首先定義以下函數,然后繪制它,示例代碼:
import numpy as np from scipy
import optimize import matplotlib.pyplot as plt
def f(x): return x**2 + 10*np.sin(x)
x = np.arange(-10, 10, 0.1)
plt.plot(x, f(x))
plt.show()
結果如下圖所示:

>>> optimize.fmin_bfgs(f, 0)
Optimization terminated successfully. Current function value: -7.945823 Iterations: 5 Function evaluations: 24 Gradient evaluations: 8 array([-1.30644003])
這個方法一個可能的問題在于,如果函數有局部最小值,算法會因初始點不同找到這些局部最小而不是全局最小,示例代碼:
>>> optimize.fmin_bfgs(f, 3, disp=0)#disp是布爾型數據,如果為1,打印收斂消息
array([ 3.83746663])
如果我們不知道全局最小值的鄰近值來選定初始點,我們需要借助于耗費資源些的全局優化。為了找到全局最小點,最簡單的算法是蠻力算法,該算法求出給定格點的每個函數值。示例代碼:
>>>grid = (-10, 10, 0.1)
>>>xmin_global = optimize.brute(f, (grid, ))
>>>xmin_global
array([-1.30641113])
>>> xmin_local = optimize.fminbound(f, 0, 10)
>>> xmin_local 3.8374671...
下面的程序通過求解卷積的逆運算演示fmin的功能。對于一個離散線性時不變系統h, 如果輸入是x,那么其輸出y可以用x和h的卷積表示:

import scipy.optimize as opt
import numpy as np
def test_fmin_convolve(fminfunc, x, h, y, yn, x0): """ x (*) h = y, (*)表示卷積 yn為在y的基礎上添加一些干擾噪聲的結果 x0為求解x的初始值 """ def convolve_func(h): """ 計算 yn - x (*) h 的power fmin將通過計算使得此power最小 """
return np.sum((yn - np.convolve(x, h))**2)
# 調用fmin函數,以x0為初始值
h0 = fminfunc(convolve_func, x0)
print fminfunc.__name__
print "---------------------"
# 輸出 x (*) h0 和 y 之間的相對誤差
print "error of y:", np.sum((np.convolve(x, h0)-y)**2)/np.sum(y**2)
# 輸出 h0 和 h 之間的相對誤差
print "error of h:", np.sum((h0-h)**2)/np.sum(h**2)
print def test_n(m, n, nscale): """ 隨機產生x, h, y, yn, x0等數列,調用各種fmin函數求解b
m為x的長度, n為h的長度, nscale為干擾的強度 """ x = np.random.rand(m) h = np.random.rand(n) y = np.convolve(x, h) yn = y + np.random.rand(len(y)) * nscale x0 = np.random.rand(n) test_fmin_convolve(opt.fmin, x, h, y, yn, x0) test_fmin_convolve(opt.fmin_powell, x, h, y, yn, x0) test_fmin_convolve(opt.fmin_cg, x, h, y, yn, x0) test_fmin_convolve(opt.fmin_bfgs, x, h, y, yn, x0) test_n(200, 20, 0.1)
運行結果為:
import scipy.optimize as opt
import numpy as np
def test_fmin_convolve(fminfunc, x, h, y, yn, x0): """ x (*) h = y, (*)表示卷積 yn為在y的基礎上添加一些干擾噪聲的結果 x0為求解x的初始值 """
def convolve_func(h): """ 計算 yn - x (*) h 的power fmin將通過計算使得此power最小 """
return np.sum((yn - np.convolve(x, h))**2)
# 調用fmin函數,以x0為初始值
h0 = fminfunc(convolve_func, x0)
print fminfunc.__name__
print "---------------------"
# 輸出 x (*) h0 和 y 之間的相對誤差
print "error of y:", np.sum((np.convolve(x, h0)-y)**2)/np.sum(y**2)
# 輸出 h0 和 h 之間的相對誤差
print "error of h:", np.sum((h0-h)**2)/np.sum(h**2)
print def test_n(m, n, nscale): """ 隨機產生x, h, y, yn, x0等數列,調用各種fmin函數求解b m為x的長度, n為h的長度, nscale為干擾的強度 """ x = np.random.rand(m) h = np.random.rand(n) y = np.convolve(x, h) yn = y + np.random.rand(len(y)) * nscale x0 = np.random.rand(n) test_fmin_convolve(opt.fmin, x, h, y, yn, x0) test_fmin_convolve(opt.fmin_powell, x, h, y, yn, x0) test_fmin_convolve(opt.fmin_cg, x, h, y, yn, x0) test_fmin_convolve(opt.fmin_bfgs, x, h, y, yn, x0) test_n(200, 20, 0.1)
(4)函數求解fsolve()
- func是用于定義需求解的非線性方程組的函數文件名
- x0為未知數矢量的初始值。
import matplotlib.pyplot as plt
from scipy.optimize import fsolve
import numpy as np
line = lambda x:x+3 solution = fsolve(line, -2) print(solution)
結果為:
[-3,]
通過以下繪圖函數可以看出當函數等于0時,x軸的坐標值為-3,示例代碼:
x = np.linspace(-5.0, 0, 100)
plt.plot(x,line(x), color="green",label = "function")
plt.plot(solution,line(solution), "o", label = "root")
plt.legend(loc = "best")
plt.show()
結果為:
下面我們通過一個簡單的示例介紹一下兩個方程交點的求解方法,示例代碼:
from scipy.optimize
import fsolve
import numpy as np import matplotlib.pyplot as plt
# 定義解函數
def findIntersection(func1, func2, x0):
return fsolve(lambda x: func1(x)-func2(x),x0)
# 定義兩方程 funky = lambda x : np.cos(x / 5) * np.sin(x / 2)
line = lambda x : 0.01 * x - 0.5
# 定義兩方程交點的取值范圍
x = np.linspace(0, 45, 1000)
result = findIntersection(funky, line, [15, 20, 30, 35, 40, 45])
# 輸出結果 print(result, line(result))
plt.plot(x,funky(x), color="green",label = "funky func")
plt.plot(x,line(x), color="yellow",label = "line func")
plt.plot(result,line(result), "o", label = "intersection")
plt.legend(loc = "best")
plt.show()
結果為:

如果要對如下方程組進行求解的話:
- f1(u1,u2,u3) = 0
- f2(u1,u2,u3) = 0
- f3(u1,u2,u3) = 0
def func(x):
u1,u2,u3 = x return [f1(u1,u2,u3), f2(u1,u2,u3), f3(u1,u2,u3)]
下面是一個實際的例子,求解如下方程組的解:
- 5*x1 + 3 = 0
- 4*x0*x0 - 2*sin(x1*x2) = 0
- x1*x2 - 1.5 = 0
from scipy.optimize import fsolve from math import sin,cos def f(x):
x0 = float(x[0])
x1 = float(x[1])
x2 = float(x[2]) return [ 5*x1+3, 4*x0*x0 - 2*sin(x1*x2),
x1*x2 - 1.5 ]
result = fsolve(f, [1,1,1]) print (result)
結果為:
[-0.70622057 -0.6 -2.5 ]
2.3 插值interpolate模塊
計算插值有兩種基本的方法,1、對一個完整的數據集去擬合一個函數;2、對數據集的不同部分擬合出不同的函數,而函數之間的曲線平滑對接。第二種方法又叫做仿樣內插法,當數據擬合函數形式非常復雜時,這是一種非常強大的工具。我們首先介紹怎樣對簡單函數進行一維插值運算,然后進一步深入比較復雜的多維插值運算。
interp1d(x, y, kind='linear', ...)
其中,x和y參數是一系列已知的數據點,kind參數是插值類型,可以是字符串或整數,它給出插值的B樣條曲線的階數,候選值及作用下表所示:
候選值 | 作用 |
‘zero’ 、'nearest' | 階梯插值,相當于0階B樣條曲線 |
‘slinear’ 、'linear' | 線性插值,用一條直線連接所有的取樣點,相當于一階B樣條曲線 |
‘quadratic’ 、'cubic' | 二階和三階B樣條曲線,更高階的曲線可以直接使用整數值指定 |
import numpy as np from scipy.interpolate
import interp1d import matplotlib.pyplot as plt
#創建待插值的數據 x = np.linspace(0, 10*np.pi, 20)
y = np.cos(x)
# 分別用linear和quadratic插值
fl = interp1d(x, y, kind='linear')
fq = interp1d(x, y, kind='quadratic')
#設置x的最大值和最小值以防止插值數據越界
xint = np.linspace(x.min(), x.max(), 1000)
yintl = fl(xint)
yintq = fq(xint)
plt.plot(xint,fl(xint), color="green", label = "Linear")
plt.plot(xint,fq(xint), color="yellow", label ="Quadratic")
plt.legend(loc = "best")
plt.show()
結果如下圖所示:

(2)噪聲數據插值
import numpy as np from scipy.interpolate
import UnivariateSpline import matplotlib.pyplot as plt
# 通過人工方式添加噪聲數據
sample = 30 x = np.linspace(1, 10*np.pi, sample)
y = np.cos(x) + np.log10(x) + np.random.randn(sample)/10
# 插值,參數s為smoothing factor
f = UnivariateSpline(x, y, s=1)
xint = np.linspace(x.min(), x.max(), 1000)
yint = f(xint)
plt.plot(xint,f(xint), color="green", label = "Interpolation")
plt.plot(x, y, color="yellow", label ="Original")
plt.legend(loc = "best")
plt.show()
需要說明的是:在UnivariateSpline()函數中,參數s是平滑向量參數,被用來擬合還有噪聲的數據。如果參數s=0,將忽略噪聲對所有點進行插值運算。結果如下圖所示:
griddata(points, values, xi, method='linear', fill_value=nan)
import numpy as np from scipy.interpolate
import griddata#定義一個函數
def ripple(x,y):
return np.sqrt(x**2 + y**2) + np.sin(x**2 + y**2)
# 生成grid數據,復數定義了生成grid數據的step,若無該復數則step為5
grid_x, grid_y = np.mgrid[0:5:1000j, 0:5:1000j]
# 生成待插值的樣本數據 points = np.random.rand(1000,2)
value = ripple(points[:,0]*5,points[:,1]*5)
# 用nearest方法插值
grid_z0 = griddata(points*5,value, (grid_x,grid_y),method='nearest')
我們還可以使用interpolate模塊的SmoothBivariateSpline類進行多元仿樣插值運算,對圖片進行重構。示例代碼:
import numpy as np from scipy.interpolate
import SmoothBivariateSpline as SBS #定義一個函數
def ripple(x,y):
return np.sqrt(x**2 + y**2) + np.sin(x**2 + y**2)
# 生成grid數據,復數定義了生成grid數據的step,若無該復數則step為5
grid_x, grid_y = np.mgrid[0:5:1000j, 0:5:1000j]
# 生成待插值的樣本數據 points = np.random.rand(1000,2)
value = ripple(points[:,0]*5,points[:,1]*5)
# 用nearest方法插值
fit = SBS(points[:,0]*5, points[:,1]*5, value, s=0.01, kx=4, ky=4)
interp = fit(np.linspace(0, 5, 1000), np.linspace(0, 5, 1000))
通過反復測試,盡管SmoothBivariateSpline表現略好,但其對給定的樣本數據非常敏感,就可能導致忽略一些顯著特征。而griddata函數有很強的魯棒性,不管給定的數據樣本,能夠合理的進行插值運算。
NumPy庫已經提供了一些基本的統計函數,如求期望、方差、中位數、最大值和最小值等。示例代碼:
import numpy as np
#構建一個1000個隨機變量的數組
x = np.random.randn(1000)
#對數組元素的值進行統計 mean = x.mean()
std = x.std()
var = x.var() print(mean,std,var)
結果為:
(0.02877273942510088, 0.97623362287515114, 0.95303208643194282)
SciPy的stats模塊提供了大約80種連續隨機變量和10多種離散分布變量,這些分布都依賴于numpy.random函數。可以通過如下語句獲得stats模塊中所有的連續隨機變量,示例代碼:
from scipy import stats
[k for k, v in stats.__dict__.items() if isinstance(v, stats.rv_continuous)]
運行結果為:
['ksone', 'kstwobign', 'norm', 'alpha', 'anglit', 'arcsine', 'beta', 'betaprime',
'bradford', 'burr', 'burr12', 'fisk', 'cauchy', 'chi', 'chi2', 'cosine', 'dgamma',
'dweibull', 'expon', 'exponnorm', 'exponweib', 'exponpow', 'fatiguelife', 'foldcauchy',
'f', 'foldnorm', 'frechet_r', 'weibull_min', 'frechet_l', 'weibull_max', 'genlogistic',
'genpareto', 'genexpon', 'genextreme', 'gamma', 'erlang', 'gengamma', 'genhalflogistic',
'gompertz', 'gumbel_r', 'gumbel_l', 'halfcauchy', 'halflogistic', 'halfnorm', 'hypsecant',
'gausshyper', 'invgamma', 'invgauss', 'invweibull', 'johnsonsb', 'johnsonsu', 'laplace',
'levy', 'levy_l', 'levy_stable', 'logistic', 'loggamma', 'loglaplace', 'lognorm', 'gilbrat',
'maxwell', 'mielke', 'kappa4', 'kappa3', 'nakagami', 'ncx2', 'ncf', 't', 'nct', 'pareto', 'lomax',
'pearson3', 'powerlaw', 'powerlognorm', 'powernorm', 'rdist', 'rayleigh', 'reciprocal', 'rice'
, 'recipinvgauss', 'semicircular', 'skewnorm', 'trapz', 'triang', 'truncexpon', 'truncnorm',
'tukeylambda', 'uniform', 'vonmises', 'vonmises_line', 'wald', 'wrapcauchy', 'gennorm', 'halfgennorm']
連續隨機變量對象主要使用如下方法,下表所示:
方法名 | 全稱 | 功能 |
rvs | Random Variates of given type | 對隨機變量進行隨機取值,通過size參數指定輸出數組的大小 |
Probability Density Function | 隨機變量的概率密度函數 | |
cdf | Cumulative Distribution Function | 隨機變量的累積分布函數,它是概率密度函數的積分 |
sf | Survival function | 隨機變量的生存函數,它的值是1-cdf(t) |
ppf | Percent point function | 累積分布函數的反函數 |
stats | statistics | 計算隨機變量的期望值和方差 |
fit | fit | 對一組隨機取樣進行擬合,找出最適合取樣數據的概率密度函數的系數 |
from scipy import stats
# 設置正態分布參數,其中loc是期望值參數,scale是標準差參數
X = stats.norm(loc=1.0, scale=2.0)
# 計算隨機變量的期望值和方差 print(X.stats())
結果為:
(array(1.0), array(4.0))
此外,通過調用隨機變量X的rvs()方法,可以得到包含一萬次隨機取樣值的數組x,然后調用NumPy的mean()和var()計算此數組的均值和方差,其結果符合隨機變量X的特性,示例代碼:
#對隨機變量取10000個值
x = X.rvs(size=10000) print(np.mean(x), np.var(x))
結果為:
(1.0287787687588861, 3.9944276709242805)
使用fit()方法對隨機取樣序列x進行擬合,它返回的是與隨機取樣值最吻合的隨機變量參數,示例代碼:
#輸出隨機序列的期望值和標準差
print(stats.norm.fit(x))
結果為:
(1.0287787687588861, 1.998606432223283)
在下面的例子中,計算取樣值x的直方圖統計以及累計分布,并與隨機變量的概率密度函數和累積分布函數進行比較。示例代碼:
pdf, t = np.histogram(x, bins=100, normed=True)
t = (t[:-1]+t[1:])*0.5 cdf = np.cumsum(pdf) * (t[1] - t[0])
p_error = pdf - X.pdf(t)
c_error = cdf - X.cdf(t)
print("max pdf error: {}, max cdf error: {}".format(np.abs(p_error).max(), np.abs(c_error).max()))
運行結果如下所示:
max pdf error: 0.0208405611169, max cdf error: 0.0126874590568
通過繪圖的方式查看概率密度函數求得的理論值(theory value)和直方圖統計值(statistic value),可以看出二者是一致的,示例代碼:
import pylab as pl
pl.plot(t, pdf, color="green", label = "statistic value")
pl.plot(t, X.pdf(t), color="yellow", label ="theory value")
pl.legend(loc = "best")
pl.show()
結果見下圖所示:
也可以用同樣的方式顯示隨機變量X的累積分布和數組pdf的累加結果,示例代碼:
pl.plot(t, cdf, color="green", label = "statistic value")
pl.plot(t, X.cdf(t), color="yellow", label ="theory value")
pl.legend(loc = "best")
pl.show()
結果為:
p = (0.4, 0.2, 0.1, 0.1, 0.1, 0.1)
# 創建表示這個骰子的隨機變量dice,調用其rvs()方法投擲此骰子20次,獲得符合概率p的隨機數
dice = stats.rv_discrete(values=(x, p))
print(dice.rvs(size=20))
運行結果:
array([3, 6, 4, 5, 5, 2, 1, 3, 3, 1, 1, 3, 1, 5, 1, 3, 4, 1, 2, 2])
除了自定義離散概率分布,我們也可以利用stats模塊里的函數定義各種分布。下面以生成幾何分布為例,其函數是geom(),示例代碼:
import numpy as np from scipy.stats
cdf = dist.cdf(x)
# 生成500個隨機數
sample = dist.rvs(500)
(3)描述與檢驗函數
import numpy as np from scipy
import stats
# 生成包括100個服從正態分布的隨機數樣本
sample = np.random.randn(100)
# 用normaltest檢驗原假設
out = stats.normaltest(sample)
print('normaltest output')
print('Z-score = ' + str(out[0]))
print('P-value = ' + str(out[1]))
# kstest 是檢驗擬合度的Kolmogorov-Smirnov檢驗,這里針對正態分布進行檢驗 # D是KS統計量的值,越接近0越好
out = stats.kstest(sample, 'norm')
print('\nkstest output for the Normal distribution')
print('D = ' + str(out[0]))
print('P-value = ' + str(out[1]))
# 類似地可以針對其他分布進行檢驗,例如Wald分布
out = stats.kstest(sample, 'wald')
print('\nkstest output for the Wald distribution')
print('D = ' + str(out[0]))
print('P-value = ' + str(out[1]))
SciPy的stats模塊中還提供了一些描述函數,如幾何平均(gmean)、偏度(skew)、樣本頻數(itemfreq)等。
示例代碼
import stats # 生成包括100個服從正態分布的隨機數樣本
out = stats.hmean(sample[sample > 0])
print('Harmonic mean = ' + str(out))
out = stats.tmean(sample, limits=(-1, 1)) print('\nTrimmed mean = ' + str(out))
# 計算樣本偏度 out = stats.skew(sample) print('\nSkewness = ' + str(out))
print('\nSize = ' + str(out[0]))
print('Min = ' + str(out[1][0]))
print('Max = ' + str(out[1][1]))
print('Mean = ' + str(out[2]))
print('Variance = ' + str(out[3]))
print('Skewness = ' + str(out[4]))
print('Kurtosis = ' + str(out[5]))