numpy[ˋnʌmpi](讀音為難py) 可以把它想像成是一台強大的工程計算機。
Python 常用的三台強大計算機分別為 Numpy、Tensorflow、PyTorch。
Numpy : 使用 CPU 計算。
Tensorflow : 使用 CPU/GPU計算,由 Google 開發。
PyTorch : 使用 CPU/GPU計算,由 Facebook開發。烏俄戰爭無人機使用 Yolo 搭配 PyTorch 演算而來。
Numpy 是計算統計學及許多科學函數的第三方套件,基本資料形態就是陣列。numpy 涵蓋範圍多且廣,不易完全熟悉。
numpy 會產生很多有用的數字,但這些數字人類無法理解,所以可以透過 Matplotlib 將數字視覺化。
numpy 可以包含基本的整數,小數及字元,甚至是字串。 而 numpy 的效能遠比 list、tuple 高出許多。
numpy 一但建立出來, 其元素的長度就無法變更。因為它就是基於陣列建立出來的,其本質並不是集合,所以和 list 完全不一樣。
安裝套件及 import
numpy 在使用前,需使用如下指令進行安裝
pip install numpy
然後再 import numpy
import numpy as np
numpy 在 2024 年 6 月進化到了 2.0 版,跟 1.0 版有些大幅的改進,效能也更好。
一維陣列
下面的代碼是比較簡單的一維陣列. 使用 np.array()建立一個陣列, 參數必需是list, 如
a=np.array([1,2,3,4,5]). 當陣列一建立後, 其長度就無法再改變.
存取每個元素, 可以使用索引(index)指定. 但請注意, 索引是由 0 開始. 當指定的索引超出陣列的長度, 就會於Runtime時期發生out of bundle exception
Array跟List用法表面上蠻像的,如a[0]=100, list也是 l[0]=100。但List可以增加長度,如l.append(100)。而Array就無法增加。
Numpy增加了sort類別方法 : np.sort([…])
也有物件方法 : sum ,mean, var, std等統計的功能,這是List所沒有的。
列印陣列時, 如果直接列印 a, 則會將每個元素以陣列的方式印出. 若要一個一個印出, 可以使用迴圈.
import numpy as np
import random a=np.array([1,2,3,4,5]) print(a) for i in range(0,5): a[i]=random.randint(1,100) for i in range(0,5): print("a[%d]=%d" % (i, a[i])) b=np.array(range(1, 11))
print(b)
結果 : [1 2 3 4 5] a[0]=7 a[1]=85 a[2]=75 a[3]=20 a[4]=70
[ 1 2 3 4 5 6 7 8 9 10]
型別
np.array其實還有第二個參數,可以指定型別,如下所示
x=np.array([1,2,3,4], dtype=np.int32)
print(x.dtype) #印出int32
dtype即為型別參數,若沒有dtype, 則整數預設為 np.int64,小數預設為 np.float64。可用的型別有
bool, string,
int8, int16, int32, int64,
uint8, uint16, uint32, uint64
float16, float32, float64
dtype可以使用np.intxx,亦可以使用字串 “intxx”,或直接使用 np.intxx({})
x=np.array([1,2,3], dtype=np.int32)
y=np.array([1,2,3], dtype="int32")
z=np.int32([1,2,3])
np.zeros
np.zeros([長度]), 可以產生特定長度的空陣列, 每個元素皆填入 0.
import numpy as np
a=np.zeros([10])
np.ones
全部填入1
import numpy as np
a=np.ones([10])
print(a)
結果 :
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
排序
np的類別方法 np.sort([….]) 可進行排序,其參數可以為陣列,亦可以為List。結果為排序後的陣列。
而系統函數 sorted([…]),其參數亦可以為陣列或List,結果為排序後的List。
a=np.array([6,4,5,1,8,7])
print(np.sort(a)) #印出排序後的陣列
print(sorted(a, reverse=False)) #印出厞序後的list
汽泡排序法
下面的演算法, 就是頂頂有名的汽泡排序法,但此法僅作為教學用。若真的要排序,np.sort()會切換到C/C++語言進行排序,故效能會高很多。
import numpy as np, random #產生10個元素的陣列, 並把每個元素都填入 0 d=np.zeros([10]) #將亂數填入陣列中 for i in range(0,len(d)): d[i]=random.randint(1,100) #列印未排序的陣列 for i in range(0,len(d)): print("%d " % d[i],end='') print() #汽泡排序法 for i in range(0, len(d)-1): for j in range(i+1, len(d)): if d[i]>d[j]: tmp=d[i] d[i]=d[j] d[j]=tmp #列印已排序的陣列 for i in range(0,len(d)): print("%d " % d[i],end='') print() 結果 : 9 41 5 19 3 59 42 26 73 10 3 5 9 10 19 26 41 42 59 73
陣列相加
二個陣列可以進行相加, 這功能還蠻方便的
import numpy as np a=np.array([1,2,3,4,5]) b=np.array([6,7,8,9,10]) c=a+b print(c) 結果 : [ 7 9 11 13 15]
二維陣列
二維陣列的宣告, 就是使用 [ [], [],[] …], 每一列的長度都可以不一樣.
import numpy as np a=np.array([[1,2,3,4,5], [6,7,8], [10,20,30,40]]) for i in range(0,len(a)): for j in range(0,len(a[i])): print("%d " % a[i][j], end='') print() 結果 : 1 2 3 4 5 6 7 8 10 20 30 40
空二維陣列
要產生特定長度的二維陣列, 同樣使用zeros(), 於list中指定列數及行數
a=np.zeros([3,10])
reshape
這個功能是要將一維變成二維, 或是二維變成一維. 請注意, 如果是二維的話, 在變換時, 每列的長度都必需一樣
import numpy as np a=np.array([[1, 2, 3, 4], [5, 6, 7, 8]]) print ("2*4陣列 : \n%s" % a) a=a.reshape([1, 8]) print ("1*8陣列 : \n %s" % a) a=a.reshape([4, 2]) print ("4*2陣列 : \n %s " % a) 結果 : 2*4陣列 : [[1 2 3 4] [5 6 7 8]] 1*8陣列 : [[1 2 3 4 5 6 7 8]] 4*2陣列 : [[1 2] [3 4] [5 6] [7 8]]
統計功能
numpy其實還有統計的特異功能, 如下變異數,標準差,平均值。
有關變異數及標準差,請參照 數學變異數 這篇
import array, numpy as np a=np.array([1,2,3,4,5]) print("標準差 : %.2f" % a.std()) print("最小值 : %.2f" % a.min()) print("最大值 : %.2f" % a.max()) print("平均值 : %.2f" % a.mean()) print("總 合 : %.2f" % a.sum()) 結果 : 標準差 : 1.41 最小值 : 1.00 最大值 : 5.00 平均值 : 3.00 總 合 : 15.00
範例一
公司請了三個營業員, 販賣五項商品, 每個營業員的銷售數量如下
sales1 : 10, 15, 11, 13, 20
sales2 : 8, 20, 18, 19, 25
sales3 : 15, 25, 31, 10, 28
公司的每項商品價格如下
price : 10, 20, 30, 40, 50
請計算
1. 每位營業員的銷售金額, 如
sales1 : 10*10+15*20+11*30+13*40+20+50
2. 計算每項商品的營業額, 如
item1 : (10+8+15)*10
import numpy as np, random
qty=np.array([
[10,15,11,13,20],
[8,20,18,19,25],
[15,25,31,10,28]])
price=np.array([10,20,30,40,50])
for i in range(0,len(qty)):
total=0
for j in range(0,len(price)):
total+=qty[i][j]*price[j]
print(f"sales{i} 銷售額為 : {total:.2f}")
for i in range(0,len(price)):
total=0
for j in range(0,len(qty)):
total+=qty[j][i]
print(f"item{i} 營業額 : {total*price[i]:.2f}")
結果 :
sales1 銷售額為 : 2250.00
sales2 銷售額為 : 3030.00
sales3 銷售額為 : 3380.00
item1 營業額 : 330.00
item2 營業額 : 1200.00
item3 營業額 : 1800.00
item4 營業額 : 1680.00
item5 營業額 : 3650.00
但是如果使用 numpy 的新思維,可以改成如下
import numpy as np, random qty=np.array([ [10,15,11,13,20], [8,20,18,19,25], [15,25,31,10,28]]) price=np.array([10,20,30,40,50]) sales=qty*price print(sales) for i in range(0,len(qty)): print(f"sales{i} 銷售額為 : {sales[i].sum():.2f}")
範例二
河圖洛書, 每列加總=每行加總=對角加總
8 | 1 | 6 |
3 | 5 | 7 |
4 | 9 | 2 |
import numpy as np, random n=5 d=np.zeros([n, n]) x=int(n/2) y=0 index=1 while index <= n*n: d[y][x]=index index+=1 if(x==n-1 and y==0):y+=1 else: x=(x+1)%n y=(y-1+n)%n if(d[y][x]!=0): x-=1 y+=2 for i in range(0,n): for j in range(0,n): print("%3d " % (d[i][j]), end="") print() 結果 : 17 24 1 8 15 23 5 7 14 16 4 6 13 20 22 10 12 19 21 3 11 18 25 2 9
三角函數
三角函數需且需先pip install numpy(1.19.3版)
(File/Setting/專案名稱/Python Interpreter/再加 numpy套件,然後於右下角的Specify version選取 1.19.3)
np.sin(np.pi/180*角度) : 請注意,三角函數裏面的參數不是角度,而是弧度。
import numpy as np
for i in [0,30,60,45,90]:
sin = np.sin(np.pi / 180 * i)
cos = np.cos(np.pi / 180 * i)
tan = np.tan(np.pi / 180 * i)
print(f'sin{i:02}={sin:.3f}, cos{i:02}={cos:.3f}, tan{i:02}={tan:.3f}')
結果 :
sin00=0.000, cos00=1.000, tan00=0.000
sin30=0.500, cos30=0.866, tan30=0.577
sin60=0.866, cos60=0.500, tan60=1.732
sin45=0.707, cos45=0.707, tan45=1.000
sin90=1.000, cos90=0.000, tan90=16331239353195370.000 <==此為無窮大
反三角函數
反三角函數的目的,是經由三角函數的值反算其角度。比如$(sin(30) = 0.5)$. 那麼
$(sin^{-1}(0.5)=0.524)$。 0.524是弧度,需再經由np.degress(0.524)才會算出30度角
arc=np.arcsin(0.5)
ang=np.degrees(arc)
print(f'弧度 : {arc:.3f}')
print(f'角度 : {ang:.3f}')
結果 :
弧度 : 0.524
角度 : 30.000
array.array
array並不是陣列, 其本質就是集合, 而且跟list一樣, 但只能包含整數, 小數及字元, 其他如物件等無法加入. 所以其效能也比list高出許多
import array a=array.array("l") a.append(1) a.append(2) a.append(3) a.append(4) a.append(5) a.pop() a.remove(2) #刪除第二個, 第一個為 1 print(a[0]) print(a)
建立array
建立arry時, 使用array.array(數據型態). 數據型態如下表所示
Type code | C Type | Python Type | Minimum size in bytes | Notes |
---|---|---|---|---|
'b' |
signed char | int | 1 | |
'B' |
unsigned char | int | 1 | |
'u' |
Py_UNICODE | Unicode character | 2 | (1) |
'h' |
signed short | int | 2 | |
'H' |
unsigned short | int | 2 | |
'i' |
signed int | int | 2 | |
'I' |
unsigned int | int | 2 | |
'l' |
signed long | int | 4 | |
'L' |
unsigned long | int | 4 | |
'q' |
signed long long | int | 8 | (2) |
'Q' |
unsigned long long | int | 8 | (2) |
'f' |
float | float | 4 | |
'd' |
double | float | 8 |
存取
array可以使用索引進行存取, 如 a[0]
常用函數
常用的有如 reverse, count, index, 請參照如下
import array, numpy as np a=array.array("l") a.append(1) a.append(3) a.append(3) a.append(4) print("3出現的次數 : %d" % a.count(3))#3出現的次數 print("4第一次出現的位置 : %d" % a.index(4))#4第一次出現的位置, 位置由0開始 a.reverse()#反轉 print("反轉後的結果 : ", a) 結果 : 3出現的次數 : 2 4第一次出現的位置 : 3 反轉後的結果 : array('l', [4, 3, 3, 1])
Slicing
Slicing是要擷取陣列某片段的資料。底下代碼中,a為[1,2,3…10]的陣列,
a[2:4]表示式中,2為擷取的啟始編號,4為擷取的結束編號,但不包含4。
import numpy as np
a=np.array([1,2,3,4,5,6,7,8,9,10])
b=a[2:4]
print(b)
結果:
[3,4]
若要擷取全部的資料,只需使用 a[:]即可
結束編號亦可為負值,表示由後面開始算起,如a[2:-1],則由2開始抓取到最後第2個,所以結果為
[3 4 5 6 7 8 9]
如果是二維陣列,則用 “,” 隔開每一維的編號,如下
0:2 表示取得 第0及1列
2:4 表示第2到3行
import numpy as np
a=np.array([
[1,2,3,4,5],
[6,7,8,9,10]
])
b=a[0:2,2:4]
print(b)
結果:
[[3 4]
[8 9]]
過濾器
todo