本篇筆記是根據(jù)學習《Python for data analysis》這本英文教程里的Numpy這一部分來記錄的筒饰。這本書在網(wǎng)上的評價還是很高的缴啡,里面講的東西也比較細壁晒,鑒于是英文的,所以我就打算只挑部分來看业栅,時間充裕的同學可以從頭到尾的細看一遍秒咐。
Numpy,是Numerical Python的簡寫,它是Python里數(shù)字計算的最重要的一個基礎(chǔ)包碘裕。
The NumPy ndarray: A Multidimensional Array Object
Numpy ndarray:一個多維數(shù)組對象
Numpy 的一個關(guān)鍵的特點是其N-維數(shù)組對象携取,或者叫做ndarray,它是一個快速的帮孔,靈活的大數(shù)據(jù)python“容器”雷滋。Arrays使得你可以對整個block使用簡單的語法來進行數(shù)學計算文兢。舉個例子,導入Numpy并且生成一個小的隨機數(shù)組:
#首先進入ipython姆坚,具體方法請見我前一篇文章
#這里你可以使用shell,或者web界面兼呵,根據(jù)你喜好來
$ ipython
Python 3.7.6 (default, Jan 8 2020, 19:59:22)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.12.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import numpy as np #導入Numpy
In [2]: data = np.random.randn(2,3) #生成隨機數(shù)組兔辅,2個數(shù)組,每個里面3個元素
In [3]: data
Out[3]:
array([[ 0.01738749, -0.05367916, 0.72654692],
[ 1.45506185, -0.71293169, 1.35346708]])
對數(shù)組進行數(shù)學運算:
In [4]: data*10
Out[4]:
array([[ 0.17387488, -0.53679156, 7.26546924],
[14.55061854, -7.12931685, 13.53467077]])
In [5]: data+data
Out[5]:
array([[ 0.03477498, -0.10735831, 1.45309385],
[ 2.91012371, -1.42586337, 2.70693415]])
ndarray是用于存放同種數(shù)據(jù)的多維“容器”维苔,也就是說懂昂,所有的元素必須是同樣的類型介时。每一個數(shù)組都有自己的shape,用shape
可以查看每一個維度的大小潮尝;使用dtype
可以查看數(shù)組內(nèi)的數(shù)據(jù)類型:
In [6]: data.shape
Out[6]: (2, 3)
In [7]: data.dtype
Out[7]: dtype('float64')
NOTE: Whenever you see “array,” “NumPy array,” or “ndarray” in the text,
with few exceptions they all refer to the same thing: the ndarray object.
Creating ndarrays
創(chuàng)建一個ndarray的最簡單的方法就是使用array
功能。比如說:
In [8]: data1 = [6, 7.5, 8, 0, 1]
In [9]: arr1 = np.array(data1)
In [10]: arr1
Out[10]: array([6. , 7.5, 8. , 0. , 1. ])
或者你想創(chuàng)建嵌套序列勉失,比如等長列表,將會被轉(zhuǎn)換為多維數(shù)組:
In [11]: data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]
In [12]: arr2 = np.array(data2)
In [13]: arr2
Out[13]:
array([[1, 2, 3, 4],
[5, 6, 7, 8]])
因為data2是一個由list組成的list顽素,所以arr2的shape是一個二維的數(shù)組徒蟆。你可以用ndim
和shape
來檢查:
In [14]: arr2.ndim #看維度
Out[14]: 2
In [15]: arr2.shape
Out[15]: (2, 4)
In [16]: arr2.dtype
Out[16]: dtype('int64') #數(shù)組內(nèi)數(shù)據(jù)類型是int整數(shù)
另外,np.array
還有很多其他的功能來創(chuàng)建新的arrays段审。比如說,它可以創(chuàng)建全是1或者全是0的array抑淫。還可以創(chuàng)建一個空的array姥闪,即沒有確定值:
In [17]: np.zeros(10) #創(chuàng)建全是0的一維數(shù)組
Out[17]: array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
In [18]: np.zeros((3,6)) #創(chuàng)建全是0的二維數(shù)組
Out[18]:
array([[0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0.]])
In [19]: np.empty((2,3,2)) #創(chuàng)建空數(shù)組
Out[19]:
array([[[6.95334423e-310, 0.00000000e+000],
[0.00000000e+000, 0.00000000e+000],
[0.00000000e+000, 0.00000000e+000]],
[[0.00000000e+000, 0.00000000e+000],
[0.00000000e+000, 0.00000000e+000],
[0.00000000e+000, 0.00000000e+000]]])
有的時候,
np.empty
創(chuàng)建的空數(shù)組筐喳,返回值不是0,而是一堆亂七八糟的值荣月,也就是“garbage” values槐脏。
Data Types for ndarrays
在你創(chuàng)建一個ndarray的時候,你可以指定這個ndarray里的數(shù)據(jù)類型是什么顿天,比如說:
In [20]: arr1 = np.array([1, 2, 3], dtype=np.float64)
In [21]: arr1
Out[21]: array([1., 2., 3.])
In [22]: arr2 = np.array([1, 2, 3], dtype=np.int32)
In [23]: arr2
Out[23]: array([1, 2, 3], dtype=int32)
In [24]: arr1.dtype
Out[24]: dtype('float64')
In [25]: arr2.dtype
Out[25]: dtype('int32')
此外牌废,你也可以更改一個數(shù)組的數(shù)據(jù)類型:
In [26]: arr = np.array([1, 2, 3, 4, 5])
In [27]: arr.dtype
Out[27]: dtype('int64')
In [28]: float_arr = arr.astype(np.float64) #把整數(shù)類型改成浮點類型
In [29]: float_arr.dtype
Out[29]: dtype('float64')
相反咽白,你也可以把浮點類型改成整數(shù),但是小數(shù)部分就會被截掉:
In [30]: arr = np.array([3.7, -1.2, -2.6, 0.5, 12.9, 10.1])
In [31]: arr
Out[31]: array([ 3.7, -1.2, -2.6, 0.5, 12.9, 10.1])
In [32]: arr.astype(np.int32)
Out[32]: array([ 3, -1, -2, 0, 12, 10], dtype=int32)
如果你的數(shù)組內(nèi)是字符串類型鸟缕,也可以使用這種方法進行轉(zhuǎn)換:
In [33]: numeric_strings = np.array(['1.25', '-9.6', '42'], dtype=np.string_)
In [34]: numeric_strings.astype(float)
Out[34]: array([ 1.25, -9.6 , 42. ])
在使用
numpy.string_
進行數(shù)據(jù)類型轉(zhuǎn)換的時候需要注意,有的時候會在沒有任何提示下截斷你的數(shù)據(jù)授段。
Arithmetic(運算) with NumPy Arrays
array很重要,因為它們使你能夠?qū)?shù)據(jù)批量處理操作届搁,而不需要編寫任何for循環(huán)窍育。NumPy用戶稱之為向量化。任何算術(shù)必須在相同大小數(shù)組之間進行操作:
In [35]: arr = np.array([[1., 2., 3.], [4., 5., 6.]])
In [36]: arr
Out[36]:
array([[1., 2., 3.],
[4., 5., 6.]])
In [37]: arr*arr
Out[37]:
array([[ 1., 4., 9.],
[16., 25., 36.]])
In [38]: 1/arr
Out[38]:
array([[1. , 0.5 , 0.33333333],
[0.25 , 0.2 , 0.16666667]])
In [39]: arr**0.5
Out[39]:
array([[1. , 1.41421356, 1.73205081],
[2. , 2.23606798, 2.44948974]])
你還可以比較兩個不同的array的大小漱抓,這里比較的時候是數(shù)組之間相同位置進行比較:
In [40]: arr2 = np.array([[0., 4., 1.], [7., 2., 12.]])
In [41]: arr2
Out[41]:
array([[ 0., 4., 1.],
[ 7., 2., 12.]])
In [42]: arr2>arr
Out[42]:
array([[False, True, False],
[ True, False, True]])
Basic Indexing(索引) and Slicing(切片)
在Numpy里乞娄,你有很多種方法可以在data里選擇一個subset,或者選擇出某一個元素补胚。對于一維數(shù)組來說是非常簡單的:
In [43]: arr=np.arange(10)
In [44]: arr
Out[44]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [45]: arr[5]
Out[45]: 5
In [46]: arr[5:8]
Out[46]: array([5, 6, 7])
In [47]: arr[5:8]=12 #從索引的第5位到第7位改成12(這里涉及python的索引規(guī)則)
In [48]: arr
Out[48]: array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])
對數(shù)組進行“切片”:
In [49]: arr_slice=arr[5:8]
In [50]: arr_slice
Out[50]: array([12, 12, 12])
對切出來的“片段”進行修改:
In [51]: arr_slice[1]=12345
In [52]: arr #對切片的修改會影響整個原始數(shù)組
Out[52]:
array([ 0, 1, 2, 3, 4, 12, 12345, 12, 8,
9])
對于二維數(shù)組來說:
In [53]: arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
In [54]: arr2d[2]
Out[54]: array([7, 8, 9])
In [55]: arr2d[0][2]
Out[55]: 3
In [56]: arr2d[0,2] #這樣的表示方法可以參考下面的示意圖來進行理解
Out[56]: 3
那如果是多維數(shù)組呢溶其?比如現(xiàn)在有一個2 × 2 × 3 array:
In [57]: arr3d = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
In [58]: arr3d
Out[58]:
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
In [59]: arr3d[0]
Out[59]:
array([[1, 2, 3],
[4, 5, 6]])
更改多維數(shù)組里的數(shù)據(jù):
In [60]: old_values=arr3d[0].copy()
In [61]: arr3d[0]=42 #更改其中一個元素敦间,使得這個元素里的所有值都變成42
In [62]: arr3d
Out[62]:
array([[[42, 42, 42],
[42, 42, 42]],
[[ 7, 8, 9],
[10, 11, 12]]])
In [63]: arr3d[0]=old_values #再改回來
In [64]: arr3d
Out[64]:
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
對多維數(shù)組切片:
In [65]: arr3d[1,0]
Out[65]: array([7, 8, 9])
In [66]: arr2d
Out[66]:
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
In [67]: arr2d[:2]
Out[67]:
array([[1, 2, 3],
[4, 5, 6]])
In [68]: arr2d[:2,1:] #在二維數(shù)組里取第0和1個索引對應(yīng)的list廓块,然后在這兩個list里取從索引1開始,到最后的元素
Out[68]:
array([[2, 3],
[5, 6]])
In [69]: arr2d[1,:2] #取索引是1的list带猴,然后在這個list里取從開始到索引為2(不包括2)的元素
Out[69]: array([4, 5])
有關(guān)二維數(shù)組的切片的索引位置,可以參考下圖:
將數(shù)組里小于0的數(shù)都設(shè)置為0:
In [70]: data = np.random.randn(7, 4)
In [71]: data
Out[71]:
array([[ 1.07484753, -1.37075898, -1.76641029, 1.39686773],
[ 1.12808743, 0.38325471, 2.26384631, 1.21861537],
[-0.37522887, -1.2066686 , -0.07729884, 1.76493675],
[ 0.51771666, 0.14024697, 0.91802525, 0.88580838],
[-0.17494945, -0.14744639, 0.82242766, -0.060019 ],
[ 1.11820368, -1.18942934, 1.34140358, -0.9074736 ],
[ 0.01312651, -2.17228966, 0.97890648, 1.51395293]])
In [72]: data[data<0]=0
In [73]: data
Out[73]:
array([[1.07484753, 0. , 0. , 1.39686773],
[1.12808743, 0.38325471, 2.26384631, 1.21861537],
[0. , 0. , 0. , 1.76493675],
[0.51771666, 0.14024697, 0.91802525, 0.88580838],
[0. , 0. , 0.82242766, 0. ],
[1.11820368, 0. , 1.34140358, 0. ],
[0.01312651, 0. , 0.97890648, 1.51395293]])
Fancy Indexing
花式索引是NumPy采用的術(shù)語,用于描述對整數(shù)數(shù)組進行索引:
In [74]: arr=np.empty((8,4)) #比如先創(chuàng)建一個8*4的空數(shù)組
In [75]: arr #這就是上面說到的口予,有時候你創(chuàng)建的空數(shù)組不是每次都會是0
Out[75]:
array([[ 6.95334381e-310, 0.00000000e+000, 6.93002310e-310,
4.34669976e-118],
[ 6.93002307e-310, 6.93002310e-310, 1.04440620e+181,
6.93002307e-310],
[ 6.93002310e-310, -1.76250980e-304, 6.93002307e-310,
6.93002310e-310],
[ 8.10582968e-283, 6.93002307e-310, 6.93002310e-310,
2.58280046e+280],
[ 6.93002308e-310, 6.93002461e-310, 1.20122413e+036,
6.93002307e-310],
[ 6.93002461e-310, 6.39556658e-245, 6.93002307e-310,
6.93002461e-310],
[ 9.69473502e+012, 6.93002307e-310, 6.93002461e-310,
2.99497312e+029],
[ 6.93002307e-310, 6.93002461e-310, -2.36433447e+212,
6.93002307e-310]])
In [76]: for i in range(8): #給這個空數(shù)組賦值
...: arr[i]=i
...:
In [77]: arr
Out[77]:
array([[0., 0., 0., 0.],
[1., 1., 1., 1.],
[2., 2., 2., 2.],
[3., 3., 3., 3.],
[4., 4., 4., 4.],
[5., 5., 5., 5.],
[6., 6., 6., 6.],
[7., 7., 7., 7.]])
選擇你想提取的subset沪停,并按照特定順序排列:
In [78]: arr[[4,3,0,6]]
Out[78]:
array([[4., 4., 4., 4.],
[3., 3., 3., 3.],
[0., 0., 0., 0.],
[6., 6., 6., 6.]])
In [79]: arr[[-3,-5,-7]] #負數(shù)表示從倒數(shù)順序來取subset
Out[79]:
array([[5., 5., 5., 5.],
[3., 3., 3., 3.],
[1., 1., 1., 1.]])
通用函數(shù)
In [1]: import numpy as np
In [2]: arr = np.arange(10)
In [3]: arr
Out[3]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [4]: np.sqrt(arr) #計算每一個元素的開方
Out[4]:
array([0. , 1. , 1.41421356, 1.73205081, 2. ,
2.23606798, 2.44948974, 2.64575131, 2.82842712, 3. ])
In [5]: np.exp(arr) #numpy.exp():返回e的冪次方裳涛,e是一個常數(shù)為2.71828
Out[5]:
array([1.00000000e+00, 2.71828183e+00, 7.38905610e+00, 2.00855369e+01,
5.45981500e+01, 1.48413159e+02, 4.03428793e+02, 1.09663316e+03,
2.98095799e+03, 8.10308393e+03])
Unique
針對一維數(shù)組众辨,這個函數(shù)是把數(shù)組里“不重復的”元素挑選出來。
In [11]: names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
In [12]: np.unique(names)
Out[12]: array(['Bob', 'Joe', 'Will'], dtype='<U4')
In [13]: ints = np.array([3, 3, 3, 2, 2, 1, 1, 4, 4])
In [14]: np.unique(ints)
Out[14]: array([1, 2, 3, 4])