如何在执行numpy数组赋值或追加到numpy数组时复制dtype



我在使用Python/numpy方面相当文盲。

我有以下代码:

data = np.array([])
for i in range(10):
data = np.append(data, GetData())
return data

GetData((返回一个具有自定义数据类型的numpy数组。然而,当执行上面的代码时,数字会转换为float64,我怀疑这是我遇到其他问题的罪魁祸首。如何在保留数据类型的同时复制/附加函数的输出?

给定注释,说明只有在运行GetData()后才能知道数据类型,并且需要多种类型,您可以这样做:

# [...]
dataByType = {} # dictionary to store the dtypes encountered and the arrays with given dtype
for i in range(10):
newData = GetData()
if newData.dtype not in dataByType:
# If the dtype has not been encountered yet,
# create an empty array with that dtype and store it in the dict
dataByType[newData.dtype] = np.array([], dtype=newData.dtype)
# Append the new data to the corresponding array in dict, depending on dtype
dataByType[newData.dtype] = np.append(dataByType[newData.dtype], newData)

考虑到hpaulj的答案,如果您希望在每次迭代时不创建新数组的情况下保留可能遇到的不同类型,您可以将以上内容调整为:

# [...]
dataByType = {} # dictionary to store the dtypes encountered and the list storing data with given dtype
for i in range(10):
newData = GetData()
if newData.dtype not in dataByType:
# If the dtype has not been encountered yet,
# create an empty list with that dtype and store it in the dict
dataByType[newData.dtype] = []
# Append the new data to the corresponding list in dict, depending on dtype
dataByType[newData.dtype].append(newData)
# At this point, you have all your data pieces stored according to their original dtype inside the dataByType dictionary.
# Now if you wish you can convert them to numpy arrays as well
# Either by concatenation, updating what is stored in the dict
for dataType in dataByType:
dataByType[dataType] = np.concatenate(dataByType[dataType])
# No need to specify the dtype in concatenate here, since previous step ensures all data pieces are the same type
# Or by creating array directly, to store each data piece at a different index
for dataType in dataByType:
dataByType[dataType] = np.array(dataByType[dataType])
# As for concatenate, no need to specify the dtype here

一个小例子:

import numpy as np
# to get something similar to GetData in the example structure:
getData = [
np.array([1.,2.], dtype=np.float64),
np.array([1,2], dtype=np.int64),
np.array([3,4], dtype=np.int64),
np.array([3.,4.], dtype=np.float64)
] # dtype precised here for clarity, but not needed

dataByType = {}
for i in range(len(getData)):
newData = getData[i]
if newData.dtype not in dataByType:
dataByType[newData.dtype] = []
dataByType[newData.dtype].append(newData)
print(dataByType) # output formatted below for clarity
# {dtype('float64'): 
#     [array([1., 2.]), array([3., 4.])],
#  dtype('int64'): 
#     [array([1, 2], dtype=int64), array([3, 4], dtype=int64)]}

现在,如果我们在该数据集上使用concatenate,我们得到1D数组,保留原始类型(dtype=float64在输出中不精确,因为它是浮点值的默认类型(:

for dataType in dataByType:
dataByType[dataType] = np.concatenate(dataByType[dataType])
print(dataByType) # once again output formatted for clarity
# {dtype('float64'):
#      array([1., 2., 3., 4.]),
#  dtype('int64'):
#      array([1, 2, 3, 4], dtype=int64)}

如果我们使用array,我们得到2D阵列:

for dataType in dataByType:
dataByType[dataType] = np.array(dataByType[dataType])
print(dataByType)
# {dtype('float64'): 
#      array([[1., 2.],
#             [3., 4.]]),
#  dtype('int64'): 
#      array([[1, 2],
#             [3, 4]], dtype=int64)}

需要注意的重要事项:如果要组合的所有阵列都不具有相同的形状,则使用array将无法按预期工作:

import numpy as np
print(repr(np.array([
np.array([1,2,3]),
np.array([4,5])])])))
# array([array([1, 2, 3]), array([4, 5])], dtype=object)

您得到一个dtype对象的数组,在本例中,这些对象都是不同长度的数组。

使用[]append表明您在天真地复制常见的列表习惯用法:

alist = []
for x in another_list:
alist.append(x)

您的data不是[]列表的克隆:

In [220]: np.array([])
Out[220]: array([], dtype=float64)

它是一个具有形状(0,(和数据类型float的数组。

np.append不是列表附加克隆。我强调这一点,因为太多的新用户犯了这个错误,结果是出现了许多不同的错误。它实际上只是np.concatenate的一个封面,它接受2个参数而不是一个参数列表。正如文档所强调的,它返回一个数组,当迭代使用时,这意味着要进行大量复制。

最好将数组收集在一个列表中,并将其交给concatenate。列表附加已经到位,并且在迭代时效果更好。如果给concatenate一个数组列表,则生成的dtype将是通用的(或任何升级所需的(。(新版本允许您在调用concatenate时指定dtype。(

手头有numpy文档(必要时也可以使用python(,并查找函数。注意它们的调用方式,包括关键字参数(。并用小例子进行练习。我手头有一个交互式python会话,即使在写答案的时候也是如此。

使用阵列时,请密切关注shapedtype。不要做假设。

串联2个int数组:

In [238]: np.concatenate((np.array([1,2]),np.array([4,3])))
Out[238]: array([1, 2, 4, 3])

使一个成为浮点数组(只需在一个数字上加一个小数点(:

In [239]: np.concatenate((np.array([1,2]),np.array([4,3.])))
Out[239]: array([1., 2., 4., 3.])

它不允许我将结果更改为int:

In [240]: np.concatenate((np.array([1,2]),np.array([4,3.])), dtype=int)
Traceback (most recent call last):
File "<ipython-input-240-91b4e3fec07a>", line 1, in <module>
np.concatenate((np.array([1,2]),np.array([4,3.])), dtype=int)
File "<__array_function__ internals>", line 180, in concatenate
TypeError: Cannot cast array data from dtype('float64') to dtype('int64') according to the rule 'same_kind'

如果一个元素是字符串,结果也是字符串dtype:

In [241]: np.concatenate((np.array([1,2]),np.array(['4',3.])))
Out[241]: array(['1', '2', '4', '3.0'], dtype='<U32')

有时需要在计算后调整数据类型:

In [243]: np.concatenate((np.array([1,2]),np.array(['4',3.]))).astype(float)
Out[243]: array([1., 2., 4., 3.])
In [244]: np.concatenate((np.array([1,2]),np.array(['4',3.]))).astype(float).as
...: type(int)
Out[244]: array([1, 2, 4, 3])

最新更新