在构建整数列表时约束频率

2024-05-16 22:38:03 发布

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

我正在尝试编写一个函数,它将返回一个整数列表,这些整数列表对应于我要将化学物质集中到的池。我想让每个池中的化学品数量尽可能保持一致。每种化学品在池中复制若干次(在本例中,在9个池中复制3次)。对于下面的例子,我有31种化学品。因此,每个池中应该有10.333种药物(或者,更具体地说,每个池应该有一个下限(93/9)=10种药物,93%9=3个池中有11种药物。我的函数如下。目前,我正在尝试让函数循环,直到剩下一组整数(即3个池中有9种化学物质)因此,我可以对函数进行编码,以识别哪些池允许再添加一种化学品,并最终确定列表列表,该列表告诉我将每个化学品放入哪些池

但是,正如现在所写的,对于列表中出现的整数的频率,函数不会总是给出我想要的11,11,11,10,10,10,9,9,9的分布。我写了以下内容试图限制分布:1)随机选择位(池号)列表,而不进行替换。如果所选列表中的任何位具有频率>;=10在输出列表中,我已经有3个频率为11的池,丢弃这个位列表2)如果所选列表中的任何位具有频率>;=输出列表中的9,并且有6个池的频率>;=10,放弃此位列表3)如果所选列表中的任何位具有频率>;=11在输出列表中,放弃此位列表这段代码似乎工作不正常。我认为这与我对这三种情况的编码不当有关。某些位列表似乎被意外丢弃,而其他位列表则被不正确地添加到输出列表中。或者,也可能出现这样一种情况,即两个池在同一步骤中从9种化学品变为10种化学品,结果是4个10种化学品池,而不是3个10种化学品池。我对这个问题的想法错了吗?是否有明显的地方我的代码不起作用?

用于生成规范化池的函数: (重叠_kbits返回长度的位列表,复制,每个位都是[1,]范围内的整数,经过筛选,两个列表之间的重叠不得超过。)

import numpy as np
import pandas as pd
import itertools
import re
import math
from collections import Counter

def normalized_pool(pools, replicates, overlaps, ligands):
    solvent_bits = [list(bits) for bits in itertools.combinations(range(pools),replicates)]
        
    print(len(solvent_bits))
    
    total_items = ligands*replicates
    norm_freq = math.floor(total_items/pools)
    num_extra = total_items%pools
    num_norm = pools-3
    normed_bits = []
    count_extra = 0
    count_norm = 0
    
    while len(normed_bits) < ligands-1 and len(solvent_bits)>0:
        rand = np.random.randint(0,len(solvent_bits))
        bits = solvent_bits.pop(rand) #Sample without replacement
        print(bits)
        bin_freqs = Counter(itertools.chain.from_iterable(normed_bits))
        print(bin_freqs)
        previous = len(normed_bits)
        
        #Constrain the frequency distribution
        count_extra = len([bin_freqs[bit] for bit in bin_freqs.keys() if bin_freqs[bit] >= norm_freq+1])
        count_norm = len([bin_freqs[bit] for bit in bin_freqs.keys() if bin_freqs[bit] >= norm_freq])
        if any(bin_freqs[bit] >= norm_freq for bit in bits) and count_extra == num_extra:
            print('rejected')
            continue #i.e. only allow num_extra number of bits to have a frequency higher than norm_freq
        elif any(bin_freqs[bit] >= norm_freq+1 for bit in bits):
            print('rejected')
            continue #i.e. never allow any bit to be greater than norm_freq+1
        elif (any(bin_freqs[bit] >= norm_freq-1 for bit in bits) and count_norm >= num_norm):
            if count_extra == num_extra:
                print('rejected')
                continue #only num_norm bins can have norm_freq
        
        normed_bits.append(bits)
    
    bin_freqs = Counter(itertools.chain.from_iterable(normed_bits))

    return normed_bits

test_bits = normalized_pool(9,3,2,31)
test_freqs = Counter(itertools.chain.from_iterable(test_bits))
print(test_freqs)
print(len(test_bits))

我可以得到从11,11,11,10,10,9,9,9(我想要的输出)到11,11,11,10,10,10,10,7的任何东西。举个简单的例子,请尝试:

test_bits = normalized_pool(7,3,2,10)
test_freqs = Counter(itertools.chain.from_iterable(test_bits))
print(test_freqs)

它应该返回5,5,4,4,3,3作为测试频率计数器的元素

编辑:修改函数,使其可以在复制和粘贴时运行。将函数调用合并到更大的代码块中,因为它被忽略了。


Tags: 函数testnorm列表lenbinbitextra