2016-02-28 202 views
2

Python新手,並且一直在學習數組。我堅持一個足夠簡單的問題,需要一個解決方案。我有兩個陣列:Python:比較兩個數組的所有元素並修改第二個數組

a = [2.0, 5.1, 6.2, 7.9, 23.0]  # always increasing 
b = [5.1, 5.5, 5.7, 6.2, 00.0]  # also always increasing 

和欲得到的數組是:

c = [0.0, 5.1, 6.2, 0.0, 0.0]  # 5.5, 5.7, 00.0 from 'b' were dropped and rearranged such that position of equivalent elements as in 'a' are maintained 

我比較兩者 '一' & 'B' 使用numpy的如:

y = np.isclose(a, b) 
print y 
# [False False False False False] 

(或者)我也嘗試過這樣的事情,這是不正確的方式(我認爲):

c = np.zeros(len(a)) 
for i in range (len(a)): 
    for j in range (len(a)): 
     err = abs(a[i]-b[j]) 
     if err == 0.0 or err < abs(1): 
      print (err, a[i], b[j], i, j) 
     else: 
      print (err, a[i], b[j], i, j) 

如何從這裏開始獲取'c'?

+1

嘗試'y = np.isclose(a,b,atol = 0.05)'。 – Norman

+0

它不影響結果。把'atol = 0.5'給出'[False True False False]',這是'c'bool明智的。 – rNov

+0

我是否簡單地將'a'的元素值複製到'True'值的位置?還是有更好的方法呢? – rNov

回答

4

這些解決方案的工作,即使數組大小不同。

簡易型

c = [] 

for i in a: 
    if any(np.isclose(i, b)): 
     c.append(i) 
    else: 
     c.append(0.0) 

numpy的版本

aa = np.tile(a, (len(b), 1)) 
bb = np.tile(b, (len(a), 1)) 
cc = np.isclose(aa, bb.T) 
np.any(cc, 0) 
c = np.zeros(shape=a.shape) 
result = np.where(np.any(cc, 0), a, c) 

解釋:

我會做矩陣比較在這裏。首先將數組展開爲矩陣。長度爲交換,有一個尺寸大小相等它創建矩陣:

aa = np.tile(a, (len(b), 1)) 
bb = np.tile(b, (len(a), 1)) 

他們看起來像這樣:

# aa 
array([[ 2. , 5.1, 6.2, 7.9, 23. ], 
     [ 2. , 5.1, 6.2, 7.9, 23. ], 
     [ 2. , 5.1, 6.2, 7.9, 23. ], 
     [ 2. , 5.1, 6.2, 7.9, 23. ], 
     [ 2. , 5.1, 6.2, 7.9, 23. ]]) 

# bb 
array([[ 5.1, 5.5, 5.7, 6.2, 0. ], 
     [ 5.1, 5.5, 5.7, 6.2, 0. ], 
     [ 5.1, 5.5, 5.7, 6.2, 0. ], 
     [ 5.1, 5.5, 5.7, 6.2, 0. ], 
     [ 5.1, 5.5, 5.7, 6.2, 0. ]]) 

然後對它們進行比較。需要注意的是BB調換:

cc = np.isclose(aa, bb.T) 

,你會得到:

np.any(cc, 0) 

返回

array([False, True, True, False, False], dtype=bool) 

現在創建:

array([[False, True, False, False, False], 
     [False, False, False, False, False], 
     [False, False, False, False, False], 
     [False, False, True, False, False], 
     [False, False, False, False, False]], dtype=bool) 

您可以通過軸0彙總此數組c:

c = np.zeros(shape=a.shape) 

並選擇合適的值,無論是從一個或c:

np.where(np.any(cc, 0), a, c) 

而結果:

array([ 0. , 5.1, 6.2, 0. , 0. ]) 
+0

我認爲這是OP想要的。但他現在添加了一條評論,說在'b'數組末尾可能存在一些必須忽略的垃圾值。所以在使用之前需要修改該數組,或者修改算法。 (適用於所有當前的答案,我認爲。) – Norman

+0

是的,我已經添加了關於這個假設的評論。如有必要,餘數可以是np.append。 – hruske

+0

非常詳細的解釋我必須說。唯一的問題是,如果使用numpy生成零(例如)'c'的空矩陣,將不會'np.append'拋出錯誤,而不是使用'c [i] = b [j]'。 – rNov

1

嘗試更好地解釋你的程序應該在一個更一般的方式做什麼。只給出數組a,b和c不會告訴它應該做什麼。就好像有人說「如果A = 5,B = 7,寫一個程序,使得C = 20」。

從你的嘗試中,我猜測任務是「c的每個元素應該等於a的相應元素,如果它的值接近(相差0.5或更小)與b中的對應值。如果不是,它應該是零。「

另外,你真的需要使用numpy嗎?嘗試只使用循環和列表方法。你也可以看看「生成器表達式和列表解析」

最後,你的標題說「(...)並修改第二個數組」。不應該有第三個名爲c的數組。結果應該顯示在數組b的修改版本中。


編輯:如果規範是真的這一點,那麼代碼可能是

a = [2.0, 5.1, 6.2, 7.9, 23.0] 
b = [5.1, 5.5, 5.7, 6.2, 0.0] 
c = [] 
for x,y in zip(a,b): c.append(x if abs(x-y)<=0.5 else 0.0) 
print c 

其中給出以下答案

[0.0, 5.1, 6.2, 0.0, 0.0] 

順便說一句,如果這是一個過程,你仍然可能因爲不遵循規範而導致不好的成績(「......並修改第二個數組」)。

+0

你猜對了任務。我試着交替使用循環代替Numpy(請參閱第二段代碼)。修改第二個數組是我需要做的,但我會解決第三個數組'''因爲它有助於保持簡單的暫時。 – rNov

+0

提示:如果您是以python開頭,您應該堅持使用基本語言(即python文檔中的「語言參考」和「庫參考」)。不要嘗試使用外部庫(例如Numpy)。 –

+0

這不是一個順便說一句,我是一個數據科學愛好者,在處理不同的數據集時遇到了這個問題。數組實際上代表了一個更大的數據集的列。 – rNov

1

With np.isclose您已經創建了一個「最近」元素爲True的數組。因此,您可以使用此結果將所有其他元素設置爲零。

import numpy as np 
a = np.array([2.0, 5.1, 6.2, 7.9, 23.0])  # always increasing 
b = np.array([5.1, 5.5, 5.7, 6.2, 00.0])  # also always increasing 
a[~np.isclose(a,b, atol=0.5)] = 0 
a 

這返回array([ 0. , 5.1, 6.2, 0. , 0. ])

但是請注意,您希望設置所有未關閉的元素,因此您需要反轉(~)結果。

1

看來你想保留a也是b的元素。

純線性時間蟒溶液:

c=zeros_like(a) 

j=0 
n=len(c) 
for i in range(n): 
    while j<n and b[j]<a[i]-.1 : j+=1 
    if j==n : break 
    if abs(a[i]-b[j])<.1 : c[i]=a[i] 

而對於精確匹配一個numpy的溶液:

a*in1d(a,b)

in1d(a,b)指示a是在b元件的地方:in1d(a,b)[False, True, True, False, False]

由於True1False0a*in1d(a,b)[ 0., 5.1, 6.2, 0. , 0. ]。由於in1d分類爲ab,這是一個複雜的算法,但通常更快。如果需要近似相等,則解決方案可以先舍入陣列(np.round(a,1)

+0

我的解決方案與您的解決方案非常相似,只使用嵌套for循環 – rNov

+0

是的,但它是一種二次算法,它不使用數組排序的事實。在大數組上效率不高。 –

0

這是我能夠獲得c所需佈置的替代方法。

import numpy as np 

a = [2.0, 5.1, 6.2, 7.9, 23.0] # always increasing 
b = [5.1, 5.5, 5.7, 6.2, 00.0] # also always increasing 
c = np.zeros(len(a)) 

for i in range (len(a)): 
    for j in range (len(a)): 
     err = abs(a[i]-b[j]) 
     if err == 0.0 or err < abs(0.1): 
      c[i] = b[j] 

print c 
#[ 0. 5.1 6.2 0. 0. ] 
+0

謝謝。現在你的目標更清晰了。我在帖子中給出了更有效的解決方案。 –

+0

在'if'語句中,'abs(0.1)'可以在沒有'abs'函數的情況下被寫入(abs(0.1)爲0.1)。同樣,如果'err == 0.0',那也意味着'err <0.1',所以第一個條件是多餘的。你可以寫'如果錯誤<0.1:'。 –

+0

在這種情況下,abs(0.1)'是多餘的,但是當值足夠接近時,在某些情況下'err'可能是負數。因此需要'err == 0'和'err rNov