1. 程式人生 > >[開源庫學習] Numpy日記 Section.2

[開源庫學習] Numpy日記 Section.2

前言

   最近開始學習Data anaysis,將numpy入門學習日記分享出來,也當做個記錄。

 【Numpy官網學習地址】:Click Here

   備註:

        我儘可能的將官網快速教程中的case都貼出來了,但越往下越發現這個庫是真的龐大,教程也是由淺及深,後面會涉及到向量、線性代數等高數概念,這個日記中不會提到,需要的話自行前往官網檢視。這個日記分為兩個Section,加起來可能佔到官網快速教程中的case的80%左右,入門Numpy足矣。

    

Numpy日記 Section.1

正文


#broadcast 機制
#一般來說,只有相同shape的ndarray物件才能進行算術運算,如下
a23 = np.array(range(3)) #[0  1  2]
a23_t = np.ones(3) # [1. 1. 1.]
#print(a23+a23_t)  # [1. 2. 3.]
#上面的需求很簡單,把一個數組物件的所有元素都加1,看不出什麼問題,如果現在要讓所有元素都*3
# 難道要建立一個np.array([3,3,3]),再去乘以a23嗎?當然不太科學,可以這樣實現
print(a23*3)  #同a23 * [3]
#這就是broadcast機制,numpy處理兩個形狀不同的陣列時,會將長度/維度較小的陣列按照較大的
# 陣列的尺寸進行“廣播”(可理解為擴張),這個例子中,[3] “廣播”成 [3,3,3],這是numpy的處理方法,但實際執行時
# 並不會真正的對陣列元素進行復制,所以執行效率高
a23_t1 = np.ones((2,3,4)) #三維陣列,3行4列
a23_t2 = np.ones((3,1)) #二維陣列,3行1列
a23_t3 = np.ones(3) #[1. 1. 1.]
a23_t4 = np.ones(4) #[1. 1. 1. 1.]

# print(a23_t2+a23_t1,111) #OK
# print(a23_t3+a23_t1,222) #拋異常,無法按照a23_t1的尺寸對a23_t3進行廣播
# print(a23_t4+a23_t1,333)  #OK
#廣播操作也有原則,不同維數(至少是一維,單個元素不算是一維陣列)陣列間的進行算術運算時,他們的列數必須相等,
# 也就是shape的最後一個值必須相等,否則無法進行運算
# 例外:單列多行的陣列(二維)可以與單行多列的陣列(一維)之間可以進行運算
a23_t5 = np.ones((2,1,4))
print(a23_t1+a23_t5,444)
a23_t6 = np.ones((2,3,3))
#print(a23_t1+a23_t6,555)  #丟擲異常

#幾個例子
t = np.arange(4) # shape = (4,) 單行4列
t1 = t.reshape(4,1) # shape = (4,1) 單列4行
v = np.ones(5) #shape = (5,) 單行5列
v1 = np.ones((3,4))  #shape = (3,4) 3行4列

#tv = t + v  # ERROR
t1v = t1 + v  #OK 印證上面提到的例外
tv1 = t + v1 #OK



#shape 變換
a24 = np.floor(10*np.random.random((3,4)))
#print(a24.shape)  #(3,4)
a24_flat = a24.ravel()  #無論幾維,均轉換為一維,等效於reshape(1,12)
#print(a24_flat) #[7. 9. 5. 3. 3. 1. 7. 5. 2. 1. 1. 0.]
#print(a24.reshape(6,2)) #列印臨時修改shape後的陣列,並不會修改原陣列的shape
print(a24)
print(a24.T)  #將多維陣列進行順時針旋轉90度(看起來像是這樣),shape引數對調

a24.resize((6,2)) #直接修改原陣列物件
print(a24)

print(a24.reshape(3,-1))  #若只想傳入一個尺寸引數,另一個自動計算,就可以用-1填充另一個引數的位置。



#ndarray物件的堆疊操作
# https://docs.scipy.org/doc/numpy/user/quickstart.html#stacking-together-different-arrays
a25 = np.ceil(10*np.random.random((2,2)))
print(a25)
a25_t = np.ceil(10*np.random.random((2,2)))
print(a25_t)
vertically_stacked = np.vstack((a25,a25_t))  #垂直堆疊
horizontally_stacked = np.hstack((a25,a25_t)) #水平堆疊

#column_stack方法: 水平堆疊二維陣列,或將一維陣列垂直堆疊後再self.transpose()得到一個二維陣列
print(np.column_stack((a25,a25_t)))
a25_t1 = np.array([1,0,2])
a25_t2 = np.array([2,3,1])
# print(np.column_stack((a25_t1,a25_t2)))
# print(np.vstack((a25_t1,a25_t2)).T)  #column_stack操作一維陣列時等效於此操作


#ndarray物件的分割操作:
# https://docs.scipy.org/doc/numpy/reference/generated/numpy.array_split.html#numpy.array_split
a26 = np.arange(8)
a26_t = np.array([ [1,23,2], [3,4,1], [2,2,2] ])
a26_vsplit = np.array_split(a26,3,axis=0) #[array([0, 1, 2]), array([3, 4, 5]), array([6, 7])]
a26_t_vsplit = np.array_split(a26_t,3,axis=0) # [array([[ 1, 23,  2]]), array([[3, 4, 1]]), array([[2, 2, 2]])]


#拷貝和檢視
# https://docs.scipy.org/doc/numpy/user/quickstart.html#copies-and-views
a27 = np.arange(12)
a27_t = a27   #這種操作不會建立新物件(不拷貝),兩個變數指向同一個物件
#但是修改任意一個變數會導致另一個變數也改變
print(a27 is a27_t)  #True
a27.resize((2,6))
print(a27.shape, a27_t.shape)  #(2, 6) (2, 6)

a27_t1 = a27.view() #檢視(淺拷貝):這個方法建立了新的物件,但兩個物件共享一份資料,其他屬性不相關
#建立了新的物件,意味著兩者互不相關
print(a27_t1 is a27, a27_t1.base is a27) #False, True
a27_t1.resize((3,4))
print(a27.shape, a27_t1.shape) #(2, 6) (3, 4)
a27[:] = 0
print(a27.ravel() == a27_t1.ravel()) #[True True ...(all True) ] 改變原物件的資料,新物件的資料也跟著改變了


a27_t2 = a27[:,:2] #分片操作不會建立新物件
a27_t2[:] = 666
print(a27)

a27_t3 = a27.copy() #深拷貝,完全建立一個新物件,與原物件毫不相關
print(a27_t3 is a27, a27_t3.base is a27) #False, False
a27[:] = 0
print(a27 == a27_t3)  #[(false)...]
a27_t3.resize((1,12))
print(a27.shape == a27_t3.shape)  #False



#結構化陣列:它也是ndarray物件,但其datatype是由命名欄位的序列組合構成的,這是原文直譯,需要結合例項理解
# https://docs.scipy.org/doc/numpy/user/basics.rec.html#structured-arrays

datatype = [('name','U10'), ('age','i4'), ('weight','f4')]
a28 = np.array([('eli',22,101.0), ('alex',30,140.5)], dtype=datatype)
print(a28, a28.dtype) #[('eli', 22, 101. ) ('alex', 30, 140.5)] \
# [('name', '<U10'), ('age', '<i4'), ('weight', '<f4')]
#這裡的a28是一個一維陣列,它的datatype是由三個欄位組成的結構化組合。
# U10:長度<=10的string,欄位名為name; i4: 4位元組的整數,欄位名為age; f4: 4位元組的浮點數,欄位名為weight

print(a28[1])  #('alex', 30, 140.5)  索引正常使用
print(a28['name'])  #['eli' 'alex']     使用欄位進行索引
a28['age'] = '66'  #利用索引修改資料
print(a28)  #[('eli', 66, 101. ) ('alex', 66, 140.5)]

#dtype可以使用np.dtype函式構造,它是由一系列元組組合成的list,一個欄位名佔一個元組
# 一個元組有三個引數(fieldname, datatype, shape),shape可選,shape可以是單獨一個元組
dtype = np.dtype([('name','S5'),('age', np.int32), ('weight', np.float32), ('location', 'f4', (2,))])
a28_t = np.array( [('lei',22,123.5,(3,4)), ('amor',25,140.1,(5,7))] ,dtype=dtype)
print(a28_t) #[(b'lei', 22, 123.5, [3., 4.]) (b'amor', 25, 140.1, [5., 7.])]

#快速建立dtype,欄位名會以'f#'的形式自動建立
dtype1 = np.dtype('i4,f4,S3')
print(dtype1)  #[('f0', '<i4'), ('f1', '<f4'), ('f2', '<U3')]
dtype2 = np.dtype('3int8, float32, (2,3)float64')
print(dtype2) #[('f0', 'i1', (3,)), ('f1', '<f4'), ('f2', '<f8', (2, 3))]
哪兒不對或者有疑問,各位老鐵可以留言,我會盡量回復。