2010-11-04 7 views
14

मेरे पास वैक्टर (पायथन में) की एक सूची है जिसे मैं सामान्य बनाना चाहता हूं, जबकि साथ ही वेक्टरों को हटाकर मूल रूप से छोटे मानदंडों को हटाते हैं।एक साथ फ़िल्टरिंग और परिवर्तन के लिए एक सूची समझ में इंटरमीडिएट वैरिएबल

इनपुट सूची है, उदा। 0.5

मैं बस जरूरत है -

a = [(1,1),(1,2),(2,2),(3,4)] 

और मैं निर्गम (x * एन, y * एन) एन = (एक्स * 2 + y * 2) ** के साथ की जरूरत होने के लिए

an = [ (x**2+y**2)**0.5 for x,y in a ] 

यह भी सिर्फ एक सामान्यीकृत एक्स भी उदाहरण के लिए स्टोर करने के लिए, आसान होगा, लेकिन क्या मैं चाहता हूँ यह अस्थायी चर है "n: मानदंडों, उदाहरण के लिए, कि एक सूची समझ के साथ आसान होगा ", दो गणनाओं में उपयोग करने के लिए, और इसे फेंक दें।

मैं सिर्फ लैम्ब्डा फ़ंक्शन का उपयोग नहीं कर सकता क्योंकि मुझे सूची को फ़िल्टर करने के लिए एन की भी आवश्यकता है। तो सबसे अच्छा तरीका क्या है?

अभी मैं इस नेस्टेड सूची समझ यहाँ उपयोग कर रहा हूँ (भीतरी सूची में एक अभिव्यक्ति के साथ):

a = [(1,1),(1,2),(2,2),(3,4)] 

[(x*n,y*n) for (n,x,y) in (((x**2.+y**2.)**-0.5 ,x,y) for x,y in a) if n < 0.4] 

# Out[14]: 
# [(0.70710678118654757, 0.70710678118654757), 
# (0.60000000000000009, 0.80000000000000004)] 

भीतरी सूची एक अतिरिक्त मूल्य (एन) के साथ tuples उत्पन्न करता है, और उसके बाद मैं इन मानों का उपयोग गणना और फ़िल्टरिंग के लिए। क्या यह वास्तव में सबसे अच्छा तरीका है? क्या कोई भयानक अक्षमता है जिसके बारे में मुझे अवगत होना चाहिए?

उत्तर

11
Is this really the best way? 

खैर, यह कुशलता से काम करता है और यदि आप सच में, सच oneliners लिखना चाहते हैं तो यह सबसे अच्छा तुम कर सकते है।

दूसरी ओर, एक सरल 4 लाइन समारोह एक ही अधिक स्पष्ट करना होगा:

def normfilter(vecs, min_norm): 
    for x,y in vecs: 
     n = (x**2.+y**2.)**-0.5 
     if min_norm < n: 
      yield (x*n,y*n) 

normalized = list(normfilter(vectors, 0.4)) 

Btw, आपकी कोड या वर्णन में एक बग है - आप कहते हैं कि तुम कम वैक्टर लेकिन अपने कोड को फ़िल्टर इसके विपरीत: पी

+0

धन्यवाद, कि अच्छा लगता है। एक इटरेटर फ़ंक्शन इस तरह की कुछ जटिल के लिए वास्तव में बेहतर है। – dividebyzero

+0

वेक्टर चयन के बारे में, एन वास्तव में मानक का पारस्परिक है, यह ** - 0.5 है, और ** 0.5 नहीं है। यही कारण है कि एक विभाजन के बजाय एन द्वारा गुणा।ऐसा इसलिए है क्योंकि मैं या तो एक्सपोनिएशन या उदाहरण का उपयोग करने के बजाय लगभग पारस्परिक वर्ग रूट की गणना करने के लिए एक विशिष्ट फ़ंक्शन का उपयोग करने की योजना बना रहा हूं। 1/(sqrt (x))। – dividebyzero

1

यह सुझाव देता है कि एक फोर्लोप का उपयोग सबसे तेज़ तरीका हो सकता है। अपने मशीन पर टाइमिट परिणाम जांचना सुनिश्चित करें, क्योंकि ये परिणाम कई कारकों (हार्डवेयर, ओएस, पायथन संस्करण, a, आदि की लंबाई) के आधार पर भिन्न हो सकते हैं।

a = [(1,1),(1,2),(2,2),(3,4)] 

def two_lcs(a): 
    an = [ ((x**2+y**2)**0.5, x,y) for x,y in a ] 
    an = [ (x*n,y*n) for n,x,y in an if n < 0.4 ] 
    return an 

def using_forloop(a): 
    result=[] 
    for x,y in a: 
     n=(x**2+y**2)**0.5 
     if n<0.4: 
      result.append((x*n,y*n)) 
    return result 

def using_lc(a):  
    return [(x*n,y*n) 
      for (n,x,y) in (((x**2.+y**2.)**-0.5 ,x,y) for x,y in a) if n < 0.4] 

इन timeit परिणाम प्राप्त होते हैं:

% python -mtimeit -s'import test' 'test.using_forloop(test.a)' 
100000 loops, best of 3: 3.29 usec per loop 
% python -mtimeit -s'import test' 'test.two_lcs(test.a)' 
100000 loops, best of 3: 4.52 usec per loop 
% python -mtimeit -s'import test' 'test.using_lc(test.a)' 
100000 loops, best of 3: 6.97 usec per loop 
+0

"सबसे तेज़ तरीका" के साथ "सर्वश्रेष्ठ तरीका" को भंग न करें। यदि प्रदर्शन सबसे बड़ा मुद्दा है, तो उसे शायद वैसे भी numpy का उपयोग करना चाहिए। –

+0

@ ग्लेन द न्यूम्पी वे निश्चित रूप से बेहतर है, मैं सूची समझ, इटरेटर आदि का उपयोग करके इसे हल करने के बारे में उत्सुक था ... – dividebyzero

1

unutbu से कोड चोरी, यहाँ एक numpy संस्करण और इटरेटर संस्करण सहित एक बड़ा परीक्षण है। ध्यान दें कि सूची को numpy में परिवर्तित करने के लिए कुछ समय लग सकता है।

import numpy 

# a = [(1,1),(1,2),(2,2),(3,4)] 
a=[] 
for k in range(1,10): 
    for j in range(1,10): 
     a.append((float(k),float(j))) 

npa = numpy.array(a) 

def two_lcs(a): 
    an = [ ((x**2+y**2)**-0.5, x,y) for x,y in a ] 
    an = [ (x*n,y*n) for n,x,y in an if n < 5.0 ] 
    return an 

def using_iterator(a): 
    def normfilter(vecs, min_norm): 
     for x,y in vecs: 
      n = (x**2.+y**2.)**-0.5 
      if n < min_norm: 
       yield (x*n,y*n) 

    return list(normfilter(a, 5.0)) 

def using_forloop(a): 
    result=[] 
    for x,y in a: 
     n=(x**2+y**2)**-0.5 
     if n<5.0: 
      result.append((x*n,y*n)) 
    return result 

def using_lc(a):  
    return [(x*n,y*n) 
      for (n,x,y) in (((x**2.+y**2.)**-0.5 ,x,y) for x,y in a) if n < 5.0] 


def using_numpy(npa): 
    n = (npa[:,0]**2+npa[:,1]**2)**-0.5 
    where = n<5.0 
    npa = npa[where] 
    n = n[where] 
    npa[:,0]=npa[:,0]*n 
    npa[:,1]=npa[:,1]*n 
    return(npa) 

और परिणाम ...

[email protected]:~$ python -mtimeit -s'import test' 'test.two_lcs(test.a)' 
10000 loops, best of 3: 65.8 usec per loop 
[email protected]:~$ python -mtimeit -s'import test' 'test.using_lc(test.a)' 
10000 loops, best of 3: 65.6 usec per loop 
[email protected]:~$ python -mtimeit -s'import test' 'test.using_forloop(test.a)' 
10000 loops, best of 3: 64.1 usec per loop 
[email protected]:~$ python -mtimeit -s'import test' 'test.using_iterator(test.a)' 
10000 loops, best of 3: 59.6 usec per loop 
[email protected]:~$ python -mtimeit -s'import test' 'test.using_numpy(test.npa)' 
10000 loops, best of 3: 48.7 usec per loop 
संबंधित मुद्दे