如何在Python中生成随机数字对,包括一个条目相同的对,并排除两个条目相同的对?

Dav*_*ave 8 python random numpy

我正在使用Python并且正在使用numpy.我想生成一对随机数.我想排除对的重复结果,两个条目都是相同的数字,我想包括只有一个条目是相同数字的对.我试图使用

import numpy
numpy.random.choice(a,(m,n),replace=False) 
Run Code Online (Sandbox Code Playgroud)

对于它,但它完全排除任何具有相同条目的tupels,即

import numpy
numpy.random.choice(a=2,(m=2,n=1),replace=False) 
Run Code Online (Sandbox Code Playgroud)

只给我(1,0)和(0,1)而不是(1,1),(0,0),(1,0)和(0,1).

我想这样做是因为我想绘制一个随机元组的样本,其中包含大的a和大的n(如上所述),而不会获得完全相同的tupels.它也应该或多或少有效.有没有一种方法可以实现这一点?

Jam*_*lls 12

生成器随机唯一坐标:

from random import randint

def gencoordinates(m, n):
    seen = set()

    x, y = randint(m, n), randint(m, n)

    while True:
        seen.add((x, y))
        yield (x, y)
        x, y = randint(m, n), randint(m, n)
        while (x, y) in seen:
            x, y = randint(m, n), randint(m, n)
Run Code Online (Sandbox Code Playgroud)

输出:

>>> g = gencoordinates(1, 100)
>>> next(g)
(42, 98)
>>> next(g)
(9, 5)
>>> next(g)
(89, 29)
>>> next(g)
(67, 56)
>>> next(g)
(63, 65)
>>> next(g)
(92, 66)
>>> next(g)
(11, 46)
>>> next(g)
(68, 21)
>>> next(g)
(85, 6)
>>> next(g)
(95, 97)
>>> next(g)
(20, 6)
>>> next(g)
(20, 86)
Run Code Online (Sandbox Code Playgroud)

正如你所看到的巧合x,重复了一个坐标!


ali*_*i_m 6

假设您的xy坐标都是0到n之间的整数.对于小n,一个简单的方法可能是生成所有可能的xy坐标的集合np.mgrid,将其重新整形为(nx * ny, 2)数组,然后从中采样随机行:

nx, ny = 100, 200
xy = np.mgrid[:nx,:ny].reshape(2, -1).T
sample = xy.take(np.random.choice(xy.shape[0], 100, replace=False), axis=0)
Run Code Online (Sandbox Code Playgroud)

如果nx和/或ny非常大,则创建所有可能坐标的数组会变得昂贵,在这种情况下,使用生成器对象并跟踪以前使用的坐标可能会更好,如James的回答.


按照@morningsun的建议,另一种方法是从nx*ny索引集合中采样到平顶数组中,然后将它们直接转换为x,y坐标,这样可以避免构造整个nx*ny数组的可能x,y排列.

为了比较,这里是我对N维数组进行推广的原始方法的一个版本,以及使用新方法的版本:

def sample_comb1(dims, nsamp):
    perm = np.indices(dims).reshape(len(dims), -1).T
    idx = np.random.choice(perm.shape[0], nsamp, replace=False)
    return perm.take(idx, axis=0)

def sample_comb2(dims, nsamp):
    idx = np.random.choice(np.prod(dims), nsamp, replace=False)
    return np.vstack(np.unravel_index(idx, dims)).T
Run Code Online (Sandbox Code Playgroud)

在实践中没有太大的区别,但第二种方法的好处对于更大的阵列来说变得更加明显:

In [1]: %timeit sample_comb1((100, 200), 100)
100 loops, best of 3: 2.59 ms per loop

In [2]: %timeit sample_comb2((100, 200), 100)
100 loops, best of 3: 2.4 ms per loop

In [3]: %timeit sample_comb1((1000, 2000), 100)
1 loops, best of 3: 341 ms per loop

In [4]: %timeit sample_comb2((1000, 2000), 100)
1 loops, best of 3: 319 ms per loop
Run Code Online (Sandbox Code Playgroud)


如果您安装了scikit-learn,则sklearn.utils.random.sample_without_replacement使用Floyd的算法提供更快的方法来生成随机索引而无需替换:

from sklearn.utils.random import sample_without_replacement

def sample_comb3(dims, nsamp):
    idx = sample_without_replacement(np.prod(dims), nsamp)
    return np.vstack(np.unravel_index(idx, dims)).T

In [5]: %timeit sample_comb3((1000, 2000), 100)
The slowest run took 4.49 times longer than the fastest. This could mean that an
intermediate result is being cached 
10000 loops, best of 3: 53.2 µs per loop
Run Code Online (Sandbox Code Playgroud)