Reputation: 133
I have a list with these normalized values
list_a = [0.25, 0.25, 0.25, 0.25]
Now I want to change the value of one entry to another number, let's say 0.75
. This number is fixed and shouldn't change anymore.
list_a_changed = [0.25, 0.25, 0.75, 0.25]
To still make sure the sum of all the values in the list add up to 1
, the remaining values need to be 0.0833
. So my list will have to be:
list_a_normalized = [0.083, 0.083, 0.75, 0.083]
This is easy enough to figure out if all values share the same percentage in the initial list. I can just do 1 - 0.75 = 0.25
, and divide that 0.25
between remaining numbers since they all hold the same percentage of the total sum.
value_change = 0.75
remaining_value = 1 - value_change
divided_remaining_value = remaining_value / (len(list_a_changed) - 1)
list_a_normalized = [divided_remaining_value, divided_remaining_value, value_change, divided_remaining_value ]
But how would you do it if the original list was something like:
list_b = [0.25, 0.45, 0.20, 0.10]
And I change one value to 0.05
list_b_changed = [0.25, 0.45, 0.05, 0.10]
How would you calculate what the values of the other numbers will have to be so they each hold the appropriate portion of the remaining 0.95
?
Upvotes: 0
Views: 821
Reputation: 54148
You may
remaining
def normalize(values, index_not_change):
remaining = 1 - values[index_not_change]
total_except_remaining = sum(values) - values[index_not_change]
return [(value * remaining / total_except_remaining if idx != index_not_change else value)
for idx, value in enumerate(values)]
print(normalize([0.25, 0.25, 0.75, 0.25], 2)) # [0.0833333333, 0.0833333333, 0.75, 0.0833333333]
print(normalize([0.25, 0.45, 0.05, 0.10], 2)) # [0.296875, 0.534375, 0.05, 0.11875000000000001]
To understand the total_except_remaining
purpose, without it it'd have been that
normalize([0.25, 0.25, 0.75, 0.25], 2) -> [0.0625, 0.0625, 0.75, 0.0625]
because you'd have compute a quarter of the remaining (0.25
) but adding the fact that the relative sum was 0.75
and not 1, you update to their real proportion
You can put the modification in the same method too
def normalize(values, position, new_value):
values[position] = new_value
remaining = 1 - new_value
total_except_remaining = sum(values) - new_value
return [(value * remaining / total_except_remaining if idx != position else value)
for idx, value in enumerate(values)]
print(normalize([0.25, 0.25, 0.25, 0.25], 2, 0.75))
Upvotes: 1
Reputation: 6298
Use change_normalized
item and keep the list normalized:
The re_normalize
keeps the list normalized by multiplying with the correct factor (which is the ratio between one and the sum without the changed item):
def change_normalized(lst, index, value):
def touch(lst, index, value):
lst[index] = value
def re_normalize(lst, index, value):
multiply_factor = (1 - value) / (sum(lst) - value)
for j in range(len(lst)):
if i == j:
continue
lst[j] *= multiply_factor
touch(lst, i, value)
re_normalize(lst, i, value)
i = 2
value = 0.05
list_b = [0.25, 0.45, 0.20, 0.10]
# Change item at index to value and keep list normalized
change_normalized(list_b, i, value)
# 1.0
print(sum(list_b))
This code can be shrinked to:
def change_normalized(lst, index, value):
lst[index] = value
multiply_factor = (1 - value) / (sum(lst) - value)
lst[:] = [multiply_factor * x if i != j else x for j, x in enumerate(lst)
Upvotes: 1