在Python中高效的列表构建

时间:2018-03-23 19:44:33

标签: python python-2.7 performance random processing-efficiency

作为一个长期的Matlab用户,每当我在循环中构建一个包含多个元素的列表/数组/任何内容时,我都习惯于小心谨慎,这样每次都会改变大小,因为这样会减慢速度。

当我自学Python 2.7时,我想知道这样的规则是否适用于字符串。我确切地知道我希望我的字符串有多长,并且我有一个特定的字符列表,我想要构建它,但我希望它是随机的。我到目前为止写的我最喜欢的代码是:

def BernSeq(length,freq):
"""Create a Bernoulli sequence - a random bitstring - of the given length 
and with the given frequency of 1s"""
    seq = '0'*length
    for ii in range(length):
        num = np.random.rand(1)
        if num < freq:
            cha = '1'
            seq = seq[:ii] + cha + seq[ii+1:]

我将其称为BernSeq(20,.25),我得到输出'10001000000001011101'

我已经尝试了seq[ii] = '1',但是,用IPython的话来说,TypeError: 'str' object does not support item assignment

所以,我这样做是最恐怖的方式,还是有一些我尚未见过的手法 - 可能是一个随机的字符串或列表生成器,我可以直接给出一个我希望它的字符列表随机选择,我希望每种可能性的概率,以及我希望这个字符串或列表有多长?

(我已经看过关于随机字符串的other questions,但是虽然它们确实解决了如何使它成为正确的长度,但它们通常会尝试生成密码,所有ASCII字符同样可能。这不是我的意思。想。)

4 个答案:

答案 0 :(得分:3)

有几种方法可以做到。

首先,您可以从头开始创建正确的元素:

seq = "".join("1" if np.random.rand(1) < freq else "0" for _ in range(length))

但要问的第一个问题是:你想要什么作为输出?你需要它是一个字符串吗?也许你对布尔列表没问题?

然后

seq = [np.random.rand(1) < freq for _ in range(length)]

也足够了。

答案 1 :(得分:0)

您可以定义一个根据您的分发首选项生成随机字母的函数,然后根据您喜欢的次数执行它。

import random
def my_letter():
   a = random.randint(1,10)
   if a > 5:
   return "a"
   else:
   return "b"

然后根据您的长度偏好:

my_str = ""
for x in range(length):
   my_str += my_letter()

答案 2 :(得分:0)

python中的字符串是不可变的

In [1]: a = '1' * 5

In [2]: a
Out[2]: '11111'

In [3]: type(a)
Out[3]: str

In [4]: a[2] = 'c'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-69ed835eb212> in <module>()
----> 1 a[2] = 'c'

TypeError: 'str' object does not support item assignment

In [5]: b = [1] * 5

In [6]: b
Out[6]: [1, 1, 1, 1, 1]

调整代码以改为使用int列表。 (最小修正,不修复风格或优化其他事情)

def BernSeq(length,freq):
"""Create a Bernoulli sequence - a random bitstring - of the given length 
and with the given frequency of 1s"""
    seq = [0] * length
    for ii in range(length):
        num = np.random.rand(1)
        if num < freq:
            cha = 1
            seq.append(cha)

答案 3 :(得分:0)

NumPy中有二项分布,np.random.binomial。以您想要的频率从中采样然后将字符串表示连接在一起将比自己重新创建更快。

def bernouilli_str(N, one_freq):
    return ''.join(np.random.binomial(1, one_freq, N).astype('U1'))

<强>基准

In [112]: %timeit ''.join(np.random.binomial(1, 0.75, 10**6).astype('U1'))
637 ms ± 5.75 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [113]: %timeit "".join("1" if np.random.rand(1) < 0.75 else "0" for _ in range(10**6))
1.69 s ± 11 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)