Skip to main content

Averaging replicates

Technical replicates are several rows of the data table with the same sample_name: for example, the same solution measured in three wells. With Average technical replicates on, the rows of each sample are replaced by one row with the mean values, and the model is built on these averaged rows.

The option is in the preprocessing section of the analysis dialog and is off by default (average_replicates: false). It is available for all classification methods. PCA ignores it.

What is averaged​

  • Rows are grouped by the sample_name column, whatever the label column is.
  • Features: every selected feature column is averaged within the group.
  • Label: all rows of one sample must have the same label. If a sample has rows with different labels, the analysis stops with the error Group <n> has conflicting labels: [...]. Fix the labels in the data table and run the analysis again.

After averaging, the data set has one row per sample. The number of rows in the results (predictions, score plots, confusion matrices) is the number of samples, not the number of wells.

note

With LDA, averaging is not available when the label column is sample_name: every class would then have a single row, and LDA needs at least two rows per class. The dialog disables the checkbox and shows a warning.

Mean and median​

The averaging function supports the mean and the median, but the analyses always call it with the mean (method='mean'). There is no median option in the dialog.

Effect on cross-validation​

After averaging, each row is its own group. There are no replicates left that could leak between folds, so every CV scheme gives an honest estimate.

Averaging onAveraging off + Group K-Fold
Rows the model seesOne per sampleAll replicates
Measurement noiseReduced by averagingStays in the data; the model has to cope with it
Leakage between foldsNoneNone (replicates stay in one fold)
Rows for trainingFewerMore, but not independent
Prediction on new dataThe model expects averaged rows: turn on averaging in the prediction dialog tooThe model expects single wells

Use averaging when you want a model of samples and you will always measure new samples in replicates. Keep the replicates and use Group K-Fold when you want a model that works on single wells. More on the choice in Replicates and Group K-Fold.

Source code​

analysis.py · average_replicates() · lines 13–70
def average_replicates(X, y, groups, method='mean'):
"""
Average rows that belong to the same group (technical replicates).

Parameters:
-----------
X : ndarray (n_samples, n_features)
Feature matrix.
y : ndarray (n_samples,)
Labels.
groups : ndarray (n_samples,)
Group indices (same value = same sample_name).
method : str, default='mean'
Aggregation method for X (e.g., 'mean', 'median').

Returns:
--------
X_avg : ndarray (n_unique_groups, n_features)
Averaged feature matrix.
y_avg : ndarray (n_unique_groups,)
Labels for each group (majority vote, or raise if conflict).
new_groups : ndarray (n_unique_groups,)
New group indices (0..n_unique_groups-1) for possible future use.
"""
import numpy as np
from scipy.stats import mode

unique_groups = np.unique(groups)
n_groups = len(unique_groups)
n_features = X.shape[1]

X_avg = np.zeros((n_groups, n_features))
y_avg = np.zeros(n_groups, dtype=object)

for i, g in enumerate(unique_groups):
mask = groups == g
if method == 'mean':
X_avg[i] = np.mean(X[mask], axis=0)
elif method == 'median':
X_avg[i] = np.median(X[mask], axis=0)
else:
raise ValueError("method must be 'mean' or 'median'")

# Determine label for this group – majority vote, or raise if conflicting
labels = y[mask]
uniq, counts = np.unique(labels, return_counts=True)
if len(uniq) > 1:
# Option 1: raise an error (recommended for supervised tasks)
raise ValueError(f"Group {g} has conflicting labels: {uniq.tolist()}")
# Option 2: use majority vote (uncomment below)
# y_avg[i] = uniq[np.argmax(counts)]
else:
y_avg[i] = labels[0]

# New groups are just sequential (each row is its own group)
new_groups = np.arange(n_groups)

return X_avg, y_avg, new_groups

It is the first step of every run_<method>_analysis function. Example from LDA:

analysis.py · run_lda_analysis() · lines 998–1003
if parameters.get('average_replicates', False):
groups = parameters.get('groups')
if groups is None:
raise ValueError("'groups' must be provided when averaging replicates is enabled.")
X, y, new_groups = average_replicates(X, y, groups, method='mean')
parameters['groups'] = new_groups