Create n-item playlist from playlist from multiple other lists

I am trying to create a list of values ​​from three other lists (high, medium and low). The new list should be evaluated with probability_arith, from which it should choose a random value. The new list should be like a playlist: before a randomly selected value is selected twice (high, medium, or low), all other values ​​of the particular list (high, medium, or low) must be in the newly created list.

Any ideas how I can achieve this. My code:

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, ...]
"""

      

thank

+3


source to share


3 answers


with it np.random.choice

is possible to specify the probability of selecting items You can create a list high, medium, low

with this and pass it to another loop to create the playlist correctly

- at the suggestion of roganjosh, I also removed the ability to make the same item go backwards

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)

      

output:



the counter shows that different strengths of correspondence are found at acceptable frequencies Counter({'high': 19, 'medium': 10, 'low': 1})

and the playlist is [(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


source


I do not pretend to the effectiveness of this approach (it illustrates one potential method, and not the final code), but it will work to ensure that each list ( high

, medium

, low

) is consumed entirely before it will be repeated a second time, etc. It will work for a final sequence of any length, but it can easily cause the same "track" to appear back to back. It was not clarified in the comments if this was the problem.



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)]

# Initialise exntended lists
new_high = []
new_medium = []
new_low = []

# Create extended lists as repeating units

for x in range(3):
    np.random.shuffle(high)
    np.random.shuffle(medium)
    np.random.shuffle(low)
    new_high.extend(high)
    new_medium.extend(medium)
    new_low.extend(low)

# Probability distribution for consuming the extended lists
probability_array = np.random.choice(
    ['High', 'Medium', 'Low',],
    array_length,
    p=[4.0/7, 2.0/7, 1.0/7]
)

# Our final sequence
playlist = []

# Keep track of how far we got through each of the extended lists
high_counter, medium_counter, low_counter = 0, 0, 0

for pick in probability_array:
    if pick == 'High':
        playlist.append(new_high[high_counter])
        high_counter += 1
    elif pick == 'Medium':
        playlist.append(new_medium[medium_counter])
        medium_counter += 1
    else:
        playlist.append(new_low[low_counter])
        low_counter += 1

print(playlist)

      

0


source


Try the following:

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

      

0


source







All Articles