randomly sort a list with bias

强颜欢笑 提交于 2021-01-28 19:11:19

问题


I have a list as follows:

i = [
        {'id': '1', 'P': 0.5},
        {'id': '2', 'P': 0.4},
        {'id': '3', 'P': 0.8},
        ...
        {'id': 'x', 'P': P(x)}
    ]

When I do the following:

i.sort(key=lambda x: x['P'], reverse=True)

The list gets sorted based on P where the element with the largest P is in front. but what if I want to make it seem randomized so that even a element with a small P value (with very small probability) can be the first item in the list?
Is it possible to implement that using the sort() function or do I have to write my own?


回答1:


As I alluded to in a comment, you could sort with a level of random bias by sampling a bias factor from a standard normal distribution. You can then add this bias (which is symmetrical either side of zero) to your P value.

import numpy as np

#Give some control over the level of rearrangement - larger equals more rearrangement
bias_factor = 0.5

i.sort(key=lambda x: x['P'] + np.random.randn()*bias_factor, reverse=True)

Or if you just want to use the standard library:

from random import gauss

#Give some control over the level of rearrangement - larger equals more rearrangement
sigma = 0.5

i.sort(key=lambda x: x['P'] + gauss(0, sigma), reverse=True)



回答2:


According to my understanding, you want to have the list sorted but still want some some randomness. A list cannot be sorted as well as random at the same time. The nearest can be achieved via something like

i.sort(key=lambda x: x['P']*random.triangular(0.6, 1.4), reverse=True)

This while ensuring that the order is not exactly random as well as not sorted in a similar way.

The values 0.6 and 1.4 can be changed depending on the deviation you want.




回答3:


Here is my take on it: Suppose that item 1 has similarity score 0.3 and item 2 has similarity score 0.4. Then, it seems reasonable that when choosing between these two items, item 1 should be before item 2 with probability 0.3 / (0.3 + 0.4). This way the higher-scored item is usually before the lower-scored. The following functions implement a variant of merge-sort which incorporates this idea:

import random

def pick(a,b,key = None):
    ka = key(a) if key else a
    kb = key(b) if key else b
    if ka+kb == 0:
        return random.int(0,1)
    else:
        p = ka/(ka+kb)
        return 0 if random.random() <= p else 1

def randMerge(xs,ys,key = None):
    merged = []
    i = j = 0
    while i < len(xs) and j < len(ys):
        k = pick(xs[i],ys[j],key)
        if k == 0:
            merged.append(xs[i])
            i += 1
        else:
            merged.append(ys[j])
            j += 1
    if i == len(xs):
        merged.extend(ys[j:])
    else:
        merged.extend(xs[i:])
    return merged

def randSort(items,key = None):
    if len(items) < 2:
        return items
    else:
        n = len(items)//2
        xs = items[:n]
        ys = items[n:]
        return randMerge(randSort(xs,key),randSort(ys,key),key)

For testing:

i = [
        {'id': '1', 'P': 0.5},
        {'id': '2', 'P': 0.4},
        {'id': '3', 'P': 0.8},
        {'id': '4', 'P': 0.9}
    ]

For example:

>>> for j in range(5): print(randSort(i,key = lambda x: x['P']))

[{'P': 0.5, 'id': '1'}, {'P': 0.9, 'id': '4'}, {'P': 0.8, 'id': '3'}, {'P': 0.4, 'id': '2'}]
[{'P': 0.8, 'id': '3'}, {'P': 0.5, 'id': '1'}, {'P': 0.9, 'id': '4'}, {'P': 0.4, 'id': '2'}]
[{'P': 0.9, 'id': '4'}, {'P': 0.5, 'id': '1'}, {'P': 0.8, 'id': '3'}, {'P': 0.4, 'id': '2'}]
[{'P': 0.5, 'id': '1'}, {'P': 0.8, 'id': '3'}, {'P': 0.9, 'id': '4'}, {'P': 0.4, 'id': '2'}]
[{'P': 0.8, 'id': '3'}, {'P': 0.4, 'id': '2'}, {'P': 0.9, 'id': '4'}, {'P': 0.5, 'id': '1'}]


来源:https://stackoverflow.com/questions/38455356/randomly-sort-a-list-with-bias

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!