我想创建一个二维numpy数组,每行都有不同数量的元素。
尝试
cells = numpy.array([[0,1,2,3], [2,3,4]])
给出错误
ValueError: setting an array element with a sequence.
答案 0 :(得分:22)
我们现在问了这个问题差不多7年了,还有你的代码
cells = numpy.array([[0,1,2,3], [2,3,4]])
在numpy 1.12.0,python 3.5中执行,不会产生任何错误
cells
包含:
array([[0, 1, 2, 3], [2, 3, 4]], dtype=object)
您可以将cells
元素视为cells[0][2] # (=2)
。
tom10's solution的替代方案,如果要在新元素(即数组)可用时动态构建numpy数组列表,请使用append
:
d = [] # initialize an empty list
a = np.arange(3) # array([0, 1, 2])
d.append(a) # [array([0, 1, 2])]
b = np.arange(3,-1,-1) #array([3, 2, 1, 0])
d.append(b) #[array([0, 1, 2]), array([3, 2, 1, 0])]
答案 1 :(得分:21)
虽然Numpy知道任意对象的数组,但它针对具有固定维度的同类数字数组进行了优化。如果您确实需要数组数组,最好使用嵌套列表。但是,根据数据的预期用途,不同的数据结构可能会更好,例如如果您有一些无效的数据点,则为掩码数组。
如果您真的想要灵活的Numpy阵列,请使用以下内容:
numpy.array([[0,1,2,3], [2,3,4]], dtype=object)
然而,这将创建一个存储列表引用的一维数组,这意味着你将失去Numpy的大部分好处(矢量处理,局部性,切片等)。
答案 2 :(得分:12)
这在Numpy中得不到很好的支持(根据定义,几乎在所有地方,“二维数组”都有相同长度的所有行)。 Numpy数组的Python列表可能是一个很好的解决方案,因为这样你就可以获得Numpy的优势,你可以使用它们:
cells = [numpy.array(a) for a in [[0,1,2,3], [2,3,4]]]
答案 3 :(得分:2)
另一种选择是将数组存储为一个连续的数组,并存储它们的大小或偏移量。这需要对如何对阵列进行操作进行更多的概念性思考,但是可以使用大量的操作,就好像你有一个不同大小的二维数组一样。在他们不能的情况下,np.split
可用于创建calocedrus建议的列表。最简单的操作是ufunc,因为它们几乎不需要修改。以下是一些例子:
cells_flat = numpy.array([0, 1, 2, 3, 2, 3, 4])
# One of these is required, it's pretty easy to convert between them,
# but having both makes the examples easy
cell_lengths = numpy.array([4, 3])
cell_starts = numpy.insert(cell_lengths[:-1].cumsum(), 0, 0)
cell_lengths2 = numpy.diff(numpy.append(cell_starts, cells_flat.size))
assert np.all(cell_lengths == cell_lengths2)
# Copy prevents shared memory
cells = numpy.split(cells_flat.copy(), cell_starts[1:])
# [array([0, 1, 2, 3]), array([2, 3, 4])]
numpy.array([x.sum() for x in cells])
# array([6, 9])
numpy.add.reduceat(cells_flat, cell_starts)
# array([6, 9])
[a + v for a, v in zip(cells, [1, 3])]
# [array([1, 2, 3, 4]), array([5, 6, 7])]
cells_flat + numpy.repeat([1, 3], cell_lengths)
# array([1, 2, 3, 4, 5, 6, 7])
[a.astype(float) / a.sum() for a in cells]
# [array([ 0. , 0.16666667, 0.33333333, 0.5 ]),
# array([ 0.22222222, 0.33333333, 0.44444444])]
cells_flat.astype(float) / np.add.reduceat(cells_flat, cell_starts).repeat(cell_lengths)
# array([ 0. , 0.16666667, 0.33333333, 0.5 , 0.22222222,
# 0.33333333, 0.44444444])
def complex_modify(array):
"""Some complicated function that modifies array
pretend this is more complex than it is"""
array *= 3
for arr in cells:
complex_modify(arr)
cells
# [array([0, 3, 6, 9]), array([ 6, 9, 12])]
for arr in numpy.split(cells_flat, cell_starts[1:]):
complex_modify(arr)
cells_flat
# array([ 0, 3, 6, 9, 6, 9, 12])
答案 4 :(得分:2)
在numpy 1.14.3中,使用append:
d = [] # initialize an empty list
a = np.arange(3) # array([0, 1, 2])
d.append(a) # [array([0, 1, 2])]
b = np.arange(3,-1,-1) #array([3, 2, 1, 0])
d.append(b) #[array([0, 1, 2]), array([3, 2, 1, 0])]
您将获得数组列表(长度可以不同),并且可以执行类似d[0].mean()
的操作。另一方面,
cells = numpy.array([[0,1,2,3], [2,3,4]])
产生一系列列表。
您可能想这样做:
a1 = np.array([1,2,3])
a2 = np.array([3,4])
a3 = np.array([a1,a2])
a3 # array([array([1, 2, 3]), array([3, 4])], dtype=object)
type(a3) # numpy.ndarray
type(a2) # numpy.ndarray
答案 5 :(得分:0)
稍微偏离主题,但由于急切模式(现在是默认模式)而没有想到的那么多: 如果您使用Tensorflow,则可以执行以下操作:
a = tf.ragged.constant([[0, 1, 2, 3]])
b = tf.ragged.constant([[2, 3, 4]])
c = tf.concat([a, b], axis=0)
然后您就可以继续进行所有数学运算,例如tf.math.reduce_mean
等。
答案 6 :(得分:0)
np.array([[0,1,2,3], [2,3,4]], dtype=object)
返回列表的“数组”。
a = np.array([np.array([0,1,2,3]), np.array([2,3,4])], dtype=object)
返回一个数组数组。它已经允许进行诸如a+1
之类的操作。
在此基础上,可以通过子类化来增强功能。
import numpy as np
class Arrays(np.ndarray):
def __new__(cls, input_array, dims=None):
obj = np.array(list(map(np.array, input_array))).view(cls)
return obj
def __getitem__(self, ij):
if isinstance(ij, tuple) and len(ij) > 1:
# handle twodimensional slicing
if isinstance(ij[0],slice) or hasattr(ij[0], '__iter__'):
# [1:4,:] or [[1,2,3],[1,2]]
return Arrays(arr[ij[1]] for arr in self[ij[0]])
return self[ij[0]][ij[1]] # [1,:] np.array
return super(Arrays, self).__getitem__(ij)
def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
axis = kwargs.pop('axis', None)
dimk = [len(arg) if hasattr(arg, '__iter__') else 1 for arg in inputs]
dim = max(dimk)
pad_inputs = [([i]*dim if (d<dim) else i) for d,i in zip(dimk, inputs)]
result = [np.ndarray.__array_ufunc__(self, ufunc, method, *x, **kwargs) for x in zip(*pad_inputs)]
if method == 'reduce':
# handle sum, min, max, etc.
if axis == 1:
return np.array(result)
else:
# repeat over remaining axis
return np.ndarray.__array_ufunc__(self, ufunc, method, result, **kwargs)
return Arrays(result)
现在可行:
a = Arrays([[0,1,2,3], [2,3,4]])
a[0:1,0:-1]
# Arrays([[0, 1, 2]])
np.sin(a)
# Arrays([array([0. , 0.84147098, 0.90929743, 0.14112001]),
# array([ 0.90929743, 0.14112001, -0.7568025 ])], dtype=object)
a + 2*a
# Arrays([array([0, 3, 6, 9]), array([ 6, 9, 12])], dtype=object)
要使纳米功能正常工作,可以这样做
# patch for nanfunction that cannot handle the object-ndarrays along with second axis=-1
def nanpatch(func):
def wrapper(a, axis=None, **kwargs):
if isinstance(a, Arrays):
rowresult = [func(x, **kwargs) for x in a]
if axis == 1:
return np.array(rowresult)
else:
# repeat over remaining axis
return func(rowresult)
# otherwise keep the original version
return func(a, axis=axis, **kwargs)
return wrapper
np.nanmean = nanpatch(np.nanmean)
np.nansum = nanpatch(np.nansum)
np.nanmin = nanpatch(np.nanmin)
np.nanmax = nanpatch(np.nanmax)
np.nansum(a)
# 15
np.nansum(a, axis=1)
# array([6, 9])