Subject: Bug report: mean(..., trim) silently applies integer truncation
when k = trim * n is non-integer
Dear R Core Team,
I am writing to report a structural limitation in the mean(..., trim)
function in base R that has gone undetected for over three decades and
affects the overwhelming majority of practical uses of trimmed mean
computation.
--- NARRATIVE JUSTIFICATION ---
For more than three decades, researchers in econometrics, finance, public
health, environmental sciences and many other fields have trusted that
mean(..., trim = 0.05) applies exactly 5% trimming to their data. This
implicit trust is precisely what makes the integer truncation problem so
consequential: it affects any combination of n and trim that produces a
non-integer k = trim * n, which represents the overwhelming majority of
practical uses.
The problem has two manifestations. When k < 1 (Type A), R reduces k to
zero and returns the arithmetic mean, completely ignoring the requested
trimming without any warning. When k > 1 but non-integer (Type B), R trims
fewer observations than requested, with losses reaching 33% of the nominal
value, also without any warning.
The scope extends beyond direct users: packages such as WRS2 (hundreds of
thousands of downloads) use mean(x, tr) internally, propagating the
distortion silently to confidence intervals and hypothesis tests.
We are not requesting a change in the existing algorithm. We are requesting
transparency: a warning when the effective trimming differs from the
requested trimming, preserving complete backward compatibility.
The existence of sgmean as a separate package (CRAN v0.1.1) should not be
interpreted as a permanent solution. sgmean and mean(..., trim) produce
identical results whenever k = trim * n is an exact integer. The only
difference is that sgmean also handles non-integer k correctly. Directing
users to install a separate package to obtain the result that base R's own
mean() function should produce is not a solution — it is a transfer of
responsibility. The R Core Team has the unique opportunity to resolve this
at the root, ensuring that every R user benefits from correct trimmed mean
computation.
--- REPRODUCIBLE EXAMPLE ---
x <- c(850, 920, 980, 1050, 1120, 1180, 1250,
1320, 1400, 1480, 1550, 1700, 1850, 2100, 8500)
# TYPE A: k < 1
cat('k requested:', 0.05 * 15, '| k applied:', floor(0.05 * 15), '\n')
# k requested: 0.75 | k applied: 0
mean(x) # [1] 1816.667
mean(x, trim = 0.05) # [1] 1816.667 -- SAME: no trimming applied
# Expected (Statgraphics): 1499.074
# TYPE B: k > 1, non-integer
cat('k requested:', 0.10 * 15, '| k applied:', floor(0.10 * 15), '| Loss:
33.3%\n')
mean(x, trim = 0.10) # [1] 1376.923
# Expected (Statgraphics): 1365.833
--- CROSS-PLATFORM EVIDENCE ---
This bug exists identically in Python's scipy.stats.trim_mean, confirming
that integer truncation in trimmed mean computation is a systematic
limitation shared across the two most widely used scientific computing
environments in the world.
Software | Type A (k=0.75) | Type B (k=1.50)
R base mean(...,trim) | 1816.667 (wrong)| 1376.923 (wrong)
Python trim_mean | 1816.667 (wrong)| 1376.923 (wrong)
Statgraphics | 1499.074 (correct) | 1365.833 (correct)
sgmean CRAN v0.1.1 | 1499.074 (correct) | 1365.833 (correct)
--- PROPOSED SOLUTION ---
Minimum fix: add a warning in mean.default() when k = trim * n is
non-integer:
if (k != floor(k)) {
if (floor(k) == 0L) {
warning(paste0('trim * length(x) = ', k, ' < 1. ',
'No trimming applied (effective trim = 0%). ',
'Consider sgmean::sgmean() for proportional trimming.'))
} else {
warning(paste0('trim * length(x) = ', k, ' is not an integer. ',
'Effective trimming: ', round(floor(k)/length(x)*100,1), '% ',
'(requested: ', trim*100, '%, loss: ',
round((k-floor(k))/k*100,1), '%).'))
}
}
--- AVAILABLE SOLUTION ---
A corrected implementation is available on CRAN:
install.packages('sgmean')
DOI: https://doi.org/10.32614/CRAN.package.sgmean
GitHub: https://github.com/jcarlosgaviria/sgmean
--- R VERSION ---
R version 4.5.3 (2026-03-11 ucrt)
Platform: x86_64-w64-mingw32/x64
Best regards,
Juan C. Gaviria-Chaverra
ALIADO-Analytics and Research for Decision Making
Department of Industrial Engineering, Universidad de Antioquia
Medellin, Colombia
[email protected]
ORCID: 0009-0008-9403-416X
GitHub: https://github.com/jcarlosgaviria
--
"La información aquí contenida es para uso exclusivo de la persona o
entidad de destino. Está estrictamente prohibida su utilización, copia,
descarga, distribución, modificación y/o reproducción total o parcial, sin
el permiso expreso de Universidad de Antioquia, pues su contenido puede ser
de carácter confidencial y/o contener material privilegiado. Si usted
recibió esta información por error, por favor contacte en forma inmediata a
quien la envió y borre este material de su computador. Universidad de
Antioquia no es responsable por la información contenida en esta
comunicación, el directo responsable es quien la firma o el autor de la
misma."
______________________________________________
[email protected] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel