NumPy 數值計算基礎
Numpy簡介
NumPy(Numerical Python)是Python的一種開源的數值計算擴展。這種工具可用來存儲和處理大型矩陣,比Python自身的嵌套列表(nested list structure)結構要高效的多(該結構也可以用來表示矩陣(matrix)),支持大量的維度數組與矩陣運算,此外也針對數組運算提供大量的數學函數庫 。
NumPy 是一個運行速度非常快的數學庫,主要用於數組計算,包含:
•一個強大的N維數組對象 ndarray
•廣播功能函數
•整合 C/C++/Fortran 代碼的工具
•線性代數、傅立葉變換、隨機數生成等功能
NumPy 數組對象 ndarray
數組對象 ndarray簡介
NumPy 最重要的一個特點是其 N 維數組對象 ndarray,它是一系列同類型數據的集合,以 0 下標為開始進行集合中元素的索引。
ndarray 對象是用於存放同類型元素的多維數組。
ndarray 中的每個元素在內存中都有相同存儲大小的區域。
ndarray 內部由以下內容組成:
•一個指向數據(內存或內存映射文件中的一塊數據)的指針。
•數據類型或 dtype,描述在數組中的固定大小值的格子。
•一個表示數組形狀(shape)的元組,表示各維度大小的元組。
•一個跨度元組(stride),其中的整數指的是為了前進到當前維度下一個元素需要"跨過"的字節數。
ndarray 的內部結構:
數組屬性
ndarray(數組)是存儲單一數據類型的多維數組
屬性
說明
ndim
返回 int。表示數組的維數
shape
返回 tuple。表示數組的尺寸,對於 n 行 m 列的矩陣,形狀為(n,m)
size
返回 int。表示數組的元素總數,等於數組形狀的乘積
dtype
返回 data-type。描述數組中元素的類型
itemsize
返回 int。表示數組的每個元素的大小(以字節為單位)。
數組創建
numpy.array(object, dtype=None, copy=True, order='K',subok=False, ndmin=0)
參數名稱
object
dtype
ndmin
代碼案例
import numpy as np
# 數組屬性:ndarray(數組)是存儲單一數據類型的多維數組。
# 創建一維數組
arr1 = np.array([1, 2, 3, 4])
print("創建的數組為: ", arr1)
# 創建二維數組
arr2 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [11, 22, 33]])
print("創建的數組為:\n", arr2)
# 查看數組結構
print("數組結構為 ", arr2.shape)
# 查看數組類型
print("數組類型為 ", arr2.dtype)
# 查看數組元素個數
print("查看數組元素個數", arr2.size)
# 查看數組每個元素大小
print("查看數組每個元素的大小", arr2.itemsize)
# 查看數組維度
print("查看數組維度", arr2.ndim)
# 重新設置數組的 shape 屬性
# 第一種寫法
arr2.shape = 2, 6
print("重新設置shape維度的arr2: \n", arr2)
# 第二種寫法
arr2 = arr2.reshape(4, 3)
print("重新設置shape維度的arr2: \n", arr2)
# 創建二維數組
# 使用arange 函數創建數組
print("使用arange函數創建數組為: \n", np.arange(0, 1, 0.1))
# 使用linspace 函數創建數組
print("使用linspace函數創建數組: \n", np.linspace(0, 1, 12))
# 使用logspace 函數創建等比數列
print("使用logspace函數創建的數組為: \n", np.logspace(0, 2, 20))
# 使用zeros函數創建數組
print("使用zeros函數創建數組:\n", np.zeros((2, 3)))
# 使用eye函數創建數組
print("使用eye函數創建數組: \n", np.eye(3))
# 使用giag函數創建數組
print("使用diag函數創建數組: \n", np.diag([1, 2, 3, 4]))
# 使用ones函數創建數組
print("使用ones函數創建數組: \n", np.ones((5, 3)))
數組數據類型
名稱
描述
bool_
布爾型數據類型(True 或者 False)
int_
默認的整數類型(類似於 C 語言中的 long,int32 或 int64)
intc
與 C 的 int 類型一樣,一般是 int32 或 int 64
intp
用於索引的整數類型(類似於 C 的 ssize_t,一般情況下仍然是 int32 或 int64)
int8
字節(-128 to 127)
int16
整數(-32768 to 32767)
int32
整數(-2147483648 to 2147483647)
int64
整數(-9223372036854775808 to 9223372036854775807)
uint8
無符號整數(0 to 255)
uint16
無符號整數(0 to 65535)
uint32
無符號整數(0 to 4294967295)
uint64
無符號整數(0 to 18446744073709551615)
float_
float64 類型的簡寫
float16
半精度浮點數,包括:1 個符號位,5 個指數位,10 個尾數位
float32
單精度浮點數,包括:1 個符號位,8 個指數位,23 個尾數位
float64
雙精度浮點數,包括:1 個符號位,11 個指數位,52 個尾數位
complex_
complex128 類型的簡寫,即 128 位複數
complex64
複數,表示雙 32 位浮點數(實數部分和虛數部分)
complex128
複數,表示雙 64 位浮點數(實數部分和虛數部分)
numpy 的數值類型實際上是 dtype 對象的實例,並對應唯一的字符,包括 np.bool_,np.int32,np.float32,等等。
數據類型對象 (dtype)
數據類型對象(numpy.dtype 類的實例)用來描述與數組對應的內存區域是如何使用,它描述了數據的以下幾個方面::
•數據的類型(整數,浮點數或者 Python 對象)
•數據的大小(例如, 整數使用多少個字節存儲)
•數據的字節順序(小端法或大端法)
•在結構化類型的情況下,欄位的名稱、每個欄位的數據類型和每個欄位所取的內存塊的部分
•如果數據類型是子數組,那麼它的形狀和數據類型是什麼。
字節順序是通過對數據類型預先設定 << span=""> 或 > 來決定的。 << span=""> 意味著小端法(最小值存儲在最小的地址,即低位組放在最前面)。> 意味著大端法(最重要的字節存儲在最小的地址,即高位組放在最前面)。
數組數據類型轉換
代碼案例
import numpy as np
# 數組數據類型轉換
# 整型轉換為浮點型
print("轉換結果:", np.float64(42))
# 浮點型轉換為整型
print("轉換結果:", np.int8(42.0))
# 整型轉換為布爾型
print("轉換結果:", np.bool(42))
# 整型轉換為布爾型
print("轉化結果:", np.bool(0))
# 布爾型轉換為浮點型
print("轉化結果:", np.float(True))
# 布爾型轉化為浮點型
print("轉化結果:", np.float(False))
# 創建一個存儲餐飲企業庫存信息的數據類型。其中,用一個長度為40個字符的字符串來記錄商品的名稱,用一個64位的整數來記錄商品的庫存數量,最後用一個64位的單精度浮點數來記錄商品的價格,具體步驟如下。
# 創建數據類型
df = np.dtype([("name", np.str_, 40), ("numitems", np.int64), ("price", np.float64)])
print("數據類型為:", df)
# 查看數據類型,可以直接查看或者使用numpy.dtype 函數查看
print("數據類型為:", df["name"])
print("數據類型為:", np.dtype(df["name"]))
# 在使用array函數創建數組時,數組的數據類型默認是浮點型。自定義數組數據,則可以預先指定數據類型
itemz = np.array([("tomatoes", 42, 4.14), ("cabbages", 13, 1.72)], dtype=df)
print("自定義數據為:", itemz)
生成隨機數
random模塊常用隨機數生成函數
函數
seed
permutation
shuffle
binomial
normal
beta
chisquare
gamma
uniform
代碼案例
import numpy as np
# 生成隨機數
# 五約束條件下生成隨機數
print("生成的隨機數組為:\n", np.random.random(100))
# 生成服從均勻分布的隨機數
print("生成的隨機數組為:\n", np.random.rand(10, 5))
# 生成服從正態分布的隨機數
print("生成的隨機數組為: \n", np.random.randn(10, 5))
# 生成給定上下範圍的隨機數,如創建一個最小值不低於 2、最大值不高於 10 的 2 行 5 列數組
print("生成的隨機數組為:\n", np.random.randint(2, 10, size=[2, 5]))
代碼實現
訪問數組
import numpy as np
# 通過索引訪問數組
# 一維數組的原理
arr = np.arange(10)
# 用整數作為下標可以獲取數組中的每個元素 列式存儲
print("索引結果為:", arr[5])
# 用範圍作為下標獲取數組的一個切片,包括arr[3]不包括arr[5]
print("索引結果為:", arr[3:5])
# 省略開始下標,表示從arr[0]開始
print("索引結果為:", arr[:5])
# 下標可以使用負數,-1表示從數組後往前數的第一個元素
print("索引結果為:", arr[-1])
# 下標還可以用來修改元素的值
arr[2:4] = 100, 101 # 索引結果為:: [ 0 1 100 101 4 5 6 7 8 9]
# 下標還可以用來修改元素的值
print("索引結果為:", arr)
# 範圍中的第三個參數表示步長,2表示隔一個元素取一個元素
print("索引結果為: ", arr[1:-1:2])
# 步長為負數時,開始下標必須大於結束下標
print("索引結果為:", arr[5:1:-2])
# 多維數組的索引
arr = np.array([[1, 2, 3, 4, 5], [4, 5, 6, 7, 8], [7, 8, 9, 10, 11]])
print("創建的二維數組為:\n", arr)
# 索引第0行中第3和4列的元素
print("索引結果為:\n", arr[0, 3:5])
# 索引第2和3行中第3~5列的元素
print("索引結果為:\n", arr[1:, 2:])
# 索引第2列的元素
print("索引結果為: \n", arr[:, 2])
# 多維數組的索引(使用整數和布爾值索引訪問數據)
# 從兩個序列的對應位置取出兩個整數來組成下標:arr[0,1], arr[1,2], arr[2,3]
print("索引結果為:", arr[[(0, 1, 2), (1, 2, 3)]])
# 索引第2、3行中第0、2、3列的元素
print("索引結果為:", arr[1:, (0, 2, 3)])
# mask是一個布爾數組,它索引第1、3行中第2列的元素
mask = np.array([1, 0, 1], dtype=np.bool)
print("索引結果為:", arr[mask, 2])
改變數組形狀
import numpy as np
# 改變數組形態
# 創建一維數組
arr = np.arange(12)
print("創建的一維數組為:", arr)
# 設置數組的形狀
print("新的一維數組為:\n", arr.reshape(3, 4))
# 查看數組維度
print("數組維度為:", arr.reshape(3, 4).ndim)
# 使用ravel函數展平數組
arr = np.arange(12).reshape(3, 4)
print('創建的二維數組為:\n', arr)
print("數組展平後為: \n", arr.ravel())
# 使用flatten函數展平數組
# 橫向展平
print("數組展平為:", arr.flatten())
# 縱向展平
print("數組展平為:", arr.flatten('F'))
# 組合數組
arr1 = np.arange(12).reshape(3, 4)
arr2 = arr1 * 3
print("創建的數組1為:\n", arr1)
print("創建的數組2為:\n", arr2)
# 使用hstack函數實現數組橫向組合:np.hstack((arr1,arr2))
print("橫向組合為:\n", np.hstack((arr1, arr2)))
# 使用vstack函數實現數組縱向組合:np.vstack((arr1,arr2))
print("縱向組合:\n", np.vstack((arr1, arr2)))
# 使用concatenate函數實現數組橫向組合:np.concatenate((arr1,arr2),axis = 1))
print("concatenat 橫向組合:\n", np.concatenate((arr1, arr2), axis=1))
# 使用concatenate函數實現數組縱向組合:np.concatenate((arr1,arr2),axis = 0))
print("concatenat 縱向組合:\n", np.concatenate((arr1, arr2), axis=0))
# 切割數組
arr = np.arange(16).reshape(4, 4)
print("切割數組")
print("數組為:\n", arr)
# 使用hsplit函數實現數組橫向分割: np.hsplit(arr1, 2)
print("hsplit 數值橫向切割 \n", np.hsplit(arr, 2))
# 使用vsplit函數實現數組縱向分割: np.vsplit(arr, 2)
print("vsplit 數值縱向分割\n", np.vsplit(arr, 2))
# 使用split函數實現數組橫向分割: np.split(arr, 2, axis=1)
print("split 函數實現數組橫向分割\n", np.split(arr, 2, axis=1))
# 使用split函數實現數組縱向分割: np.split(arr, 2, axis=0)
print("split 函數實現數組縱向分割\n", np.split(arr, 2, axis=0))
NumPy 矩陣與通用函數
創建與組合矩陣
•使用mat函數創建矩陣:
matr1 = np.mat("1 2 3;4 5 6;7 8 9")
•使用matrix函數創建矩陣:
matr2 = np.matrix([[123],[456],[789]])
•使用bmat函數合成矩陣:
np.bmat("arr1 arr2; arr1 arr2")
矩陣的運算
•矩陣與數相乘:matr1*3
•矩陣相加減:matr1±matr2
•矩陣相乘:matr1*matr2
•矩陣對應元素相乘:np.multiply(matr1,matr2)
•矩陣特有屬性:
ufunc函數
全稱通用函數(universal function),是一種能夠對數組中所有元素進行操作的函數。
•四則運算:加(+)、減(-)、乘(*)、除(/)、冪(**)。數組間的四則運算表示對每個數組中的元素分別進行四則運算,所以形狀必須相同。
•比較運算:>、<、==、>=、<=、!=。比較運算返回的結果是一個布爾數組,每個元素為每個數組對應元素的比較結果。< span="">
•邏輯運算:np.any函數表示邏輯「or」,np.all函數表示邏輯「and」。運算結果返回布爾值。
ufunc函數的廣播機制
廣播(broadcasting)是指不同形狀的數組之間執行算術運算的方式。需要遵循4個原則。
•讓所有輸入數組都向其中shape最長的數組看齊,shape中不足的部分都通過在前面加1補齊。
•輸出數組的shape是輸入數組shape的各個軸上的最大值。
•如果輸入數組的某個軸和輸出數組的對應軸的長度相同或者其長度為1時,這個數組能夠用來計算,否則出錯。
•當輸入數組的某個軸的長度為1時,沿著此軸運算時都用此軸上的第一組值。
一維數組的廣播機制
二維數組的廣播機制
代碼實現
ufunc函數
import numpy as np
# ufunc函數的廣播機制
# 一維數組的廣播機制
x = np.array([1, 2, 3])
y = np.array([4, 5, 6])
# 四則運算
print("數組相加結果為:", x + y)
print("數組相減結果為:", x - y)
print("數組相除結果為:", x / y)
print("數組相乘結果為:", x ** y)
# 數組比較運算
x = np.array([1, 3, 5])
y = np.array([2, 3, 4])
print("數組比較結果: x<y< span="">\n", x << span=""> y)
print("數組比較結果: x>y\n", x > y)
print("數組比較結果: x==y\n", x == y)
print("數組比較結果: x>=y\n", x >= y)
print("數組比較結果: x<=y< span="">\n", x <=< span=""> y)
print("數組比較結果: x!=y\n", x != y)
# 邏輯運算
# numpy邏輯運算中,np.all函數表示邏輯and np.any函數表示邏輯or
print("數組邏輯運算結果為:", np.all(x == y))
print("數組邏輯運算結果為:", np.any(x == y))</y<>
讀寫文件
import numpy as np
arr = np.array([1, 2, 3, 4, 5, 6])
# 讀寫二進位文件
# save 函數
np.save(arr=arr, file="./data/save_arr")
# load 函數
arr1 = np.load(file="./data/save_arr.npy")
print("arr1 ", arr1)
# savez 函數
np.savez("./data/save_arrs", arr, arr1 * 3)
arr3 = np.load("./data/save_arrs.npz")
print("arr3 ", arr3)
# 讀寫文本文件
# savetxt 將數組寫入到文件中,指定分隔符
np.savetxt("./data/save_arr.txt", arr, fmt="%d", delimiter=",")
# loadtxt
arr4 = np.loadtxt("./data/save_arr.txt", delimiter=",")
print("arr4\t", arr4)
# genfromtxt 面向的是結構化數據和缺失數據
print(np.genfromtxt(fname="./data/save_arr.txt", delimiter=","))
創建與組合矩陣
import numpy as np
# 使用mat函數創建矩陣
matr1 = np.mat("1 2 3;4 5 6;7 8 9")
# 使用matrix函數創建矩陣
matr2 = np.matrix([[123], [456], [789]])
# 使用bmat函數合成矩陣
np.bmat("arr1 arr2;arr1 arr2")
廣播機制
import numpy as np
arr1 = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3]])
print("創建的數組1為:", arr1)
print("數組1的shape為:", arr1.shape)
arr2 = np.array([1, 2, 3])
print("創建數組2為:", arr2)
print("數組2的shape為:", arr2.shape)
# 一維數組廣播
print("數組相加結果為:", arr1 + arr2)
# 二維數組廣播
arr2 = np.array([1, 2, 3, 4]).reshape((4, 1))
print("創建的數組2為:", arr2)
print("數組2的shape為:", arr2.shape)
print("數組相加結果為:", arr1 + arr2)
矩陣運算
import numpy as np
matr1 = np.mat("1 2 3;4 5 6;7 8 9")
matr2 = np.mat("1 2 3;4 5 6;7 8 9")
# 矩陣與數相乘:matr1*3
print("矩陣與數相乘:\n", matr1 * 3)
# 矩陣相加減:matr1±matr2
print("矩陣向:\n", matr1 + matr2)
# 矩陣相乘:matr1*matr2
print("矩陣相乘:\n", matr1 * matr2)
# 矩陣對應元素相乘:np.multiply(matr1,matr2)
print("矩陣點成: \n", np.multiply(matr1, matr2))
# 矩陣特有屬性:
# T 返回自身的轉置
print("T \n", matr1.T)
# H 返回自身的共軛轉置
print("H \n", matr1.H)
# I 返回自身的逆矩陣
print("I \n", matr1.I)
# A 返回自身數據的2維數據的一個視圖
print("A \n", matr1.A)
排序與去重
import numpy as np
# 直接排序
# 生成隨機數組
arr = np.random.rand(3, 3)
print("arr\n", arr)
arr1 = np.sort(arr, axis=0)
print("arr1 縱向排序\n", arr1)
arr2 = np.sort(arr, axis=1)
print("arr1 橫向排序\n", arr2)
# 間接排序
# argsort
arr3 = np.argsort(arr)
print("arr3\n", arr3)
# lexsort
arr4 = np.lexsort(arr)
print("arr4\n", arr4)
# 去重與重複數據
arr5 = np.unique([3, 7, 4, 4, 5, 5, 6, 6, 6])
print("arr5 \n", arr5)
arr6 = np.tile(A=arr, reps=2, axis=0)
print("arr6 \n", arr6)
利用NumPy 進行統計分析
讀寫文件
NumPy文件讀寫主要有二進位的文件讀寫和文件列表形式的數據讀寫兩種形式
•save函數是以二進位的格式保存數據。
np.save("../tmp/save_arr",arr)
•load函數是從二進位的文件中讀取數據。
np.load("../tmp/save_arr.npy")
•savez函數可以將多個數組保存到一個文件中。
np.savez('../tmp/savez_arr',arr1,arr2)
•存儲時可以省略擴展名,但讀取時不能省略擴展名。
讀取文本格式的數據
•savetxt函數是將數組寫到某種分隔符隔開的文本文件中。
np.savetxt("../tmp/arr.txt", arr, fmt="%d", delimiter=",")
•loadtxt函數執行的是把文件加載到一個二維數組中。
np.loadtxt("../tmp/arr.txt",delimiter=",")
•genfromtxt函數面向的是結構化數組和缺失數據。
np.genfromtxt("../tmp/arr.txt", delimiter = ",")
使用數組進行統計分析
•直接排序
–sort函數是最常用的排序方法。 arr.sort()
–sort函數也可以指定一個axis參數,使得sort函數可以沿著指定軸對數據集進行排序。axis=1為沿橫軸排序; axis=0為沿縱軸排序。
•間接排序
–argsort函數返回值為重新排序值的下標。 arr.argsort()
–lexsort函數返回值是按照最後一個傳入數據排序的。 np.lexsort((a,b,c))
•去重與重複數據
–通過unique函數可以找出數組中的唯一值並返回已排序的結果。
–tile函數主要有兩個參數,參數「A」指定重複的數組,參數「reps」指定重複的次數。
np.tile(A,reps)
–repeat函數主要有三個參數,參數「a」是需要重複的數組元素,參數「repeats」是重複次數,參數「axis」指定沿著哪個軸進行重複,axis = 0表示按行進行元素重複;axis = 1表示按列進行元素重複。
numpy.repeat(a, repeats, axis=None)
–這兩個函數的主要區別在於,tile函數是對數組進行重複操作,repeat函數是對數組中的每個元素進行重複操作。
•常用的統計函數
當axis=0時,表示沿著縱軸計算。當axis=1時,表示沿著橫軸計算。默認時計算一個總值。
函數
sum
mean
std
var
min
max
argmin
argmax
cumsum
cumprod
案例
任務要求
讀取iris數據集中的花萼長度數據(已保存為csv格式),並對其進行排序、去重,並求出和、累積和、均值、標準差、方差、最小值、最大值
實現代碼
import numpy as np
# 讀取iris數據集中的花萼長度數據(已保存為csv格式),並對其進行排序、去重,並求出和、累積和、均值、標準差、方差、最小值、最大值
arr = np.loadtxt(fname="iris_sepal_length.csv", delimiter=",")
# 去重排序
arr = np.unique(arr)
print(arr)
# 求和
print("np.sum(arr)\t", np.sum(arr, axis=0))
# 累積和
print("np.sum(arr)\t", np.cumsum(arr))
# 均值
print("np.mean(arr)\t", np.mean(arr))
# 標準差
print("np.std(arr)\t", np.std(arr))
# 方差
print("np.var(arr)\t", np.var(arr))
# 最小值
print("np.min(arr)\t", np.min(arr))
# 最大值
print("np.max(arr)\t", np.max(arr))