NORMALITY

Normality tests assess whether sample values are plausibly drawn from a normal distribution.

Depending on the selected method, Pingouin applies tests such as Shapiro-Wilk or D’Agostino-Pearson. Results include test statistics, p-values, and a boolean decision at the specified significance level.

This wrapper accepts tabular data and returns Pingouin’s normality test table.

Excel Usage

=NORMALITY(data, dv, group, method, alpha)
  • data (list[list], required): Input table where the first row contains column names.
  • dv (str, required): Name of the dependent-variable column.
  • group (str, optional, default: ““): Grouping column name; use empty string to test without groups.
  • method (str, optional, default: “shapiro”): Normality method (for example shapiro or normaltest).
  • alpha (float, optional, default: 0.05): Significance level for decision threshold.

Returns (list[list]): 2D table containing normality test results.

Example 1: Grouped Shapiro tests

Inputs:

data dv group
score grp score grp
1.1 A
1.2 A
1.3 A
1.4 A
1.5 A
1.6 A
1.7 A
1.8 A
1.9 A
2 A
2.1 A
2.2 A
2.3 A
2.4 A
2.5 A
2.6 A
2.7 A
2.8 A
2.9 A
3 A
2.1 B
2.2 B
2.3 B
2.4 B
2.5 B
2.6 B
2.7 B
2.8 B
2.9 B
3 B
3.1 B
3.2 B
3.3 B
3.4 B
3.5 B
3.6 B
3.7 B
3.8 B
3.9 B
4 B
3.1 C
3.2 C
3.3 C
3.4 C
3.5 C
3.6 C
3.7 C
3.8 C
3.9 C
4 C
4.1 C
4.2 C
4.3 C
4.4 C
4.5 C
4.6 C
4.7 C
4.8 C
4.9 C
5 C

Excel formula:

=NORMALITY({"score","grp";1.1,"A";1.2,"A";1.3,"A";1.4,"A";1.5,"A";1.6,"A";1.7,"A";1.8,"A";1.9,"A";2,"A";2.1,"A";2.2,"A";2.3,"A";2.4,"A";2.5,"A";2.6,"A";2.7,"A";2.8,"A";2.9,"A";3,"A";2.1,"B";2.2,"B";2.3,"B";2.4,"B";2.5,"B";2.6,"B";2.7,"B";2.8,"B";2.9,"B";3,"B";3.1,"B";3.2,"B";3.3,"B";3.4,"B";3.5,"B";3.6,"B";3.7,"B";3.8,"B";3.9,"B";4,"B";3.1,"C";3.2,"C";3.3,"C";3.4,"C";3.5,"C";3.6,"C";3.7,"C";3.8,"C";3.9,"C";4,"C";4.1,"C";4.2,"C";4.3,"C";4.4,"C";4.5,"C";4.6,"C";4.7,"C";4.8,"C";4.9,"C";5,"C"}, "score", "grp")

Expected output:

W pval normal
0.960375 0.551372 true
0.960375 0.551372 true
0.960375 0.551372 true
Example 2: Overall Shapiro test without grouping

Inputs:

data dv
x x
1.1
1.2
1
1.3
1.1
1.2
1
1.3

Excel formula:

=NORMALITY({"x";1.1;1.2;1;1.3;1.1;1.2;1;1.3}, "x")

Expected output:

W pval normal
0.897413 0.273806 true
Example 3: Grouped normaltest method

Inputs:

data dv group method
value batch value batch normaltest
1.1 B1
1.2 B1
1.3 B1
1.4 B1
1.5 B1
1.6 B1
1.7 B1
1.8 B1
1.9 B1
2 B1
2.1 B1
2.2 B1
2.3 B1
2.4 B1
2.5 B1
2.6 B1
2.7 B1
2.8 B1
2.9 B1
3 B1
2.1 B2
2.2 B2
2.3 B2
2.4 B2
2.5 B2
2.6 B2
2.7 B2
2.8 B2
2.9 B2
3 B2
3.1 B2
3.2 B2
3.3 B2
3.4 B2
3.5 B2
3.6 B2
3.7 B2
3.8 B2
3.9 B2
4 B2
3.1 B3
3.2 B3
3.3 B3
3.4 B3
3.5 B3
3.6 B3
3.7 B3
3.8 B3
3.9 B3
4 B3
4.1 B3
4.2 B3
4.3 B3
4.4 B3
4.5 B3
4.6 B3
4.7 B3
4.8 B3
4.9 B3
5 B3

Excel formula:

=NORMALITY({"value","batch";1.1,"B1";1.2,"B1";1.3,"B1";1.4,"B1";1.5,"B1";1.6,"B1";1.7,"B1";1.8,"B1";1.9,"B1";2,"B1";2.1,"B1";2.2,"B1";2.3,"B1";2.4,"B1";2.5,"B1";2.6,"B1";2.7,"B1";2.8,"B1";2.9,"B1";3,"B1";2.1,"B2";2.2,"B2";2.3,"B2";2.4,"B2";2.5,"B2";2.6,"B2";2.7,"B2";2.8,"B2";2.9,"B2";3,"B2";3.1,"B2";3.2,"B2";3.3,"B2";3.4,"B2";3.5,"B2";3.6,"B2";3.7,"B2";3.8,"B2";3.9,"B2";4,"B2";3.1,"B3";3.2,"B3";3.3,"B3";3.4,"B3";3.5,"B3";3.6,"B3";3.7,"B3";3.8,"B3";3.9,"B3";4,"B3";4.1,"B3";4.2,"B3";4.3,"B3";4.4,"B3";4.5,"B3";4.6,"B3";4.7,"B3";4.8,"B3";4.9,"B3";5,"B3"}, "value", "batch", "normaltest")

Expected output:

W pval normal
2.90979 0.233425 true
2.90979 0.233425 true
2.90979 0.233425 true
Example 4: Custom alpha threshold

Inputs:

data dv group alpha
metric type metric type 0.01
1.1 T1
1.2 T1
1.3 T1
1.4 T1
1.5 T1
1.6 T1
1.7 T1
1.8 T1
1.9 T1
2 T1
2.1 T1
2.2 T1
2.3 T1
2.4 T1
2.5 T1
2.6 T1
2.7 T1
2.8 T1
2.9 T1
3 T1
2.1 T2
2.2 T2
2.3 T2
2.4 T2
2.5 T2
2.6 T2
2.7 T2
2.8 T2
2.9 T2
3 T2
3.1 T2
3.2 T2
3.3 T2
3.4 T2
3.5 T2
3.6 T2
3.7 T2
3.8 T2
3.9 T2
4 T2
3.1 T3
3.2 T3
3.3 T3
3.4 T3
3.5 T3
3.6 T3
3.7 T3
3.8 T3
3.9 T3
4 T3
4.1 T3
4.2 T3
4.3 T3
4.4 T3
4.5 T3
4.6 T3
4.7 T3
4.8 T3
4.9 T3
5 T3

Excel formula:

=NORMALITY({"metric","type";1.1,"T1";1.2,"T1";1.3,"T1";1.4,"T1";1.5,"T1";1.6,"T1";1.7,"T1";1.8,"T1";1.9,"T1";2,"T1";2.1,"T1";2.2,"T1";2.3,"T1";2.4,"T1";2.5,"T1";2.6,"T1";2.7,"T1";2.8,"T1";2.9,"T1";3,"T1";2.1,"T2";2.2,"T2";2.3,"T2";2.4,"T2";2.5,"T2";2.6,"T2";2.7,"T2";2.8,"T2";2.9,"T2";3,"T2";3.1,"T2";3.2,"T2";3.3,"T2";3.4,"T2";3.5,"T2";3.6,"T2";3.7,"T2";3.8,"T2";3.9,"T2";4,"T2";3.1,"T3";3.2,"T3";3.3,"T3";3.4,"T3";3.5,"T3";3.6,"T3";3.7,"T3";3.8,"T3";3.9,"T3";4,"T3";4.1,"T3";4.2,"T3";4.3,"T3";4.4,"T3";4.5,"T3";4.6,"T3";4.7,"T3";4.8,"T3";4.9,"T3";5,"T3"}, "metric", "type", 0.01)

Expected output:

W pval normal
0.960375 0.551372 true
0.960375 0.551372 true
0.960375 0.551372 true

Python Code

import pandas as pd
from pingouin import normality as pg_normality

def normality(data, dv, group='', method='shapiro', alpha=0.05):
    """
    Test normality by group or overall using Pingouin.

    See: https://pingouin-stats.org/build/html/generated/pingouin.normality.html

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

    Args:
        data (list[list]): Input table where the first row contains column names.
        dv (str): Name of the dependent-variable column.
        group (str, optional): Grouping column name; use empty string to test without groups. Default is ''.
        method (str, optional): Normality method (for example shapiro or normaltest). Default is 'shapiro'.
        alpha (float, optional): Significance level for decision threshold. Default is 0.05.

    Returns:
        list[list]: 2D table containing normality test results.
    """
    try:
        def to2d(x):
            return [[x]] if not isinstance(x, list) else x

        def build_dataframe(table):
            table = to2d(table)
            if not isinstance(table, list) or not table or not all(isinstance(row, list) for row in table):
                return None, "Error: data must be a non-empty 2D list"
            if len(table) < 2:
                return None, "Error: data must include a header row and at least one data row"

            headers = [str(h).strip() for h in table[0]]
            if any(h == "" for h in headers):
                return None, "Error: header row contains empty column names"
            if len(set(headers)) != len(headers):
                return None, "Error: header row contains duplicate column names"

            rows = []
            for row in table[1:]:
                if len(row) != len(headers):
                    return None, "Error: all data rows must match header width"
                rows.append([None if cell == "" else cell for cell in row])

            return pd.DataFrame(rows, columns=headers), None

        def dataframe_to_2d(df):
            out = [list(df.columns)]
            for values in df.itertuples(index=False, name=None):
                row = []
                for value in values:
                    if pd.isna(value):
                        row.append("")
                    elif isinstance(value, bool):
                        row.append(value)
                    elif isinstance(value, (int, float)):
                        row.append(float(value))
                    else:
                        row.append(str(value))
                out.append(row)
            return out

        frame, error = build_dataframe(data)
        if error:
            return error

        if dv not in frame.columns:
            return f"Error: dv column '{dv}' not found"

        if group is None or group == "":
            # Pingouin's normality() has a bug where dv is provided without a group
            # and it asserts that group is in the DataFrame columns (even when group is None).
            # Workaround: call it on the Series for the dv column.
            result = pg_normality(data=frame[dv], method=method, alpha=float(alpha))
        else:
            if group not in frame.columns:
                return f"Error: group column '{group}' not found"
            result = pg_normality(data=frame, dv=dv, group=group, method=method, alpha=float(alpha))

        return dataframe_to_2d(result)
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

Input table where the first row contains column names.
Name of the dependent-variable column.
Grouping column name; use empty string to test without groups.
Normality method (for example shapiro or normaltest).
Significance level for decision threshold.