Process reference: statistical_analysis

Generated from the docstrings of vaft.process.statistical_analysis: 11 public functions. Each entry is what vaft.process.describe("statistical_analysis.<name>") prints. All process categories

Overview

The workflow behind the confinement-scaling study: take a table of shots with their engineering parameters and energy confinement time, take natural logarithms, fit ln tau_E = c0 + sum_i c_i ln p_i by ordinary least squares, and read the scaling exponents off the coefficients. Everything operates on pandas DataFrames whose columns are named by the caller; nothing here knows which columns exist except through the eng_params list it is handed.

Two functions are not statistics and are here for historical reasons: generate_core_profiles_history_dataframe builds the input table by running a workflow script, and confinement_time_histogram draws one. Both are documented as they are; their home is decided by #263.

SymbolMeaningUnit
tau_Eenergy confinement times
p_ian engineering parameterany
c_ithe scaling exponent of ``p_i``-
alphasignificance level-

Functions

analyze_significanceFlag which scaling exponents are statistically significant.
compute_metricsGoodness-of-fit metrics of the regression in original units. Convention
confinement_time_histogramPlot histograms of the scaling parameters in an m x n grid.
filter_dataframeDrop shots with unrealistic loss power and rectify the toroidal field sign. Convention
generate_core_profiles_history_dataframeBuild the scaling table by running the core-profiles history workflow.
get_correlation_matrixPearson correlation matrix of the log-transformed regressors and target.
get_individual_correlationsPearson correlation of each log regressor with the log target.
get_residualsResiduals of the log-space fit.
load_data_from_excelLoad a confinement-scaling table from an Excel file.
log_transformTake natural logarithms of the engineering parameters and the target. Convention
perform_ols_regressionFit the log-linear scaling by ordinary least squares. Convention

analyze_significance

Machine-independent source
analyze_significance(results, alpha=0.05)
Show source vaft/process/statistical_analysis.py, lines 406–446
def analyze_significance(results: RegressionResults, 
                         alpha: float = 0.05) -> Dict[str, bool]:
    """Flag which scaling exponents are statistically significant.

    Parameters
    ----------
    results : RegressionResults
        A fitted regression [-].
    alpha : float, optional
        Significance level; a coefficient with ``p < alpha`` is significant
        [-].

    Returns
    -------
    dict of str to bool
        Parameter name to whether its exponent is significant; a parameter
        absent from the fit is ``False`` [-].

    Defaults
    --------
    ``alpha = 0.05`` is the conventional literature value, no more.

    Applicability
    -------------
    Machine-independent.

    Limitations
    -----------
    A p-value from a small sample with correlated regressors overstates
    significance; see :func:`get_correlation_matrix` before trusting it.
    """
    significance = {}
    for param in results.eng_params:
        param_name = f'ln_{param}'
        if param_name in results.pvalues:
            pval = results.pvalues[param_name]
            significance[param] = pval < alpha
        else:
            significance[param] = False

    return significance

Flag which scaling exponents are statistically significant.

NameTypeUnitDescription
resultsRegressionResults-

A fitted regression.

alphafloat, optional-

Significance level; a coefficient with p < alpha is significant

Returns
—dict of str to bool-

Parameter name to whether its exponent is significant; a parameter absent from the fit is False.

Defaults · Applicability · Limitations

Defaults

alpha = 0.05 is the conventional literature value, no more.

Applicability

Machine-independent.

Limitations

A p-value from a small sample with correlated regressors overstates significance; see get_correlation_matrix before trusting it.

compute_metrics

Machine-independentConvention-sensitive source
compute_metrics(results, df, target_param='tauE_s')

Goodness-of-fit metrics of the regression in original units.

NameTypeUnitDescription
resultsRegressionResults-

A fitted regression.

dfpd.DataFrame-

The original table the regression was fitted from.

target_paramstr, optional-

Column name of the confinement time.

Returns
—dict of str to float-

R2, RMSE, MAE, Mean_Relative_Error_% and Median_Relative_Error_%.

Convention

Metrics are in the original units, so R2 here is not the rsquared of the log fit on the results object; the two differ and both are reported deliberately. RMSE and MAE carry the target’s unit, seconds for tauE_s, and are returned as plain floats.

Processing steps · Applicability · Limitations

Processing steps

  1. Exponentiate the fitted log values to get predicted confinement times.
  2. Select the actual values at the rows the fit used.
  3. Compute the metrics with sklearn.metrics and NumPy.

Applicability

Machine-independent.

Limitations

When the fitted values carry no index the actual values are truncated to the shorter length, which silently misaligns rows if any were dropped.

confinement_time_histogram

Machine-independent source
confinement_time_histogram(df, eng_params=None, m=None, n=None, figsize=None, bins=30, alpha=0.7, edgecolor='black', **kwargs)
Show source vaft/process/statistical_analysis.py, lines 699–748
def confinement_time_histogram(df: pd.DataFrame,
                               eng_params: Optional[List[str]] = None,
                               m: Optional[int] = None,
                               n: Optional[int] = None,
                               figsize: Optional[Tuple[float, float]] = None,
                               bins: Union[int, str] = 30,
                               alpha: float = 0.7,
                               edgecolor: str = 'black',
                               **kwargs):
    """Plot histograms of the scaling parameters in an ``m x n`` grid.

    Parameters
    ----------
    df : pd.DataFrame
        The scaling table [-].
    eng_params : list of str or None, optional
        Columns to plot; ``None`` for the renderer's default set [-].
    m : int or None, optional
        Grid rows [-].
    n : int or None, optional
        Grid columns [-].
    figsize : tuple of (float, float) or None, optional
        Figure size in inches [-].
    bins : int or str, optional
        Histogram bins, as Matplotlib takes them [-].
    alpha : float, optional
        Bar opacity [-].
    edgecolor : str, optional
        Bar edge colour [-].

    Returns
    -------
    matplotlib.figure.Figure
        The figure, as :func:`vaft.plot.history.confinement_time_histogram`
        returns it [-].

    Applicability
    -------------
    Machine-independent.

    Limitations
    -----------
    Rendering lives in :func:`vaft.plot.history.confinement_time_histogram`
    (issue #63); this is a compatibility shim that keeps the old call site
    and pulls Matplotlib in on call.  Its removal is tracked in #263.
    """
    from vaft.plot.history import confinement_time_histogram as _render

    return _render(df, eng_params=eng_params, m=m, n=n, figsize=figsize,
                   bins=bins, alpha=alpha, edgecolor=edgecolor, **kwargs)

Plot histograms of the scaling parameters in an m x n grid.

NameTypeUnitDescription
dfpd.DataFrame-

The scaling table.

eng_paramslist of str or None, optional-

Columns to plot; None for the renderer’s default set.

mint or None, optional-

Grid rows.

nint or None, optional-

Grid columns.

figsizetuple of (float, float) or None, optional-

Figure size in inches.

binsint or str, optional-

Histogram bins, as Matplotlib takes them.

alphafloat, optional-

Bar opacity.

edgecolorstr, optional-

Bar edge colour.

Returns
—matplotlib.figure.Figure-

The figure, as vaft.plot.history.confinement_time_histogram returns it.

Applicability · Limitations

Applicability

Machine-independent.

Limitations

Rendering lives in vaft.plot.history.confinement_time_histogram (issue #63); this is a compatibility shim that keeps the old call site and pulls Matplotlib in on call. Its removal is tracked in #263.

filter_dataframe

VEST-specificConvention-sensitive source
filter_dataframe(df)
Show source vaft/process/statistical_analysis.py, lines 126–171
def filter_dataframe(df: pd.DataFrame) -> pd.DataFrame:
    """Drop shots with unrealistic loss power and rectify the toroidal field sign.

    Parameters
    ----------
    df : pd.DataFrame
        The scaling table; ``Ploss_MW`` and ``Bt_T`` are acted on when present
        [-].

    Returns
    -------
    pd.DataFrame
        The filtered table [-].

    Processing steps
    ----------------
    1. Keep rows with ``Ploss_MW <= 3``.
    2. Replace ``Bt_T`` by its absolute value.

    Defaults
    --------
    The 3 MW ceiling is a hard-coded empirical cut from the study; its
    derivation is not recorded.  It is not a parameter.

    Convention
    ----------
    ``Bt_T`` is made positive regardless of the field direction actually run,
    so the fit sees magnitude only.  Any sign convention on the field is
    discarded here.

    Applicability
    -------------
    VEST-specific.  The ceiling and the column names are the VEST study's.

    Limitations
    -----------
    Assigns into the frame it was given (``df["Bt_T"] = ...``), so the
    caller's table may be modified and pandas may warn about a copy.
    """
    if 'Ploss_MW' in df.columns:
        df = df[df['Ploss_MW'] <= 3]

    # Ensure Bt_T is always positive
    if 'Bt_T' in df.columns:
        df['Bt_T'] = df['Bt_T'].abs()
    return df

Drop shots with unrealistic loss power and rectify the toroidal field sign.

NameTypeUnitDescription
dfpd.DataFrame-

The scaling table; Ploss_MW and Bt_T are acted on when present

Returns
—pd.DataFrame-

The filtered table.

Convention

Bt_T is made positive regardless of the field direction actually run, so the fit sees magnitude only. Any sign convention on the field is discarded here.

Processing steps · Defaults · Applicability · Limitations

Processing steps

  1. Keep rows with Ploss_MW <= 3.
  2. Replace Bt_T by its absolute value.

Defaults

The 3 MW ceiling is a hard-coded empirical cut from the study; its derivation is not recorded. It is not a parameter.

Applicability

VEST-specific. The ceiling and the column names are the VEST study’s.

Limitations

Assigns into the frame it was given (df["Bt_T"] = ...), so the caller’s table may be modified and pandas may warn about a copy.

generate_core_profiles_history_dataframe

VEST-specific source
generate_core_profiles_history_dataframe(max_shots=None, Z_eff=2.0)

Build the scaling table by running the core-profiles history workflow.

NameTypeUnitDescription
max_shotsint or None, optional-

Stop after this many shots; None for all.

Z_efffloat, optional-

Effective charge assumed for every shot when computing the ion contribution.

Returns
—pd.DataFrame-

One row per shot with the engineering parameters and tauE_s.

Raises

  • ImportError The workflow script cannot be found or loaded.
  • ValueError The script returned nothing.
Processing steps · Defaults · Applicability · Limitations · Provenance

Processing steps

  1. Locate workflow/automatic_pipeline_3_data_summary/gen_core_profiles_history.py relative to this file and load it by path.
  2. Call its generate_core_profiles_history_excel(max_shots, Z_eff).

Defaults

Z_eff = 2.0 is an assumed value, used because no shot-resolved measurement exists; its origin is not recorded.

Applicability

VEST-specific. The script reads the VEST database.

Limitations

Loads a workflow script by file path and inserts its directory into sys.path, which only works from a source checkout and is a layer-boundary violation: a process function reaching up into a workflow. Tracked in #263.

Provenance

  1. workflow/automatic_pipeline_3_data_summary/gen_core_profiles_history.py.

get_correlation_matrix

Machine-independent source
get_correlation_matrix(log_df, eng_params, target_param='tauE_s')
Show source vaft/process/statistical_analysis.py, lines 607–644
def get_correlation_matrix(log_df: pd.DataFrame, 
                          eng_params: List[str],
                          target_param: str = 'tauE_s') -> pd.DataFrame:
    """Pearson correlation matrix of the log-transformed regressors and target.

    Parameters
    ----------
    log_df : pd.DataFrame
        Output of :func:`log_transform` [-].
    eng_params : list of str
        Column names of the engineering parameters [-].
    target_param : str, optional
        Column name of the confinement time [-].

    Returns
    -------
    pd.DataFrame
        The correlation matrix over the available ``ln_`` columns; empty when
        fewer than two exist [-].

    Applicability
    -------------
    Machine-independent.

    Limitations
    -----------
    Pairwise-complete, as ``DataFrame.corr`` is; rows are not dropped
    consistently across pairs.
    """
    cols = [f'ln_{p}' for p in eng_params] + [f'ln_{target_param}']
    available_cols = [c for c in cols if c in log_df.columns]

    if len(available_cols) < 2:
        logger.warning("Not enough columns for correlation matrix")
        return pd.DataFrame()

    corr_df = log_df[available_cols].corr()
    return corr_df

Pearson correlation matrix of the log-transformed regressors and target.

NameTypeUnitDescription
log_dfpd.DataFrame-

Output of log_transform.

eng_paramslist of str-

Column names of the engineering parameters.

target_paramstr, optional-

Column name of the confinement time.

Returns
—pd.DataFrame-

The correlation matrix over the available ln_ columns; empty when fewer than two exist.

Applicability · Limitations

Applicability

Machine-independent.

Limitations

Pairwise-complete, as DataFrame.corr is; rows are not dropped consistently across pairs.

get_individual_correlations

Machine-independent source
get_individual_correlations(log_df, eng_params, target_param='tauE_s')
Show source vaft/process/statistical_analysis.py, lines 647–692
def get_individual_correlations(log_df: pd.DataFrame,
                               eng_params: List[str],
                               target_param: str = 'tauE_s') -> Dict[str, float]:
    """Pearson correlation of each log regressor with the log target.

    Parameters
    ----------
    log_df : pd.DataFrame
        Output of :func:`log_transform` [-].
    eng_params : list of str
        Column names of the engineering parameters [-].
    target_param : str, optional
        Column name of the confinement time [-].

    Returns
    -------
    dict of str to float
        Parameter name to its correlation with the target; NaN when the
        column is missing or fewer than two complete rows exist [-].

    Applicability
    -------------
    Machine-independent.
    """
    correlations = {}
    target_col = f'ln_{target_param}'

    if target_col not in log_df.columns:
        logger.warning(f"Target column {target_col} not found")
        return correlations

    for param in eng_params:
        param_col = f'ln_{param}'
        if param_col in log_df.columns:
            # Remove NaN values for correlation calculation
            valid_mask = ~(log_df[param_col].isna() | log_df[target_col].isna())
            if valid_mask.sum() > 1:
                corr, _ = pearsonr(log_df[param_col][valid_mask], 
                                  log_df[target_col][valid_mask])
                correlations[param] = corr
            else:
                correlations[param] = np.nan
        else:
            correlations[param] = np.nan

    return correlations

Pearson correlation of each log regressor with the log target.

NameTypeUnitDescription
log_dfpd.DataFrame-

Output of log_transform.

eng_paramslist of str-

Column names of the engineering parameters.

target_paramstr, optional-

Column name of the confinement time.

Returns
—dict of str to float-

Parameter name to its correlation with the target; NaN when the column is missing or fewer than two complete rows exist.

Applicability

Applicability

Machine-independent.

get_residuals

Machine-independent source
get_residuals(results)
Show source vaft/process/statistical_analysis.py, lines 587–604
def get_residuals(results: RegressionResults) -> pd.Series:
    """Residuals of the log-space fit.

    Parameters
    ----------
    results : RegressionResults
        A fitted regression [-].

    Returns
    -------
    pd.Series
        ``ln(actual) - ln(fitted)`` per row used in the fit [-].

    Applicability
    -------------
    Machine-independent.
    """
    return results.residuals

Residuals of the log-space fit.

NameTypeUnitDescription
resultsRegressionResults-

A fitted regression.

Returns
—pd.Series-

ln(actual) - ln(fitted) per row used in the fit.

Applicability

Applicability

Machine-independent.

load_data_from_excel

Machine-independent source
load_data_from_excel(filepath)
Show source vaft/process/statistical_analysis.py, lines 89–124
def load_data_from_excel(filepath: str) -> pd.DataFrame:
    """Load a confinement-scaling table from an Excel file.

    Parameters
    ----------
    filepath : str
        Path to the ``.xlsx`` file; one row per shot, columns as the study
        named them [-].

    Returns
    -------
    pd.DataFrame
        The table as read, untouched [-].

    Raises
    ------
    Exception
        Whatever ``pandas.read_excel`` raises, after logging it.

    Applicability
    -------------
    Machine-independent.  The tables under
    ``workflow/automatic_pipeline_3_data_summary/`` are VEST, but nothing here
    depends on that.

    Provenance
    ----------
    .. [1] The study notebook [NB]_.
    """
    try:
        df = pd.read_excel(filepath)
        logger.info(f"Loaded {len(df)} rows from {filepath}")
        return df
    except Exception as e:
        logger.error(f"Error loading Excel file: {e}")
        raise

Load a confinement-scaling table from an Excel file.

NameTypeUnitDescription
filepathstr-

Path to the .xlsx file; one row per shot, columns as the study named them.

Returns
—pd.DataFrame-

The table as read, untouched.

Raises

  • Exception Whatever pandas.read_excel raises, after logging it.
Applicability · Provenance

Applicability

Machine-independent. The tables under workflow/automatic_pipeline_3_data_summary/ are VEST, but nothing here depends on that.

Provenance

  1. The study notebook [NB].

log_transform

Machine-independentConvention-sensitive source
log_transform(df, eng_params, target_param='tauE_s')
Show source vaft/process/statistical_analysis.py, lines 262–312
def log_transform(df: pd.DataFrame, 
                  eng_params: List[str], 
                  target_param: str = 'tauE_s') -> pd.DataFrame:
    """Take natural logarithms of the engineering parameters and the target.

    Parameters
    ----------
    df : pd.DataFrame
        The scaling table [-].
    eng_params : list of str
        Column names of the engineering parameters [-].
    target_param : str, optional
        Column name of the confinement time [-].

    Returns
    -------
    pd.DataFrame
        Columns ``ln_<name>`` for each parameter and the target, same index as
        ``df``; a missing column becomes all-NaN with a warning [-].

    Convention
    ----------
    Natural logarithm, so the fitted coefficients are the exponents of a
    power law directly.  A value that is not strictly positive has no
    logarithm and becomes NaN, to be dropped by :func:`perform_ols_regression`.

    Applicability
    -------------
    Machine-independent.
    """
    log_df = pd.DataFrame(index=df.index)

    # Log transform engineering parameters
    for param in eng_params:
        if param in df.columns:
            # Handle NaN and non-positive values
            valid_mask = (df[param] > 0) & ~np.isnan(df[param])
            log_df[f'ln_{param}'] = np.where(valid_mask, np.log(df[param]), np.nan)
        else:
            logger.warning(f"Parameter {param} not found in DataFrame")
            log_df[f'ln_{param}'] = np.nan

    # Log transform target parameter
    if target_param in df.columns:
        valid_mask = (df[target_param] > 0) & ~np.isnan(df[target_param])
        log_df[f'ln_{target_param}'] = np.where(valid_mask, np.log(df[target_param]), np.nan)
    else:
        logger.warning(f"Target parameter {target_param} not found in DataFrame")
        log_df[f'ln_{target_param}'] = np.nan

    return log_df

Take natural logarithms of the engineering parameters and the target.

NameTypeUnitDescription
dfpd.DataFrame-

The scaling table.

eng_paramslist of str-

Column names of the engineering parameters.

target_paramstr, optional-

Column name of the confinement time.

Returns
—pd.DataFrame-

Columns ln_<name> for each parameter and the target, same index as df; a missing column becomes all-NaN with a warning.

Convention

Natural logarithm, so the fitted coefficients are the exponents of a power law directly. A value that is not strictly positive has no logarithm and becomes NaN, to be dropped by perform_ols_regression.

Applicability

Applicability

Machine-independent.

perform_ols_regression

Machine-independentConvention-sensitive source
perform_ols_regression(df, eng_params, target_param='tauE_s', dropna=True)

Fit the log-linear scaling by ordinary least squares.

NameTypeUnitDescription
dfpd.DataFrame-

The scaling table, in original units.

eng_paramslist of str-

Column names of the engineering parameters to regress on.

target_paramstr, optional-

Column name of the confinement time.

dropnabool, optional-

Drop rows with any NaN among the regressors or the target.

Returns
—RegressionResults-

The fitted statsmodels model with the log table, the parameter list and the target name; get_exponents() reads the scaling exponents off it.

Convention

The fit is in log space, so the coefficients are exponents and the residuals are relative errors. Metrics in original units come from compute_metrics, which exponentiates the fitted values.

Raises

  • ValueError No rows remain after dropping NaN.
Processing steps · Defaults · Applicability · Provenance

Processing steps

  1. log_transform the table.
  2. Select the ln_ regressors and the ln_ target.
  3. Drop rows with NaN, if dropna.
  4. Add an intercept column and fit statsmodels.api.OLS.

Defaults

dropna = True is a validated-workflow default; statsmodels would otherwise raise on NaN.

Applicability

Machine-independent.

Provenance

  1. The study notebook [NB].

results matching ""

    No results matching ""