使用随机模块python进行不同程度的洗牌

2024-06-09 18:56:46 发布

您现在位置:Python中文网/ 问答频道 /正文

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

Grasshopper包含一个名为“Jitter”的函数,它将洗牌一个列表,但是它有一个从0.0到1.0的输入,它控制洗牌的程度-0.0导致没有洗牌1.0产生一个完整的洗牌。在

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

最终的目标是生产一系列实心和釉面面板,但要产生一种轻微的随机效果(但要避免大量的固体和釉面元素聚集,因此我想要“轻洗牌”)

我写了一个代码,它将计算所需的上釉(真)和实(假)值的数量,然后根据指定的项目数和百分比均匀分布真值和假值。在

我已经检查了随机模块参考,但是我不熟悉所描述的各种分布。在

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

(我做了一个小小的欺骗,通过交替添加True-False来组成列表中正确的项数-list3是最终列表,list2包含True-False的重复模块)

非常感谢

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))

Tags: 模块ofto程序falsetrue列表for
3条回答

您所指的其他算法可能是在幕后使用Fisher-Yates洗牌。在

这种无序排列从数组的第一个元素开始,然后用一个随机的更高的元素交换它,然后用一个随机的更高的元素交换第二个元素,依此类推。在

当然,在到达某个分数[0,1]处的最后一个元素之前停止这种洗牌将得到一个部分随机数组,如您所愿。在

不幸的是,前面的结果是所有的“随机性”都建立在数组的一侧。在

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

这是一个基于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的结果,并将不同的百分比应用于同一个列表:

^{pr2}$

典型输出:

00000000000000000000111111111111111111110000000000000000000011111111111111111111
00000000000000111100001101111011011111001010000100010001101000110110111111111111
00000000100100000101111110000110111101000001110001101001010101100011111111111110
00000001010010011011000100111010101100001111011100100000111010110111011001011111
00100001100000001101010000011010011011111011001100000111011011111011010101011101
00000000011101000110000110000010011001010110011111100100111101111011101100111110
00110000000001011001000010110011111101001111001001100101010011010111111011101100
01101100000100100110000011011000001101111111010100000100000110111011110011011111
01100010110100010100010100011000000001000101100011111011111011111011010100011111
10011100101000100010001100100000100111001111011011000100101101101010101101011111
10000000001000111101101011000011010010110011010101110011010100101101011110101110

我不确定以上的原则是什么,但这似乎是一个合理的起点。在

对于“洗牌程度”(degree of shuffling)(d)的含义没有明确的定义,所以你需要选择一个。一个选项是:“剩余未缓冲的项目的比例是(1-d)”。在

您可以将其实现为:

  1. 编制索引列表
  2. 删除(1-d)*N个
  3. 洗牌剩下的
  4. 重新插入拆下的
  5. 使用这些可以从原始数据中查找值

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

相关问题 更多 >