[英]Appending to numpy arrays
我正在嘗試構造一個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]]
?
numpy.append
與python的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的副本,其值附加在axis上。 請注意,append不會就地發生:分配並填充了一個新數組。
如果您事先知道numpy
數組輸出的形狀,則可以通過np.zeros(n)
進行實例化, np.zeros(n)
其填充結果。
另一個選擇:如果您的計算大量使用了在數組左側插入元素的方法 ,請考慮使用標准庫中的collections.deque
。
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])
如上所述, 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數組。 或者,如果性能確實很關鍵, numpy.append
在所有情況下都使用使用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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.