簡體   English   中英

與使用“ for循環”相比,我該如何改變思維以“向量化計算”?

[英]How do I shift my thinking to 'vectorize my computation' more than using 'for-loops'?

這絕對是一個概念性問題,但是我想在SO上讓其他人就此主題提供專業意見。 最近,我的大部分編程工作都來自Numpy數組。 我一直在匹配兩個左右大小不同的數組中的項目。 大多數時候,我會去for-loop,甚至最糟糕的是嵌套的for-loop。 我最終嘗試避免使用for循環,因為我嘗試在Data Science中獲得更多經驗,因為for循環的執行速度較慢。

我非常了解Numpy和我可以研究的預定義cmd,但是對於那些經驗豐富的人, 當您遍歷某些內容時,您是否具有一般的思路?

類似於以下內容:

small_array = np.array(["a", "b"])
big_array = np.array(["a", "b", "c", "d"])

for i in range(len(small_array)):
    for p in range(len(big_array)):
        if small_array[i] == big_array[p]:
            print "This item is matched: ", small_array[i]

我很清楚有一種方法可以用這種方法給貓咪剝皮,但是我對其他方法和思維方式很感興趣。

由於我從事數組語言(APL,MATLAB和numpy)已有數十年的經驗,因此我無法幫助您入門。 但是我懷疑我主要是根據模式,過去見過和使用過的東西工作。 我在互動環節中做了很多實驗。

舉個例子:

In [273]: small_array = np.array(["a", "b"])
     ...: big_array = np.array(["a", "b", "c", "d"])
     ...: 
     ...: for i in range(len(small_array)):
     ...:     for p in range(len(big_array)):
     ...:         if small_array[i] == big_array[p]:
     ...:             print( "This item is matched: ", small_array[i])
     ...:             
This item is matched:  a
This item is matched:  b

通常,我運行迭代案例只是為了清楚地了解所需的內容。

In [274]: small_array
Out[274]: 
array(['a', 'b'],
      dtype='<U1')
In [275]: big_array
Out[275]: 
array(['a', 'b', 'c', 'd'],
      dtype='<U1')

我之前見過-遍歷兩個數組,並對成對的值進行處理。 這是一種outer操作。 有多種工具,但我最喜歡的一種工具是使用numpy廣播。 它將一個數組轉換為(n,1)數組,並將其與另一個(m,)數組一起使用

In [276]: small_array[:,None]
Out[276]: 
array([['a'],
       ['b']],
      dtype='<U1')

用(1,m)運算的(n,1)的結果是(n,m)數組:

In [277]: small_array[:,None]==big_array
Out[277]: 
array([[ True, False, False, False],
       [False,  True, False, False]], dtype=bool)

現在,我可以在任一軸上進行anyall縮減:

In [278]: _.all(axis=0)
Out[278]: array([False, False, False, False], dtype=bool)

In [280]: __.all(axis=1)
Out[280]: array([False, False], dtype=bool)

我也可以使用np.where將布爾值減少為索引。


糟糕,我應該使用any

In [284]: (small_array[:,None]==big_array).any(0)
Out[284]: array([ True,  True, False, False], dtype=bool)
In [285]: (small_array[:,None]==big_array).any(1)
Out[285]: array([ True,  True], dtype=bool)

玩過這個游戲后,我記得有一個in1d做類似的事情

In [286]: np.in1d(big_array, small_array)
Out[286]: array([ True,  True, False, False], dtype=bool)

但是,當我查看in1d的代碼時(請參閱文檔中的[source]鏈接),我看到,在某些情況下,它實際上是在小數組上進行迭代的:

In [288]: for x in small_array:
     ...:     print(x==big_array)
     ...:     
[ True False False False]
[False  True False False]

將此與Out[277]進行比較。 x==big_array將標量與數組進行比較。 numpy ,使用數組和標量執行==+*等類似的操作很容易,並且應該成為第二自然。 下一步是對2個匹配形狀的數組進行相同的操作。 然后從那里開始播放可廣播的形狀。

在其他情況下,它使用np.uniquenp.argsort

通過相互廣播輸入,然后將值與某種歸約方式(任意,全部,和,均值等)進行組合來創建更高維數組的這種模式非常普遍。

我將以更具體的方式解釋您的問題:

  1. 如何使用索引變量退出?

  2. 如何開始編寫列表推導而不是普通循環”?

要退出使用索引變量,關鍵是要了解Python中的“ for”不是其他語言的“ for”。 應該將其稱為“每個”。

for x in small_array:
    for y in big_array:
        if x == y:
            print "This item is matched: ", x

那好多了。

我也發現自己會用普通的循環編寫代碼(或者實際上是這樣做),然后開始懷疑列表理解是否會更清晰,更優雅。

列表理解實際上是創建列表的特定於領域的語言,因此第一步將是學習其基礎知識。 典型的陳述是:

l = [f(x) for x in list_expression if g(x)]

意思是“為list_expression中滿足條件g的所有x給我一個f(x)列表”

因此,您可以通過以下方式編寫它:

matched = [x for x in small_array if x in big_array]

等等 ,您正邁向Python風格!

如您所說,最好使用矢量化的東西來加快速度。 學習這是一條漫長的道路。 如果您還沒有使用矩陣乘法,則必須使用它。 一旦使用完,請嘗試將數據轉換為矩陣並查看可以執行的乘法。 通常,您無法執行此操作並擁有超矩陣(超過2D維度)。 那是numpy變得有用的地方。

Numpy提供了一些功能,例如np.where ,知道如何使用它們。 了解諸如small_array[small_array == 'a'] = 'z'類的快捷方式。 嘗試將numpy函數與nativ python(地圖,過濾器...)結合使用。

要處理多維矩陣,不需要任何秘密,練習和使用紙張來了解您在做什么。 但是從4個維度開始,它變得非常棘手。

for循環不一定很慢。 由於matlab自身的錯誤,這是隨時間流逝的matlab廢話。 向量化 “用於”循環的,但級別較低。 您需要掌握要處理哪種數據和體系結構以及對數據執行哪種功能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM