Python 在一组二进制字符串中查找重叠位
我正在做一个项目,我需要为不同分子的组合池生成几个标识符。为此,我给每个分子分配了一个n位的字符串(其中n是我拥有的池的数量。在本例中为79个池),每个字符串有4个“开”位(4位等于1),对应于该分子将出现在哪些池中。接下来,我想减少字符串的数量,这样两个分子在同一个池中出现的次数不会超过两次(换句话说,两个字符串之间的最大重叠位数不能超过2) 为此,我:1)编译了一个包含k个“开”位的所有n位字符串的列表;2)生成了一个列表,其中每个元素都是一个索引列表,其中该位使用Python 在一组二进制字符串中查找重叠位,python,algorithm,jupyter-notebook,Python,Algorithm,Jupyter Notebook,我正在做一个项目,我需要为不同分子的组合池生成几个标识符。为此,我给每个分子分配了一个n位的字符串(其中n是我拥有的池的数量。在本例中为79个池),每个字符串有4个“开”位(4位等于1),对应于该分子将出现在哪些池中。接下来,我想减少字符串的数量,这样两个分子在同一个池中出现的次数不会超过两次(换句话说,两个字符串之间的最大重叠位数不能超过2) 为此,我:1)编译了一个包含k个“开”位的所有n位字符串的列表;2)生成了一个列表,其中每个元素都是一个索引列表,其中该位使用re.finditer打开
re.finditer
打开;3)迭代列表以比较字符串,只将符合我的条件的字符串添加到最终的字符串列表中
我用于比较字符串的代码:
drug_strings = [] #To store suitable strings for combinatorial pooling rules
class badString(Exception): pass
for k in range(len(strings)):
bit_current = bit_list[k]
try:
for bits in bit_list[:k]:
intersect = set.intersection(set(bit_current),set(bits))
if len(intersect) > 2:
raise badString() #pass on to next iteration if string has overlaps in previous set
drug_strings.append(strings[k])
except badString:
pass
然而,这段代码需要永远运行。我使用n=79位字符串运行此操作,每个字符串的k=4“开”(可能是约1.5M的字符串),因此我假设运行时间长是因为我将每个字符串与前一个字符串进行比较。有没有其他更明智的方法来实现这一点?一种运算速度更快、更健壮的算法
编辑:我意识到解决这个问题的更简单的方法不是确定适合我的项目的整个字符串子集,而是用k“on”位随机采样较大的n位字符串集,只存储符合我标准的字符串,一旦我有了适当数量的合适字符串,只需从这些字符串中获取我所需要的数量。新代码如下:
my_strings = []
my_bits = []
for k in range(2000):
random = np.random.randint(0, len(strings_77))
string = strings_77.pop(random)
bits = [m.start()+1 for m in re.finditer('1',string)]
if all(len(set(bits) & set(my_bit)) <= 2
for my_bit in my_bits[:k]):
my_strings.append(string)
my_bits.append(bits)
my_strings=[]
我的字节=[]
对于范围内的k(2000):
random=np.random.randint(0,len(strings_77))
字符串=字符串\u 77.pop(随机)
位=[m.start()+1代表re.finditer中的m('1',字符串)]
如果all(len(set(bits)&set(my_bit))您的代码中需要改进的一些小事情可能会导致一些开销:
设置(位\u电流)
将其移出内环
拆下提升
部件以外的部分
因为如果len(intersect)>2:
有这个条件,你可以尝试实现拦截
方法,在满足该条件时停止。这样你就避免了不必要的计算
因此,代码将变成:
for k in range(len(strings)):
bit_current = set(bit_list[k])
intersect = []
for bits in bit_list[:k]:
intersect = []
b = set(bits)
for i in bit_current:
if i in b:
intersect.append(i)
if len(intersect) > 2:
break
if len(intersect) > 2:
break
if len(intersect) <= 2:
drug_strings.append(strings[k])
范围内的k(len(strings)):
位电流=设置(位列表[k])
相交=[]
对于位_列表[:k]中的位:
相交=[]
b=设置(位)
对于位_电流中的i:
如果我在b:
intersect.append(一)
如果len(相交)>2:
打破
如果len(相交)>2:
打破
如果len(intersect)引发异常代价高昂。将创建一个复杂的数据结构,并且必须解开堆栈。事实上,设置try/except块代价高昂
实际上,您需要检查所有交点的长度是否小于或等于2,然后追加。不需要异常
for k in range(len(strings)):
bit_current = bit_list[k]
if all(len(set(bit_current) & set(bits)) <= 2
for bits in bit_list[:k]):
drug_strings.append(strings[k])
从我的原始代码中继承下来的一点是,将每个比特集与当前字符串之前的每个字符串中的比特集进行比较。将代码重构为向前看而不是向后看会更快吗?事实上,每次迭代都会逐渐变长,但如果重构,每次迭代都会变短。是吗这两种方式都没有好处吗?
for index, (drug_string, bit_current) in enumerate(zip(strings, bit_list)):
if all(len(set(bit_current) & set(bits)) <= 2
for bits in bit_list[:k]):
drug_strings.append(drug_string)
for index, (drug_string, bit_current) in enumerate(zip(strings, bit_list)):
bit_set = set(bit_current)
if all(len(bit_set & set(bits)) <= 2
for bits in bit_list[:k]):
drug_strings.append(drug_string)