2010-11-04 18 views
14

Mam listę wektorów (w języku Python), które chcę znormalizować, jednocześnie usuwając wektory, które pierwotnie miały małe normy.Zmienna pośrednia w zrozumieniu listy do równoczesnego filtrowania i transformacji

Lista wejściowa to np.

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

I muszą być wyjście (x * n r * n) z n = (X * 2 + y x 2) ** - 0,5

Jeśli to potrzebne normy, na przykład, że będzie łatwo z listowego:

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

byłoby również łatwe do przechowywania zaledwie znormalizowane X, też, na przykład, ale to, co chcę jest mieć tę zmienną tymczasową „n ", do użycia w dwóch obliczeniach, i wyrzucić go.

Nie mogę po prostu użyć funkcji lambda, ponieważ potrzebuję również n do filtrowania listy. Jaki jest najlepszy sposób?

Teraz używam tego pod listowych tutaj (z wyrazem na liście wewnętrznej):

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

Lista wewnętrzna generuje krotki z dodatkową wartość (n), a następnie użyć tych wartości do obliczeń i filtrowania. Czy to naprawdę najlepszy sposób? Czy są jakieś okropne nieskuteczności, o których powinienem wiedzieć?

Odpowiedz

11
Is this really the best way? 

Dobrze, że działa sprawnie i jeśli naprawdę chcesz napisać oneliners to jest to najlepsze, co możesz zrobić.

Z drugiej strony, to prosta funkcja 4 linia zrobi to samo znacznie jaśniejsze:

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, nie jest to błąd w kodzie lub opis - mówisz odfiltrować krótkie wektory ale kod przeciwnie: p

+0

Dzięki, że ładnie wygląda. Funkcja iteracji jest naprawdę lepsza dla czegoś bardziej skomplikowanego. – dividebyzero

+0

O wyborze wektora, n jest w rzeczywistości odwrotnością normy, wynosi ** - 0,5, a nie ** 0,5. Dlatego mnożenie przez n zamiast podziału.Dzieje się tak dlatego, że zamierzam użyć określonej funkcji do obliczenia przybliżonego pierwiastkowania kwadratowego w przybliżeniu, zamiast używać potęgowania lub np. 1/(sqrt (x)). – dividebyzero

1

Sugeruje to, że użycie forloop może być najszybszym sposobem. Pamiętaj, aby sprawdzić wyniki timeit na własnej maszynie, ponieważ te wyniki mogą się różnić w zależności od wielu czynników (sprzęt, system operacyjny, wersja Pythona, długość a itd.).

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] 

daje wyniki te 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

Nie łącz "najlepszym sposobem" z "najszybszą drogą". Jeśli wydajność jest największym problemem, powinien prawdopodobnie używać numpy. –

+0

@Glenn the Numpy Way jest zdecydowanie lepszy, byłem tylko ciekawy, jak rozwiązać ten problem, używając do tego listy, iteratorów itp. – dividebyzero

1

kradzież kodu z unutbu, tutaj jest większa próba tym numpy wersji i wersji iteracyjnej. Zauważ, że konwersja listy na numpy może kosztować trochę czasu.

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) 

a wynik ...

[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]er:~$ 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 
Powiązane problemy