2017-07-25 40 views
3

我想執行操作如何向量化/與不規則排列numpy的tensorize操作形狀

form1

如果form2有一個規則的形狀,然後我可以使用np.einsum,我相信語法將是

np.einsum('ijp,ipk->ijk',X, alpha) 

不幸的是,我的數據X有一個非規則的結構(如果我們是零指數)的軸。

爲了提供更多的背景知識,form3指的是第i組第j個成員的第p個特徵。由於組的大小不同,實際上,它是不同長度的列表的列表,具有相同長度的列表。

form4有一個規則的結構,因此可以保存爲一個標準的numpy數組(它進入1維然後我使用alpha.reshape(a,b,c)其中a,b,c是問題特定的整數)

我想避免存儲X作爲列表的列表清單或不同尺寸的np.arrays的列表,並寫像

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的/數據結構這樣做還是我將不得不妥協與一些僅部分矢量化的實施?

+1

你可以添加一個案例嗎? – Divakar

+0

借調;特別是id有興趣瞭解涉及不同軸的典型尺寸;以及group_sizes中的整數是如何分佈的。偶然,group_sizes是否具有相對較少的獨特元素? –

+0

group_sizes在幾十到幾千之間變化。有82個組。有人建議我可以通過置零來使結構保持正常。這在數學上可以算出來,但是由於最大的團隊比最小的團隊大得多(〜2個數量級),所以它將包括比必要更多的操作。 – gazza89

回答

1

我知道這聽起來很明顯,但是,如果你能負擔得起內存,我只需簡單地通過填充數據來檢查性能即可獲得統一的大小,即只需添加零並執行操作。有時候更簡單的解決方案比更理想的更具有Python/C往返速度的解決方案更快。

如果這不起作用,那麼你最好的選擇,就像Tom Wyllie建議的那樣,可能是一個分水嶺戰略。假設X是你的名單列表和列表alpha是一個數組,你可以通過收集第二個索引的大小開始(也許你已經有這個):

X_sizes = np.array([len(x_i) for x_i in X]) 

而且對它們進行排序:

idx_sort = np.argsort(X_sizes) 
X_sizes_sorted = X_sizes[idx_sort] 

然後你選擇一些桶,這是你工作的分區數。假設你選擇BUCKETS = 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可能會

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) 

這部分慢。同樣,如果你能負擔得起內存,那麼將X放在單個填充陣列中,然後就是X[idx, :bucket_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]] 

,對不起,我不給一個適當的功能,但我不知道是你的輸入或輸出的預期究竟如何,所以我只是把它們放在一起,你可以根據你的需要使用它們。