将重复参数传递给 Numpy 向量化函数的最佳方法
Best way to pass repeated parameter to a Numpy vectorized function
因此,继续我和@TheBlackCat 在 中的讨论,我想知道将参数传递给 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))
(问题请参考这里:)
我的问题与函数 pointer
内部发生的事情有关。我将 points
转换为 pandas.Series
然后获取值(在第 4 行,就在 if
语句下方)的原因是使其与多边形具有相同的形状。如果我只是将点称为 points = [point]*len(intersect)
或 points = itertools.repeat(point, len(intersect))
,Numpy 会抱怨它 "cannot broadcast arrays of size (n,2) and size (n,) together"(n 是 intersect
的长度)。
如果我这样调用 vect_dist_funct
:dist = vect_dist_funct(itertools.repeat(points, len(intersect)), polygons)
,vincenty
会抱怨我给它传递了太多参数。我完全不知道两者之间的区别。
请注意,这些是坐标,因此总是成对出现。以下是 point
和 polygons
的示例:
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 都不会抱怨我传递了错误的参数?此外,还寻求导致最小内存消耗和增加速度的技术。目标是计算点到每个多边形质心之间的距离。
np.vectorize
在这里并不能真正帮助你。根据 documentation:
The vectorize function is provided primarily for convenience, not for performance. The implementation is essentially a for loop.
事实上,vectorize
会主动伤害您,因为它将输入转换为 numpy 数组,进行不必要且昂贵的类型转换并产生您所看到的错误。你最好使用带有 for
循环的函数。
使用函数而不是 lambda
作为 to-level 函数更好,因为它可以让你有一个文档字符串。
这就是我将如何实施您正在做的事情:
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
并仅矢量化第二个参数:
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)
因此,继续我和@TheBlackCat 在
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))
(问题请参考这里:
我的问题与函数 pointer
内部发生的事情有关。我将 points
转换为 pandas.Series
然后获取值(在第 4 行,就在 if
语句下方)的原因是使其与多边形具有相同的形状。如果我只是将点称为 points = [point]*len(intersect)
或 points = itertools.repeat(point, len(intersect))
,Numpy 会抱怨它 "cannot broadcast arrays of size (n,2) and size (n,) together"(n 是 intersect
的长度)。
如果我这样调用 vect_dist_funct
:dist = vect_dist_funct(itertools.repeat(points, len(intersect)), polygons)
,vincenty
会抱怨我给它传递了太多参数。我完全不知道两者之间的区别。
请注意,这些是坐标,因此总是成对出现。以下是 point
和 polygons
的示例:
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 都不会抱怨我传递了错误的参数?此外,还寻求导致最小内存消耗和增加速度的技术。目标是计算点到每个多边形质心之间的距离。
np.vectorize
在这里并不能真正帮助你。根据 documentation:
The vectorize function is provided primarily for convenience, not for performance. The implementation is essentially a for loop.
事实上,vectorize
会主动伤害您,因为它将输入转换为 numpy 数组,进行不必要且昂贵的类型转换并产生您所看到的错误。你最好使用带有 for
循环的函数。
使用函数而不是 lambda
作为 to-level 函数更好,因为它可以让你有一个文档字符串。
这就是我将如何实施您正在做的事情:
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
并仅矢量化第二个参数:
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)