問題
這個問題:Numpy where function multiple conditions詢問如何使用np.where兩個條件。This answer建議&在條件之間使用運算子,如果我們可以輸入的條件數量很少,則該運算子有效。這個答案建議使用np.logical_and,它只能接受兩個引數。
這個執行緒:Numpy "where" with multiple conditions也討論了 for 的多個條件np.where,但條件的數量是預先知道的。
我正在尋找一種方法來評估np.where運算式而無需事先知道條件的數量。
可重現的設定
我有一個二維陣列:
arr = \
np.array([[1,2,3,4],
[4,5,6,7],
[9,8,7,6],
[0,1,0,1],
[9,7,6,5]])
例如,選擇索引 1 元素大于 5、索引 2 元素大于 3 的行。為此,我執行以下操作:
res = arr[np.where((arr[:,1]>5) & (arr[:,2]>4))]
res 然后是:
array([[9, 8, 7, 6],
[9, 7, 6, 5]])
正如預期的那樣。
但是如果我將這些條件作為串列呢?上面的例子是:
cols = [1,2] # arbitrary length list
tholds = [5,4] # arbitrary length list
這兩個串列預先未知長度,但它們具有相同的長度。
我怎樣才能res使用cols和tholds串列?
我試過的
使用ast.literal_eval定義:
filterstring = "&".join([f"(pdist[:,{col}]>{th})" for col, th in zip(cols,tholds)])
其計算結果為(pdist[:,1]>5)&(pdist[:,2]>4),即np.where()當手動輸入條件時我們上面的內容。
但是,ast.literal_eval(f"np.where({filterstring})")給出了一個錯誤:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-269-1aaff20de82f> in <module>()
----> 1 ast.literal_eval(f"np.where({filterstring})")
3 frames
/usr/lib/python3.7/ast.py in _convert_num(node)
53 elif isinstance(node, Num):
54 return node.n
---> 55 raise ValueError('malformed node or string: ' repr(node))
56 def _convert_signed_num(node):
57 if isinstance(node, UnaryOp) and isinstance(node.op, (UAdd, USub)):
ValueError: malformed node or string: <_ast.Call object at 0x7f41daa21f10>
所以這不起作用。這個答案的問題ast.literal_eval()畸形節點或字串,同時將字串轉換成使用陣列串列()■確認,這不是正確的做法。
編輯:
np.where連續使用s的建議適用于這個特定示例,但并不是我真正想要的。我想呼叫np.where一次,而不是多次只評估一個條件。
uj5u.com熱心網友回復:
試圖避免評估。它有一些安全隱患。
你可以迭代它,像這樣
def unknown_conditions(arr, cols, tholds):
for col, thold in zip(cols, tholds):
arr = arr[np.where(arr[:, col] > thold)]
return arr
uj5u.com熱心網友回復:
您可以累積滿足條件的數量,然后呼叫該np.where函式一次。從那里可以很容易地根據條件進行混合和/或組合。
(概念上與學院的建議非常相似。)
def filter_by_conditions(arr, cols, tholds):
n_conditions = len(cols)
bool_accumulator = np.zeros(arr.shape[0])
for c, t in zip(cols, tholds):
bool_accumulator = (arr[:, c] > t).astype(int)
return arr[np.where(bool_accumulator) == n_conditions]
uj5u.com熱心網友回復:
您可以通過將陣列列的重新排序視圖(這是說“使用索引串列”的一種奇特方式)與廣播比較相結合,減少行 np.all
>>> arr[np.where(np.all(arr[:,cols] > thds, axis=1))]
array([[9, 8, 7, 6],
[9, 7, 6, 5]])
正如您的第一個鏈接所指示的(并且如np.where 檔案頂部的注釋中所述),np.where在這種情況下實際上不需要;它只會減慢速度。您可以使用布爾串列對 Numpy 陣列進行切片,因此無需將布爾串列更改為索引串列。由于np.all與&運算子一樣,回傳布林值的 Numpy 陣列,因此也不需要np.asarrayor np.nonzero(如上述注釋中所建議的):
>>> arr[np.all(arr[:,cols] > thds, axis=1)]
array([[9, 8, 7, 6],
[9, 7, 6, 5]])
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/377971.html
