【问题标题】:Set of HUGE permutation object (in Python or R)一组巨大的排列对象(在 Python 或 R 中)
【发布时间】:2017-02-22 15:10:28
【问题描述】:

目标:我想获得(或能够使用)一组从字符串列表中获得的所有可能排列。

Python 示例:

import pandas as pd
import itertools

list1 = ['A', 'A', 'B', 'B']

# Get all permutations
list1_perm = list(itertools.permutations(list1))

len(list1_perm)
24

list1_perm
[('A', 'A', 'B', 'B'),
 ('A', 'A', 'B', 'B'),
 ('A', 'B', 'A', 'B'),
 ('A', 'B', 'B', 'A'),
 ('A', 'B', 'A', 'B'),
 ('A', 'B', 'B', 'A'),
 ('A', 'A', 'B', 'B'),
 ('A', 'A', 'B', 'B'),
 ('A', 'B', 'A', 'B'),
 ('A', 'B', 'B', 'A'),
 ('A', 'B', 'A', 'B'),
 ('A', 'B', 'B', 'A'),
 ('B', 'A', 'A', 'B'),
 ('B', 'A', 'B', 'A'),
 ('B', 'A', 'A', 'B'),
 ('B', 'A', 'B', 'A'),
 ('B', 'B', 'A', 'A'),
 ('B', 'B', 'A', 'A'),
 ('B', 'A', 'A', 'B'),
 ('B', 'A', 'B', 'A'),
 ('B', 'A', 'A', 'B'),
 ('B', 'A', 'B', 'A'),
 ('B', 'B', 'A', 'A'),
 ('B', 'B', 'A', 'A')]

由于我的分析('A', 'A', 'B', 'B')('A', 'A', 'B', 'B')相同,(虽然'A'可能改变了位置),所以我这样做:

# Get set of permutations
set1_perm = set(itertools.permutations(list1))

len(set1_perm)
6

set1_perm
{('A', 'A', 'B', 'B'),
 ('A', 'B', 'A', 'B'),
 ('A', 'B', 'B', 'A'),
 ('B', 'A', 'A', 'B'),
 ('B', 'A', 'B', 'A'),
 ('B', 'B', 'A', 'A')}

现在这很好,但我要处理的列表有 481 个字符串,其中有 5 个不同频率的唯一字符串:

len(real_list)
481

len(set(real_list))
5

# Count number of times each unique value appears
pd.Series(real_list).value_counts()
A  141
B  116
C  80
D  78
E  66

这对itertools.permutations(real_list) 来说不是问题,但是当我想获得set 时,需要很长时间。这是因为排列的数量是9.044272819E+1082

我想做的是: 首先,我想知道该排列空间中唯一元素的数量,即集合的长度。要获得独特元素的数量,可以通过分析来完成,但是由于每个独特元素的频率不同,我不知道如何做到这一点。

其次,我希望能够获得排列集中那些独特元素的样本。

如果能提供任何帮助,我将不胜感激。

最好, 亚历杭德罗

【问题讨论】:

    标签: python r set permutation itertools


    【解决方案1】:

    计算唯一排列的数量只是应用一个公式的问题 - 我们知道如果我们有 n 不同的元素,我们将有 n! 排列。然后为了解释重复排列,我们必须除以重复字母的每个排列计数。这是一个多项式系数

    所以生成唯一计数的简单实现可能类似于

    from math import factorial
    from functools import reduce
    from collections import Counter
    
    def perm_cnt(l):
        denom = reduce(lambda x,y: x*factorial(y), Counter(l).values())
        return factorial(len(l)) // denom
    

    然后,通过确保您的样本值保持唯一性,而不是尝试生成所有唯一值并然后进行采样,可能最简单地实现从唯一排列中采样。在 itertools 模块中有一个 reciperandom_permutation,它可能对此很有用。

    def random_permutation(iterable, r=None):
        "Random selection from itertools.permutations(iterable, r)"
        pool = tuple(iterable)
        r = len(pool) if r is None else r
        return tuple(random.sample(pool, r))
    

    所以创建一个独特的样本可能看起来像

    def uniq_sample(l, size):
        s = set()
        perm_size = perm_cnt(l)
        cnt = 0
        while cnt < min(perm_size, size):
            samp = random_permutation(l)
            if samp not in s:
                s.add(samp)
                cnt += 1
        return s
    

    演示

    >>> perm_cnt(list1)
    6
    
    >>> perm_cnt(['a']*3 + ['b']*5 + ['d']*2)
    2520
    
    >>> perm_cnt(np.random.randint(10, size=20))
    105594705216000
    
    >>> uniq_sample(list1, 4)
    {('A', 'A', 'B', 'B'),
     ('B', 'A', 'A', 'B'),
     ('B', 'A', 'B', 'A'),
     ('B', 'B', 'A', 'A')}
    

    【讨论】:

    • 这太棒了!非常感谢所有的解释、代码和演示!
    猜你喜欢
    • 2014-04-29
    • 1970-01-01
    • 2019-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-18
    • 2021-04-15
    • 1970-01-01
    相关资源
    最近更新 更多