Python 我怎么能很快想到重新定购一个扁平的;“锯齿状”;numpy阵列

Python 我怎么能很快想到重新定购一个扁平的;“锯齿状”;numpy阵列,python,performance,numpy,jagged-arrays,Python,Performance,Numpy,Jagged Arrays,所以我在一个单一的平面数组中有很多数据,这些数组被分组成大小不规则的块。这些块的大小在另一个数组中给出。我需要做的是根据第三个索引数组重新排列块(想想奇妙的索引) 这些块的长度始终大于等于3,通常为4,但从技术上讲是无界的,因此,将其填充到最大长度并屏蔽是不可行的。另外,由于技术原因,我只能访问numpy,所以没有scipy或熊猫 为了便于阅读,本例中的数据很容易分组。在真实数据中,数字可以是任何东西,并且不遵循此模式 [编辑]已更新,数据不那么混乱 data = np.array([1,2,3

所以我在一个单一的平面数组中有很多数据,这些数组被分组成大小不规则的块。这些块的大小在另一个数组中给出。我需要做的是根据第三个索引数组重新排列块(想想奇妙的索引)

这些块的长度始终大于等于3,通常为4,但从技术上讲是无界的,因此,将其填充到最大长度并屏蔽是不可行的。另外,由于技术原因,我只能访问numpy,所以没有scipy或熊猫

为了便于阅读,本例中的数据很容易分组。在真实数据中,数字可以是任何东西,并且不遵循此模式

[编辑]已更新,数据不那么混乱

data = np.array([1,2,3,4, 11,12,13, 21,22,23,24, 31,32,33,34, 41,42,43, 51,52,53,54])
chunkSizes = np.array([4, 3, 4, 4, 3, 4])
newOrder = np.array([0, 5, 4, 5, 2, 1])
这种情况下的预期输出为

np.array([1,2,3,4, 51,52,53,54, 41,42,43, 51,52,53,54, 21,22,23,24, 11,12,13])

由于实际数据可能有数百万长,我希望有某种numpy魔术可以在没有python循环的情况下做到这一点。

如果使用
np.cumsum
建立索引,则可以使用
np.split
将视图创建到与chunkSize对应的
数据
数组中。然后,您可以使用花式索引根据newOrder索引对视图进行重新排序。这应该是相当有效的,因为当您在重新排序的视图上调用
np.concatenate
时,数据仅复制到新数组:

将numpy导入为np
数据=np.数组([0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5])
chunkSizes=np.array([4,3,4,4,3,4])
newOrder=np.array([0,5,4,5,2,1])
CumIndex=np.cumsum(块大小)
splitArray=np.array(np.split(数据,索引[:-1]))
targetArray=np.concatenate(拆分数组[newOrder])
#>>>目标雷
#数组([0,0,0,0,5,5,5,5,5,4,4,5,5,5,5,5,2,2,2,1,1])
方法#1

这是一个基于创建规则数组和掩蔽的矢量化方法-

def chunk_rearrange(data, chunkSizes, newOrder):
    m = chunkSizes[:,None] > np.arange(chunkSizes.max())
    d1 = np.empty(m.shape, dtype=data.dtype)
    d1[m] = data
    return d1[newOrder][m[newOrder]]
给定样本的输出-

In [4]: chunk_rearrange(data, chunkSizes, newOrder)
Out[4]: array([0, 0, 0, 0, 5, 5, 5, 5, 4, 4, 4, 5, 5, 5, 5, 2, 2, 2, 2, 1, 1, 1])
方法#2

另一个是基于
cumsum
的矢量化的,对于那些非常不规则的块大小,占用的空间更小-

def chunk_rearrange_cumsum(data, chunkSizes, newOrder):
    # Setup ID array that will hold specific values at those interval starts,
    # such that a final cumsum would lead us to the indices which when indexed
    # by the input array gives us the re-arranged o/p   
    idar = np.ones(len(data), dtype=int)

    # New chunk lengths
    newlens = chunkSizes[newOrder]

    # Original chunk intervals
    c = np.r_[0,chunkSizes[:-1].cumsum()]

    # Indices from original order that form the interval starts in new arrangement
    d1 = c[newOrder]

    # Starts of chunks in new arrangement where those from d1 are to be assigned
    c2 = np.r_[0,newlens[:-1].cumsum()]

    # Offset required for the starts in new arrangement for final cumsum to work
    diffs = np.diff(d1)+1-np.diff(c2)
    idar[c2[1:]] = diffs
    idar[0] = d1[0]

    # Final cumsum and indexing leads to desired new arrangement
    out = data[idar.cumsum()]
    return out

newOrder
是否包含索引或值?
newOrder
是索引。事实上,它与数据相同,只是为了测试/演示。事实上,为了减少混淆,我有更好的示例数据,这在大多数情况下都有效,而且肯定在所有正常情况下都有效。问题是当我在一百万块数据集中得到一个2000长的愚蠢数据块时,我得到了一个内存错误。现在,由于这是一个快速而简单的方法,我可以添加一个健全性检查,在那些情况下,由于内存占用较小,我可以使用
np.split
解决方案。@TylerFox check out刚刚添加的方法#2.Nice!太好了!我的数据集是由艺术家创建的,他们。。。就说他们喜欢打破规则吧。通常他们会修正这些异常值,但他们的第一次传递似乎总是有一些疯狂的东西。我只知道2k发生过一次,但当它发生的时候,它破坏了很多东西。再次感谢你!