【问题标题】:How do I sort a list probabilistically based on properties of their elements?如何根据元素的属性对列表进行概率排序?
【发布时间】:2020-10-19 09:40:21
【问题描述】:

考虑这个User 对象示例:

import numpy as np


class User:
    def __init__(self, name, rating, actual_rating):
        self.name: str = name
        self.rating: int = rating

        # Actual States
        self.actual_rating: int = actual_rating

users = []
for actual_rating in np.random.binomial(10000, 0.157, 1000):
    users.append(
        User(str(random()), 1500, actual_rating)
    )


# Sorting Users Randomly
sorted_users = []

我如何对这个users 列表进行排序,以便对象在sorted_users 中的索引较低的可能性取决于actual_rating 较高。例如,随机的User("0.5465454", 1500, 1678)User("0.7689989", 1500, 1400) 更有可能被排序到sorted_users 列表的索引0。

如果可能的话,有没有一种简洁易读的方法来做到这一点?

【问题讨论】:

  • 你可以使用sorted_users = sorted(users, key=lambda x: x.actual_rating)
  • 我似乎无法弄清楚使用什么函数来根据概率对其进行排序。是否有一个 numpy 函数可以做到这一点?
  • 听起来您想将十进制值映射到某种概率分布,然后根据值在分布中的位置进行排序?还是只是您希望排序有时会起作用,有时会失败,具体取决于某种概率?
  • 第一次如何为每个用户生成一个来自高斯分布的随机数,平均值为actual_rating?然后你按照这个随机数排序,而不是直接按照actual_rating排序。

标签: python python-3.x sorting


【解决方案1】:

为每个用户生成一个随机值,然后根据这个值排序

如何进行第一遍,为每个用户生成一个来自高斯分布的随机数,平均为实际评级?那你就按照这个随机数排序,而不是直接按照actual_rating排序。

stddev = 1.0   # the larger this number, the more shuffled the list - the smaller, the more sorted the list

sorted_users = sorted(users, key=lambda u:np.random.normal(u.actual_rating, stddev))

注意参数stddev,您可以根据需要进行调整。这个参数越高,最后打乱的列表越多。

对列表进行排序,然后轻轻洗牌

灵感来自How to lightly shuffle a list in python?

将列表按照actual_rating排序,然后轻轻洗牌。

sorted_users = sorted(users, key=lambda u:u.actual_rating)

nb_passes = 3
proba_swap = 0.25

for k in range(nb_passes):
  for i in range(k%2, len(sorted_users) - 1, 2):
    if random() < proba_swap:
      sorted_users[i], sorted_users[i+1] = sorted_users[i+1], sorted_users[i]

注意nb_passes(正整数)和proba_swap(介于0.0 和1.0 之间)这两个参数,您可以调整它们以更好地满足您的需求。

除了使用固定参数proba_swap,您还可以根据两个用户的实际评分接近程度制定一个交换概率公式,例如def proba_swap(r1,r2): return math.exp(-a*(r1-r2)**2)/2.0 用于某些正参数a

或者:

sorted_users = sorted(users, key=lambda u:u.actual_rating)

nb_swaps = int(1.5 * len(sorted_users))  # parameter to experiment with

for i in random.choices(range(len(sorted_users)-1), k=nb_swaps):
    sorted_users[i], sorted_users[i+1] = sorted_users[i+1], sorted_users[i]

另见

搜索了一下,发现了这个类似的问题:

【讨论】:

  • @superbrain 谢谢!在写评论之前,我实际上搜索了 sort/sorted 的文档,但找不到此信息。现在我想起来了,我应该测试一下使用键 def k(x): print(x); return x 对一个小列表进行排序。
  • @superbrain 谢谢,我编辑考虑到你的批评。
  • 非常好的改组修复!
  • 嗯,虽然例如 nb_passes 为 1 且列表长度为奇数,但最后一个元素没有机会移动。所以我觉得比以前好多了,但还是有点不公平。
  • @superbrain 是的,我想随机选择使用 random.sample(range(len(sorted_users)-1), nb_swaps) 交换的元素会更有意义。
猜你喜欢
  • 2016-03-02
  • 2016-01-26
  • 1970-01-01
  • 1970-01-01
  • 2019-06-30
  • 1970-01-01
  • 1970-01-01
  • 2022-01-11
  • 2019-06-10
相关资源
最近更新 更多