Normalised data and fold change · Choose a method
qPCR statistics: test ΔCt values, not 2^−ΔΔCt fold changes
Run the t-test on ΔCt values, one per biological sample, then report the 2^−ΔΔCt fold change with a back-transformed confidence interval. Worked example, simulation and code in R and Python.
On this page
Quick answer. Run the statistics on ΔCt values, one per biological sample, and report the fold change afterwards. Average the technical replicate wells of each sample first; compute ΔCt = Ct(target) − mean Ct(reference genes); compare two independent groups with a Welch t-test on ΔCt (ask for it explicitly: R’s
t.testgives Welch by default in R 4.3.3, SciPy needsequal_var=False); if each treated sample has its own matched control, use a paired t-test on ΔCt. Then report the fold change 2^−ΔΔCt, valid only when target and reference amplify with near-100%, approximately equal efficiencies, with the 95% confidence interval of ΔΔCt back-transformed the same way; otherwise multiply each Ct by log₂ of its assay’s amplification factor E (E = 2.0 at 100% efficiency) and run the same test. Lower ΔCt means more target transcript.
Terms used below. Ct (also Cq) is the cycle at which a well crosses the fluorescence threshold; at 100% efficiency, one cycle less means twice as much starting template. ΔCt is the target’s Ct minus the reference genes’ Ct in the same sample. ΔΔCt is the treated group’s mean ΔCt minus the control group’s. Fold change is 2^−ΔΔCt. A technical replicate is a repeat well of the same cDNA; a biological replicate is a separate animal, patient or culture. Efficiency is how close each cycle comes to doubling the product (100% = exact doubling); the amplification factor E is the fold increase per cycle (E = 2.0 at 100%), measured from a standard curve (a dilution series). Welch’s t-test compares two group means without assuming equal spreads; a paired t-test compares matched samples. A 95% confidence interval (CI) is the range of values compatible with the data; back-transformed means converted from the Ct scale to a fold change.
Four steps
- One value per biological sample. Average the technical wells of each gene within each sample. The sample — usually the animal — is n, because it is the unit that received the treatment (what counts as n).
- ΔCt per sample. Subtract the reference Ct from the target Ct. With two or more validated reference genes, use the mean of their Ct values: on the Ct scale the arithmetic mean is the same as the geometric mean of their quantities, which is how Vandesompele et al. (2002) combine reference genes.
- Test ΔCt. Two independent groups: Welch t-test (R’s
t.testdefault; in SciPy passequal_var=False, becausettest_indassumes equal variances by default). Matched pairs: paired t-test on ΔCt. Three or more groups: Welch’s ANOVA or a linear model on ΔCt. - Report on the fold-change scale. Fold change = 2^−ΔΔCt, valid only if target and reference efficiencies are approximately equal (otherwise use the efficiency-weighted ΔCt below); its 95% CI is 2^−(upper limit of ΔΔCt) to 2^−(lower limit), smaller number first (in the example 2^0.253 = 1.19 to 2^1.877 = 3.67). The interval is asymmetric and never reaches zero, which is what a ratio should look like.
Do this: keep every calculation on the Ct scale until the last line, and convert only the estimate and its interval.
Why the test belongs on ΔCt
Ct values are logarithms: a Ct is proportional to −log2 of the starting quantity. Differences of Ct are log fold changes, and means of Ct correspond to geometric means of quantities. Fold changes are the exponentiated version — skewed, bounded below by zero, and with “2× up” and “2× down” sitting at 2 and 0.5 instead of symmetrically around 1. Ganger et al. (2017) put it directly: staying in the log scale “opens up a larger world of parametric statistical tests that cannot be validly applied at the level of the relative expression ratio”. So run the test on ΔCt and convert only the result. Yuan et al. (2006) compared four analyses of the same qPCR data, including a ΔCt t-test, all estimating ΔΔCt and its interval on the Ct scale before any transformation.
To see what the common shortcuts do, we simulated 20,000 experiments per row with 5 mice per group and 3 technical wells per gene, using the variance components of the worked example below (sample input SD 0.5 cycles, biological SD 0.6, reference-gene SD 0.15, well SD 0.15; seed 20261110). The share of experiments with p < 0.05:
| Analysis | No true difference (false positives; intended 5%) | True 2-fold increase | True 2-fold decrease |
|---|---|---|---|
| Welch t-test on ΔCt, one value per mouse | 4.2% | 58.3% | 58.0% |
| Technical wells counted as n (15 per group) | 28.9% | 91.9% | 92.4% |
| Controls set to exactly 1, treated fold changes tested against 1 | 11.6% | 57.8% | 76.4% |
| Welch t-test on the fold changes | 3.4% | 46.9% | 46.6% |
Read across the rows. Counting wells as n raises false positives from 4.2% to 28.9%, because wells share everything except pipetting noise. Setting every control to 1 throws away the control group’s variability: false positives more than double (4.2% to 11.6%), and the test favours decreases over increases of the same size (76% vs 58%). Testing fold changes directly keeps false positives in check but loses power — 47% instead of 58% — because the skewed scale wastes information. Only the ΔCt test is calibrated and symmetric. Under these assumptions, 5 mice per group detected a true 2-fold change in 58% of experiments: plan more animals if a 2-fold effect is the smallest that matters (how many biological replicates). Welch’s 4.2% is slightly below 5% at this group size, the usual small cost of not assuming equal variances.
Do this: if your spreadsheet ends in a fold-change column with the control fixed at 1, go back one column to ΔCt and run the test there.
Worked example
Constructed data: Il6 expression in 5 control and 5 treated mice, three wells per gene, reference genes Actb and Gapdh. The true effect built into the data is a 2-fold increase; the random seed was fixed in advance, not chosen for the result. Download qpcr.csv (one row per well).
| Mouse | C1 | C2 | C3 | C4 | C5 | T1 | T2 | T3 | T4 | T5 |
|---|---|---|---|---|---|---|---|---|---|---|
| ΔCt (Il6 − mean of Actb, Gapdh) | 5.083 | 5.782 | 4.192 | 4.572 | 4.503 | 3.710 | 3.368 | 3.480 | 4.547 | 3.702 |
Control mean ΔCt 4.826 (SD 0.623), treated 3.761 (SD 0.463).
| Analysis | Result |
|---|---|
| Welch t-test on ΔCt (5 vs 5) | ΔΔCt = −1.065 (95% CI −1.877 to −0.253), t(7.39) = −3.07, p = 0.017 |
| Reported fold change (assumes equal efficiencies; treated mice have the lower ΔCt, so more Il6) | 2.09 (95% CI 1.19 to 3.67) |
| Wells as n (15 vs 15) | t(26.05) = −5.50, p = 0.000009 |
| Controls set to 1, one-sample t-test against 1 | t(4) = 4.45, p = 0.011 |
| Welch t-test on fold changes | difference of mean fold changes 1.10 (not a fold change; means 2.17 treated vs 1.07 control; 95% CI 0.35 to 1.85), p = 0.010 |
In this dataset every analysis gives p < 0.05, because the true effect is large. The shortcuts are still wrong: their p-values are not calibrated (table above), wells as n reports a precision the experiment does not have, and the fold-change analyses give a symmetric interval for a ratio. The ΔCt analysis gives the interval to report: the increase is between about 1.2-fold and 3.7-fold.
Python (SciPy 1.18.1):
import pandas as pd
from scipy import stats
d = pd.read_csv("qpcr.csv") # columns: group, mouse, gene, well, ct
m = d.groupby(["group", "mouse", "gene"])["ct"].mean().unstack("gene") # average technical wells
m["dct"] = m["Il6"] - (m["Actb"] + m["Gapdh"]) / 2 # target - mean of references
ctrl, trt = m.loc["control", "dct"], m.loc["treated", "dct"]
r = stats.ttest_ind(trt, ctrl, equal_var=False) # Welch t-test on Delta-Ct
ci = r.confidence_interval()
ddct = trt.mean() - ctrl.mean()
print(f"ddCt = {ddct:.3f}, t({r.df:.1f}) = {r.statistic:.2f}, p = {r.pvalue:.3f}")
print(f"fold change = {2**-ddct:.2f} (95% CI {2**-ci.high:.2f} to {2**-ci.low:.2f})")
R 4.3.3:
d <- read.csv("qpcr.csv") # columns: group, mouse, gene, well, ct
m <- aggregate(ct ~ group + mouse + gene, data = d, FUN = mean) # average technical wells
w <- reshape(m, idvar = c("group", "mouse"), timevar = "gene", direction = "wide")
w$dct <- w$ct.Il6 - (w$ct.Actb + w$ct.Gapdh) / 2 # target - mean of references (divide by your number of reference genes)
trt <- w$dct[w$group == "treated"]
ctrl <- w$dct[w$group == "control"]
tt <- t.test(trt, ctrl) # Welch is R's default; CI is for treated - control
ddct <- mean(trt) - mean(ctrl)
sprintf("ddCt = %.3f, t(%.1f) = %.2f, p = %.3f", ddct, tt$parameter, tt$statistic, tt$p.value)
sprintf("fold change = %.2f (95%% CI %.2f to %.2f)", 2^-ddct, 2^-tt$conf.int[2], 2^-tt$conf.int[1])
Both print ddCt = -1.065, t(7.4) = -3.07, p = 0.017 and fold change = 2.09 (95% CI 1.19 to 3.67).
Do this: export your Ct table in long format with the same columns (one row per well, for example control,C1,Il6,1,24.30), then change the gene names, the reference-averaging line (divide by your number of reference genes) and the group labels; for three or more groups use Welch’s ANOVA or a linear model on ΔCt instead of the t-test.
When 2^−ΔΔCt is valid: amplification efficiency
Livak and Schmittgen (2001), who described the method, state the condition plainly: “For the ΔΔCT calculation to be valid, the amplification efficiencies of the target and reference must be approximately equal.” Their derivation also uses an efficiency close to 100%, which they expect for short amplicons with optimised primer and Mg²⁺ concentrations. Check it with a dilution series: their test is that ΔCt stays flat across dilutions (slope near zero).
When the efficiencies differ, use an efficiency-corrected ratio (Pfaffl 2001). The same idea in a form you can test is the efficiency-weighted Ct of Ganger et al. (2017): multiply each Ct by log2 of that gene’s amplification factor per cycle (2.0 = 100%), then compute ΔCt and run the same Welch t-test. Get each assay’s amplification factor from a standard curve: regress Ct on log₁₀ of the input amount over a dilution series; E = 10^(−1/slope), so a slope of −3.32 gives E = 2.00 (100%). In R, with illustrative standard-curve values:
input <- c(1, 0.1, 0.01, 0.001, 0.0001)
ct <- c(18.1, 21.6, 25.1, 28.6, 32.1) # illustrative values for one assay
slope <- coef(lm(ct ~ log10(input)))[2]
E <- 10^(-1 / slope) # here slope -3.50, E = 1.93 (93% efficiency)
Then, with the amplification factors of all three assays:
E <- c(Il6 = 1.92, Actb = 2.00, Gapdh = 1.98) # amplification factor per cycle (2 = 100%)
w$dct_w <- w$ct.Il6 * log2(E["Il6"]) - (w$ct.Actb * log2(E["Actb"]) + w$ct.Gapdh * log2(E["Gapdh"])) / 2
t.test(dct_w ~ group, data = w) # then fold change = 2^-(difference), as above
With these illustrative efficiencies the example’s fold change becomes 2.01 (95% CI 1.19 to 3.39, p = 0.016) instead of 2.09. MIQE 2.0 (Bustin et al. 2025) goes further and recommends converting Cq values into efficiency-corrected quantities for reporting.
Do this: report each assay’s efficiency and how it was measured; if either assay is not near 100%, or target and reference differ by more than a few percent, use the efficiency-weighted ΔCt.
Other designs
- Matched samples (each treated culture has its own control from the same passage, or one plate per pair): paired t-test on ΔCt, which is a one-sample test of the within-pair ΔΔCt against 0 (R
t.test(trt, ctrl, paired = TRUE), Pythonstats.ttest_rel(trt, ctrl), with the two ΔCt vectors in matching pair order; paired vs unpaired). - Three or more groups or two factors: fit Welch’s ANOVA or a linear model with ΔCt as the outcome; report each comparison’s fold change from its estimated difference and interval, with a multiple-comparison correction where several comparisons are reported.
- Several samples per animal (for example two tissue pieces): average them, or use a mixed model on ΔCt.
- A clearly outlying sample with n = 5: check the wells and the melt curve first; if the value is real, a rank test on ΔCt (Mann–Whitney) is the fallback, at the cost of power (details).
- Undetermined Ct (no amplification): report how many wells and samples were non-detects per group, and analyse them explicitly rather than substituting a cycle number such as 40 or dropping samples silently; MIQE 2.0 (Bustin et al. 2025) asks for each target’s detection limit and dynamic range to be reported.
- Reference genes: pick ones whose expression the treatment does not change and confirm it in your data; a single unvalidated reference gene can give large normalisation errors (Vandesompele et al. 2002).
Do this: write the design (independent, matched, more groups, nested) in your analysis plan before you look at the fold changes.
“But Livak and Schmittgen say to use 2^−Ct”
Their section on statistical analysis says that “statistical data should be converted to the linear form by the 2^−CT calculation and should not be presented by the raw CT values” (Livak & Schmittgen 2001, p. 408). Use the linear scale for presentation, as they ask. Their example: 96 replicate reactions have a Ct CV of 0.971%, but 13.5% after conversion to 2^−Ct, so a Ct standard deviation makes replicates look tighter than they are.
Our reading — an interpretation, not their words — is that this is a presentation rule: it governs how results and their spread are presented, not which values enter a test, so run the test on ΔCt and convert only the estimate and interval. Their own worked method supports that reading: in §1.4 they estimate the error on the ΔΔCt scale and then evaluate 2^−ΔΔCt at ΔΔCt plus and minus the standard deviation, which “leads to a range of values that is asymmetrically distributed relative to the average value” (p. 406). This page does the same with a confidence interval: the test and interval are computed on ΔCt, and the result is presented on the linear scale as a fold change with an asymmetric interval. The same section adds that if the calibrator is reported as 1× without error, the calibrator’s error has to be carried into each ΔΔCt — the step that testing fold changes against 1 skips.
Do this: show individual animals’ fold changes in the figure, and put the test and interval from ΔCt in the text or legend.
Check what an AI assistant ran
Ask to see the code and look for four things:
- The unit: does the test run on 15 wells per group or 5 animals? Look for a grouping step (
groupby,aggregate) before the test. - The scale: is the t-test applied to a column built with
2**or2^? Move it to the ΔCt column. - The control: are control values replaced by 1 before testing? Use the control animals’ own ΔCt instead.
- The test:
scipy.stats.ttest_indwithoutequal_var=Falseruns Student’s test; R’st.testruns Welch by default. Ask for Welch, and for the fold-change CI back-transformed from the ΔΔCt interval.
Report it
Ct values of technical triplicates were averaged per sample. Il6 expression was normalised to the mean Ct of Actb and Gapdh (ΔCt). Groups were compared with a Welch t-test on ΔCt (n = 5 mice per group). Il6 expression was 2.09-fold higher in treated mice (95% CI 1.19 to 3.67; ΔΔCt = −1.065, t(7.4) = −3.07, p = 0.017), calculated as 2^−ΔΔCt. Amplification efficiencies were [x]% (Il6), [y]% (Actb) and [z]% (Gapdh), from [a five-point 1:10 dilution series], approximately equal and near 100%, so the 2^−ΔΔCt method applies.
Keep the efficiency sentence with your own measured values; if the efficiencies were not approximately equal, describe the efficiency-weighted ΔCt instead. Add the MIQE items reviewers look for (Bustin et al. 2009; Bustin et al. 2025): reference-gene validation, assay efficiencies with how they were measured, the number of biological and technical replicates, and the software used.
References
- Bustin SA, Benes V, Garson JA, et al. (2009). The MIQE guidelines: minimum information for publication of quantitative real-time PCR experiments. Clinical Chemistry 55:611–622. doi:10.1373/clinchem.2008.112797
- Bustin SA, Ruijter JM, van den Hoff MJB, et al. (2025). MIQE 2.0: revision of the minimum information for publication of quantitative real-time PCR experiments guidelines. Clinical Chemistry. doi:10.1093/clinchem/hvaf043
- Ganger MT, Dietz GD, Ewing SJ (2017). A common base method for analysis of qPCR data and the application of simple blocking in qPCR experiments. BMC Bioinformatics 18:534. doi:10.1186/s12859-017-1949-5
- Livak KJ, Schmittgen TD (2001). Analysis of relative gene expression data using real-time quantitative PCR and the 2^−ΔΔCT method. Methods 25:402–408. doi:10.1006/meth.2001.1262
- Pfaffl MW (2001). A new mathematical model for relative quantification in real-time RT–PCR. Nucleic Acids Research 29:e45. doi:10.1093/nar/29.9.e45
- Vandesompele J, De Preter K, Pattyn F, et al. (2002). Accurate normalization of real-time quantitative RT-PCR data by geometric averaging of multiple internal control genes. Genome Biology 3:research0034. doi:10.1186/gb-2002-3-7-research0034
- Yuan JS, Reed A, Chen F, Stewart CN (2006). Statistical analysis of real-time PCR data. BMC Bioinformatics 7:85. doi:10.1186/1471-2105-7-85
How this page was made
- Written and published by Licklider. Every method statement is cited to the original method papers, peer-reviewed comparisons or the MIQE guidelines listed under References; quoted passages were checked against the source text.
- The worked example uses constructed data. Its numbers and our simulation were produced by stored code (Python with SciPy 1.18.1; R 4.3.3), and Python and R agree to every printed digit.
- Separate review passes checked the statistics, the citations and readability before publication.