問題陳述:
正如標題所述,我想從一個一維陣列具有除去部分連續的 零和長度等于或高于一個閾值。
我的解決方案:
我生成了以下 MRE 中顯示的解決方案:
import numpy as np
THRESHOLD = 4
a = np.array((1,1,0,1,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,1))
print("Input: " str(a))
# Find the indices of the parts that meet threshold requirement
gaps_above_threshold_inds = np.where(np.diff(np.nonzero(a)[0]) - 1 >= THRESHOLD)[0]
# Delete these parts from array
for idx in gaps_above_threshold_inds:
a = np.delete(a, list(range(np.nonzero(a)[0][idx] 1, np.nonzero(a)[0][idx 1])))
print("Output: " str(a))
輸出:
Input: [1 1 0 1 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 1]
Output: [1 1 0 1 1 1 0 0 0 1 1]
題:
在 numpy 陣列上有沒有更簡單、更有效的方法來做到這一點?
編輯:
基于@mozway 評論,我正在編輯我的問題以提供更多資訊。
基本上,問題域是:
- 我有長度 ~20.000 個樣本的一維信號
- 由于噪聲,部分信號已歸零
- 信號的其余部分具有非零值,范圍為 ~[50, 250]
- 前導和尾隨零已被洗掉
正如我已經說過的,我的目標是洗掉長度閾值以上的零部分。
更詳細的問題:
- 就numpy 的 高效處理而言,上述解決方案是否有更好的解決方案?
- 就有效的 信號處理技術而言,是否有比使用 numpy 更合適的方法來實作預期目標?
對答案的評論:
關于我對高效 numpy 處理的第一個擔憂,@mathfux 的解決方案真的很棒,基本上就是我想要的。這就是為什么我接受了這個。
然而,@Jér?me Richard 的方法回答了我的第二個問題,它提供了一個非常高性能的解決方案;如果資料集非常大,那真的很有用。
感謝您的精彩回答!
uj5u.com熱心網友回復:
np.delete每次呼叫時都會創建一個新陣列,這是非常低效的。更快的解決方案是將所有值存盤在掩碼/布爾陣列中,然后立即過濾輸入陣列。但是,如果僅使用 Numpy 完成,這仍然可能需要純 Python 回圈。一個更簡單、更快的解決方案是使用Numba(或 Cython)來做到這一點。這是一個實作:
import numpy as np
import numba as nb
@nb.njit('int_[:](int_[:], int_)')
def filterZeros(arr, threshold):
n = len(arr)
res = np.empty(n, dtype=arr.dtype)
count = 0
j = 0
for i in range(n):
if arr[i] == 0:
count = 1
else:
if count >= threshold:
j -= count
count = 0
res[j] = arr[i]
j = 1
if n > 0 and arr[n-1] == 0 and count >= threshold:
j -= count
return res[0:j]
a = np.array((1,1,0,1,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,1))
a = filterZeros(a, 4)
print("Output: " str(a))
這是我機器上包含 100_000 個專案的隨機二進制陣列的結果:
Reference implementation: 5982 ms
Mozway's solution: 23.4 ms
This implementation: 0.11 ms
因此,該溶液為約54381更快比初始溶液和212倍比Mozway的一個更快。通過就地作業(銷毀輸入陣列)并告訴 Numba 陣列在記憶體中是連續的(使用::1代替:),代碼甚至可以快 30% 。
uj5u.com熱心網友回復:
還可以找到非零項的差異,修復超過閾值的項并以正確的方式重建序列。
def numpy_fix(a, THRESHOLD):
idx = np.flatnonzero(a)
df = np.diff(idx, prepend=0)
df[df>THRESHOLD] = 1
cs = np.cumsum(df)
z = np.zeros(cs[-1] 1, dtype=int)
z[cs] = 1
return z
>>> numpy_fix(a)
array([1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1])
(請注意,只有a沒有前導零或尾隨零時才正確)
%timeit numpy_fix(np.tile(a, (1, 50000)))
39.3 ms ± 865 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)
uj5u.com熱心網友回復:
一個非常有效的方法是使用itertools.groupby itertools.chain:
from itertools import groupby, chain
a2 = np.array(list(chain(*(l for k,g in groupby(a)
if len(l:=list(g))<THRESHOLD or k))))
輸出:
array([1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1])
這相對較快,例如在 100 萬個專案上:
# A = np.random.randint(2, size=1000000)
%%timeit
np.array(list(chain(*(l for k,g in groupby(a)
if len(l:=list(g))<THRESHOLD or k))))
# 254 ms ± 3.03 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/367617.html
上一篇:如何生成長度為6的唯一字母組合?
