numpy的深复制与浅复制的区别_Python之Numpy基础,强大到让你五体投地
以前總認為Numpy是渣渣,直到深入接觸以后才知道功能這么強大??氨萂atlab啊。果然是人生苦短,我用Python,所以本文作為一個記錄&筆記,文章內容大多數取自網絡以&官網快速入門等(文末有參考鏈接,如有侵權請聯系本人改正),希望可以幫助大家快速入門Numpy。如果你有Matlab基礎,那么你能很快看懂本文!!!(本文長期更新!!!)
一個栗子
>>> import numpy as np>>> a = np.arange(15).reshape(3, 5)>>> aarray([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]])>>> a.shape(3, 5)>>> a.ndim # 數組軸的個數,在python的世界中,軸的個數被稱作秩2>>> a.dtype.name'int64'>>> a.itemsize # 數組中每個元素的字節大小。8>>> a.size15>>> type(a)>>> b = np.array([6, 7, 8])>>> barray([6, 7, 8])>>> type(b)創建矩陣
對于Python中的numpy模塊,一般用其提供的ndarray對象。 創建一個ndarray對象很簡單,只要將一個list作為參數即可。 例如:
>>> import numpy as np#創建一維的narray對象>>> a = np.array([2,3,4])>>> aarray([2, 3, 4])>>> a.dtypedtype('int64')# 浮點類型>>> b = np.array([1.2, 3.5, 5.1])>>> b.dtypedtype('float64')#創建二維的narray對象>>>a2 = np.array([[1,2,3,4,5],[6,7,8,9,10]])>>> b = np.array([(1.5,2,3), (4,5,6)]) # 使用的是元組>>> barray([[ 1.5, 2. , 3. ], [ 4. , 5. , 6. ]])# The type of the array can also be explicitly specified at creation time:>>> c = np.array( [ [1,2], [3,4] ], dtype=complex )>>> carray([[ 1.+0.j, 2.+0.j], [ 3.+0.j, 4.+0.j]])矩陣行數列數
import numpy as npa = np.array([[1,2,3,4,5],[6,7,8,9,10]])print(a.shape) #結果返回一個tuple元組 (2, 5) 2行,5列print(a.shape[0]) #獲得行數,返回 2print(a.shape[1]) #獲得列數,返回 5矩陣按行列選取
矩陣的截取和list相同,可以通過[](方括號)來截取
import numpy as npa = np.array([[1,2,3,4,5],[6,7,8,9,10]])print(a[0:1]) #截取第一行,返回 [[1 2 3 4 5]]print(a[1,2:5]) #截取第二行,第三、四、五列,返回 [8 9 10]print(a[1,:]) #截取第二行,返回 [ 6 7 8 9 10]矩陣按條件截取
import numpy as npa = np.array([[1,2,3,4,5],[6,7,8,9,10]])b = a[a>6] # 截取矩陣a中大于6的元素,返回的是一維數組print(b) # 返回 [ 7 8 9 10]# 其實布爾語句首先生成一個布爾矩陣,將布爾矩陣傳入[](方括號)實現截取print(a>6) # 返回[[False False False False False] [False True True True True]]按條件截取應用較多的是對矩陣中滿足一定條件的元素變成特定的值。 例如將矩陣中大于6的元素變成0。
import numpy as npa = np.array([[1,2,3,4,5],[6,7,8,9,10]])print(a)#開始矩陣為[[ 1 2 3 4 5] [ 6 7 8 9 10]]a[a>6] = 0print(a)#大于6清零后矩陣為[[1 2 3 4 5] [6 0 0 0 0]]Stacking together different arrays
矩陣的合并可以通過numpy中的hstack方法和vstack方法實現:
>>> a = np.floor(10*np.random.random((2,2)))>>> aarray([[ 8., 8.], [ 0., 0.]])>>> b = np.floor(10*np.random.random((2,2)))>>> barray([[ 1., 8.], [ 0., 4.]])>>> np.vstack((a,b))array([[ 8., 8.], [ 0., 0.], [ 1., 8.], [ 0., 4.]])>>> np.hstack((a,b))array([[ 8., 8., 1., 8.], [ 0., 0., 0., 4.]])- 矩陣的合并也可以通過concatenatef方法。
- np.concatenate( (a1,a2), axis=0 ) 等價于 np.vstack( (a1,a2) )
- np.concatenate( (a1,a2), axis=1 ) 等價于 np.hstack( (a1,a2) )
通過函數創建矩陣
arange
import numpy as npa = np.arange(10) # 默認從0開始到10(不包括10),步長為1print(a) # 返回 [0 1 2 3 4 5 6 7 8 9]a1 = np.arange(5,10) # 從5開始到10(不包括10),步長為1print(a1) # 返回 [5 6 7 8 9]a2 = np.arange(5,20,2) # 從5開始到20(不包括20),步長為2print(a2) # 返回 [ 5 7 9 11 13 15 17 19]linspace/ logspace
import numpy as np# 類似于matlaba = np.linspace(0,10,7) # 生成首位是0,末位是10,含7個數的等差數列print(a) # 結果 [ 0. 1.66666667 3.33333333 5. 6.66666667 8.33333333 10. ]>>> a = np.ones(3, dtype=np.int32)>>> b = np.linspace(0,pi,3)>>> b.dtype.name'float64'>>> c = a+b>>> carray([ 1. , 2.57079633, 4.14159265])>>> c.dtype.name'float64'>>> d = np.exp(c*1j)>>> darray([ 0.54030231+0.84147098j, -0.84147098+0.54030231j, -0.54030231-0.84147098j])>>> d.dtype.name'complex128'ones、zeros、eye、empty
ones創建全1矩陣 ,zeros創建全0矩陣 ,eye創建單位矩陣 ,empty創建空矩陣(實際有值)
import numpy as npa_ones = np.ones((3,4)) # 創建3*4的全1矩陣print(a_ones)# 結果[[ 1. 1. 1. 1.] [ 1. 1. 1. 1.] [ 1. 1. 1. 1.]]>>> np.ones((2,3,4), dtype=np.int16 ) # dtype can also be specifiedarray([[[ 1, 1, 1, 1], [ 1, 1, 1, 1], [ 1, 1, 1, 1]], [[ 1, 1, 1, 1], [ 1, 1, 1, 1], [ 1, 1, 1, 1]]], dtype=int16)a_zeros = np.zeros((3,4)) # 創建3*4的全0矩陣print(a_zeros)# 結果[[ 0. 0. 0. 0.] [ 0. 0. 0. 0.] [ 0. 0. 0. 0.]]a_eye = np.eye(3) # 創建3階單位矩陣print(a_eye)# 結果[[ 1. 0. 0.] [ 0. 1. 0.] [ 0. 0. 1.]]a_empty = np.empty((3,4)) # 創建3*4的空矩陣 print(a_empty)# 結果[[ 1.78006111e-306 -3.13259416e-294 4.71524461e-309 1.94927842e+289] [ 2.10230387e-309 5.42870216e+294 6.73606381e-310 3.82265219e-297] [ 6.24242356e-309 1.07034394e-296 2.12687797e+183 6.88703165e-315]]# 有些矩陣太大,如果不想省略中間部分,通過set_printoptions來強制NumPy打印所有數據。>>> np.set_printoptions(threshold='nan')fromstring
fromstring()方法可以將字符串轉化成ndarray對象,需要將字符串數字化時這個方法比較有用,可以獲得字符串的ascii碼序列。
import numpy as npa = "abcdef"b = np.fromstring(a,dtype=np.int8) # 因為一個字符為8位,所以指定dtype為np.int8print(b) # 返回 [ 97 98 99 100 101 102]random
>>> a = np.random.random((2,3)) # 產生2行,3列的隨機矩陣 >>> aarray([[ 0.18626021, 0.34556073, 0.39676747], [ 0.53881673, 0.41919451, 0.6852195 ]])fromfunction
fromfunction()方法可以根據矩陣的行號列號生成矩陣的元素。 例如創建一個矩陣,矩陣中的每個元素都為行號和列號的和。
import numpy as npdef func(i,j): return i+ja = np.fromfunction(func,(5,6)) # 第一個參數為指定函數,第二個參數為列表list或元組tuple,說明矩陣的大小print(a)# 返回[[ 0. 1. 2. 3. 4. 5.] [ 1. 2. 3. 4. 5. 6.] [ 2. 3. 4. 5. 6. 7.] [ 3. 4. 5. 6. 7. 8.] [ 4. 5. 6. 7. 8. 9.]]#注意這里行號的列號都是從0開始的矩陣的運算
常用矩陣運算符
Numpy中的ndarray對象重載了許多運算符,使用這些運算符可以完成矩陣間對應元素的運算。
運算符說明+矩陣對應元素相加-矩陣對應元素相減*矩陣對應元素相乘/矩陣對應元素相除,如果都是整數則取商%矩陣對應元素相除后取余數**矩陣每個元素都取n次方,如**2:每個元素都取平方
import numpy as npa1 = np.array([[4,5,6],[1,2,3]])a2 = np.array([[6,5,4],[3,2,1]])print(a1+a2) # 相加# 結果[[10 10 10] [ 4 4 4]]print(a1/a2) # 整數相除取商# 結果[[0 1 1] [0 1 3]]print(a1%a2) # 相除取余數# 結果[[4 0 2] [1 0 0]]常用矩陣函數
同樣地,numpy中也定義了許多函數,使用這些函數可以將函數作用于矩陣中的每個元素。 表格中默認導入了numpy模塊,即 import numpy as np 。a為ndarray對象。
常用矩陣函數說明np.sin(a)對矩陣a中每個元素取正弦,sin(x)np.cos(a)對矩陣a中每個元素取余弦,cos(x)np.tan(a)對矩陣a中每個元素取正切,tan(x)np.arcsin(a)對矩陣a中每個元素取反正弦,arcsin(x)np.arccos(a)對矩陣a中每個元素取反余弦,arccos(x)np.arctan(a)對矩陣a中每個元素取反正切,arctan(x)np.exp(a)對矩陣a中每個元素取指數函數,exnp.sqrt(a)對矩陣a中每個元素開根號
- 當矩陣中的元素不在函數定義域范圍內,會產生RuntimeWarning,結果為nan(not a number)
矩陣乘法(點乘)
矩陣乘法必須滿足矩陣乘法的條件,即第一個矩陣的列數等于第二個矩陣的行數。 矩陣乘法的函數為 dot 。
import numpy as npa1 = np.array([[1,2,3],[4,5,6]]) # a1為2*3矩陣a2 = np.array([[1,2],[3,4],[5,6]]) # a2為3*2矩陣print(a1.shape[1]==a2.shape[0]) # True, 滿足矩陣乘法條件print(a1.dot(a2)) # a1.dot(a2)相當于matlab中的a1*a2# 而Python中的a1*a2相當于matlab中的a1.*a2# 結果[[22 28] [49 64]]矩陣的轉置 a.T
import numpy as npa = np.array([[1,2,3],[4,5,6]])print(a.transpose())# 結果[[1 4] [2 5] [3 6]]矩陣的轉置還有更簡單的方法,就是a.T。
import numpy as npa = np.array([[1,2,3],[4,5,6]])print(a.T)# 結果[[1 4] [2 5] [3 6]]矩陣的逆
設A是數域上的一個n階方陣,若在相同數域上存在另一個n階矩陣B,使得: AB=BA=E。 則我們稱B是A的逆矩陣,而A則被稱為可逆矩陣。
求矩陣的逆需要先導入numpy.linalg,用linalg的inv函數來求逆。矩陣求逆的條件是矩陣應該是方陣。
import numpy as npimport numpy.linalg as lga = np.array([[1,2,3],[4,5,6],[7,8,9]])print(lg.inv(a))# 結果[[ -4.50359963e+15 9.00719925e+15 -4.50359963e+15] [ 9.00719925e+15 -1.80143985e+16 9.00719925e+15] [ -4.50359963e+15 9.00719925e+15 -4.50359963e+15]]a = np.eye(3) # 3階單位矩陣print(lg.inv(a)) # 單位矩陣的逆為他本身# 結果[[ 1. 0. 0.] [ 0. 1. 0.] [ 0. 0. 1.]]矩陣信息獲取(如均值等)
最值
獲得矩陣中元素最大最小值的函數分別是max和min,可以獲得整個矩陣、行或列的最大最小值。
import numpy as npa = np.array([[1,2,3],[4,5,6]])print(a.max()) #獲取整個矩陣的最大值 結果: 6print(a.min()) #結果:1# 可以指定關鍵字參數axis來獲得行最大(小)值或列最大(小)值# axis=0 行方向最大(小)值,即獲得每列的最大(小)值# axis=1 列方向最大(小)值,即獲得每行的最大(小)值# 例如print(a.max(axis=0))# 結果為 [4 5 6]print(a.max(axis=1))# 結果為 [3 6]# 要想獲得最大最小值元素所在的位置,可以通過argmax函數來獲得print(a.argmax(axis=1))# 結果為 [2 2]平均值
獲得矩陣中元素的平均值可以通過函數mean()。同樣地,可以獲得整個矩陣、行或列的平均值。
import numpy as npa = np.array([[1,2,3],[4,5,6]])print(a.mean()) #結果為: 3.5# 同樣地,可以通過關鍵字axis參數指定沿哪個方向獲取平均值print(a.mean(axis=0)) # 結果 [ 2.5 3.5 4.5]print(a.mean(axis=1)) # 結果 [ 2. 5.]方差
方差的函數為var(),方差函數var()相當于函數mean(abs(x - x.mean())**2),其中x為矩陣。
import numpy as npa = np.array([[1,2,3],[4,5,6]])print(a.var()) # 結果 2.91666666667print(a.var(axis=0)) # 結果 [ 2.25 2.25 2.25]print(a.var(axis=1)) # 結果 [ 0.66666667 0.66666667]標準差
標準差的函數為std()。 std()相當于sqrt(mean(abs(x - x.mean())**2)),或相當于sqrt(x.var())。
import numpy as npa = np.array([[1,2,3],[4,5,6]])print(a.std()) # 結果 1.70782512766print(a.std(axis=0)) # 結果 [ 1.5 1.5 1.5]print(a.std(axis=1)) # 結果 [ 0.81649658 0.81649658]中值
中值指的是將序列按大小順序排列后,排在中間的那個值,如果有偶數個數,則是排在中間兩個數的平均值。中值的函數是median(),調用方法為numpy.median(x,[axis]),axis可指定軸方向,默認axis=None,對所有數取中值。
import numpy as npx = np.array([[1,2,3],[4,5,6]])print(np.median(x)) # 對所有數取中值# 結果3.5print(np.median(x,axis=0)) # 沿第一維方向取中值# 結果[ 2.5 3.5 4.5]print(np.median(x,axis=1)) # 沿第二維方向取中值# 結果[ 2. 5.]求和
矩陣求和的函數是sum(),可以對行,列,或整個矩陣求和
import numpy as npa = np.array([[1,2,3],[4,5,6]])print(a.sum()) # 對整個矩陣求和# 結果 21print(a.sum(axis=0)) # 對行方向求和# 結果 [5 7 9]print(a.sum(axis=1)) # 對列方向求和# 結果 [ 6 15]累積和
某位置累積和指的是該位置之前(包括該位置)所有元素的和。例如序列[1,2,3,4,5],其累計和為[1,3,6,10,15],即第一個元素為1,第二個元素為1+2=3,……,第五個元素為1+2+3+4+5=15。矩陣求累積和的函數是cumsum(),可以對行,列,或整個矩陣求累積和。
import numpy as npa = np.array([[1,2,3],[4,5,6]])print(a.cumsum()) # 對整個矩陣求累積和# 結果 [ 1 3 6 10 15 21]print(a.cumsum(axis=0)) # 對列方向求累積和# 結果[[1 2 3] [5 7 9]]print( a.cumsum(axis=1)) # 對行方向求累積和# 結果[[ 1 3 6] [ 4 9 15]]極差
>>>import numpy as np>>>a = np.arange(10)>>>a.ptp()# 結果是9百分位數
numpy.percentile(a, q, axis)序號參數及描述1.a 輸入數組2.q 要計算的百分位數,在 0 ~ 100 之間3.axis 沿著它計算百分位數的軸
加權平均值
>>> data = range(1,5)>>> data[1, 2, 3, 4]>>> np.average(data)2.5>>> np.average(range(1,11), weights=range(10,0,-1))4.0>>> data = np.arange(6).reshape((3,2))>>> dataarray([[0, 1], [2, 3], [4, 5]])>>> np.average(data, axis=1, weights=[1./4, 3./4])array([ 0.75, 2.75, 4.75])>>> np.average(data, weights=[1./4, 3./4])Traceback (most recent call last):...TypeError: Axis must be specified when shapes of a and weights differ.Shape Manipulation
Changing the shape of an array
>>> a = np.floor(10*np.random.random((3,4)))>>> aarray([[ 2., 8., 0., 6.], [ 4., 5., 1., 1.], [ 8., 9., 3., 6.]])>>> a.shape(3, 4)數組的形狀可以用以下方式改變。Note that the following three commands all return a modified array, but do not change the original array:
>>> a.ravel() # returns the array, flattenedarray([ 2., 8., 0., 6., 4., 5., 1., 1., 8., 9., 3., 6.])>>> a.reshape(6,2) # returns the array with a modified shapearray([[ 2., 8.], [ 0., 6.], [ 4., 5.], [ 1., 1.], [ 8., 9.], [ 3., 6.]])>>> a.T # returns the array, transposedarray([[ 2., 4., 8.], [ 8., 5., 9.], [ 0., 1., 3.], [ 6., 1., 6.]])>>> a.T.shape(4, 3)>>> a.shape(3, 4)The reshape function returns its argument with a modified shape, whereas thendarray.resize method modifies the array itself:
>>> aarray([[ 2., 8., 0., 6.], [ 4., 5., 1., 1.], [ 8., 9., 3., 6.]])>>> a.resize((2,6))>>> aarray([[ 2., 8., 0., 6., 4., 5.], [ 1., 1., 8., 9., 3., 6.]])If a dimension is given as -1 in a reshaping operation, the other dimensions are automatically calculated:
>>> a.reshape(3,-1)array([[ 2., 8., 0., 6.], [ 4., 5., 1., 1.], [ 8., 9., 3., 6.]])Splitting one array into several smaller ones
Using hsplit, you can split an array along its horizontal axis, either by specifying the number of equally shaped arrays to return, or by specifying the columns after which the division should occur:
>>> a = np.floor(10*np.random.random((2,12)))>>> aarray([[ 9., 5., 6., 3., 6., 8., 0., 7., 9., 7., 2., 7.], [ 1., 4., 9., 2., 2., 1., 0., 6., 2., 2., 4., 0.]])>>> np.hsplit(a,3) # Split a into 3[array([[ 9., 5., 6., 3.], [ 1., 4., 9., 2.]]), array([[ 6., 8., 0., 7.], [ 2., 1., 0., 6.]]), array([[ 9., 7., 2., 7.], [ 2., 2., 4., 0.]])]Copies and Views
When operating and manipulating arrays, their data is sometimes copied into a new array and sometimes not. This is often a source of confusion for beginners. There are three cases:
No Copy At All
a = b,改變b就相當于改變a,或者相反。
>>> a = np.arange(12)>>> b = a # no new object is created>>> b is a # a and b are two names for the same ndarray objectTrue>>> b.shape = 3,4 # changes the shape of a>>> a.shape(3, 4)View or Shallow Copy
Different array objects can share the same data. The view method creates a new array object that looks at the same data.
>>> c = a.view()>>> c is aFalse>>> c.base is a # c is a view of the data owned by aTrue>>> c.flags.owndataFalse>>>>>> c.shape = 2,6 # a's shape doesn't change>>> a.shape(3, 4)>>> c[0,4] = 1234 # a's data changes>>> aarray([[ 0, 1, 2, 3], [1234, 5, 6, 7], [ 8, 9, 10, 11]])Slicing an array returns a view of it:
>>> s = a[:,1:3] # spaces added for clarity; could also be written "s = a[:,1:3]">>> s[:] = 10 # s[:] is a view of s. Note the difference between s=10 and s[:]=10>>> aarray([[ 0, 10, 10, 3], [1234, 10, 10, 7], [ 8, 10, 10, 11]])Deep Copy
The copy method makes a complete copy of the array and its data.
>>> d = a.copy() # a new array object with new data is created>>> d is aFalse>>> d.base is a # d doesn't share anything with aFalse>>> d[0,0] = 9999>>> aarray([[ 0, 10, 10, 3], [1234, 10, 10, 7], [ 8, 10, 10, 11]])numpy關于copy有三種情況,完全不復制、視圖(view)或者叫淺復制(shadow copy)和深復制(deep copy)。而b = a[:]就屬于第二種,即視圖,這本質上是一種切片操作(slicing),所有的切片操作返回的都是視圖。具體來說,b = a[:]會創建一個新的對象b(所以說 id 和a不一樣),但是b的數據完全來自于a,和a保持完全一致,換句話說,b的數據完全由a保管,他們兩個的數據變化是一致的,可以看下面的示例:
a = np.arange(4) # array([0, 1, 2, 3])b = a[:] # array([0, 1, 2, 3])b.flags.owndata # 返回 False,b 并不保管數據a.flags.owndata # 返回 True,數據由 a 保管# 改變 a 同時也影響到 ba[-1] = 10 # array([0, 1, 2, 10])b # array([0, 1, 2, 10])# 改變 b 同時也影響到 ab[0] = 10 # array([10, 1, 2, 10])a # array([10, 1, 2, 10])b = a 和 b = a[:] 的差別就在于后者會創建新的對象,前者不會。兩種方式都會導致a和b的數據相互影響。要想不讓a的改動影響到b,可以使用深復制:unique_b = a.copy()
曼德勃羅
import numpy as npimport matplotlib.pyplot as pltdef mandelbrot( h,w, maxit=20 ): """Returns an image of the Mandelbrot fractal of size (h,w).""" y,x = np.ogrid[ -1.4:1.4:h*1j, -2:0.8:w*1j ] c = x+y*1j z = c divtime = maxit + np.zeros(z.shape, dtype=int) for i in range(maxit): z = z**2 + c diverge = z*np.conj(z) > 2**2 # who is diverging div_now = diverge & (divtime==maxit) # who is diverging now divtime[div_now] = i # note when z[diverge] = 2 # avoid diverging too much return divtimeplt.imshow(mandelbrot(400,400))plt.show()參考文獻:
1. numpy庫:常用基本 - smallpi - 博客園
2. Quickstart tutorial
總結
以上是生活随笔為你收集整理的numpy的深复制与浅复制的区别_Python之Numpy基础,强大到让你五体投地的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 寺库宣布将 ChatGPT 与奢侈品业务
- 下一篇: 车库遥控器丢了怎么配