Standard Benfords
Executive Summary

Executive Summary

Benford's Law read on 1,500 values from Transaction Amount

Values Analyzed
1500
MAD
0.0049
Conformity
close conformity
Chi-Square p
0.874
Digits Flagged
0
Verdict
conforms
Verdict: the first-digit distribution of Transaction Amount conforms. Across 1,500 values the mean absolute deviation from the Benford curve is 0.0049, which lands in Nigrini's close conformity band, and the chi-square goodness-of-fit gives p = 0.874. No individual digit stands out beyond ordinary sampling wobble. Benford deviation is a screening signal, not proof of fabrication — a deviating digit pattern says where an auditor should look, nothing more.
Suggested Interpretation

The short answer

The vendor invoice amounts conform to Benford's Law. Across 1,500 transactions, the first-digit distribution shows close conformity with a MAD of 0.0049 and a chi-square p-value of 0.874—no digits deviate beyond ordinary sampling variation. This pattern is consistent with organic, unmanipulated transaction data.

The detail

Mean absolute deviation of 0.0049 places the dataset squarely in Nigrini's close-conformity band, and the chi-square goodness-of-fit test yields p = 0.874, well above any threshold for concern. Zero individual digits are flagged; all standardized residuals remain within ±1.96 standard errors of their Benford expectations. The verdict is straightforward: conforms.

What this can't tell you

Benford conformity is a screening test, not a proof of integrity. It detects systematic digit-pattern manipulation but cannot uncover fraud schemes that happen to fall within the natural distribution, targeted falsification of individual invoices, or collusive schemes. A passing Benford screen is necessary but not sufficient for audit clearance.

Overview

Analysis Overview

Benford's Law screening of 1,500 values from Transaction Amount.

N Observations1500
Mad0.0049
Digits Flagged0
Suggested Interpretation

The short answer

The vendor invoice amounts follow the natural pattern predicted by Benford's Law, with no evidence of systematic manipulation or fabrication. Digit 1 appears 29.3 percent of the time (expected 30.1 percent) and digit 9 appears 5.2 percent (expected 4.6 percent)—minor variations consistent with random sampling from a genuine transaction pool.

The detail

Benford's Law screening compares observed first-digit distributions against the log₁₀(1 + 1/d) curve, which models how organically generated amounts naturally arise. The mean absolute deviation (MAD) of 0.0049 falls within Nigrini's close-conformity band. Chi-square goodness-of-fit yields p = 0.874, indicating no systematic departure from expectation. All 1,500 analyzed values track the expected downward slope from 30.1 percent at digit 1 to 4.6 percent at digit 9. This is the signature of unmanipulated transaction data.

What this can't tell you

Benford conformity rules out certain broad manipulation patterns (e.g., wholesale round-number entry) but cannot detect small-scale targeted fraud, collusion-based schemes, or invoices falsified within the natural digit distribution. This screen is a negative test: it identifies where to look, not what was done.

Data Preparation

Data Quality

How the amounts were cleaned before digit extraction.

Initial Rows1535
Final Rows1500
Rows Removed35
Suggested Interpretation

The short answer

Of 1,535 rows loaded, 1,500 entered the screen. Fifteen blank or non-numeric entries were removed, 20 zeros were dropped (a zero has no first digit), 30 negative values were kept via absolute value, and 511 values below 1 were retained using the first-significant-digit definition.

The detail

Data quality rules applied before digit extraction: 15 blank or non-numeric entries removed because they carry no digits to read. 20 zero values dropped—zeros have no first significant digit. 30 negative values (refunds, reversals) kept by taking absolute value; a negative amount still has a leading digit. 511 values below 1 kept because the first significant digit is defined as the leftmost non-zero digit (so 0.0042 counts as digit 4, just as 4,200 does). This treatment preserves the full range of the data while respecting the mathematical definition of first significant digit. The final 1,500 values exceed the 100-value minimum required for Benford screening.

What this can't tell you

Preprocessing choices affect which patterns emerge. Absolute-value treatment of negatives assumes refunds and reversals belong in the same digit pool as purchases; if reversals follow distinct business logic, separate screening might be warranted.

Visualization

First Digits: Observed vs Expected

Share of values starting with each digit 1-9, against Benford's Law.

Suggested Interpretation

The short answer

The observed first-digit distribution tracks the Benford slope closely across all nine digits. Digit 2 is furthest above its expectation (18.5 percent observed vs. 17.6 percent expected), and digit 1 is furthest below (29.3 percent vs. 30.1 percent expected)—both gaps are small and consistent with normal sampling variation.

The detail

Benford's Law predicts a downward slope: digit 1 at 30.1 percent, digit 2 at 17.6 percent, digit 3 at 12.49 percent, declining to digit 9 at 4.58 percent. Observed shares: digit 1 is 29.3 percent, digit 2 is 18.5 percent, digit 3 is 11.93 percent, digit 4 is 9.87 percent, digit 5 is 7.4 percent, digit 6 is 6.4 percent, digit 7 is 6.07 percent, digit 8 is 5.4 percent, digit 9 is 5.2 percent. The observed bars follow the expected curve without systematic bulges or dips. The largest individual deviation is digit 2 at +0.9 percentage points; all others are smaller. This consistency across the full range of digits is the hallmark of naturally distributed amounts.

What this can't tell you

A smooth digit distribution does not rule out systematic bias within specific vendors, time periods, or transaction types. Benford screening is a population-level test; subgroup anomalies may be hidden in the aggregate.

Data Table

Per-Digit Deviations

Observed vs expected share per digit with standardized residuals.

DigitObservedExpectedStd ResidualFlag
10.29270.301-0.71
20.18470.17610.87
30.11930.1249-0.66
40.09870.09690.23
50.0740.0792-0.74
60.0640.0669-0.46
70.06070.0580.44
80.0540.05120.5
90.0520.04581.16
Suggested Interpretation

The short answer

No digit's observed share deviates more than ordinary sampling wobble from its Benford expectation. Every standardized residual falls between −0.71 and +1.16, well short of the ±1.96 threshold used to flag anomalies.

The detail

Standardized residuals measure how many standard errors each digit's observed share sits from its Benford expectation, given 1,500 values. Flagging threshold: |residual| > 1.96. Observed residuals: digit 1 is −0.71, digit 2 is +0.87, digit 3 is −0.66, digit 4 is +0.23, digit 5 is −0.74, digit 6 is −0.46, digit 7 is +0.44, digit 8 is +0.50, digit 9 is +1.16. None crosses 1.96 in either direction. The largest, digit 9 at +1.16, is still 0.80 points below the flag threshold. This means the observed distribution is consistent with random sampling from a Benford-distributed population; no digit stands out as over- or under-represented.

What this can't tell you

Absence of per-digit flags does not rule out correlated deviations across multiple digits or concentration of anomalies in a small subset of amounts. Standardized residuals assume independence; they do not detect patterns like clustering of high amounts or temporal trends.

Data Table

Data Hygiene

What was dropped, what was kept, and why.

ReasonRows AffectedAction
Blank or non-numeric entries15dropped — no digits to read
Zero values20dropped — a zero has no first digit
Negative values30kept — absolute value used
Values below 1511kept — first significant digit used
Values analyzed1500screened against Benford's Law
Suggested Interpretation

The short answer

Of 1,535 loaded invoice records, 35 were dropped before screening (15 blank or non-numeric, 20 exactly zero), leaving 1,500 values. Negative values (30 rows) were kept via absolute value; sub-unit amounts (511 rows) were kept using the first-significant-digit rule. The final analyzed set is clean and defensible.

The detail

Starting population: 1,535 rows. Blanks and non-numeric entries: 15 dropped (no digits to extract). Zeros: 20 dropped (zero has no first digit). Negatives: 30 kept, converted to absolute value. Values below 1: 511 kept, first significant digit extracted (e.g., 0.047 → digit 4). Final analyzed count: 1,500. This preprocessing follows forensic-accounting convention and preserves all information-bearing entries.

What this can't tell you

The preprocessing is transparent but does not validate the source data itself. If the 1,535 loaded rows already contain falsified, duplicate, or corrupted entries, no cleaning step will reveal that. Benford screening assumes the input data are genuine transaction records, not fabricated or massaged before loading.

Data Table

Method and Thresholds

Nigrini's conformity bands, the tests run, and when Benford applies.

BandMad CutoffMeaningThis Data
Close conformity0.006MAD below 0.006 — observed digits track the Benford curve closelyyes
Acceptable conformity0.012MAD from 0.006 up to 0.012 — ordinary sampling wobble, no cause for review
Marginal conformity0.015MAD from 0.012 up to 0.015 — borderline; worth a look if other signals agree
Nonconformity0.015MAD of 0.015 or more — the digit pattern departs from Benford; investigate
Suggested Interpretation

The short answer

The analysis used Nigrini's mean absolute deviation (MAD) thresholds and a chi-square goodness-of-fit test. The MAD of 0.0049 falls in the close conformity band (below 0.006), and the chi-square p-value of 0.874 indicates the observed digit distribution is well within sampling variation of Benford's expectation.

The detail

First-digit test: chi-square goodness-of-fit against Benford's Law with 8 degrees of freedom, p = 0.874. MAD of 0.0049 read against Nigrini's conformity thresholds: close conformity below 0.006 (this data qualifies), acceptable conformity 0.006–0.012, marginal 0.012–0.015, nonconformity 0.015 and above. Individual digits flagged when standardized residual exceeds 1.96 (none do). First-two-digit test also ran on the same 1,500 values: chi-square across 90 combinations (10–99) gives p = 0.575, first-two-digit MAD of 0.0020, confirming no additional departure beyond first-digit sampling noise. Applicability: the amounts span 6.0 orders of magnitude across 1,499 distinct values—sufficiently wide-ranging that Benford's Law is a valid expectation. Caveat: data that is naturally assigned (identifiers), capped, floored, or single-price does not follow Benford and should not be screened this way.

What this can't tell you

Statistical conformity does not establish absence of fraud. Benford deviation is a screening signal; conformity clears the test but does not rule out isolated fabrications or collusion that preserves overall digit distribution.

Methodology

Methodology

Statistical methodology and diagnostics for Benford's Law Screening

Statistical Method

Benford's Law Screening

Standard-library analysis: screen a column of amounts against Benford's Law, the forensic-accounting standard for spotting numbers that may have been fabricated or manipulated. The observed first-digit distribution is compared with the expected log10(1 + 1/d) curve using a chi-square goodness-of-fit test, the mean absolute deviation (MAD) read against Nigrini's conformity bands, per-digit standardized residuals flagging which digits deviate most, and a first-two-digit test when at least 1,000 values are available. Deviation is reported as a screening signal to investigate — never as proof of fraud — and a computed applicability check warns when the data's range is too narrow for Benford's Law to apply naturally.

Data
N = 1500 observations · 35 excluded
Assumptions
  • Amounts are organically generated and span several orders of magnitude
  • Values are numeric or cleanly convertible to numeric
  • Observations are independent records, not aggregates of each other
Limitations
  • Benford deviation is a screening signal, not proof of fraud or manipulation
  • Assigned numbers, capped or floored ranges, and single-price data violate Benford naturally — the module warns when the data spans under 2 orders of magnitude
  • Chi-square grows oversensitive on very large samples; read the MAD band alongside the p-value
  • The first-two-digit test needs at least 1,000 values and is skipped below that
Software & Citation
MCP Analytics · mcpanalytics.ai
Code Appendix

Analysis Code

Complete R source code for this analysis

Benford's Law Screening — Do These Numbers Look Fabricated?

Screens a numeric amount column against Benford's Law: the observed first-significant-digit distribution versus the expected log10(1 + 1/d) curve, a chi-square goodness-of-fit test, the mean absolute deviation (MAD) read against Nigrini's conformity bands, per-digit standardized residuals flagging which digits deviate most, and an optional first-two-digit test when there is enough data.

Why This Method?

Organic amounts that grow multiplicatively — transactions, expenses, invoice totals — start with 1 about 30 percent of the time and with 9 under 5 percent of the time. Invented numbers rarely follow that curve, which makes the first-digit test a fast, standard screen in forensic accounting and audit. Deviation is a SCREENING signal that says "look closer here", never proof of manipulation.

What This Analysis Covers

  • Observed versus expected share for each first digit 1-9
  • Chi-square goodness-of-fit against the Benford expectation
  • MAD with Nigrini's conformity bands (close / acceptable / marginal /

nonconformity)

  • Per-digit standardized residuals with deviates-high / deviates-low flags
  • First-two-digit test when at least 1,000 usable values are present
  • A computed applicability check: narrow-range data violates Benford

naturally and is warned about, not accused

Standard Library

Platform standard-library module (LAT-1441): runs on ANY dataset via the semantic mapping {value}. All narrative is derived from the user's own column name and computed values.

suppressPackageStartupMessages(library(DT))
suppressPackageStartupMessages(library(htmlwidgets))
suppressPackageStartupMessages(library(arrow))
suppressPackageStartupMessages(library(knitr))
suppressPackageStartupMessages(library(rmarkdown))
suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(tidyr))
suppressPackageStartupMessages(library(ggplot2))
suppressPackageStartupMessages(library(stringr))
suppressPackageStartupMessages(library(lubridate))
suppressPackageStartupMessages(library(broom))
suppressPackageStartupMessages(library(Matrix))
suppressPackageStartupMessages(library(cluster))
suppressPackageStartupMessages(library(data.table))

Core Analysis Pipeline

Step 1: Locate the mapped amount column

initial_rows <- nrow(df)
  if (!("value" %in% names(df))) {
    stop("column_mapping must map the value column — the numeric amounts to screen.")
  }
  hv <- humanize_semantic("value", col_map)

Step 2: Data hygiene — every drop is counted and reported.

Blanks and non-numeric entries are dropped; zeros are dropped (a zero has no first digit); negatives are KEPT via absolute value (a refund of -420 still leads with a 4); values below 1 are KEPT because the digit is defined as the first SIGNIFICANT digit (0.0042 counts as a 4).

v_raw <- df$value
  ch <- as.character(v_raw)
  blank_mask <- is.na(v_raw) | is.na(ch) | trimws(ch) == ""
  conv <- suppressWarnings(as.numeric(ch))
  nonnum_mask <- !blank_mask & is.na(conv)
  n_blank <- as.integer(sum(blank_mask) + sum(nonnum_mask))
  n_nonblank <- sum(!blank_mask)
  if (n_nonblank > 0 && sum(!blank_mask & !is.na(conv)) < 0.95 * n_nonblank) {
    stop(paste0(hv, " does not look numeric: fewer than 95 percent of its ",
                "non-blank entries could be read as numbers. Benford ",
                "screening needs a numeric amount column such as ",
                "transaction amounts, expenses, or invoice totals."))
  }
  x0 <- conv[!blank_mask & !nonnum_mask]
  n_zero <- as.integer(sum(x0 == 0))
  n_neg  <- as.integer(sum(x0 < 0))
  x <- abs(x0[x0 != 0])
  n_sub1 <- as.integer(sum(x < 1))
  n <- length(x)
  final_rows <- n
  rows_removed <- initial_rows - final_rows

Step 3: Volume guard — Benford needs volume to mean anything.

if (n < 100) {
    stop(sprintf(paste0(
      "Benford screening needs at least 100 usable values to be meaningful, ",
      "but %s has only %d after removing blank and zero entries. First-digit ",
      "proportions are far too noisy below that volume for the conformity ",
      "thresholds to carry any signal — gather more records and re-run."),
      hv, n))
  }

Step 4: First significant digits, extracted robustly.

sprintf("%.6e", x) yields the normalized mantissa, so the first (and second) significant digits are positional characters — immune to the floating-point trap where floor(log10(1000)) evaluates to 2.

e_str <- sprintf("%.6e", x)
  d1 <- as.integer(substr(e_str, 1, 1))
  d2 <- as.integer(substr(e_str, 3, 3))

Step 5: First-digit test — chi-square, MAD, Nigrini bands, residuals

digits <- 1:9
  benford_p <- log10(1 + 1 / digits)
  obs_counts <- tabulate(d1, nbins = 9)
  obs_p <- obs_counts / n

  chi <- suppressWarnings(chisq.test(obs_counts, p = benford_p, rescale.p = TRUE))
  chi_stat <- as.numeric(chi$statistic)
  chi_p <- as.numeric(chi$p.value)

  mad_val <- mean(abs(obs_p - benford_p))

Nigrini's first-digit conformity bands (Nigrini 2012): MAD < 0.006 close; < 0.012 acceptable; < 0.015 marginal; else nonconformity

band <- if (mad_val < 0.006) "close conformity" else
          if (mad_val < 0.012) "acceptable conformity" else
          if (mad_val < 0.015) "marginal conformity" else "nonconformity"
  verdict <- if (band %in% c("close conformity", "acceptable conformity")) {
    "conforms"
  } else {
    "deviates(investigate)"
  }

  se <- sqrt(benford_p * (1 - benford_p) / n)
  z <- (obs_p - benford_p) / se
  flag <- ifelse(z > 1.96, "deviates high", ifelse(z < -1.96, "deviates low", ""))
  n_flagged <- as.integer(sum(flag != ""))

Step 6: Applicability — computed against the data, not assumed.

Benford's Law only arises in amounts spanning several orders of magnitude. Assigned numbers, capped or floored ranges, and single-price data violate it NATURALLY — deviation there is not suspicious.

span_oom <- log10(max(x) / min(x))
  n_distinct <- length(unique(x))
  range_warning <- is.finite(span_oom) && span_oom < 2
  applicability_notes <- character(0)
  if (range_warning) {
    applicability_notes <- c(applicability_notes, paste0(
      "Warning: the amounts in ", hv, " span only ", sprintf("%.1f", span_oom),
      " orders of magnitude(from ", fmt_num(min(x)), " to ", fmt_num(max(x)),
      "), and Benford&#x27;s Law may not apply to numbers confined to such a ",
      "narrow band — assigned numbers, capped or floored amounts, and ",
      "single-price data all depart from Benford naturally. Treat the ",
      "conformity reading with caution: the deviation here can be a ",
      "property of the data&#x27;s range, not of anyone's behavior."))
  } else if (n_distinct < 50) {
    applicability_notes <- c(applicability_notes, paste0(
      "Warning: ", hv, " holds only ", n_distinct, " distinct amounts, ",
      "which suggests a fixed price list or assigned values rather than ",
      "organically generated amounts — a situation where Benford&#x27;s Law may ",
      "not apply. Treat the conformity reading with caution."))
  }

Step 7: First-two-digit test — only with volume (n >= 1000).

ftd_ran <- n >= 1000
  ftd_chi_p <- NA_real_
  ftd_mad <- NA_real_
  if (ftd_ran) {
    ftd <- 10L * d1 + d2
    ftd_counts <- tabulate(ftd, nbins = 99)[10:99]
    ftd_exp_p <- log10(1 + 1 / (10:99))
    ftd_chi <- suppressWarnings(chisq.test(ftd_counts, p = ftd_exp_p, rescale.p = TRUE))
    ftd_chi_p <- as.numeric(ftd_chi$p.value)
    ftd_mad <- mean(abs(ftd_counts / n - ftd_exp_p))
    ftd_note <- paste0(
      "The first-two-digit test ran on the same ", format(n, big.mark = ","),
      " values(it requires at least 1,000): chi-square across the 90 ",
      "two-digit combinations 10 through 99 gives ", fmt_pp(ftd_chi_p),
      ", with a first-two-digit MAD of ", sprintf("%.4f", ftd_mad), ". ",
      if (!is.na(ftd_chi_p) && ftd_chi_p < 0.05) {
        "It agrees with the first-digit read that the digit pattern departs from the Benford expectation."
      } else {
        "It finds no additional departure beyond first-digit sampling noise."
      })
  } else {
    ftd_note <- paste0(
      "The first-two-digit test was skipped: it requires at least 1,000 ",
      "usable values and this data has ", format(n, big.mark = ","),
      " — the 90 two-digit proportions are too noisy below that volume to ",
      "read against an expectation.")
  }

Step 9: Metrics + computed answer

metrics <- list(
    `Values Analyzed` = as.integer(n),
    `MAD`             = round(mad_val, 4),
    `Conformity`      = band,
    `Chi-Square p`    = fmt_p(chi_p),
    `Digits Flagged`  = n_flagged,
    `Verdict`         = verdict
  )

  flagged_digits <- digits[flag != ""]
  flag_txt <- if (n_flagged > 0) {
    paste0(n_flagged, " digit", .s(n_flagged), " (",
           paste(flagged_digits, collapse = ", "), ") deviate",
           if (n_flagged == 1) "s" else "",
           " beyond the 1.96 standardized-residual line. ")
  } else {
    "No individual digit deviates beyond the 1.96 standardized-residual line. "
  }

  json_output <- list(
    answer = paste0(
      "Benford&#x27;s Law screening of ", format(n, big.mark = ","),
      " values from ", hv, ": mean absolute deviation ",
      sprintf("%.4f", mad_val), " — ", band,
      " on Nigrini&#x27;s thresholds — with a chi-square goodness-of-fit ",
      fmt_pp(chi_p), ". Verdict: ", verdict, ". ", flag_txt,
      if (length(applicability_notes) > 0)
        paste0(paste(applicability_notes, collapse = " "), " ") else "",
      "Benford deviation is a screening signal that says where to look ",
      "closer; it is not proof of fabrication or manipulation."
    ),
    cards = lapply(
      c("tldr", "overview", "preprocessing", "digit_distribution",
        "deviations", "data_hygiene", "methods"),
      function(cid) list(id = cid, metrics = metrics)
    )
  )

  list(
    initial_rows = initial_rows, final_rows = final_rows,
    rows_removed = rows_removed,
    hv = hv, n = n,
    n_blank = n_blank, n_zero = n_zero, n_neg = n_neg, n_sub1 = n_sub1,
    obs_p = obs_p, benford_p = benford_p, obs_counts = obs_counts,
    chi_stat = chi_stat, chi_p = chi_p,
    mad_val = mad_val, band = band, verdict = verdict,
    z = z, flag = flag, n_flagged = n_flagged,
    flagged_digits = flagged_digits,
    span_oom = span_oom, n_distinct = n_distinct,
    range_warning = range_warning,
    applicability_notes = applicability_notes,
    ftd_ran = ftd_ran, ftd_chi_p = ftd_chi_p, ftd_mad = ftd_mad,
    ftd_note = ftd_note,
    digit_distribution_df = digit_distribution_df,
    deviations_df = deviations_df,
    data_hygiene_df = data_hygiene_df,
    conformity_bands_df = conformity_bands_df,
    metrics = metrics, json_output = json_output
  )
}
Your data has more stories to tell. Run any analysis on your own data — validated R modules, interactive reports, AI insights, and PDF export. 500 free credits on signup.
Try Free — No Signup Sign Up Free

Report an Issue

Tell us what's wrong. You'll get a free re-run of this analysis so you can try again with different parameters. If the re-run still doesn't meet your expectations, we'll refund your credits.

Want to run this analysis on your own data? Upload CSV — Free Analysis See Pricing