2017-02-15 108 views
0

我一直在使用這種結構來排序向量(數組)的向量的某些屬性。這種結構(通過將它們用標量壓縮並按標量排序來排序向量)一直在其他部分代碼中工作,但在這種情況下,它失敗並顯示警告: 數組的真值更多比一個元素含糊不清。這取決於標量是有重複值(見下文)排序標量和numpy數組的壓縮列表:不處理重複

from numpy import array 

pnts =[array([ 0.  , 0.45402743, -0.64209154]), 
     array([-0.27803373, 0.45402743, -0.64209154]), 
     array([-0.64874546, 0.45402743, 0.  ]), 
     array([-0.27803373, 0.45402743, 0.64209154]), 
     array([ 0.  , 0.45402743, 0.64209154]), 
     array([ 0.  , -0.45402743, 0.64209154]), 
     array([-0.27803373, -0.45402743, 0.64209154]), 
     array([-0.64874546, -0.45402743, 0.  ]), 
     array([-0.27803373, -0.45402743, -0.64209154]), 
     array([ 0.  , -0.45402743, -0.64209154]), 
     array([-0.46338972, 0.  , 0.64209154]), 
     array([-0.46338972, 0.  , -0.64209154]), 
     array([-0.83410135, 0.  , 0.  ])] 

ds = [0.64209154071986396, 0.69970301064027385, 0.64874545642786008, 
     0.69970301064027385, 0.64209154071986396, 0.64209154071986396, 
     0.69970301064027385, 0.64874545642785986, 0.69970301064027385, 
     0.64209154071986396, 0.79184062463701899, 0.79184062463701899, 
     0.83410134835400274] 

pnts = [pnt for (d,pnt) in sorted(zip(ds,pnts))] #sort by distances ds 
print pnts 

但是,如果我把它縮短到第一3點,它的工作:

from numpy import array 

pnts =[array([ 0.  , 0.45402743, -0.64209154]), 
    array([-0.27803373, 0.45402743, -0.64209154]), 
    array([-0.64874546, 0.45402743, 0.  ])] 

ds = [0.64209154071986396, 0.69970301064027385, 0.64874545642786008] 

pnts = [pnt for (d,pnt) in sorted(zip(ds,pnts))] 
print pnts 

>[array([ 0.  , 0.45402743, -0.64209154]), array([-0.64874546, 0.45402743, 0.  ]), array([-0.27803373, 0.45402743, -0.64209154])] 

我敢肯定這個問題是因爲ds之間有重複。當我從3點到4點出現第一個副本時,它再次失敗。但是其他Python中的排序例程在重複時很好地工作。爲什麼不是這個?

+1

爲什麼要使用'np.arrays'的'list'。 –

+0

一般來說,當您嘗試比較2個數組並將結果用作標量布爾值時,會產生「ValueError」。經典案例是「如果A == B:」。這是因爲'sort'試圖比較'pts'列表中的兩個數組。 – hpaulj

回答

1

您並未按ds值排序pnts。您正在整理zip(ds, pnts)的元素。這些元組按照字典順序排列;如果您將(x, y)(x, z)進行比較,則比較會發現第一個元素相等,並繼續比較yz。由於元組的第二個元素是NumPy數組,它們沒有排序關係*,因此排序失敗。

如果你想通過ds值進行排序,指定挑出這些值排序關鍵字:

sorted(zip(ds, pnts), key=lambda x: x[0]) 

import operator 
sorted(zip(ds, pnts), key=operator.itemgetter(0)) 

*具體而言,如果比較兩個NumPy的使用像<這樣的運算符的數組,而不是告訴你第一個數組是否以某種方式「小於」另一個數組,它將爲您提供一系列廣播元素比較結果。

+0

您的解決方案奏效!並感謝您的解釋。 – hess8

+0

有趣的是,這些錯誤並沒有出現在我的代碼中存在「重複」的其他部分,因爲數字噪聲使得它們在最後一位數字上略有不同。 – hess8

1

Python中的元組按字典順序進行比較。這種比較短路,即如果前兩個元件不同,則其它元件被跳過,因爲它們不能顛倒順序。 這就是爲什麼你沒有看到這個錯誤,當沒有重複。

一個解決辦法是使用np.argsort

order = np.argsort(ds) 
pnts_sorted = np.array(pnts)[order, :] 

這避免了壓縮和返回的已排序的點作爲一個二維數組,這對於許多用途是更方便的結構。如果你仍然想要一個數組列表:list(pnts_sorted)會給你一個。

np.argsort執行間接排序,而不是移動它的參數的元素它寫下他們應該如何移動,以便他們排序。這個「洗牌配方」(只是一個整數數組,每個指示要排序的數組中的哪個元素必須位於其位置)可以應用於其他數組,如果它們具有相同數量的排序軸上的元素。在代碼片段中,我們將pnts轉換爲2d數組(因爲順序不適用於索引到列表中),然後根據ds使用順序對行進行排序。 (索引中的冒號告訴numpy將shuffle應用於整行。)

最後,如果我可以的話,一個一般的建議。除非有令人信服的理由,否則通常建議在數組中保留這種數據(包括ds和pnts),而不是列表。例如,排序數組通常比排序列表要快得多(除非您使用np.sort對列表進行排序,但這僅僅是因爲np.sort即使給它提供列表也會返回數組)。

+0

謝謝保羅。這是排序的好方法...我會嘗試。列表非常好,因爲它很容易添加到它們而不是np.arrays。 – hess8

+0

是的,如果您的數據大小經常變化且無法預測,那就是使用列表的原因。如果只是幾次,'np.concatenate'可能仍然是更好的選擇。當然,如果不考慮性能,那麼在某些情況下列表可能會更方便。 –