Standard Pareto
Executive Summary

Executive Summary

The 80/20 split across 11,493 categories

Categories
11493
Vital Few (80%)
2374
Vital Few Share %
20.7
Top Category Share %
0.93
Top 3 Share %
2.1
Concentration (Gini)
0.755
The vital few in this data is 2374 of the 11493 Name categories (20.7 percent of them), which together drive 80 percent of the total Global Sales. The single biggest contributor is Wii Sports, holding 0.93 percent on its own, and the top 3 together account for 2.1 percent. Overall the total is highly concentrated across categories. Focusing on the A-class 2374 categories is where effort moves the total the most.
What this means

Video game sales are highly concentrated: just 2,374 titles (20.7 percent of 11,493) drive 80 percent of total Global Sales, while Wii Sports alone accounts for 0.93 percent. The top 3 titles together hold 2.1 percent of the total, and the overall Gini coefficient is 0.755—indicating strong concentration. Effort directed at the A-class vital few will move the largest share of the total.

Overview

Analysis Overview

Pareto analysis of 11,493 Name categories across 16,598 rows.

N Categories11493
N Rows16598
Vital Few2374
A Class2374
What this means

This analysis applies Pareto's principle to rank 11,493 video game titles by Global Sales and identify the vital few that drive most revenue. The method totals sales by title, ranks from largest to smallest, and follows the cumulative share down the list. Here, 2,374 of the 11,493 titles (20.7 percent) together account for 80 percent of total Global Sales. The remaining 9,119 titles (79.3 percent) supply only 20 percent. This split is the foundation for ABC classification: A-class titles (the vital few) warrant tight management; B and C classes benefit from batching or bulk handling.

Data Preparation

Data Quality

Rows, categories, negatives handling, and the chart rollup.

Initial Rows16598
Final Rows16598
Rows Removed0
N Categories11493
Negative Dropped0
Zero Kept0
What this means

The analysis ingested 16,598 rows across 11,493 Name categories, with a grand total of 8,920 in Global Sales. All 16,598 rows were retained; no records were removed for blanks or missing values, and no negative values were present. For the Pareto chart visualization, the top 20 titles are displayed individually while the remaining 11,473 titles are pooled into an "Other" bar. This rollup is visual only; every title still counts toward the vital-few threshold and ABC class assignments. The concentration metrics and rankings reflect the full dataset.

Visualization

Pareto Chart

Ranked category totals with the cumulative share.

What this means

The short answer

The top titles fall away sharply: Wii Sports leads at 0.93 percent of total sales, and the cumulative share flattens quickly, crossing 80 percent only at the 2,374th ranked title. This steep drop is the signature of extreme concentration.

The detail

Wii Sports holds 82.74 in Global Sales (0.93 percent of the total), followed by Grand Theft Auto V at 55.92 (1.55 percent cumulative). The top 20 titles shown reach only 7.62 percent cumulatively. The chart's rapid descent and flat tail illustrate the Pareto principle: the ranked bars drop from 82.74 down to 23.86 across just the first 20 categories, then the remaining 11,473 categories pool into "Other" at 8,240.42. The cumulative share crosses 80 percent at the 2,374th category.

What this can't tell you

The chart shows only the top 20 named titles; the detailed shape of the middle and tail ranks is pooled into "Other." A full ranked list would reveal whether concentration is driven by a handful of blockbusters or distributed across a wider middle class.

Data Table

ABC Classes

Category counts and value share for the A, B, and C classes.

ClassCategoriesValueValue Share PCTDescription
A23747,13680Vital few - the top categories that together reach about 80 percent of the total.
B32431,33815Useful many - the next categories carrying the 80 to 95 percent band.
C58764465Trivial many - the long tail below the last 5 percent.
What this means

The A-class vital few comprises 2,374 titles holding 7,136 in Global Sales (80 percent of the total). Class B—the useful many—contains 3,243 titles with 1,338 in sales (15 percent), bridging the 80 to 95 percent band. Class C, the trivial many, includes 5,876 titles generating 446 in sales (5 percent). The decisive split is A: management effort here moves 80 percent of revenue. The 9,119 titles outside class A (B and C combined) supply only 20 percent, so batching or bulk handling is appropriate for those categories.

Data Table

Top Contributors

The highest-value categories ranked, with cumulative share.

RankCategoryValueShare PCTCumulative PCT
1Wii Sports830.930.93
2Grand Theft Auto V560.631.55
3Super Mario Bros.450.512.06
4Tetris360.42.46
5Mario Kart Wii360.42.87
6Wii Sports Resort330.373.24
7Pokemon Red/Pokemon Blue310.353.59
8Call of Duty: Black Ops310.353.94
9Call of Duty: Modern Warfare 3310.354.28
10New Super Mario Bros.300.344.62
11Call of Duty: Black Ops II300.334.95
12Wii Play290.335.28
13New Super Mario Bros. Wii290.325.6
14Duck Hunt280.325.91
15Call of Duty: Ghosts270.316.22
What this means

Wii Sports ranks first with 83 in Global Sales and a 0.93 percent share. Grand Theft Auto V is second at 56 and 0.63 percent, followed by Super Mario Bros. at 45 and 0.51 percent. By rank 15 (Call of Duty: Ghosts at 27 and 0.31 percent), the cumulative share reaches 6.22 percent. The vital-few line (80 percent) is crossed at the 2,374th title, meaning the top 2,374 titles span from Wii Sports down to titles with individually negligible shares. This ranking is the concrete priority list: the first 2,374 rows are the focus; beyond that, individual title performance becomes marginal to overall sales.

Rate this report Was this the answer you needed?
The exact source that produced this report — yours to keep, read, and re-run.
Download PDF
How this was computed method · R source · citation
The code that did it

Pareto Analysis — The Vital Few (80/20)

Finds the few categories that drive most of the total. Aggregates a raw category/value table, sorts the categories from biggest to smallest, builds the cumulative curve, and reports the "vital few" that reach 80% of the total, the ABC classes, and how concentrated the total is.

Why This Method?

The Pareto principle — roughly 80% of effects come from 20% of causes — is the workhorse of Lean and Six Sigma. It turns a long, flat list of defects, complaints, SKUs, or revenue lines into a ranked priority list: fix the vital few and you move most of the total. It needs no model, only a category and an amount.

What This Analysis Covers

  • The vital few: the smallest set of categories reaching 80% of the total
  • ABC classes (A up to 80%, B 80-95%, C the tail)
  • The Pareto chart (ranked bars with the cumulative share)
  • Concentration: the top category and top-three shares

Standard Library

Platform standard-library module (LAT-1441): runs on ANY dataset via the semantic mapping {category, value}. All narrative is derived from the user's own column names 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

Number formatter — plain rounded strings with thousands separators.

Table numerics are formatted through this so large totals never serialize in scientific notation (e.g. 2.76e+04) inside a rendered table.

fmt_num <- function(x, digits = 0) {
  format(round(as.numeric(x), digits), big.mark = ",", scientific = FALSE,
         trim = TRUE, nsmall = digits)
}

Gini concentration (0 = every category equal, 1 = one holds it all).

Defensive: needs a positive total and >=2 categories, else returns NA.

gini_concentration <- function(v) {
  v <- v[!is.na(v)]
  n <- length(v)
  s <- sum(v)
  if (n < 2 || s <= 0) return(NA_real_)
  vs <- sort(v)
  (2 * sum(seq_len(n) * vs) / (n * s)) - (n + 1) / n
}

compute_shared <- function(df, params, col_map = list()) {
  # === SHARED EXPORTS ===
  #   initial_rows/final_rows/rows_removed   $ row accounting
  #   n_missing_cat / n_missing_value / n_negative / n_zero  $ preprocessing counts
  #   negative_total          $ numeric — summed value of dropped negatives
  #   cat_name / value_name   $ humanized user column names
  #   agg_df                  $ data.frame(category, value, share_pct,
  #                             cumulative, cumulative_pct, rank, abc) sorted desc
  #   n_categories / total_value                $ integer / numeric
  #   vital_few_n / vital_few_cat_share / vital_few_value_share
  #   top_category / top_share / top3_share     $ concentration headline
  #   gini                    $ numeric — Gini concentration
  #   abc_summary_df          $ data.frame(class, categories, value,
  #                             value_share_pct, description)
  #   n_a / n_b / n_c         $ integer — ABC class sizes
  #   pareto_df               $ data.frame(category, value, cumulative_pct) top 20 + Other
  #   top_contributors_df     $ data.frame(rank, category, value, share_pct, cumulative_pct)
  #   metrics / json_output
  # === /SHARED EXPORTS ===

Step 1: Required semantic columns + humanized names

initial_rows <- nrow(df)
  cat_name   <- humanize_semantic("category", col_map)[1]
  value_name <- humanize_semantic("value", col_map)[1]
  for (need in c("category", "value")) {
    if (!need %in% names(df)) {
      stop(sprintf("Required column &#x27;%s' is not mapped.",
                   humanize_semantic(need, col_map)[1]))
    }
  }

Step 2: Category — character, drop blank/missing

cat_v <- trimws(as.character(df$category))
  keep_cat <- !is.na(cat_v) & cat_v != ""
  n_missing_cat <- sum(!keep_cat)
  cat_v <- cat_v[keep_cat]
  val <- df$value[keep_cat]

Step 3: Value — 95% numeric coercion rule; drop NA

if (!is.numeric(val)) {
    conv <- suppressWarnings(as.numeric(as.character(val)))
    n_orig <- sum(!is.na(val) & trimws(as.character(val)) != "")
    if (n_orig == 0 || sum(!is.na(conv)) < 0.95 * n_orig) {
      stop(sprintf(
        "Column &#x27;%s' is not numeric enough to total up — fewer than 95%% of its values could be read as numbers.",
        value_name))
    }
    val <- conv
  }
  keep_val <- !is.na(val)
  n_missing_value <- sum(!keep_val)
  cat_v <- cat_v[keep_val]
  val <- val[keep_val]

Step 4: Drop negatives (Pareto assumes non-negative contributions),

keep zeros. Count and total the dropped negatives for the narrative.

neg_mask <- val < 0
  n_negative <- sum(neg_mask)
  negative_total <- if (n_negative > 0) sum(val[neg_mask]) else 0
  cat_v <- cat_v[!neg_mask]
  val <- val[!neg_mask]
  n_zero <- sum(val == 0)

  final_rows <- length(val)
  rows_removed <- initial_rows - final_rows
  if (final_rows < 5) {
    stop(sprintf(
      "Only %d usable rows remain after cleaning &#x27;%s' and '%s' — need at least 5.",
      final_rows, cat_name, value_name))
  }

Step 5: Aggregate (sum) by category, sort biggest to smallest

agg <- data.frame(category = cat_v, value = val, stringsAsFactors = FALSE) %>%
    group_by(category) %>%
    summarise(value = sum(value), .groups = "drop") %>%
    as.data.frame(stringsAsFactors = FALSE)
  agg <- agg[order(-agg$value), , drop = FALSE]
  rownames(agg) <- NULL

  n_categories <- nrow(agg)
  total_value <- sum(agg$value)
  if (total_value <= 0) {
    stop(sprintf(
      "The total of &#x27;%s' across all categories is zero, so there is no share to distribute.",
      value_name))
  }

Step 6: Shares + cumulative curve

agg$share_pct      <- round(100 * agg$value / total_value, 2)
  agg$cumulative     <- cumsum(agg$value)
  agg$cumulative_pct <- round(100 * agg$cumulative / total_value, 2)
  agg$rank           <- seq_len(n_categories)

Step 7: The vital few — smallest prefix reaching 80% cumulative.

cumulative_pct is monotonic and its last value is 100, so a match always exists; which.max returns the first TRUE (guarded fallback regardless).

reach80 <- agg$cumulative_pct >= 80
  vital_few_n <- if (any(reach80)) which.max(reach80) else n_categories
  vital_few_cat_share   <- round(100 * vital_few_n / n_categories, 1)
  vital_few_value_share <- round(agg$cumulative_pct[vital_few_n], 1)

Step 8: ABC classes (A up to 80%, B 80-95%, C the tail)

reach95 <- agg$cumulative_pct >= 95
  b_end <- if (any(reach95)) max(which.max(reach95), vital_few_n) else n_categories
  abc <- rep("C", n_categories)
  abc[seq_len(vital_few_n)] <- "A"
  if (b_end > vital_few_n) abc[(vital_few_n + 1):b_end] <- "B"
  agg$abc <- abc

  n_a <- sum(abc == "A"); n_b <- sum(abc == "B"); n_c <- sum(abc == "C")

  abc_desc <- c(
    A = "Vital few - the top categories that together reach about 80 percent of the total.",
    B = "Useful many - the next categories carrying the 80 to 95 percent band.",
    C = "Trivial many - the long tail below the last 5 percent."
  )
  abc_summary_df <- do.call(rbind, lapply(c("A", "B", "C"), function(cl) {
    idx <- abc == cl
    data.frame(
      class = cl,
      categories = sum(idx),
      value = fmt_num(sum(agg$value[idx]), 0),
      value_share_pct = round(100 * sum(agg$value[idx]) / total_value, 1),
      description = unname(abc_desc[cl]),
      stringsAsFactors = FALSE
    )
  }))
  rownames(abc_summary_df) <- NULL

Step 9: Concentration headline

top_category <- agg$category[1]
  top_share    <- agg$share_pct[1]
  top3_n       <- min(3, n_categories)
  top3_share   <- round(sum(agg$share_pct[seq_len(top3_n)]), 1)
  gini         <- round(gini_concentration(agg$value), 3)

Step 10: Pareto chart data — top 20 categories, rest rolled into

"Other" (chart only; the vital-few and ABC counts use the FULL data).

cap <- 20
  if (n_categories > cap) {
    head_df <- agg[seq_len(cap), c("category", "value", "cumulative_pct")]
    other_value <- total_value - sum(agg$value[seq_len(cap)])
    pareto_df <- rbind(
      head_df,
      data.frame(category = "Other", value = round(other_value, 2),
                 cumulative_pct = 100, stringsAsFactors = FALSE)
    )
  } else {
    pareto_df <- agg[, c("category", "value", "cumulative_pct")]
  }
  pareto_df$value <- round(pareto_df$value, 2)
  rownames(pareto_df) <- NULL

Step 11: Top contributors table — top 15, values as plain strings

tc_n <- min(15, n_categories)
  top_contributors_df <- data.frame(
    rank = agg$rank[seq_len(tc_n)],
    category = agg$category[seq_len(tc_n)],
    value = fmt_num(agg$value[seq_len(tc_n)], 0),
    share_pct = agg$share_pct[seq_len(tc_n)],
    cumulative_pct = agg$cumulative_pct[seq_len(tc_n)],
    stringsAsFactors = FALSE
  )
  rownames(top_contributors_df) <- NULL

  metrics <- list(
    `Categories`            = n_categories,
    `Vital Few(80%)`       = vital_few_n,
    `Vital Few Share %`     = vital_few_cat_share,
    `Top Category Share %`  = top_share,
    `Top 3 Share %`         = top3_share,
    `Concentration(Gini)`  = gini
  )

  json_output <- list(
    answer = paste0(
      "Pareto analysis of ", format(n_categories, big.mark = ","),
      " categories from ", format(final_rows, big.mark = ","), " rows: ",
      "the vital few is ", vital_few_n, " ", cat_name,
      if (vital_few_n == 1) " category" else " categories", " (",
      vital_few_cat_share, "% of them) driving ", vital_few_value_share,
      "% of total ", value_name, ". The single biggest is ", top_category,
      " at ", top_share, "%; the top ", top3_n, " together hold ", top3_share,
      "%. ABC split: A = ", n_a, ", B = ", n_b, ", C = ", n_c, " categories."
    ),
    cards = lapply(
      c("tldr", "overview", "preprocessing", "pareto_chart",
        "abc_classes", "top_contributors"),
      function(cid) list(id = cid, metrics = metrics)
    )
  )

  list(
    initial_rows = initial_rows, final_rows = final_rows,
    rows_removed = rows_removed,
    n_missing_cat = n_missing_cat, n_missing_value = n_missing_value,
    n_negative = n_negative, negative_total = negative_total, n_zero = n_zero,
    cat_name = cat_name, value_name = value_name,
    agg_df = agg, n_categories = n_categories, total_value = total_value,
    vital_few_n = vital_few_n, vital_few_cat_share = vital_few_cat_share,
    vital_few_value_share = vital_few_value_share,
    top_category = top_category, top_share = top_share, top3_share = top3_share,
    top3_n = top3_n, gini = gini,
    abc_summary_df = abc_summary_df, n_a = n_a, n_b = n_b, n_c = n_c,
    pareto_df = pareto_df, top_contributors_df = top_contributors_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 SignupSign Up Free

Cite this analysis

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