2016-01-05 16 views
8

Ben numpyarray (veya pandasDataFrame), en az window_size uzunluğu ile aynı değerin sadece sürekli dizi tutulan bir şekilde ve her şey kümeye filtre etmek istiyorum 4Filtreleme pandalar veya minimum pencere uzunluğunda sürekli serisi için numpy diziler

[0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1] 
bir pencere boyutu kullanıldığında

[1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,1,1,1,0,1,1,1,1] 

olmalıdır: Örneğin 0.

için 0

ve scipy.ndimage.filtes.gerneric_filter kullanmayı denedim, ancak haddeleme çekirdek işlevlerinin doğası nedeniyle burada doğru yaklaşım olduğunu düşünmüyorum (ve şu anda onunla takılıyorum).

Burada yine benim girişimi eklemek şöyledir:

import numpy as np 
import pandas as pd 
import scipy 
#from scipy import ndimage 
df= pd.DataFrame({'x':np.array([1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,1,1,1,0,1,1,1,1])}) 
df_alt = df.copy() 
def filter_df(df, colname, window_size): 
    rolling_func = lambda z: z.sum() >= window_size 
    df[colname] = pd.rolling_apply(df[colname], 
            window_size, 
            rolling_func, 
            min_periods=window_size/2, 
            center = True) 

def filter_alt(df, colname, window_size): 
    rolling_func = lambda z: z.sum() >= window_size 
    return scipy.ndimage.filters.generic_filter(df[colname].values, 
               rolling_func, 
               size = window_size,          
               origin = 0) 

window_size = 4 
filter_df(df, 'x', window_size) 
print df 
filter_alt(df_alt, 'x', window_size) 
+0

Onların tanımları aşağıda listelenmiştir? Değerler her zaman aynı mı yoksa aynı dizi için farklı mıdır? – Stefan

+0

Bunları da 1 dizisi olarak tutmak istiyorum. Gibi: [1,1,1,1,1] -> [1,1,1,1,1] – pho

cevap

6

da temelde 1D durum için bir image closing operation in image-processing olup. Bu işlemler, evrişim yöntemleri ile uygulanabilir. Şimdi, NumPy does support 1D convolution, bu yüzden şanslıyız!

def conv_app(A, WSZ): 
    K = np.ones(WSZ,dtype=int) 
    L = WSZ-1 
    return (np.convolve(np.convolve(A,K)>=WSZ,K)[L:-L]>0).astype(int) 

Numune çalışma - -

In [581]: A 
Out[581]: array([1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1]) 

In [582]: conv_app(A,4) 
Out[582]: array([0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]) 

In [583]: A = np.append(1,A) # Append 1 and see what happens! 

In [584]: A 
Out[584]: array([1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1]) 

In [585]: conv_app(A,4) 
Out[585]: array([1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]) 

Süre testleri -

Bu bölüm yayınlanmıştır çözmek için listelenen diğer yaklaşımların çift kriterler Böylece, bizim olayı çözmek için, bu gibi bir şey olurdu soru.

def groupby_app(A,WSZ): # @lambo477's solution 
    groups = itertools.groupby(A) 
    result = [] 
    for group in groups: 
     group_items = [item for item in group[1]] 
     group_length = len(group_items) 
     if group_length >= WSZ: 
      result.extend([item for item in group_items]) 
     else: 
      result.extend([0]*group_length) 
    return result 

def stride_tricks_app(arr, window): # @ajcr's solution 
    x = pd.rolling_min(arr, window) 
    x[:window-1] = 0 
    y = np.lib.stride_tricks.as_strided(x, (len(x)-window+1, window), (8, 8)) 
    y[y[:, -1] == 1] = 1 
    return x.astype(int)    

Zamanlamaları'na - - Nasıl pencere boyutu daha uzun aynı değerlerin bir dizisini tedavi etmek istiyorum

In [541]: A = np.random.randint(0,2,(100000)) 

In [542]: WSZ = 4 

In [543]: %timeit groupby_app(A,WSZ) 
10 loops, best of 3: 74.5 ms per loop 

In [544]: %timeit stride_tricks_app(A,WSZ) 
100 loops, best of 3: 3.35 ms per loop 

In [545]: %timeit conv_app(A,WSZ) 
100 loops, best of 3: 2.82 ms per loop 
+1

Hızlı bir yol bulacağınızı biliyordum! Konvolüsyon hakkında kısaca düşündüm ama iki kez uygulamayı düşünmedim. Güzel çözüm. –

+1

Evet, tam olarak! Aferin ve çok teşekkürler Divakar! – pho

2

Sen itertools.groupby kullanabilirsiniz:

import itertools 
import numpy as np 

my_array = np.array([1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,1,1,1,0,1,1,1,1]) 
window_size = 4 

groups = itertools.groupby(my_array) 

result = [] 
for group in groups: 
    group_items = [item for item in group[1]] 
    group_length = len(group_items) 
    if group_length >= window_size: 
     result.extend([item for item in group_items]) 
    else: 
     result.extend([0]*group_length) 

print(result) 

Çıktı

[0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1] 
+0

Bu da iyi bir çözüm ve sağladığımdan biraz daha hızlı olduğuna inanıyorum. – johnchase

+0

Teşekkürler lambo Hasta çözümlerinizi test edin ve hangisinin daha iyi performans gösterdiğini görün. – pho

+1

itertools groupby, oldukça büyük veri platformlarımda şaşırtıcı derecede hızlıdır. Johnchase çözümüne karşı 10000 yinelemeyi test ettim ve çok daha iyi bir bellek ve çalışma zamanı bilge gerçekleştirdi. Bu yüzden bunu daha iyi bir çözüm olarak göreceğim. John'un oldukça güzel görünse de performanstan yoksundur. Yine de teşekkürler! – pho

1

çok iyi daha iyi bir çözüm olabilir Ancak bunun işe yarayacağını düşünüyorum:

In [90]: x = np.array([1,1,1,0,0,1,1,1,1,0,0,1,0,1,2,1,4,4,4,4,4,0,1,1,1,1]) 

Sadece bunun için hesap koduna gereksiniminiz olması durumunda diğer bazı numaraları ekledim;

In [93]: y = np.split(x, np.where(np.diff(x) != 0)[0]+1) 
     z = [list(e) if len(e) >= 4 else [0]*len(e) for e in y] 
     result = np.array([item for sublist in z for item in sublist]) 

ilk satırı burada ardışık karakterleri orijinal diziyi ayırdığını, ikinci satır az 4 ardışık 0s ile karakterleri ve son satır bölünmüş listesini düzleştirir içeren herhangi bir öğeyi değiştirir. Sonra var

def func(arr, window): 
    x = pd.rolling_min(arr, window) 
    x[:window-1] = 0 
    y = np.lib.stride_tricks.as_strided(x, (len(x)-window+1, window), (8, 8)) 
    y[y[:, -1] == 1] = 1 
    return x.astype(int) 

:

In [96]: result 
Out[96]: array([0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]) 

çözümün ilk hattı da burada pd.rolling_min ve adım hileler kullanarak tek yaklaşımdır önceki SO answer

+0

Cevabınız için teşekkür ederiz. Bu oldukça zarif görünüyor, veri setimde denerim ve nasıl performans gösterdiğini göreceğim. – pho

2

geniş kullanımı yapar

>>> x = np.array([1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,1,1,1,0,1,1,1,1]) 
>>> func(x, 4) 
array([0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]) 
>>> y = np.array([1,1,1,0,0,1,1,1,1,1,0,1,0,0,0,1,1,1,0,1,1,1,1]) # five 1s 
>>> func(y, 4) 
array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]) 

Büyük dizilerde bu yaklaşım oldukça hızlıdır. Sistem GroupBy yaklaşık 20 kat daha yavaş) aşağıdaki gibidir:

>>> x = np.random.randint(0, 2, size=1000000) 
>>> %timeit func(x, 4) 
10 loops, best of 3: 24.4 ms per loop 
+0

Evet ajcr Denedim ve en yavaştı. Itertools çözümü en hızlıdır. Veri kümemde her döngüde 13.9 ms, Johns döngü başına yaklaşık 153 msn ve yaklaşık 3 saniyenizi alır. Teşekkür ederim. – pho

+0

@pho: Ben 'haddeleme_deri' ile 'rolling_min' yerine ben sorulduktan hemen sonra değiştirdim (yanlış işlevi yapıştırdım - özür dilerim). Daha büyük herhangi bir veri kümesinde önemli ölçüde daha hızlı olmalıdır. –

+0

Ayrıca, değiştirilmiş groupby işlevimde bir hata olduğunu ve bunun hızlı olduğunu açıklıyor. Hep yarın tekrar test ederim. Teşekkürler ajcr – pho

1

itertools.groupby çözeltisi üzerine daha kompakt bir varyasyon:

window_size = 4 
groups = [list(g) for k, g in itertools.groupby(my_array)] 
filtered_array = [g if sum(g) >= window_size else [0]*len(g) for g in groups] 
[int(i) for sub in filtered_array for i in sub] 

[0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1] 
İlgili konular