2011-09-08 81 views
4

我想知道用給定條件的數組中其他隨機元素替換數組中元素的最有效方法。更具體地說,我需要將不符合給定條件的每個元素替換爲該行中的另一個隨機值。例如,我想將每行數據替換爲介於-.8和.8之間的數據(行)中的隨機單元格。我inefficinet解決方案看起來是這樣的:Python中的高效數組替換

import numpy as np 
data = np.random.normal(0, 1, (10, 100)) 
for index, row in enumerate(data): 
     row_copy = np.copy(row) 
     outliers = np.logical_or(row>.8, row<-.8) 
     for prob in np.where(outliers==1)[0]: 
      fixed = 0 
      while fixed == 0: 
       random_other_value = r.randint(0,99) 
       if random_other_value in np.where(outliers==1)[0]: 
        fixed = 0 
       else: 
        row_copy[prob] = row[random_other_value] 
        fixed = 1 

顯然,這是沒有效率的。

回答

4

我認爲把所有好的值拉出來會更快,然後用random.choice()來選擇一個你需要的值。類似這樣的:

import numpy as np 
import random 
from itertools import izip 

data = np.random.normal(0, 1, (10, 100)) 
for row in data: 
    good_ones = np.logical_and(row >= -0.8, row <= 0.8) 
    good = row[good_ones] 
    row_copy = np.array([x if f else random.choice(good) for f, x in izip(good_ones, row)]) 

您編寫的高級Python代碼比Python的C內部要慢。如果你能將工作推到C內部,通常會更快。換句話說,試着讓Python爲你做繁重的工作,而不是寫很多代碼。這是禪...寫更少的代碼來獲得更快的代碼。

我添加了一個循環來運行您的代碼1000次,並運行我的代碼1000次,並測量他們執行多長時間。根據我的測試,我的代碼速度快了十倍。

的這是什麼代碼正在做補充說明:

row_copy正在通過建立一個新的列表,然後調用新的名單上np.array()將其轉換爲一個與NumPy數組對象設置。新列表正在通過列表理解來構建。

新的列表是按照規則制定的:如果數字是好的,保留它;否則,從好值中隨機選擇。

列表理解遍歷一系列值,但要應用此規則,我們需要兩個值:數字和標誌說明該數字是否好。使列表理解同時沿着兩個序列走的最簡單和最快的方式是使用izip()將兩個序列「壓縮」在一起。 izip()將產生元組,每次一個元組,其中元組爲(f, x); f在這種情況下是國旗說好還是不好,x是這個數字。 (Python有一個名爲zip()的內置功能,它幾乎完全相同,但實際上構建了一個元組列表; izip()只是產生一個產生元組值的迭代器,但您可以在Python提示符下使用zip()以瞭解更多信息它是如何工作)

在Python中,我們可以解開一個元組到變量名像這樣:

a, b = (2, 3) 

在這個例子中,我們設置a至2 b至3.在列表理解我們解開將izip()的元組分解爲變量fx

則列表理解的心臟是一個「三元if」語句,像這樣:

a if flag else b 

以上將返回值a如果flag值爲true,否則返回b。在這個列表中的理解是:

x if f else random.choice(good) 

這實現了我們的規則。

+0

我真的很感激這個答案。如果你有一點時間,你能否更多地解釋一下這條線是幹什麼的? row_copy = np.array([if if else] f,x iniziz(good_ones,row)]]) – mike

+0

當然。我會把答案放在答案中。往上看。 – steveha