Python:numpy.ma模塊


翻譯總結自:The numpy.ma module — NumPy v1.21 Manual

前言

ma是Mask的縮寫,關於Mask的解釋,如果有PS的基礎,可以理解為蒙版,如果有計算機網絡的基礎,可以理解為掩碼。Mask array是專門用於提取數組中特定元素構成的新數組的中間數組。

類比的話,如果說原數組是一塊棋盤,每個位置都寫了特定數字,那么Mask array就是和原棋盤大小相同的一塊布,只是上邊有幾個洞。那么,把這塊布蓋在棋盤上,就只能顯示出這幾個洞處的數字了,其他位置上的數字都被蒙上了,顯示的結果就是對原數組進行Mask的結果,這塊布就是Mask。

原理

Masked array(就是前言中所寫的棋盤,即原數組)中可能存在缺省值非法值numpy.ma模塊提供了一個類似於numpy工作模式的Masked array

注意區分Masked array與Mask array的差別,Masked array是原數組,Mask array是參與Mask的中間數組。

什么是Masked array?

在大多數情況下,數據集中可能包含有無效數據(比如空值、非法值)。numpy.ma模塊通過引入Masked array來解決這個問題。

Masked array並不是單個數組,而是①標准ndarray和②Mask array的組合。一個Mask array也可以是一個nomask,在Mask array中,要么用空值代表了非法值,要么用布爾數組中的TrueFalse指明哪些值有效和無效。

如果Masked中某個元素是無效的,那么它對應的Mask中的這個位置的元素就是True,說明這個元素需要被“蒙”起來;反之,有效元素的位置上,Mask array中就是False,這個元素就不會被“蒙”。

這就確保了,那些Masked元素不會被用於計算。

舉個例子,假設我們有以下一個數據集:

 

import numpy as np
import numpy.ma as ma
x=np.array([1,2,3,-1,5])

 

如果第四個數據非法且需要Mask的,最簡單的方法就是構造一個Masked array:

mx=ma.masked_array(x,mask=[0,0,0,1,0])

然后,我們就可以排除這個無效值再對正確的數據集進行統計分析了:

mx.mean() #均值
#2.75

numpy.ma

ma模塊最主要的功能是MaskedArray類,它是numpy.ndarray的子類。關於這個類的屬性和方法,可以通過看MaskedArray class來獲取更多的細節。

簡單來說,numpy.ma可以看做是numpy的補充:

import numpy as np
import numpy.ma as ma

如果要構造一個第二個元素是非法元素的數組,我們可以這樣寫:

y=ma.array([1,2,3],mask=[0,1,0])

如果要構造一個,所有與1.e20相差不多的值視為無效值的Masked array,可以這樣寫:

z=ma.masked_values([1.0,1.e20,3.0,4.0],1.e20)

此外,還有許多構造Masked array的方法,可以看Constructing masked arrays

使用numpy.ma

1)構造Masked array

Masked array由兩部分組成:①標准ndarray;②Mask array;兩者尺寸相同。

有多種構造Masked array的方法:

  • 直接引入 MaskedArray 類;
  • 兩種Masked array構造器,array 與 masked_array
    array(data[,dtype,copy,order,mask,...]) 最常用,直接用一個array和與之對應的mask進行構造
    masked_array 等同於numpy.ma.core.MaskedArray
  • 其它方法(常用的被我用紅色標注):

asarray(a[, dtype, order])

將一個array正常轉化為masked array

asanyarray(a[, dtype])

與asarray相同

fix_invalid(a[, mask, copy, fill_value])

無效值(NaN和inf)會被Mask,並且無效值會被填充為fill_value

masked_equal(x, value[, copy])

等於value的值會被Mask

masked_greater(x, value[, copy])

大於value的值會被Mask

masked_greater_equal(x, value[, copy])

大於等於value的值會被Mask

masked_inside(x, v1, v2[, copy])

給定區間內的值會被Mask

masked_invalid(a[, copy])

無效值(NaN和inf)會被Mask

masked_less(x, value[, copy])

小於value的值會被Mask

masked_less_equal(x, value[, copy])

小於等於value的值會被Mask

masked_not_equal(x, value[, copy])

不等於value的值會被Mask

masked_object(x, value[, copy, shrink])

完全等同於value(常用於String)的值會被Mask

masked_outside(x, v1, v2[, copy])

給定區間外的值會被Mask

masked_values(x, value[, rtol, atol, copy, …])

浮點值相等的值會被Mask

masked_where(condition, a[, copy])

符合條件的下標/索引會被Mask

2)訪問數據

Masked array中的data array可以通過多種方式訪問:

  • 通過data屬性;輸出結果是一個numpy.ndarray(或子類)的視圖:m.data
  • 通過__array__方法;輸出結果是一個numpy.ndarray
  • 通過getdata函數。

通常情況下,需要先把其中無效數據通過filled方法填充后,才能通過以上方法進行訪問。

3)訪問Mask

訪問Mask array可以用 mask 屬性:m.mask。一定要注意,Mask中的True代表着Masked array中的無效數據。

另外兩種訪問Mask的方法是通過getmask和 getmaskarray 方法:

  • getmask(x)要么返回Mask array,要么返回nomask
  • getmaskarray(x)要么返回Mask array,要么返回全是False布爾數組

4)訪問合法元素

①~mask

如果我們要提取合法元素,我們可以用~mask作為索引

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)

提取結果是MaskedArray,只是data全是合法元素,mask全是False。

②compress

另一種提取合法元素的方法是用compressed ,它只返回由合法元素組成的ndarray

x.compressed()
array([1, 4])

需要注意compressed的輸出總是一維數組。

5)調整Mask

①Mask特定元素

a、直接標記特定元素為masked(推薦)

如果想把Masked array中的某個或某些元素手動標記為無效元素,推薦方法是直接把這個元素修改為 masked

#①單個元素
x = ma.array([1, 2, 3])
x[0] = ma.masked
x
masked_array(data=[--, 2, 3],
             mask=[ True, False, False],
       fill_value=999999)

#②根據坐標篩選多個元素
y = ma.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
#同時給出橫縱坐標,兩者組合得到一個元素位置/索引
y[(0, 1, 2), (1, 2, 0)] = ma.masked
y
masked_array(
  data=[[1, --, 3],
        [4, 5, --],
        [--, 8, 9]],
  mask=[[False,  True, False],
        [False, False,  True],
        [ True, False, False]],
  fill_value=999999)
#③用切片得到多個元素
z = ma.array([1, 2, 3, 4])
z[:-2] = ma.masked
z
masked_array(data=[--, --, 3, 4],
             mask=[ True,  True, False, False],
       fill_value=999999)

b、修改Mask array

x = ma.array([1, 2, 3])
x.mask = [0, 1, 0]#修改mask

x masked_array(data=[1, --, 3], mask=[False, True, False], fill_value=999999)

②取消Mask特定元素

a、直接給特定元素賦值(合法值)

x = ma.array([1, 2, 3], mask=[0, 0, 1])
x[-1] = 5

x
masked_array(data=[1, 2, 5],
             mask=[False, False, False],
       fill_value=999999)

這種方法對於hard mask會失效,一個array是否是hard mask,可以通過屬性hardmask查看。

可以通過soften_mask來把hard mask變為soft mask,也可以通過harden_mask把它變成hard mask

b、取消全部元素的Mask

在mask不是hard mask的前提下,可以通過把mask設置為nomask來取消全部元素的mask。

x = ma.array([1, 2, 3], mask=[0, 0, 1])
x.mask = ma.nomask
x
masked_array(data=[1, 2, 3],
             mask=[False, False, False],
       fill_value=999999)

6)索引和切片

由於MaskedArrayndarray的子類,所以它也繼承了ndarray的索引和切片機制。

①索引

通過索引訪問MaskedArray單個元素時,如果MaskedArray是一維的,那么輸出結果要么是正常元素(Mask中該元素是False時),要么是一個特殊的值——masked(Mask中該元素是True時):

x = ma.array([1, 2, 3], mask=[0, 0, 1])
x[0] #正常元素 Mask為False
1
x[-1] #特殊元素 Mask為True
masked

x[-1] is ma.masked
True

如果MaskedArray是多維的,那么通過一個索引訪問時,會列出該維度下的所有數據(除了Mask為False的元素):

y = ma.masked_array([(1,2), (3, 4)],
               mask=[(0, 0), (0, 1)],
              dtype=[('a', int), ('b', int)])
y[0] #第一行
(1, 2)
y[-1] #最后一行
(3, --)

②切片

通過切片訪問MaskedArray時,會返回一個新的MaskedArray,它的data和mask是由原MaskedArray的data和mask進行切片獲取到的:

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, False, False],
       fill_value=999999)
x.mask
array([False, False, False, False,  True])
x.data
array([ 1, -1,  3,  4,  5])

 

7)Masked Array相關操作與運算

Masked Array支持一系列的算術比較運算。無效數據通常不會參與運算,這意味着運算前后data的樣式應該是一樣的(有效的還是有效,無效的還是無效)。

numpy.ma模塊中實現了數組運算的大部分函數,有些一元或者二元函數(比如logdivide)在對某些值進行操作時,可能導致結果出現無效值(比如log(0)、log(-1)等):

ma.log([-1, 0, 1, 2])
masked_array(data=[--, --, 0.0, 0.6931471805599453],
             mask=[ True,  True, False, False],
       fill_value=1e+20)

Masked Array也支持標准numpy函數,輸出也是Masked Array。

x = ma.array([-1, 1, 0, 2, 3], mask=[0, 0, 0, 0, 1])
np.log(x)
masked_array(data=[--, 0.0, --, 0.6931471805599453, --],
             mask=[ True, False,  True, False,  True],
       fill_value=1e+20)

例子

1)用某個特定值代替無效值的Array

考慮一個List x,其中存放一系列元素,用-9999代替無效值。

我們希望①計算這些元素的平均值;②計算這些元素與平均值間的差值(以上計算都不包含無效值)。

import numpy.ma as ma
x = [0.,1.,-9999.,3.,4.]

mx=ma.masked_values(x,-9999.)#構造Masked Array,標記-9999為無效值

#計算平均值
print(mx.mean())
2.0

#計算差值
print(mx - mx.mean())
[-2.0 -1.0 -- 1.0 2.0]
print(mx.anom())
[-2.0 -1.0 -- 1.0 2.0]

2)填充無效值

還以1)為背景,假設我們想把無效值填充為有效值的平均值:

print(mx.filled(mx.mean()))
[ 0.  1.  2.  3.  4.]

3)數學運算

數學運算時,會簡單地不考慮無效值、除以0、對負值開根號等情況:

import numpy.ma as ma
x = ma.array([1., -1., 3., 4., 5., 6.], mask=[0,0,0,0,1,0])
y = ma.array([1., 2., 0., 4., 5., 6.], mask=[0,0,0,0,0,1])
print(ma.sqrt(x/y))
[1.0 -- -- 1.0 -- --]

如果出現以上所說情況,會把這些情況的結果視為無效值。

4)忽略極端值

假設我們有一個array d,其中的元素都是位於(0,1)間的浮點值,我們想要計算d中位於[0.2,0.9]范圍外值的平均值:

d = np.linspace(0, 1, 20)

d_mean=d.mean()

d_out=ma.masked_outside(d,0.2,0.9)#提取在[0.2,0.9]范圍內的值
d_out_mean=d_out.mean()

d_in_mean=d_mean-d_out_mean
-0.05263157894736836

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM