Python 数据分析三剑客之 NumPy(三):数组的迭代与位运算
CSDN 課程推薦:《Python 數據分析與挖掘》,講師劉順祥,浙江工商大學統計學碩士,數據分析師,曾擔任唯品會大數據部擔任數據分析師一職,負責支付環節的數據分析業務。曾與聯想、亨氏、網魚網咖等企業合作多個企業級項目。
NumPy 系列文章:
- Python 數據分析三劍客之 NumPy(一):理解 NumPy / 數組基礎
- Python 數據分析三劍客之 NumPy(二):數組索引 / 切片 / 廣播 / 拼接 / 分割
- Python 數據分析三劍客之 NumPy(三):數組的迭代與位運算
- Python 數據分析三劍客之 NumPy(四):字符串函數總結與對比
- Python 數據分析三劍客之 NumPy(五):數學 / 算術 / 統計 / 排序 / 條件 / 判斷函數合集
- Python 數據分析三劍客之 NumPy(六):矩陣 / 線性代數庫與 IO 操作
另有 Pandas、Matplotlib 系列文章已更新完畢,歡迎關注:
- Pandas 系列文章:https://itrhx.blog.csdn.net/category_9780397.html
- Matplotlib 系列文章:https://itrhx.blog.csdn.net/category_9780418.html
推薦學習資料與網站(博主參與部分文檔翻譯):
- NumPy 官方中文網:https://www.numpy.org.cn/
- Pandas 官方中文網:https://www.pypandas.cn/
- Matplotlib 官方中文網:https://www.matplotlib.org.cn/
- NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table
文章目錄
- 【1x00】numpy.nditer 迭代器對象
- 【1x01】單數組的迭代
- 【1x02】控制迭代順序
- 【1x03】修改數組元素
- 【1x04】使用外部循環
- 【1x05】跟蹤元素索引
- 【1x06】廣播數組迭代
- 【2x00】NumPy 位運算
- 【2x01】numpy.bitwise_and()
- 【2x02】numpy.bitwise_or()
- 【2x03】numpy.bitwise_xor()
- 【2x04】numpy.invert()
- 【2x05】numpy.left_shift()
- 【2x06】numpy.right_shift()
這里是一段防爬蟲文本,請讀者忽略。 本文原創首發于 CSDN,作者 TRHX。 博客首頁:https://itrhx.blog.csdn.net/ 本文鏈接:https://itrhx.blog.csdn.net/article/details/105185337 未經授權,禁止轉載!惡意轉載,后果自負!尊重原創,遠離剽竊!
【1x00】numpy.nditer 迭代器對象
numpy.nditer 是 NumPy 的迭代器對象,迭代器對象提供了許多靈活的方法來訪問一個或多個數組中的所有元素,簡單來說,迭代器最基本的任務就是完成對數組元素的訪問。
【1x01】單數組的迭代
單數組迭代示例:
>>> import numpy as np >>> a = np.arange(10).reshape(2, 5) >>> print(a) [[0 1 2 3 4][5 6 7 8 9]] >>> for i in np.nditer(a):print(i, end=' ')0 1 2 3 4 5 6 7 8 9注意:默認對數組元素的訪問順序,既不是以標準 C(行優先) 也不是 Fortran 順序(列優先),選擇的順序是和數組內存布局一致的,這樣做是為了提高訪問效率,反映了默認情況下只需要訪問每個元素而不關心特定排序的想法。以下用一個數組的轉置來理解這種訪問機制。
>>> import numpy as np >>> a = np.arange(10).reshape(2, 5) >>> print(a) [[0 1 2 3 4][5 6 7 8 9]] >>> >>> b = a.T >>> print(b) [[0 5][1 6][2 7][3 8][4 9]] >>> >>> c = a.T.copy(order='C') >>> print(c) [[0 5][1 6][2 7][3 8][4 9]] >>> >>> for i in np.nditer(a):print(i, end=' ')0 1 2 3 4 5 6 7 8 9 >>> >>> for i in np.nditer(b):print(i, end=' ')0 1 2 3 4 5 6 7 8 9 >>> >>> for i in np.nditer(c):print(i, end=' ')0 5 1 6 2 7 3 8 4 9例子中 a 是一個 2 行 5 列的數組,b 數組對 a 進行了轉置,而 c 數組則是對 a 進行轉置后按照 C order(行優先)的形式復制到新內存中儲存,b 數組雖然進行了轉置操作,但是其元素在內存當中的儲存順序仍然和 a 一樣,所以對其迭代的效果也和 a 一樣,c 數組元素在新內存當中的儲存順序不同于 a 和 b,因此對其迭代的效果也不一樣。
【1x02】控制迭代順序
如果想要按照特定順序來對數組進行迭代,nditer 同樣也提供了 order 參數,可選值為:C F A K
- numpy.nditer(a, order='C'):標準 C 順序,即行優先;
- numpy.nditer(a, order='F'): Fortran 順序,即列優先;
- numpy.nditer(a, order='A'):如果所有數組都是 Fortran 順序的,則 A 表示以 F 順序,否則以 C 順序;
- numpy.nditer(a, order='K'):默認值,保持原數組在內存當中的順序。
應用舉例:
>>> import numpy as np >>> a = np.arange(12).reshape(3, 4) >>> print(a) [[ 0 1 2 3][ 4 5 6 7][ 8 9 10 11]] >>> >>> for i in np.nditer(a, order='C'):print(i, end= ' ')0 1 2 3 4 5 6 7 8 9 10 11 >>> >>> for i in np.nditer(a, order='F'):print(i, end= ' ')0 4 8 1 5 9 2 6 10 3 7 11 >>> >>> for i in np.nditer(a, order='K'):print(i, end= ' ')0 1 2 3 4 5 6 7 8 9 10 11【1x03】修改數組元素
nditer 對象提供了可選參數 op_flags,默認情況下,該參數值為 readonly(只讀),如果在遍歷數組的同時,要實現對數組中元素值的修改,則可指定 op_flags 值為 readwrite(讀寫) 或者 writeonly(只寫)。
應用舉例:
>>> import numpy as np >>> a = np.arange(10).reshape(2, 5) >>> print(a) [[0 1 2 3 4][5 6 7 8 9]] >>> >>> for i in np.nditer(a, op_flags=['readwrite']):i[...] = i+1>>> print(a) [[ 1 2 3 4 5][ 6 7 8 9 10]] >>> import numpy as np >>> li = [] >>> a = np.arange(12).reshape(3, 4) >>> print(a) [[ 0 1 2 3][ 4 5 6 7][ 8 9 10 11]] >>> >>> for i in np.nditer(a, op_flags=['readwrite']):li.append(i*2)>>> print(li) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]【1x04】使用外部循環
nditer 對象支持 flags 參數,該參數最常用的值是 external_loop,表示使給定的值為具有多個值的一維數組。
通俗來講,當 Ndarray 的順序和遍歷的順序一致時,就會將所有元素組成一個一維數組返回;當 Ndarray 的順序和遍歷的順序不一致時,則返回每次遍歷的一維數組
官方介紹:https://docs.scipy.org/doc/numpy/reference/arrays.nditer.html#using-an-external-loop
應用舉例:
>>> import numpy as np >>> a = np.array([[0,1,2,3], [4,5,6,7], [8,9,10,11]], order='C') >>> for i in np.nditer(a, flags=['external_loop'], order='C' ):print(i, end=' ')[ 0 1 2 3 4 5 6 7 8 9 10 11] >>> for i in np.nditer(a, flags=['external_loop'], order='F' ):print(i, end=' ')[0 4 8] [1 5 9] [ 2 6 10] [ 3 7 11]【1x05】跟蹤元素索引
在迭代期間,我們有可能希望在計算中使用當前元素的索引值,同樣可以通過指定 flags 參數的取值來實現:
| c_index | 跟蹤 C 順序索引 |
| f_index | 跟蹤 Fortran 順序索引 |
| multi_index | 跟蹤多個索引或每個迭代維度一個索引的元組(多重索引) |
在以下實例當中:
當參數為 c_index 和 f_index 時,it.index 用于輸出元素的索引值
當參數為 multi_index 時,it.multi_index 用于輸出元素的索引值
it.iternext() 表示進入下一次迭代,直到迭代完成為止
multi_index 可理解為對迭代對象進行多重索引
>>> import numpy as np >>> a = np.arange(6).reshape(2, 3) >>> it = np.nditer(a, flags=['c_index']) >>> while not it.finished:print('%d <%s>' %(it[0], it.index))it.iternext()0 <0> True 1 <1> True 2 <2> True 3 <3> True 4 <4> True 5 <5> False >>> import numpy as np >>> a = np.arange(6).reshape(2, 3) >>> it = np.nditer(a, flags=['f_index']) >>> while not it.finished:print('%d <%s>' %(it[0], it.index))it.iternext()0 <0> True 1 <2> True 2 <4> True 3 <1> True 4 <3> True 5 <5> False >>> import numpy as np >>> a = np.arange(6).reshape(2, 3) >>> it = np.nditer(a, flags=['multi_index']) >>> while not it.finished:print('%d <%s>' %(it[0], it.multi_index))it.iternext()0 <(0, 0)> True 1 <(0, 1)> True 2 <(0, 2)> True 3 <(1, 0)> True 4 <(1, 1)> True 5 <(1, 2)> False【1x06】廣播數組迭代
如果兩個數組滿足廣播原則,nditer 對象能夠同時迭代它們,即廣播數組迭代(多數組的迭代)。
>>> import numpy as np >>> a = np.arange(3) >>> b = np.arange(6).reshape(2,3) >>> print(a) [0 1 2] >>> print(b) [[0 1 2][3 4 5]] >>> for m, n in np.nditer([a,b]):print(m,n)0 0 1 1 2 2 0 3 1 4 2 5如果兩個數組不滿足廣播原則,將會拋出異常:
>>> import numpy as np >>> a = np.arange(4) >>> b = np.arange(6).reshape(2,3) >>> print(a) [0 1 2 3] >>> print(b) [[0 1 2][3 4 5]] >>> for m, n in np.nditer([a,b]):print(m,n)Traceback (most recent call last):File "<pyshell#55>", line 1, in <module>for m, n in np.nditer([a,b]): ValueError: operands could not be broadcast together with shapes (4,) (2,3)這里是一段防爬蟲文本,請讀者忽略。 本文原創首發于 CSDN,作者 TRHX。 博客首頁:https://itrhx.blog.csdn.net/ 本文鏈接:https://itrhx.blog.csdn.net/article/details/105185337 未經授權,禁止轉載!惡意轉載,后果自負!尊重原創,遠離剽竊!
【2x00】NumPy 位運算
由于位運算是直接對整數在內存中的二進制位進行操作,所以有必要先了解一下如何來表示數字的二進制。
在 Python 中,提供了一個內置函數 bin(),將整數轉換為以 0b 為前綴的二進制字符串,如果要去掉 0b 前綴,則可以使用 format 方法,因為返回的是字符串,所以也可以使用切片等其他方法去掉前綴。
>>> bin(3) '0b11' >>> format(3, 'b') '11' >>> f'{3:b}' '11'除了內置函數以外,NumPy 還提供了一個 numpy.binary_repr 函數,該函數的作用也是以字符串形式返回輸入數字的二進制表示形式。
基本語法:numpy.binary_repr(num, width=None)
參數解釋:
| num | 要表示的數,只能是整數形式 |
| width | 可選項,對于負數,如果未指定 width,則會在前面添加減號,如果指定了 width,則返回該寬度的負數的二進制補碼 |
以下是 NumPy 數組當中用到的位運算函數,各函數與其對應的用操作符計算的作用相同。
| bitwise_and | 對數組元素進行按位與(AND)操作 | & |
| bitwise_or | 對數組元素進行按位或(OR)操作 | | |
| bitwise_xor | 對數組元素執行按位異或(XOR)操作 | ^ |
| invert | 對數組元素執行按位取反(NOT)操作 | ~ |
| left_shift | 將數組元素的二進制形式向左移動指定位,右側附加相等數量的 0 | << |
| right_shift | 將數組元素的二進制形式向右移動指定位,左側附加相等數量的 0 | >> |
【2x01】numpy.bitwise_and()
numpy.bitwise_and() 函數對數組元素進行按位與(AND)操作。
>>> import numpy as np >>> np.binary_repr(10), np.binary_repr(15) ('1010', '1111') >>> np.bitwise_and(10, 15) 10 >>> np.binary_repr(10) '1010'numpy.bitwise_and() 函數還支持多個元素同時進行按位與操作:
>>> import numpy as np >>> np.bitwise_and([14,3], 13) array([12, 1], dtype=int32) >>> import numpy as np >>> np.bitwise_and([11,7], [4,25]) array([0, 1], dtype=int32) >>> >>> np.array([11,7]) & np.array([4,25]) # 函數與 & 操作符作用一樣 array([0, 1], dtype=int32)還可以傳入布爾值:
>>> import numpy as np >>> np.bitwise_and([True,False,True],[True,True,True]) array([ True, False, True])【2x02】numpy.bitwise_or()
numpy.bitwise_or() 函數對數組元素進行按位或(OR)操作。
>>> import numpy as np >>> np.binary_repr(10), np.binary_repr(14) ('1010', '1110') >>> np.bitwise_or(10, 14) 14 >>> np.binary_repr(14) '1110'和按位與操作一樣,numpy.bitwise_or() 函數也支持傳入布爾值和多個元素同時進行操作:
>>> import numpy as np >>> np.bitwise_or([33,4], 1) array([33, 5], dtype=int32) >>> >>> np.bitwise_or([33,4], [1,2]) array([33, 6], dtype=int32) >>> >>> np.bitwise_or(np.array([2,5,255]), np.array([4,4,4])) array([ 6, 5, 255], dtype=int32) >>> >>> np.array([2,5,255]) | np.array([4,4,4]) # 函數與 | 運算符作用相同 array([ 6, 5, 255], dtype=int32) >>> >>> np.bitwise_or([True, True], [False,True]) array([ True, True])【2x03】numpy.bitwise_xor()
numpy.bitwise_xor() 函數對數組元素執行按位異或(XOR)操作。
>>> import numpy as np >>> bin(13), bin(17) ('0b1101', '0b10001') >>> np.bitwise_xor(13,17) 28 >>> bin(28) '0b11100' >>> import numpy as np >>> np.bitwise_xor([31,3], 5) array([26, 6], dtype=int32) >>> >>> np.bitwise_xor([31,3], [5,6]) array([26, 5], dtype=int32) >>> >>> np.array([31,3]) ^ np.array([5,6]) # 函數與 ^ 運算符作用相同 array([26, 5], dtype=int32) >>> >>> np.bitwise_xor([True, True], [False, True]) array([ True, False])【2x04】numpy.invert()
numpy.invert() 函數將對數組元素執行按位取反(NOT)操作,注意按位取反和取反操作不同。
按位取反通用公式:~x = -(x+1)
我們將原來的數稱為 A,按位取反后的數稱為 B,按位取反的步驟如下:
先求 A 的補碼,對 A 的補碼每一位取反(包括符號位),得到的數為 B 的補碼,將 B 的補碼轉換為 B 的原碼得到最終結果。
分情況具體討論:
| 正數按位取反步驟 |
1、將其轉換成二進制形式;
2、求其補碼(正數的原碼、反碼、補碼都相同);
3、將補碼每一位進行取反操作(包括符號位);
【經過步驟 3 后的結果為一個二進制形式的負數補碼,接下來將這個負數補碼轉換成原碼(負數原碼到補碼的逆運算)】
4、對步驟 3 得到的負數 -1 得到反碼;
5、對步驟 4 得到的反碼再進行取反得到原碼;
6、將步驟 5 得到的原碼轉回十進制即是最終結果。
| 負數按位取反步驟 |
1、將其轉換成二進制形式;
2、求其補碼(先求其反碼、符號位不變,末尾 +1 得到其補碼);
3、將補碼每一位進行取反操作(包括符號位);
【經過步驟 3 后的結果為一個二進制形式的正數,接下來將這個正數轉換成原碼即可】
4、由于正數的原碼、反碼、補碼都相同,所以直接將其轉換成十進制即為最終結果。
注意:第 3 步的取反操作,包括符號位都要取反,與求反碼不同,求反碼時符號位不變。
具體計算舉例(二進制前 4 位為符號位):
| 9 的按位取反 |
① 原碼:0000 1001
② 反碼:0000 1001
③ 補碼:0000 1001
④ 取反:1111 0110 (包括符號位一起取反,得到新的補碼)
⑤ 反碼:1111 0101 (將新的補碼 -1 得到其反碼)
⑥ 原碼:1111 1010 (將反碼取反得到原碼)
⑦ 轉為十進制:-10
| -9 的按位取反 |
① 原碼:1111 1001
② 反碼:1111 0110
③ 補碼:1111 0111
④ 取反:0000 1000 (包括符號位一起取反,得到新的補碼)
⑤ 原碼:0000 1000 (由于新的補碼為正數,所以原碼補碼相同)
⑥ 轉為十進制:8
其他關于按位取反操作的知識:
-
按位取反運計算方法
-
[干貨]按位取反怎么算?~圖文詳解
Python 代碼應用示例:
>>> import numpy as np >>> np.binary_repr(9, width=8) '00001001' >>> np.invert(9) -10 >>> np.invert(-9) 8【2x05】numpy.left_shift()
numpy.left_shift() 函數將數組元素的二進制形式向左移動指定位,右側附加相等數量的 0。
應用舉例:
>>> import numpy as np >>> np.binary_repr(10, width=8) '00001010' >>> np.left_shift(10, 2) 40 >>> 10 << 2 # numpy.left_shift 函數相當于 Python 當中的 << 運算符 40 >>> np.binary_repr(40, width=8) '00101000'【2x06】numpy.right_shift()
numpy.right_shift() 函數將數組元素的二進制形式向右移動指定位,左側附加相等數量的 0
>>> import numpy as np >>> np.binary_repr(10, width=8) '00001010' >>> np.right_shift(10, 2) 2 >>> 10 >> 2 # numpy.right_shift 函數相當于 Python 當中的 >> 運算符 2 >>> np.binary_repr(2, width=8) '00000010'這里是一段防爬蟲文本,請讀者忽略。 本文原創首發于 CSDN,作者 TRHX。 博客首頁:https://itrhx.blog.csdn.net/ 本文鏈接:https://itrhx.blog.csdn.net/article/details/105185337 未經授權,禁止轉載!惡意轉載,后果自負!尊重原創,遠離剽竊!
總結
以上是生活随笔為你收集整理的Python 数据分析三剑客之 NumPy(三):数组的迭代与位运算的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 出手了!看看两部门联合发布的《网络主播行
- 下一篇: 矿卡时代过去了 板卡三巨头加快显卡清仓: