liberata_metrics.metrics package

Overview

The metrics module is the heart of the Liberata Scientometrics library. It provides a comprehensive suite of functions and classes for computing scientometric metrics on academic capital systems.

What are these metrics?

The Liberata system models academic knowledge production as a capital accrual system, where:

  • Manuscripts are publications that produce citations

  • Contributors are researchers who accrue academic capital from manuscripts

  • Capital represents the influence and returns that researchers accrue from their work

  • References encode the citation relationships between manuscripts

The metrics in this module help you understand:

  • How capital flows through the academic system

  • Portfolio performance and risk characteristics

  • Market dynamics and efficiency

  • System health and concentration

  • Individual and collective contributions

Key Submodules

Common Patterns

Most metric computation follows this pattern:

  1. Prepare data: Load or generate references and capital matrices

  2. Create metric object: Instantiate a metric class with your data

  3. Compute metrics: Call computation methods to get results

  4. Analyze results: Interpret and visualize the output

Example:

from liberata_metrics.metrics.portfolio_metrics import PortfolioMetrics
import numpy as np
from scipy import sparse

# Create example capital matrix (manuscripts × contributors)
capital = sparse.random(100, 50, density=0.1)

# Compute metrics
pm = PortfolioMetrics(capital)
total_capital = pm.total_capital()
volatility = pm.compute_volatility()

Module Contents

liberata_metrics.metrics.academic_capital(capital: spmatrix, contributor_index_map_subset: Dict[str, int]) float[source]

Compute total academic capital for a subset of contributors.

Parameters:
  • capital (scipy.sparse.spmatrix) – Sparse matrix where each row is a manuscript and each column is a contributor. Entries represent capital allocated from a contributor to a manuscript.

  • contributor_index_map_subset (Dict[str, int]) – Mapping from contributor identifier to the corresponding column index in capital. Only columns referenced by this mapping are included in the total.

Returns:

Total academic capital aggregated across the specified contributor columns. Returns 0.0 if the mapping is empty.

Return type:

float

Raises:

TypeError – If capital is not a scipy sparse matrix.

Notes

The function sums the selected columns of the sparse matrix and returns the scalar total.

liberata_metrics.metrics.allocation_weights(capital: spmatrix, contributor_index_map_subset: Dict[str, int]) Dict[int, float][source]

Compute allocation weights for each manuscript in a portfolio, i.e., the fraction of total portfolio capital contributed due to each manuscript. :param capital: Sparse matrix where each row represents a manuscript and each column represents a contributor.

Entries represent the amount of capital allocated from a contributor to a manuscript. This function requires a scipy sparse matrix input and will raise TypeError if given a non-sparse array.

Parameters:

contributor_index_map_subset (Dict[str, int]) – Mapping from contributor identifier to the corresponding column index in capital. Only the columns specified by the values of this mapping are considered. If this mapping is empty, the function returns an empty dictionary.

Returns:

A dictionary mapping manuscript row indices (int) to their allocation weight (float). Each weight equals the manuscript’s aggregated capital from the selected contributors divided by the total capital across the portfolio. Manuscripts with zero aggregated capital are omitted. If the total portfolio capital is zero, an empty dictionary is returned.

Return type:

Dict[int, float]

Raises:
  • TypeError – If capital is not a scipy sparse matrix.

  • IndexError, ValueError, or other slicing-related exceptions – May be raised if provided column indices are out of bounds or otherwise invalid. The function attempts a direct column slice and falls back to constructing the submatrix by stacking individual columns.

Notes

  • The returned weights sum to 1.0 up to floating-point precision when non-empty.

  • Implementation details: the function first tries to slice capital using the provided column indices. If slicing fails, it falls back to horizontally stacking individual columns via capital.getcol.

  • Output contains only manuscripts with non-zero aggregated capital.

Examples

>>> # capital: scipy CSR matrix with shape (num_manuscripts, num_contributors)
>>> # contributor_index_map_subset = {'alice': 0, 'bob': 2}
>>> allocation_weights(capital, {'alice': 0, 'bob': 2})
{0: 0.5, 3: 0.25, 7: 0.25}
liberata_metrics.metrics.compute_fair_marketprice(capital: spmatrix, mask_reviewers: slice, mask_replicators: slice, manuscript_memberships: spmatrix, contributor_index_map_subset: Dict[str, int], num_contributors: int) Tuple[spmatrix, spmatrix][source]

Compute tag-level fair market prices (FMP) for reviewers and replicators based on the capital allocated to these roles across all manuscripts. The function performs the following steps: 1. Masks the global capital allocation by reviewer and replicator roles using the provided

mask matrices (mask_reviewers and mask_replicators).

  1. Computes the per-manuscript capital allocated to reviewers and replicators using

    get_per_manuscript_cap, restricted to the specified subset of contributors.

  2. Aggregates the per-manuscript capital up to tags using the manuscript_memberships matrix.

  3. Divides the aggregated capital per tag by the number of manuscripts associated with each tag

    to yield the fair market price (FMP) for reviewers and replicators per tag.

Parameters:
  • capital (sparse.spmatrix) – Contributor-level capital matrix. Shape: (n_manuscripts, n_contributors).

  • mask_reviewers (sparse.spmatrix) – Manuscript-by-contributor mask indicating reviewer involvement. Shape: (n_manuscripts, n_contributors). Used to select reviewers’ share of capital per manuscript.

  • mask_replicators (sparse.spmatrix) – Manuscript-by-contributor mask indicating replicator involvement. Shape: (n_manuscripts, n_contributors). Used to select replicators’ share of capital per manuscript.

  • manuscript_memberships (sparse.spmatrix) – Tag-by-manuscript membership matrix (shape: n_tags x n_manuscripts). Used to aggregate per-manuscript capital up to tags. Membership entries may be binary or weighted.

  • contributor_index_map_subset (Dict[str, int]) – Mapping from contributor identifier (string) to column index in the mask matrices for the subset of contributors of interest. The function uses the mapped indices to select columns from mask_reviewers and mask_replicators.

Returns:

A tuple containing two sparse arrays (each of length n_tags): - reviewer_fmp: tagwise fair market price for reviewers. - replicator_fmp: tagwise fair market price for replicators.

Return type:

Tuple[sparse.spmatrix, sparse.spmatrix]

Raises:
  • ValueError – If input matrix/vector shapes are incompatible (e.g., contributor counts, manuscript counts, or tag counts do not align) the function may raise errors propagated from underlying sparse operations or from get_per_manuscript_cap.

  • KeyError – If contributor_index_map_subset contains indices that do not correspond to columns in the provided mask matrices, column selection may fail.

Notes

  • The function attempts a fast column-slicing of mask_reviewers and mask_replicators

    for the contributor subset and falls back to an explicit hstack/getcol approach if slicing is not supported.

  • Elementwise multiplications and sums assume broadcasting consistent with sparse matrix

    shapes: reviewer/replicator masks are treated as per-manuscript indicators and are multiplied with per-manuscript capital vectors produced by get_per_manuscript_cap.

  • manuscript_memberships is expected to map manuscripts to tags (rows correspond to tags).

  • The returned fair market price values are not normalized by the number of reviewers

    or replicators unless such normalization is performed earlier (e.g., in get_per_manuscript_cap).

  • All inputs are expected to be sparse-compatible to avoid dense expansion; be mindful of

    memory usage when converting between sparse and dense formats.

Examples

Shape conventions (illustrative): - mask_reviewers / mask_replicators: (n_manuscripts, n_contributors) - capital: (n_manuscripts, n_contributors) - contributor_index_map_subset: subset of contributor -> column index mappings - get_per_manuscript_cap(masked_capital, subset_map) -> returns array of length n_manuscripts - manuscript_memberships: (n_tags, n_manuscripts)

liberata_metrics.metrics.compute_relative_performance(shares: spmatrix, capital_history: List[spmatrix], time_history: List[float], manuscript_memberships: spmatrix, contributor_index_map_subset: Dict[str, int]) float[source]

Compute portfolio relative performance against manuscript-domain benchmarks.

This metric evaluates the weighted quality/performance of manuscripts held by a contributor-defined portfolio. For each manuscript in the portfolio, the manuscript expected return is divided by the expected return of its domain (as defined by manuscript tag memberships), then aggregated using portfolio manuscript weights.

Conceptually, the function computes:

rho_Pi = (1 / sum_{m in Pi} s_m) * sum_{m in Pi} s_m * (mu_m / mu_d(m))

where: - Pi is the set of manuscripts held by the portfolio, - s_m is the portfolio weight/share in manuscript m, - mu_m is the manuscript expected return, - mu_d(m) is the expected return of manuscript m’s domain/tag.

Processing overview

1. Infer portfolio manuscript weights with allocation_weights using the provided shares matrix and contributor subset. 2. For each manuscript in the inferred portfolio: - Estimate manuscript expected return from manuscript-level slices of

capital_history via get_expected_returns.

  • Identify the manuscript’s tag/domain membership from

    manuscript_memberships.

  • Build domain-level capital history using mix_by_tag and estimate

    domain expected return via get_expected_returns.

  • Accumulate the weighted ratio s_m * (mu_m / mu_d(m)).

  1. Normalize by total portfolio shares/weights.

param shares:

Sparse manuscript-by-contributor matrix of shares/weights used to infer the portfolio composition for contributor_index_map_subset. Must be compatible with allocation_weights indexing conventions.

type shares:

scipy.sparse.spmatrix

param capital_history:

Chronological sequence of sparse capital matrices used to estimate returns over time. Each entry should be aligned to the same manuscript and contributor indexing scheme.

type capital_history:

List[scipy.sparse.spmatrix]

param time_history:

Time points corresponding to capital_history. Must be the same length as capital_history and strictly increasing for return-per-time calculations in get_expected_returns.

type time_history:

List[float]

param manuscript_memberships:

Sparse tag-by-manuscript membership matrix of shape (n_tags, n_manuscripts) where entry [t, m] indicates membership of manuscript m in tag/domain t.

type manuscript_memberships:

scipy.sparse.spmatrix

param contributor_index_map_subset:

Mapping from contributor identifier to contributor column index for the portfolio entity being evaluated.

type contributor_index_map_subset:

Dict[str, int]

returns:

Relative performance score for the selected portfolio. Values above 1.0 indicate average outperformance versus domain baselines, while values below 1.0 indicate underperformance.

rtype:

float

raises TypeError:

If shares is not a scipy sparse matrix.

raises ValueError:

If contributor_index_map_subset is empty, or if called helper functions reject invalid input shapes/history lengths.

Notes

  • Portfolio manuscript membership is inferred from non-zero allocation

weights returned by allocation_weights. - Domain return extraction depends on manuscript_memberships and assumes consistent manuscript row indexing across all inputs. - The implementation currently propagates edge-case behavior from helper functions (for example, domain-return zero handling) rather than explicitly applying a zero-safe division at this level.

Examples

>>> rp = compute_relative_performance(
...     shares=shares,
...     capital_history=capital_history,
...     time_history=time_history,
...     manuscript_memberships=manuscript_memberships,
...     contributor_index_map_subset=subset_map,
... )
>>> isinstance(rp, float)
True
liberata_metrics.metrics.compute_risk_adjusted_excess_return(capital_history: List[spmatrix], time_history: List[float], manuscript_memberships: spmatrix, contributor_index_map_subset: Dict[str, int], manuscript_index: int) ndarray[source]

Compute manuscript-level risk-adjusted excess return (alpha).

For the selected manuscript, this function estimates:

alpha_m = mu_m - beta_m * mu_d(m)

where manuscript and domain expected returns are derived from capital_history and time_history using get_expected_returns, and beta_m is computed via compute_sensitivity.

Domain returns are constructed by: 1. extracting the manuscript’s tag/domain memberships from manuscript_memberships; 2. aggregating capital history by tag with mix_by_tag; and 3. selecting/summing the relevant domain rows for the manuscript.

Parameters:
  • capital_history (List[scipy.sparse.spmatrix]) – Chronological list of sparse capital matrices. Each matrix should use consistent manuscript and contributor indexing.

  • time_history (List[float]) – Time points corresponding to capital_history used to compute expected returns per unit time.

  • manuscript_memberships (scipy.sparse.spmatrix) – Sparse tag-by-manuscript matrix indicating manuscript-domain membership.

  • contributor_index_map_subset (Dict[str, int]) – Mapping from contributor identifier to contributor column index for the portfolio subset used in return calculations.

  • manuscript_index (int) – Row index of the manuscript for which to compute risk-adjusted excess return.

Returns:

Risk-adjusted excess return (alpha) for the specified manuscript.

Return type:

np.ndarray

Raises:
  • IndexError – If manuscript_index is out of bounds for any matrix in capital_history or for manuscript_memberships.

  • ValueError – Propagated from helper functions when histories are invalid (for example, length mismatches or insufficient points).

  • TypeError – Propagated from helper functions when non-sparse inputs are supplied where sparse matrices are expected.

Notes

  • This routine computes alpha for a single manuscript index.

  • If domain expected returns are constant/degenerate, sensitivity estimation

may be unstable depending on NumPy behavior.

Examples

>>> alpha = compute_risk_adjusted_excess_return(
...     capital_history=capital_history,
...     time_history=time_history,
...     manuscript_memberships=manuscript_memberships,
...     contributor_index_map_subset=subset_map,
...     manuscript_index=10,
... )
liberata_metrics.metrics.compute_risk_adjusted_relative_performance(capital_history: List[spmatrix], time_history: List[float], manuscript_memberships: spmatrix, contributor_index_map_subset: Dict[str, int]) float[source]

Compute risk-adjusted relative performance for an entire portfolio.

This function extends manuscript-level risk-adjusted excess return to a portfolio-level quantity by evaluating every manuscript row in the first capital matrix. For each manuscript, it computes the risk-adjusted excess return alpha_m and then normalizes it by the manuscript’s domain-level expected return mu_d(m). The final result is the sum of these manuscript-wise contributions.

Conceptually, the metric follows:

RARP = sum_{m in Pi} lpha_m / mu_d(m)

where: - Pi is the set of manuscripts in the portfolio, - alpha_m is the risk-adjusted excess return for manuscript m, - mu_d(m) is the expected return of the manuscript’s domain/tag.

The manuscript-level alpha_m values are computed by calling compute_risk_adjusted_excess_return for each manuscript index. Domain returns are then reconstructed from capital_history using mix_by_tag and the manuscript’s tag membership in manuscript_memberships.

Parameters:
  • capital_history (List[scipy.sparse.spmatrix]) – Chronological sequence of sparse capital matrices. The first matrix is used to determine the manuscript rows iterated over, and all matrices should share the same manuscript indexing convention.

  • time_history (List[float]) – Time points corresponding to capital_history. These are passed to get_expected_returns when computing manuscript and domain expected returns.

  • manuscript_memberships (scipy.sparse.spmatrix) – Sparse tag-by-manuscript membership matrix of shape (n_tags, n_manuscripts). Entry [t, m] indicates whether manuscript m belongs to tag/domain t.

  • contributor_index_map_subset (Dict[str, int]) – Mapping from contributor identifier to contributor column index for the subset of contributors used in the portfolio calculation.

Returns:

Risk-adjusted relative performance score for the portfolio.

Return type:

float

Raises:
  • ValueError – If contributor_index_map_subset is empty.

  • TypeError – May be raised by helper functions if the provided histories are not sparse-compatible.

  • IndexError – May be raised if manuscript indices are out of bounds for the supplied matrices.

Notes

  • The loop iterates over range(capital_history[0].shape[0]).

  • The current implementation accumulates alpha / domain_returns for

every manuscript and returns the total. - Division by zero is not handled explicitly here; any zero-domain-return behavior is inherited from the underlying arithmetic and helper calls.

Examples

>>> rarp = compute_risk_adjusted_relative_performance(
...     capital_history=capital_history,
...     time_history=time_history,
...     manuscript_memberships=manuscript_memberships,
...     contributor_index_map_subset=subset_map,
... )
>>> isinstance(rarp, float)
True
liberata_metrics.metrics.compute_risk_premiums(capital: spmatrix, mask_authors: slice, mask_reviewers: slice, mask_replicators: slice, contributor_index_map_subset: Dict[str, int], reviewer_fmp: sparray, replicator_fmp: sparray, manuscript_memberships: spmatrix) Tuple[sparray, sparray][source]

Compute tag-level risk premiums for reviewers and replicators corresponding to manuscripts authored by a given subset of contributors. This function calculates, for each tag, the difference between the capital that reviewers (or replicators) have obtained from manuscripts authored by the specified contributor subset and the fair market price (FMP) for that tag. The computation proceeds in these steps: 1. Select the subset of author columns from mask_authors and create a per-manuscript mask

indicating which manuscripts were authored by selected contributors.

  1. Mask the global capital allocation by reviewer/replicator role (mask_reviewers

    / mask_replicators) and compute the per-manuscript capital given for QC services, i.e., peer review and replication.

  2. Restrict reviewer/replicator per-manuscript capital to manuscripts authored by the

    selected contributors.

  3. Aggregate per-manuscript capital up to tags via manuscript_memberships (tags x manuscripts).

  4. Subtract the provided tag-level fair market price vectors (reviewer_fmp, replicator_fmp)

    to produce tag-level risk premiums.

Parameters:
  • capital (sparse.spmatrix) – Contributor-level capital vector or sparse column matrix. Expected length (or number of rows) equals the number of contributors (n_contributors). This represents the capital each contributor has available/allocated (units consistent with FMP).

  • mask_authors (sparse.spmatrix) – Manuscript-by-contributor binary (or weighted) mask indicating authorship. Shape: (n_manuscripts, n_contributors). Nonzero entry indicates that the contributor authored (or contributed to) the manuscript.

  • mask_reviewers (sparse.spmatrix) – Manuscript-by-contributor mask indicating reviewer involvement. Shape: (n_manuscripts, n_contributors). Used to select reviewers’ share of capital per manuscript.

  • mask_replicators (sparse.spmatrix) – Manuscript-by-contributor mask indicating replicator involvement. Shape: (n_manuscripts, n_contributors). Used to select replicators’ share of capital per manuscript.

  • contributor_index_map_subset (Dict[str, int]) – Mapping from contributor identifier (string) to column index in the mask matrices for the subset of contributors of interest. The function uses the mapped indices to select columns from mask_authors, mask_reviewers and mask_replicators.

  • reviewer_fmp (sparse.sparray) – Tag-level fair market price vector for reviewers. Shape: (n_tags,). Units must match those of capital after aggregation.

  • replicator_fmp (sparse.sparray) – Tag-level fair market price vector for replicators. Shape: (n_tags,). Units must match those of capital after aggregation.

  • manuscript_memberships (sparse.spmatrix) – Tag-by-manuscript membership matrix (shape: n_tags x n_manuscripts). Used to aggregate per-manuscript capital up to tags. Membership entries may be binary or weighted.

Returns:

A tuple containing two sparse arrays (each of length n_tags): - reviewer_risk_premium: tagwise (aggregated) reviewer capital on manuscripts authored by the selected contributors minus reviewer_fmp. - replicator_risk_premium: tagwise (aggregated) replicator capital on manuscripts authored by the selected contributors minus replicator_fmp.

Return type:

Tuple[sparse.sparray, sparse.sparray]

Raises:
  • ValueError – If input matrix/vector shapes are incompatible (e.g., contributor counts, manuscript counts, or tag counts do not align) the function may raise errors propagated from underlying sparse operations or from get_per_manuscript_cap.

  • KeyError – If contributor_index_map_subset contains indices that do not correspond to columns in the provided mask matrices, column selection may fail.

Notes

  • The function attempts a fast column-slicing of mask_authors for the contributor subset

    and falls back to an explicit hstack/getcol approach if slicing is not supported.

  • Elementwise multiplications and sums assume broadcasting consistent with sparse matrix

    shapes: author masks are treated as per-manuscript indicators and are multiplied with per-manuscript capital vectors produced by get_per_manuscript_cap.

  • manuscript_memberships is expected to map manuscripts to tags (rows correspond to tags).

  • The returned risk premium values are not normalized by the number of authors, reviewers,

    or replicators unless such normalization is performed earlier (e.g., in get_per_manuscript_cap).

  • All inputs are expected to be sparse-compatible to avoid dense expansion; be mindful of

    memory usage when converting between sparse and dense formats.

Examples

Shape conventions (illustrative): - mask_authors: (n_manuscripts, n_contributors) - mask_reviewers / mask_replicators: (n_manuscripts, n_contributors) - capital: (n_contributors,) or (n_contributors, 1) - contributor_index_map_subset: subset of contributor -> column index mappings - get_per_manuscript_cap(masked_capital, subset_map) -> returns array of length n_manuscripts - manuscript_memberships: (n_tags, n_manuscripts) - reviewer_fmp / replicator_fmp: (n_tags,)

liberata_metrics.metrics.compute_sensitivity(manuscript_expected_returns: float, domain_expected_returns: float) float[source]

Compute sensitivity (beta) of manuscript returns to domain returns.

This function returns the ratio of covariance between manuscript expected returns and corresponding domain expected returns to the variance of domain expected returns:

beta = Cov(mu_m, mu_d(m)) / Var(mu_d(m))

Parameters:
  • manuscript_expected_returns (float) – Manuscript expected return value(s). While typed as float in the current signature, this implementation delegates to NumPy covariance and variance routines and is typically meaningful when array-like values are provided.

  • domain_expected_returns (float) – Domain expected return value(s) aligned with manuscript_expected_returns.

Returns:

Sensitivity (beta) estimate. Returns 0.0 if domain variance is zero or very close to zero (within numerical epsilon).

Return type:

float

Notes

  • The implementation uses np.var(..., ddof=0), i.e., population variance.

This is appropriate when working with return series. - Returns 0.0 when domain variance is near zero to avoid division by zero.

Examples

>>> beta = compute_sensitivity(np.array([3.0, 5.0, 7.0, 9.0]), np.array([1.0, 2.0, 3.0, 4.0]))
>>> isinstance(beta, float)
True
liberata_metrics.metrics.compute_utility_function(capital_history: List[spmatrix], time_history: List[float], contributor_index_map_subset: Dict[str, int], risk_willingness: float) ndarray[source]

Compute mean-variance utility for a contributor subset over time.

This function derives expected returns from the provided capital history, estimates volatility over the same history, and combines the two using a standard quadratic utility formulation.

The computation proceeds in these steps: 1. Compute expected returns for the selected contributors using get_expected_returns. 2. Compute volatility for the same contributor subset using get_volatility. 3. Combine expected return and volatility with the risk willingness coefficient to produce a utility vector.

Parameters:
  • capital_history (List[sparse.spmatrix]) – Sequence of sparse capital matrices, ordered over time. Each matrix is expected to contain manuscript-by-contributor capital allocations for a single time point.

  • time_history (List[float]) – Time values corresponding to capital_history. These are passed to get_expected_returns when computing the expected return series.

  • contributor_index_map_subset (Dict[str, int]) – Mapping from contributor identifier to the corresponding column index in the capital matrices. Only the contributors in this subset are included in the utility calculation.

  • risk_willingness (float) – Risk preference coefficient used in the mean-variance utility formula. Larger values penalize volatility more strongly.

Returns:

A 1D NumPy array containing utility values for the selected contributors. The result is computed as:

utility = expected_returns - 0.5 * risk_willingness * volatility

Return type:

np.ndarray

Raises:
  • ValueError – If the input histories are incompatible in length or if the expected return / volatility helpers reject the provided data.

  • TypeError – If any history element is not sparse-compatible in a way that the downstream helper functions can process.

Notes

  • The function assumes the helper routines return aligned vectors for the

same contributor subset. - No normalization is performed here beyond the risk-adjusted utility expression. - The returned values are higher when expected returns increase and lower when volatility increases.

Examples

>>> utility = compute_utility_function(capital_history, time_history, contributor_index_map_subset, 1.5)
>>> utility.shape
(n_contributors,)
liberata_metrics.metrics.get_author_citations(capital: spmatrix, references: spmatrix, contributor_col: int) Dict[int, int][source]

For a contributor, returns authored manuscripts and corresponding citations

Parameters:
  • capital – Sparse matrix of shape (M, M + 3*C). Used to find which manuscripts this author contributed to.

  • references – Sparse citation matrix of shape (M, M).

  • contributor_col – Column index of the author in the contributor space (0-indexed, before the M offset). Pass contributor_index_map[id] at the call site.

Returns:

Dict mapping each manuscript index to its citation count.

liberata_metrics.metrics.get_citation_counts(references: spmatrix, manuscript_rows: list[int]) Dict[int, int][source]

Returns the number of incoming citations for each manuscript in the subset.

references[i, j] encodes a citation from paper j (citing) to paper i (cited), so the number of papers citing manuscript i is the number of non-zero entries in row i.

Parameters:
  • references – Sparse citation matrix of shape (M, M).

  • manuscript_row – List of row indices.

Returns:

Dict mapping each manuscript index to its incoming citation count (int).

liberata_metrics.metrics.get_g_index(capital: spmatrix, references: spmatrix, contributor_col: int) int[source]

Computes the g-index

Parameters:
  • capital – Sparse matrix of shape (M, M + 3*C). Used to find which manuscripts this author contributed to (author block: cols M to M+C).

  • references – Sparse citation matrix of shape (M, M).

  • contributor_col – Column index of the author in the contributor space (0-indexed, before the M offset). Pass contributor_index_map[id] at the call site.

Returns:

The g-index as an integer

liberata_metrics.metrics.get_h_index(capital: spmatrix, references: spmatrix, contributor_col: int) int[source]

Computes the h-index for a single author.

h is the largest integer such that h of the author’s papers each have at least h incoming citations.

Parameters:
  • capital – Sparse matrix of shape (M, M + 3*C). Used to find which manuscripts this author contributed to (author block: cols M to M+C).

  • references – Sparse citation matrix of shape (M, M).

  • contributor_col – Column index of the author in the contributor space (0-indexed, before the M offset). Pass contributor_index_map[id] at the call site.

Returns:

The h-index as an integer.

liberata_metrics.metrics.get_i10_index(capital: spmatrix, references: spmatrix, contributor_col: int) int[source]

Computes the i-10 index

Parameters:
  • capital – Sparse matrix of shape (M, M + 3*C). Used to find which manuscripts this author contributed to. The author block are the cols M to M+C because the capital matrix columns are blocked by author, peer reviewer, and replicator, with each contributor located in indentical indices within each block.

  • references – Sparse citation matrix of shape (M, M).

  • contributor_col – Column index of the author in the contributor space (0-indexed, before the M offset). Pass contributor_index_map[id] at the call site.

Returns:

The i-10 index as an integer

liberata_metrics.metrics.get_manuscript_memberships_matrix(manuscript_tags: Dict[str, sparray]) Tuple[spmatrix, List[str]][source]

Build a stacked membership matrix from a tag-to-membership mapping.

Parameters:

manuscript_tags (Dict[str, sparse.sparray]) – Mapping from tag name to a sparse one-hot row array of length num_manuscripts indicating which manuscripts belong to that tag.

Returns:

  • manuscript_memberships (scipy.sparse.spmatrix) – CSR matrix of shape (num_tags, num_manuscripts) where rows are tags and columns are manuscripts. Entry [i, j] is 1 if manuscript j belongs to tag i.

  • keys (List[str]) – Ordered list of tag names corresponding to the rows of the matrix.

liberata_metrics.metrics.get_per_manuscript_cap(capital: spmatrix, contributor_index_map_subset: Dict[str, int]) spmatrix[source]

Extract per-manuscript capital for a subset of contributors. :param capital: Sparse matrix where each row represents a manuscript and each column represents a contributor.

Entries represent the amount of capital allocated from a contributor to a manuscript.

Parameters:

contributor_index_map_subset (Dict[str, int]) – Mapping from contributor identifier to the corresponding column index in capital. Only the columns specified by the values of this mapping are considered.

Returns:

Sparse matrix containing the per-manuscript capital aggregated over the specified contributor columns.

Return type:

scipy.sparse.spmatrix

Raises:
  • TypeError – If capital is not a scipy sparse matrix.

  • ValueError – If contributor_index_map_subset is empty.

Notes

  • The returned matrix has the same number of rows as capital and a single column,

    where each entry represents the total capital for that manuscript from the specified contributors.

  • Implementation details: the function first tries to slice capital using the provided column indices. If slicing fails, it falls back to horizontally stacking individual columns via capital.getcol.

Examples

>>> # capital: scipy CSR matrix with shape (num_manuscripts, num_contributors)
>>> # contributor_index_map_subset = {'alice': 0, 'bob': 2}
>>> get_per_manuscript_cap(capital, {'alice': 0, 'bob   : 2})
<2x1 sparse matrix of type '<class 'numpy.float64'>'
    with 3 stored elements in Compressed Sparse Row format>
liberata_metrics.metrics.hhi_discrepancy(shares_matrix: spmatrix, mask_portfolio: slice) float[source]

Compute the discrepancy between the HHI of the field and that of the manuscript or portfolio. :param shares_matrix: Sparse matrix where each row represents a manuscript and each column represents an author.

Entries are the shares each author has for each given manuscript. This matrix should have all manuscripts in the field/discipline.

Parameters:

indices (np.array) – Array of indices of manuscripts in the shares_matrix that are to be considered in the HHI calculation.

Returns:

The HHID value, a measure of discrepancy between a portfolio and the industry. Higher values indicate an anomaly that should be further investigated.

Return type:

float

Examples

>>> hhi_discrepancy(shares_matrix, [1,2,5,6,7])
0.375
liberata_metrics.metrics.mix_by_role(capital, contributor_index_map_subset, mask_by_role, manuscript_memberships)[source]

Compute total capital and tag-wise capital mix for a specific role.

Parameters:
  • capital (scipy.sparse.spmatrix) – Full capital matrix

  • contributor_index_map_subset (Dict[str, int]) – Mapping from contributor identifier to column index

  • mask_by_role (slice) – Slice selecting the columns in the capital matrix that correspond to the role (Example: np.s_[:, 10:60] selects all rows and columns 10-59)

  • manuscript_memberships (scipy.sparse.spmatrix (num_tags, num_manuscripts)) – Entry [t, i] is 1 if manuscript i belongs to tag t

Returns:

  • rolewise_cap_tot (float) – Total capital attributed to this role across all manuscripts and contributors

  • rolewise_capmix_by_tag (sparse.sparray (num_tags, num_contributors)) – Entry [t, j] is the total capital of contributor j in manuscripts belonging to tag t

liberata_metrics.metrics.mix_by_tag(capital_sub: sparray, manuscript_memberships: spmatrix) sparray[source]

Find capital by tag and contributor

Parameters:
  • capital_sub (sparse.sparray (num_manuscripts, num_contributors)) – A capital matrix where entry [i, j] is the capital of contributor j on manuscript i

  • manuscript_memberships (scipy.sparse.spmatrix (num_tags, num_manuscripts)) – Matrix where entry [t, i] is 1 if manuscript i belongs to tag t and 0 otherwise

Returns:

Entry [t, j] is the total capital of contributor j across all manuscripts belonging to tag t

Return type:

sparse.sparray (num_tags, num_contributors)

liberata_metrics.metrics.portfolio_gini(capital: spmatrix, contributor_index_map_subset: Dict[str, int]) float[source]

Compute the Gini coefficient of a portfolio. :param capital: Sparse matrix where each row represents a manuscript and each column represents a contributor.

Entries represent the amount of capital allocated from a contributor to a manuscript.

Parameters:

contributor_index_map_subset (Dict[str, int]) – Mapping from contributor identifier to the corresponding column index in capital.

Returns:

The Gini coefficient, a measure of inequality in the portfolio. Returns 0.0 if the portfolio is empty or if there is only one manuscript.

Return type:

float

Raises:

TypeError – If capital is not a scipy sparse matrix.

Notes

  • The Gini coefficient is calculated based on the allocation weights.

Examples

>>> portfolio_gini(capital, {'alice': 0, 'bob': 2})
0.25
liberata_metrics.metrics.portfolio_hhi(capital: spmatrix, contributor_index_map_subset: Dict[str, int]) float[source]

Compute the Herfindahl-Hirschman Index (HHI) of a portfolio. :param capital: Sparse matrix where each row represents a manuscript and each column represents a contributor.

Entries represent the amount of capital allocated from a contributor to a manuscript.

Parameters:

contributor_index_map_subset (Dict[str, int]) – Mapping from contributor identifier to the corresponding column index in capital.

Returns:

The HHI value, a measure of concentration in the portfolio. Returns 0.0 if the portfolio is empty or if all weights are zero.

Return type:

float

Raises:

TypeError – If capital is not a scipy sparse matrix.

Notes

  • The HHI is calculated as the sum of the squares of the allocation weights.

Examples

>>> portfolio_hhi(capital, {'alice': 0, 'bob': 2})
0.375
liberata_metrics.metrics.portfolio_normalized_entropy(capital: spmatrix, contributor_index_map_subset: Dict[str, int]) float[source]

Compute the normalized entropy of a portfolio. :param capital: Sparse matrix where each row represents a manuscript and each column represents a contributor.

Entries represent the amount of capital allocated from a contributor to a manuscript.

Parameters:

contributor_index_map_subset (Dict[str, int]) – Mapping from contributor identifier to the corresponding column index in capital.

Returns:

The normalized entropy, a measure of diversity in the portfolio. Returns 0.0 if the portfolio is empty or if there is only one manuscript.

Return type:

float

Raises:

TypeError – If capital is not a scipy sparse matrix.

Notes

  • The normalized entropy is calculated based on the allocation weights.

Examples

>>> portfolio_normalized_entropy(capital, {'alice': 0, 'bob': 2})
0.85
liberata_metrics.metrics.query_portfolio_mix(capital: spmatrix, mask_authors: slice, mask_reviewers: slice, mask_replicators: slice, manuscript_memberships: spmatrix, contributor_index_map_subset: Dict[str, int], by: str = 'role') Tuple[List[float], List[sparray]][source]

Query the portfolio mix by specified criteria. This function computes allocation weights across a portfolio of manuscripts and aggregates them based on the specified grouping criterion (by role or by tag). :param capital: A scipy sparse matrix representing capital allocation. :type capital: sparse.spmatrix :param contributor_index_map_subset: A dictionary mapping contributor names

to their indices, representing a subset of all contributors.

Parameters:
  • manuscript_index_map (Dict[str, int]) – A dictionary mapping manuscript names to their indices.

  • manuscript_tags (Dict[str, sparse.spmatrix]) – A dictionary mapping tag names to sparse binary matrices indicating manuscript membership in each tag.

  • by (str, optional) – The criterion for grouping the portfolio mix. Either ‘role’ or ‘tag’. Defaults to ‘role’.

Returns:

A dictionary mapping role or tag names to their corresponding

allocation weights in the portfolio.

Return type:

dict[str, float]

Raises:

TypeError – If capital is not a scipy sparse matrix.

Notes

  • When by=’tag’: For each tag, a sparse mask identifies manuscripts belonging to that tag, and weights are intersected with the mask.

  • When by=’role’: Capital is subsampled by role, and allocation weights are computed for each role separately.

  • Returns an empty dictionary if no weights can be computed or if n <= 1.

liberata_metrics.metrics.role_based_proportional_loss(capital: spmatrix, retractions_capital: spmatrix, mask_by_role: slice, contributor_index_map_subset: Dict[str, int]) float[source]

Compute the proportion of capital loss for a specific role in the portfolio. :param capital: Sparse matrix where each row represents a manuscript and each column represents a contributor.

Entries represent the amount of capital accrued from a manuscript by a contributor.

Parameters:
  • retraction_capital (scipy.sparse.spmatrix) – Sparse matrix of the same shape as capital, representing capital associated with retracted manuscripts.

  • mask_by_role (scipy.sparse.spmatrix) – Sparse binary matrix indicating which entries in capital correspond to the specified role.

  • contributor_index_map_subset (Dict[str, int]) – Mapping from contributor identifier to the corresponding column index in capital.

Returns:

The proportion of capital loss for the specified role in the portfolio. Returns 0.0 if the total capital is zero.

Return type:

float

Raises:

TypeError – If capital or mask_by_role is not a scipy sparse matrix.

Notes

  • The function computes the total capital for the specified role and compares it to the overall total capital to determine the proportion of loss.

liberata_metrics.metrics.share_splits_inequality(portfolio: spmatrix) float[source]

Compute the Herfindahl-Hirschman Index (HHI) of a portfolio of manuscripts. :param portfolio: Sparse matrix where each row represents a manuscript and each column represents an author.

Entries are the shares each author has for each given manuscript.

Returns:

  • float – The mean HHI value, a measure of the typical concentration in the portfolio. Returns 0.0 if the portfolio is empty.

  • ——

  • TypeError – If portfolio is not a scipy sparse matrix.

Notes

  • The share splits inequality is calculated as the mean HHI of all provided manuscripts.

  • The HHI for a single manuscript is calculated as the sum of the squares of the share splits for that manuscript.

Examples

>>> share_splits_inequality(portfolio)
0.375