1. 程式人生 > 其它 >Numpy基礎筆記

Numpy基礎筆記

Basic Numpy

ndarray物件基礎

什麼是ndarray物件?即是N-dimentional array,也就是n維陣列物件。

指定ndarray型別的物件——dtype(data type,就是n維陣列物件內的基本元素型別)

numpy陣列的基本知識

陣列的基本屬性

  1. shape屬性,即是陣列的形狀,用元組來描述(儲存著幾行幾列的資訊)
  2. axis屬性,即是陣列的軸,有0、1、2……軸(在引數列表中的axis代表著以哪個軸作為基準)
  3. ndim屬性,即是陣列的維數,用元組來表示(其實就是反映陣列有幾個軸)
  4. size屬性,返回陣列的長度(就是看數組裡面一共有多少基本元素,不要與len()函式返回值混淆,len與ndim返回值一致)
  5. dtype屬性,即是陣列元素的型別(也可以在外面直接創造複雜dtype型別,並把它與一個變數繫結,可以節省程式碼量)
  6. itemsize屬性,即是陣列中每個元素的長度(以位元組形式表示)

資料型別(主要在結構化陣列中應用)

全部資料型別

Python Data Analysis P34,不過一般很少使用

結構化陣列中的資料型別
bytes b1
int i1, i2, i4, i8
usigned ints u1, u2, u4, u8
floats f2, f4, f8
complex c8, c16
fixed length strings a

可以通過type函式來檢視元素型別

或檢視ndarray的dtype屬性


建立陣列(包含特殊陣列建立)

  1. arr = np.array([1, 2, 3]) 
    //array接收序列引數,通常用list, tuple(且他們地位等價,即互相巢狀可以換位)
    
  2.  np.arange(1, 100, 2) 
       //arange在給定範圍內生成一個一維陣列,為閉開區間,為比較常用的方法。
       //接收一個引數時預設從0開始,數字型引數-初始,結束,步長(步長可以為小數,與range不同,這十分特殊!!!!!)
       // 記住reshape函式!!!即可接收元組也可直接接受元組內的引數,通常使用
       c = np.arange(0, 16).reshape((4, 4)) 
       //reshape方法可以返回一個按引數指定形狀的多維陣列
       np.arange(0, 16).resize((4, 4)) 
       //resize方法與reshape方法的不同之處在於resize直接修改原物件,但是resize並不常用,我們希望物件更安全
       //但是reshape產生的新檢視,其實是一個引用,即使兩者形狀不一樣,但是他們指向記憶體的同一塊區域,如果要更改其中之一,請使用copy函式來避免這種事情發生
    
  3. arr = np.linspace(0, 10, 5) 
    //linspace函式接收:起始,結束,份數。它與arange相對應,只不過第三個引數從步長變為了份數
    //其餘像與shape, reshape方法的配合與arange一直(本質是對物件應用,只不過它們通常成對出現)
    // 其實linspace與arange是一樣的,只不過使用的方式略有區別而已
    // linspace中的重要引數,restep(導致linspace返回一個元組,前半部分是生成的array,後部分是步長),linspace與arange的不同之處在於
    linspace預設包括右端而arange並不是,可以通過將endpoint設定為False,就可不取右端點
    
  4.  //快速建立特殊陣列
     // 注意!zeros、ones、random只能接收元組類引數!注意與reshape、shape區別!
       // 零陣列
       np.zeros((3, 3))
       array([[0., 0., 0.],
              [0., 0., 0.],
              [0., 0., 0.]])
       //zeros_like函式!跟ones_like一模一樣
       
       //一陣列
       np.ones((3, 3))
       array([[1., 1., 1.],
              [1., 1., 1.],
              [1., 1., 1.]])
       arr = np.array([1, 2, 3])
       // one_like函式!可以根據已有陣列的形狀建立一陣列
       np.ones_like(arr)
       
       //隨機陣列
       np.random.random((3, 3))
       array([[0.23159009, 0.63306642, 0.63343724],
              [0.2765953 , 0.57742195, 0.3329211 ],
              [0.02730095, 0.86618645, 0.98329664]])
        
       // 建立一個空陣列(隨機分配的垃圾值)
       np.empty((2, 3))
       np.empty_like(arr)
       
       // 最一般的特殊陣列建立函式!full函式
       np.full(((2, 3), 7.1))
       // 建立一個2x3的7.1充滿的陣列
       np.full_like(arr, 7.1)
       //請注意,full_like函式在填充時會根據arr內型別進行型別轉換,比如arr的資料型別原來為int型,會將7.1變為7
        
       //建立diagnal(一般是主對角線)
       np.eye(5)
    [[1. 0. 0. 0. 0.]
     [0. 1. 0. 0. 0.]
     [0. 0. 1. 0. 0.]
     [0. 0. 0. 1. 0.]
     [0. 0. 0. 0. 1.]]
    
      eye的k引數,正數代表向右平移,負數代表向左平移(是指主對角線漂移)
      // 通過已有陣列建立元素型別不同的陣列
      arr = arr.astype(np.float)
    
  5. //建立結構化陣列示例
    // 我可能想複雜了,其實往往不需要在後面寫生dtype,除非有特殊需求
    
    structured = np.array([(1, 'First', 0.5, 1+2j), (2, 'Second', 1.3, 2-2j), (3, 'Third', 0.8, 1+3j)], 
                          dtype=[('id', 'i2'), ('position', 'a6'), ('value', 'f4'), ('complexs', 'c8')])
    //這樣就可以通過像字典一樣的形式來操作結構化陣列
    array([(1, b'First', 0.5, 1.+2.j), (2, b'Second', 1.3, 2.-2.j),
           (3, b'Third', 0.8, 1.+3.j)],
          dtype=[('id', '<i2'), ('position', 'S6'), ('value', '<f4'), ('complexs', '<c8')])
    
    // 另一種方法來制定各欄位名稱
    structured = np.array([(1, 'First', 0.5, 1+2j), (2, 'Second', 1.3, 2-2j), (3, 'Third', 0.8, 1+3j)], 
                          dtype=['i2', 'a6', 'f4', 'c8'])
    structured.dtype.names = ['id', 'position', 'value', 'complexs'] 
    //改變dtype屬性的names欄位,這是給列取名字!!!
    //這樣就可以像字典一樣使用了,
    
    //結構化陣列呼叫示例
    structured['id']
    

陣列的基本操作

運算的前提——廣播與廣播機制(umm……不太熟)

numpy可以實現元素級操作,同時numpy實現了對不同形狀物件的運算,這種機制稱為廣播

廣播機制:將兩種不同形狀的陣列物件進行元素級運算的預處理機制(也就是升維),分為兩個階段。

[1]. 判斷兩個陣列的各個維度是否相容,如果相容直接進行[2]。如果不相容,再判斷其中一個數組是否為一維,如果為一維也進行[2],否則不能進行.

[2]. 用已有的元素生成其他的元素

算數基本操作

算數運算子

+, -, *, /, %, **, //等所有算數運算子都是元素級運算子,結果返回新陣列

注意:python中的*指的是元素級乘法,採用dot方法計算矩陣積

特殊的運算子:+=,-=(自增、自減最常用)等某等運算子可以直接更改物件


通用函式與運算(Universal function)

通用函式是指元素級操作函式,可以抽象為f(arr)

其中較常用的為dot(矩陣積),等。讓人感動的是numpy重複實現了math庫中絕大多數函式,以靜態方法方式呼叫。

arr.T //陣列轉置
arr.flatten() //將陣列將為1維,返回新的副本(意味著直接返回全新的陣列物件,可以直接修改,注意這是與reshape不同的地方)
np.flat() //將陣列將為1維,返回一個1維迭代器,可以用for迴圈遍歷
arr.ravel() //將陣列將為1維,返回檢視(記憶體的位置是不變的!!!)
arr.astype(np.float) // 返回一個新陣列,將原陣列的資料經過float()處理
arr.swapaxes(ax1, ax2) // 將兩個維度互換(換軸)
arr.transpose() // 不帶引數時,效果相當於轉置
arr.transpose(2, 1, 0) // 相當於將arr的三個軸轉換到新位置
arr.tolist() //將ndarray轉換為列表,如果使用哦那個list()函式轉換,其實是相當於向量函式作用在ndarray上,是向量操作,打不傲tolist()的的效果
arr.tostring() // 將ndarray轉換為字串

// arr形狀轉換等其他實現參照建立陣列章節
聚合函式(Group function)

聚合函式是指對一組值(往往是一個數組)進行操作,返回單一值。

其中常用的有:sum, min, max, mean, std(標準差)

索引與切片(花式索引、布林索引)—— 需要更多的練習

索引的操作與標準庫中的list相同,一起回憶一下:

操作相同但是返回值型別有區別:list的切片得到副本,而陣列的切片得到檢視

副本可以理解為原物件變化不對副本產生影響(當然有深淺copy之分,這裡不贅述了),檢視就像是SQL資料庫中的檢視,原物件變化會導致檢視物件發生變化,倘若陣列想要得到副本可以使用例項方法copy來得到

//一維陣列索引示例 (在python中切片與索引(花式索引除外)返回的是副本,但在numpy中只返回檢視!!!需要用copy與deep copy來建立副本)
a = np.arange(10)
a[2] = 2 
a[-1] = 9 //反向索引也很常見,相當於從第一個元素反著查

//陣列切片示例(結果很顯然,不寫了)
a[:]
a[1:2] //閉開區間
a[1:]
a[:8]
a[1:9:2] //帶步長的切片
a[::-1] // 逆序地去除所有資料

//二維陣列切片示例(多維陣列以此類推)
A = np.array([range(10), range(10, 20)])
A[1, 2] // 選出第一行、第三列元素
A[1] //相當於選取第二行,當然還有更標準的寫法,見下一個
A[1,:] //選取第2行,這相當於是省略了1軸的操作,這個逗號甚至可以省掉
A[:,1] //選取第2列 切記!零軸空操作,就是指前面的那個冒號,是不能被省略的!
// 注意!!!A[1]這種索引式返回結果是降維後的結果!!!而切片式返回的陣列與原陣列位數相同
// 分別在0軸和1軸上切分,輸出為兩個軸切出的交集
A[0:2, 0:2] //選取一個子矩陣
// 索引與切片相結合,因為有索引所以降了一個維度哦!
A[1, :2]

// 花式索引!!!
// 還是索引產生的副本!!!這與其他的取法不同!!!
A[[1, 9]:2] //列表(序列均可)可選取我們要拿出來的單列,是花式索引!!!(花式索引甚至可以重複放並且支援負數) 
// 花式索引的另一種情況,將有高維數陣列作為索引傳入一維陣列,會得到與高維陣列相同形狀的切片!!!
arr = np.arange(9)
b = np.arange(4).reshape(2, 2)
arr[b]
// 花式索引應用在二維陣列(不熟)
arr = np.arange(15).reshape(4, 4)

// 布林索引,也就是布林陣列作為索引,只取出值為True對應的值(不熟)

// 不同種索引相互配合

陣列迭代

最初級的方法是使用foreach迴圈

更pythonic的方法是使用apply_along_axis()函式——直接對行、列整體進行操作

np.apply_along_axis(function, axis, arr)
//下面是對行求平均值的示例
np.apply_along_axis(np.mean, axis=1, arr=A)
//非常值得注意的地方!axis是along which axis的含義!尤其是之後的split都是這樣!
//被我們操作的函式可以是自己定義的

陣列篩選與bool陣列

A = np.arange(-8, 8).reshape((4, 4))

//array([[-8, -7, -6, -5],
//       [-4, -3, -2, -1],
//       [ 0,  1,  2,  3],
//       [ 4,  5,  6,  7]])

A[A > 0] //篩選出陣列中符合要求的元素,以一位陣列返回

A > 0 //相當於一個元素級操作,返回bool陣列

陣列的形狀變換

包括前面提到過的reshape, shape。

ravel方法可以得到二維陣列對應的一維陣列(返回新陣列)

transpose方法可以實現轉置以及換軸(返回新陣列)swapaxes也可以實現換軸

陣列切分

陣列的切分靠split族函式來實現:vsplit,hsplit,split

其實split完全可以代替vsplit與hsplit

//vertival split
[B, C] = np.vsplit(A, 2) //將A切為兩部分,預設沿著列
[B, C] = np.hsplit(A, 2) //將A切為兩部分,預設沿著行

//更為複雜但更靈活的split函式
[A1, A2, A3] = np.split(A, [1, 3], axis=1) //沿著1軸(就是沿著columns切)將A抽取[1, 3]後分成三部分

陣列拷貝

在numpy中唯一為ndarray建立副本的方法是使用copy方法

淺拷貝就是指直接的賦值 a = b

這與python不同,python的copy函式是淺拷貝,deepcopy函式才是深拷貝

陣列資料檔案的讀寫

numpy提供 save, load函式來儲存與讀取二進位制檔案,getfromtxt從文字檔案中讀取

data = np.random.random((3, 3))
np.save('sava_data', data) //將data存在save_data.npy檔案中,npy是預設儲存拓展名
dataget = np.load('save_data.npy') //讀取資料

//讀取文字檔案資料示例
data = getfromtxt('data.csv', delimiter=',', names=True) //delimiter是分隔符,由於為CSV檔案,分隔符自然為逗號
                                                         //names代表資料中是否含有標題
    													 //缺失的資料會被補成nan

事實上這些讀取的工作常常由pandas來操作