1. 程式人生 > >numpy高階教程之np.where和np.piecewise

numpy高階教程之np.where和np.piecewise

歡迎關注“勇敢AI”公眾號,更多python學習、資料分析、機器學習、深度學習原創文章與大家分享,還有更多電子資源、教程、資料集下載。勇敢AI,一個專注於人工智慧AI的公眾號。

==================================================================================

       關於numpy的教程,前面已經總結了不少文章,且前面已經寫過了numpy的高階應用之select和choose,需要的同學可以看我的部落格或者是在我部落格裡面的微信公眾平臺,對這兩個函式有特別清晰的介紹。今天的文章主要是看一下np.where和np.piecewise,以及掩碼陣列。

一、np.where()函式詳解

顧名思義,該函式所實現的也是類似於查詢的功能,where即在哪裡的意思,前面的select和choose即選擇的意思,這有一些類似。實際上,where函式提供了“查詢”的更高階的功能。

1、where函式的定義

numpy.where(condition[, xy])  

If only condition is given, return condition.nonzero().

Parameters:

condition : array_like, bool

When True, yield x, otherwise yield y.

x, y : array_like, optional

Values from which to choose. xy and condition need to be broadcastable to some shape.

Returns:

out : ndarray or tuple of ndarrays

If both x and y

 are specified, the output array contains elements of x where condition is True, and elements from y elsewhere.

If only condition is given, return the tuple condition.nonzero(), the indices where condition is True.

解釋:

該函式可以接受一個必選引數condition,注意該引數必須是array型的,只不過元素是true或者是false

x,y是可選引數:如果條件為真,則返回x,如果條件為false,則返回y,注意condition、x、y三者必須要能夠“廣播”到相同的形狀

返回結果:返回的是陣列array或者是元素為array的tuple元組,如果只有一個condition,則返回包含array的tuple,如果是有三個引數,則返回一個array。後面會詳細介紹。

總結:numpy實際上是條件操作的高度封裝,可以說numpy.where函式是三元表示式x if condition else y的向量化版本。定義一個布林陣列和兩個值陣列,它返回的結果實際上就是查詢的元素的“位置”或者是“索引”或者是“座標”。位置、索引、座標是等價的意思,通俗的說就是返回的值就是元素到底在哪裡。

2、只含有一個引數condition的實際案例

(1)condition是一維的

a = np.array([2,4,6,8,10])
a_where=np.where(a > 5)             # 返回索引,a>5得到的是array。
print(a_where)
print(a[np.where(a > 5)])        # 等價於 a[a>5],布林索引

b=np.array([False,True,False,True,False])
print(np.where(b))

列印的結果為如下:

(array([2, 3, 4], dtype=int64),) #返回的2,3,4即對應於元素大於5(True)的元素的索引位置,即第3、4、5個元素,以array得形式返回
[ 6  8 10]
(array([1, 3], dtype=int64),)  #返回元素中為True的元素所對應的位置索引,即第2個和第4個元素,以array的形式返回。

(2)condition是二維的

a=np.array([[1,2,3,4,5],[2,3,4,5,6],[3,4,5,6,7],[4,5,6,7,8]])  #二維陣列
a_where=np.where(a>3)
print(a_where)
print(a[a_where])

執行結果為:

(array([0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3], dtype=int64), array([3, 4, 2, 3, 4, 1, 2, 3, 4, 0, 1, 2, 3, 4], dtype=int64))
[4 5 4 5 6 4 5 6 7 4 5 6 7 8]

對於第一個返回的結果,我們可以看到,它返回的是一個元組tuple,元組的第一個元素是一個array,它的值來源於滿足條件的元素的行索引,兩個0行的,三個1行的,四個2行的,五個3行的;元祖的第二個元素也是一個array,它的值來源於滿足條件的元素的列索引。

再看一個例子

b=np.where([[0, 3,2], [0,4, 0]])
print(b)

返回結果為:

(array([0, 0, 1], dtype=int64), array([1, 2, 1], dtype=int64))

#返回的依然是一個元組tuple,第一個元素是一個array,來源於行,第二個元素也是一個array,來源於列。注意,這一沒有刪選條件啊,因為where的引數就是b而不是什麼,b>1,b>2之類的布林表示式,那是怎麼回事呢,實際上,它是經過進一步處理了的,將0元素看成是false,將大於0的全部當成是true,與下面的執行結果是完全等價的。

c=np.array([[False,True,True],[False,True,False]])
print(np.where(c))

輸出結果為: (array([0, 0, 1], dtype=int64), array([1, 2, 1], dtype=int64)) #同上面完全一樣

(3)condition是多維的——以三維為例

a=[
    [
        [1,2,3],[2,3,4],[3,4,5]
    ],
    [
        [0,1,2],[1,2,3],[2,3,4]
    ]
]
a=np.array(a)
print(a.shape)  #形狀為(2,3,3)
a_where=np.where(a>3)
print(a_where)

執行結果為:

(array([0, 0, 0, 1], dtype=int64),

array([1, 2, 2, 2], dtype=int64),

array([2, 1, 2, 2], dtype=int64)) 

同上,返回的是一個元組,第一個元素是array型別,來源於第一個維度滿足條件的索引,第二個元素是array型別,來源於第二個維度滿足條件的索引,第三個元素是array型別,來源於第三個維度滿足條件的索引。

總結:針對上面的講述,where的作用就是返回一個數組中滿足條件的元素(True)的索引,且返回值是一個tuple型別,tuple的每一個元素均為一個array型別,array的值即對應某一緯度上的索引。

在之給定一個引數condition的時候,np.where(condition)和condition.nonzero()是完全等價的。

3、包含三個引數condition、x、y 的實際案例

a = np.arange(10)
a_where=np.where(a,1,-1)
print(a_where)      

a_where_1=np.where(a > 5,1,-1)
print(a_where_1)

b=np.where([[True,False], [True,True]],    #第一個引數
             [[1,2], [3,4]],               #第二個引數
             [[9,8], [7,6]]                #第三個引數
            )             

print(b)

執行結果為:

[-1  1  1  1  1  1  1  1  1  1]
[-1 -1 -1 -1 -1 -1  1  1  1  1]
[[1 8]
 [3 4]]

對於第一個結果,因為只有第一個是0,即false,故而用-1替換了,後面的都大於0,即true,故而用1替換了

對於第二個結果,前面的6個均為false,故而用-1替換,後面的四個為true,則用1替換

對於第三個結果,

第一個True對應的索引位置為(0,0),true在第二個引數中尋找,(0,0)對應於元素1

第二個false對應的索引位置為(0,1),false在第三個引數中尋找,(0,1)對應於元素8

第三個True對應的索引位置為(1,0),true在第二個引數中尋找,(0,0)對應於元素3

第四個True對應的索引位置為(1,1),true在第二個引數中尋找,(0,0)對應於元素4

總結:在使用三個引數的時候,要注意,condition、x、y必須具有相同的維度或者是可以廣播成相同的形狀,否則會報錯,它返回的結果是一個列表,同原始的condition具有相同的維度和形狀。

總結:通過上面的講述,已經瞭解到了np.where函式的強大之處,它的本質上就是選擇操作,但是如果我們自己編寫條件運算,使用if-else或者是列表表示式這樣的語句,效率低下,故而推薦使用np.where。

二、np.piecewise函式詳解

np.piecewise也和前面講過的where、select、choose一樣,屬於高階應用,而且實現的功能也有類似的,即根據相關的條件,進行篩選,然後對漫步不同條件的元素進行相關的操作,這個操作可以來源與函式、lambda表示式等,並得到新的結果。

1、np.piecewise的定義

numpy.piecewise(xcondlistfunclist*args**kw)

Evaluate a piecewise-defined function.

Given a set of conditions and corresponding functions, evaluate each function on the input data wherever its condition is true.

Parameters:

x : ndarray or scalar

The input domain.

condlist : list of bool arrays or bool scalars

Each boolean array corresponds to a function in funclist. Wherever condlist[i] is True, funclist[i](x) is used as the output value.

Each boolean array in condlist selects a piece of x, and should therefore be of the same shape as x.

The length of condlist must correspond to that of funclist. If one extra function is given, i.e. iflen(funclist) == len(condlist) + 1, then that extra function is the default value, used wherever all conditions are false.

funclist : list of callables, f(x,*args,**kw), or scalars

Each function is evaluated over x wherever its corresponding condition is True. It should take a 1d array as input and give an 1d array or a scalar value as output. If, instead of a callable, a scalar is provided then a constant function (lambda x: scalar) is assumed.

args : tuple, optional

Any further arguments given to piecewise are passed to the functions upon execution, i.e., if called piecewise(..., ..., 1, 'a'), then each function is called as f(x, 1, 'a').

kw : dict, optional

Keyword arguments used in calling piecewise are passed to the functions upon execution, i.e., if calledpiecewise(..., ..., alpha=1), then each function is called as f(x, alpha=1).

Returns:

out : ndarray

The output is the same shape and type as x and is found by calling the functions in funclist on the appropriate portions of x, as defined by the boolean arrays in condlist. Portions not covered by any condition have a default value of 0.

引數一 x:表示要進行操作的物件

引數二:condlist,表示要滿足的條件列表,可以是多個條件構成的列表

引數三:funclist,執行的操作列表,引數二與引數三是對應的,當引數二為true的時候,則執行相對應的操作函式。

返回值:返回一個array物件,和原始操作物件x具有完全相同的維度和形狀

2、np.piecewise的實際案例

(1)案例一

x = np.arange(0,10)
print(x)
xx=np.piecewise(x, [x < 4, x >= 6], [-1, 1])
print(xx)

執行結果為:

[0 1 2 3 4 5 6 7 8 9]
[-1 -1 -1 -1  0  0  1  1  1  1]

即將元素中小於4的用-1替換掉,大於等於6的用1替換掉,其餘的預設以0填充。其實這裡的替換和填充就是function,這不過這裡的function跟簡單粗暴,都用同一個數替換了。實際上,上面的程式碼完全等價於下面的程式碼:

x = np.arange(0,10)

def func1(y):
    return -1

def func2(y):
    return 1
xxx=np.piecewise(x, [x < 4, x >= 6], [func1, func2])
print(xxx)

執行結果為:

 [-1 -1 -1 -1  0  0  1  1  1  1]  #同上面一樣

(2)案例二——定義相關的操作函式

x = np.arange(0,10)

#元素進行平方
def func2(y):
    return 1ef func1(y):
    return y**2

#元素乘以100
def func2(y):
    return y*100
xxx=np.piecewise(x, [x < 4, x >= 6], [func1, func2])
print(xxx)

執行結果為:

[  0   1   4   9   0   0 600 700 800 900]

(3)案例三——使用lambda表示式

x = np.arange(0,10)

xxxx=np.piecewise(x, [x < 4, x >= 6], [lambda x:x**2, lambda x:x*100])
print(xxxx)

執行結果為:

[  0   1   4   9   0   0 600 700 800 900]

總結:piecewise的處理方法快捷方便,比自己編寫迴圈和條件語句的執行效率高很多,推薦多使用。