| name | temporal-genomics-temporal-clustering |
| description | Clusters genes by temporal expression profile shape using Mfuzz soft clustering, TCseq, and DEGreport degPatterns. Groups co-regulated genes into shared trajectory patterns via fuzzy c-means or hierarchical approaches. Use when categorizing temporally dynamic genes into response groups or identifying co-expression modules across time points. Requires temporally variable genes identified first (see differential-expression/timeseries-de). |
| tool_type | mixed |
| primary_tool | Mfuzz |
Version Compatibility
Reference examples tested with: numpy 1.26+, scanpy 1.10+, scikit-learn 1.4+
Before using code patterns, verify installed versions match. If versions differ:
- Python:
pip show <package> then help(module.function) to check signatures
- R:
packageVersion('<pkg>') then ?function_name to verify parameters
If code throws ImportError, AttributeError, or TypeError, introspect the installed
package and adapt the example to match the actual API rather than retrying.
Temporal Gene Clustering
"Group my time-course genes by expression pattern shape" -> Cluster temporally variable genes into co-expression modules by trajectory shape using fuzzy c-means (Mfuzz), hierarchical methods, or DTW-based approaches, revealing coordinated response patterns.
- R:
Mfuzz::mfuzz() for soft (fuzzy) temporal clustering
- Python:
sklearn.cluster.KMeans on z-scored time profiles for hard clustering
Groups genes with similar temporal expression dynamics into clusters, revealing shared regulatory programs and coordinated response patterns across time-course experiments.
Core Workflow
- Select temporally variable genes (pre-filtered by DE or variance)
- Standardize expression profiles (z-score across timepoints)
- Choose clustering method and number of clusters
- Assign genes to clusters (hard or soft membership)
- Validate clusters and run functional enrichment per cluster
Mfuzz (R/Bioconductor)
Goal: Group temporally variable genes into co-expression clusters by trajectory shape using fuzzy c-means, revealing shared regulatory programs.
Approach: Create an ExpressionSet from the time-series matrix, filter low-variance genes, standardize profiles, estimate the fuzzifier parameter, then run fuzzy c-means to assign soft cluster memberships.
Soft (fuzzy) c-means clustering assigns genes membership scores across all clusters, capturing genes with ambiguous temporal behavior.
Setup and Preprocessing
library(Mfuzz)
library(Biobase)
expr_mat <- as.matrix(read.csv('temporal_expression.csv', row.names = 1))
eset <- ExpressionSet(assayData = expr_mat)
eset <- filter.std(eset, min.std = 0.5)
eset <- standardise(eset)
Fuzzifier Estimation and Clustering
m <- mestimate(eset)
cat(sprintf('Estimated fuzzifier: %.2f\n', m))
cl <- mfuzz(eset, c = 8, m = m)
core_genes <- acore(eset, cl, min.acore = 0.5)
Visualization
mfuzz.plot2(eset, cl, mfrow = c(2, 4), time.labels = colnames(expr_mat),
centre = TRUE, x11 = FALSE)
overlap.plot(cl, over = overlap(cl), thres = 0.05)
Cluster Number Selection
validity_scores <- numeric()
for (k in 4:20) {
cl_k <- mfuzz(eset, c = k, m = m)
centroids <- cl_k$centers
dists <- as.matrix(dist(centroids))
diag(dists) <- Inf
validity_scores <- c(validity_scores, min(dists))
}
plot(4:20, validity_scores, type = 'b', xlab = 'Number of clusters' ylab
TCseq (R/Bioconductor)
Temporal clustering with fuzzy c-means and k-means on time-course sequencing data.
library(TCseq)
tc <- timeclust(expr_mat, algo = 'cm', k = 6, standardize = TRUE)
timeclustplot(tc, value = 'z-score', cols = 3)
tc_km <- timeclust(expr_mat, algo = 'km', k = 6, standardize = TRUE)
DEGreport degPatterns (R)
Automatic cluster number selection and publication-ready plots.
library(DEGreport)
patterns <- degPatterns(expr_mat, metadata = sample_info,
time = 'timepoint', col = 'condition', minc = 15)
cluster_df <- patterns$df
degPlotCluster(patterns$normalized, time = 'timepoint', color = 'condition')
tslearn (Python)
Time-series clustering with Dynamic Time Warping (DTW) distance.
import numpy as np
from tslearn.clustering import TimeSeriesKMeans
from tslearn.preprocessing import TimeSeriesScalerMeanVariance
from tslearn.utils import to_time_series_dataset
from sklearn.metrics import silhouette_score
expr_scaled = TimeSeriesScalerMeanVariance().fit_transform(expr_mat[:, :, np.newaxis])
model = TimeSeriesKMeans(n_clusters=8, metric='dtw', max_iter=50, random_state=42)
labels = model.fit_predict(expr_scaled)
from tslearn.metrics import cdist_dtw
dist_matrix = cdist_dtw(expr_scaled)
sil = silhouette_score(dist_matrix, labels, metric='precomputed')
Cluster Number Selection with Silhouette
sil_scores = []
for k in range(3, 16):
model = TimeSeriesKMeans(n_clusters=k, metric='softdtw', max_iter=30, random_state=42)
labels = model.fit_predict(expr_scaled)
sil_scores.append(silhouette_score(expr_scaled.squeeze(), labels, metric='euclidean'))
Method Comparison
| Method | Clustering Type | Distance | Best For |
|---|
| Mfuzz | Soft (fuzzy c-means) | Euclidean | Standard temporal profiling |
| TCseq | Soft or hard | Euclidean | RNA-seq time courses |
| DEGreport | Hierarchical | Correlation | Automatic k selection |
| tslearn | Hard (k-means) | DTW/soft-DTW | Phase-shifted profiles |
Tips
- Always standardize (z-score) before clustering; otherwise, highly expressed genes dominate
- Soft clustering (Mfuzz) is preferred when genes may participate in multiple temporal programs
- DTW-based clustering captures time-shifted patterns but is computationally expensive for >5000 genes
- Run functional enrichment (GO/GSEA) per cluster to interpret biological meaning
- Membership threshold of 0.5 for Mfuzz filters ~30-50% of genes as ambiguous; adjust if too stringent
Related Skills
- circadian-rhythms - Rhythm-specific clustering by phase
- trajectory-modeling - Continuous trajectory fitting before clustering
- differential-expression/timeseries-de - Upstream temporal DE for gene selection
- pathway-analysis/go-enrichment - Per-cluster functional enrichment