2013-03-22 74 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]