我试图生成一个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)
有人知道将这些值附加(或连接或...)到我的矩阵的最佳方法吗?我一直在查找有关追加和连接的类似问题,并尝试了很多不同的东西,但我无法弄明白。我发现很难解释我的问题,所以我希望我的描述清楚。
答案 0 :(得分: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解释器,这通常不会发生。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)
答案 1 :(得分: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)
虽然我不确定这会给我们买多少。