Correlation, regression and survival · Choose a method

How to compare IC50 values statistically: pIC50, independent experiments and the extra-sum-of-squares F test

Fit one curve per compound in each independent experiment, convert each IC50 to pIC50, and compare the pIC50s with a t-test; report the IC50 ratio with its 95% confidence interval. Pooling wells across experiments overstates certainty. R and Python code.

By Licklider · Published · Last reviewed · How this page was made · Markdown

On this page
  1. Why pIC50 and why one value per experiment
  2. Worked example: two compounds, four experiments
  3. Before you compare: is each IC50 trustworthy?
  4. Why overlapping confidence intervals do not settle it
  5. The extra-sum-of-squares F test: one experiment only
  6. Check what an AI assistant ran
  7. Report it
  8. References

Quick answer. Treat each independent experiment (a separate day, culture or passage, with its own dilutions) as one observation; replicate plates from the same culture and day count as one. In each experiment, fit a four-parameter logistic (4PL) curve per compound and, for curves that reach both plateaus, take each curve’s IC50 and convert it to pIC50 (−log₁₀ of the IC50 in mol/L). Compare the compounds’ pIC50s with a paired t-test if both were run in the same experiments, or Welch’s t-test if they were run separately. Report the ratio of IC50s (for example “2.6-fold less potent”) with its 95% confidence interval and the geometric mean IC50s; a single ratio describes the curves fairly only if they have similar slopes and plateaus. Do not pool every well from all experiments into one fit and test that fit, and do not judge the difference by whether two confidence intervals overlap.

Terms used below. IC50: the concentration that gives half the maximal inhibition; the relative IC50 is the 4PL midpoint between the plateaus, the absolute IC50 the concentration giving 50% of the control response. pIC50: −log₁₀(IC50 in mol/L); an IC50 of 100 nM is a pIC50 of 7.0, and a higher pIC50 means a more potent compound. Four-parameter logistic (4PL) curve: the usual sigmoid fit, with bottom, top, IC50 and Hill slope. Independent experiment: a repeat on a separate day, culture or passage, with its own dilutions. Technical replicates: wells of the same concentration in one experiment. Geometric mean: the mean on the log scale, back-transformed; for IC50s it is 10^(−mean pIC50). Extra-sum-of-squares F test: compares a fit with separate IC50s against one with a shared IC50. Welch’s t-test: compares two means without assuming equal spread. Lognormal: a quantity whose logarithm is normally distributed, as IC50s usually are. Hill slope: the steepness of the curve. Bend points: where the curve flattens into its upper and lower plateaus. df (degrees of freedom): a number printed with the test that reflects the amount of independent data. Holm’s adjustment: a correction for several planned comparisons. Random effect: a model term for variation between experiments. Plateau: the flat top or bottom of the curve. Relative potency: how many times more concentrated one compound must be to give the same effect as another. Likelihood ratio test: a test comparing how well two nested models fit. α: the false-positive threshold, usually 0.05. Nonlinear mixed-effects model: a curve fit across experiments with a random effect for each experiment.

Why pIC50 and why one value per experiment

IC50s spread out on a ratio scale: a compound that is twice as potent sits at half the concentration, whatever the starting value. Motulsky and colleagues note that “despite their ubiquity in pharmacological parameters (eg, EC50, IC50, Kd, and Km), lognormal distributions are often overlooked or misunderstood”, and recommend “the lognormal Welch’s t test … for comparing 2 unpaired groups, the lognormal ratio paired t test for paired comparisons, and lognormal ANOVA for ≥3 groups” (Motulsky et al. 2025). A t-test on pIC50 is exactly that lognormal test, and the curve itself is fitted on the log-concentration scale for the same reason (Ritz et al. 2015).

Within one experiment, you can fit the individual wells or their means: with equal replicates per concentration the IC50 estimate is the same, and the choice mainly affects the curve’s own standard error. Wells of one plate still share the cells, the dilution and the day; to show that the potency difference reappears, repeat the experiment. How reproducible a potency difference is depends on the number of independent experiments. The same rule is set out for all lab data in what counts as n.

Your data Analysis
Two compounds, each tested in the same independent experiments (same days or cultures) One pIC50 per compound per experiment → paired t-test on the differences
Two compounds tested in separate experiments One pIC50 per experiment → Welch’s t-test on pIC50
Three or more compounds One pIC50 per compound per experiment → Welch’s ANOVA on pIC50 (or a repeated-measures model if all share the experiments), then planned comparisons with Holm’s adjustment
A single experiment with two curves The extra-sum-of-squares F test describes that experiment only; repeat the experiment before claiming a difference

With two experiments the paired test has df = 1 and says almost nothing about variability; treat such a result as preliminary. With three to five experiments per compound, Welch’s test has little power, so report the interval for the ratio rather than relying on the p-value (t-test with n = 3, Welch vs Student’s t-test).

Worked example: two compounds, four experiments

Constructed data: compounds A and B, both on the same plate in each of four independent experiments (separate days), 9 concentrations from 1 nM to 10 µM, triplicate wells. For each compound, the triplicates were averaged and the means fitted with a 4PL curve per experiment. Stored code and data: viability.csv (made by make_data.py), analysis.py, analysis.R and the analysis output; both languages print the same output.

Experiment pIC50, A pIC50, B A − B
1 7.13 6.56 0.57
2 6.79 6.52 0.26
3 6.94 6.51 0.43
4 6.96 6.59 0.37

Geometric mean IC50: A 112 nM, B 285 nM.

Analysis IC50 ratio B/A (95% CI) Test
Paired t-test on pIC50 (same plates) 2.55 (1.6 to 4.1) t = 6.41, df = 3, p = 0.008
Welch’s t-test on pIC50, pairing ignored (for comparison only; use the paired test when experiments are shared) 2.55 (1.6 to 4.2) t = 5.69, df = 3.4, p = 0.008
Shortcut, not valid for a claim about the compounds: all 216 wells pooled, F test of one shared IC50 — F(1, 208) = 82.3, p < 10⁻¹⁵

Read the first row as “B was 2.6-fold less potent than A (95% CI 1.6 to 4.1-fold) across four independent experiments”. The spread of the A − B values shows how much the potency gap varied from plate to plate; that variation is what a reader needs to know. The per-experiment values are rounded; the tests use the unrounded fits, so A − B can differ by 0.01 from the values in the rounded columns.

The pooled shortcut treats 216 wells as 216 independent observations and reports overwhelming certainty. Its p-value reflects well-to-well noise, not whether the difference would reappear in a new experiment. In 10,000 simulated studies of this design with no true difference between the compounds (experiment-to-experiment SD of log₁₀ IC50 0.15 shared by both compounds, a further 0.08 per compound, well noise 5 percentage points, α = 0.05), the pooled F test declared them different in 17.1% of studies; the paired t-test on pIC50 did so in 4.8% (simulation.py, output).

import numpy as np, pandas as pd
from scipy import stats
from scipy.optimize import curve_fit

d = pd.read_csv("viability.csv")             # columns: experiment, compound, conc_M, well, viability
m = d.groupby(["experiment", "compound", "conc_M"], as_index=False).viability.mean()
def four_pl(logx, bottom, top, log_ic50, hill):
    return bottom + (top - bottom) / (1 + 10 ** ((logx - log_ic50) * hill))
p50 = {}
for (e, comp), g in m.groupby(["experiment", "compound"]):
    p, _ = curve_fit(four_pl, np.log10(g.conc_M), g.viability, p0=[0, 100, -7, 1], maxfev=10000)
    p50[(e, comp)] = -p[2]                    # pIC50; p0 = [bottom, top, log10 IC50, Hill] starting values
fits = pd.Series(p50).unstack()               # one row per experiment, one column per compound
diff = fits["A"] - fits["B"]
t = stats.ttest_1samp(diff, 0)                # paired t-test on pIC50
ci = t.confidence_interval()
print(f"IC50 ratio B/A = {10 ** diff.mean():.2f} (95% CI {10 ** ci.low:.1f} to {10 ** ci.high:.1f}), "
      f"t = {t.statistic:.2f}, df = {t.df:.0f}, p = {t.pvalue:.3f}")
# Compounds run in separate experiments instead: stats.ttest_ind(fits["A"].dropna(), fits["B"].dropna(), equal_var=False)
library(drc)
d <- read.csv("viability.csv")
m <- aggregate(viability ~ experiment + compound + conc_M, data = d, FUN = mean)
fits <- do.call(rbind, lapply(split(m, list(m$experiment, m$compound)), function(g)
  data.frame(experiment = g$experiment[1], compound = g$compound[1],
             pIC50 = -log10(coef(drm(viability ~ conc_M, data = g, fct = LL.4()))[["e:(Intercept)"]]))))
w <- reshape(fits, idvar = "experiment", timevar = "compound", direction = "wide")  # pairs by experiment
t <- t.test(w$pIC50.A, w$pIC50.B, paired = TRUE)   # paired t-test on pIC50
10^c(ratio = unname(t$estimate), t$conf.int)        # IC50 ratio B/A with 95% CI
t$p.value
# Compounds run in separate experiments instead: t.test(w$pIC50.A, w$pIC50.B)  (Welch by default)

The columns must be conc_M in mol/L (1 nM = 1e-9, 10 µM = 1e-5) and viability in percent of control (0–100); rename yours to match. To get percent of control from raw plate-reader signal, use 100 × (well − blank) / (mean untreated control − blank) on each plate. In GraphPad Prism, if you entered concentrations as log molar, the 4PL fit’s LogIC50 is −pIC50. These are condensed versions; the full scripts, which print every row of the tables above, are analysis.py and analysis.R, with the Python output and the R output. For three or more compounds, see Welch’s ANOVA. With SciPy, curve_fit fits the curve you define; it has no built-in 4PL or IC50 comparison, so write the model as above. In R, the drc package’s LL.4() model reports the IC50 as the parameter e (Ritz et al. 2015).

Before you compare: is each IC50 trustworthy?

  1. Both plateaus defined. Sebaugh’s guideline: “The relative EC50/IC50 should only be used if there are at least two assay concentrations beyond the lower and upper bend points” (Sebaugh 2011, abstract). If a curve never reaches its bottom, its IC50 is an extrapolation; report “IC50 > [highest concentration]” rather than a number. In a paired analysis, dropping it for one compound breaks the pair: drop that experiment for both compounds and say so, or ask a statistician about a censored-data analysis (one that uses “greater than” values).
  2. Relative or absolute IC50. The 4PL midpoint (relative IC50) and the concentration giving 50% of the control response (absolute IC50) differ when the curve does not fall to zero. Name the one you report, and use the same one for every compound.
  3. Same constraints for every fit. If you fixed the top at 100% or the bottom at 0% for one compound, do the same for the others; otherwise the IC50s answer different questions.
  4. Look at every fit. Plot each experiment’s points with its curve. A poor fit in one experiment gives a wild pIC50 that dominates a four-value t-test. Decide in advance what counts as a failed fit (for example: the fit does not converge, the IC50 lies outside the tested range, or a plateau is missing), and report how many experiments were excluded.
  5. Similar curve shapes. A single IC50 ratio is the potency difference at every response level only when the curves are parallel; Ritz and colleagues note that the relative potency is constant in that special case and “more often it will change” with the response level (Ritz et al. 2015, p. 10). Compare the Hill slopes and plateaus across compounds; if they differ, report the IC50s and the curves rather than one fold change.

Why overlapping confidence intervals do not settle it

Two compounds’ 95% intervals can overlap while the paired test on their difference is clearly significant, because the difference is estimated more precisely than either IC50 when experiment effects are shared. Overlap therefore does not mean “no difference”. Test the difference, and report the interval for the ratio, as in the table above (how to interpret a confidence interval).

The extra-sum-of-squares F test: one experiment only

The F test describes one experiment’s wells, not the compounds. Within that single experiment, comparing a fit with separate IC50s against one with a shared IC50 is a reasonable way to ask whether the two curves differ on that plate; for least-squares fits, GraphPad notes that “the extra sum-of-squares F test is equivalent to the likelihood ratio test” (GraphPad Prism Curve Fitting Guide). For a claim about the compounds, repeat the experiment and compare one pIC50 per experiment. If you need to use every well from several experiments in one model, a nonlinear mixed-effects model with the experiment as a random effect is the alternative (Jiang & Kopp-Schneider 2014).

Check what an AI assistant ran

  1. One fit to all wells from all experiments, or wells counted as n. Refit per experiment and test the pIC50s.
  2. A t-test on IC50 in nM instead of pIC50. Convert first.
  3. “No difference” concluded from overlapping confidence intervals. Test the difference.
  4. An IC50 from a curve with no lower plateau reported as a number. Check the concentration range.
  5. Unpaired test when both compounds shared experiments. Use the paired test on pIC50.
  6. A relative IC50 for one compound compared with an absolute IC50 for another. Use the same definition for all.

Report it

Methods:

For each independent experiment (n = [4]), concentration–response data (mean of [triplicate] wells) were fitted with a four-parameter log-logistic (LL.4) model ([drc 4.0.0 in R 4.3.3]), and the relative IC50 was converted to pIC50 (−log₁₀ IC50 [M]). Compounds tested on the same plates were compared with a paired t-test on pIC50. IC50s are reported as geometric means, and the difference as the IC50 ratio with its 95% confidence interval.

Results:

Compound B was less potent than compound A (geometric mean IC50 285 vs 112 nM; IC50 ratio 2.55, 95% CI 1.6 to 4.1; paired t-test on pIC50, t = 6.41, df = 3, p = 0.008; n = 4 independent experiments).

Replace the bracketed values with your own.

References

  • Motulsky HJ, Head T, Clarke PBS (2025). Analyzing lognormal data: a nonmathematical practical guide. Pharmacological Reviews 77:100049. doi:10.1016/j.pharmr.2025.100049
  • Ritz C, Baty F, Streibig JC, Gerhard D (2015). Dose-response analysis using R. PLOS ONE 10:e0146021. doi:10.1371/journal.pone.0146021
  • Sebaugh JL (2011). Guidelines for accurate EC50/IC50 estimation. Pharmaceutical Statistics 10:128–134. doi:10.1002/pst.426
  • Jiang X, Kopp-Schneider A (2014). Summarizing EC50 estimates from multiple dose-response experiments: a comparison of a meta-analysis strategy to a mixed-effects model approach. Biometrical Journal 56:493–512. doi:10.1002/bimj.201300123
  • GraphPad Prism Curve Fitting Guide: replicates that are not independent; approaches to comparing models. graphpad.com (checked 11 November 2026)

How this page was made

  • Written and published by Licklider. Recommendations cite peer-reviewed methods papers and official software documentation listed under References; cited passages were checked against the source text.
  • The worked example uses constructed data. Its numbers were produced by stored code (Python 3.13 with SciPy 1.18.1; R 4.3.3 with drc 4.0.0), and the two languages print identical output to the precision shown; the simulation was run in Python.
  • Separate review passes checked the statistics, the citations and readability before publication.