Skip to content

metrics

dprime(y_true, y_pred, pmarg=0.01, outputs=['dprime', 'bias', 'accuracy'])

Calculate D-Prime for binary data. 70% for both classes is d=1.0488. Highest possible is 6.93, but effectively 4.65 for 99%

http://www.birmingham.ac.uk/Documents/college-les/psych/vision-laboratory/sdtintro.pdf

This function is not designed to behave as a valid 'Tensorflow metric'.

Parameters:

Name Type Description Default
y_true array-like

True labels.

required
y_pred array-like

Predicted labels.

required
pmarg float 0.01
outputs List[str]

list of outputs among 'dprime', 'bias', 'accuracy'

['dprime', 'bias', 'accuracy']

Returns:

Type Description
tuple

Calculated d-prime value.

Source code in indl/utils/metrics.py
def dprime(y_true, y_pred, pmarg: float = 0.01, outputs: List[str] = ['dprime', 'bias', 'accuracy']) -> tuple:
    """
    Calculate D-Prime for binary data.
    70% for both classes is d=1.0488.
    Highest possible is 6.93, but effectively 4.65 for 99%

    http://www.birmingham.ac.uk/Documents/college-les/psych/vision-laboratory/sdtintro.pdf

    This function is not designed to behave as a valid 'Tensorflow metric'.

    Args:
        y_true (array-like): True labels.
        y_pred (array-like): Predicted labels.
        pmarg:
        outputs: list of outputs among 'dprime', 'bias', 'accuracy'

    Returns:
        Calculated d-prime value.
    """

    import numpy as np
    from scipy.stats import norm

    # TODO: Adapt this function for tensorflow
    # y_pred = ops.convert_to_tensor(y_pred)
    # y_true = math_ops.cast(y_true, y_pred.dtype)
    # return K.mean(math_ops.squared_difference(y_pred, y_true), axis=-1)

    # TODO: Check that true_y only has 2 classes, and test_y is entirely within true_y classes.
    b_true = y_pred == y_true
    b_pos = np.unique(y_true, return_inverse=True)[1].astype(bool)

    true_pos = np.sum(np.logical_and(b_true, b_pos))
    true_neg = np.sum(np.logical_and(b_true, ~b_pos))
    false_pos = np.sum(np.logical_and(~b_true, b_pos))
    false_neg = np.sum(np.logical_and(~b_true, ~b_pos))

    tpr = true_pos / (true_pos + false_neg)
    tpr = max(pmarg, min(tpr, 1-pmarg))
    fpr = false_pos / (false_pos + true_neg)
    fpr = max(pmarg, min(fpr, 1 - pmarg))
    ztpr = norm.ppf(tpr, loc=0, scale=1)
    zfpr = norm.ppf(fpr, loc=0, scale=1)

    # Other measures of performance:
    # sens = tp ./ (tp+fp)
    # spec = tn ./ (tn+fn)
    # balAcc = (sens+spec)/2
    # informedness = sens+spec-1

    output = tuple()
    for out in outputs:
        if out == 'dprime':
            dprime = ztpr - zfpr
            output += (dprime,)
        elif out == 'bias':
            bias = -(ztpr + zfpr) / 2
            output += (bias,)
        elif out == 'accuracy':
            accuracy = 100 * (true_pos + true_neg) / (true_pos + false_pos + false_neg + true_neg)
            output += (accuracy,)

    return output

quickplot_history(history)

A little helper function to do a quick plot of model fit results.

Parameters:

Name Type Description Default
history tf.keras History required
Source code in indl/utils/metrics.py
def quickplot_history(history) -> None:
    """
    A little helper function to do a quick plot of model fit results.
    Args:
        history (tf.keras History):
    """
    import matplotlib.pyplot as plt
    if hasattr(history, 'history'):
        history = history.history
    hist_metrics = [_ for _ in history.keys() if not _.startswith('val_')]

    for m_ix, m in enumerate(hist_metrics):
        plt.subplot(len(hist_metrics), 1, m_ix + 1)
        plt.plot(history[m], label='Train')
        plt.plot(history['val_' + m], label='Valid.')
        plt.xlabel('Epoch')
        plt.ylabel(m)
    plt.legend()
    plt.tight_layout()
    plt.show()