如何用NumPy创建不同维度形状的嵌套列表?
我想要创建一个各轴长度不同的随机数嵌套列表h[i,j,k],尝试了以下代码:
import numpy as np import random as rng NBR1 = 2 NBR2 = [2,3,1] list = np.array([np.array([np.array([rng.uniform(-1,1) for k in range(NBR2[i+1])]) for j in range(NBR2[i])]) for i in range(NBR1)])
不使用np.array时,变量浏览器里的嵌套列表结构符合需求,但用了之后不仅没法深入查看层级,还收到警告:
VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
另外提取向量时结果不符合预期,比如执行:
testtt = list[0][:][0]
预期得到长度为2的h[0,:,0](即{h[0,0,0], h[0,1,0]}),但实际长度是3。
编辑1:看起来NumPy并不适合处理非均匀列表,这应该是问题核心。
编辑2:我想要的嵌套列表结构为:第一层包含2个元素,第一个元素是由2个子列表组成的列表,每个子列表是长度为3的随机数序列;第二个元素是由3个子列表组成的列表,每个子列表是长度为1的随机数序列。
1. 优先用纯Python嵌套列表
NumPy的设计初衷是处理形状均匀的数组,非均匀的“参差不齐”结构本来就不是它的强项,纯Python列表反而能完美适配你的需求,而且索引逻辑更直观:
import random as rng NBR1 = 2 NBR2 = [2,3,1] # 生成符合要求的纯Python嵌套列表 h = [[[rng.uniform(-1,1) for k in range(NBR2[i+1])] for j in range(NBR2[i])] for i in range(NBR1)] # 提取你需要的h[0,:,0] testtt = [sub_item[0] for sub_item in h[0]] # 结果就是[h[0,0,0], h[0,1,0]],长度为2
这样生成的结构完全符合预期,变量浏览器也能正常展开查看层级,操作逻辑清晰。
2. 非要用NumPy的话,指定dtype=object
如果必须用NumPy数组存储非均匀结构,创建数组时必须显式指定dtype=object,让NumPy把每个元素当作独立对象存储,而非强制生成均匀形状的数组:
import numpy as np import random as rng NBR1 = 2 NBR2 = [2,3,1] # 先生成纯Python列表,再转为object类型的NumPy数组 h_list = [[[rng.uniform(-1,1) for k in range(NBR2[i+1])] for j in range(NBR2[i])] for i in range(NBR1)] h = np.array(h_list, dtype=object) # 正确提取h[0,:,0] testtt = np.array([item[0] for item in h[0]])
但要注意,这种object类型的NumPy数组失去了NumPy核心的向量运算优势,操作起来和纯列表差异不大,除非有特殊需求,否则不推荐使用。
关于你的索引错误
你之前写的list[0][:][0]逻辑有误:list[0]取到第一层的第一个元素(包含2个子列表的列表),[:]只是返回这个子列表的全部元素(还是那2个子列表),[0]则是取这2个子列表中的第一个(长度为3的那个),所以结果长度是3。正确做法是遍历h[0]里的每个子元素,取它们的第0个元素,也就是上面代码中的列表推导式写法。
内容的提问来源于stack exchange,提问作者GaloisFan

