簡體   English   中英

在 Numpy 數組中查找模式

[英]Finding Patterns in a Numpy Array

我試圖在一個名為valuesnumpy array中找到模式。 我想返回模式的起始索引位置。 我知道我可以迭代每個元素並檢查該元素和下一個元素是否與模式匹配,但是在一個非常低效的大型數據集上,我正在尋找更好的替代方案。

我有一個使用np.where搜索單個值的工作解決方案,但我無法讓它用於查找模式或兩個數字。

例子:

import numpy as np
values = np.array([0,1,2,1,2,4,5,6,1,2,1])
searchval = [1,2]
print  np.where(values == searchval)[0]

輸出:

[]

預期輸出:

[1, 3, 8]

您不能簡單地使用np.where (假設這是查找元素的最佳方法),然后只檢查滿足第一個條件的模式。

import numpy as np
values = np.array([0,1,2,1,2,4,5,6,1,2,1])
searchval = [1,2]
N = len(searchval)
possibles = np.where(values == searchval[0])[0]

solns = []
for p in possibles:
    check = values[p:p+N]
    if np.all(check == searchval):
        solns.append(p)

print(solns)

這是使用 where 的直接方法。 從找到匹配項的邏輯表達式開始:

In [670]: values = np.array([0,1,2,1,2,4,5,6,1,2,1])
     ...: searchval = [1,2]
     ...: 
In [671]: (values[:-1]==searchval[0]) & (values[1:]==searchval[1])
Out[671]: array([False,  True, False,  True, False, False, False, False,  True, False], dtype=bool)
In [672]: np.where(_)
Out[672]: (array([1, 3, 8], dtype=int32),)

這可以概括為一個在多個searchval上運行的循環。 獲得正確的切片范圍將需要一些擺弄。 在另一個答案中建議的roll可能會更容易,但我懷疑會慢一些。

只要searchvalvalues相比較小,這種通用方法就應該是有效的。 有一個np.in1d可以進行這種匹配,但使用or測試。 所以不適用。 但它也使用這種迭代方法是searchval列表足夠小。

廣義切片

In [716]: values
Out[716]: array([0, 1, 2, 1, 2, 4, 5, 6, 1, 2, 1])
In [717]: searchvals=[1,2,1]
In [718]: idx = [np.s_[i:m-n+1+i] for i in range(n)]
In [719]: idx
Out[719]: [slice(0, 9, None), slice(1, 10, None), slice(2, 11, None)]
In [720]: [values[idx[i]] == searchvals[i] for i in range(n)]
Out[720]: 
[array([False,  True, False,  True, False, False, False, False,  True], dtype=bool),
 array([False,  True, False,  True, False, False, False, False,  True], dtype=bool),
 array([False,  True, False, False, False, False,  True, False,  True], dtype=bool)]
In [721]: np.all(_, axis=0)
Out[721]: array([False,  True, False, False, False, False, False, False,  True], dtype=bool)
In [722]: np.where(_)
Out[722]: (array([1, 8], dtype=int32),)

我使用中間np.s_來查看切片並確保它們看起來合理。

as_strided

一個高級技巧是使用as_strided構造“滾動”數組並對其執行 2d ==測試。 as_strided很整潔但很棘手。 要正確使用它,您必須了解步幅,並獲得正確的形狀。

In [740]: m,n = len(values), len(searchvals)
In [741]: values.shape
Out[741]: (11,)
In [742]: values.strides
Out[742]: (4,)
In [743]: 
In [743]: M = as_strided(values, shape=(n,m-n+1),strides=(4,4))
In [744]: M
Out[744]: 
array([[0, 1, 2, 1, 2, 4, 5, 6, 1],
       [1, 2, 1, 2, 4, 5, 6, 1, 2],
       [2, 1, 2, 4, 5, 6, 1, 2, 1]])
In [745]: M == np.array(searchvals)[:,None]
Out[745]: 
array([[False,  True, False,  True, False, False, False, False,  True],
       [False,  True, False,  True, False, False, False, False,  True],
       [False,  True, False, False, False, False,  True, False,  True]], dtype=bool)
In [746]: np.where(np.all(_,axis=0))
Out[746]: (array([1, 8], dtype=int32),)

我認為這可以完成工作:

np.where((values == 1) & (np.roll(values,-1) == 2))[0]

如果輸入是隨機的,Ed Smith 解決方案會更快。 但是,如果您有一些可用值,則此哈希解決方案可以提供幫助:

"""
Can be replaced with any revertable hash
"""
def my_hash(rem, h, add):
    return rem^h^add

"""
Imput
"""
values = np.array([0,1,2,1,2,4,5,6,1,2,1])
searchval = [1,2]


"""
Prepare
"""
sh = 0
vh = 0
ls = len(searchval)
lv = len(values)

for i in range(0, len(searchval)):
    vh = my_hash(0, vh, values[i])
    sh = my_hash(0, sh, searchval[i])

"""
Find matches
"""
for i in range(0, lv-ls):
    if sh == vh:
        eq = True
        for j in range(0, ls):
            if values[i+j] != searchval[j]:
                eq = False
                break
        if eq:
            print i
    vh = my_hash(values[i], vh, values[i+ls])

緊湊的 straitforward 解決方案將是 as_strid 解決方案的“合法”變體。 其他人提到np.roll 但這里有一個通用的解決方案,只有一個圓圈(132 µs)。

seq = np.array([0,1,2,1,2,4,5,6,1,2,1])
patt = np.array([1,2])

Seq = np.vstack([np.roll(seq, shift) for shift in -np.arange(len(patt))]).T
where(all(Seq == patt, axis=1))[0]

具有小整數的序列的另一個選項將轉換為字符串。 它每接近 6 倍 (20 µs) 更快。 僅適用於小的正整數!

import re

def to_string(arr):
    return ''.join(map(chr, arr))

array([m.start() for m in re.finditer(to_string(patt), to_string(seq))])

暫無
暫無

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

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