Numpy的使用

<span id="test">參考內(nèi)容</span>
Numpy是python中高效導(dǎo)入、處理、存儲、運(yùn)算數(shù)據(jù)的包。它的底層語言是C語言。這里,主要介紹Numpy的一些基本操作。深入學(xué)習(xí)請查看官方文檔。

主要內(nèi)容:

  • 數(shù)據(jù)類型
  • 數(shù)據(jù)訪問
  • 高效函數(shù)
  • 布爾蒙版 和 花式索引
  • 結(jié)構(gòu)體

導(dǎo)入Numpy和查看介紹

import numpy as np
In [1]: np.<TAB>
In [2]: ?np

python里的數(shù)據(jù)類型

不同于其他語言的數(shù)據(jù)類型(比如C語言),變量賦值前必須定義類型。python的數(shù)據(jù)類型是動態(tài)類型,隨用隨取。

// C code
int sum = 0;
for(int i=0, i<=100,i++)
{ sum+=i;}
#python code
for i in range(100):
     sum+=i

一個python數(shù)據(jù)類型的整數(shù)不僅僅是一個數(shù)字,它還包括ob_refcnt ob_type ob_size ob_digit
而C語言就沒這么多存儲的東西,給你分配一個32字節(jié)的地址,就完事。這也就是python語言慢的原因之一。

python中的list 也不僅僅是一個 list
它存儲的每一個數(shù)據(jù)都是指向?qū)ο蟮牡刂?,而每一個對象都是(和上述的一樣)存儲了一堆數(shù)據(jù),而C語言的數(shù)組在定義時就指定了類型,每個數(shù)據(jù)都是指向數(shù)據(jù)本身。因此python列表可以存儲混合結(jié)構(gòu)。

In [10] : L3 = [True, "2", 3.0, 4]
In [11] : [type(item) for item in L3]
Out[11] : [bool, str, float, int]

為了提高運(yùn)算速率,python里有了array基礎(chǔ)模塊,拋棄了list里存儲的冗雜信息,存儲單一的類型(需指定,或者類型提升)

import array
L = list(range(10)
A = array.array('i',L)
A

結(jié)果:array('i', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
i 代表整數(shù)類型。

但是僅僅這樣還是不夠,array太基礎(chǔ)了,我們需要做一些運(yùn)算時不太方便,比如加和,長度,維度,長度,等。于是有了 numpy.

從列表list創(chuàng)建數(shù)組array

# integer array:
np.array([1, 4, 2, 5, 3])

array([1, 4, 2, 5, 3])

隱式轉(zhuǎn)換

np.array([3.14, 4, 2, 3])

顯式轉(zhuǎn)換

np.array([3.14, 4, 2, 3],dtype='float32')

使用列表生成式

np.array([range(i-1, i + 3) for i in [4, 4, 6]])

array([[3, 4, 5, 6],
[3, 4, 5, 6],
[5, 6, 7, 8]])

也可以使用函數(shù)快速生成

如果使用過matlab或者octave那么對這些肯定很熟悉。

  • 生成0矩陣
  • 生成單位矩陣
  • 生成對角矩陣
  • 生成滿矩陣
  • 生成等距向量
  • 生成隨機(jī)矩陣
  • 生成正態(tài)矩陣
np.zeros((3,3),dtype='int'))
np.ones((3,4),dtype='float32')
np.eyes((3,3),dtype='int')
np.full((3,5),1,2)
np.linspace(0,0.1,5)
np.random.random((3,3))
np.random.normal(0,1,(3,3))
np.random.randint(0,10,(3,3))

介紹numpy的一些標(biāo)準(zhǔn)數(shù)據(jù)類型

bool_
int_
intc
intp
int8
int16
int32
int 64
uint8
uint16
float32
complex64
后面的數(shù)字表示位數(shù),在計算機(jī)中用多少位來存儲,前面的表示類型。_等同于64位.

numpy的基本介紹

numpy數(shù)組的屬性

使用 當(dāng) x是一個numpy類型的數(shù)組時,x.<tab>即可查看。

x.ndim 矩陣的維度
x.shape 矩陣每個維度的大小
x.size 矩陣的個數(shù)大小
x.dtype 矩陣的數(shù)據(jù)類型
x.itemsize 矩陣的每個對象的大小
x.nbypes 矩陣的存儲總大小 #x.nbypes = x.itemsizexsize

切片

如何訪問數(shù)組?

x1 = arange(10)
x1[1]#第二個數(shù)
x1[-1]#倒數(shù)第一個數(shù)
x2 = np.random.randint(10,(3,3))
x2[2,2]
x2[-1,-1]

切片

x = np.arange(10)
x[:5] #第一個到第五個
x[3:] #第三個之后
x[2:-1]#第二個到倒數(shù)第一個
x[from:to:setp]#開始的index,結(jié)束的index,以及步長 缺省就是開始和結(jié)束和1
#二維
x2[::2,::1]#和一維相同,推廣一下

復(fù)制數(shù)組
當(dāng)我們切出子數(shù)組時,他只是原數(shù)組的指針,如果改變了子數(shù)組,原數(shù)組也會改變。

>>>print(x2)
[[12  5  2  4]
 [ 7  6  8  8]
 [ 1  6  7  7]]
>>>x2_sub = x2[:2, :2]
>>>print(x2_sub)
>>>x2_sub[0, 0] = 99
>>>print(x2_sub)
[[99  5]
 [ 7  6]]
>>>print(x2)
[[99  5  2  4]
 [ 7  6  8  8]
 [ 1  6  7  7]]
=====
需要使用copy()函數(shù)
=====
>>>x2_sub_copy = x2[:2, :2].copy()
>>>print(x2_sub_copy)
[[99  5]
 [ 7  6]]
>>>x2_sub_copy[0, 0] = 42
>>>print(x2_sub_copy)
[[42  5]
 [ 7  6]]
>>>print(x2)
[[99  5  2  4]
 [ 7  6  8  8]
 [ 1  6  7  7]]

數(shù)組重塑

x.reshape((3,3))
注意:前提是變換前后的數(shù)組大小相同

在這里,介紹另一個常見的表達(dá),如果是一個一維的向量想變成二維的行矩陣或者列矩陣,可以使用 x.reshape(1,n) or x.reshape(n,1) ,也可以使用更簡單的表達(dá)式: x[np.newaxis,:],x[:,np.newaxis] 同樣的效果。

數(shù)組拼接

np.concatenate()
np.hstack() 垂直堆棧
np.vstack() 水平堆棧
ps : np.dstack() 第三維連接

x = np.array([1, 2, 3])
y = np.array([3, 2, 1])
np.concatenate([x, y])

數(shù)組切割

np.split()
np.hsplit()
np.vsplit()
Ps: np.dsplit()

>>>grid = np.arange(16).reshape((4, 4))
>>>grid
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])
>>>upper, lower = np.vsplit(grid, [2])#上下分割
>>>left, right = np.hsplit(grid, [2])# 左右分割

numpy的數(shù)值運(yùn)算函數(shù)

使用循環(huán)來計算是非常慢的,numpy提供了很多底層語言寫的優(yōu)化函數(shù)來加快計算。被稱為普遍函數(shù)。

在numpy中使用數(shù)組運(yùn)算十分自然,不需要你特別處理,已經(jīng)被優(yōu)化了。
使用運(yùn)算符

+
-
*
/
//   #整除
**  #平方
%  #余數(shù)

也可以使用函數(shù):

operator 等效函數(shù) 描述
+ np.add() 相加 1+1=2
- np.substract() 相減 3-2=1
- np.negative() 負(fù)數(shù) -2
* np.multiply() 相乘 2*2=4
/ np.divide() 相除 4 / 2 = 2
// np.floor_divide() 整除 5 / 2 = 2
** np.power() 平方 2** = 4
% np.mod() 取模 或 求余 9%4=1

其他函數(shù):

np.abs()
np.log()
np.exp()
np.exp2()
np.sin()
np.arcsin()
np.log()
np.log1p()
and more

一些更特殊的運(yùn)算可以導(dǎo)入scipy包

from scipy import special
special.gamma(x)#伽瑪分布
special.erf(x)#高斯分布
更多查看文檔

output的妙用
在函數(shù)運(yùn)算中可以加上out參數(shù),直接輸出到一個變量中。

y = np.zeros(10)
np.power(2, x, out=y[::2])
>>> print(y)

[  1.   0.   2.   0.   4.   0.   8.   0.  16.   0.]

累加,累乘,對應(yīng)乘
reduce accumulate
可以直接使用以下函數(shù)
np.sum, np.prod, np.cumsum, np.cumprod

>>> x = np.arange(1, 8)
>>> np.add.reduce(x)
28
>>> np.multiply.reduce(x)
5040
>>> np.add.accumulate(x)
array([ 1,  3,  6, 10, 15, 21, 28], dtype=int32)
>>> np.multiply.accumulate(x)
array([   1,    2,    6,   24,  120,  720, 5040], dtype=int32)
#每一項對應(yīng)乘 1*1 1*2 1*3... 2*1 2*2 ....
>>> x = np.arange(1, 6)
>>> np.multiply.outer(x, x)
array([[ 1,  2,  3,  4,  5],
       [ 2,  4,  6,  8, 10],
       [ 3,  6,  9, 12, 15],
       [ 4,  8, 12, 16, 20],
       [ 5, 10, 15, 20, 25]])

聚合函數(shù) max,min,等統(tǒng)計函數(shù)

首先,不使用 numpy包也能計算求和,最大值,最小值,但是,使用np的方法可以減少執(zhí)行時間。

import numpy as np
big_array = np.random.rand(1000000)
%timeit sum(big_array)
%timeit np.sum(big_array)
#比較不同
10 loops, best of 3: 104 ms per loop
1000 loops, best of 3: 442 μs per loop

最大值,最小值

min(big_array), max(big_array)
np.min(big_array), np.max(big_array)
%timeit min(big_array)
%timeit np.min(big_array)
63.7 ms ± 1.17 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
499 μs ± 7.58 μs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

對于多維數(shù)組,可以指定計算的方向,默認(rèn)為所有的數(shù)據(jù)。
axis=0 行方向 axis=1 列方向

其他聚合函數(shù)

Function Name NaN-safe Version Description
np.sum np.nansum Compute sum of elements
np.prod np.nanprod Compute product of elements
np.mean np.nanmean Compute mean of elements
np.std np.nanstd Compute standard deviation
np.var np.nanvar Compute variance
np.min np.nanmin Find minimum value
np.max np.nanmax Find maximum value
np.argmin np.nanargmin Find index of minimum value
np.argmax np.nanargmax Find index of maximum value
np.median np.nanmedian Compute median of elements
np.percentile np.nanpercentile Compute rank-based statistics of elements
np.any N/A Evaluate whether any elements are true
np.all N/A Evaluate whether all elements are true

所謂的 NaN-safe 版本意思是該函數(shù)可以忽略NaN值,更加安全。

廣播數(shù)組運(yùn)算

numpy的通用函數(shù)增加了我們計算的能力,廣播數(shù)組運(yùn)算也稍微提升了運(yùn)算能力。據(jù)我了解,我還沒有在其他語言碰到這種簡化。

數(shù)組廣播的規(guī)矩:
NumPy中的廣播遵循一組嚴(yán)格的規(guī)則來確定兩個數(shù)組之間的交互:
規(guī)則1:如果兩個數(shù)組的維數(shù)不同,則維數(shù)較少的那個數(shù)組的形狀會在其前邊(左)填充維數(shù)。
規(guī)則2:如果兩個數(shù)組的形狀在任何維度都不匹配,則將該維度中形狀為1的數(shù)組拉伸以匹配另一個形狀。
規(guī)則3:如果在任何維度中大小不一致,且兩者都不等于1,則會出現(xiàn)錯誤。

舉一個實例:

>>> M = np.ones((3,2))
array([[1., 1., 1.],
       [1., 1., 1.]])
>>> a = np.arange(3)
 array([0, 1, 2])
>>>a +M
array([[1., 2., 3.],
       [1., 2., 3.]])

雖然數(shù)組a的大小與M并不相同,在數(shù)學(xué)上是不能相加的,但是由于廣播機(jī)制,維度和M變成相同,因此相加得到結(jié)果。
它的過程是a先向下擴(kuò)展,然后相加。

布爾蒙版,布爾邏輯運(yùn)算

這個簡單,邏輯值有兩個False True
通過比較運(yùn)算符可以得到邏輯值。

>>> x = np.array([1, 2, 3, 4, 5])
>>> x < 3  # less than
array([ True,  True, False, False, False], dtype=bool)
>>> x > 3  # greater than
array([False, False, False,  True,  True], dtype=bool)
>>> x <= 3  # less than or equal
array([ True,  True,  True, False, False], dtype=bool)
>>> x >= 3  # greater than or equal
array([False, False,  True,  True,  True], dtype=bool)
>>> x != 3  # not equal
array([ True,  True, False,  True,  True], dtype=bool)
>>> x == 3  # equal
array([False, False,  True, False, False], dtype=bool)
#甚至:
>>> (2 * x) == (x ** 2)
array([False,  True, False, False, False], dtype=bool)

也可以使用函數(shù):np.equal() np.not_equal() ...
多維數(shù)組同理。

怎樣使用布爾數(shù)組

  1. 用來計數(shù)
    any() all()
>>> print(x)
array([[9, 7, 2],
       [6, 2, 3],
       [9, 5, 9]])
>>> np.count_nonzero(x < 6)
2
>>>np.sum(x<6)
2
>>>np.all(x<10)
True
>>> np.all(x<0)
False
  1. 布爾運(yùn)算符
    & | ~ ^
    且 或 取反 異或運(yùn)算

  2. 在掩模中的布爾數(shù)組
    意思是直接把布爾數(shù)組放入原數(shù)組中可以得到結(jié)果。
    【True返回結(jié)果,F(xiàn)alse返回0】

>>> x
array([[5, 0, 3, 3],
       [7, 9, 3, 5],
       [2, 4, 7, 6]]
>>> x < 5
array([[False,  True,  True,  True],
       [False, False,  True, False],
       [ True,  True, False, False]], dtype=bool)
>>> x[x < 5]
array([0, 3, 3, 3, 2, 4])

bool and or bin

使用bool直接返回邏輯值
不等于0的值返回True,等于0返回False
and 和 or 相當(dāng)于& |
bin 得到二進(jìn)制

>>> bool(42), bool(0)
(True, False)
>>> bool(42 and 0)
False
>>> bool(42 or 0)
True
>>> bin(42)
'0b101010'

注意一點,兩個數(shù)組之間不能使用 or and 簡單的關(guān)系運(yùn)算。 or and 兩邊只能連接邏輯矩陣或者邏輯變量。

花式索引

在前面,我們已經(jīng)介紹了簡單的索引
切片,布爾蒙版,直接arr[1] 訪問和修改數(shù)組的各個部分,現(xiàn)在我們學(xué)習(xí)一種新的索引方式,通過傳遞索引數(shù)組來代替單個標(biāo)量,這讓我們非常快速地訪問和修改數(shù)組值的復(fù)雜子集。

簡單實例:

>>> x = rand.randint(100,size=10)
>>> x
[51 92 14 71 60 20 82 86 74 74]
>>> index = [3,4,6]
>>> x[index]
array([71,60,82])

其中,廣播數(shù)組也適用

>>> print(X)
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
>>> X[2, [2, 0, 1]]
array([10,  8,  9])
>>> X[1:, [2, 0, 1]]
array([[ 6,  4,  5],
       [10,  8,  9]])

布爾蒙版也適用

>>>mask = np.array([1, 0, 1, 0], dtype=bool)
>>> X[[[0],[1],[2]], mask]
array([[ 0,  2],
       [ 4,  6],
       [ 8, 10]])

介紹兩個簡單函數(shù)np.searchsorted(bins,x)
其作用是返回x在bins數(shù)據(jù)中按照順序應(yīng)該被插入的位置。

>>> np.searchsorted([1,2,3,4,5], 3)
2
>>> np.searchsorted([1,2,3,4,5], 3, side='right')
3
>>> np.searchsorted([1,2,3,4,5], [-10, 10, 2, 3])
array([0, 5, 1, 2])

np.histogram()直方圖統(tǒng)計

數(shù)組排序

基礎(chǔ)包里有一個sorted()方法用來排序,不過只能對列表,一維數(shù)組排序,且效率不高。

numpy提供了快速排序的方法。
np.sort np.argsort
np.sort 返回排序后的數(shù)組
np.argsort 返回排序后的索引

>>>  x = np.random.randint(1,100,10);x
array([79, 15, 72,  4, 87, 83, 30,  5, 72, 25])
>>> np.sort(x)
array([ 4,  5, 15, 25, 30, 72, 72, 79, 83, 87])
>>> np.argsort(x)
array([3, 7, 1, 9, 6, 2, 8, 0, 5, 4], dtype=int64)

對于高維數(shù)組來說,可以單獨的對某一維進(jìn)行排序。

In [37]: x = np.random.randint(1,100,(3,3,3))

In [38]: x
Out[38]:
array([[[46, 56, 17],
        [64, 97, 89],
        [16, 85, 60]],

       [[ 3, 40, 64],
        [35, 13, 29],
        [99, 66, 68]],

       [[66, 28, 39],
        [ 3, 12, 70],
        [11, 46, 78]]])
In [39] : np.sort(x,axis=0)
out [39]:
array([[[ 3, 28, 17],
        [ 3, 12, 29],
        [11, 46, 60]],

       [[46, 40, 39],
        [35, 13, 70],
        [16, 66, 68]],

       [[66, 56, 64],
        [64, 97, 89],
        [99, 85, 78]]])
In [40]: np.sort(x,axis=1)
Out[40]:
array([[[16, 56, 17],
        [46, 85, 60],
        [64, 97, 89]],

       [[ 3, 13, 29],
        [35, 40, 64],
        [99, 66, 68]],

       [[ 3, 12, 39],
        [11, 28, 70],
        [66, 46, 78]]])

部分排序

如果不想對全部數(shù)據(jù)進(jìn)行排序,也可以對部分?jǐn)?shù)據(jù)進(jìn)行排序。

np.partition() np.argpartition()

>>> x = np.array([7, 2, 3, 1, 6, 5, 4])
>>> np.partition(x, 3)
array([2, 1, 3, 4, 6, 5, 7])

它的意思是找到最小的K個值放到數(shù)組左邊,順序隨機(jī)。
另一個是得到索引。

numpy中的結(jié)構(gòu)體

在numpy也有結(jié)構(gòu)體數(shù)組。
定義的方法如下:

name = ['Alice', 'Bob', 'Cathy', 'Doug']
age = [25, 45, 37, 19]
weight = [55.0, 85.5, 68.0, 61.5]

可以使用函數(shù)定義:

data = np.zeros(4, dtype={'names':('name', 'age', 'weight'),
                          'formats':('U10', 'i4', 'f8')})

or:
np.dtype({'names':('name', 'age', 'weight'),
          'formats':('U10', 'i4', 'f8')})
or:
np.dtype({'names':('name', 'age', 'weight'),
          'formats':((np.str_, 10), int, np.float32)})

格式的寫法含義:
后面的數(shù)字表示所占的bit位。

Character Description Example
'b' Byte np.dtype('b')
'i' Signed integer np.dtype('i4') == np.int32
'u' Unsigned integer np.dtype('u1') == np.uint8
'f' Floating point np.dtype('f8') == np.int64
'c' Complex floating point np.dtype('c16') == np.complex128
'S', 'a' String np.dtype('S5')
'U' Unicode string np.dtype('U') == np.str_
'V' Raw data (void) np.dtype('V') == np.void

結(jié)構(gòu)體的訪問方法:

data['feild']
可以使用np.recarray類使用屬性訪問

>>> data_rec = data.view(np.recarray)
array([25, 45, 37, 19], dtype=int32)
>>> data_rec.age
array([25, 45, 37, 19], dtype=int32)

如果要更進(jìn)一步使用結(jié)構(gòu)體的話或許pandas是一個不錯的選擇。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容