library(moments)
skewness(iris$Sepal.Length, na.rm = TRUE)[1] 0.3117531
Fix non-normal, skewed data so parametric tests apply — measure skewness, pick the right transformation, and confirm it worked
Learn how to transform skewed data to normality in R so parametric tests (t-test, ANOVA) apply. Measure skewness with the moments package, choose the right transformation (square-root, log or inverse, for positive or negative skew), and confirm the result with density plots and the before/after skewness.
June 23, 2026
July 7, 2026
moments::skewness(): 0 = symmetric, positive = right-skewed, negative = left-skewed; the larger the magnitude, the worse the departure.1/x (severe) — with a mirrored form for negative skew.Parametric methods such as the t-test and ANOVA assume the outcome is approximately normally distributed in each group. When the normality check fails because the data are skewed, transforming the variable can pull it back toward normal so the parametric test becomes valid.
Skewness measures the asymmetry of a distribution. A positively skewed (right-skewed) variable has a long right tail (Mode < Median < Mean); a negatively skewed (left-skewed) one has a long left tail. The sign and size of the skewness coefficient tell you the direction and severity — and therefore which transformation to reach for. This lesson works through it on the built-in USJudgeRatings data.
The moments package computes the skewness coefficient — here for iris$Sepal.Length:
A small positive value (~0.3) means a mild right skew — close enough to symmetric.
Pick the transformation by the severity of the skew, and use the mirrored form for negative skew (where max(x + 1) - x flips the tail before transforming):
| Severity | Positive (right) skew | Negative (left) skew |
|---|---|---|
| Moderate | sqrt(x) |
sqrt(max(x + 1) - x) |
| Greater | log10(x) |
log10(max(x + 1) - x) |
| Severe | 1 / x |
1 / (max(x + 1) - x) |
For a log transformation, every value must be positive — add a constant first if the data contain zeros or negatives.
We use USJudgeRatings and two of its columns: CONT (lawyer–judge contacts, positively skewed) and PHYS (physical ability, negatively skewed).
CONT PHYS
1.085972 -1.558215
CONT has skewness +1.09 (right-skewed) and PHYS −1.56 (left-skewed) — both well away from zero. Plot their densities against the normal curve to see it:
library(ggpubr)
df <- USJudgeRatings
ggarrange(
ggdensity(df, x = "CONT", fill = "#3a86d4", title = "CONT (right-skewed)") +
stat_overlay_normal_density(color = "red", linetype = "dashed"),
ggdensity(df, x = "PHYS", fill = "#3a86d4", title = "PHYS (left-skewed)") +
stat_overlay_normal_density(color = "red", linetype = "dashed"),
ncol = 2
)
Apply a log10 transformation — the plain form for the right-skewed CONT, the mirrored form for the left-skewed PHYS:
library(ggpubr)
df <- USJudgeRatings
df$CONT <- log10(df$CONT) # positive skew: plain log
df$PHYS <- log10(max(df$PHYS + 1) - df$PHYS) # negative skew: mirrored log
ggarrange(
ggdensity(df, x = "CONT", fill = "#3a86d4", title = "CONT (log10)") +
stat_overlay_normal_density(color = "red", linetype = "dashed"),
ggdensity(df, x = "PHYS", fill = "#3a86d4", title = "PHYS (mirrored log10)") +
stat_overlay_normal_density(color = "red", linetype = "dashed"),
ncol = 2
)
Confirm with the skewness of the transformed variables:
CONT PHYS
0.6555572 0.5824358
Both skews shrink in magnitude: CONT’s right skew eases (+1.09 → +0.66), and PHYS’s strong left skew drops to a mild right skew (−1.56 → +0.58) — much closer to symmetric, though the mirrored log slightly over-corrects PHYS past zero. Transformation reduces the skew but does not always land exactly on normal, which is why you re-check rather than assume.
Transform a skewed variable yourself and watch the skewness drop. The sandbox boots on first Run.
Ask Prova “my outcome is skewed and fails the normality test — measure its skewness and suggest the right transformation, then check whether it worked” — it answers with code you can run on your own data. The runtime is the judge. Ask Prova →
You logged data containing zeros or negatives. log10(0) is -Inf and log10() of a negative is NaN. Add a constant so all values are positive first (e.g. log10(x + 1)).
You used the positive-skew formula on negatively skewed data. Negative (left) skew needs the mirrored form transform(max(x + 1) - x), which flips the long tail before transforming. Check the sign of skewness() first.
The transformation didn’t help — or you don’t want to interpret transformed units. Transformation isn’t guaranteed to work, and it complicates interpretation (a difference in log10 units, not raw units). With samples larger than ~30–40 the central limit theorem often lets parametric tests cope with mild non-normality, so transforming may be unnecessary — run the test on both and compare.
Parametric tests (t-test, ANOVA, regression) assume an approximately normal outcome. When the data are skewed enough to violate that, a transformation (log, square-root, inverse) can reshape the distribution toward normal so the parametric test’s p-values are trustworthy — an alternative to switching to a non-parametric test.
Match it to the severity of the skew: square-root for moderate, log for greater, and inverse (1/x) for severe skew. Use the plain form for positive (right) skew and the mirrored form (transform(max(x + 1) - x)) for negative (left) skew. Check the result by re-computing skewness() and re-plotting against the normal curve.
Skewness measures asymmetry: 0 is perfectly symmetric, a positive value means a long right tail (right-skewed), and a negative value means a long left tail (left-skewed). The larger the magnitude, the further from normal — values beyond about ±1 indicate substantial skew worth addressing.
No. Transformation complicates interpretation and isn’t always successful. For the t/F family of tests, moderate non-normality is often tolerable, and with samples larger than ~30–40 the central limit theorem usually makes parametric tests valid anyway. Transform only when the violation is real and the test requires it — or consider a non-parametric alternative instead.
USJudgeRatings$CONT before and after a log10 transformation. Fill the blank. Did the skewness move toward 0?Fill the blank with log10. Compare the two skewness values. For question 2, recall that negative skew needs transform(max(x + 1) - x) to flip the long tail before transforming.
The log10 transformation reduced the skew. For question 2: a strongly left-skewed variable uses a mirrored transformation such as log10(max(x + 1) - x) — the mirror reflects the long left tail to the right so the log can compress it, which a plain log10(x) would not do.
You can now transform skewed data to normality in R: measure the skew with moments::skewness(), match a square-root, log or inverse transformation to its severity (mirrored for negative skew), and confirm with density plots and the recomputed skewness. Use it to rescue a parametric test when the normality assumption fails — but remember it complicates interpretation, and large samples often make it unnecessary.
Prove you can do it. Master the whole Statistical Assumptions in R series — track your path, build projects, and earn a certificate.
Go Pro — unlimited Prova on your own data and a verifiable certificate that proves the skill.
from $15/mo billed yearly
✓ You're Pro — keep going. The runtime is the judge.
Ready to level up?
Get new R & Python lessons by email
Practical, reproducible, no spam. Unsubscribe anytime.
Double opt-in. We never share your email.
Every result on this page was produced by the code shown, run at build time against a pinned R environment — edit any block and Run to reproduce it yourself.
@online{2026,
author = {},
title = {Transforming {Data} to {Normality} in {R:} {Log,}
{Square-Root} \& {Inverse}},
date = {2026-06-23},
url = {https://www.datanovia.com/learn/biostatistics/assumptions/data-transformation-in-r},
langid = {en}
}