Python 如何在具有不规则数组形状的numpy中对操作进行矢量化/张力化

Python 如何在具有不规则数组形状的numpy中对操作进行矢量化/张力化,python,numpy,vectorization,tensor,numpy-einsum,Python,Numpy,Vectorization,Tensor,Numpy Einsum,我想做手术 如果有一个规则的形状,那么我可以使用np.einsum,我相信语法是 np.einsum('ijp,ipk->ijk',X, alpha) 不幸的是,我的数据X在第1轴(如果索引为零)上有一个非规则结构 更详细地说,是指第i组第j个成员的第p个特征。因为组有不同的大小,实际上,它是一个不同长度的列表,相同长度的列表的列表 有一个规则的结构,因此可以保存为标准的numpy数组(它是一维的,然后我使用alpha.reforme(a,b,c),其中a,b,c是特定于问题的整数)

我想做手术

如果有一个规则的形状,那么我可以使用np.einsum,我相信语法是

np.einsum('ijp,ipk->ijk',X, alpha)
不幸的是,我的数据X在第1轴(如果索引为零)上有一个非规则结构

更详细地说,是指第i组第j个成员的第p个特征。因为组有不同的大小,实际上,它是一个不同长度的列表,相同长度的列表的列表

有一个规则的结构,因此可以保存为标准的numpy数组(它是一维的,然后我使用alpha.reforme(a,b,c),其中a,b,c是特定于问题的整数)

我希望避免将X存储为列表列表或不同维度的np.array列表,并编写类似于

A = []
for i in range(num_groups):
    temp = np.empty(group_sizes[i], dtype=float)
    for j in range(group_sizes[i]):
        temp[i] = np.einsum('p,pk->k',X[i][j], alpha[i,:,:])
    A.append(temp)

这是一个很好的numpy函数/数据结构吗?还是我将不得不妥协于一些仅部分矢量化的实现?

我知道这听起来很明显,但是,如果你能负担得起内存,我会从检查性能开始,只需将数据填充到统一的大小,即,只需添加零并执行该操作。有时,一个更简单的解决方案比一个具有更多Python/C往返的更理想的解决方案要快

如果这不起作用,那么你的最佳选择,正如建议的那样,可能是一种打压策略。假设
X
是您的列表列表,而
alpha
是一个数组,您可以从收集第二个索引的大小开始(可能您已经有了这个):

并对其进行排序:

idx_sort = np.argsort(X_sizes)
X_sizes_sorted = X_sizes[idx_sort]
然后选择一个bucket数,即工作的分区数。假设您选择
bucket=4
。您只需划分数据,使每个片段的大小大致相同:

sizes_cumsum = np.cumsum(X_sizes_sorted)
total = sizes_cumsum[-1]
bucket_idx = []
for i in range(BUCKETS):
    low = np.round(i * total / float(BUCKETS))
    high = np.round((i + 1) * total / float(BUCKETS))
    m = sizes_cumsum >= low & sizes_cumsum < high
    idx = np.where(m),
    # Make relative to X, not idx_sort
    idx = idx_sort[idx]
    bucket_idx.append(idx)
在这一部分,填充数组
X_bucket
可能会很慢。同样,如果您能负担得起内存,那么将
X
放在一个填充数组中,然后只切片
X[idx,:bucket\u size,:]
会更有效

最后,您可以将结果放回列表中:

result = [None] * len(X)
for res, idx in zip(bucket_results, bucket_idx):
    for r, X_i in zip(res, idx):
        result[X_i] = res[:X_sizes[X_i]]

很抱歉,我没有给出正确的函数,但我不确定您的输入或预期输出的准确程度,因此我只是将这些片段放在一起,您可以根据需要使用它们。

您可以添加一个示例案例吗?附议;特别是,我想知道不同轴的典型尺寸;以及组大小中的整数是如何分布的。组大小是否碰巧有相对较少的独特元素?组大小在数十到数千之间变化。共有82个小组。有人向我建议,我可以通过加零使结构规则化。这在数学上是可行的,但由于最大的组比最小的组大得多(~2个数量级),它包含的操作比需要的多得多。@gazza89您可能希望使用一些分区策略,例如将0-20之间的所有组和20-50之间的所有组进行聚类,50-500等转换为它们自己的矩阵,然后您可以对这些矩阵运行向量化操作,这将避免许多不必要的计算。但是,找到最佳分区将是困难的(我认为是np难的)。
bucket_results = []
for idx in bucket_idx:
    # The last index in the bucket will be the biggest
    bucket_size = X_sizes[idx[-1]]
    # Fill bucket array
    X_bucket = np.zeros((len(X), bucket_size, len(X[0][0])), dtype=X.dtype)
    for i, X_i in enumerate(idx):
        X_bucket[i, :X_sizes[X_i]] = X[X_i]
    # Compute
    res = np.einsum('ijp,ipk->ijk',X, alpha[:, :bucket_size, :])
    bucket_results.append(res)
result = [None] * len(X)
for res, idx in zip(bucket_results, bucket_idx):
    for r, X_i in zip(res, idx):
        result[X_i] = res[:X_sizes[X_i]]