将重复参数传递给Numpy向量化函数的最佳方法

时间:2016-06-28 17:45:09

标签: python numpy optimization geopy

所以,继续讨论@TheBlackCat和我在this answer中的讨论,我想知道将参数传递给Numpy向量化函数的最佳方法。因此定义了有问题的函数:

vect_dist_funct = np.vectorize(lambda p1, p2: vincenty(p1, p2).meters)

其中,vincenty来自Geopy package

我目前以这种方式致电vect_dist_funct

def pointer(point, centroid, tree_idx):
    intersect = list(tree_idx.intersection(point))
    if len(intersect) > 0:
        points = pd.Series([point]*len(intersect)).values
        polygons = centroid.loc[intersect].values
        dist = vect_dist_funct(points, polygons)
        return pd.Series(dist, index=intercept, name='Dist').sort_values()
    else:
        return pd.Series(np.nan, index=[0], name='Dist')

points['geometry'].apply(lambda x: pointer(point=x.coords[0], centroid=line['centroid'], tree_idx=tree_idx))

(请参阅此处的问题:Labelled datatypes Python

我的问题与函数pointer中发生的事情有关。我将points转换为pandas.Series然后获取值(在第4行,恰好在if语句下)的原因是使其与多边形形状相同。如果我只是将点数称为points = [point]*len(intersect)points = itertools.repeat(point, len(intersect)),Numpy会抱怨它不能同时广播大小(n,2)和大小(n,)的数组" (n是intersect)的长度。

如果我这样致电vect_dist_functdist = vect_dist_funct(itertools.repeat(points, len(intersect)), polygons)vincenty抱怨说我已经传递了太多论据。我完全不知道两者之间的区别。

请注意,这些是坐标,因此将始终成对使用。以下是pointpolygons的示例:

point = (-104.950752   39.854744) # Passed directly to the function like this.
polygons = array([(-104.21750802451864, 37.84052458697633),
                  (-105.01017084789603, 39.82012158954065),
                  (-105.03965315742742, 40.669867471420886),
                  (-104.90353460825702, 39.837631505433706),
                  (-104.8650601872832, 39.870796282334744)], dtype=object)
           # As returned by statement centroid.loc[intersect].values

在这种情况下调用vect_dist_funct的最佳方法是什么,这样我可以进行矢量化调用,Numpy和vincenty都不会抱怨我传递了错误的参数?此外,寻求导致最小存储器消耗和增加速度的技术。目标是计算点与每个多边形质心之间的距离。

1 个答案:

答案 0 :(得分:3)

np.vectorize在这里没有真正帮到你。根据{{​​3}}:

  

提供矢量化功能主要是为了方便,而不是为了提高性能。实现基本上是for循环。

事实上,vectorize会主动伤害你,因为它会将输入转换为numpy数组,执行不必要且昂贵的类型转换并产生您看到的错误。使用带有for循环的函数要好得多。

最好使用函数而不是lambda作为顶级函数,因为它允许你有一个文档字符串。

这就是我实现你正在做的事情的方式:

def vect_dist_funct(p1, p2):
    """Apply `vincenty` to `p1` and each element of `p2`.

    Iterate over `p2`, returning `vincenty` with the first argument
    as `p1` and the second as the current element of `p2`.  Returns
    a numpy array where each row is the result of the `vincenty` function
    call for the corresponding element of `p2`.
    """
    return [vincenty(p1, p2i).meters for p2i in p2]

如果你真的想使用vectorize,你可以使用excluded参数来不对p1参数进行向量化,或者更好地设置一个lambda包裹vincenty {1}}并且只对第二个参数进行矢量化:

def vect_dist_funct(p1, p2):
    """Apply `vincenty` to `p1` and each element of `p2`.

    Iterate over `p2`, returning `vincenty` with the first argument
    as `p1` and the second as the current element of `p2`.  Returns
    a list where each value is the result of the `vincenty` function
    call for the corresponding element of `p2`.
    """
    vinc_p = lambda x: vincenty(p1, x)
    return np.vectorize(vinc_p)(p2)