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

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

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

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

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

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

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

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

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

  1. def func(u):
  2. # The size of A,B,C,D may change, so it is good idea to keep the function as general as possible
  3. A = np.array([[-1, 0], [-0.2, 1]]).reshape(2, 2)
  4. B = np.array([1, 0]).reshape(2, 1)
  5. C = np.array([[1, 0], [0, 1]]).reshape(2, 2)
  6. D = np.array([1, 1]).reshape(2, 1)
  7. xx = A @ xx + B @ u
  8. return C @ xx + D @ u
  9. N = 100
  10. values = np.ones(N).reshape(N, 1)
  11. result = np.array(list(map(func, values)))
6kkfgxo0

6kkfgxo01#

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

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

  1. np.vstack(result[:2])
  2. #output
  3. array([[ 0.981, 0.23 ],
  4. [ 1.231, -0.56 ]])

  1. np.array(result[:2])
  2. #output
  3. array([[ 0.981, 0.23 ],
  4. [ 1.231, -0.56 ]])

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

  1. 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误用:

  1. In [79]: np.fromiter(range(3))
  2. ---------------------------------------------------------------------------
  3. TypeError Traceback (most recent call last)
  4. Cell In[79], line 1
  5. ----> 1 np.fromiter(range(3))
  6. TypeError: fromiter() missing required argument 'dtype' (pos 2)

正确使用dtype:

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

或者使用理解生成器:

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

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

  1. In [82]: np.fromiter((np.array([1,2])+i for i in range(3)),int)
  2. ---------------------------------------------------------------------------
  3. TypeError Traceback (most recent call last)
  4. TypeError: only size-1 arrays can be converted to Python scalars
  5. The above exception was the direct cause of the following exception:
  6. ValueError Traceback (most recent call last)
  7. Cell In[82], line 1
  8. ----> 1 np.fromiter((np.array([1,2])+i for i in range(3)),int)
  9. ValueError: setting an array element with a sequence.

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

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

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

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

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

  1. In [90]: def foo(x): return np.array([1,2])+x
  2. In [91]: list(map(foo, range(3)))
  3. Out[91]: [array([1, 2]), array([2, 3]), array([3, 4])]

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

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

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

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

编辑

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

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

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

展开查看全部
watbbzwu

watbbzwu3#

执行

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

示出

  1. [[ 0.6 6.66666667]
  2. [ 0.9 10. ]]

关于fromiter的Numpy手册

相关问题