예제 #1
0
def global_recall(Theta_true, Theta_est, eps=1e-6):
    """Compute precision where true positives are the number of correctly estimated
    edges and the denominator (true positives + false positives) is the amount of
    detected edges.

    Parameters
    ----------
    Theta_true : 3D ndarray, shape (timesteps, n_vertices, n_vertices)
    Theta_est : 3D ndarray, shape (timesteps, n_vertices, n_vertices)
    eps : float
        threshold to consider precision entry as edge

    Returns
    -------
    float precision
    """
    assert len(Theta_est) == len(Theta_true)
    n = len(Theta_est)
    tps, exps = 0, 0
    for i in range(n):
        est_edges = set(get_edges(Theta_est[i], eps))
        gt_edges = set(get_edges(Theta_true[i], eps))
        n_joint = len(est_edges.intersection(gt_edges))
        tps, exps = tps + n_joint, exps + len(gt_edges)
    return tps / exps if exps > 0 else 1
예제 #2
0
def recall(Theta_true, Theta_est, eps=1e-6, per_ts=False):
    """Compute the recall of graph recovery given true and estimated precision matrices.
    It is possible to average the recall score over all timesteps or get a list of
    recall scores for each timestep. For a global recall score, i.e. weighted
    average of recall by the amount of detected and true edges, see `global_recall`.

    Parameters
    ----------
    Theta_true : 3D ndarray, shape (timesteps, n_vertices, n_vertices)
    Theta_est : 3D ndarray, shape (timesteps, n_vertices, n_vertices)
    eps : float
    per_ts : bool
        whether to compute average or per timestep recall

    Returns
    -------
    ndarray or float
        recall list or single precision value
    """
    assert len(Theta_est) == len(Theta_true)
    n = len(Theta_est)
    recall = [] if per_ts else 0
    for i in range(n):
        est_edges = set(get_edges(Theta_est[i], eps))
        gt_edges = set(get_edges(Theta_true[i], eps))
        n_joint = len(est_edges.intersection(gt_edges))
        latest = n_joint / len(gt_edges) if len(gt_edges) > 0 else 1
        recall += [latest] if per_ts else latest
    return np.array(recall) if per_ts else recall / n
예제 #3
0
def global_f_score(Theta_true, Theta_est, beta=1, eps=1e-6):
    """In line with `global_precision` and `global_recall`, compute the
    global f score given true and estimated graphical structures. The
    f score has the only parameter beta.

    Parameters
    ----------
    Theta_true : 3D ndarray, shape (timesteps, n_vertices, n_vertices)
    Theta_est : 3D ndarray, shape (timesteps, n_vertices, n_vertices)
    beta : float (default 1)
        beta value of the F score to be computed
    eps : float
    per_ts : bool
        whether to compute average or per timestep recall

    Returns
    -------
    float f-beta score
    """
    assert Theta_est.shape == Theta_true.shape
    d = Theta_true.shape[1]
    n = len(Theta_est)
    tps = fps = fns = tns = 0
    for i in range(n):
        est_edges = set(get_edges(Theta_est[i], eps))
        gt_edges = set(get_edges(Theta_true[i], eps))
        n_joint = len(est_edges.intersection(gt_edges))
        tps += n_joint
        fps += len(est_edges) - n_joint
        fns += len(gt_edges) - n_joint
        tns += d**2 - d - tps - fps - fns
    nom = (1 + beta**2) * tps
    denom = nom + beta**2 * fns + fps
    with np.errstate(divide='ignore', invalid='ignore'):
        f = np.nan_to_num(np.true_divide(nom, denom))
        return f
예제 #4
0
    def nxGraph(self):
        """Associates a networkX graph object with the corresponding
        precision matrix.

        Returns
        -------
        nxGraph: nx graph object
        """
        nxGraph = nx.Graph()
        p = self.Theta.shape[0]
        nxGraph.add_nodes_from(range(1, p + 1))
        edges = np.array(get_edges(self.Theta, self.eps)) + 1
        nxGraph.add_weighted_edges_from([(i, j, self.Theta[i-1, j-1])
                                         for i, j in edges])
        return nxGraph
예제 #5
0
def n_estimated_edges(Theta_est, eps=1e-6, per_ts=True):
    """Sums up the number of edges in each individual precision graph and by default
    sums the number for each graph over the whole timeseries. per_ts allows to change
    this so only a scalar is returned

    Parameters
    ----------
    Theta_est : 3D ndarray, shape (timesteps, n_vertices, n_vertices)
    eps : float
    per_ts : bool
        whether to return array or sum the amount of edges up

    Returns
    -------
    list for edges or int for global sum
    """
    n_edges = [len(get_edges(G, eps)) for G in Theta_est]
    return n_edges if per_ts else sum(n_edges)
예제 #6
0
def changepoint_density(Theta_est, eps=1e-6, per_ts=True):
    """Sums up the number of edges changed either per timestep or globally. A changed
    edge exists at t if the weight of edge changes between timestep t-1 and t where the
    prior graph is equal to the first, so no changepoint is possible at t=1.

    Parameters
    ----------
    Theta_est : 3D ndarray, shape (timesteps, n_vertices, n_vertices)
    eps : float
    per_ts : bool
        whether to return array or sum the amount of edges up

    Returns
    -------
    list for changepoints or int for global sum
    """
    cps = [len(get_edges(Theta_est[t-1] - Theta_est[t], eps))
           for t in range(1, len(Theta_est))]
    cps = [0] + cps
    return cps if per_ts else sum(cps)
예제 #7
0
 def n_edges(self):
     return len(get_edges(self.Theta, self.eps))
예제 #8
0
 def test_active_edges(self):
     n_verts, n_edges = 5, 3
     ER = ErdosRenyiPrecisionGraph(n_verts, n_edges)
     adj_list = get_edges(ER.Theta, eps=1e-7)
     self.assertEqual(len(adj_list), n_edges)