Python 查找创建平衡值集的集合的子集

Python 查找创建平衡值集的集合的子集,python,algorithm,Python,Algorithm,我知道标题有点模棱两可。请阅读更多细节 输入 我有一个已知数量的可变长度的集合(比如10000个),每个集合都是英语字母表的一个子集。看起来是这样的: a = ['a', 'b', 'c', 'a'] b = ['c', 'd', 'a', 'b'] c = ['x', 'y', 'z'] .... unique_value = set((*a, *b, *c, ...)) # {'a', 'b', 'c', 'd', 'e', 'f', ..., 'u', 'v', 'w', 'x', 'y

我知道标题有点模棱两可。请阅读更多细节

输入 我有一个已知数量的可变长度的集合(比如10000个),每个集合都是英语字母表的一个子集。看起来是这样的:

a = ['a', 'b', 'c', 'a']
b = ['c', 'd', 'a', 'b']
c = ['x', 'y', 'z']
....

unique_value = set((*a, *b, *c, ...))
# {'a', 'b', 'c', 'd', 'e', 'f', ..., 'u', 'v', 'w', 'x', 'y', 'z'}
我需要什么 我需要从10000个以上的集合中选择一个固定数量的集合(比如100个),其中该子集包含所有英文字符,并且每个字符的计数尽可能为
balance
<代码>平衡表示字符分布均匀。我知道很难选择一个完全一致的分布,因此定义一个
平衡标准也很重要

我的问题
  • 如何从原始集合中拾取子集(具有上述属性)
  • 平衡标准的定义
  • 请给我一个实现这一目标的方法。任何建议都将不胜感激。

    提前谢谢

    我要尝试的一般算法是概率算法。我将创建一个从字符到子集ID的反向查找表,然后继续添加和删除子集,以平衡固定数量子集的+0/+1。在添加子集时,我会添加一个随机选择的子集,其中包含填充最少的字母,在删除时,我会从包含填充最多字母的子集中进行选择。还应该存在“变异”和选择完全随机的子集来添加/删除的小机会,以防止陷入局部最小值

    我试图编写这个解决方案,但它很快就退化为一些意大利面代码,因为我修复了一些边缘案例和bug。这远不是一个完美的解决方案,甚至可能返回错误的答案,但至少它可能会给你一些想法

    # Make lookup table
    lookup = defaultdict(set)
    for idx, subset in enumerate(subsets):
        for character in subset:
            lookup[character].add(idx)
    
    best_score, best_subsets = 1, None
    size = 10 # number of subsets to pick
    subset_indices = set() # subset_ids
    character_subsets = defaultdict(set) # subset_ids per letter
    # loop some large number of times
    for _ in range(10000):
        if len(subset_indices) > size: # remove elements
            idx = choice(list(subset_indices)) # maybe pick a random
            if random() < 0.9: # 90% chance pick an existing subset to remove
                indices = max(character_subsets.values(), key=len) # indices to pick from
                idx = choice(list(indices)) # pick one
            for character in subsets[idx]: # remove index/subset_id from lookup
                character_subsets[character].remove(idx)
            subset_indices.remove(idx) # remove subset_id from random draw pool
        else: # add a new subset
            idx = choice(list(set(range(len(subsets))) - subset_indices)) # invert random selection
            if random() < 0.9: # 90% chance to pick a new subset from the min populated
                i, indices = min(character_subsets.items(), key=lambda x:len(x[1]), default=(randint(0, len(lookup)-1),set()))
                indices = lookup[i] - indices # invert
                if not indices: continue # abort if empty
                idx = choice(list(indices)) # pick
            for character in subsets[idx]:
                character_subsets[character].add(idx) # update dict
            subset_indices.add(idx) # update random selection set
        score = pstdev(map(len, character_subsets.values())) # measure distribution
        if score < best_score and len(subset_indices) == size: # if better
            best_subsets = dict(character_subsets) # record it
            best_score = score
    
    # do logic to pretty-print or process best_subset however you like
    
    #生成查找表
    lookup=defaultdict(设置)
    对于idx,枚举中的子集(子集):
    对于子集中的字符:
    查找[字符]。添加(idx)
    最佳_分数,最佳_子集=1,无
    大小=10#要拾取的子集数
    子集索引=集合()#子集索引
    字符_子集=默认dict(set)#子集_每个字母的ID
    #循环多次
    对于范围内的(10000):
    如果len(子集索引)>大小:#删除元素
    idx=选择(列表(子集索引))#可能随机选择一个
    如果random()<0.9:#90%的几率选择要删除的现有子集
    index=max(character_subsets.values(),key=len)#要从中拾取的索引
    idx=选择(列表(索引))#选择一个
    对于子集[idx]中的字符:#从查找中删除索引/子集_id
    字符\u子集[字符]。删除(idx)
    子集索引。删除(idx)#从随机抽取池中删除子集索引
    else:#添加新子集
    idx=选择(列表(集合(范围(len(子集)))-子集(U索引))#反转随机选择
    如果random()<0.9:#90%的几率从最小值中选择新子集
    i、 index=min(character_subsets.items(),key=lambda x:len(x[1]),default=(randint(0,len(lookup)-1),set())
    索引=查找[i]-索引#反转
    如果没有索引:继续#如果为空则中止
    idx=选择(列表(索引))#选择
    对于子集[idx]中的字符:
    字符集[character].add(idx)#update dict
    子集_索引。添加(idx)#更新随机选择集
    score=pstdev(映射(len,character_subsets.values())#度量分布
    如果得分<最佳得分和len(子集指数)=大小:#如果更好
    最佳子集=dict(字符子集)#记录它
    最佳分数=分数
    #按照你喜欢的方式打印或处理最好的子集
    
    很抱歉,响应太晚。你能详细说明这一部分吗
    在添加子集时,我会添加一个随机选择的包含最少填充字母的子集,在删除时,我会从包含最多填充字母的子集中进行选择
    @enamoria您希望平衡每个字母出现的次数,因此当我们添加新子集时,我们会选择一个包含最少出现字母的子集。然而,为了“洗牌”一些东西,希望它能解决它的方式进入一个全局最小值,我们还删除了一个子集(为添加另一个子集腾出空间)。我们删除的这个子集应该是包含出现次数最多的字母的子集,这样可以降低它,并希望能够平衡一些事情。我在设计这个算法时从中得出了一些想法,如果这有助于给你我推理背后的直觉的话。