Python數(shù)據(jù)處理入門教程(Numpy版)
值得一提的是,深度學(xué)習(xí)的各大框架很多 API 和 numpy 也是一脈相承的哦,可以說 numpy 玩兒熟了,幾個深度學(xué)習(xí)框架的不少 API 也同時學(xué)會了。本文是教程的「第一部分」,從實際的代碼應(yīng)用出發(fā),講解了Numpy創(chuàng)建到統(tǒng)計的操作。

開源項目地址:https://github.com/datawhalechina/powerful-numpy
本教程原則如下: ?· 偏實用高頻 API ?·?展示實際用法 ?·?簡單直接 使用說明:內(nèi)容中?(1-5個)表示重要程度,越多越重要;?? 表示需要特別注意的 提示:使用過程中無須過多關(guān)注 API 各種參數(shù)細節(jié),教程提供的用法足以應(yīng)付絕大部分場景,更深入的可自行根據(jù)需要探索或?qū)W習(xí)后續(xù)的教程。 下面正式開始講解。
#?導(dǎo)入?library
import?numpy?as?np
#?畫圖工具
import?matplotlib.pyplot?as?plt
創(chuàng)建和生成
本節(jié)主要介紹 array 的創(chuàng)建和生成。為什么會把這個放在最前面呢?主要有以下兩個方面原因:
首先,在實際工作過程中,我們時不時需要驗證或查看 array 相關(guān)的 API 或互操作。同時,有時候在使用 sklearn,matplotlib,PyTorch,Tensorflow 等工具時也需要一些簡單的數(shù)據(jù)進行實驗。
所以,先學(xué)會如何快速拿到一個 array 是有很多益處的。本節(jié)我們主要介紹以下幾種常用的創(chuàng)建方式:
使用列表或元組
使用 arange
使用 linspace/logspace
使用 ones/zeros
使用 random
從文件讀取
其中,最常用的一般是 linspace/logspace 和 random,前者常常用在畫坐標軸上,后者則用于生成「模擬數(shù)據(jù)」。舉例來說,當我們需要畫一個函數(shù)的圖像時,X 往往使用 linspace 生成,然后使用函數(shù)公式求得 Y,再 plot;當我們需要構(gòu)造一些輸入(比如 X)或中間輸入(比如 Embedding、hidden state)時,random 會異常方便。
從 python 列表或元組創(chuàng)建
?? 重點掌握傳入 list 創(chuàng)建一個 array 即可:np.array(list)
?? 需要注意的是:「數(shù)據(jù)類型」。如果您足夠仔細的話,可以發(fā)現(xiàn)下面第二組代碼第 2 個數(shù)字是「小數(shù)」(注:Python 中 1. == 1.0),而 array 是要保證每個元素類型相同的,所以會幫您把 array 轉(zhuǎn)為一個 float 的類型。
#?一個?list
np.array([1,2,3])
array([1, 2, 3])
#?二維(多維類似)
#?注意,有一個小數(shù)哦
np.array([[1,?2.,?3],?[4,?5,?6]])
array([[1., 2., 3.],
[4., 5., 6.]])
#?您也可以指定數(shù)據(jù)類型
np.array([1,?2,?3],?dtype=np.float16)
array([1., 2., 3.], dtype=float16)
#?如果指定了?dtype,輸入的值都會被轉(zhuǎn)為對應(yīng)的類型,而且不會四舍五入
lst?=?[
????[1,?2,?3],
????[4,?5,?6.8]
]
np.array(lst,?dtype=np.int32)
array([[1, 2, 3],
[4, 5, 6]], dtype=int32)
#?一個?tuple
np.array((1.1,?2.2))
array([1.1, 2.2])
#?tuple,一般用?list?就好,不需要使用?tuple
np.array([(1.1,?2.2,?3.3),?(4.4,?5.5,?6.6)])
array([[1.1, 2.2, 3.3],
[4.4, 5.5, 6.6]])
#?轉(zhuǎn)換而不是上面的創(chuàng)建,其實是類似的,無須過于糾結(jié)
np.asarray((1,2,3))
array([1, 2, 3])
np.asarray(([1.,?2.,?3.],?(4.,?5.,?6.)))
array([[1., 2., 3.],
[4., 5., 6.]])
使用 arange 生成
??
range 是 Python 內(nèi)置的整數(shù)序列生成器,arange 是 numpy 的,效果類似,會生成一維的向量。我們偶爾會需要使用這種方式來構(gòu)造 array,比如:
需要創(chuàng)建一個連續(xù)一維向量作為輸入(比如編碼位置時可以使用) 需要觀察篩選、抽樣的結(jié)果時,有序的 array 一般更加容易觀察
?? 需要注意的是:在 reshape 時,目標的 shape 需要的元素數(shù)量一定要和原始的元素數(shù)量相等。
np.arange(12).reshape(3,?4)
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
#?注意,是小數(shù)哦
np.arange(12.0).reshape(4,?3)
array([[ 0., 1., 2.],
[ 3., 4., 5.],
[ 6., 7., 8.],
[ 9., 10., 11.]])
np.arange(100,?124,?2).reshape(3,?2,?2
array([[[100, 102],
[104, 106]],
[[108, 110],
[112, 114]],
[[116, 118],
[120, 122]]])
#?shape?size?相乘要和生成的元素數(shù)量一致
np.arange(100.,?124.,?2).reshape(2,3,4)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)in
----> 1 np.arange(100., 124., 2).reshape(2,3,4)
ValueError: cannot reshape array of size 12 into shape (2,3,4)
使用 linspace/logspace 生成
???
OK,這是我們遇到的第一個比較重要的 API,前者需要傳入 3 個參數(shù):開頭,結(jié)尾,數(shù)量;后者需要額外傳入一個 base,它默認是 10。
?? 需要注意的是:第三個參數(shù)并不是步長。
np.linspace
#?線性
np.linspace(0,?9,?10).reshape(2,?5)
array([[0., 1., 2., 3., 4.],
[5., 6., 7., 8., 9.]])
np.linspace(0,?9,?6).reshape(2,?3)
array([[0. , 1.8, 3.6],
[5.4, 7.2, 9. ]])
#?指數(shù)?base?默認為?10
np.logspace(0,?9,?6,?base=np.e).reshape(2,?3)
array([[1.00000000e+00, 6.04964746e+00, 3.65982344e+01],
[2.21406416e+02, 1.33943076e+03, 8.10308393e+03]])
#?_?表示上(最近)一個輸出
#?logspace?結(jié)果?log?后就是上面?linspace?的結(jié)果
np.log(_)
array([[0. , 1.8, 3.6],
[5.4, 7.2, 9. ]])
下面我們更進一步看一下:
N?=?20
x?=?np.arange(N)
y1?=?np.linspace(0,?10,?N)?*?100
y2?=?np.logspace(0,?10,?N,?base=2)
plt.plot(x,?y2,?'*');
plt.plot(x,?y1,?'o');
#?檢查每個元素是否為?True
#?base?的?指數(shù)為?linspace?得到的就是?logspace
np.alltrue(2?**?np.linspace(0,?10,?N)??==?y2)
True?? 補充:關(guān)于 array 的條件判斷
#?不能直接用?if?判斷?array?是否符合某個條件
arr?=?np.array([1,?2,?3])
cond1?=?arr?>?2
cond1
array([False, False, True])
if?cond1:
????print("這不行")
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)in
----> 1 if cond1:
2 print("這不行")
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
#?即便你全是?True?它也不行
arr?=?np.array([1,?2,?3])
cond2?=?arr?>?0
cond2
array([ True, True, True])
if?cond2:
????print("這還不行")
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)in
----> 1 if cond2:
2 print("這還不行")
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
#?咱們只能用 any 或 all,這個很容易犯錯,請務(wù)必注意。
if?cond1.any():
????print("只要有一個為True就可以,所以——我可以")
只要有一個為True就可以,所以——我可以
if?cond2.all():
????print("所有值為True才可以,我正好這樣")
所有值為True才可以,我正好這樣
使用 ones/zeros 創(chuàng)建
?
創(chuàng)建全 1/0 array 的快捷方式。需要注意的是 np.zeros_like 或 np.ones_like,二者可以快速生成給定 array 一樣 shape 的 0 或 1 向量,這在需要 Mask 某些位置時可能會用到。
?? 需要注意的是:創(chuàng)建出來的 array 默認是 float 類型。
np.ones(3)
array([1., 1., 1.])
np.ones((2,?3))
array([[1., 1., 1.],
[1., 1., 1.]])
np.zeros((2,3,4))
array([[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]],
[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]]])
#?像給定向量那樣的?0?向量(ones_like?是?1?向量)
np.zeros_like(np.ones((2,3,3)))
array([[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]],
[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]]])
使用 random 生成
?????
如果要在這一節(jié)選一個最重要的 API,那一定是 random 無疑了,這里我們只介紹幾個比較常用的「生產(chǎn)」數(shù)據(jù)相關(guān)的 API。它們經(jīng)常用于隨機生成訓(xùn)練或測試數(shù)據(jù),神經(jīng)網(wǎng)路初始化等。
?? 需要注意的是:這里我們統(tǒng)一推薦使用新的 API 方式創(chuàng)建,即通過 np.random.default_rng() 先生成 Generator,然后再在此基礎(chǔ)上生成各種分布的數(shù)據(jù)(記憶更加簡便清晰)。不過我們依然會介紹就的 API 用法,因為很多代碼中使用的還是舊的,您可以混個眼熟。
#?0-1?連續(xù)均勻分布
np.random.rand(2,?3)
array([[0.42508994, 0.5842191 , 0.09248675],
[0.656858 , 0.88171822, 0.81744539]])
#?單個數(shù)
np.random.rand()
0.29322641374172986
#?0-1?連續(xù)均勻分布
np.random.random((3,?2))
array([[0.17586271, 0.5061715 ],
[0.14594537, 0.34365713],
[0.28714656, 0.40508807]])
#?指定上下界的連續(xù)均勻分布
np.random.uniform(-1,?1,?(2,?3))
array([[ 0.66638982, -0.65327069, -0.21787878],
[-0.63552782, 0.51072282, -0.14968825]])
#?上面兩個的區(qū)別是?shape?的輸入方式不同,無傷大雅了
#?不過從?1.17?版本后推薦這樣使用(以后大家可以用新的方法)
#?rng?是個?Generator,可用于生成各種分布
rng?=?np.random.default_rng(42)
rng
Generator(PCG64) at 0x111B5C5E0
#?推薦的連續(xù)均勻分布用法
rng.random((2,?3))
array([[0.77395605, 0.43887844, 0.85859792],
[0.69736803, 0.09417735, 0.97562235]])
#?可以指定上下界,所以更加推薦這種用法
rng.uniform(0,?1,?(2,?3))
array([[0.47673156, 0.59702442, 0.63523558],
[0.68631534, 0.77560864, 0.05803685]])
#?隨機整數(shù)(離散均勻分布),不超過給定的值(10)
np.random.randint(10,?size=2)
array([6, 3])
#?隨機整數(shù)(離散均勻分布),指定上下界和?shape
np.random.randint(0,?10,?(2,?3))
array([[8, 6, 1],
[3, 8, 1]])
#?上面推薦的方法,指定大小和上界
rng.integers(10,?size=2)
array([9, 7])
#?上面推薦的方法,指定上下界
rng.integers(0,?10,?(2,?3))
array([[5, 9, 1],
[8, 5, 7]])
#?標準正態(tài)分布
np.random.randn(2,?4)
array([[-0.61241167, -0.55218849, -0.50470617, -1.35613877],
[-1.34665975, -0.74064846, -2.5181665 , 0.66866357]])
#?上面推薦的標準正態(tài)分布用法
rng.standard_normal((2,?4))
array([[ 0.09130331, 1.06124845, -0.79376776, -0.7004211 ],
[ 0.71545457, 1.24926923, -1.22117522, 1.23336317]])
#?高斯分布
np.random.normal(0,?1,?(3,?5))
array([[ 0.30037773, -0.17462372, 0.23898533, 1.23235421, 0.90514996],
[ 0.90269753, -0.5679421 , 0.8769029 , 0.81726869, -0.59442623],
[ 0.31453468, -0.18190156, -2.95932929, -0.07164822, -0.23622439]])
#?上面推薦的高斯分布用法
rng.normal(0,?1,?(3,?5))
array([[ 2.20602146, -2.17590933, 0.80605092, -1.75363919, 0.08712213],
[ 0.33164095, 0.33921626, 0.45251278, -0.03281331, -0.74066207],
[-0.61835785, -0.56459129, 0.37724436, -0.81295739, 0.12044035]])
總之,一般會用的就是2個分布:均勻分布和正態(tài)(高斯)分布。另外,size 可以指定 shape。
rng?=?np.random.default_rng(42)
#?離散均勻分布
rng.integers(low=0,?high=10,?size=5)
array([0, 7, 6, 4, 4])
#?連續(xù)均勻分布
rng.uniform(low=0,?high=10,?size=5)
array([6.97368029, 0.94177348, 9.75622352, 7.61139702, 7.86064305])
#?正態(tài)(高斯)分布
rng.normal(loc=0.0,?scale=1.0,?size=(2,?3))
array([[-0.01680116, -0.85304393, 0.87939797],
[ 0.77779194, 0.0660307 , 1.12724121]])
從文件讀取
?
這小節(jié)主要用于加載實現(xiàn)存儲好的權(quán)重參數(shù)或預(yù)處理好的數(shù)據(jù)集,有時候會比較方便,比如訓(xùn)練好的模型參數(shù)加載到內(nèi)存里用來提供推理服務(wù),或者耗時很久的預(yù)處理數(shù)據(jù)直接存起來,多次實驗時不需要重新處理。
?? 需要注意的是:存儲時不需要寫文件名后綴,會自動添加。
#?直接將給定矩陣存為?a.npy
np.save('./data/a',?np.array([[1,?2,?3],?[4,?5,?6]]))
#?可以將多個矩陣存在一起,名為?`b.npz`
np.savez("./data/b",?a=np.arange(12).reshape(3,?4),?b=np.arange(12.).reshape(4,?3))
#?和上一個一樣,只是壓縮了
np.savez_compressed("./data/c",?a=np.arange(12).reshape(3,?4),?b=np.arange(12.).reshape(4,?3))
#?加載單個?array
np.load("data/a.npy")
array([[1, 2, 3],
[4, 5, 6]])
#?加載多個,可以像字典那樣取出對應(yīng)的?array
arr?=?np.load("data/b.npz")
arr["a"]
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
arr["b"]
array([[ 0., 1., 2.],
[ 3., 4., 5.],
[ 6., 7., 8.],
[ 9., 10., 11.]])
#?后綴都一樣,你干脆當它和上面的沒區(qū)別即可
arr?=?np.load("data/c.npz")
arr["b"]
array([[ 0., 1., 2.],
[ 3., 4., 5.],
[ 6., 7., 8.],
[ 9., 10., 11.]])
統(tǒng)計和屬性
本節(jié)我們從 array 的基本統(tǒng)計屬性入手,對剛剛創(chuàng)建的 array 進一步的了解。主要包括以下幾個方面:
尺寸相關(guān) 最大、最小、中位、分位值 平均、求和、標準差等
都是描述性統(tǒng)計相關(guān)的指標,對于我們從整體了解一個 array 很有幫助。其中,用到最多的是尺寸相關(guān)的「shape」,最大、最小值,平均值、求和等。
本節(jié)的內(nèi)容非常簡單,您只需要特別關(guān)注(記住)兩個重要的特性:
按維度(指定 axis)求結(jié)果。一般0表示列1表示行,可以用「沿著行/列操作」這樣理解,不確定時可以拿個例子試一下。 計算后保持維度( keepdims=True)
另外,為了便于操作,我們使用一個隨機生成的 array 作為操作對象;同時,我們指定了 seed,這樣每次運行,每個人看到的結(jié)果都是一樣的。一般我們在訓(xùn)練模型時,往往需要指定 seed,這樣才能在「同等條件」下進行調(diào)參。
#??先創(chuàng)建一個?Generator
rng?=?np.random.default_rng(seed=42)
#??再生成一個均勻分布
arr?=?rng.uniform(0,?1,?(3,?4))
arr
array([[0.77395605, 0.43887844, 0.85859792, 0.69736803],
[0.09417735, 0.97562235, 0.7611397 , 0.78606431],
[0.12811363, 0.45038594, 0.37079802, 0.92676499]])
尺寸相關(guān)
??
這一小節(jié)主要包括:維度、形狀和數(shù)據(jù)量,其中形狀 shape 我們用到的最多。
?? 需要注意的是:size 不是 shape,ndim 表示有幾個維度。
#?維度,array?是二維的(兩個維度)
arr.ndim
2
np.shape
#?形狀,返回一個?Tuple
arr.shape
(3, 4)
#?數(shù)據(jù)量
arr.size
12
最值分位
???
這一小節(jié)主要包括:最大值、最小值、中位數(shù)、其他分位數(shù),其中『最大值和最小值』我們平時用到的最多。
?? 需要注意的是:分位數(shù)可以是 0-1 的任意小數(shù)(表示對應(yīng)分位),而且分位數(shù)并不一定在原始的 array 中。
arr
array([[0.77395605, 0.43887844, 0.85859792, 0.69736803],
[0.09417735, 0.97562235, 0.7611397 , 0.78606431],
[0.12811363, 0.45038594, 0.37079802, 0.92676499]])
#?所有元素中最大的
arr.max()
0.9756223516367559
np.max/min
#?按維度(列)最大值
arr.max(axis=0)
array([0.77395605, 0.97562235, 0.85859792, 0.92676499])
#?同理,按行
arr.max(axis=1)
array([0.85859792, 0.97562235, 0.92676499])
#?是否保持原來的維度
#?這個需要特別注意下,很多深度學(xué)習(xí)模型中都需要保持原有的維度進行后續(xù)計算
#?shape?是?(3,1),array?的?shape?是?(3,4),按行,同時保持了行的維度
arr.min(axis=1,?keepdims=True)
array([[0.43887844],
[0.09417735],
[0.12811363]])
#?保持維度:(1,4),原始array是(3,4)
arr.min(axis=0,?keepdims=True)
array([[0.09417735, 0.43887844, 0.37079802, 0.69736803]])
#?一維了
arr.min(axis=0,?keepdims=False)
array([0.09417735, 0.43887844, 0.37079802, 0.69736803])
#?另一種用法,不過我們一般習(xí)慣使用上面的用法,其實兩者一回事
np.amax(arr,?axis=0)
array([0.77395605, 0.97562235, 0.85859792, 0.92676499])
#?同?amax
np.amin(arr,?axis=1)
array([0.43887844, 0.09417735, 0.12811363])
#?中位數(shù)
#?其他用法和?max,min?是一樣的
np.median(arr)
0.7292538655248584
#?分位數(shù),按列取1/4數(shù)
np.quantile(arr,?q=0.25,?axis=0)
array([0.11114549, 0.44463219, 0.56596886, 0.74171617])
#?分位數(shù),按行取?3/4,同時保持維度
np.quantile(arr,?q=0.75,?axis=1,?keepdims=True)
array([[0.79511652],
[0.83345382],
[0.5694807 ]])
#?分位數(shù),注意,分位數(shù)可以是?0-1?之間的任何數(shù)字(分位)
#?如果是?1/2?分位,那正好是中位數(shù)
np.quantile(arr,?q=1/2,?axis=1)
array([0.73566204, 0.773602 , 0.41059198])
平均求和標準差
???
這一小節(jié)主要包括:平均值、累計求和、方差、標準差等進一步的統(tǒng)計指標。其中使用最多的是「平均值」。
arr
array([[0.77395605, 0.43887844, 0.85859792, 0.69736803],
[0.09417735, 0.97562235, 0.7611397 , 0.78606431],
[0.12811363, 0.45038594, 0.37079802, 0.92676499]])
np.average
#?平均值
np.average(arr)
0.6051555606435642
#?按維度平均(列)
np.average(arr,?axis=0)
array([0.33208234, 0.62162891, 0.66351188, 0.80339911])
#?另一個計算平均值的?API
#?它與?average?的主要區(qū)別是,np.average?可以指定權(quán)重,即可以用于計算加權(quán)平均
#?一般建議使用 average,忘掉 mean 吧!
np.mean(arr,?axis=0)
array([0.33208234, 0.62162891, 0.66351188, 0.80339911])
np.sum
#?求和,不多說了,類似
np.sum(arr,?axis=1)
array([2.76880044, 2.61700371, 1.87606258])
np.sum(arr,?axis=1,?keepdims=True)
array([[2.76880044],
[2.61700371],
[1.87606258]])
#?按列累計求和
np.cumsum(arr,?axis=0)
array([[0.77395605, 0.43887844, 0.85859792, 0.69736803],
[0.8681334 , 1.41450079, 1.61973762, 1.48343233],
[0.99624703, 1.86488673, 1.99053565, 2.41019732]])
#?按行累計求和
np.cumsum(arr,?axis=1)
array([[0.77395605, 1.21283449, 2.07143241, 2.76880044],
[0.09417735, 1.0697997 , 1.8309394 , 2.61700371],
[0.12811363, 0.57849957, 0.94929759, 1.87606258]])
#?標準差,用法類似
np.std(arr)
0.28783096517727075
#?按列求標準差
np.std(arr,?axis=0)
array([0.3127589 , 0.25035525, 0.21076935, 0.09444968])
#?方差
np.var(arr,?axis=1)
array([0.02464271, 0.1114405 , 0.0839356 ])文獻和資料
NumPy 教程 | 菜鳥教程 NumPy 中文
- END -
機??器學(xué)習(xí)算法交流群,邀您加入!!!
入群:提問求助;認識行業(yè)內(nèi)同學(xué),交流進步;共享資源...
掃描??下方二維碼,備注“加群”
一鍵三連,一起學(xué)習(xí)???
