2013-03-22 16 views
8

gcd ha una funzione nella sua struttura di moduli?Numpy gcd function

Sono a conoscenza di fractions.gcd ma ho pensato che un equivalente numpy potrebbe essere potenzialmente più veloce e funzionare meglio con i tipi di dati numpy.

Non riesco a trovare nulla su Google diverso da questo link che sembra scaduto e non so come accedere alla funzione _gcd suggerita.

Ingenuamente cercando:

np.gcd 
np.euclid 

non ha funzionato per me ...

+1

penso che il '_gcd' funzione che si sta parlando è a' numpy.core._internal._gcd', ma è in pure Python (e quindi non troppo veloce) e non gestisce in alcun caso gli array numpy. – DSM

+1

è l'approccio de facto per usare fractions.gcd? Presumo che sarà un'implementazione C più veloce – bph

risposta

10

potete scrivere voi stessi:

def numpy_gcd(a, b): 
    a, b = np.broadcast_arrays(a, b) 
    a = a.copy() 
    b = b.copy() 
    pos = np.nonzero(b)[0] 
    while len(pos) > 0: 
     b2 = b[pos] 
     a[pos], b[pos] = b2, a[pos] % b2 
     pos = pos[b[pos]!=0] 
    return a 

Ecco il codice per verificare il risultato e la velocità:

In [181]: 
n = 2000 
a = np.random.randint(100, 1000, n) 
b = np.random.randint(1, 100, n) 
al = a.tolist() 
bl = b.tolist() 
cl = zip(al, bl) 
from fractions import gcd 
g1 = numpy_gcd(a, b) 
g2 = [gcd(x, y) for x, y in cl] 
print np.all(g1 == g2) 

True 

In [182]: 
%timeit numpy_gcd(a, b) 

1000 loops, best of 3: 721 us per loop 

In [183]: 
%timeit [gcd(x, y) for x, y in cl] 

1000 loops, best of 3: 1.64 ms per loop 
+0

due volte più veloce per la tua versione numpy – bph

+0

la funzione che hai scritto non funziona con numpy_gcd (10, 5) o sto facendo qualcosa di sbagliato? Ottengo che gli array 0-d non possono essere indicizzati – evan54

+0

È perché la funzione prevede array numpy (e probabilmente scalari numpy). Dovresti essere in grado di eseguire numpy_gcd [10], [5]) o modificare la funzione per lavorare direttamente con gli scalari Python. – coderforlife

7

Sembra che ci sia alcuna funzione gcd ancora in numpy. Tuttavia, c'è un gcd function in fractions module. Se è necessario eseguire gcd su numpy array, si potrebbe costruire un ufunc usarlo:

gcd = numpy.frompyfunc(fractions.gcd, 2, 1) 
+7

Sono sorpreso che Numpy non contenga una funzione gcd – bph

+0

Nice. Per prendere il gcd di un intero elenco, puoi usare 'numpy.ufunc.reduce (gcd, m)' dove 'm' è l'elenco e' gcd' è come definito in questa risposta. –

7

annuncio di servizio pubblico per chiunque utilizzi Python 3.5

from math import gcd 
gcd(2, 4) 

E se si vuole scrivere da soli in una battuta:

def gcd(a: int, b: int): return gcd(b, a % b) if b else a 
0

Nel caso in cui il risultato desiderato non è un GCD elemento-saggio, ma piuttosto il MCD di tutti i numeri nella matrice, si può usare il codice qui sotto

import numpy as np 
from math import gcd as mathgcd 

def numpy_set_gcd(a): 
    a = np.unique(a) 
    if not a.dtype == np.int or a[0] <= 0: 
     raise ValueError("Argument must be an array of positive " + 
         "integers.") 

    gcd = a[0] 
    for i in a[1:]: 
     gcd = mathgcd(i, gcd) 
     if gcd == 1: 
      return 1 

    return gcd 

A seconda del caso d'uso, può essere più veloce di omettere la fase di smistamento a = np.unique(a).

Un'alternativa (forse più elegante ma più lento) implementazione utilizzando ufuncs è

import numpy as np 
from math import gcd as mathgcd 
npmathgcd = np.frompyfunc(mathgcd, 2, 1) 

def numpy_set_gcd2(a): 
    a = np.unique(a) 
    if not a.dtype == np.int or a[0] <= 0: 
     raise ValueError("Argument must be an array of positive " + 
         "integers.") 
    npmathgcd.at(a[1:], np.arange(a.size-1), a[:-1]) 
    return a[-1]