funciones_network_science.py 20.9 KB
Newer Older
Maria Marin's avatar
Maria Marin committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
#! /usr/bin/env python

"""
# ---------------------------------------------------------------------------
#
# funciones_network_science.py
#
# Archivo con todas las funciones que he utilizado para aplicar métricas de 
# ciencia de redes a redes bipartitas y proyectadas.
#
# TFG: Ciencia de redes y reposicionamiento de fármacos: potencial a través 
# de la medicina de redes
#
# María Marín Tercero
# ----------------------------------------------------------------------------
"""

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import networkx as nx
from networkx.algorithms import bipartite
import nxpd
    
# =================================================================================

def asociaciones(archivo, var1, var2, nombre_var1, nombre_var2, ax):
    """
    Esta función toma un archivo que representa asociaciones entre dos grupos disjuntos de nodos. Finalmente, representa en un histograma la distribución del número de asociaciones de un grupo de nodos con nodos de la otra clase. 
    Datos de entrada: 
    1. archivo: Archivo con asociaciones entre nodos organizado en dos columnas, una para cada grupo de nodos 
    2. var1: Nombre de una columna
    3. var2: Nombre de la otra columna
    4. nombre_var1: Nombre de los nodos representados en la columna 1
    5 nombre_var2: Nombre de los nodos representados en la columna 2
    6. ax: Variable empleada para la representación organizada en un subplot
    
    """
    conteo = archivo.groupby(var1)[var2].count().reset_index() #cuento el número de asociaciones del grupo var1 con el grupo var2
    
    #Represento los resultados
    ax.hist(conteo[var2], bins=20, color='#79C4FF', edgecolor='black')
    ax.set_xlabel('Nº de ' + nombre_var2, fontsize=12)
    ax.set_ylabel(nombre_var1, fontsize=12)
    ax.set_title('Distribución de '+ r'$\mathbf{' + nombre_var2 + '}$' + " por " + r'$\mathbf{' + nombre_var1 + '}$' ,  fontsize=12)

# =================================================================================

def matriz_spl_enfermedades_bip(archivo, graf):
    """
    Esta función genera una matriz bidimensional que contiene los Shortest Path 
    Lenghts de todos los nodos enfermedades de una red bipartita compuesta por dos 
    grupos disjuntos de nodos.
    Datos de entrada:
    1. archivo: Archivo con los datos sobre los enlaces entre los nodos de la red
    2. graf: Red bipartita 
    """
    
    enfermedades = list(set(archivo['dis'])) #lista de enfermedades (columna "dis" del archivo)

    matriz_spl = np.zeros((len(enfermedades), len(enfermedades))) #Inicializo una matriz de ceros para almacenar los SPL

    #Calculo los SPL entre todas las parejas de enfermedades
    for i in range(len(enfermedades)): #enfermedad_i
        for j in range(i + 1, len(enfermedades)): #enfermedad_i+1
            enfermedad_i = enfermedades[i] #guardo el nodo enfermedad_i en la fila i de la matriz
            enfermedad_j = enfermedades[j] #guardo el nodo enfermedad_i+1 en la columna j de la matriz
            try: #me aseguro de que exista un camino entre ambas enfermedades
                spl = nx.shortest_path_length(graf, source=enfermedad_i, target=enfermedad_j) #calculo su spl
                matriz_spl[i, j] = spl #añado el valor a la matriz en su posición correspondiente
                matriz_spl[j, i] = spl #añado el valor a la matriz en su posición correspondiente
            except nx.NetworkXNoPath: #si no hay camino, continúo
                pass
    #Creo un DataFrame con la matriz de SPLs
    df_matriz_spl = pd.DataFrame(matriz_spl, index=enfermedades, columns=enfermedades)

    return df_matriz_spl

# =================================================================================

def matriz_spl_var_bip(archivo, graf, nombre_var):
    """
    Esta función genera una matriz bidimensional que contiene los Shortest Path 
    Lenghts para el grupo de nodos distinto a enfermedades en una red bipartita 
    que contiene dos grupos diferenets de nodos, siendo uno enfermedades. El otro
    grupo varía en función de la red. 
    Datos de entrada:
    1. archivo: Archivo con los datos sobre los enlaces entre los nodos de la red
    2.  graf: Red bipartita
    3. nombre_var: Identificador del grupo de nodos distinto a enfermedades en el archivo
    """

    var = list(set(archivo[str(nombre_var)])) #lista de nodos del grupo disjunto a enfermedades (columna con el identificador añadido en los datos de entrada)

    matriz_spl = np.zeros((len(var), len(var))) #Inicializo una matriz de ceros para almacenar los SPL

    #Calculo los SPL entre todas las parejas de los nodos seleccionados
    for i in range(len(var)): #nodos_i
        for j in range(i + 1, len(var)): #nodo_i+1
            var_i = var[i] #guardo el nodo_i en la fila i de la matriz
            var_j =  var[j] #guardo el nodo_i+1 en la columna j de la matriz
            try: #me aseguro de que exista un camino entre ambos nodos
                spl = nx.shortest_path_length(graf, source=var_i, target=var_j) #calculo su spl
                matriz_spl[i, j] = spl #añado el valor a la matriz en su posición correspondiente
                matriz_spl[j, i] = spl #añado el valor a la matriz en su posición correspondiente
            except nx.NetworkXNoPath: #si no hay camino, continúo
                pass

    #Creo un DataFrame con la matriz de SPLs
    df_matriz_spl = pd.DataFrame(matriz_spl, index=var, columns=var)

    return df_matriz_spl

# =================================================================================

def matriz_spl_enfermedades_proj(archivo, graf):
    """
    Esta función genera una matriz bidimensional que contiene los Shortest Path 
    Lenghts para las enfermedades en una red proyectada. 
    Datos de entrada:
    1. archivo: Archivo con los datos sobre los enlaces entre los nodos de la red
    2. graf: Red bipartita
    """
    all_shortest_paths = dict(nx.all_pairs_shortest_path_length(graf)) #creo un diccionario con los spls entre todas las parejas de nodos de la red 
    
    enfermedades = list(graf.nodes) # Obtengo la lista de nodos enfermedades
    
    matriz_spl = np.zeros((len(enfermedades), len(enfermedades))) #Inicializo una matriz de ceros para almacenar los SPL
   
    for i, enfermedad_i in enumerate(enfermedades): #enfermedad_i
        for j, enfermedad_j in enumerate(enfermedades): #enfermedad_j
            matriz_spl[i, j] = all_shortest_paths[enfermedad_i].get(enfermedad_j, 0) #añado a la matriz el spl entre la enfermedad_i y la enfermedad_j según el diccionario con el total de spls
    
    #Creo un DataFrame con la matriz de SPLs
    df_matriz_spl = pd.DataFrame(matriz_spl, index=enfermedades, columns=enfermedades)
    return df_matriz_spl

# =================================================================================
def degree_bip(graf, archivo, nombre_graf, nombre_var, ax, ax1):
    """
    Esta función calcula y representa la distribución de grados de dos 
    grupos disjuntos de nodos en una red bipartita, siendo uno de esos grupos
    el correspondiente a enfermedades
    Datos de entrada:
    1. graf: Red bipartita
    2. archivo: Archivo con los datos sobre los enlaces entre los nodos de la red
    3. nombre_graf: Nombre de la red
    4. nombre_var: Nombre del grupo disjunto de nodos distinto a enfermedades
    5. ax: Variable empleada para la representación organizada de la primera distribución en un subplot
    6. ax1: Variable empleada para la representación organizada  de la segunda distribución en un subplot
    """
    degrees_dict = dict(graf.degree())  # diccionario con los grados de los nodos del grafo
    
    nodos_enf = set(archivo.iloc[:, 0])  # selecciono el set de nodos enfermedades en el archivo (que se encuentran en la primera columna)
    nodos_var = set(archivo.iloc[:, 1])  # selecciono el set de nodos del grupo variable en el archivo (que se encuentran en la segunda columna)

    # Filtro los degrees para nodos de enfermedades y variables
    degree_enf = [degrees_dict[clave] for clave in nodos_enf if clave in degrees_dict]
    degree_var = [degrees_dict[clave] for clave in nodos_var if clave in degrees_dict]

    # Represento la distribución de grados de las enfermedades
    G_lista_enf = pd.DataFrame(list(zip(nodos_enf, degree_enf)), columns=['node', 'degree'])
    G_plot_enf = G_lista_enf.groupby('degree').count()
    ax.scatter(G_plot_enf.index, G_plot_enf['node'], marker='o', color='#79C4FF', s=10)
    ax.set_yscale('log')
    ax.set_xscale('log')
    ax.set_xlabel('Grado', fontsize=10)
    ax.set_ylabel('Nº nodos', fontsize=10)
    ax.set_title('Distribución de grados de ' + r'$\mathbf{' + "enfermedades" + '}$' +' en\n' + r'$\mathbf{' + "red" + '}$' + " " + r'$\mathbf{' + "bipartita" + '}$'+ " "+ r'$\mathbf{' + nombre_graf + '}$' , fontsize=12)
    
    # Represento la distribución de grados del grupo disjunto de nodos distinto a enfermedades
    G_lista_var = pd.DataFrame(list(zip(nodos_var, degree_var)), columns=['node', 'degree'])
    G_plot_var = G_lista_var.groupby('degree').count()
    ax1.scatter(G_plot_var.index, G_plot_var['node'], marker='o', color='#79C4FF', s=10)
    ax1.set_yscale('log')
    ax1.set_xscale('log')
    ax1.set_xlabel('Grado', fontsize=10)
    ax1.set_ylabel('Nº nodos', fontsize=10)
    ax1.set_title('Distribución de grados de ' +  r'$\mathbf{' + nombre_var + '}$' + ' en\n' + r'$\mathbf{' + " red" + '}$' + " "+ r'$\mathbf{' + "bipartita" + '}$'+ " " + r'$\mathbf{' + nombre_graf + '}$', fontsize=12)


# =================================================================================

def degree_proj(graf, nombre_graf, ax):
    """
    Esta función calcula y representa la distribución de grados de las enfermedades
    en una red proyectada.
    Datos de entrada:
    1. graf: Red bipartita
    2. nombre_graf: Nombre de la red
    3. ax: Variable empleada para la representación organizada de la distribución en un subplot
    """
    degrees_dict = dict(graf.degree())  # diccionario con los grados de los nodos del grafo
    
    nodos = list(degrees_dict.keys())  # lista con los nodos de la red (claves del diccionario anterior)
    degrees = list(degrees_dict.values())  # lista con los grados de los nodos de la red (valores del diccionario anterior)
    
    # Represento la distribución de grados
    G_lista = pd.DataFrame(list(zip(nodos, degrees)), columns=['node', 'degree'])
    G_plot = G_lista.groupby('degree').count()
    ax.scatter(G_plot.index, G_plot['node'], marker='o', color='#79C4FF', s=10)
    ax.set_yscale('log')
    ax.set_xscale('log')
    ax.set_xlabel('Grado', fontsize=10)
    ax.set_ylabel('Nº nodos', fontsize=10)
    ax.set_title('Distribución de grados de ' + r'$\mathbf{' + "enfermedades" + '}$'+  ' en\n' + r'$\mathbf{' + " red "+ '}$'+ " "+ r'$\mathbf{' + "proyectada" + '}$' + " " + r'$\mathbf{' + nombre_graf + '}$',  fontsize=12)

# =================================================================================

def average_spl(matriz_spl, nombre_graf, nombre_var, ax, bipartita = True):
    """
    Esta función realiza una distribución de los Average SPL d los nodos de un grafo.
    Datos de entrada: 
    1. matriz_spl: Matriz con la información sobre los SPLs entre todas las parejas de nodos
    2. nombre_graf: Nombre de la red
    3. nombre_var: Nombre del tipo de nodos representado
    4. ax: Variable empleada para la representación organizada de la distribución en un subplot
    5. Bipartita: dependiendo de si es igualue o False, añade el título correspondiente a una red bipartita o una proyectada, respectivamente.
    """
    average_spl_por_nodo = matriz_spl.mean(axis=0) #Calculo el Average_SPL de cada nodo (media de cada columna de la matriz de SPLs)
    
    df_average_spl = pd.DataFrame({'Nodo': matriz_spl.index, 'AverageSPL': average_spl_por_nodo.values}) #creo un DataFrame con los resultados
    
     # Represento la distribución de los Average Shortest Path Lengths
    ax.hist(df_average_spl['AverageSPL'], bins=20, color='#79C4FF', edgecolor='black')
    ax.set_xlabel('Average Shortest Path Lengths', style='italic', fontsize=12)
    ax.set_ylabel('Nº nodos', fontsize=12)
    if bipartita == True:
        ax.set_title('Distribución de Average SPLs de ' + r'$\mathbf{' + nombre_var + '}$'+  '  en\n' + r'$\mathbf{' + " red "+ '}$'+ " "+ r'$\mathbf{' + "bipartita" + '}$' + " " + r'$\mathbf{' + nombre_graf + '}$',  fontsize=12)
    else:
         ax.set_title('Distribución de Average SPLs de ' + r'$\mathbf{' + "enfermedades" + '}$'+  ' en\n' + r'$\mathbf{' + " red "+ '}$'+ " "+ r'$\mathbf{' + "proyectada" + '}$' + " " + r'$\mathbf{' + nombre_graf + '}$',  fontsize=12)

# =================================================================================

def centrality_b_bip(graf, archivo, nombre_graf, nombre_var, ax, ax1):
    """
    Esta función calcula y representa la distribución de centralidad de intermediación 
    de dos grupos disjuntos de nodos en una red bipartita, siendo uno de esos grupos
    el correspondiente a enfermedades
    Datos de entrada:
    1. graf: Red bipartita
    2. archivo: Archivo con los datos sobre los enlaces entre los nodos de la red
    3. nombre_graf: Nombre de la red
    4. nombre_var: Nombre del grupo disjunto de nodos distinto a enfermedades
    5. ax: Variable empleada para la representación organizada de la primera distribución en un subplot
    6. ax1: Variable empleada para la representación organizada  de la segunda distribución en un subplot
    
    """
    #Calculo la centralidad de intermediación de todos los nodos del grafo
    bc = nx.betweenness_centrality(graf, k=None, normalized=True, weight=None, endpoints=False, seed=None)

    nodos_enf = set(archivo.iloc[:, 0]) #selecciono el set de nodos enfermedades en el archivo (que se encuentran en la primera columna)
    nodos_var = set(archivo.iloc[:, 1]) #selecciono el set de nodos del grupo variable en el archivo (que se encuentran en la segunda columna)

    #Filtro la centralidad de intermediación para ambos grupos de nodos
    bc_enf = {clave: bc[clave] for clave in nodos_enf if clave in bc}
    bc_var = {clave: bc[clave] for clave in nodos_var if clave in bc}

    #Creo DataFrames para la centralidad de intermediación de ambos grupos de nodos
    df_bc_enf = pd.DataFrame({'Nodo': list(bc_enf.keys()), 'Centralidad de intermediación': list(bc_enf.values())})
    df_bc_var = pd.DataFrame({'Nodo': list(bc_var.keys()), 'Centralidad de intermediación': list(bc_var.values())})

    #Represento la centralidad de intermediación de las enfermedades
    ax.hist(df_bc_enf['Centralidad de intermediación'], bins=20, color='#79C4FF', edgecolor='black')
    ax.set_xlabel('Centralidad de intermediación', style='italic', fontsize=10)
    ax.set_ylabel('Nº nodos', fontsize=10)
    ax.set_title('Distribución de centralidad de intermediación de ' + r'$\mathbf{' + "enfermedades" + '}$' +' en\n' + r'$\mathbf{' + "red" + '}$' + " " + r'$\mathbf{' + "bipartita" + '}$'+ " "+ r'$\mathbf{' + nombre_graf + '}$' , fontsize=10)

    #Represento la centralidad de intermediación del grupo disjunto de nodos distinto a enfermedades
    ax1.hist(df_bc_var['Centralidad de intermediación'], bins=20, color='#79C4FF', edgecolor='black')
    ax1.set_xlabel('Centralidad de intermediación', style='italic', fontsize=10)
    ax1.set_ylabel('Nº nodos', fontsize=10)
    ax1.set_title('Distribución de centralidad de intermediación de ' +  r'$\mathbf{' + nombre_var + '}$' + ' en\n' + r'$\mathbf{' + " red" + '}$' + " "+ r'$\mathbf{' + "bipartita" + '}$'+ " " + r'$\mathbf{' + nombre_graf + '}$', fontsize=10)

# =================================================================================

def centrality_b_proj(graf, nombre_graf, ax):
    """
    Esta función calcula y representa la distribución de centralidad de intermediación 
    de enfermedades en una red proyectada.
    Datos de entrada:
    1. graf: Red bipartita
    2. nombre_graf: Nombre de la red
    3. ax: Variable empleada para la representación organizada de la distribución en un subplot
    """
    #Calculo la centralidad de intermediación de todos los nodos del grafo
    bc= nx.betweenness_centrality(graf, k=None, normalized=True, weight=None, endpoints=False, seed=None)
    
    #Creo un DataFrame para la centralidad de intermediación de las enfermedades
    df_bc = pd.DataFrame({'Nodo': list(bc.keys()), 'Centralidad de intermediación': list(bc.values())})
    
    #Represento la centralidad de intermediación de las enfermedades
    ax.hist(df_bc['Centralidad de intermediación'], bins=20, color='#79C4FF', edgecolor='black')
    ax.set_xlabel('Centralidad de intermediación',style='italic', fontsize=10)
    ax.set_ylabel('Nº nodos', fontsize=10)
    ax.set_title('Distribución de centralidad de intermediación de ' + r'$\mathbf{' + "enfermedades" + '}$'+  ' en\n' + r'$\mathbf{' + " red "+ '}$'+ " "+ r'$\mathbf{' + "proyectada" + '}$' + " " + r'$\mathbf{' + nombre_graf + '}$',  fontsize=10)

# =================================================================================

def centrality_c_bip(graf, archivo, nombre_graf, nombre_var, ax, ax1):
    """
    Esta función calcula y representa la distribución de centralidad de cercanía 
    de dos grupos disjuntos de nodos en una red bipartita, siendo uno de esos grupos
    el correspondiente a enfermedades
    Datos de entrada:
    1. graf: Red bipartita
    2. archivo: Archivo con los datos sobre los enlaces entre los nodos de la red
    3. nombre_graf: Nombre de la red
    4. nombre_var: Nombre del grupo disjunto de nodos distinto a enfermedades
    5. ax: Variable empleada para la representación organizada de la primera distribución en un subplot
    6. ax1: Variable empleada para la representación organizada  de la segunda distribución en un subplot
    
    """
    #Calculo la centralidad de intermediación de todos los nodos del grafo
    cc = nx.closeness_centrality(graf, u=None, distance=None, wf_improved=True)

    nodos_enf = set(archivo.iloc[:, 0]) #selecciono el set de nodos enfermedades en el archivo (que se encuentran en la primera columna)
    nodos_var = set(archivo.iloc[:, 1]) #selecciono el set de nodos del grupo variable en el archivo (que se encuentran en la segunda columna)

    #Filtro la centralidad de cercanía para ambos grupos de nodos
    cc_enf = {clave: cc[clave] for clave in nodos_enf if clave in cc}
    cc_var = {clave: cc[clave] for clave in nodos_var if clave in cc}

    #Creo DataFrames para la centralidad de cercanía de ambos grupos de nodos
    df_cc_enf = pd.DataFrame({'Nodo': list(cc_enf.keys()), 'Centralidad de cercanía': list(cc_enf.values())})
    df_cc_var = pd.DataFrame({'Nodo': list(cc_var.keys()), 'Centralidad de cercanía': list(cc_var.values())})

    #Represento la centralidad de intermediación de las enfermedades
    ax.hist(df_cc_enf['Centralidad de cercanía'], bins=20, color='#79C4FF', edgecolor='black')
    ax.set_xlabel('Centralidad de cercanía', style='italic', fontsize=10)
    ax.set_ylabel('Nº nodos', fontsize=10)
    ax.set_title('Distribución de centralidad de cercanía de ' + r'$\mathbf{' + "enfermedades" + '}$' +' en\n' + r'$\mathbf{' + "red" + '}$' + " " + r'$\mathbf{' + "bipartita" + '}$'+ " "+ r'$\mathbf{' + nombre_graf + '}$' , fontsize=10)

    #Represento la centralidad de cercanía del grupo disjunto de nodos distinto a enfermedades
    ax1.hist(df_cc_var['Centralidad de cercanía'], bins=20, color='#79C4FF', edgecolor='black')
    ax1.set_xlabel('Centralidad de cercanía', style='italic', fontsize=10)
    ax1.set_ylabel('Nº nodos', fontsize=10)
    ax1.set_title('Distribución de centralidad de cercanía de ' +  r'$\mathbf{' + nombre_var + '}$' + ' en\n' + r'$\mathbf{' + " red" + '}$' + " "+ r'$\mathbf{' + "bipartita" + '}$'+ " " + r'$\mathbf{' + nombre_graf + '}$', fontsize=10)
    
# =================================================================================

def centrality_c_proj(graf, nombre_graf,ax):
    """
    Esta función calcula y representa la distribución de centralidad de cercanía 
    de enfermedades en una red proyectada.
    Datos de entrada:
    1. graf: Red bipartita
    2. nombre_graf: Nombre de la red
    3. ax: Variable empleada para la representación organizada de la distribución en un subplot
    """
    #Calculo la centralidad de cercanía de todos los nodos del grafo
    cc= nx.closeness_centrality(graf, u=None, distance=None, wf_improved=True)
    #Creo un DataFrame para la centralidad de cercanía de las enfermedades
    df_cc = pd.DataFrame({'Nodo': list(cc.keys()), 'Centralidad de cercanía': list(cc.values())})
    #Represento la centralidad de cercanía de alas enfermedades
    ax.hist(df_cc['Centralidad de cercanía'], bins=20, color='#79C4FF', edgecolor='black')
    ax.set_xlabel('Centralidad de cercanía',style='italic', fontsize=10)
    ax.set_ylabel('Nº nodos', fontsize=10)
    ax.set_title('Distribución de centralidad de cercanía de ' + r'$\mathbf{' + "enfermedades" + '}$'+  ' en\n' + r'$\mathbf{' + " red "+ '}$'+ " "+ r'$\mathbf{' + "proyectada" + '}$' + " " + r'$\mathbf{' + nombre_graf + '}$',  fontsize=10)

# =================================================================================