NumPy從入門到放棄

愚生浅末發表於2024-08-08

看前建議:

本文以jupyter notebook為編輯器進行示例,建議有一定python基礎後再進行學習。

python的安裝:https://www.cnblogs.com/scfssq/p/17478132.html

jupyter notebook的安裝:https://www.cnblogs.com/kohler21/p/18349764
公眾號本文地址:https://mp.weixin.qq.com/s/EocThNWhQlI2zeLcUApsQQ

NumPy簡介

公眾號:愚生淺末
Numeric Python(簡稱NumPy)是使用Python進行科學計算的基本包,它是一個Python庫,提供了多維陣列物件,使用NumPy相較於直接編寫Python程式碼實現,效能更加高效、程式碼更加簡潔。NumPy廣泛應用於各類場合,例如在機器學習、數值處理、爬蟲等。NumPy主要是圍繞Ndarray物件展開,透過NumPy的線性代數庫對其進行一系列操作如切片索引、廣播、修改陣列(形狀、維度、元素的增刪改)、連線陣列等,以及對多維陣列的點積等。除了陣列,Numpy還有很多函式包括三角函式、統計函式等。

NumPy的重要特點之一就是 n 維陣列物件,即 ndarray。

在使用Numpy之前需要線匯入Numpy:

import numpy as np

生成陣列

  1. 生成0\1陣列

生成0/1陣列,利用np.ones(shape, dtype)或np.ones_like(a, shape)、np.zeros(shape, dtype)或np.zeros_like(a, shape)

one_matrix = np.ones([3, 3]) # 生成一個3x3的矩陣,矩陣元素都為1
one_matrix

效果:

生成一個3x3的矩陣,矩陣元素都為0

zero_matrix = np.zeros_like(one_matrix) 
zero_matrix

效果:

  1. 從現有資料生成陣列,透過np.array(object, dtype)或np.asarray(a, dtype)
arr = np.array([[3, 4],[1, 2]])
print([[3, 4],[1, 2]])
arr

效果:

arr1 = np.array(arr)
arr1

效果:

arr2 = np.asarray(arr)
arr2

可以發現,arr1和arr2與arr1完全一直,但是採用了不同的函式,實際上這兩個複製函式是不同的,對於arr1採用的是np.array(),而arr2採用的是np.asarray()。當修改arr的元素值時候,arr1的元素值不會改變,而arr2的元素值會隨著arr的元素值的改變而改變,示例如下:

# 修改原陣列arr的元素值,對比arr1與arr2的變化
arr[1, 1] = 6

  1. 生成固定範圍的陣列,利用np.arange()

透過np.linspace(start,stop,num=50)、np.arange([start=None],stop=None,[stop=None])、np.logspace(start,stop,num=50)均可以生成指定範圍的數字,以np.arange()示例如下:

arr = np.arange(0, 13, 2)

可以發現生成的陣列不包含指定的最後一個數字,因為這個區間設定是左閉右開的。
公眾號:愚生淺末
4. 生成隨機陣列

生成隨機陣列有多種方法。

rand基本用法

numpy.randon.rand(d0,d1,...dn),產生[0,1)之間均勻分佈的隨機浮點數,其中d0,d1,...dn標識傳入的陣列形狀。

np.random.rand(2)#產生形狀為(2,)的陣列,也就是相當於有兩個元素的一維陣列
np.random.rand(2,4)#產生一個形狀為(2,4)的陣列,陣列中的每個元素是[0,1)之間均勻分佈的隨機浮點數

random基本用法

numpy.random.random(size),產生[0,1)之間的隨機浮點數,非均勻分佈

numpy.random.random_sample、numpy.random.ranf、numpy.random.sample用法與該函式類似

注意:該函式和rand()的區別

(1)random()引數只有一個引數"size",有3種取值:None,int型整數,int型元組。而在之前的numpy.random.rand()中可以有多個引數。例如,如果要產生一個3*3的隨機陣列(不考慮服從什麼分佈),那麼在rand()中的寫法是:numpy.random.rand(3,3),而在random中的寫法是numpy.random.random((3,3)),這裡面是個元組,是有小括弧的。

(2)random()產生的隨機數的分佈為非均勻分佈,numpy.random.rand()產生的隨機數的分佈為均勻分佈

#產生一個[0,1)之間的形狀為(3,3)的陣列
np.random().random((3,3))
#產生[-5,0)之間的形狀為(3,3)的隨機陣列,即5*[0,1)-5
5*np.random.random_sample((3,3))-5
#產生[5,10)之間的形狀為(3,3)的隨機陣列,即10*[0,1)-5[0,1)+5
(10-5)*np.eandom.random_sample((3,3))+5

numpy.random.uniform

np.random.uniform(0.0, 1.0,size=None),從指定範圍內產生均勻分佈的隨機浮點數,如果在seed()中傳入的數字相同,那麼接下來生成的隨機數序列都是相同的,僅作用於最接近的那句隨機數產生語句

#預設產生一個[0,1)之間隨機浮點數
np.random.uniform()
#預設產生一個[1,5)之間的形狀為(2,4)的隨機浮點數
np.random.uniform(1,5,size=(2,4))

randn基本用法

np.random.randn(d0,d1,...,dn),產生服從於標準正態分佈(均值為0,方差為1)的隨機浮點數,使用方法和rand()類似

# 產生形狀為(2,)的陣列
np.random.rand(2)
# 產生形狀為(2,4)的陣列
np.random.rand(2,4)

如果要指定正態分佈的均值和方差,則可以使用這個公式:

sigma * np.random.randn(...) + mu:2.5 *np.random.randn(2,4) + 3

注意:2.5是標準差(不是方差),3是期望

normal基本用法

numpy.random.normal(loc=0.0, scale=1.0, size=None),產生服從正態分佈(均值為loc,標準差為scale)的隨機浮點數

#產生均值為1標準差為10形狀為(1000,)的陣列
np.random.normal(1,10,100)
#產生均值為3標準差為2形狀為(2,4)的陣列
np.random.normal(3,2,size=(2,4))

randint基本用法

numpy.random.randint(low[,high,size,dtype]),產生[low,high)之間的隨機數,如果high不知名,則產生[0,low)之間的隨機整數,size可以是int整數,或者int型的元組,標識產生隨機數的個數,或者隨機陣列的形狀。dtype標識具體隨機數的型別,預設是int,可以指定成int64.

#產生一個[0,10)之間的隨機整數
np.random.randint(10)
#產生一個[0,10)之間的隨機整數8個,以陣列的形式返回
np.random.randint(10,size=8)
#產生一個[5,10)之間的形狀為(2,4)的隨機整數8個,以陣列的形式返回
np.random.randint(5,10,size=(2,4))

choice基本用法

numpy.random.choice(a, size=None, replace=True, p=None),從一維arrary a中按機率p選擇size個陣列,若a為int,則從np.arrange(a)中選擇,若a為array,則直接從a中選擇。

numpy.random.choice(5,3)#從np.arrange(a)中等機率選擇3個,等價於np.random.randint(0,5,3)
numpy.random.choice(5,3,p=[0.1,0,0.3,0.6,0])#從np.arrange(a)中按機率p選擇3個
numpy.random.choice(5,3,p=[0.1,0,0.3,0.6,0]
numpy.random.choice(5,3,replace=False,p=[0.1,0,0.3,0.6,0])
aa_milne_arr = ['pooh','rabbit','piglet','Christopher']
np.random.choice(aa_milne_arr,5,p=[0.5,0.1,0.1,0.3])

numpy.random.shuffle

numpy.random.shuffle(x)按x的第一個維度進行打亂,x只能是array

np.random.shuffle(np.arange(9).reshape((3,3)))#對np.arange(9).reshape((3,3))打亂

numpy.random.permutation

numpy.random.permutation(x),按x的第一個維度進行打亂,若a為int,則對np.arrange(a)打亂,若a為array,則直接對a打亂

np.random.permutation(10)#對np.arange(10)打亂
np.random.permutation(np.arange(9).reshape((3,3)))#對np.arange(9).reshape((3,3))打亂

numpy.random.seed

若果在seed()中傳入的數字相同,那麼接下來生成的隨機數序列都是相同的,僅作用於最接近的那句隨機數產生語句

np.random.seed(10)
temp1 = np.random.rand(4)
np.random.seed(10)
temp2=np.random.rand(4)
temp3=np.random.rand(4)

上述temp1和temp2是相同的,temp3是不同的,因為seed僅作用於最接近的那句隨機數產生語句。

numpy.linspace

numpy.linspace(start,stop,num=50,endpoint = True,retstep = False,dtype = None,axis = 0),區間均等分

np.linspace(2.0,3.0,num=5) #array([2.,2.25,2.5,2.75,3.])
np.linspace(2.0,3.0,num=5,endpoint=False) #array([2.,2.2,2.4,2.6,2.8])
np.linspace(2.0,3.0,num=5,retstep=True) #(array([2.,2.25,2.5,2.75,3.]),0.25)

zeros(),ones(),empty(),eye(),identity(),diag()

  • zeros(),ones(),empty()三者用法一樣,np.zeros(3,dtype=int) np.zeros((2,3))
  • 使用empty()時需要對生成的每一個數進行重新賦值,否則即為隨機數,所以慎重使用
  • np.eye(2,3,k=1)he np.identity(3) : np.identity只能建立方形矩陣,np.eye可以建立矩形矩陣,且k值可以調節,為1 的對角線的位置偏離度,0居中,1向上偏離1,2向上偏離2,以此類推,-1向下偏離。值的絕對值過大就偏離出去了,整個矩陣就全是0了。np.diag可以建立對角矩陣。

陣列的索引、切片

ndarray的索引、切片與list稍不同,他只有一個'[]'程式碼如下:

arr = np.array([ [[1, 2, 3],[4, 5, 6]], [[7, 8, 9],[10, 11, 12]] ])
list1 = [ [[1, 2, 3],[4, 5, 6]], [[7, 8, 9],[10, 11, 12]] ]
# 以下兩種方法取值相同
a1 = arr[0, :]
b1 = arr[0][:]
print(list1[0][:])  # list只能用兩個中括號來取值
print(a1, b1) # [[1, 2, 3][4, 5, 6]]

a2 = arr[0, 0, 0]
print(a2) # 1

可以看到ndarray的切片索引方法就是:物件[x, y, z, …]先行後列,依據物件的緯度輸入的引數也不同。對於ndarray來說,以下兩種索引方式均可以。

a = [[1, 2, 3],[4, 5, 6]], [[7, 8, 9],[10, 11, 12]]
b = np.array(a)
print(b[0, 1])  # array([4, 5, 6])
print(b[0][1])  # array([4, 5, 6])

而對於二維的list而言,只能使用[][][] []索引

a = [[1, 2, 3],[4, 5, 6]], [[7, 8, 9],[10, 11, 12]]
# b = np.array(a)
# print(a[0, 1]), 該種索引方式會報錯
print(a[0][1])  # [4, 5, 6]

形狀修改

透過ndarray.T可以實現一個矩陣的轉置,程式碼如下:

arr = np.array([[1, 2],[3, 4]])
arr.T  # [[1, 3],[2, 4]]

可以透過ndarray.reshapre()將arr變成一個1行4列的陣列,reshape()實際上是將原來的陣列壓平成一維陣列,然後再重新排序成目標形狀,但不改變原陣列。程式碼如下:

new_arr = arr.reshape([1, 4])
new_arr  # [[1, 2, 3, 4]]

也可以透過ndarray.resize()實現改變結構,但是resize()會改變原陣列,而不是直接返回一個新陣列。程式碼如下:

arr.resize([1, 4])
arr  # [[1, 2, 3, 4]]

透過np.repeat(a,reps,axis),可以實現對原陣列的複製、重構。其中a是目標陣列,reps是重複的次數,axis標識沿某個方向複製。若axis=0,則沿第0個維度變化的方向複製,即增加了行數,若axis=None,則原陣列會展平成一維陣列,程式碼如下:

arr = np.array([[1, 2], [3, 4]])
flat_arr = np.repeat(arr, 2)
flat_arr  # [1, 1, 2, 2, 3, 3, 4, 4]
re_arr = np.repeat(arr, 2, axis = 1)
re_arr  # [[1, 1, 2, 2], [3, 3, 4, 4]]

透過np.tile(a, reps),以可以實現對透過複製原陣列構建新的陣列,其中a是目標陣列,reps是重複的次數。相較於np.repeat(),np.tile()的引數更少,但而這實現的功能是類似的,但其複製的規則不同,np.tile()是對整個array進行復制,np.repeat()是對其中的元素進行復制程式碼如下:

arr = np.array([[1, 2], [3, 4]])
flat_arr = np.tile(arr, 2)
flat_arr  # [1, 1, 2, 2, 3, 3, 4, 4]
tile_arr = np.tile(arr, (2, 1))
tile_arr  # [[1, 2], [3, 4], [1, 2], [3, 4]]

透過np.concatenate((a, b), axis)可以實現對陣列的連線,其中a、b分別標識兩個陣列;axis表示沿著第幾個維度疊加,例如,axis=0時,即沿第0個維度變化的方向相加,程式碼如下:

a = [[1, 2], [3, 4]]
b = [[10, 11], [12, 13]]
res1 = np.concatenate((a, b), axis = 0)
res1  # [[1, 2], [3, 4], [10, 11], [12, 13]]

res2 = np.concatenate((a, b), axis = 1)
res2  # [[1, 2, 10, 11], [3, 4, 12, 13]]

此外,np.vstack((a, b))的作用與np.concatenate((a, b), axis = 0)相似,np.hstack((a, b))的作用與np.concatenate((a, b), axis = 1)相似,程式碼如下:

v_res = np.vstack((a, b))
v_res  # [[1, 2], [3, 4], [10, 11], [12, 13]]
h_res = np.hstack((a, b))
h_res  # [[1, 2, 10, 11], [3, 4, 12, 13]

型別修改

首先生成一個陣列,程式碼如下:

# 生成陣列
arr = np.array([[1, 2], [3, 4]])

可以透過ndarray.astype(str)將這個陣列中的每個元素都變成string型別,該方法不改變原陣列,而是返回一個新陣列,程式碼如下:

arr1 = arr.astype(str)
arr1  # [['1' '2'], ['3' '4']]

陣列的通用函式

透過np.unique()可以實現對一個現有陣列,除去其中重複的元素,返回一個沒有重複元素的一維陣列,且這個方法不會改變原陣列,程式碼如下:

arr = np.array([[1, 1, 2, 3],[1, 22, 34, 5]])
unique = np.unique(arr)
unique  # [1, 2, 3, 5, 22, 34]

如果按某個維度去重,則使用axis指定去重維度即可,程式碼如下:

a = [[1, 2, 3],[4, 5, 6]], [[1, 2, 3],[4, 5, 6]]
b = np.array(a)
c = np.unique(b, axis=0)
print(c)  # array([[[1, 2, 3], [4, 5, 6]]])

透過np.intersect1d()和np.union1d(),可以分別實現求兩個矩陣的交集和並集。程式碼如下:

a = [1, 2, 3, 4]
b = [3, 4, 5, 6]
print(np.intersect1d(a, b))  # [3, 4]
print(np.union1d(a, b))  # [1, 2, 3, 4, 5, 6]

Numpy中還有一些常用的一元函式、二元函式,在原陣列進行操作,直接修改原陣列的元素。np.abs(),可以實現計算浮點數、整數或複數的絕對值.

a = [-1, 2, -3, 4]
print(np.abs(a))  # [1, 2, 3, 4]

np.sqrt(),可以實現計算元素的平方根,相當於Python中的“ ** ”的反函式

b = [3, 4, 5, 6]
print(np.sqrt(b))  # [1.73205081, 2, 2.23606798, 2.44948974]
print(2**2)

np.square()計算各元素的平方,np.exp()可以計算各元素的e指數,np.power(arr, t)可以計算陣列中各元素t次方

# np.square()計算各元素的平方,np.exp()可以計算各元素的e指數,np.power(arr, t)可以計算陣列中各元素t次方
a = [-1, 2, -3, 4]
print(np.square(a))  # [1, 4, 9, 16]
print(np.exp(a))  # [3.67879441e-01, 7.38905610e+00, 4.97870684e-02, 5.45981500e+01]
print(np.power(a, 3)) # [ -1, 8, -27, 64]

np.isnan()用於判斷陣列中哪些元素是空值

c = [1, np.nan, 3, 5]
print(np.isnan(c))  # [False, True, False, False]
np.sum(np.isnan(c))

np.where()可以對陣列進行篩選,有兩種用法:

1、np.where(condition, x, y):x, y是兩個陣列,condition指選擇條件,若滿足條件則輸出x,否則,輸出y;

2、np.where(condition):condition是一個條件,輸出陣列中滿足條件的下標。

a = [[1, 2], [3, 0]]
b = [[7, 8], [9, 1]]
c = [1, 2, 3, 4]
print(np.where([[True, False], [False, False]], a, b))  # [[1, 2], [9, 0]]
np.where(np.array(c)>2)
c = np.array(a)
np.where(c > 1)

輸出結果:

(array([0, 1], dtype=int64), array([1, 0], dtype=int64))

Numpy也實現了三角函式的計算,np.sin(),np.cos(),np.tan()

a = [-1, 2, -3, 4]
print(np.sin(a))  # [-0.84147098, 0.90929743, -0.14112001, -0.7568025 ]
print(np.cos(a))  # [ 0.54030231, -0.41614684, -0.9899925, -0.65364362]
print(np.tan(a))  # [-1.55740772, -2.18503986, 0.14254654, 1.15782128]

線性代數

NumPy的中的np.linalg模組實現了許多矩陣的基本操作,如:求對角線元素,求對角線元素的和(求跡)、矩陣乘積、求解矩陣行列式等。

首先生成兩個陣列,程式碼如下:

# 生成兩個陣列
a = [1, 2, 3]
b = [[1, 3, 9], [2, 7, 0], [4, 3, 2]]

透過np.diag(matrix),matirx為一個矩陣,當matrix為二維陣列時,以一維陣列的形式返回方陣的對角線;當matrix為一維陣列時,則返回非對角線元素均為0的方陣。

print(np.diag(a))  # [[1, 0, 0], [0, 2, 0], [0, 0, 3]]

print(np.diag(b))  # [1, 7, 2]

透過np.trace(),可以計算矩陣對角線元素的跡

print(np.trace(b))  # 10

透過np.dot()可以實現矩陣乘積

print(np.dot(b, a))  # [34, 16, 16]

透過np.det()可以計算矩陣的行列式

np.linalg.det(b)  # -196.00000000000009

np.linalg.eig()可以計算方陣的特徵值、特徵向量

eig = np.linalg.eig(b)
array([-4.40641364,  9.92452468,  4.48188896])
# 特徵值
eig[0]  # [-4.40641364, 9.92452468, 4.48188896]

# 特徵向量
eig[1]  # [[0.86881121, -0.6982852, 0.69750503], [-0.15233731,  -0.47753756, -0.55399068], [-0.47112676, -0.53325009, 0.4545119]]

np.linalg.inv()可以計算矩陣的逆

np.linalg.inv(b)  # [[-0.07142857, -0.10714286, 0.32142857], [0.02040816, 0.17346939, -0.09183673], [0.1122449, -0.04591837, -0.00510204]]

np.linalg.solve(A,b)可以求解線性方程組Ax=b,A為一個方陣

np.linalg.solve(b,a)  # [0.67857143, 0.09183673, 0.00510204]

np.linalg.svd(a, full_matrices = 1, compute_uv = 1)可以用於矩陣的奇異值分解,返回該矩陣的左奇異值(u)、奇異值(s)、右奇異值(v)

svd = np.linalg.svd(b)
svd

統計分析

1) 透過np.sum(a, axis)計算陣列a沿指定軸的和;

2) np.mean(a,axis)計算陣列a沿指定軸的平均值;

3) min(axis)和a.max(axis)用於獲取陣列a,沿指定軸的最小值和最大值;

4) np.std(a,axis)計算陣列a沿指定軸的標準差;

5) np.var(a,axis)計算陣列a沿指定軸的方差;

6) np.argmin(a,axis)和np.argmax(a,axis)分別用於獲取陣列a,沿指定軸的最小值和最大值的索引。

注:axis=None時,會返回所有元素的和;axis=0時,會沿著第0個維度(也就是列)的變化方向進行計算,即按列求和;axis=1時,則為按行求和,以此類推。

a = np.array([[1, 2, 3], [4, 5, 6]])
# 透過np.sum(a, axis)計算陣列a沿指定軸的和
print(np.sum(a))  # 21
print(np.sum(a, axis=0))  # [5, 7, 9]
#  np.mean(a,axis)計算陣列a沿指定軸的平均值
print(np.mean(a, axis=1))  # [2, 5]
# min(axis)和a.max(axis)用於獲取陣列a,沿指定軸的最小值和最大值
print(a.min(axis=0))  # [1, 2, 3]
#  np.std(a,axis)計算陣列a沿指定軸的標準差
print(np.std(a, axis=1))  # [0.81649658, 0.81649658]
#  np.argmin(a,axis)和np.argmax(a,axis)分別用於獲取陣列a,沿指定軸的最小值和最大值的索引
print(np.argmax(a, axis=1))  # [2, 2]

公眾號:愚生淺末

歡迎關注公眾號:愚生淺末
公眾號本文地址:https://mp.weixin.qq.com/s/EocThNWhQlI2zeLcUApsQQ

相關文章