Python:从稀疏矩阵恢复距离完整图

时间:2018-03-13 14:37:43

标签: python graph distance

我试图模仿细菌的生长。比如说,每个物种进行一次反应,将物质A转化为物质B并获得(或失去)能量。

如果我使用少量物质,我可以手动检查无限生成周期(例如A => B => C => A路径具有正能量增益)。如果我使用10种物质,那么事情就会变得复杂。

import numpy as np
import pandas as pd

def add_symmetry(df):
    for i in df.index:
        for j in df.columns:
            if df.loc[i,j]!=0:
                df.loc[j,i] = -1*(df.loc[i,j])
    return(df)

names = [_ for _ in 'ABCDEFGHJK']

en_df = pd.DataFrame(np.zeros((10,10)), index=names, columns=names)

en_df.loc['A','F'] = 1.9
en_df.loc['F','B'] = 0.8
en_df.loc['B', 'G'] = 4.6
en_df.loc['G','C'] = 1.5
en_df.loc['C','A'] = -9.4

# cycle2
en_df.loc['D','H'] = -5
en_df.loc['H','E'] = 2
en_df.loc['E','J'] = 1.1

en_df.loc['K','E'] = 1.2

en_df.loc['G','H'] = -1

en_df = add_symmetry(en_df)

     A    B    C    D    E    F    G    H    J    K
A  0.0  0.0  9.4  0.0  0.0  1.9  0.0  0.0  0.0  0.0
B  0.0  0.0  0.0  0.0  0.0 -0.8  4.6  0.0  0.0  0.0
C -9.4  0.0  0.0  0.0  0.0  0.0 -1.5  0.0  0.0  0.0
D  0.0  0.0  0.0  0.0  0.0  0.0  0.0 -5.0  0.0  0.0
E  0.0  0.0  0.0  0.0  0.0  0.0  0.0 -2.0  1.1 -1.2
F -1.9  0.8  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
G  0.0 -4.6  1.5  0.0  0.0  0.0  0.0 -1.0  0.0  0.0
H  0.0  0.0  0.0  5.0  2.0  0.0  1.0  0.0  0.0  0.0
J  0.0  0.0  0.0  0.0 -1.1  0.0  0.0  0.0  0.0  0.0
K  0.0  0.0  0.0  0.0  1.2  0.0  0.0  0.0  0.0  0.0

这给了我一个对称矩阵,总共45个中有10个反应。我想自动填写其余部分,以便没有正的和周期 E.g:

A=>F is +1.9 energy units
F=>B is +0.8 eu
A => B is (1.9 + 0.8 - 0.1) = 2.6 eu
剩下的

有没有一种简单的方法可以做到这一点,还是我需要为每个零单元实现最佳路径搜索算法?

1 个答案:

答案 0 :(得分:0)

到目前为止,我的解决方案看起来像这样

import copy
import networkx as nx
import numpy as np
import pandas as pd

from collections import deque


def add_symmetry(df):

    for i in df.index:
        for j in df.columns:
            if df.loc[i,j]!=0:
                df.loc[j,i] = -1*(df.loc[i,j])

    return(df)

def from_pd_df(df):

    gr = nx.DiGraph()
    for i in df.index:
        for j in df.columns:
            if df.loc[i, j] != 0:
                gr.add_edge(i, j, weight=df.loc[i, j])
    return(gr)

def fill_zeros(df):

    temp = copy.copy(df)

    # Deal only with positive energies
    # Substitute maximal path problem with a minimal path one
    temp[temp<0] = 0
    temp = -1*temp

    gr = from_pd_df(temp)

    for i in temp.index:

        try:
            p = nx.bellman_ford(gr, i, weight = 'weight')

        except nx.NetworkXUnbounded:
            print('{} is involved in an infinite cycle'.format(i))

            return(None)
   # If a previously implicit path exists, save it ti temp
        for j in p[1]:
            if df.loc[i,j] == 0:
                temp.loc[i,j] = p[1][j]
                temp.loc[j, i] = -1*p[1][j]
    # Revert back to maximal path problem   
    temp = -1*temp

    # Add reverse reaction
    temp = add_symmetry(temp)

    return(temp)

>> Define the matrix


en_df = add_symmetry(en_df)
x = fill_zeros(en_df)