Numpy 修煉之道 (11)—— 掩碼陣列
有時候資料集中存在缺失、異常或者無效的數值,我們可以標記該元素為被遮蔽(無效)狀態。
>>> import numpy as np
>>> import numpy.ma as ma
>>> x = np.array([1, 2, 3, -99, 5])
>>> x
array([ 1, 2, 3, -99, 5])
現在可以創造一個掩碼陣列(標記第四個元素為無效狀態)。
>>> mx = ma.masked_array(x, mask=[0,
0, 0, 1, 0])
>>> mx
masked_array(data = [1 2 3 -- 5],
mask = [False False False True False],
fill_value = 999999)
接下來可以計算平均值而不用考慮無效資料。
>>> mx.mean()
2.75
訪問掩碼
可通過其mask屬性訪問掩碼陣列的掩碼。我們必須記住,掩碼中的True條目表示無效資料。
>>> mx
masked_array(data = [1 2 3 -- 5],
mask = [False False False True False],
fill_value = 999999)
>>> mx.mask
array([False, False, False, True, False], dtype=bool)
只訪問有效資料
當只想訪問有效資料時,我們可以使用掩碼的逆作為索引。可以使用numpy.logical_not函式或簡單使用~運算子計算掩碼的逆:
>>> x = ma.array([[1, 2], [3, 4]],
mask=[[0, 1], [1, 0]])
>>> x[~x.mask]
masked_array(data = [1 4],
mask = [False False],
fill_value = 999999)
另一種檢索有效資料的方法是使用compressed方法,該方法返回一維ndarray(或其子類之一,取決於baseclass屬性):
>>> x.compressed()
array([1, 4])
修改掩碼
通過將True賦給掩碼,可以立即遮蔽陣列的所有資料:
>>> x = ma.array([1, 2, 3], mask=[0,0, 1])
>>> x.mask = True
>>> x
masked_array(data = [-- -- --],
mask = [ True True True],
fill_value = 999999)
最後,可以通過向掩碼分配一系列布林值來對特定資料條目進行掩碼和/或取消掩碼:
>>> x = ma.array([1, 2, 3])
>>> x.mask = [0, 1, 0]
>>> x
masked_array(data = [1 -- 3],
mask = [False True False],
fill_value = 999999)
取消掩碼
要取消遮蔽一個或多個特定資料條目,我們只需為它們分配一個或多個新的有效值:
>>> x = ma.array([1, 2, 3], mask=[0,0, 1])
>>> x
masked_array(data = [1 2 --],
mask = [False False True],
fill_value = 999999)
>>> x[-1] = 5
>>> x
masked_array(data = [1 2 5],
mask = [False False False],
fill_value = 999999)
要取消遮蔽掩碼陣列的所有掩碼條目(假設掩碼不是硬掩碼),最簡單的解決方案是將常量nomask分配給掩碼:
>>> x = ma.array([1, 2, 3], mask=[0,0, 1])
>>> x
masked_array(data = [1 2 --],
mask = [False False True],
fill_value = 999999)
>>> x.mask = ma.nomask
>>> x
masked_array(data = [1 2 3],
mask = [False False False],
fill_value = 999999)
索引和切片
由於MaskedArray是numpy.ndarray的子類,它會繼承其用於索引和切片的機制。
當訪問沒有命名欄位的被掩蔽陣列的單個條目時,輸出是標量(如果掩碼的相應條目是False)或特殊值masked (如果掩碼的相應條目為True):
>>> x = ma.array([1, 2, 3], mask=[0,0, 1])
>>> x[0]
1
>>> x[-1]
masked_array(data = --,
mask = True,
fill_value = 1e+20)
>>> x[-1] is ma.masked
True
如果掩蔽的陣列具有命名欄位,訪問單個條目將返回numpy.void物件(如果沒有掩碼),或者如果至少一個欄位具有與初始陣列相同的dtype的0d掩碼陣列的欄位被遮蔽。
>>> y = ma.masked_array([(1,2), (3,4)],
...
mask=[(0, 0), (0, 1)],
...
dtype=[('a', int), ('b', int)])
>>> y[0]
(1, 2)
>>> y[-1]
masked_array(data = (3, --),
mask = (False, True),
fill_value = (999999,999999),
dtype = [('a', '<i4'), ('b', '<i4')])
當訪問切片時,輸出是掩蔽的陣列,其data屬性是原始資料的檢視,並且其掩碼是nomask(如果沒有無效條目原始陣列)或原始掩碼的相應切片的副本。需要複製以避免將掩模的任何修改傳播到原始版本。
>>> x = ma.array([1, 2, 3, 4, 5],
mask=[0, 1, 0, 0, 1])
>>> mx = x[:3]
>>> mx
masked_array(data = [1 -- 3],
mask = [False True False],
fill_value = 999999)
>>> mx[1] = -1
>>> mx
masked_array(data = [1 -1 3],
mask = [False True False],
fill_value = 999999)
>>> x.mask
array([False, True, False, False, True], dtype=bool)
>>> x.data
array([ 1, -1, 3, 4, 5])
腦洞科技棧專注於人工智慧與量化投資領域
瞭解更多幹貨文章,關注小程式八斗問答