2015-04-01 46 views
1

如何從這個數組做數組的數組列表在Python

s = np.array([[35788, 41715, ... 34964], 
      [5047, 23529, ... 5165], 
      [12104, 33899, ... 11914], 
      [3646, 21031, ... 3814], 
      [8704, 7906, ... 8705]]) 

我有這樣

end =[] 
for i in range(len(s)): 
    for j in range(i, len(s)): 
     out = mahalanobis(s[i], s[j], invcov)  
     end.append(out) 
print end 

一個循環,我把輸出:

[0.0, 12.99, 5.85, 10.22, 3.95, 0.0, 5.12, 3.45, 4.10, 0.0, 5.05, 8.10, 0.0, 15.45, 0.0] 

但我想像這樣的輸出:

[[0.0, 12.99, 5.85, 10.22, 3.95], 
[12.99, 0.0, 5.12, 3.45, 4.10], 
[5.85, 5.12, 0.0, 5.05, 8.10], 
[10.22, 3.45, 5.05, 0.0, 15.45], 
[3.95, 4.10, 8.10, 15.45, 0.0]] 
+1

要澄清,你想要一個清單,每個清單包含5個項目?或者內部列表的大小會有所不同? – Banjer 2015-04-01 01:17:09

+0

我想要一個列表,每個列表包含正好5個項目,就像距離矩陣 – 2015-04-01 01:20:34

回答

3

給n中的清單,

end = [0.0, 12.99, 5.85, 10.22, 3.95, 0.0, 5.12, 3.45, 4.10, 0.0, 5.05, 8.10, 0.0, 15.45, 0.0] 

可以構建使用

import numpy as np 
result = np.zeros((s.shape[0],)*2)    # 1 
result[np.triu_indices(s.shape[0], 0)] = end  # 2 
result += result.T        # 3 
print(result) 

其產生

[[ 0. 12.99 5.85 10.22 3.95] 
[ 12.99 0.  5.12 3.45 4.1 ] 
[ 5.85 5.12 0.  5.05 8.1 ] 
[ 10.22 3.45 5.05 0. 15.45] 
[ 3.95 4.1 8.1 15.45 0. ]] 
  1. 使用零填充的陣列所需的2維陣列
  2. np.triu_indices(s.shape[0], 0)返回上三角形的索引形狀爲(s.shape[0], s.shape[0])的數組。

    In [95]: np.triu_indices(5, 0) 
    Out[95]: 
    (array([0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4]), 
    array([0, 1, 2, 3, 4, 1, 2, 3, 4, 2, 3, 4, 3, 4, 4])) 
    

    result[...] = end填充上三角形與來自end的值。

  3. result的轉置並將其添加到result,從而使result對稱。

這允許你獲得的結果,而無需調用二者mahalanobis(s[i], s[j])mahalanobis(s[j], s[i])這是不必要的,因爲mahalanbis距離是對稱的。


注意,對角線始終是零,因爲mahalanobis(x,x)等於爲 任何x爲零。因此,對於一點點增加效率,您可以排除對角線:

end =[] 
for i in range(len(s)): 
    for j in range(i+1, len(s)):    # <-- note i+1 
     out = mahalanobis(s[i], s[j], invcov)  
     end.append(out) 

,然後建立result用,除了像以前相同的代碼,現在我們可以使用

result[np.triu_indices(s.shape[0], 1)] = end  

,而不是

result[np.triu_indices(s.shape[0], 0)] = end  

np.triu_indices的第二個參數控制對角偏移量。當偏移量爲1時,對應於主對角線的索引被省略。

In [96]: np.triu_indices(5, 1) 
Out[96]: (array([0, 0, 0, 0, 1, 1, 1, 2, 2, 3]), array([1, 2, 3, 4, 2, 3, 4, 3, 4, 4])) 
6

您需要循環不同的至少方式:

end =[] 
for s1 in s: 
    end.append([mahalanobis(s1, s2, invcov) for s2 in s]) 

最重要的事情是,內環必須對整個s再次,否則你將永遠不會得到一個正方形,但1 + 2 + ... + len(s)項目(在這種情況下15爲len(s)爲5)。

接下來,內部循環必須包含在列表中,因爲您需要列表列表。

不重要但很好:我已經改變了內部循環到列表理解;並且我已將兩個循環更改爲直接在s上,因爲實際上沒有理由繼續循環遍歷索引的間接方法,然後使用這些索引來獲得s項目關注

所以我做了四個改變,但前兩個是你真正需要得到你想要的結果,另外兩個只是很好的改進:-)。

+0

很好緊湊,但是如何確保在內部陣列中有5個元素?當我運行你的代碼,我得到不同的數組長度取決於輸入,我認爲陛下想要5修復? – 2015-04-01 01:36:27

+0

每個子列表中的項目數與子列表數量一樣多 - 「像距離矩陣」(N個點之間的距離矩陣當然總是一個方陣,N乘N)。 – 2015-04-01 01:48:48

0

你的循環是好的,如果你只需要添加一個計數器和一個第二陣列,那麼您可以在5個元素的組羣的結果在一個陣列(如果這是期望的結果)

end =[] 
tmp =[] 
for i in range(len(s)): 
    for j in range(i, len(s)): 
     out = mahalanobis(s[i], s[j], invcov) 
     if k % 5 == 0 and k != 0: 
      end.append(tmp) 
      tmp =[]  
     k += 1 
     tmp.append(out) 
if len(tmp) > 0: 
    end.append(tmp) 
print end 

不管你的輸入然後,你的輸出將是具有n陣列的陣列,每個具有5名成員[[1,2,3,4,5],[...],[...], ... ]

+0

您錯過了'範圍(i,len(s))'中最重要的錯誤 - 每次生成越來越少的項目。如果len爲5,則這是一個三乘五的矩陣,而不是** 5中的5被聲明爲問題主體中的期望輸出。 – 2015-04-01 01:53:07

+0

@AlexMartelli yupp,我只專注於5陣列業務,因爲陛下直到我發佈我的答案才發佈樣本數據......我更喜歡你的風格,如果結果是所需的,那麼完美! – 2015-04-01 02:03:12

0

的另一種方法是使用您的代碼,並在它下面:

end2 = [] 
for repeat in range(len(end)/5-1): 
    end2.append(end[0:4]) 
    end = end[5:] 
+0

由Q的發佈代碼生成的'end'只有15個項目(不是25),所以這將在'end2'的尾部有大量的空白。 – 2015-04-01 01:50:13

0

下面是的out要素分配到對稱矩陣直向前迭代:

x=np.zeros((5,5)) 
cnt=0 
for i in range(5): 
    for j in range(i,5): 
     x[j,i] =x[i,j] = out[cnt] 
     cnt += 1 

生產

array([[ 0. , 12.99, 5.85, 10.22, 3.95], 
     [ 12.99, 0. , 5.12, 3.45, 4.1 ], 
     [ 5.85, 5.12, 0. , 5.05, 8.1 ], 
     [ 10.22, 3.45, 5.05, 0. , 15.45], 
     [ 3.95, 4.1 , 8.1 , 15.45, 0. ]]) 

由於本次迭代平行原來的一個,你可以構建矩陣立即:

n = s.shape[0] 
x = np.zeros((n,n)) 
for i in range(n): 
    for j in range(i+1, n): 
     x[i,j] = x[j,i] = mahalanobis(s[i], s[j], invcov)  
print x 

我在內循環中使用i+1,因爲顯然mahalanobis對於i==j爲0。