2016-01-05 5 views
8

मैं एक numpyarray (या pandasDataFrame) एक तरह से है कि कम से कम window_size लंबाई के साथ एक ही मूल्य का केवल सतत श्रृंखला रखा जाता है और सब कुछ किसी और सेट को फ़िल्टर करना चाहते हैंछनन पांडा या कम से कम खिड़की लंबाई के साथ सतत श्रृंखला के लिए NumPy सरणी

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

जब 4

[0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1] 
की एक खिड़की आकार का उपयोग होना चाहिए: 0.

उदाहरण के लिए करने के लिए 0

मैं गिरी कार्यों मुझे नहीं लगता कि इसे यहाँ सही दृष्टिकोण है रोलिंग की प्रकृति के कारण rolling_apply और scipy.ndimage.filtes.gerneric_filter लेकिन का उपयोग कर की कोशिश की है (और मैं इस समय इसके साथ अटक कर रहा हूँ)।

मैं यहाँ किसी भी तरह अपना प्रयास सम्मिलित करें:

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

आप विंडो का आकार से अधिक समय में एक ही मान के अनुक्रम का इलाज कैसे करना चाहेंगे उनकी परिभाषा के नीचे सूचीबद्ध हैं? क्या मूल्य हमेशा समान हैं या क्या वे एक ही सरणी के लिए भिन्न हो सकते हैं? – Stefan

+0

मैं उन्हें 1 की श्रृंखला के रूप में भी रखना चाहता हूं। पसंद: [1,1,1,1,1] -> [1,1,1,1,1] – pho

उत्तर

6

मूल रूप से एक -1 डी मामले के लिए एक image closing operation in image-processing है कि यद्यपि। इस तरह के आपरेशनों घुमाव के तरीकों के साथ लागू किया जा सकता। अब, NumPy does support 1D convolution, तो हम भाग्य में हैं!

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) 

नमूना रन - -

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]) 

रनटाइम परीक्षण -

यह खंड तैनात हल करने के लिए सूचीबद्ध अन्य तरीकों की जोड़ी मानक इस प्रकार, हमारे मामले को हल करने के लिए, यह कुछ इस तरह होगा सवाल।

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)    

समय - -

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

मुझे पता होना चाहिए कि आपको एक तेज़ तरीका मिलेगा! मैंने संकल्प के बारे में संक्षेप में सोचा, लेकिन इसे दो बार लागू करने के बारे में नहीं सोचा। अच्छा समाधान –

+1

हां बिल्कुल! अच्छा किया और बहुत बहुत धन्यवाद Divakar! – pho

2

आप इस प्रकार itertools.groupby इस्तेमाल कर सकते हैं:

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) 

आउटपुट

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

यह भी एक अच्छा समाधान है और मैं मानता हूं कि मैंने जो कुछ प्रदान किया है उससे थोड़ा तेज है। – johnchase

+0

धन्यवाद lambo बीमार भी अपने समाधान का परीक्षण करें और देखें कि कौन सा बेहतर प्रदर्शन करता है। – pho

+1

itertools groupby मेरे बड़े डेटाफ्रेम पर आश्चर्यजनक रूप से तेज़ है। मैंने जॉनचेस समाधान के खिलाफ 10000 पुनरावृत्तियों का परीक्षण किया और यह बहुत बेहतर स्मृति और रनटाइम के अनुसार किया। तो मैं इसे बेहतर समाधान पर विचार करूंगा। हालांकि जॉन काफी अच्छा दिखता है लेकिन प्रदर्शन की कमी है। फिर भी धन्यवाद! – pho

1

वहाँ बहुत अच्छी तरह से एक बेहतर समाधान हो सकता , फिर भी मुझे लगता है कि यह काम करना चाहिए:

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]) 

मैंने वहां कुछ अन्य नंबर शामिल किए हैं, यदि आपको उस कोड की आवश्यकता है, तो उसमें कोड की आवश्यकता है;

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]) 

पहली पंक्ति यहाँ लगातार अक्षरों में मूल सरणी बंटवारे है, दूसरी पंक्ति यदि कोई चीज़ 0s के साथ कम से कम 4 लगातार वर्ण और अंतिम पंक्ति विभाजन सूची सपाट होता है बदल देता है।

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]) 

समाधान की पहली पंक्ति भी यहाँ pd.rolling_min और कदम चाल का उपयोग कर एक तरीका है एक पिछले SO answer

+0

उत्तर के लिए धन्यवाद। यह काफी सुरुचिपूर्ण दिखता है मैं इसे अपने डेटा सेट पर आज़माउंगा और देख सकता हूं कि यह कैसा प्रदर्शन करता है। – pho

2

का काफी उपयोग किया है:

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) 

तब हमने:

>>> 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]) 

बड़े सरणियों पर, इस दृष्टिकोण (काफी तेज है पर मेरे प्रणाली GroupBy 20 बार धीमी) के आसपास है:

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

हाँ एजेसीआर मैंने कोशिश की है और यह सबसे धीमा था। Itertools समाधान अब तक सबसे तेज़ है। मेरे डेटासेट पर 13.9 एमएस प्रति लूप Aroung, जॉन्स प्रति लूप 153 एमएस और लगभग 3 सेकंड लेते हैं। धन्यवाद। – pho

+0

@pho: मैंने पूछे जाने के ठीक बाद 'रोलिंग_प्ली' के साथ 'rolling_apply' को बदल दिया (मैंने गलत फ़ंक्शन - माफी माँग ली थी)। यह किसी भी बड़े डेटासेट पर काफी तेजी से होना चाहिए। –

+0

मुझे अपने संशोधित समूहबी फ़ंक्शन में भी एक त्रुटि हुई जो बताती है कि यह तेज़ है। मैं कल एक बार फिर परीक्षण करें। धन्यवाद AJRr – pho

1

itertools.groupby समाधान पर एक अधिक कॉम्पैक्ट भिन्नता:

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] 
संबंधित मुद्दे