【发布时间】:2015-07-15 14:50:43
【问题描述】:
作为我自己对基因型网络研究的一部分,我有一段代码,我试图在其中从字符串列表构建一个单差网络。流程是这样的:
- 遍历字符串的所有成对组合。
- 如果字符串相差一个位置,则在网络中在它们之间绘制一条边。
- 如果它们没有一个位置差异,则通过。
我现在的代码块是这样的:
from itertools import combinations
import Levenshtein as lev # a package that wraps a C-implemented levenshtein distance
import networkx as nx
strings = [...list of strings...]
G = nx.Graph()
for (s1, s2) in combinations(strings, 2):
if s1 not in G.nodes():
G.add_node(s1)
if s2 not in G.nodes():
G.add_node(s2)
if lev.distance(s1, s2) == 1:
G.add_edge(s1, s2)
显然没有办法提高图构造过程的计算复杂度——它总是O(n**2)。至少,在我有限的知识范围内,我是这么认为的——也许我错了?
也就是说,考虑到我需要进行的比较次数的正常规模(约 2000-5000 次),如果总体上我能获得几个数量级的加速,那么实际计算时间将仍然可以接受 - 使用当前的 Python 实现,构建图形需要〜几天。使用正确的导入(下文未说明),我尝试了下面的 Cython 实现,但无法弄清楚如何使其更快:
cpdef cython_genotype_network(sequences):
G = nx.Graph()
cdef:
unicode s1
unicode s2
for (s1, s2) in combinations(sequences, 2):
if lev.distance(s1, s2) == 1:
G.add_edge(s1, s2)
return G
特别是,Cython 期望 bytes,而不是 str 用于 s1 和 s2。该代码块引发错误。
所以...我来回答我的两个问题:
- Q1:Cython 实施会有帮助吗?以及如何修复 bytes vs. str 错误?
- Q2:是否可以改用
numpy来解决这个问题?从numpy矩阵转换为NetworkX 很容易;但是,我似乎无法弄清楚如何在每行和每列对应一个字符串的 n×n 空矩阵中广播 Levenshtein 距离函数。
更新 1:如何生成示例数据
要生成字符串:
from random import choice
def create_random_nucleotides_python(num_nucleotides):
"""
Creates random nucleotides of length num_nucleotides.
"""
sequence = ''
letters = ['A', 'T', 'G', 'C']
for i in range(num_nucleotides):
sequence = sequence + choice(letters)
return sequence
def mutate_random_position(string):
"""
Mutates one position in the nucleotide sequence at random.
"""
positions = [i for i in range(len(string))]
pos_to_mut = choice(positions)
letters = ['A', 'T', 'G', 'C']
new_string = ''
for i, letter in enumerate(string):
if i == pos_to_mut:
new_string = new_string + choice(letters)
else:
new_string = new_string + letter
return new_string
# Create 100 Python srings by mutating a first sequence, then randomly choosing stuff to mutate a single position.
base_sequence = create_random_nucleotides_python(1000)
sequences = [base_sequence]
for i in range(99):
sequence = choice(sequences)
mutseq = mutate_random_position(sequence)
sequences.append(mutseq)
【问题讨论】:
-
什么是
.nodes()?它不是一个集合,它应该是 -
基于
networkx文档,Graph.nodes()返回一个列表,但底层实现是一个字典。 -
那是
O(n)每次查找,我认为节点是键? -
是的,我认为这是正确的。
-
好吧,
if s1 not in G或if G.has_node(s1)应该给你 0(1) 次查找,我想G.has_node是if s1 not in G的语法糖,但我没有检查
标签: python numpy combinations cython levenshtein-distance