2013-03-22 99 views
8

numpy有一個gcd函數在其模塊結構的某處嗎?Numpy gcd功能

我知道fractions.gcd,但認爲numpy相當於可能更快,並與numpy數據類型更好地工作。

我一直無法發現谷歌以外的任何東西,而不是這個link這似乎過時了,我不知道我將如何訪問它建議存在的_gcd函數。

天真嘗試:

np.gcd 
np.euclid 

並沒有爲我工作...

+1

我覺得'你在談論_gcd'功能是'numpy.core._internal._gcd',但它在純Python(所以不要太快),並且在任何情況下都不處理numpy數組。 – DSM 2013-03-22 11:43:50

+1

是使用fractions.gcd的事實上的方法嗎?我假設這將是一個更快的C實現 – bph 2013-03-22 11:45:15

回答

10

你可以把它寫自己:

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 

以下是測試結果和速度的代碼:

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

兩個和你的numpy版本更快一點點 – bph 2013-03-22 13:07:36

+0

你寫的函數不適用於numpy_gcd(10,5)還是我做錯了什麼?我得到0-d數組無法索引 – evan54 2014-04-15 21:14:52

+0

它是因爲函數期望numpy數組(可能是numpy標量)。您應該可以執行numpy_gcd [10],[5])或修改該函數以直接與Python標量一起工作。 – coderforlife 2015-04-22 05:07:29

7

似乎沒有gcd功能尚未在numpy。但是,有一個gcd function in fractions module。如果您需要在numpy陣列進行gcd,你可以用它建立一個ufunc

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

我很驚訝numpy不包含gcd功能 – bph 2013-03-22 11:59:14

+0

不錯。要獲取整個列表的gcd,可以使用'numpy.ufunc.reduce(gcd,m)',其中'm'是列表,'gcd'就是這個答案中定義的。 – 2017-06-06 13:27:17

7

公共服務公告的使用Python 3.5

from math import gcd 
gcd(2, 4) 

如果你想自己動手寫一個班輪:

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

萬一期望的結果是不是各個元素的最大公約數,而是所有數字的數組中的GCD,你可能會使用下面的代碼。

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 = np.unique(a)

另一種(也許更優雅,但更慢)的實現使用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]