NORMALTEST

Overview

The NORMALTEST function tests whether a sample differs significantly from a normal distribution using the D’Agostino-Pearson omnibus test. This test is widely used in statistical analysis to verify the normality assumption that underpins many parametric statistical methods, including t-tests, ANOVA, and linear regression.

The D’Agostino-Pearson test combines two measures of distribution shape—skewness and kurtosis—into a single omnibus statistic. Skewness measures the asymmetry of a distribution, while kurtosis measures the “tailedness” or the weight of the tails relative to a normal distribution. By combining these two independent tests, the omnibus approach provides greater power to detect departures from normality than either test alone.

The test statistic K^2 is computed as:

K^2 = Z_s^2 + Z_k^2

where Z_s is the z-score from the skewtest (based on sample skewness) and Z_k is the z-score from the kurtosistest (based on sample excess kurtosis). Under the null hypothesis that the data comes from a normal distribution, K^2 follows a chi-squared distribution with 2 degrees of freedom.

This implementation uses the scipy.stats.normaltest function from the SciPy library. The test requires at least 8 observations to produce valid results, as the underlying skewness and kurtosis tests require sufficient sample size for reliable z-score transformations.

The function returns both the test statistic and the two-sided p-value. A small p-value (typically < 0.05) indicates evidence against the null hypothesis, suggesting the data does not follow a normal distribution. The original methodology was developed by D’Agostino (1971) and refined by D’Agostino and Pearson (1973) in their work on tests for departure from normality published in Biometrika.

This example function is provided as-is without any representation of accuracy.

Excel Usage

=NORMALTEST(data)
  • data (list[list], required): 2D array of numeric values to test for normality. Must contain at least 8 elements.

Returns (list[list]): 2D list [[statistic, p_value]], or error message string.

Examples

Example 1: Normal data (centered around zero)

Inputs:

data
0.1
0.2
0
-0.1
0.05
-0.05
0.15
-0.2

Excel formula:

=NORMALTEST({0.1;0.2;0;-0.1;0.05;-0.05;0.15;-0.2})

Expected output:

Result
0.26686858400566005 0.8750849671690968

Example 2: Non-normal bimodal distribution

Inputs:

data
1
1.1
1.2
1.3
5
5.1
5.2
5.3

Excel formula:

=NORMALTEST({1;1.1;1.2;1.3;5;5.1;5.2;5.3})

Expected output:

Result
8.380237218904178 0.015144488487033304

Example 3: Slightly skewed sequential data

Inputs:

data
0.5
0.6
0.7
0.8
0.9
1
1.1
1.2

Excel formula:

=NORMALTEST({0.5;0.6;0.7;0.8;0.9;1;1.1;1.2})

Expected output:

Result
0.6786792214509989 0.7122405234903403

Example 4: Uniformly spaced data

Inputs:

data
0.1
0.3
0.5
0.7
0.9
1.1
1.3
1.5

Excel formula:

=NORMALTEST({0.1;0.3;0.5;0.7;0.9;1.1;1.3;1.5})

Expected output:

Result
0.6786792214510033 0.7122405234903386

Python Code

from scipy.stats import normaltest as scipy_normaltest
import math

def normaltest(data):
    """
    Test whether a sample differs from a normal distribution (omnibus test).

    See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.normaltest.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        data (list[list]): 2D array of numeric values to test for normality. Must contain at least 8 elements.

    Returns:
        list[list]: 2D list [[statistic, p_value]], or error message string.
    """
    def to2d(x):
        return [[x]] if not isinstance(x, list) else x

    data = to2d(data)

    if not isinstance(data, list) or not all(isinstance(row, list) for row in data):
        return "Invalid input: data must be a 2D list."

    flat = []
    for row in data:
        for x in row:
            try:
                flat.append(float(x))
            except (TypeError, ValueError):
                return "Invalid input: data must be numeric."

    if len(flat) < 8:
        return "Invalid input: data must contain at least 8 elements."

    try:
        result = scipy_normaltest(flat)
        stat = float(result.statistic)
        pval = float(result.pvalue)
    except Exception as e:
        return f"scipy.stats.normaltest error: {e}"

    if math.isnan(stat) or math.isnan(pval) or math.isinf(stat) or math.isinf(pval):
        return "Invalid output: statistic or p-value is nan or inf."

    return [[stat, pval]]

Online Calculator