简体   繁体   中英

Selecting items from a list through weighted probabilities

I have the following list:

60, 62, 63, 65, 66, 68, 69, 71, 73, 74, 76, 77, 79, 80, 82, 83, 85, 87, 88

and I need to have pitches chosen from the list with these conditions:

  1. 100 pitches need to be chosen

  2. First a random pitch from the list needs to be chosen, and the following pitches chosen from the list would be determined through weighted probabilities.

What I am trying to accomplish is, after the first pitch is randomly chosen from the list (71), the next pitch chosen would be determined by weighted probability according to its proximity to 71 (69 and 73 would have the most probability of being chosen, followed by 68 and 74, etc.)

Supposing 68 would be chosen as the pitch following 71, then the next pitch following 68 would be determined by weighted probability according to its proximity to 68 (66 and 69 would have the most probability of being chosen, followed by 65 and 71, etc.)

My main concern is that, although the program runs without errors (that is, at least an error message doesn't interrupt its execution), I am still not convinced if it is running the way I intended. The reason I say this is because, even though I want the program to choose 100 notes, it always chooses exactly 5050 notes. Why 5050?

Here is my code:

from music import *
from random import *

solo = Phrase()
solo.setTempo(100)

durations = []
pitches = []
pitchIndex = ()
numberOfNotesInSolo = 0
listOfAvailablePitches = [60, 62, 63, 65, 66, 68, 69, 71, 73, 74, 76, 77, 79, 80, 82, 83, 85, 87, 88]

pitch = choice(listOfAvailablePitches)
pitchIndex = listOfAvailablePitches.index(pitch)

while numberOfNotesInSolo < 100:

   weightedProbabilitiesForPitches = [pitchIndex + 1] * 20 + [pitchIndex - 1] * 20 + [pitchIndex + 2] * 15 + [pitchIndex - 2] * 15 + [pitchIndex + 3] * 12 + [pitchIndex - 3] * 12 + [pitchIndex + 4] * 8 + [pitchIndex - 4] * 8 + [pitchIndex + 5] * 5 + [pitchIndex - 5] * 5 + [pitchIndex + 6] * 3 + [pitchIndex - 6] * 3        

   pitchIndex = choice(weightedProbabilitiesForPitches)         

   while pitchIndex > 18 or pitchIndex < 0:

      pitchIndex = choice(weightedProbabilitiesForPitches)

   pitch = listOfAvailablePitches[pitchIndex]
   weightedProbabilitiesForDurations = [SN] * 1 + [EN] * 1 + [DEN] * 1 + [QN] * 1 + [DQN] * 1

   duration = choice(weightedProbabilitiesForDurations)
   pitches.append(pitch)
   durations.append(duration)
   solo.addNoteList(pitches, durations)
   numberOfNotesInSolo = numberOfNotesInSolo + 1     

print solo

I think the problem you're facing is on how to generate a list of weight for your list of pitches. Here is my code:

pitches =  [60, 62, 63, 65, 66, 68, 69, 71, 73, 74, 76, 77, 79, 80, 82, 83, 85, 87, 88]
num = len(pitches)
choice = random.randint(0, num-1)
below = choice
above = num-choice-1
weightbelow = list(range(num-1, num-1-below, -1))[::-1]
weightabove = list(range(num-1, num-1-above, -1))
weight = weightbelow + [num] + weightabove

For example, if the choice of pitch is 11 (ie, pitches[11]=77 ), the weight will become:

[8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 18, 17, 16, 15, 14, 13, 12]

Then you can do weighted random choice like the one in A weighted version of random.choice

The code above is to create an ascending list of integers up to len(pitches)-1 , then a descending list, both of suitable length according to your choice, then concatendate them together. If you need a different distribution other than a linear one, do some transformation on it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM