追加到numpy数组

2024-09-29 01:36:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图构造一个numpy数组,然后将整数和另一个数组附加到它。 我试过这样做:

xyz_list = frag_str.split()
nums = numpy.array([])
coords = numpy.array([])
for i in range(int(len(xyz_list)/4)):
    numpy.append(nums, xyz_list[i*4])
    numpy.append(coords, xyz_list[i*4+1:(i+1)*4])
print(atoms)
print(coords)

打印输出只会得到空数组。为什么? 另外,我如何重写coords以允许我有这样的二维数组:array[[0,0,0],[0,0,1],[0,0,-1]]


Tags: innumpyfor整数数组coordsarraylist
3条回答

与python的list.append不同,numpy.append不执行适当的操作。因此,您需要将结果分配回变量,如下所示。

import numpy

xyz_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
nums = numpy.array([])
coords = numpy.array([])

for i in range(int(len(xyz_list)/4)):
    nums = numpy.append(nums, xyz_list[i*4])
    coords = numpy.append(coords, xyz_list[i*4+1:(i+1)*4])

print(nums)    # [ 1.  5.  9.]
print(coords)  # [  2.   3.   4.   6.   7.   8.  10.  11.  12.]

您可以按如下方式重塑coords

coords = coords.reshape(3, 3)

# array([[  2.,   3.,   4.],
#        [  6.,   7.,   8.],
#        [ 10.,  11.,  12.]])

有关numpy.append行为的更多详细信息

Documentation

Returns: A copy of arr with values appended to axis. Note that append does not occur in-place: a new array is allocated and filled.

如果您事先知道numpy数组输出的形状,那么通过np.zeros(n)实例化并在稍后用结果填充它是有效的。

另一种选择是:如果您的计算大量使用在数组的左侧插入元素,请考虑使用标准库中的^{}

如上所述,numpy.append不在适当位置追加项,但重要的原因是。必须将返回的数组从numpy.append存储到原始变量,否则代码将无法工作。尽管如此,你应该重新思考你的逻辑。

Numpy在内部使用C样式的数组,这些数组位于连续内存中,没有前导或尾随未使用的元素。为了将一个项追加到一个数组中,Numpy必须分配一个数组大小为+1的缓冲区,复制所有数据并添加追加的元素。

在pseudo-C代码中,会出现以下情况:

int* numpy_append(int* arr, size_t size, int element)
{
    int* new_arr = malloc(sizeof(int) * (size+1);
    mempcy(new_arr, arr, sizeof(int) * size);
    new_arr[size] = element;
    return new_arr;
}

这是非常低效的,因为每次都必须分配一个新数组(内存分配很慢),必须复制所有元素,并将新元素添加到新数组的末尾。

相比之下,Python列表会保留超出容器大小的额外元素,直到其大小与列表的容量相同,并呈指数增长。对于容器末尾的插入,这比每次重新分配整个缓冲区要高效得多。

您应该使用Python列表和list.append,然后将新列表转换为NumPy数组。或者,如果性能非常关键,在所有场景中使用^ {CD4}}而不是^ {CD1}}使用C++扩展。重新编写你的代码,否则它将是冰封的。

编辑

此外,正如注释中指出的,如果您事先知道Numpy数组的大小,那么使用np.zeros(n)预分配它是有效的,就像在Numpy数组周围使用自定义包装一样

class extendable_array:
    def __init__(self, size=0, dtype=np.int):
        self.arr = np.array(dtype=dtype)
        self.size = size

    def grow(self):
        '''Double the array'''

        arr = self.arr
        self.arr = np.zeros(min(arr.size * 2, 1), dtype=arr.dtype)
        self.arr[:arr.size] = arr

    def append(self, value):
        '''Append a value to the array'''

        if self.arr.size == self.size:
            self.grow()

        self.arr[self.size] = value
        self.size += 1.

    # add more methods here

np.append不是列表克隆。这是一个笨拙的包装。最好学会正确使用它。

xyz_list = frag_str.split()
nums = []
coords = []
for i in range(int(len(xyz_list)/4)):
    nums.append(xyz_list[i*4])
    coords.append(xyz_list[i*4+1:(i+1)*4])
nums = np.concatenate(nums)
coords = np.concatenate(coords)

List append更快,更容易初始化。np.concatenate可以很好地处理数组列表。np.append使用concatenate,但只接受两个输入。^如果列表包含数字或字符串,则需要{}。


你没有给出frag_str的例子。但是split的名称和用法表明它是一个字符串。我认为其他任何东西都没有split方法。

In [74]: alist = 'one two three four five six seven eight'.split()

这是一个字符串列表。使用索引,我可以构造两个列表:

In [76]: [alist[i*4] for i in range(2)]
Out[76]: ['one', 'five']

In [77]: [alist[i*4+1:(i+1)*4] for i in range(2)]
Out[77]: [['two', 'three', 'four'], ['six', 'seven', 'eight']]

我可以从这些列表中创建数组:

In [78]: np.array(Out[76])
Out[78]: array(['one', 'five'], dtype='<U4')
In [79]: np.array(Out[77])
Out[79]: 
array([['two', 'three', 'four'],
       ['six', 'seven', 'eight']], dtype='<U5')

在第一种情况下,数组是1d,在第二种情况下,数组是2d

如果字符串包含数字,我们可以通过指定dtype来生成整数数组。

In [80]: alist = '1 2 3 4 5 6 7 8'.split()
In [81]: np.array([alist[i*4] for i in range(2)])
Out[81]: array(['1', '5'], dtype='<U1')
In [82]: np.array([alist[i*4] for i in range(2)], dtype=int)
Out[82]: array([1, 5])

相关问题 更多 >