Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 指定大小的随机子集的Numpy列表_Python_Arrays_Numpy_Random - Fatal编程技术网

Python 指定大小的随机子集的Numpy列表

Python 指定大小的随机子集的Numpy列表,python,arrays,numpy,random,Python,Arrays,Numpy,Random,我想计算一个数组的随机子集列表,其中子集中的顺序是随机的,它们各自子集中的每个元素都是唯一的,我想高效地这样做(在时间和空间方面) 例如,带有一些参数k=3和n=5的数组[1,2,3,4,5]应该生成一个矩阵 [[4,3,1], [1,2,5], [2,4,5], [3,2,5], [2,3,1]] i、 例如,我们从数组中获得包含k=3randomunique元素的n=5列表 我希望这是尽可能快,而不创建一个庞大的查找表的可能组合,因为时间和空间都是至关重要的 我试着用numpy.r

我想计算一个数组的随机子集列表,其中子集中的顺序是随机的,它们各自子集中的每个元素都是唯一的,我想高效地这样做(在时间和空间方面)

例如,带有一些参数
k=3
n=5
的数组
[1,2,3,4,5]
应该生成一个矩阵

[[4,3,1],
 [1,2,5],
 [2,4,5],
 [3,2,5],
 [2,3,1]]
i、 例如,我们从数组中获得包含
k=3
randomunique元素的
n=5
列表

我希望这是尽可能快,而不创建一个庞大的查找表的可能组合,因为时间和空间都是至关重要的

我试着用
numpy.random.choice(array,n*k).重塑((n,k))
来实现这一点,除了唯一性部分之外,这几乎是我想要的。我决定了以下几点

subsets = numpy.zeros(n).reshape((n,1))
subsets = numpy.apply_along_axis(lambda x: numpy.random.choice(array, k, replace=False),1, subsets)
然而,由于这不是纯粹的numpy,这是缓慢的。对我的申请来说太慢了。是否有一些方法可以改进运行时,或者使用纯numpy命令来实现这一点


任何帮助都将不胜感激

假设
k
将比
n
小得多,您可以自己实施采样而无需更换:

N = [1, 2, 3, 4, 5]
k = 3
n = 5

arr = np.array([N] * n)

arr
array([[1, 2, 3, 4, 5],
       [1, 2, 3, 4, 5],
       [1, 2, 3, 4, 5],
       [1, 2, 3, 4, 5],
       [1, 2, 3, 4, 5]])

[np.random.shuffle(i) for i in arr]

arr
array([[3, 5, 1, 2, 4],
       [5, 1, 3, 2, 4],
       [3, 5, 2, 4, 1],
       [4, 5, 1, 2, 3],
       [1, 5, 3, 2, 4]])

arr[:, :3]
array([[3, 5, 1],
       [5, 1, 3],
       [3, 5, 2],
       [4, 5, 1],
       [1, 5, 3]])
idx = np.random.randint([5,4,3], size=[5,3])
idx[:,2:] += idx[:,2:] >= idx[:,1,None]
idx[:,1:] += idx[:,1:] >= idx[:,0,None]
np.array([1,2,3,4,5])[arr]
将其放入函数中,可以是:

def sample_noreplace(arr, n, k):
    assert k <= len(arr)
    idx = np.random.randint(len(arr) - np.arange(k), size=[n, k])
    for i in range(k-1, 0, -1):
        idx[:,i:] += idx[:,i:] >= idx[:,i-1,None]
    return np.array(arr)[idx]
这给了我:
{0:600288,1:599656,2:600494,3:599233,4:600329}
,看起来很统一。接下来,我们可以在每个位置内检查:

out = np.zeros([3, 5])
for i in range(3):
    n, c = np.unique(arr[:,i], return_counts=True)
    out[i, n] = c
这给了我一张桌子,看起来像:

array([[199936., 199701., 200106., 199843., 200414.],
       [200227., 200044., 200345., 199897., 199487.],
       [200125., 199911., 200043., 199493., 200428.]])

这看起来也很一致。

考虑到你的数字,一个好的方法是简单地用替换画出,然后用重复画出

以下是从不同大小的阵列中提取5000个10%或10%(以较小者为准)样本的时间安排。pp_overdraw提取过多样本并丢弃,pp_fillin提取到准确的数量,重新绘制坏样本,直到没有剩余样本。pythran是一个编译解决方案。因为OP要求的是纯numpy,所以这里仅供参考

代码:

文件


输出矩阵中的第二个数组具有非唯一成员
1
[1,5,1]
中,如果N较大,k较小,则此新版本在空间方面可能非常昂贵。这不是一个很好的解决方案,但使用map更快<代码>np.数组(列表(映射(lambda x:np.random.choice(数组,3,replace=False),范围(5))。您期望的大小是多少?
n
k
以及输入数组?@PaulPanzer目前,len(数组)大约为500,n在1000到5000之间,k在2到5000之间10@PaulPanzer说得好,我也应该问这个问题!请注意,如果
k
远低于
sqrt(len(array))
,则使用不同的算法会很有用,因为拾取重复的几率相对较低。如需了解sqrt的来源,请参阅from@SamMason如果您感兴趣,我已经为一个解决方案添加了代码,该解决方案对任何参数都很有效(
O(len(array)+nk)
),但依赖Pyran(numba也可以)提高速度,因为它是循环的。--顺便说一句,你认为你的算法适用于哪种制度?它在k中是二次的,所以它也必须在kvery干净溶液中的某个地方,谢谢。我也很欣赏概率分析!
array([[199936., 199701., 200106., 199843., 200414.],
       [200227., 200044., 200345., 199897., 199487.],
       [200125., 199911., 200043., 199493., 200428.]])
import pyflip
import numpy as np
from simple_benchmark import BenchmarkBuilder, MultiArgument

B = BenchmarkBuilder()

@B.add_function()
def pythran(A,k,n):
    assert len(A) >= k
    if A.dtype not in (float,int) or A.ndim > 1:
        return A[pyflip.without_repl(np.arange(len(A)),k,n)]
    else:
        return pyflip.without_repl(A,k,n)

from scipy import stats

@B.add_function()
def pp_overdraw(A,k,n):
    N = len(A)
    p = np.linspace(1-(k-1)/N,1-1/N,k-1).prod()
    nn = int(n/p + 4*np.sqrt(n-n*p)) + 1
    out = np.random.randint(0,N,(nn,k))
    os = np.sort(out,1)
    valid = (os[:,:-1] != os[:,1:]).all(1)
    validx, = valid.nonzero()
    while len(validx)<n: # very unlikely
        replace = np.random.randint(0,N,(nn-len(validx),k))
        rs = np.sort(replace,1)
        rvalid = (rs[:,:-1] != rs[:,1:]).all(1)
        out[~valid,:] = replace
        valid[~valid] = rvalid
        validx, = valid.nonzero()
    return A[out[validx[:n]]]

@B.add_function()
def pp_fillin(A,k,n):
    N = len(A)
    out = np.random.randint(0,N,(n,k))
    os = np.sort(out,1)
    valid = (os[:,:-1] != os[:,1:]).all(1)
    validx, = valid.nonzero()
    while len(validx)<n:
        replace = np.random.randint(0,N,(n-len(validx),k))
        rs = np.sort(replace,1)
        rvalid = (rs[:,:-1] != rs[:,1:]).all(1)
        out[~valid,:] = replace
        valid[~valid] = rvalid
        validx, = valid.nonzero()
    return A[out]


@B.add_function()
def OP(A,k,n):
    subsets = np.zeros(n).reshape((n,1))
    subsets = np.apply_along_axis(lambda x: np.random.choice(A, k, replace=False),1, subsets)

@B.add_function()
def Sam_Mason(A,k,n):
    assert k <= len(A)
    idx = np.random.randint(len(A) - np.arange(k), size=[n, k])
    for i in range(k-1, 0, -1):
        idx[:,i:] += idx[:,i:] >= idx[:,i-1,None]
    return np.array(A)[idx]

@B.add_arguments('array size')
def argument_provider():
    for exp in range(4, 15):
        sz = 2**exp
        A = np.arange(sz)
        yield sz, MultiArgument([A,min(10,sz//10+1),5000])

r = B.run()
r.plot()

import pylab
pylab.savefig('norepl.png')
pythran -O3 pyflip.py
import numpy as np

#pythran export without_repl(int[:],int,int)
#pythran export without_repl(float[:],int,int)

def without_repl(A,k,n):
    N = A.size
    out = np.empty((n,k),A.dtype)
    A = A.copy()
    for i in range(n):
        for j in range(k):
            l = np.random.randint(j,N)
            out[i,j] = A[l]
            A[l] = A[j]
            A[j] = out[i,j]
    return out