map()返回生成numpy数组的迭代器,如何将其转换为numpy数组?

2q5ifsrm  于 2023-10-19  发布在  其他
关注(0)|答案(3)|浏览(95)

我使用了一个map函数,其中返回的迭代器指向的每个元素都是一个numpy数组,即

result = list(map(func, values))
print(result[:2]))
[array([0.981, 0.23]),  array([1.231, -0.56])]

我希望结果是一个唯一的numpy数组,即

print(result[:2])
array([[0.981, 0.23],[1.231, -0.56]])

我尝试使用result = np.fromiter(map(func, values)),但收到以下弃用警告:

DeprecationWarning: Conversion of
 an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single
 element from your array before performing this operation. (Deprecated NumPy 1.25.)

如何解决这个问题?
编辑:虽然我有很好的答案,但我想直接从map返回的迭代器转换为np.array,从而跳过从迭代器到可迭代对象的转换。
编辑2:这里是一个最小的工作示例

def func(u):
    # The size of A,B,C,D may change, so it is good idea to keep the function as general as possible
    A = np.array([[-1, 0], [-0.2, 1]]).reshape(2, 2)
    B = np.array([1, 0]).reshape(2, 1)
    C = np.array([[1, 0], [0, 1]]).reshape(2, 2)
    D = np.array([1, 1]).reshape(2, 1)

    xx = A @ xx + B @ u
    return C @ xx + D @ u

N = 100
values = np.ones(N).reshape(N, 1)
result = np.array(list(map(func, values)))
6kkfgxo0

6kkfgxo01#

您可以通过以下方式更改您的值:

result = list(map(func, values))
print(result[:2]))
[array([0.981, 0.23]),  array([1.231, -0.56])]
np.stack(result[:2], axis=0 )

#output

array([[ 0.981,  0.23 ],
       [ 1.231, -0.56 ]])

np.vstack(result[:2])

#output

array([[ 0.981,  0.23 ],
       [ 1.231, -0.56 ]])

np.array(result[:2])

#output

array([[ 0.981,  0.23 ],
       [ 1.231, -0.56 ]])

也可以使用列表解析代替list,map
这取决于您的funcvalues。例如:

result = [func(x) for x in values]
tkqqtvp1

tkqqtvp12#

使用np.array(list(map(func,values)))是一个很好的通用调用,尽管我通常更喜欢np.array([func(i) for i in values])。在任何情况下,np.array都会得到一个列表参数,它可以分析并确定正确的dtype和shape。它创建一个目标数组,并使用任何必要的转换填充值。
如果列表在某种程度上是“不规则的”,有时会产生一个object dtype数组,现在会产生一个关于非均匀输入的模糊错误。
fromiter应该在1d输入的情况下使用defineddtype来简化这一点。它不必查看整个列表来识别最佳dtype;你就这么跟它说用count,它可以用np.empty(count, dtype)生成数组。如果没有count,它会进行猜测,并再执行一次resize方法调用来调整目标。
您正在突破fromiter使用方式的文档边界。
与range interable误用:

In [79]: np.fromiter(range(3))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[79], line 1
----> 1 np.fromiter(range(3))

TypeError: fromiter() missing required argument 'dtype' (pos 2)

正确使用dtype:

In [80]: np.fromiter(range(3),int)
Out[80]: array([0, 1, 2])

或者使用理解生成器:

In [81]: np.fromiter((i+3 for i in range(3)),int)
Out[81]: array([3, 4, 5])

尝试返回数组,但将dtype保留为标量int

In [82]: np.fromiter((np.array([1,2])+i for i in range(3)),int)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
TypeError: only size-1 arrays can be converted to Python scalars

The above exception was the direct cause of the following exception:

ValueError                                Traceback (most recent call last)
Cell In[82], line 1
----> 1 np.fromiter((np.array([1,2])+i for i in range(3)),int)

ValueError: setting an array element with a sequence.

利用最新的补丁,允许对象dtype:

In [83]: np.fromiter((np.array([1,2])+i for i in range(3)),object)
Out[83]: array([array([1, 2]), array([2, 3]), array([3, 4])], dtype=object)

或者使用少量文档化的子数组dtype:

In [88]: np.fromiter((np.array([1,2])+i for i in range(3)), np.dtype((int,2)))
Out[88]: 
array([[1, 2], 
       [2, 3],
       [3, 4]])

注意,只有当我们可以指定dtype的一部分作为可迭代对象返回的数组的长度时,这才有效。
将其转换为可Map函数:

In [90]: def foo(x): return np.array([1,2])+x

In [91]: list(map(foo, range(3)))
Out[91]: [array([1, 2]), array([2, 3]), array([3, 4])]

给定一个数组列表,np.array尝试默认创建一个多维数字dtype数组:

In [92]: np.array(list(map(foo, range(3))))
Out[92]: 
array([[1, 2],
       [2, 3],
       [3, 4]])

我们可以通过frompyfuncvectorize来获得对象dtype数组:

In [93]: np.frompyfunc(foo,1,1)(np.arange(3))
Out[93]: array([array([1, 2]), array([2, 3]), array([3, 4])], dtype=object)

In [94]: np.vectorize(foo, otypes=[object])(np.arange(3))
Out[94]: array([array([1, 2]), array([2, 3]), array([3, 4])], dtype=object)

编辑

注意不要对fromiter和generators/map的性能改进寄予太多希望。这些仍然涉及python级别的迭代。
我们的foo可以在“纯”numpy中完成广播,如:

In [95]: np.array([1,2])+np.arange(3)[:,None]
Out[95]: 
array([[1, 2],
       [2, 3],
       [3, 4]])

(尽管对于这种小尺寸,迭代可能仍然更快。)
你的func@可以在没有迭代的情况下表达,使用matmul中3d+数组的batch行为。但那是另一个主题了。

watbbzwu

watbbzwu3#

执行

import numpy as np 

def f(t): return np.array((t*0.3, t/0.3))
res = np.fromiter(map(f, (2, 3)), dtype=np.dtype((float, 2)))
print(res)

示出

[[ 0.6         6.66666667]
 [ 0.9        10.        ]]

关于fromiter的Numpy手册

相关问题