1

Here is my code. Assume I have this:

weights = [0.3,0.1,0.2,0.4]
temp_list = [None,1,None,None]

What I want is if the value is None, shift the weights to the highest weight. For example, The first value of temp_list is None, so I want the weight shifted to the highest weight in weights (in this case 0.4) and therefore get 0.7

[0.0,0.1,0.2,0.7] <- First element is None; add to highest weight to get (0.3+0.4 = 0.7)
[0.0,0.1,0.2,0.7] <- Second element has value; no change
[0.0,0.1,0.0,0.9] <- Third element is None; add to highest weight to get 0.9
[0.0,1.0,0.0,0.0] <-- final output; therefore this weight is 1.0 for the second element since everywhere else is None.

Here is my attempt:

for idx, element in enumerate(temp_list):

   if element == None:
      # do something about this
      max_index = weights.index(max(weights))
      weights[max_index] = weights[idx] + weights[max_index]
    
      #set value to 0
      weights[idx] = 0.0

   print(weights)

My question is how do I find the highest weight number in the list and add my current weight to it? What if I am trying to look for the second or third highest weight number? Or is there a better way to approach this kind of problem?

mathgeek
  • 125
  • 7
  • Do you want to shift just the weight corresponding to `None`, or all the weights? Could you please mention in the question how you obtained the final output you have mentioned? – Ganesh Tata Nov 10 '20 at 04:23
  • 1
    @GaneshTata Yes I just want to shift the weight corresponding to None. The obtained final output is what I want to achieve. I was not sure how to implement that in code. – mathgeek Nov 10 '20 at 04:27
  • "final output; therefore this weight is 1.0 for the second element since everywhere else is None." - How did the second element become 1.0 in the final step? Before this step, the second element was 0.1 and the max element is 0.9. So the max element must be max among all elements *excluding* the current element ( 0.9 in this case )? – Ganesh Tata Nov 10 '20 at 04:38
  • 1
    @GaneshTata Yes, by the time it reaches 'final output;therefore this weight is 1.0..', we only have values to compare (the second element and the last element). Since we know the last element is None, that weight (0.9) will shift to and add to the weight (0.1). So 0.1+0.9 and we get 1.0 as the weight. – mathgeek Nov 10 '20 at 04:44

1 Answers1

1

We can approach this problem through a pure python approach, and a numpy-based approach.

In both approaches, we can first calculate the index of the max element in the array. Now, we can iterate through temp_list and add weights to the max element. Note that until we reach the index of the max element, it remains the maximum in the array ( since we are adding more weights to it ). Once we reach the max_weights_index, we set the corresponding weight to 0 and check for the current maximum in the array. The same procedure is repeated.

Note - I am assuming there are no duplicates in the weights array.

Pure Python

weights = [0.3,0.1,0.2,0.4]
temp_list = [None,1,None,None]

def get_max_index(weights):
    # Assuming no duplicates, find index with the max element
    max_weight = -1
    max_index = -1
    for i, weight in enumerate(weights):
        if weight > max_weight:
            max_weight = weight
            max_index = i
    return max_index

max_weight_index = get_max_index(weights)

for i, tmp_element in enumerate(temp_list):
    if tmp_element is None:
        if i == max_weight_index:
            current_max = weights[i]
            weights[i] = 0
            max_weight_index = get_max_index(weights)
            weights[max_weight_index] += current_max
        else:
            weights[max_weight_index] += weights[i]
            weights[i] = 0
    print(weights)

Output

[0, 0.1, 0.2, 0.7]
[0, 0.1, 0.2, 0.7]
[0, 0.1, 0, 0.8999999999999999]
[0, 0.9999999999999999, 0, 0]

For more info regarding the precision of floating point numbers in python, please refer to this answer.

Numpy Solution

import numpy as np

weights = [0.3,0.1,0.2,0.4]
temp_list = [None,1,None,None]

weights = np.array(weights)
max_weight_index = np.argmax(weights)

for i, tmp_element in enumerate(temp_list):

    if tmp_element is None:
        if i == max_weight_index:
            current_max = weights[i]
            weights[i] = 0
            max_weight_index = np.argmax(weights)
            weights[max_weight_index] += current_max
        else:
            weights[max_weight_index] += weights[i]
            weights[i] = 0
    print(weights)

Output

[ 0.   0.1  0.2  0.7]
[ 0.   0.1  0.2  0.7]
[ 0.   0.1  0.   0.9]
[ 0.  1.  0.  0.]

Ganesh Tata
  • 1,118
  • 8
  • 26
  • 1
    Thanks! This was what I was looking for. You mentioned that you're assuming there are no duplicates in the weights array. In cases where the weights are the exact same (for ex. [0.3,0.1,0.1,0.5]; notice two values have weights 0.1). Would this cause any issue? – mathgeek Nov 10 '20 at 05:08
  • I was wondering if two indices with the max weight could cause some problems. Hence I mentioned the assumption. Would need to check this scenario. – Ganesh Tata Nov 10 '20 at 05:29
  • If it was to shift the weights evenly, How would that work? Say [None,1, 1, 1], split the 0.3 so that each of the other weights gets 0.1; which would end up as [0.0,0.2,0.3,0.5] – mathgeek Nov 10 '20 at 19:44
  • In the *pure python* approach, you would have to first perform (0.3 / len(arr) - 1) to get 0.1, iterate over all the array elements ( skipping 0.3 ) and update them with 0.1. A numpy approach might be faster, and you can give it a shot to see if you are able to speed-up the computation. – Ganesh Tata Nov 11 '20 at 03:29