我正在尝试使用其他三个列表(高,中和低)创建一个包含值的列表。新列表应该从probability_array中评估它应该从哪个列表中选择一个随机值。新列表应该是播放列表:在随机选择的值将被选取两次(从高,中或低)之前,特定列表(高,中或低)的所有其他值必须在新生成的列表中。< / p>
任何想法,我怎么能做到这一点。到目前为止我的代码:
import numpy as np
array_length = 30
high = [(1, 2), 3, 4, 5, 6, (7, 8, 9)]
medium = [10, 11, (12, 13), 14]
low = [100, 101, 102, (103, 104)]
probability_array = np.random.choice(
['High', 'Medium', 'Low',],
array_length,
p=[4/7, 2/7, 1/7]
)
# i. e.
"""
['Low' 'High' 'High' 'High' 'High' 'High' 'Medium' 'Medium' 'High' 'Medium'
'High' 'High' 'Medium' 'Medium' 'High' 'High' 'Medium' 'Medium' 'High'
'High' 'High' 'High' 'High' 'Medium' 'Medium' 'High' 'High' 'High' 'Low'
'High']
"""
# new list should look like:
"""
[102, (1, 2), 4, (7, 8, 9), 3, 6, 14, ...]
"""
由于
答案 0 :(得分:1)
np.random.choice
的可以选择指定项目被选中的概率。您可以使用该列表构建high, medium, low
的列表,并将其提供给另一个循环以正确构建播放列表
- 在roganjosh的建议中,我也删除了同一项目背靠背发生的能力
import numpy as np
import random
import collections
playlist_length = 30
# key is the match strength (ie. high, medium, low)
matches = {
'high' : {
'items' : [(1, 2), 3, 4, 5, 6, (7, 8, 9)],
'prob' : 4/7
},
'medium' : {
'items' : [10, 11, (12, 13), 14],
'prob' : 2/7
},
'low' : {
'items' : [100, 101, 102, (103, 104)],
'prob' : 1/7
}
}
# create two lists:
# a is a list of match strengths
# p is the desired probability of an item from that match strength occuring
a, p = zip(*[(match, matches[match]['prob']) for match in matches])
# build a list of match strengths, with our chosen size and probability
results = np.random.choice(a=a, p=p, size=playlist_length)
# build our playlist
playlist = []
last_item = None
for match_strength in results:
# count all the items currently in playlist (a bit inefficient, probably don't have to recreate the Counter obj everytime)
count_playlist = collections.Counter(playlist)
# filter items of the given match strength, leaving out those that are at the current max
items = matches[match_strength]['items']
max_count = max([count_playlist[item] for item in items])
filtered = list(filter(lambda item: count_playlist[item] < max_count, items))
# if all items have the same count, reset the filtered list to be any item
if not len(filtered):
filtered = items
# drop last item so that it does not repeat
if last_item and last_item in filtered and len(filtered) > 1:
filtered.remove(last_item)
# add one from filtered items to playlist
new_item = random.choice(filtered)
playlist.append(new_item)
last_item = new_item
print(collections.Counter(results))
print(playlist)
计数器显示不同的匹配强度出现在可接受的频率Counter({'high': 19, 'medium': 10, 'low': 1})
并且播放列表是
[(1, 2), 14, 4, 5, 102, 3, (7, 8, 9), 6, (1, 2), 11, 10, (12, 13), 4, 3, 10, (12, 13), 5, 11, (7, 8, 9), 14, 6, 4, (7, 8, 9), 5, 10, (1, 2), 6, 3, 11, 4]
答案 1 :(得分:0)
我没有声明这种方法的效率(它说明了一种可能的方法,而不是最终的代码),但它可以确保每个列表(high
,medium
,{{1}在它重复第二次之前完全消耗等。它将适用于任何长度的最终序列,但它很容易导致相同的“轨道”背靠背出现。评论中没有澄清这是否是一个问题。
low
答案 2 :(得分:0)
试试这个:
def make_list(high, medium, low, parr):
_, (nhigh, nlow, nmed) = np.unique(parr, return_counts=True)
# A check can be added to make sure labels are in the set ['High', 'Low', 'Medium']
dl = {}
dl['High'] = (nhigh // len(high) + 1) * np.random.permutation(np.asanyarray(high, dtype=np.object)).tolist()
dl['Medium'] = (nmed // len(medium) + 1) * np.random.permutation(np.asanyarray(medium, dtype=np.object)).tolist()
dl['Low'] = (nlow // len(low) + 1) * np.random.permutation(np.asanyarray(low, dtype=np.object)).tolist()
play_list = []
for p in parr:
play_list.append(dl[p].pop())
return play_list