Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.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 如何从笛卡尔积中取样而不重复_Python_Random_Cartesian Product - Fatal编程技术网

Python 如何从笛卡尔积中取样而不重复

Python 如何从笛卡尔积中取样而不重复,python,random,cartesian-product,Python,Random,Cartesian Product,我有一个集合列表,我希望从每个集合中抽取n个不同的样本,每个样本包含一个项目。 我不想让它按顺序排列,因此,例如,我将从第一组中获取所有必须具有相同项的样本。我也不想创造所有的笛卡尔产品,因为这在效率方面可能是不可能的。。。 你知道怎么做吗?甚至是类似于这种行为的东西 不起作用的示例: (prod for i, prod in zip(range(n), itertools.product(*list_of_sets))) 您可以使用randomlib中的sample: import rand

我有一个集合列表,我希望从每个集合中抽取n个不同的样本,每个样本包含一个项目。 我不想让它按顺序排列,因此,例如,我将从第一组中获取所有必须具有相同项的样本。我也不想创造所有的笛卡尔产品,因为这在效率方面可能是不可能的。。。 你知道怎么做吗?甚至是类似于这种行为的东西

不起作用的示例:

(prod for i, prod in zip(range(n), itertools.product(*list_of_sets)))

您可以使用
random
lib中的
sample

import random
[[random.sample(x,1)[0] for x in list_of_sets] for _ in range(n)]
例如:

list_of_sets = [{1,2,3}, {4,5,6}, {1,4,7}]
n = 3
可能的输出为:

[[2, 4, 7], [1, 4, 7], [1, 6, 1]]
编辑:

如果我们想避免重复,我们可以使用
while
循环并将结果收集到
集合
。此外,您可以检查
n
是否有效,并返回无效
n
值的笛卡尔乘积:

chosen = set()
if 0 < n < reduce(lambda a,b: a*b,[len(x) for x in list_of_sets]):
    while len(chosen) < n:
        chosen.add(tuple([random.sample(x,1)[0] for x in list_of_sets]))
else:
    chosen = itertools.product(*list_of_sets)
selected=set()
如果0
因为我不想重复,有时代码可能没有那么短。但正如@andreyF所说,
random.sample
起作用。也许还有一种更好的方法可以避免重复采样,直到存在足够多的非重复采样为止,这是我迄今为止最好的方法

import operator
import random
def get_cart_product(list_of_sets, n=None):
    max_products_num = reduce(operator.mul, [len(cluster) for cluster in list_of_sets], 1)
    if n is not None and n < max_products_num:
        refs = set()
        while len(refs) < n:
            refs.add(tuple(random.sample(cluster, 1)[0] for cluster in list_of_sets))
        return refs
        return (prod for i, prod in zip(range(n), itertools.product(*list_of_sets)))
    return itertools.product(*list_of_sets)
导入操作符
随机输入
def get_cart_产品(集合列表,n=None):
max_products_num=reduce(operator.mul,[len(cluster)用于_集合列表中的集群),1)
如果n不是无且n

请注意,代码假定有一个冻结集列表,否则应进行
random.sample(cluster,1)[0]
的转换。

以下生成器函数生成非重复样本。只有当生成的样本数远小于可能的样本数时,它才能有效地工作。它还要求集合的元素可以散列:

def samples(list_of_sets):
    list_of_lists = list(map(list, list_of_sets))  # choice only works on sequences
    seen = set()  # keep track of seen samples
    while True:
        x = tuple(map(random.choice, list_of_lists))  # tuple is hashable
        if x not in seen:
            seen.add(x)
            yield x

>>> lst = [{'b', 'a'}, {'c', 'd'}, {'f', 'e'}, {'g', 'h'}]
>>> gen = samples(lst)
>>> next(gen)
('b', 'c', 'f', 'g')
>>> next(gen)
('a', 'c', 'e', 'g')
>>> next(gen)
('b', 'd', 'f', 'h')
>>> next(gen)
('a', 'c', 'f', 'g')

上述所有解决方案在迭代结束时都会浪费大量资源来过滤重复的结果。这就是为什么我想到了一种从开始到结束(几乎)具有线性速度的方法

其思想是:给标准阶笛卡尔积的每个结果(只在你的头脑中)一个索引。例如,对于
A
x
B
x
C
2000
x
1
x
2
=
4000
元素:

0: (A[0], B[0], C[0])
1: (A[1], B[0], C[0])
...
1999: (A[1999], B[0], C[0])
2000: (A[0], B[0], C[1])
...
3999: (A[1999], B[0], C[1])
done.
因此,仍有一些问题有待解决:

  • 如何获得可能的索引列表?回答:只需乘以
    2000*1*2=4000
    ,下面的每个数字都将是有效的索引
  • 如何按顺序生成随机索引而不重复?有两个答案:如果您想要样本大小已知的样本,只需使用
    random.sample(xrange(numer\u of\u index),n)
    。但是,如果您还不知道样本大小(更一般的情况),则必须动态生成索引,以避免浪费内存。在这种情况下,您只需生成
    index=random.randint(0,k-1)
    k=numer\u of_index
    即可获得第一个索引,并为
    n
    第四个结果生成
    k=number\u of_index-n
    。只需检查下面的代码(请注意,我在那里使用单侧链表来存储完成的索引。它使插入操作成为O(1)操作,我们需要大量插入)
  • 如何从索引生成输出?回答:好吧,假设我们的索引是
    i
    。然后,
    i%2000
    将是结果的
    A
    索引。现在可以递归地将
    i//2000
    视为剩余因子笛卡尔积的索引
这就是我想出的代码:

def random_order_cartesian_product(*factors):
    amount = functools.reduce(lambda prod, factor: prod * len(factor), factors, 1)
    index_linked_list = [None, None]
    for max_index in reversed(range(amount)):
        index = random.randint(0, max_index)
        index_link = index_linked_list
        while index_link[1] is not None and index_link[1][0] <= index:
            index += 1
            index_link = index_link[1]
        index_link[1] = [index, index_link[1]]
        items = []
        for factor in factors:
            items.append(factor[index % len(factor)])
            index //= len(factor)
        yield items
def随机顺序笛卡尔乘积(*因子):
金额=functools.reduce(λ生产,系数:生产*长度(系数),系数,1)
索引链接列表=[无,无]
对于反向最大指数(范围(金额)):
索引=random.randint(0,最大索引)
索引链接=索引链接列表

虽然index_-link[1]不是None,index_-link[1][0]Matmarbon的答案是有效的,但这是一个完整的版本,有一个示例和一些修改,便于理解和使用:

import functools
import random

def random_order_cartesian_product(factors):
    amount = functools.reduce(lambda prod, factor: prod * len(factor), factors, 1)
    print(amount)
    print(len(factors[0]))
    index_linked_list = [None, None]
    for max_index in reversed(range(amount)):
        index = random.randint(0, max_index)
        index_link = index_linked_list
        while index_link[1] is not None and index_link[1][0] <= index:
            index += 1
            index_link = index_link[1]
        index_link[1] = [index, index_link[1]]
        items = []
        for factor in factors:
            items.append(factor[index % len(factor)])
            index //= len(factor)
        yield items


factors=[
    [1,2,3],
    [4,5,6],
    [7,8,9]
]

n = 5

all = random_order_cartesian_product(factors)

count = 0

for comb in all:
  print(comb)
  count += 1
  if count == n:
    break
导入工具
随机输入
def随机顺序笛卡尔积(因子):
金额=functools.reduce(λ生产,系数:生产*长度(系数),系数,1)
打印(金额)
打印(len(系数[0]))
索引链接列表=[无,无]
对于反向最大指数(范围(金额)):
索引=random.randint(0,最大索引)
索引链接=索引链接列表

虽然index_link[1]不是None,index_link[1][0]表示前两个集合看起来像
{1,2,3}
{2}
。您可以从
{1,2,3}
中随机选择
2
。你从
{2}
中随机选择什么?你“随机”选择2。当然:-)
list(map(random.choice,map(list,list of_set))
将生成这样一个示例,但重复执行不会避免重复,尽管如此。@schwobaseggl它是干净易读的,但如果多次执行,可能应该取出并保存内部映射,以提高效率。@borgr-Yup,如果重复执行,您绝对会将列表存储在列表中。不想把注释弄得乱七八糟:)编辑得很好,但请注意,如果n太大,当前代码可能永远不会停止。@borgr我假设
n
比笛卡尔坐标更小products@AndreyF
sample(x,1)
choice(x)
@schwobaseggl-yes相同。但是,
choice
doe