Calculate Jensen-Shannon divergence between query and reference gene expression profile.

def njsd(network, ref_gene_expression_dict, query_gene_expression_dict, gene_set):
    """Calculate Jensen-Shannon divergence between query and reference gene expression profile.
    """
    gene_jsd_dict = dict()
    reference_genes = ref_gene_expression_dict.keys()
    assert len(reference_genes) != 'Reference gene expression profile should have > 0 genes.'

    for gene in gene_set:
        if gene not in network.nodes:
            continue

        neighbors = find_neighbors(network, gene)

        query_expression_vec = get_neighbor_expression_vector(neighbors, query_gene_expression_dict)
        ref_expression_vec = get_neighbor_expression_vector(neighbors, ref_gene_expression_dict)
        assert len(query_expression_vec) == len(ref_expression_vec), 'Topology of reference network and query network differs. Please check.'

        # A gene which has non-expressed neighbors is ignored.
        if np.sum(query_expression_vec) == 0 and np.sum(ref_expression_vec) == 0:
            continue

        query_p_vec = exp2prob(query_expression_vec)
        ref_p_vec = exp2prob(ref_expression_vec)

        gene_jsd_dict[gene] = jsd(query_p_vec, ref_p_vec)

    return np.mean(list(gene_jsd_dict.values()))