Python中的条件“at-least”,具有伪随机性

时间:2018-01-19 16:00:24

标签: python pandas numpy

我想做伪随机化,意思是通过尊重某些规则来随机化。

想象一下以下DataFrame:

ColX 
 N
 N
 N
 N
 N
 N
 N
 N
 D
 D
 D

N代表中立,D代表偏差。在拥有一个Deviant之前,我想至少有两个中立(但是在deviants之间可以有更多的中立)并且一切都必须是随机顺序。

结果:ColX应该看起来像

ColX
 N
 N
 D
 N
 N
 N
 D
 N
 N
 N
 D

我想知道我可以在python(pandas或其他包中的函数)或R(允许这个的库中的任何函数)中使用哪种函数?)

提前谢谢。

2 个答案:

答案 0 :(得分:3)

这是使用NumPy执行此操作的一种方法,itertools提供了一个很小的循环加速:

from itertools import repeat
import numpy as np


def gen_chunk(high=5):
    """Example: gen_chunk(high=6) --> array(['n', 'n', 'n', 'd']"""
    return np.append(np.repeat('n', np.random.randint(low=2, high=high)), 'd')


def gen_series(chunks=3, high=5):
    return np.concatenate([gen_chunk(high=high) for _ in repeat(None, 3)])


df = pd.DataFrame(gen_series())

操作实例:

你可以独立生成2个或更多个N的每个“块”,然后是1个D.这就是get_chunk()上面所做的。在这种情况下,它会生成N的NumPy数组,后跟1 D,其中N的数是2和high参数之间的随机整数。

然后在gen_series()中,您可以构建单独的块(其中3个是默认值)并将它们连接成一个1d数组。

<强>更新

以上在每个chunk的生成中使用常量high参数。也许这不符合您正在寻找的psueorandom的定义。要在每个块生成中使用不同的high,您可以执行以下操作:

def gen_series(chunks, max_high):
    """Use a randomly selected `high` value for each chunk."""
    highs = np.random.randint(low=3, high=max_high, size=chunks)
    return np.concatenate([gen_chunk(high=high) for high in highs])

任何一种构造都应该相当快:

%timeit gen_series(chunks=1000, high=10)
# 36.9 µs ± 1.93 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

答案 1 :(得分:1)

这是&#34;正确&#34;这样做的方式。从某种意义上讲,每个法律组合同样可能是正确的。缺点是它比@BodSolomon的价格贵一点:

>>> def deviant_sep(N_D, N_N):
...     Didx = np.random.choice(N_N-N_D, N_D, replace=False)
...     out = np.zeros((N_N + N_D,), bool)
...     out[Didx] = True
...     Didx = np.flatnonzero(out[:N_N-N_D])
...     out[Didx] = False
...     out[Didx + np.arange(2, 2*N_D+2, 2)] = True
...     return np.array(['N', 'D'])[out.view(np.int8)]
... 
>>> deviant_sep(3, 8)
array(['N', 'N', 'D', 'N', 'N', 'N', 'N', 'D', 'N', 'N', 'D'],
      dtype='<U1')
>>> deviant_sep(3, 8)
array(['N', 'N', 'D', 'N', 'N', 'N', 'N', 'D', 'N', 'N', 'D'],
      dtype='<U1')
>>> deviant_sep(3, 8)
array(['N', 'N', 'D', 'N', 'N', 'N', 'D', 'N', 'N', 'D', 'N'],
      dtype='<U1')
>>>
>>> from timeit import repeat
>>> repeat('deviant_sep(1000, 8000)', globals=globals(), number=1000)
[0.2079479000531137, 0.20392047404311597, 0.20519483496900648]

解释:我怀疑是什么让这个缓慢是numpy的choice没有替换函数,我认为会产生一个完整的排列,然后截断它。

该方法的工作原理如下:我们可以将nD DnN N s的合法模式映射到nD {{1}的模式} s和D nN - 2 nD s通过在每个N之前移除2 N s,相反,通过插入2 D将后一种模式转换为合法模式每个N之前的s。这张地图是1比1。而无约束的模式我们知道如何以相同的概率绘制。因此,我们会这样做,然后通过在每个D之前插入2 N来映射到合法模式。