常用API?
import random# 隨機小數
print(random.random()) # 大于0且小于1之間的小數。0<= n<1.0
print(random.uniform(1,3)) # 大于1小于3的小數# 隨機整數
print(random.randint(1,5)) # 大于等于1且小于等于5之間的整數#從指定范圍內,按指定基數遞增的集合中 獲取一個隨機數。
random.randrange([start], stop[, step])
random.randrange(10, 30, 2) # 結果相當于從[10, 12, ... 26, 28]序列中獲取一個隨機數。
random.randrange(10, 30, 2) # 在結果上與 random.choice(range(10, 30, 2) 等效。# 隨機選擇一個返回
print(random.choice([1,'23',[4,5]])) # 1或者23或者[4,5]
# 隨機選擇多個返回,返回的個數為函數的第二個參數
print(random.sample([1,'23',[4,5]],2)) # 列表元素任意2個組合[[4, 5], '23']# 打亂列表順序
item=[1,3,5,7,9]
random.shuffle(item) # 打亂次序
print(item) # [5, 1, 3, 7, 9]
random.shuffle(item)
print(item) # [5, 9, 7, 1, 3]
加權隨機算法實現
方法一
最簡單的方法可以這樣:把序列按權重值擴展成:lists=[A,A,A,A,A,B,B,C,C,D],然后random.choice(lists)隨機選一個就行。雖然這樣選取的時間復雜度是O(1),但是數據量一大,空間消耗就太大了。
# coding:utf-8
import randomdef weight_choice(list, weight):""":param list: 待選取序列:param weight: list對應的權重序列:return:選取的值"""new_list = []for i, val in enumerate(list):new_list.extend(val * weight[i])return random.choice(new_list)if __name__ == "__main__":print(weight_choice(['A', 'B', 'C', 'D'], [5, 2, 2, 1]))
?
?
方法二
比較常用的方法是這樣:計算權重總和sum,然后在1到sum之間隨機選擇一個數R,之后遍歷整個集合,統計遍歷的項的權重之和,如果大于等于R,就停止遍歷,選擇遇到的項。
還是以上面的集合為例,sum等于10,如果隨機到1-5,則會在遍歷第一個數字的時候就退出遍歷。符合所選取的概率。
選取的時候要遍歷集合,它的時間復雜度是O(n)。
?
# coding:utf-8
import randomlist = ['A', 'B', 'C', 'D']def weight_choice(weight):""":param weight: list對應的權重序列:return:選取的值在原列表里的索引"""t = random.randint(0, sum(weight) - 1)for i, val in enumerate(weight):t -= valif t < 0:return iif __name__ == "__main__":print(list[weight_choice([5, 2, 2, 1])])
方法三
可以先對原始序列按照權重排序。這樣遍歷的時候,概率高的項可以很快遇到,減少遍歷的項。(因為rnd遞減的速度最快(先減去最大的數))比較{A:5,B:2,C:2,D:1}和{B:2,C:2,A:5,D:1}前者遍歷步數的期望是5/10*1+2/10*2+2/10*3+1/10*4=19/10而后者是2/10*1+2/10*2+5/10*3+1/10*4=25/10。這樣提高了平均選取速度,但是原序列排序也需要時間。先搞一個權重值的前綴和序列,然后在生成一個隨機數t后,可以用二分法來從這個前綴和序列里找,那么選取的時間復雜度就是O(logn)了。
# coding:utf-8
import random
import bisectlist = ['A', 'B', 'C', 'D']def weight_choice(weight):""":param weight: list對應的權重序列:return:選取的值在原列表里的索引"""weight_sum = []sum = 0for a in weight:sum += aweight_sum.append(sum)t = random.randint(0, sum - 1)return bisect.bisect_right(weight_sum, t)if __name__ == "__main__":print(list[weight_choice([5, 2, 2, 1])])
?