我试图构造一个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)
打印出输出只能得到我的空数组。这是为什么?
另外,如何以允许我拥有这样的2D数组的方式重写coords
:array[[0,0,0],[0,0,1],[0,0,-1]]
?
答案 0 :(得分:1)
numpy.append
不同, list.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
行为的更多详情
返回:arr的副本,其值附加到轴。注意 append不会就地发生:分配并填充新数组。
如果您事先知道numpy
数组输出的形状,则可以通过np.zeros(n)
进行实例化并稍后将其填入结果。
另一种选择:如果您的计算大量使用将数组插入数组的左侧,请考虑使用标准库中的collections.deque
。
答案 1 :(得分:1)
np.append
不是列表克隆。 np.concatenate
是一个笨拙的包装器。学会正确使用它会更好。
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)
列表追加更快,更容易初始化。 np.concatenate
可以正常使用数组列表。 np.append
使用concatenate
,但只接受两个输入。如果列表包含数字或字符串,则需要np.array
。
您没有举例frag_str
。但split
的名称和用法表明它是一个字符串。我认为其他任何方法都没有split
方法。
In [74]: alist = 'one two three four five six seven eight'.split()
这是一个字符串列表。使用索引我可以构建2个列表:
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])
答案 2 :(得分:1)
如上所述,numpy.append
没有附加项目,但原因很重要。您必须将返回的数组从numpy.append
存储到原始变量,否则您的代码将无效。话虽这么说,你应该重新考虑你的逻辑。
Numpy在内部使用C风格的数组,它们是连续内存中的数组,没有前导或尾随未使用的元素。为了将项附加到数组,Numpy必须分配数组大小为+ 1的缓冲区,复制所有数据,并添加附加元素。
在伪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数组。或者,如果性能真的很重要,请在所有方案中使用std::vector
而不是numpy.append
使用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