<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ù)組
- 用來計數(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
布爾運(yùn)算符
& | ~ ^
且 或 取反 異或運(yùn)算在掩模中的布爾數(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是一個不錯的選擇。