Numpy

      在〈Numpy〉中尚無留言

numpy[ˋnʌmpi] 是計算統計學及許多科學函數的第三方套件,基本資料形態就是陣列。numpy 涵蓋範圍多且廣,不易完全熟悉。

數字視覺化

numpy 會產生很多有用的數字,但這些數字人類無法理解,所以需先簡單了解如何將數字視覺化。

todo

numpy可以包含基本的整數, 小數及字元,甚至是字串。 而numpy的效能遠比list, tuple高出許多. 
numpy一但建立出來, 其元素的長度就無法變更. 因為它就是基於陣列建立出來的, 其本質並不是集合, 和list完全不一樣。

numpy 在使用前,  需先import numpy. 如果無法import,  記得使用 pip install numpy.

通常Python的程式計設師非常的懶,會使用 import numpy as np,然後用 np代替numpy

import numpy as np

一維陣列

下面的代碼是比較簡單的一維陣列. 使用 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.int32,小數預設為 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

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *