Project: s41467-025-59812-0 | Function: disentangle_uncertainty (python)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Decomposes predictive uncertainty into aleatoric (data inherent) and epistemic (model) uncertainties from ensemble predictions. Computes entropy-based uncertainty measures and separates different types of uncertainty for active learning and model confidence assessment.

**KEY TERMS:** {
  "pred_list": "ensemble predictions",
  "predictive_uncertainty": "total prediction uncertainty",
  "aleatoric_uncertainty": "data inherent uncertainty",
  "epistemic_uncertainty": "model uncertainty"
}

**CONTEXT CODE:**         train_y = torch.tensor(labels[train_inds])
        test_x = torch.tensor(input_data[test_inds, ...])
        test_y = torch.tensor(labels[test_inds])

        train_dataset = TensorDataset(train_x, train_y)
        train_loader = DataLoader(train_dataset, batch_size=1024, shuffle=True)

        return train_x, train_y, test_x, test_y, train_loader

    else:
        train_x = input_data[train_inds, ...]
        train_y = labels[train_inds]
        test_x = input_data[test_inds, ...]
        test_y = labels[test_inds]

        return train_x, train_y, test_x, test_y, None


def data_standardization(input_data):
    input_data = input_data[:, np.where(input_data.std(axis=0) != 0)[0]]

    mean = np.mean(input_data, axis=0)
    std = np.std(input_data, axis=0)

    standardized_data = (input_data - mean) / std

    return standardized_data


def cal_DRFP(rxn_smis, nbits=2048):
    """

    Computes the DRFP of a list of reaction smiles
    The reaction smiles should be formulated in REACTANTS.REAGENTS>>PRODUCTS
    Parameters:
        rxn_smis - the list of reaction smiles
    Returns:
        fps - the drfp with nbits length 
    """
    fps = DrfpEncoder.encode(rxn_smis, n_folded_length=nbits)
    return fps


def enable_dropout(model):
    """ Function to enable the dropout layers during test-time """
    for m in model.modules():
        if m.__class__.__name__.startswith('Dropout'):
            m.train()


def disentangle_uncertainty(pred_list):
    """ Disentangle different types of uncertainties from a list of predictions.

    Parameters:
        pred_list: A list of prediction probabilities, where each element from different sampled models.

    Returns:
        mean: The mean of the prediction probabilities.
        predictive_uncertainty: The predictive uncertainty.
        aleatoric_uncertainty: The aleatoric uncertainty.
        epistemic_uncertainty: The epistemic uncertainty.
    """
    # MASKED: Decomposes predictive uncertainty into aleatoric (data inherent) and epistemic (model) uncertainties from ensemble predictions implementation
    raise NotImplementedError("This function is masked for testing purposes.")


Complete the function implementation replacing "raise NotImplementedError".