如何使用列表作为参数对函数进行矢量化?
How to vectorize a function with lists as argument?
我需要帮助在 numpy 中向量化一个函数。在 Julia,我可以做这样的事情:
((a,b,c) -> [a,b,c]).([[1,2],[3,4]],[[5,6],[7,8]],nothing)
哪个returns
2-element Vector{Vector{Union{Nothing, Vector{Int64}}}}:
[[1, 2], [5, 6], nothing]
[[3, 4], [7, 8], nothing]
它一次从可迭代对象中取出一个子列表并展开 nothing
。
在 Python 中,我只是不能有类似的行为。我试过了:
np.vectorize(lambda a,b,c: [a,b,c])([[1,2], [3,4]], [[5,6], [7,8]], None)
但是 returns:
array([[list([1, 5, None]), list([2, 6, None])],
[list([3, 7, None]), list([4, 8, None])]], dtype=object)
如果我这样做:
np.vectorize(lambda a,b,c: print(a,b,c))([[1,2], [3,4]], [[5,6], [7,8]], np.nan)
我回来了:
1 5 nan
1 5 nan
2 6 nan
3 7 nan
4 8 nan
我尝试使用排除参数,但 il 排除了整个数组:
np.vectorize(lambda a,b,c: print(a,b,c), excluded=[0])([[1,2], [3,4]], [[5,6], [7,8]], np.nan)
打印:
[[1, 2], [3, 4]] 5 nan
[[1, 2], [3, 4]] 5 nan
[[1, 2], [3, 4]] 6 nan
[[1, 2], [3, 4]] 7 nan
[[1, 2], [3, 4]] 8 nan
顺便说一句,实际函数是 sklearn 函数,而不是 lambda 函数。
你给了它一个 (2,2), (2,2) 和标量参数。 np.vectorized
调用了您的函数 4 次,每次都使用这 3 个值的元组(一起广播)。
您也可以在 print
版本中看到这一点。开头有一个额外的元组,用于确定 return dtype,在本例中是一个列表,所以 dtype=object
.
使用 exclude
它不会迭代第一个参数的值,而是将其整个传递。
这是创建列表列表的正确方法:
In [811]: a,b,c = [[1,2], [3,4]], [[5,6], [7,8]], None
In [813]: [[i,j,None] for i,j in zip(a,b)]
Out[813]: [[[1, 2], [5, 6], None], [[3, 4], [7, 8], None]]
如果我们添加一个signature
(和otypes
):
In [821]: f = np.vectorize(lambda a,b,c: [a,b,c], signature='(n),(n),()->()', otypes=[object])
In [822]: f(a,b,c)
Out[822]:
array([list([array([1, 2]), array([5, 6]), None]),
list([array([3, 4]), array([7, 8]), None])], dtype=object)
现在它只调用函数两次。但结果要慢得多。 反复阅读 notes
关于性能的文章。
如果我们先把列表参数做成数组:
In [825]: A,B = np.array(a), np.array(b)
In [826]: A,B
Out[826]:
(array([[1, 2],
[3, 4]]),
array([[5, 6],
[7, 8]]))
签名 f
return 是同一件事,表明 vectorize
确实将列表转换为数组:
In [827]: f(A,B,c)
Out[827]:
array([list([array([1, 2]), array([5, 6]), None]),
list([array([3, 4]), array([7, 8]), None])], dtype=object)
如果我们将数组传递给列表理解,我们可以得到:
In [829]: np.array([[i,j,None] for i,j in zip(A,B)], object)
Out[829]:
array([[array([1, 2]), array([5, 6]), None],
[array([3, 4]), array([7, 8]), None]], dtype=object)
In [830]: _.shape
Out[830]: (2, 3)
我需要帮助在 numpy 中向量化一个函数。在 Julia,我可以做这样的事情:
((a,b,c) -> [a,b,c]).([[1,2],[3,4]],[[5,6],[7,8]],nothing)
哪个returns
2-element Vector{Vector{Union{Nothing, Vector{Int64}}}}:
[[1, 2], [5, 6], nothing]
[[3, 4], [7, 8], nothing]
它一次从可迭代对象中取出一个子列表并展开 nothing
。
在 Python 中,我只是不能有类似的行为。我试过了:
np.vectorize(lambda a,b,c: [a,b,c])([[1,2], [3,4]], [[5,6], [7,8]], None)
但是 returns:
array([[list([1, 5, None]), list([2, 6, None])],
[list([3, 7, None]), list([4, 8, None])]], dtype=object)
如果我这样做:
np.vectorize(lambda a,b,c: print(a,b,c))([[1,2], [3,4]], [[5,6], [7,8]], np.nan)
我回来了:
1 5 nan
1 5 nan
2 6 nan
3 7 nan
4 8 nan
我尝试使用排除参数,但 il 排除了整个数组:
np.vectorize(lambda a,b,c: print(a,b,c), excluded=[0])([[1,2], [3,4]], [[5,6], [7,8]], np.nan)
打印:
[[1, 2], [3, 4]] 5 nan
[[1, 2], [3, 4]] 5 nan
[[1, 2], [3, 4]] 6 nan
[[1, 2], [3, 4]] 7 nan
[[1, 2], [3, 4]] 8 nan
顺便说一句,实际函数是 sklearn 函数,而不是 lambda 函数。
你给了它一个 (2,2), (2,2) 和标量参数。 np.vectorized
调用了您的函数 4 次,每次都使用这 3 个值的元组(一起广播)。
您也可以在 print
版本中看到这一点。开头有一个额外的元组,用于确定 return dtype,在本例中是一个列表,所以 dtype=object
.
使用 exclude
它不会迭代第一个参数的值,而是将其整个传递。
这是创建列表列表的正确方法:
In [811]: a,b,c = [[1,2], [3,4]], [[5,6], [7,8]], None
In [813]: [[i,j,None] for i,j in zip(a,b)]
Out[813]: [[[1, 2], [5, 6], None], [[3, 4], [7, 8], None]]
如果我们添加一个signature
(和otypes
):
In [821]: f = np.vectorize(lambda a,b,c: [a,b,c], signature='(n),(n),()->()', otypes=[object])
In [822]: f(a,b,c)
Out[822]:
array([list([array([1, 2]), array([5, 6]), None]),
list([array([3, 4]), array([7, 8]), None])], dtype=object)
现在它只调用函数两次。但结果要慢得多。 反复阅读 notes
关于性能的文章。
如果我们先把列表参数做成数组:
In [825]: A,B = np.array(a), np.array(b)
In [826]: A,B
Out[826]:
(array([[1, 2],
[3, 4]]),
array([[5, 6],
[7, 8]]))
签名 f
return 是同一件事,表明 vectorize
确实将列表转换为数组:
In [827]: f(A,B,c)
Out[827]:
array([list([array([1, 2]), array([5, 6]), None]),
list([array([3, 4]), array([7, 8]), None])], dtype=object)
如果我们将数组传递给列表理解,我们可以得到:
In [829]: np.array([[i,j,None] for i,j in zip(A,B)], object)
Out[829]:
array([[array([1, 2]), array([5, 6]), None],
[array([3, 4]), array([7, 8]), None]], dtype=object)
In [830]: _.shape
Out[830]: (2, 3)