簡介
NumPy(Numerical Python)是一個開源Python科學計算庫,是Python生態圈最重要的底層支持庫,支持快速的數組運算,比純Python代碼快得多,因爲它底層使用到c來寫。NumPy是在Python中進行數據分析、機器學習、人工智能開發的必備工具,是理解學習很多Python工具包的基礎。
安裝 : pip install numpy # Anaconda已包含np,無需安裝。
numpy數組和 list列表運算時間對比示例
import numpy as np # 引入慣例, 後續都用 np
lst = list(range(1000000)) # 列表
ar = np.arange(1000000) # np數組
In: %timeit lst2 = [x*2 for x in lst]
80.8 ms ± 438 µs per loop # 列表耗時
In: %timeit ar2 = ar * 2
1.96 ms ± 34.7 µs per loop # np數組耗時
注:%魔術命令只能在IPython對話窗口運行,不能放入.py程序中。
數組對象特性
x = np.array((90, 85, 80)) # 成績
w = np.array((0.4, 0.4, 0.2)) # 權重
np.mean(x) #求平均值
np.average(x, weights=w) # 按權重求均值
np.sum(x * w) / np.sum(w) # 自行按權重求均值,(x*w)會對應的元素相乘
In: b = np.array((10, 9.5, 10.2, 11, 10.8, 10.6, 11.2)) # 收盤價
In: np.diff(b) # 差值, 也可寫爲 b[1:] - b[:-1] ,這樣寫就是後面一個元素減去前面一個元素
Out: array([-0.5, 0.7, 0.8, -0.2, -0.2, 0.6])
In: ret = np.diff(b) / b[:-1] # 漲跌率
Out: array([-0.05, 0.07, 0.08, -0.02, -0.02, 0.06])
In: np.where(ret>0) # 正收益是哪幾天
Out:(array([1, 2, 5], dtype=int64),)
In: np.__version__ # 版本號'1.16.5',一般的軟件包都有
# arange產生6個數,reshape重設爲 2x3 數組
In: b = np.arange(6).reshape(2, 3)
In: type(b) # numpy.ndarray
# 數組對象的各種特性
In: b.ndim # 數組維度 2
In: b.size # 數組中的元素個數 6, 和len(b) 不同,len(b)顯示的是數組行數
In: b.shape # 數組形狀 (2, 3)
In: b.dtype # 數組元素的數據類型 dtype('int32')
In: b.itemsize # 單個元素所需存儲字節數 4
In: b.nbytes # 整個數組所需存儲字節數 24 , 即 size * itemsize
生成數組的五種方法
#使用array()/arange()生成數組
In:b = np.array((1, 2, 3, 4)) # 一維
Out: array([1, 2, 3, 4])
In:b = np.arange(1, 5) # np.arange(1,5,0.5) 小數步長
Out: array([1, 2, 3, 4])
In: np.repeat(b,2) # 將元素重複2次
Out:array([1, 1, 2, 2, 3, 3, 4, 4])
In: np.tile(b, 3) # 將數組重複3次
Out: array([1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4])
In:b = np.array([[1, 2] , [3, 4], [5, 6]]) # 二維
In:b=np.arange(4000).reshape(4, 1000) # 二維
#可以使用ones()/zeros()/linspace()生成數組。
np.ones(5) # 生成含有5個元素的一維全1數組
np.ones((2, 3)) # 生成2x3的二維全1數組
np.zeros((2, 3)) # 生成2x3的二維全0數組
np.ones_like(b) # 生成維數和b相同的全1數組
np.eye(3) # 單位矩陣數組
np.linspace(1, 2, 5) # [1, 2] 間均勻分佈5個數
Out: array([1. , 1.25, 1.5 , 1.75, 2. ]) # 默認含終值
np.linspace(1, 2, 5, endpoint=False) # 不含終值
Out:array([1. , 1.2, 1.4, 1.6, 1.8])
x = np.linspace(0, np.pi, 7) # [0, π] 間均勻分佈7個數, 即間隔 30度
np.sin(x) # np.round(np.sin(x), 2)
#使用隨機函數生成數組。
ar = np.random.rand(3,4) # 3x4數組, [0, 1)內均勻分佈小數
np.set_printoptions(precision=3) # 小數部分顯示3位
np.random.randint(1,100,5) # [1,100)內5個隨機整數
np.random.randint(1,100,(2,3)) # 2x3 數組
np.random.randn(10,20) # 10x20的標準正太 N(0,1)數組
# 符合正太分佈N(1, 4) 的 3x4 數組
x = np.random.normal(loc=1, scale=2, size=(3, 4))
x.std() , x.var() , x.mean() # 標準差, 方差, 均值
NumPy的常用數據類型
在創建數組時可以用dtype參數指定數據類型。已有的數組可以用astype()方法轉換類型。數組元素的類型一般應相同,列表的元素類型允許不同。
In:b=np.arange(5) # 默認 'int32' 類型
In: b.dtype
Out: dtype('int32')
In: b[0] = 2**40 # 將報錯,整數超範圍
In:b=np.arange(5, dtype='float') # 指定爲 'float'
In: b.dtype
Out: dtype('float64')
In: c=b.astype('int') # 轉爲int,b不變,得到新的c
In: c.dtype
Out: dtype('int32')
In: c.astype('bool') # 轉爲bool型,非0對應True
Out: array([False, True, True, True, True])
存取數組元素
基本索引和切片操作
np數組可按類似列表訪問的語法,單個索引或切片訪問。
b=np.arange(5,10) # array([5,6,7,8,9])
b[1], b[-1], b[:2], b[1:3] # (6, 9, array([5, 6]), array([6, 7]))
b[[0,1,3]] # 花式索引 array([5,6,8]), 這裏的索引結果是複製
重要:數組切片和列表切片不同,前者是視圖,後者是複製。
b=np.arange(5,10) # array([5,6,7,8,9])
c=b[0:3] # 產生視圖,b,c指向同一內存塊
c[0]=100 # 此修改將同時影響 b 和 c
c # array([100,6,7])
b # array([100,6,7,8,9])
c = b[0:3].copy() # 複製數組,這樣 b, c分離,不會再互相影響
二維數組
b=np.arange(12).reshape(3,4)
Out:array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
b[1, 2] # 6,也可寫爲 b[1][2]
b[1, 1:3] # array([5,6])
b[1] # array([4,5,6,7])
b[:,1] # array([1,5,9])
b[1:3, 1:4] # array([5,6,7],
[9,10,11])
b[ [0,1,2], [3,2,1] ] # array([3, 6, 9]), 將行/列座標分別排列,花式索引,花式索引是複製操作
布爾索引
篩選出True值對應位置的數據。
np.random.seed(7)
b = np.random.randint(40, 100, size=10) # 生成10個的隨機整數
Out: array([87, 44, 65, 94, 43, 59, 63, 79, 68, 97])
c = b < 60 # 生成一個布爾數組c
Out: array([False, True, False, False, True, True, False, False, False, False])
b[c] # 利用布爾索引取數據,得到<60的數據
Out: array([44, 43, 59])
b[(b>=60) & (b<=80)] # 顯示60~80間的數據, 此處用&, 不能用and
b[(b<60) | (b>90)] # 顯示<60 或 >90的數據,此處用|, 不能用or
b[~(b<60)] # ~非, 顯示 >=60的數據
b=np.array((60, 70, 75, 90, 68, 89)) # 成績
c=np.array((1 , 1 , 1, 2 , 2, 2)) # 班級
b[c==1].mean() # 1班平均成績
x=np.array((70, 75, 92, 68, 89)) # 評分1
y=np.array((75, 69, 93, 70, 85)) # 評分2
np.where(x>y, x, y) # 取x/y兩兩比較的較大值
#where函數是當x>y時取x,不然取y,作用效果和np.maximum(x,y)一樣
np.where(x>y, 1, 0) # x>y則取1, 否則取0
數組運算
數組和單個數據的運算
數組和單個數據可直接運算,不需要編寫循環程序處理。
b=np.arange(5) # array([0, 1, 2, 3, 4])
b+2 # array([2, 3, 4, 5, 6])
數組和數組的運算
- 數組形狀相同時的運算
兩個數組形狀(shape)相同時,各位置上的元素對位運算。
a1=np.arange(5) # array([0, 1, 2, 3, 4])
a2=np.arange(5,10) # array([5, 6, 7, 8, 9])
a1+a2 # array([5, 7, 9, 11, 13])
- 數組形狀不同時的廣播運算
當兩個數組形狀(shape)不同時,如果能按廣播規則擴展爲同形狀的數組,則可以運算,如不符合廣播規則就不能運算。
a1=np.arange(4) # 一維 (4,) array([0, 1, 2, 3])
a2=np.arange(12).reshape(3,4) # 二維(3,4)
a1+a2
array([[ 0, 2, 4, 6],
[ 4, 6, 8, 10],
[ 8, 10, 12, 14]])
上例中的a1是一維數組(4,),a2是3x4的二維數組,兩者的維數不同。
a1的維數較小,NumPy在a1的維數前面加1補齊,可近似認爲a1的維數變爲(1,4)。
現在a1的第0維是1,a2的第0維是3,NumPy將把a1的第0維擴充爲3,
相當於將a1的維數變爲(3,4),可認爲a1在內存中被調整爲如下形狀:
array([[0, 1, 2, 3],
[0, 1, 2, 3],
[0, 1, 2, 3]]
這樣,a1和a2的形狀一致,就可以完成 a1+a2的運算。
廣播規則
- 參加運算的數組都向維數最大的數組看齊,維數較小的數組在前面加1補齊。
- 結果數組的形狀(shape)取各運算數組的各個軸上的最大值。
- 若運算數組的某個軸的長度爲1,則該軸可擴充爲結果數組的對應軸的長度。若軸的長度不爲1,則不能擴充。
- 檢查擴充後所有運算數組對應的軸的長度。若長度都相同則符合規則可以計算,否則違反規則無法計算。
a1=np.array((1,2,3)) a2=np.array((3,4)).reshape(2,1)
形狀爲(3,) 和2x1的兩個數組可運算,結果數組形狀爲2x3。
先是(1,3)和(2,1),然後變成(2,3)和(2,3)
形狀爲3x1 和1x2的兩個數組可運算,結果數組形狀爲3x2。
形狀爲2x3 和3x2的兩個數組不滿足規則,無法計算。2x3和4x3的數組也無法廣播計算。
結果數組是(3,3),但是(2,3)和(3,2)都無法變成(3,3)
數組排序
數組自帶sort()排序方法,按從小到大排列。
np.random.seed(7)
b=np.random.randint(1, 20, size=10)
Out: array([16, 5, 4, 8, 15, 9, 15, 11, 9, 8])
c=b.copy() # 備份
b.sort() # 排序後將改變數組b
b=c.copy() # 從備份中恢復b
np.sort(b) # np.sort不改變數組本身,返回新的有序數組
x=np.argsort(b) # 將返回一個代表原數據順序的有序下標數組
Out: array([2, 1, 3, 9, 5, 8, 7, 4, 6, 0], dtype=int64)
b[x] # array([ 4, 5, 8, 8, 9, 9, 11, 15, 15, 16]),花式索引
數組排序不支持列表的reverse=True參數,要從大到小排如下所示:
b[np.argsort(-b)] # 注意 -b
Out: array([16, 15, 15, 11, 9, 9, 8, 8, 5, 4])
多維數組排序
多維數組排序時可指定 axis=0(列) / 1(行),排序時默認按最大軸排序。
np.random.seed(7)
b=np.random.randint(1, 50, size=15).reshape(3, 5)
Out:array([[48, 5, 26, 4, 20],
[24, 40, 29, 15, 24],
[ 9, 26, 47, 43, 27]])
np.sort(b) # 默認按axis=1 ,在水平方向上排序
Out:array([[ 4, 5, 20, 26, 48],
[15, 24, 24, 29, 40],
[ 9, 26, 27, 43, 47]])
np.sort(b, axis=0) # 在豎直方向上排序
Out:array([[ 9, 5, 26, 4, 20],
[24, 26, 29, 15, 24],
[48, 40, 47, 43, 27]])
NumPy函數
numpy提供了很多ufunc通用函數,可一次性對整個數組進行計算,無須編寫循環處理。格式:np.函數名(數組)
常用函數
有max()、min()、ptp()、sum()、var()、std()等
np.random.seed(7)
b = np.random.randint(1, 20, size=8) # array([16, 5, 4, 8, 15, 9, 15, 11])
np.max(b), np.min(b) ,np.mean(b) # 最大值、最小值、平均值
np.ptp(b) # ptp返回數據極差12,即最大值-最小值
np.quantile(b,[0.25,0.5,0.75])
# 返回分位點對應的分位數,array([ 7.25, 10. , 15. ]),
#這個的意思是佔了這個數組的0.25的前面數字是比7.25小的數字,
#佔了0.5的是數組比10小的數字
一些函數也可寫爲"數組.函數名()"的形式
b.max(), b.min(), b.ptp(), b.sum(), b.mean()
b.var(), b.std() , np.median(b) # 方差、標準差、中位數
b.argmax(), b.argmin() # 最大值、最小值所對應的索引下標
二維數組
對於二維數組,函數計算時還可指定計算的軸axis=0/1。
b = np.arange(10).reshape(2, 5)
Out[7]:
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
np.sum(b) # 未指定軸,計算所有數據的和
Out: 45
np.sum(b, axis=0) # 指定軸axis=0,行, 沿豎直方向求和
Out: array([ 5, 7, 9, 11, 13])
np.sum(b, axis=1) # 指定軸axis=1,列, 沿水平方向求和
Out: array([10, 35])
缺失值
nan表示缺失值,如數組中含有nan ,則函數運算結果爲nan。
b = np.array([1, 2, np.nan, np.nan, 3]) # 構造含有nan值的數組
np.sum(b) # 含有nan值的數組,運算後返回nan
np.isnan(b) # isnan()測試是否nan值
Out: array([False, False, True, True, False])
np.isnan(b).sum() # 計算nan值個數,True被視爲1 , 結果 2
b[~np.isnan(b)] # 取出非nan的值
np.nan == np.nan # nan值很特殊,結果爲False
c = np.arange(1, 6) # array([1,2,3,4,5])
np.prod(c) # 累乘 120
np.cumprod(c) # 累乘並給出中間結果 array([1,2,6,24,120])
np.cumsum(c) # 累加並給出中間結果
Out: array([1,3,6,10,15], dtype=int32)
b=np.array([1,3,3,5,5,7,8])
np.unique(b) # 返回不重複的元素值 array([1, 3, 5, 7, 8])
np.all(b) # b所有元素都爲非0值則返回True
np.any(b) # b有任意元素爲非0值則返回True
NumPy還提供實現矩陣乘法運算的dot()函數。
a=np.arange(6).reshape(2, 3)
b=np.arange(6, 12).reshape(3, 2)
np.dot(a, b) # 2x3和3x2數組相乘,結果爲2x2數組。寫爲 a @ b 亦可
Out:
array([[ 28, 31],
[100, 112]])
隨機函數
np.random 隨機數模塊
np.random.seed(7) # 設置隨機數種子
np.random.rand(2,3) # 2x3小數數組
b=np.random.randint(1,100, 20) # 返回 [1,100)內20個隨機整數
np.random.choice(b, 5) # 從b中隨機抽5個數據
card=np.arange(1, 55) # 一副牌
np.random.shuffle(card) # 亂序 (隨機洗牌)
np.argwhere(card==54) # 查找數據54的位置,array([[2]]
x = ['A', 'B', 'C']
np.random.permutation(x) # 返回一個排列
Out: array(['C', 'A', 'B'], dtype='<U1')
< : 小端對齊(intelCPU), U :Unicode編碼 1:1個字符長
# 補充 Python中的排列和組合
import itertools
list(itertools.permutations(x)) # 返回所有可能的排列
list(itertools.combinations(x, 2)) # x中選2個,返回所有可能組合