This project applies ABC–XYZ inventory analysis to the Brazilian Olist e-commerce dataset to identify products that require different levels of inventory management attention. The ABC analysis classifies products according to their contribution to total revenue, while the XYZ analysis classifies products according to the predictability of their monthly demand. Combining the two approaches produces a nine-category ABC–XYZ matrix that considers both economic importance and demand variability.
The analysis covers 32,951 products. The ABC results show a strong concentration of revenue: approximately 25.9% of products (Class A) generate 80% of total revenue, while Class C products represent 39.8% of products but contribute only around 5% of revenue.
The XYZ analysis indicates that 50% of products are classified as X, 30% as Y, and 20% as Z. Importantly, the Z category accounts for approximately 55.3% of total forecast error, indicating that a relatively small proportion of products with unpredictable demand creates a disproportionate forecasting challenge.
The combined ABC–XYZ analysis shows that AX and AY products represent only 23.4% of all products but generate approximately 75.3% of total revenue. AX products combine high revenue contribution with relatively predictable demand, whereas AY products have similarly high economic importance but greater demand variability. At the other end of the spectrum, CZ products account for 10.7% of products but only 1.31% of revenue, suggesting that simplified inventory controls may be appropriate for this group.
Overall, the analysis demonstrates how combining value-based classification (ABC) with demand-predictability classification (XYZ) can provide a more informative basis for inventory prioritisation than either method alone. The results can help businesses focus forecasting, replenishment, and inventory-control resources on products where they are likely to have the greatest financial impact.
Note: The XYZ analysis is based on 26 months of monthly observations, representing approximately two annual cycles. Therefore, its forecastability classifications should be interpreted as exploratory rather than as definitive long-term demand forecasts.
Prepare the data
library(cABCanalysis)library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.4 ✔ readr 2.1.5
✔ forcats 1.0.0 ✔ stringr 1.5.1
✔ ggplot2 4.0.0 ✔ tibble 3.2.1
✔ lubridate 1.9.3 ✔ tidyr 1.3.1
✔ purrr 1.0.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Rows: 112650 Columns: 7
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): order_id, product_id, seller_id
dbl (3): order_item_id, price, freight_value
dttm (1): shipping_limit_date
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Category the sales by month for each skudf_monthly <- df |>mutate(month =floor_date(shipping_limit_date, "month"))# Group monthly demand by skumonthly_demand <- df_monthly |>group_by(product_id, month) |>summarise(quantity =n(),.groups ="drop" )
XYZ analysis
Errors %
Z (20%): 55.337
Y (30%): 42.804
X (50%): 1.859
# Plot resultsplot(z)
Interpretation of the analysis results
Class X: There are 50% of the products in class X, which contribute only 8.741% forecasting error. It means that about half of the products sold are relatively predictable
Class Y: There are 30% of the products in class Y, which contribute only 8.094% forecasting error. These are the products that have more variability than those in Class X, therefore more active monitoring is needed
Class Z: The 20% products contribute to over 83% of forecasting error. Some highly erratic low-volume products might need to be deleted. For the rest, shorter replenishment cycles are needed to avoid stockouts
Warning in cABC_postprocess_classes(Aind, Bind, Cind, Data, sorted_data, : Found 1 duplicate value(s) spanning multiple classes.
Reassigning all occurrences to the class with the most instances or based on
distance to boundary if tied. Consider checking data and plot to confirm data
is suitable for ABC analysis.
Coordinate system already present.
ℹ Adding new coordinate system, which will replace the existing one.
# A tibble: 9 × 6
abc_class xyz_class skus revenue sku_pct revenue_pct
<chr> <chr> <int> <dbl> <dbl> <dbl>
1 A X 3704 5237768. 11.2 38.5
2 A Y 4014 5004974. 12.2 36.8
3 A Z 817 630407. 2.48 4.64
4 B X 5481 970150. 16.6 7.14
5 B Y 3576 680516. 10.9 5.01
6 B Z 2244 388209. 6.81 2.86
7 C X 7291 371162. 22.1 2.73
8 C Y 2295 131077. 6.96 0.964
9 C Z 3529 177381. 10.7 1.31
Interpretation of the summary
AX: 11.2% of SKUs, contributing 38.5% revenue, economically important and predictable
AY: 12.2% of SKUs, contributing 36.8% revenue, high-value but variable
AZ: 2.48% of SKUs, contributing 4.64% revenue, high-value but unpredictable
The rest 74% of SKUs but only 20% revenue, less financial importance. SKUs in CZ might need to be deleted to simply inventory.