如何在Python中生成唯一随机浮点数列表

时间:2017-07-29 23:31:11

标签: python random distinct-values

我知道有很简单的方法可以生成唯一随机整数列表(例如random.sample(range(1, 100), 10))。

我想知道是否有一些更好的方法来生成一个独特的随机浮点数列表,除了编写一个像范围一样的函数,但接受这样的浮点数:

import random

def float_range(start, stop, step):
    vals = []
    i = 0
    current_val = start
    while current_val < stop:
        vals.append(current_val)
        i += 1
        current_val = start + i * step
    return vals

unique_floats = random.sample(float_range(0, 2, 0.2), 3)

有更好的方法吗?

8 个答案:

答案 0 :(得分:16)

答案

一种简单的方法是保留一组到目前为止看到的所有随机值,并重新选择是否有重复:

import random

def sample_floats(low, high, k=1):
    """ Return a k-length list of unique random floats
        in the range of low <= x <= high
    """
    result = []
    seen = set()
    for i in range(k):
        x = random.uniform(low, high)
        while x in seen:
            x = random.uniform(low, high)
        seen.add(x)
        result.append(x)
    return result

备注

  • 这项技术是Python实现 random.sample()的方法。

  • 该函数使用set来跟踪先前的选择,因为搜索列表时搜索集合为O(1)是O(n)。

  • 计算重复选择的概率等同于着名的Birthday Problem

  • random()给出2 ** 53个不同的可能值,重复次数很少。 平均而言,您可以预期重复浮动大约120,000,000个样本。

变体:限制浮动范围

如果人口仅限于一系列均匀间隔的浮点数,则可以直接使用random.sample()。唯一的要求是人口为Sequence

from __future__ import division
from collections import Sequence

class FRange(Sequence):
    """ Lazily evaluated floating point range of evenly spaced floats
        (inclusive at both ends)

        >>> list(FRange(low=10, high=20, num_points=5))
        [10.0, 12.5, 15.0, 17.5, 20.0]

    """
    def __init__(self, low, high, num_points):
        self.low = low
        self.high = high
        self.num_points = num_points

    def __len__(self):
        return self.num_points

    def __getitem__(self, index):
        if index < 0:
            index += len(self)
        if index < 0 or index >= len(self):
            raise IndexError('Out of range')
        p = index / (self.num_points - 1)
        return self.low * (1.0 - p) + self.high * p

这是一个选择10个随机样本而不是从41到20.0的41个均匀间隔浮点范围内进行替换的示例。

>>> import random
>>> random.sample(FRange(low=10.0, high=20.0, num_points=41), k=10)
[13.25, 12.0, 15.25, 18.5, 19.75, 12.25, 15.75, 18.75, 13.0, 17.75]

答案 1 :(得分:5)

您可以轻松使用整数列表生成浮点数:

int_list = random.sample(range(1, 100), 10)
float_list = [x/10 for x in int_list]

查看有关生成随机浮动的this Stack Overflow question

如果您希望它与python2一起使用,请添加以下导入:

from __future__ import division

答案 2 :(得分:5)

如果您需要保证唯一性,

可能更有效
  1. 立即在n中尝试生成[lo, hi]个随机浮点数。
  2. 如果唯一浮点数的长度不是n,请尝试生成但仍需要很多浮点数
  3. 并继续,直到你有足够的,而不是在Python级别循环中逐个生成它们来检查集合。

    如果你能负担得起NumPy 这样做np.random.uniform可能是一个巨大的加速。

    import numpy as np
    
    def gen_uniq_floats(lo, hi, n):
        out = np.empty(n)
        needed = n
        while needed != 0:
            arr = np.random.uniform(lo, hi, needed)
            uniqs = np.setdiff1d(np.unique(arr), out[:n-needed])
            out[n-needed: n-needed+uniqs.size] = uniqs
            needed -= uniqs.size
        np.random.shuffle(out)
        return out.tolist()
    

    如果你不能使用NumPy ,它仍然可能更高效,这取决于你的数据需要应用相同的检查dupe的概念,维持一套。

    def no_depend_gen_uniq_floats(lo, hi, n):
        seen = set()
        needed = n
        while needed != 0:
            uniqs = {random.uniform(lo, hi) for _ in range(needed)}
            seen.update(uniqs)
            needed -= len(uniqs)
        return list(seen)
    

    粗略基准

    极端堕落案例

    # Mitch's NumPy solution
    %timeit gen_uniq_floats(0, 2**-50, 1000)
    153 µs ± 3.71 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    
    # Mitch's Python-only solution
    %timeit no_depend_gen_uniq_floats(0, 2**-50, 1000)
    495 µs ± 43.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
    # Raymond Hettinger's solution (single number generation)
    %timeit sample_floats(0, 2**-50, 1000)
    618 µs ± 13 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

    更“正常”的情况(样本量较大)

    # Mitch's NumPy solution
    %timeit gen_uniq_floats(0, 1, 10**5)
    15.6 ms ± 1.12 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    # Mitch's Python-only solution
    %timeit no_depend_gen_uniq_floats(0, 1, 10**5)
    65.7 ms ± 2.31 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
    # Raymond Hettinger's solution (single number generation)
    %timeit sample_floats(0, 1, 10**5)
    78.8 ms ± 4.22 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

答案 3 :(得分:4)

您可以使用random.uniform(start, stop)。对于双精度浮动,如果您的设置很小,您可以相对确定它们是唯一的。如果你想生成大量的随机浮点数并且需要避免你有两次数字,请在将它们添加到列表之前进行检查。

但是,如果您正在寻找特定数字的选择,这不是解决方案。

答案 4 :(得分:1)

min_val=-5
max_val=15

numpy.random.random_sample(15)*(max_val-min_val) + min_val

或使用制服

numpy.random.uniform(min_val,max_val,size=15)

答案 5 :(得分:1)

如文档中所述,Python具有random.random()函数:

import random
random.random()

然后你会得到一个浮动值:0.672807098390448

所以你需要做的就是做一个for循环并打印出random.random():

>>> for i in range(10):
print(random.random())

答案 6 :(得分:0)

more_itertools有一个通用的numeric_range,它可以处理整数和浮点数。

class ViewController: UIViewController, UICollectionViewDataSource {
    let outerCollectionView = UICollectionView(frame: CGRect(x: 0, y: 40, width: 320, height: 250), collectionViewLayout: UICollectionViewFlowLayout())

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .green
        outerCollectionView.backgroundColor = .blue

        (outerCollectionView.collectionViewLayout as! UICollectionViewFlowLayout).itemSize = CGSize(width: 250, height: 300)
        outerCollectionView.register(OuterCell.self, forCellWithReuseIdentifier: "outerCell")
        view.addSubview(outerCollectionView)
        outerCollectionView.dataSource = self
    }

    func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 4 }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "outerCell", for: indexPath) as! OuterCell
        cell.outerIndex = indexPath.row + 1
        return cell
    }
}

class OuterCell: UICollectionViewCell, UICollectionViewDataSource {
    var innerCollectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: 300, height: 500), collectionViewLayout: UICollectionViewFlowLayout())
    var outerIndex: Int = 0

    override init(frame: CGRect) {
        super.init(frame: frame)
        (innerCollectionView.collectionViewLayout as! UICollectionViewFlowLayout).itemSize = CGSize(width: 140, height: 80)
        innerCollectionView.backgroundColor = .yellow
        innerCollectionView.register(InnerCell.self, forCellWithReuseIdentifier: "innerCell")
        contentView.addSubview(innerCollectionView)
        innerCollectionView.dataSource = self
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("unused")
    }
    func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 3 }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "innerCell", for: indexPath) as! InnerCell
        cell.label.text = "Cell \(outerIndex) / \(indexPath.item+1)"
        return cell
    }
}

class InnerCell: UICollectionViewCell {
    let label = UILabel(frame: CGRect(origin: .zero, size: CGSize(width: 100, height: 30)))

    override init(frame: CGRect) {
        super.init(frame: frame)
        contentView.backgroundColor = .white
        contentView.addSubview(label)
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("unused")
    }
}

答案 7 :(得分:0)

<块引用>

random.uniform 生成浮点值

import random

def get_random(low,high,length):
  lst = []
  while len(lst) < length:
    lst.append(random.uniform(low,high))
    lst = list(set(lst))
  return lst