第2章 NumPy入門(2.1-2.2)
根據<<數據科學手冊>> Python Data Science Handbook一書整理.
本章將詳細介紹NumPy(Numerical Python的簡稱)提供了高效存儲和操作密集數據緩存的藉口.在某些方面,NumPy數組和Python內置的列表類型非常相似.但是隨着數組在維度上變大,NumPy數組提供了更加高效的存儲和數據操作.NumPy數組幾乎是整個Python數據科學工具生態系統的核心.因此不管你對數據科學的哪個方面感興趣,花點時間學習如何有效使用NumPy都是非常值得的.
2.1 理解Python中的數據類型
2.1.5 創建幾個數組
import numpy as np
創建一個長度爲10的數組, 數組的值都是0
-是zeros, 不是zero
-此函數有啥作用?
np.zeros(10, dtype=int)
創建一個3 * 5的浮點型數組, 數組的值都是1
3 * 5 表示3行*5列, 輸入代碼是圓括號本身是成對出現的, 如果手動添加或者剪切, 可能會導致錯誤
np.ones((3,5),dtype=int)
array([[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]])
創建一個3 * 5的浮點型數組, 數組的值都是3.14
np.full((3,5), 3.14)
array([[3.14, 3.14, 3.14, 3.14, 3.14],
[3.14, 3.14, 3.14, 3.14, 3.14],
[3.14, 3.14, 3.14, 3.14, 3.14]])
zeros,ones,full都是np下的函數, 可以創建數組.
-第一個參數告訴數組是多長, 或者是 n*k的數組
-第二個參數,數值類型或者數值
np.zeros(10,dtype=str)
array(['', '', '', '', '', '', '', '', '', ''], dtype='<U1')
np.ones((3,3),dtype=int)
array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]])
np.full(9,520)
array([520, 520, 520, 520, 520, 520, 520, 520, 520])
創建一個線性序列, 從0開始,20結束,步長2
-和內置的range()函數類似
np.arange(0,20,2)
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
創建一個5個元素的數組,這5個數均勻分配到0-1中
-分位數嗎?
np.linspace(0,1,5)
array([0. , 0.25, 0.5 , 0.75, 1. ])
np.linspace(4,20,5)
array([ 4., 8., 12., 16., 20.]
創建一個3*3,在0-1均勻分佈的隨機數組成的數組
-重點是0-1
-均勻分佈是什麼意思
np.random.random((3,3))
array([[0.39362852, 0.25206974, 0.88385296],
[0.36547614, 0.34461809, 0.7989048 ],
[0.7369659 , 0.21725593, 0.92850852]])
np.random.random((3*3))
array([0.28620252, 0.18814101, 0.51808316, 0.09341987, 0.78624051,
0.89402738, 0.23804843, 0.04750264, 0.99956259])
np.random.random(5)
array([0.76369557, 0.88767111, 0.93486428, 0.54337144, 0.60357903])
創建一個3*3的,均值爲0,標準差爲1的
-正太分佈數組
np.random.normal(0,1,(3,3))
array([[ 0.90030434, -1.50711765, 0.97764385],
[-0.31173987, -0.84110574, -0.10047986],
[-0.43478952, 1.50298937, 0.73763183]])
np.random.normal(1.5,0.4,100) #生成均值爲1.5,標準差爲0.4的100個數字.怎麼只顯示2位小數
array([1.22261068, 1.58441532, 1.88802132, 0.61486983, 1.87470827,
2.25946452, 1.03590926, 1.33094771, 1.4062705 , 1.11332783,
1.40300437, 1.56448717, 1.84108864, 1.889423 , 0.77694291,
0.68180117, 1.30913434, 1.86453287, 1.47528384, 1.57611792,
1.18340949, 1.52063669, 1.59611354, 1.42870295, 1.74599812,
0.87469452, 0.74602807, 1.12764331, 1.25820621, 1.7901757 ,
1.63144372, 1.53547336, 1.69190459, 1.56495873, 1.92058924,
1.32189662, 1.81971028, 1.46019658, 2.35699722, 1.96548058,
2.65711447, 0.89155833, 1.90166715, 1.88020944, 1.49726831,
1.55377297, 1.25409672, 0.94901106, 0.94586283, 1.67326062,
1.37021414, 1.63778177, 1.61532023, 1.01930684, 1.73838839,
2.39846604, 1.1897899 , 0.98619697, 1.41209562, 1.66616348,
1.67276465, 1.6177355 , 1.17221527, 1.81797366, 1.71753876,
1.59004372, 2.19224441, 1.54545624, 1.62140601, 2.05344465,
1.64692645, 1.51883407, 1.83548018, 1.29491494, 1.71556491,
1.04304926, 1.04311419, 2.25142503, 1.65532576, 1.25867277,
0.98532785, 0.76105179, 0.7609183 , 1.84616896, 1.95658462,
2.37700902, 1.62810267, 1.62762617, 1.66713729, 1.87285054,
1.88304677, 1.32029194, 1.2275771 , 1.38059868, 0.73470536,
2.19813629, 1.96004672, 1.98630112, 1.74666125, 1.18260392])
創建一個3*3的,0-10區間的隨機數組成的數組
np.random.randint(0,10,(3,3))
array([4, 3, 4, 4, 8, 4])
np.random.randint(90,100,(2,2))
array([[94, 90],
[92, 99]])
創建一個3*3的單位矩陣
np.eye(3)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
創建一個由3個整數組成的未初始化的數組
-數組的值是內存空間的任意值?
np.empty(3)
array([1., 1., 1.])
2.1.6 NumPy中標準數據類型
NumPy數組包含同一類型的值. NumPy是在C語言基礎上開發的.
在構建數組時,可以用一個字符串參數指定數據類型
-NumPy中數據類型比Python中數據類型多,不加引號可能會報錯
np.zeros(10, dtype='int16')
np.zeros(10,dtype=np.int16)
np.zeros(10,dtype=int)
np.zeros(10,dtype=int16) # int16是NumPy中數據類型,報錯
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-38-ff102d8e3e0a> in <module>()
2 np.zeros(10,dtype=np.int16)
3 np.zeros(10,dtype=int)
----> 4 np.zeros(10,dtype=int16)
NameError: name 'int16' is not defined
NumPy中數據類型
-bool_ : 布爾值
-int_ : 默認整型
-intc : 同C語言中int相同
-intp : 用作索引的整型
-int8 : 字節,範圍從-128到127
-int16 :
-int32 :
-int64 :
-uint8 :
-uint16 :
-uint32 :
-uint64 :
-float_ :
-float16 :
-loat32 :
-float64 :
-complex_ :
-complex64 :
-complex128 :
2.2 NumPy數組基礎
Python中數據操作幾乎等同於NumPy中數組操作.Pandas工具也是構建在NumPy數組的基礎之上的.
-數組的屬性(大小,形狀,存儲大小,數據類型)
-數組的索引(獲取或者設置各個元素的值)
-數組的切分
-數組的變形
-數組的拼接與分裂
2.2.1 數組的屬性
import numpy as np
np.random.seed(0) #設置隨機數種子值,
x1 = np.random.randint(10,size=6) # 還可以寫成 np.random.randint(0,10,6)
np.random.randint(0,10,6)
x2 = np.random.randint(10,size=(3,4))
x3 = np.random.randint(10,size=(3,4,5))
print(x3)
[[[4 3 0 3 5]
[0 2 3 8 1]
[3 3 3 7 0]
[1 9 9 0 4]]
[[7 3 2 7 2]
[0 0 4 5 5]
[6 8 4 1 4]
[9 8 1 1 7]]
[[9 9 3 6 7]
[2 0 3 5 9]
[4 4 6 4 4]
[3 4 4 8 4]]]
每個數組都有數組的ndim(數組的維度),shape(數組每個維度的大小),size(數組的總大小)和dtype(數組的數據類型)
其他: itemsize(每個元素字節大小), nbytes(總字節大小). 什麼東東?
print('x3的維度是:',x3.ndim)
print('x3的每個維度大小是:',x3.shape) # 每個維度的大小是從外向內數?
print('x3的總大小是:',x3.size)
print('x3的數據類型是:',x3.dtype)
print('x3的字節大小是:',x3.itemsize,"bytes")
print('x3的總字節大小是:',x3.nbytes,'bytes')
x3的維度是: 3
x3的每個維度大小是: (3, 4, 5)
x3的總大小是: 60
x3的數據類型是: int32
x3的字節大小是: 4 bytes
x3的總字節大小是: 240 bytes
2.2.2 數組的索引: 獲取單個元素
一維數組
np.random.seed(0)
x1 = np.random.randint(10,size=6) # 這樣生成的6位隨機數居然和書本上的一樣
print(x1)
print(x1[0]) #第一位
print(x1[4])
print(x1[-1]) #最後一位
[5 0 3 3 7 9]
5
7
9
二維數組
print(x2)
print(x2[0,0])
print(x2[2,2])
print(x2[2,-1])
[[8 8 1 6]
[7 7 8 1]
[5 9 8 9]]
8
8
9
修改某個值數據. 數組是有數據類型的, 如果加入的數值類型不一樣, 會自動變換
x2[0,0] = "100" #如果是字符型字符串則報錯
x2[2,2] = 3.14
x2
array([[100, 8, 1, 6],
[ 7, 7, 8, 1],
[ 5, 9, 3, 9]])
三維數組
x3
array([[[ 4, 3, 0, 3, 5],
[ 0, 2, 3, 8, 1],
[ 3, 3, 3, 7, 0],
[ 1, 9, 9, 0, 4]],
[[ 7, 3, 2, 7, 2],
[ 0, 0, 4, 5, 5],
[ 6, 1000, 4, 1, 4],
[ 9, 8, 1, 1, 7]],
[[ 9, 9, 3, 6, 7],
[ 2, 0, 3, 5, 9],
[ 4, 4, 6, 4, 4],
[ 3, 4, 4, 8, 4]]])
print(x3[0,0,0])
print(x3[1,2,1]) # 二維 ,第3行,第2列
x3[1,2,1]=1000
print(x3)
4
8
[[[ 4 3 0 3 5]
[ 0 2 3 8 1]
[ 3 3 3 7 0]
[ 1 9 9 0 4]]
[[ 7 3 2 7 2]
[ 0 0 4 5 5]
[ 6 1000 4 1 4]
[ 9 8 1 1 7]]
[[ 9 9 3 6 7]
[ 2 0 3 5 9]
[ 4 4 6 4 4]
[ 3 4 4 8 4]]]
2.2.3 數組的切片: 獲取子數組
NumPy中切片語法和Python中列表的切片語法相同, 用冒號(:)分開.
x[start:stop:step]
如果以上三個參數都沒有設置,則使用默認值 start=0, stop=維度的大小, 和step=1
x = np.arange(10)
x
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x[:5] # 前5個
array([0, 1, 2, 3, 4])
x[5:]
array([5, 6, 7, 8, 9])
x[4:7]
array([4, 5, 6])
每隔一個數字
x[::2]
array([0, 2, 4, 6, 8])
x[1::2]
array([1, 3, 5, 7, 9])
一維數組逆序
x[::-1]
array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
二維數組
x2
array([[8, 8, 1, 6],
[7, 7, 8, 1],
[5, 9, 8, 9]])
x2[:2,:3]
array([[100, 8, 1],
[ 7, 7, 8]])
看見冒號(?,表示數組切片
x2[:,::2] # 所有行, 每隔一列
array([[8, 1],
[7, 8],
[5, 8]])
x2[::-1,::-1] # 顛倒順序
array([[9, 8, 9, 5],
[1, 8, 7, 7],
[6, 1, 8, 8]])
三維數組
x3
array([[[ 4, 3, 0, 3, 5],
[ 0, 2, 3, 8, 1],
[ 3, 3, 3, 7, 0],
[ 1, 9, 9, 0, 4]],
[[ 7, 3, 2, 7, 2],
[ 0, 0, 4, 5, 5],
[ 6, 1000, 4, 1, 4],
[ 9, 8, 1, 1, 7]],
[[ 9, 9, 3, 6, 7],
[ 2, 0, 3, 5, 9],
[ 4, 4, 6, 4, 4],
[ 3, 4, 4, 8, 4]]])
x3[::-1,::-1,::-1]
array([[[ 4, 8, 4, 4, 3],
[ 4, 4, 6, 4, 4],
[ 9, 5, 3, 0, 2],
[ 7, 6, 3, 9, 9]],
[[ 7, 1, 1, 8, 9],
[ 4, 1, 4, 1000, 6],
[ 5, 5, 4, 0, 0],
[ 2, 7, 2, 3, 7]],
[[ 4, 0, 9, 9, 1],
[ 0, 7, 3, 3, 3],
[ 1, 8, 3, 2, 0],
[ 5, 3, 0, 3, 4]]])
x3
array([[[ 4, 3, 0, 3, 5],
[ 0, 2, 3, 8, 1],
[ 3, 3, 3, 7, 0],
[ 1, 9, 9, 0, 4]],
[[ 7, 3, 2, 7, 2],
[ 0, 0, 4, 5, 5],
[ 6, 1000, 4, 1, 4],
[ 9, 8, 1, 1, 7]],
[[ 9, 9, 3, 6, 7],
[ 2, 0, 3, 5, 9],
[ 4, 4, 6, 4, 4],
[ 3, 4, 4, 8, 4]]])
x3[::,0,::] # 第一維度全選, 第二維度選第1行,第三維度全選
array([[4, 3, 0, 3, 5],
[7, 3, 2, 7, 2],
[9, 9, 3, 6, 7]])
x3[::2,::2,::2]
array([[[4, 0, 5],
[3, 3, 0]],
[[9, 3, 7],
[4, 6, 4]]])
獲取數組的單行或者單列
x2
array([[8, 8, 1, 6],
[7, 7, 8, 1],
[5, 9, 8, 9]])
x2[:,0] # 第1列
array([8, 7, 5])
x2[:,2] # 第3列
array([1, 8, 8])
x2[0,:] # 第1行
x2[0] #獲取行時簡寫表示方法, 對列不適用
array([8, 8, 1, 6])
x2[1,:]
array([7, 7, 8, 1])
NumPy數組切片和Python列表切片的不同之處: NumPy數組切片返回的是數組的試圖,而不是數值數據的副本. 在Pythong列表中,切片是值得副本.
-副本 : 可以理解爲複製了一份和原來的不一樣了.
-視圖 : 可以理解爲超鏈接,修改還是改的原來的路徑(文件)
-好處是,當處理大量的數據集時, 只需要修改切片即可修改原數據
print(x2)
[[100 8 1 6]
[ 7 7 8 1]
[ 5 9 8 9]]
從中抽取一個2*2的子數組
x2_sub = x2[::2,::2]
print(x2_sub)
[[100 1]
[ 5 8]]
x2_sub[0,0] = 100
x2
array([[100, 8, 1, 6],
[ 7, 7, 8, 1],
[ 5, 9, 8, 9]])
數組切片只能形成數組的視圖, 那如果要新建副本,用copy()方法
x2_sub = x2[::2,::2].copy()
print(x2)
print('*'*20)
print(x2_sub)
[[100 8 1 6]
[ 7 7 8 1]
[ 5 9 8 9]]
********************
[[100 1]
[ 5 8]]
x2_sub[1,1] = 99
print(x2)
print("*"*20)
print(x2_sub)
print('*'*20)
print(x2)
[[100 8 1 6]
[ 7 7 8 1]
[ 5 9 8 9]]
********************
[[100 1]
[ 5 99]]
********************
[[100 8 1 6]
[ 7 7 8 1]
[ 5 9 8 9]]
2.2.4 數組的變形
最常用的方法是用reshape()方法實現.
例如:期望將數字1-9,放入3*3的矩陣中,可採用如下方法:
-reshape() 數組的屬性
-newaxis() np的屬性
np.arange(1,10).reshape(3*3) #錯
np.arange(1,10).reshape(3,3)
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
原始數組的大小必須和變形後數組大小一致. reshape返回原數組的一個視圖
大小不一致的情況
a1 = ([1,2,3,4,5,6,7,8])
np.a1.reshape(3,3) # 表示方法錯. np沒有a1屬性
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-48-75353fe7632b> in <module>()
1 a1 = ([1,2,3,4,5,6,7,8,9])
----> 2 np.a1.reshape(3,3)
AttributeError: module 'numpy' has no attribute 'a1'
a1 = array([1,2,3,4,5,6,7,8]) # 數組array 前面必須帶np
a1.reshape((3,3))
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-52-202d01b8f390> in <module>()
----> 1 a1 = array([1,2,3,4,5,6,7,8])
2 a1.reshape((3,3)) # 表示方法錯
NameError: name 'array' is not defined
a1 = np.array([1,2,3,4,5,6,7,8,9])
a1.reshape((3,3))
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
np.array([1,2,3,4,5,6,7,8]).reshape(3,3) # 少了不行
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-49-1a37bef6142d> in <module>()
----> 1 np.array([1,2,3,4,5,6,7,8]).reshape(3,3)
ValueError: cannot reshape array of size 8 into shape (3,3)
np.array([1,2,3,4,5,6,7,8,9,10]).reshape(3,3) # 多了也不行
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-50-0a4d36c4b6a6> in <module>()
----> 1 np.array([1,2,3,4,5,6,7,8,9,10]).reshape(3,3)
ValueError: cannot reshape array of size 10 into shape (3,3)
x = np.array([1,2,3]) #一維數組
x.reshape(1,3) # 變成1行3列的二維數組
array([[1, 2, 3]])
x[np.newaxis,:]
array([[1, 2, 3]])
x.reshape(3,1)
array([[1],
[2],
[3]])
x[:,np.newaxis] # newaxis 屬於關鍵字
array([[1],
[2],
[3]])
2.2.5 數組的拼接和分裂
多個數組合併成一個或者一個數組拆分成多個
-np.concatenate():將數組元組和數組列表作爲第一個參數
-np.vstack()
-np.hstack()
x = np.array([1,2,3])
y = np.array([3,2,1])
x_y = np.concatenate([x,y])
print(x_y)
print(x_y.ndim)
[1 2 3 3 2 1]
1
z = [99,99,99] # 不用 np.array([99,99,99])
np.concatenate([x,y,z])
array([ 1, 2, 3, 3, 2, 1, 99, 99, 99])
x1 = [99,99,99] # 這是一個列表
x2 = np.array([99,99,99])
print(x1 == x2)
print(x1 is x2)
[ True True True]
False
二維數組的拼接
#沿着第一個軸拼接? 沿着第一個軸拼接,爲什麼是縱向
import numpy as np
x1 = np.array([[1,2,3],
[4,5,6]])
np.concatenate([x1,x1]) # 中括號不能少
array([[1, 2, 3],
[4, 5, 6],
[1, 2, 3],
[4, 5, 6]])
# 沿着第二個軸拼接, 沿着水平方向
np.concatenate([x1,x1],axis=1) # 注意中括號和圓括號的位置
array([[1, 2, 3, 1, 2, 3],
[4, 5, 6, 4, 5, 6]])
沿着固定維度處理數組時, 使用
np.vstack(垂直棧)
np.hstack(水平棧)函數更簡潔 ??
x1 = np.array([1,2,3])
x2 = np.array([[9,8,7],
[2,5,9]])
#垂直棧數組
np.vstack([x1,x2])
array([[1, 2, 3],
[9, 8, 7],
[2, 5, 9]])
#水平棧數組
x3 = np.array([[99],
[99]])
np.hstack([x3,x2])
array([[99, 9, 8, 7],
[99, 2, 5, 9]])
數組的分裂
-np.split()
-np.hsplit()
-np.vsplit()
x = [1,2,3,99,99,3,2,1] # 這不是一個序列碼
x1,x2,x3 = np.split(x,(3,5)) # 注意 x 和[3,5]的位置與括號,也可以用(3,5)
print(x1,x2,x3)
[1 2 3] [99 99] [3 2 1]
x1 = np.arange(16).reshape(4,4)
up,low = np.vsplit(x1,2) # [2]也可以寫成(2),也可以不加括號 ?
print(up)
print('*'*20)
print(low)
print('*'*20)
print(x1)
[[0 1 2 3]
[4 5 6 7]]
********************
[[ 8 9 10 11]
[12 13 14 15]]
********************
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]]
left,right = np.hsplit(x1,[2]) # 爲什麼此處的中括號必須
print(left)
print('*'*20)
print(right)
[1 2]
********************
[3]