使用numpy.reshape时如何保留数组不同行列的原有dtype?
NumPy 标准ndarray是同构数据结构,要求数组内所有元素必须使用统一的数据类型。当数组中同时存在整数和复数时,NumPy会遵循类型提升规则:复数类型无法被安全降级转换为整数,因此所有整数会被强制转换为复数,最终整个数组的dtype变为complex,这是ndarray的固有设计,和reshape操作本身无关——reshape仅修改数组的形状,不会改变元素的数据类型,类型转换在你把混合类型的列表传入NumPy构造数组的阶段就已经完成了。
你当前的实现先把整数列表和复数列表拼接为长度2020的大列表,再reshape为(2,1010),本质是要求一个二维ndarray的两行使用不同dtype,这在标准同构ndarray里是不可能实现的。
根据你的实际使用场景,可以选以下三种实现方式:
方案1:拆分为两个独立同构数组(性能最优,最推荐)
完全不需要拼接两个列表再reshape,直接把频率和复数值分别转为对应类型的一维数组即可,后续做数值计算时不会损失性能:import numpy as np freqs = [] cplxs = [] for i, line in enumerate(lines): freq = int(line[0]) complexElement = float(line[1]) + 1j * float(line[2]) freqs.append(freq) cplxs.append(complexElement) # 分别生成对应dtype的数组,形状均为(1010,) freq_arr = np.array(freqs, dtype=int) cplx_arr = np.array(cplxs, dtype=complex)如果需要模拟二维数组的索引习惯,直接用
[freq_arr, cplx_arr]按行取数即可,性能远高于异构数组。方案2:构造object类型的二维数组(兼容二维索引写法)
如果你必须要一个形状严格为(2,1010)、可以用arr[行,列]方式索引的数组,可以指定数组dtype为object,这种数组可以存储任意Python对象,不会触发自动类型提升,但会完全损失NumPy的数值计算加速能力,仅适合对计算性能没有要求的场景:# 直接按行传入两个列表,指定dtype=object,不需要提前拼接 test = np.array([freqs, cplxs], dtype=object) # 验证类型 print(type(test[0, 0])) # <class 'int'> print(type(test[1, 0])) # <class 'complex'> print(test.shape) # (2, 1010)注意:这种数组无法直接参与FFT、矩阵乘法、向量化运算等NumPy数值操作,做计算时需要先取出对应行转为对应dtype的同构数组。
方案3:使用结构化数组(适合频率与复数值一一配对的场景)
如果你的数据逻辑是「每一个频率对应一个复数值」的键值对结构,结构化数组比强行构造二维异构数组更合理,每个字段可以独立指定dtype:# 定义结构化数据类型:freq字段存整数,cplx字段存复数 dt = np.dtype([('freq', int), ('cplx', complex)]) # 配对后构造数组 test = np.array(list(zip(freqs, cplxs)), dtype=dt) # 取所有频率:test['freq'] # 取所有复数值:test['cplx']
内容的提问来源于stack exchange,提问作者Radiofreak1041

