2016-03-08 57 views
0

我正在研究一個涉及二進制模式的項目(這裏的np.arrays爲0和1)。 我想修改它們的一個隨機子集並返回一些給定部分的值已被改變的模式的改變版本(如map函數爲固定大小的數組的隨機子集) ex:take模式[0 0 1 0 1]和速率0.2,返回[[0 1 1 0 1] [1 0 1 0 1]]隨機化陣列的一部分

它通過使用輔助陣列和符合條件迭代似乎是可能的,但有一個「乾淨」的方式做到這一點?

在此先感謝!

+2

顯示你有 – JBernardo

+1

代碼所以,如果你有一個數組A的二進制值,數組中的每個索引都有一個概率P?例如,你的模式[0 0 1 0 1]可以變爲[1 1 1 1 1],即使這樣做不可能嗎? – Carser

回答

0

map函數也適用於布爾數組。您可以在子樣本邏輯添加到您的功能,像這樣:

import numpy as np 
rate = 0.2 
f = lambda x: np.random.choice((True, x),1,p=[rate,1-rate])[0] 

a = np.array([0,0,1,0,1], dtype='bool') 
map(f, a) 
# This will output array a with on average 20% of the elements changed to "1" 
# it can be slightly more or less than 20%, by chance. 

或者你可以重寫一個地圖功能,像這樣:

import numpy as np 

def map_bitarray(f, b, rate): 
    ''' 
    maps function f on a random subset of b 
    :param f: the function, should take a binary array of size <= len(b) 
    :param b: the binary array 
    :param rate: the fraction of elements that will be replaced 
    :return: the modified binary array 
    ''' 
    c = np.copy(b) 
    num_elem = len(c) 
    idx = np.random.choice(range(num_elem), num_elem*rate, replace=False) 
    c[idx] = f(c[idx]) 
    return c 

f = lambda x: True 
b = np.array([0,0,1,0,1], dtype='bool') 
map_bitarray(f, b, 0.2) 
# This will output array b with exactly 20% of the elements changed to "1" 
+0

有兩件事:首先,我有時會得到'[False False True False True]'的輸出,其中沒有元素被改變。其次,這不允許將'False'轉換爲'True'。後者可能不是一個問題,因爲OP不清楚這是否可能。 –

+0

在第一個選項中,平均爲20%,這意味着可能會出現多於或少於20%的元素髮生變化的情況。第二個選項總是給你20%的準確率(或者你要求的任何比率)。在40%的情況下,你看到'[False False True False True]'是因爲'True'被設置爲'True'(沒有改變)。 OP可以在lambda中設置他想要的任何函數,例如這個:'f = lambda x:not(x)'。 – Bastiaan

+0

更正:'f = lambda a:np.logical_not(x)' – Bastiaan

0
rate=0.2 
repeats=5 
seed=[0,0,1,0,1] 
realizations=np.tile(seed,[repeats,1])^np.random.binomial(1,rate,[repeats,len(seed)]) 

使用np.tile()以產生從所述種子行的矩陣。

np.random.binomial()用您的請求速率生成二項掩碼矩陣。

運用面具與XOR二進制運算^


編輯:

基於@Jared Goguen評論,如果你想改變位的20%,可以說明以口罩選擇要隨機更改的元素:

seed=[1,0,1,0,1] 

rate=0.2 
repeats=10 

mask_list=[] 

for _ in xrange(repeats): 
    y=np.zeros(len(seed),np.int32) 
    y[np.random.choice(len(seed),0.2*len(seed))]=1 
    mask_list.append(y) 

mask = np.vstack(mask_list) 
realizations=np.tile(seed,[repeats,1])^mask 
+0

應該指出,這並不改變0.2的條目的比例,而是每個元素有0.2的機會改變。平均重新排列將會有0.2個元素的比例發生變化,但是每個重新排列可能在沒有元素髮生變化並且所有元素髮生變化的地方都有。這個實現完美地模擬了每個元素具有*獨立*轉換概率的結構,但是如果知道具有兩個1的5個陣列將以三個1轉換爲5個陣列,則它失敗。 –

+1

感謝您指出。另一種情況將用馬爾可夫鏈建模,不是嗎? – xvan

+1

對於馬爾可夫鏈,轉換矩陣由每個狀態轉換到其他狀態的概率組成。根據定義,在這個過程中狀態向量的總和是不變的,所以我真的沒有看到使用馬爾可夫鏈對此進行建模的方法。可能有辦法使用類似的過程,但轉換矩陣不會是隨機的。 –

0

所以,已經有一個答案提供了序列,其中每個元素都有一個隨機轉移概率。但是,您似乎可能想要改變一些確切的元素部分。例如,[1, 0, 0, 1, 0]可以更改爲[1, 1, 0, 1, 0][0, 0, 0, 1, 0],但不是[1, 1, 1, 1, 0]

基於xvan的回答,前提是使用按位異或運算符^。當一位與0異或時,它的值不會改變。當一個位與1相異時,它會翻轉。從你的問題來看,你似乎想改變序列中的len(seq)*rate位數。首先創建mask其中包含len(seq)*rate的數字1。爲了得到一個改變的序列,用洗牌版本mask對原始序列進行異或。

這裏有一個簡單的,低效率的實現:

import numpy as np 

def edit_sequence(seq, rate, count): 
    length = len(seq) 
    change = int(length * rate) 
    mask = [0]*(length - change) + [1]*change 
    return [seq^np.random.permutation(mask) for _ in range(count)] 

rate = 0.2 
seq = np.array([0, 0, 1, 0, 1]) 

print edit_sequence(seq, rate, 5) 

# [0, 0, 1, 0, 0] 
# [0, 1, 1, 0, 1] 
# [1, 0, 1, 0, 1] 
# [0, 1, 1, 0, 1] 
# [0, 0, 0, 0, 1] 

我真的不知道很多關於NumPy的,所以也許更有經驗的人可以使這個效率,但這種方法似乎固體。

編輯:這裏有一個版本的情況下約30%的速度:

def edit_sequence(seq, rate, count): 
    mask = np.zeros(len(seq), dtype=int) 
    mask[:len(seq)*rate] = 1 
    output = [] 
    for _ in range(count): 
     np.random.shuffle(mask) 
     output.append(seq^mask) 
    return output 

看來,這個更新版本擴展得很好的seq的大小和count值。在seqmask中使用dtype=bool會使時間進一步縮短50%。