使用随机模块python

时间:2017-01-31 22:57:21

标签: python random shuffle

我正在使用两个架构程序,带有可视化编程插件(适用于Rhino的Grasshopper和适用于Revit的Dynamo - 适用于那些知道/感兴趣的人)

Grasshopper包含一个叫做“抖动”的函数。这将改变一个列表,但它有一个从0.0到1.0的输入控制着混乱的程度 - 0.0导致没有改组1.0产生一个完整的洗牌。

第二个程序(Dynamo)不包含此功能。它包含一个shuffle模块(包含一个种子值),但它是一个完整的随机shuffle。

最终目标是生产一系列实心和玻璃面板,但产生轻微的随机效果(但避免固体和玻璃元素的大块 - 因此我想要一个&#34;轻微洗牌&#34;)< / p>

我编写了一个代码,用于计算所需的glazed(True)和solid(False)值,然后根据项目数和指定百分比均匀分配True和False值。

我已经检查了随机模块参考,但是我并不熟悉所描述的各种发行版。

如果现有功能可以实现这一点,有人可以帮助或指出我正确的方向。

(我通过交替添加True False来略微欺骗以构成列表中正确数量的项目 - list3是最终列表,list2包含重复的真实falses模块)

非常感谢

import math
import random

percent = 30
items = 42

def remainder():
    remain = items % len(list2)

    list3.append(True)
    remain -= 1

    while remain > 0 :
        list3.append(False)
        remain -= 1

    return list3

#find module of repeating True and False values
list1 = ([True] + [False] * int((100/percent)-1))

#multiply this list to nearest multiple based on len(items)
list2 = list1 * int(items/(100/percent))

# make a copy of list2
list3 = list2[:]

#add alternating true and false to match len(list3) to len(items)
remainder()

#an example of a completely shuffled list - which is not desired 
shuffled = random.sample(list3, k = len(list3))

4 个答案:

答案 0 :(得分:4)

这是一种基于this paper的方法,它证明了通过使用相邻项目的交换来加扰列表所需的混合时间的结果

from random import choice
from math import log

def jitter(items,percent):
    n = len(items)
    m = (n**2 * log(n))
    items = items[:]
    indices = list(range(n-1))
    for i in range(int(percent*m)):
        j = choice(indices)
        items[j],items[j+1] = items[j+1],items[j]
    return items

测试,每行显示jitter的结果,其中不同百分比应用于同一列表:

ls = list(('0'*20 + '1'*20)*2)

for i in range(11):
    p = i/10.0
    print(''.join(jitter(ls,p)))

典型输出:

00000000000000000000111111111111111111110000000000000000000011111111111111111111
00000000000000111100001101111011011111001010000100010001101000110110111111111111
00000000100100000101111110000110111101000001110001101001010101100011111111111110
00000001010010011011000100111010101100001111011100100000111010110111011001011111
00100001100000001101010000011010011011111011001100000111011011111011010101011101
00000000011101000110000110000010011001010110011111100100111101111011101100111110
00110000000001011001000010110011111101001111001001100101010011010111111011101100
01101100000100100110000011011000001101111111010100000100000110111011110011011111
01100010110100010100010100011000000001000101100011111011111011111011010100011111
10011100101000100010001100100000100111001111011011000100101101101010101101011111
10000000001000111101101011000011010010110011010101110011010100101101011110101110

我不确定上述原则是多么有原则,但这似乎是一个合理的起点。

答案 1 :(得分:3)

对于什么&#34;洗牌程度没有明确的定义&#34; ( d )表示,因此您需要选择一个。一种选择是:&#34;剩下未洗过的项目的比例是( 1-d )&#34;。

您可以将其实现为:

  1. 制作索引列表
  2. 删除(1-d)* N
  3. 随意洗牌
  4. 重新插入已删除的
  5. 使用这些来查找原始数据中的值
  6. def partial_shuffle(x, d):
        """
        x: data to shuffle
        d: fraction of data to leave unshuffled
        """
        n = len(x)
        dn = int(d*n)
        indices = list(range(n))
        random.shuffle(indices)
        ind_fixed, ind_shuff = indices[dn:], indices[:dn]
    
        # copy across the fixed values
        result = x[:]
    
        # shuffle the shuffled values
        for src, dest in zip(ind_shuff, sorted(ind_shuff)):
            result[dest] = x[src]
    
        return result
    

答案 2 :(得分:1)

您所指的其他算法可能正在使用Fisher-Yates随机播放。

这个 O(n) shuffle从数组的第一个元素开始,用一个随机的更高元素交换它,然后用随机的更高元素交换第二个元素,依此类推。

当然,在你到达某个分数[0,1]的最后一个元素之前停止这个shuffle会产生一个部分随机化的数组,就像你想要的那样。

不幸的是,前面提到的效果是所有“随机性”都在阵列的一侧建立。

因此,制作一个数组索引列表,将这些索引完全混洗,然后使用索引作为Fisher-Yates算法的输入,对原始数组进行部分排序。

答案 3 :(得分:0)

我相信我找到了一种更通用、更强大、更一致的方法来实现这种“可调整的洗牌”技术。

import random
import numpy as np


def acc_shuffle(lis, sr, array=False, exc=None):  # "sr" = shuffling rate
    if type(lis) != list:  # Make it compatible with shuffling (mxn) numpy.ndarrays
        arr = lis
        shape = arr.shape
        lis = list(arr.reshape(-1))
    lis = lis[:]  # Done, such that any changes applied on "lis" wont affect original input list "x"
    indices = list(range(len(lis)))

    if exc is not None:  # Exclude any indices if necessary
        for ele in sorted(exc, reverse=True):
            del indices[ele] 

    shuff_range = int(sr * len(lis) / 2)  # How much to shuffle (depends on shuffling rate)
    if shuff_range < 1:
        shuff_range = 1  # "At least one shuffle (swap 2 elements)"

    for _ in range(shuff_range):
        i = random.choice(indices)
        indices.remove(i)  # You can opt not to remove the indices for more flexibility
        j = random.choice(indices)
        indices.remove(j)
        temp = lis[i]
        lis[i] = lis[j]
        lis[j] = temp

    if array is True:
        return np.array(lis).reshape(shape)
    return lis