在二维数组中追加/连接数组
Posted
技术标签:
【中文标题】在二维数组中追加/连接数组【英文标题】:Appending/concatenating arrays inside 2D array 【发布时间】:2018-04-18 13:15:24 【问题描述】:我正在尝试生成一个 3x4 数组,其中每个元素都将成为一个未知大小的数组。在此过程中,我将新数字一一附加到 3x4 矩阵的某些单元格中。我最终希望得到一个如下所示的数组:
[[[1,8,9],[1,2],[],[]],
[[8],[],[4,5],[9,1]],
[[],[7,1,4],[],[2,1,3]]]
现在我一直在尝试使用追加和连接,但我似乎找不到一个好的方法来做到这一点,因为内部数组的大小会发生变化。另外我不知道初始化矩阵的最佳方法是什么。简化后,我的代码如下所示:
mat = np.empty((3,4,1))
for x in range(1000):
i, j, value = somefunction()
mat[i,j,:] = np.append(mat[i,j,:], value)
有人知道将这些值附加(或连接或...)到我的矩阵的最佳方法吗?我一直在查找有关附加和连接的类似问题,并尝试了很多不同的方法,但我无法弄清楚。我发现很难解释我的问题,所以我希望我的描述清楚。
【问题讨论】:
你确定你想用一个 Numpy 数组来做这个吗? Numpy 数组应该是统一的。恕我直言,您应该为此任务使用 Python 列表。 实际上可以这样使用数组,但是效率很低。整个问题听起来像是XY Problem。你想用这个子矩阵连接来达到什么目的? 实际上 3x4 数组是一种地图,我想将这些值存储在正确的“位置”上,以查看它们在每个位置是否或多或少相似。最后我想在每个单元格中取平均值,所以我只剩下一个 3x4 数组。 【参考方案1】:测试这样一个数组是否有用的一种简单方法是将您的列表包装在np.array
中:
In [767]: mat = np.array([[[1,8,9],[1,2],[],[]],
...: [[8],[],[4,5],[9,1]],
...: [[],[7,1,4],[],[2,1,3]]])
In [768]: mat
Out[768]:
array([[list([1, 8, 9]), list([1, 2]), list([]), list([])],
[list([8]), list([]), list([4, 5]), list([9, 1])],
[list([]), list([7, 1, 4]), list([]), list([2, 1, 3])]], dtype=object)
In [769]: mat.shape
Out[769]: (3, 4)
结果是 (3,4) 对象 dtype 数组。这不是创建对象 dtype 数组的最可靠方法(以 np.empty((3,4),object)
开头更通用),但在这种情况下它可以正常工作。
但是这样的数组与原始列表相比并没有太多优势。大多数更快的数组操作都不起作用。大多数任务都需要对列表元素进行 Python 级迭代。
我可以使用np.vectorize
进行迭代,例如采取手段:
In [775]: np.vectorize(np.mean)(mat)
/usr/local/lib/python3.5/dist-packages/numpy/core/fromnumeric.py:2909: RuntimeWarning: Mean of empty slice.
out=out, **kwargs)
/usr/local/lib/python3.5/dist-packages/numpy/core/_methods.py:80: RuntimeWarning: invalid value encountered in double_scalars
ret = ret.dtype.type(ret / rcount)
Out[775]:
array([[ 6. , 1.5, nan, nan],
[ 8. , nan, 4.5, 5. ],
[ nan, 4. , nan, 2. ]])
它不喜欢取空列表的平均值。我们可以编写一个简单的函数来更优雅地处理[]
。
我可以把列表变成数组(注意otypes
的使用):
In [777]: arr = np.vectorize(np.array,otypes=[object])(mat)
In [778]: arr
Out[778]:
array([[array([1, 8, 9]), array([1, 2]), array([], dtype=float64),
array([], dtype=float64)],
[array([8]), array([], dtype=float64), array([4, 5]), array([9, 1])],
[array([], dtype=float64), array([7, 1, 4]),
array([], dtype=float64), array([2, 1, 3])]], dtype=object)
虽然我不确定这对我们有多大帮助。
【讨论】:
【参考方案2】:您可以使用所谓的对象数组来完成这项工作。通常,numpy 数组由原始类型组成,但可以创建每个元素都是任意 Python 对象的数组。这样你就可以创建一个包含数组的数组。
mat = np.empty((3, 4), dtype=object)
请注意,mat
中的每个元素现在都是 None
。让我们填充矩阵:
for x in range(1000):
i, j, value = somefunction()
if mat[i, j] is None:
mat[i, j] = np.array(value)
else:
mat[i, j] = np.append(mat[i, j], value)
这应该可以完成工作,但它的效率非常低,原因有两个:
dtype=object
几乎释放了所有使 numpy 数组快速的属性。对元素的每个操作都必须涉及 Python 解释器,这通常不会发生。
numpy 数组被设计成静态的;它们不是为了成长而设计的。所以np.append
真正做的是将旧数组复制到一个更大的新数组中。随着时间的推移,数组增长得越慢,这个速度就越慢。
考虑到您最终希望将整个事物缩减为 3x4 数组,使用常规 Python 列表可能会更好:
# initialize a 3x4x0 hierarchy of nested lists
mat = [[[] for _ in range(4)] for _ in range(3)]
for x in range(1000):
i, j, value = somefunction()
mat[i][j].append(value)
# reduce each sub-list to its mean (empty list -> nan)
for i in range(3):
for j in range(4):
mat[i][j] = np.mean(mat[i][j])
# FINALLY convert to array
mat = np.array(mat)
【讨论】:
以上是关于在二维数组中追加/连接数组的主要内容,如果未能解决你的问题,请参考以下文章