Shape / rows · All operations
Take a stratified sample
A variant of Sample rows
Sample within each class of a column so the sample keeps, or evens out, the class shares.
Status
- In arcform
Runs as a SQL step
arcform carries it as a
sql:step today.
The DuckDB step
Sample within each class, keeping the class shares or evening them out
It reads the orders table the proofs share. Create it first:
CREATE TABLE orders AS SELECT * FROM (VALUES
(1, 'Alice Ng', 'north', DATE '2026-01-03', 120.00, 'widget', 'a|b', '{"channel":"web","items":[1,2]}'),
(2, 'alice ng', 'north', DATE '2026-01-05', 80.50, 'gadget', 'b', '{"channel":"shop","items":[3]}'),
(3, 'Bob Okafor', 'south', DATE '2026-01-05', 300.00, 'widget', 'a|c', '{"channel":"web","items":[4,5,6]}'),
(4, 'Carla Díaz', 'east', DATE '2026-01-09', NULL, 'gizmo', NULL, '{"channel":"web","items":[]}'),
(5, 'Bob Okafor', 'south', DATE '2026-01-12', 45.25, 'gadget', 'c', '{"channel":"phone","items":[7]}'),
(6, 'Dev Patel', 'west', DATE '2026-01-12', 510.00, 'widget', 'a', '{"channel":"web","items":[8,9]}'),
(7, 'Carla Diaz', 'east', DATE '2026-01-20', 99.99, 'gizmo', 'b|c', '{"channel":"shop","items":[10]}'),
(8, 'Dev Patel', 'west', DATE '2026-02-02', 510.00, 'widget', 'a', '{"channel":"web","items":[8,9]}'),
(9, 'Eve Larsen', NULL, DATE '2026-02-03', 15.00, 'gadget', NULL, '{"channel":"web","items":[11]}'),
(10, 'Alice Ng', 'north', DATE '2026-02-10', 220.00, 'gizmo', 'a|b|c', '{"channel":"phone","items":[12,13]}')
) t(order_id, customer, region, order_date, amount, product, tags, meta);Then run the statement:
CREATE TEMP TABLE ranked AS
SELECT order_id, product,
row_number() OVER (PARTITION BY product ORDER BY hash(order_id::VARCHAR || '-sample-7')) AS rn,
count(*) OVER (PARTITION BY product) AS class_size
FROM orders;
-- keep a third of every class, rounded up: the shares stay close to 4 : 3 : 3
CREATE TEMP TABLE proportional AS SELECT order_id, product FROM ranked WHERE rn <= ceil(class_size / 3.0);
-- even the classes out: two rows from each
CREATE TEMP TABLE balanced AS SELECT order_id, product FROM ranked WHERE rn <= 2;
SELECT product, count(*) AS n FROM proportional GROUP BY product ORDER BY product;
SELECT product, count(*) AS n FROM balanced GROUP BY product ORDER BY product;
SELECT CASE WHEN ((SELECT map_from_entries(list((product, n) ORDER BY product)) FROM (SELECT product, count(*) AS n FROM proportional GROUP BY product)) = MAP {'gadget': 1, 'gizmo': 1, 'widget': 2} AND (SELECT list(order_id ORDER BY order_id) FROM proportional) = [1, 6, 7, 9] AND (SELECT list(order_id ORDER BY order_id) FROM balanced) = [1, 4, 5, 6, 7, 9] AND (SELECT map_from_entries(list((product, n) ORDER BY product)) FROM (SELECT product, count(*) AS n FROM balanced GROUP BY product)) = MAP {'gadget': 2, 'gizmo': 2, 'widget': 2}) THEN 'as expected' ELSE error('the proportional sample was not orders 1, 6, 7 and 9, or the balanced sample was not orders 1, 4, 5, 6, 7 and 9') END AS verdict;- It needs nothing installed beyond DuckDB itself.
- The statement checks its own result and raises an error when it is wrong: “the proportional sample was not orders 1, 6, 7 and 9, or the balanced sample was not orders 1, 4, 5, 6, 7 and 9”.
- It passed on DuckDB
v2.0.0 (Cyanoptera) d54cbbe3df.
What other tools call it
Meridian's classification; an independent blind rating agreed on 95.7% of 324 rows (variant, version 3).
KNIME Analytics Platform (1)
Equal Size Samplingread 2026-09-27Downsample so every value of a categorical column occurs equally often
RapidMiner Studio (1)
Sample (Stratified)read 2026-09-27Random sample that preserves the label's class distribution
Background
In statistics, stratified sampling is a method of sampling from a population which can be partitioned into subpopulations.[1] Stratification divides the members of a population into homogeneous subgroups, called strata, before sampling, and then samples within each stratum.[1] In RapidMiner, Sample (Stratified) builds random subsets whose class distribution, the share of rows in each class, is the same as in the whole input.[2]
When to use it
The objective of stratification is to improve the precision of the sample by reducing sampling error.[1] If measurements within strata have a lower standard deviation than the overall standard deviation in the population, stratification gives a smaller error in estimation.[1] When estimates are wanted for groups within the population, stratified sampling makes sure there are enough samples from the strata of interest.[1] Dividing a population into distinct strata can let researchers draw inferences about specific subgroups that may be lost in a more generalised random sample.[3]
In scikit-learn, cross-validation splitting on data with rare classes can generate training or validation folds, the parts the data is split into, without any occurrence of a particular class.[4] In scikit-learn, missing classes in a fold typically lead to undefined classification metrics, or to exceptions when a model is fitted.[4] In scikit-learn, splitters such as StratifiedKFold and StratifiedShuffleSplit implement stratified sampling so that relative class frequencies are approximately preserved in each fold.[4] In scikit-learn, stratification makes cross-validation folds more homogeneous, and can artificially shrink the spread of the metric measured across cross-validation iterations.[4] Stratify on the label whenever a class is rare enough that a plain random draw could leave it out, and read the spread of scores across stratified folds as possibly narrower than the real uncertainty. (Meridian's view)
Stratified sampling requires choosing relevant stratification variables, which can be difficult, and is not useful when there are no homogeneous subgroups.[3] Making subgroups' sample sizes proportional to the amount of data available from the subgroups, rather than scaling them to the subgroups' sizes, is a misapplication of stratified sampling.[1] Combining sub-strata to ensure adequate numbers can lead to Simpson's paradox, where trends that exist in different groups of data disappear or even reverse when the groups are combined.[1] Pick the column to stratify on for its link to what will be measured, not because it happens to be in the table, and leave small classes as they are rather than folding them together. (Meridian's view)
Choice-based sampling, or oversampling, is a stratified sampling strategy in which the data are stratified on the target, the variable a model is built to predict, so that rarer target classes are more represented in the sample.[3] Results from a choice-based sample usually must be adjusted to correct for the oversampling.[3] Keep the class shares when the sample has to stand in for the whole table, and even them out only when every class needs the same weight, noting beside the sample that its shares were changed. (Meridian's view) In RapidMiner, Sample (Stratified) cannot be applied to data sets without a label, the class column it stratifies on, or with a numerical label.[2] Cut a numeric column into bands before stratifying on it, and choose the bands with care, since they decide what the sample represents. (Meridian's view)
The method
The strata should be collectively exhaustive and mutually exclusive, so that every element in the population is assigned to one and only one stratum.[1] After stratification, sampling is done in each stratum, for example by simple random sampling.[1] The ratio of the size of a random selection to the size of the population it is drawn from is called a sampling fraction.[3] Proportionate allocation uses a sampling fraction in each stratum that is proportional to that of the total population.[1] Under proportional allocation, a sample of 40 from a staff of 180 gives a group of 90 staff 90 × (40 ÷ 180) = 20 places.[1]
Neyman allocation, also known as optimum allocation, is a method of sample size allocation in stratified sampling developed by Jerzy Neyman in 1934.[5] Neyman allocation determines the sample size for each stratum that minimises the variance of the estimated population parameter for a fixed total sample size and cost.[5] Neyman allocation requires prior knowledge of each stratum's standard deviation, which may not be available in practice, and its allocated sample sizes may need rounding to whole numbers.[5] The mean of a stratified random sample is the sum, over the strata, of each stratum's size times its sample mean, divided by the sum of all stratum sizes.[1]
In KNIME, the Row Sampler node's stratified strategy preserves the distribution of values in a chosen group column, in both the selected and the non-selected rows.[6] In KNIME, the Equal Size Sampling node returns all rows of the minority class, the class with the fewest rows, and a random sample from each majority class holding as many rows as the minority class.[7] In KNIME, Equal Size Sampling treats missing values in the class column as a separate category, which can itself be the minority class.[7] In KNIME, Equal Size Sampling's exact method gives each class the same number of rows, while its approximate method decides on the fly, so the counts of each class may differ slightly.[7] In Tableau Prep, the Stratified sample method groups by a chosen field and returns the requested number of rows distributed across that field's values as equally as possible.[8] In Tableau Prep, a stratified sample can, depending on the data source, give some values of the grouping field more rows than others.[8]
In DuckDB, the row_number() window function with PARTITION BY numbers the rows within each partition, for example within each region in order of time.[9]
Compared with the alternatives
A stratified survey could claim to be more representative of the population than a survey of simple random sampling or systematic sampling.[1] Even when stratified sampling does not increase statistical efficiency, it will not give less efficiency than simple random sampling, provided each stratum is proportional to the group's size in the population.[3] Poststratification introduces stratification after the sampling phase, typically because an appropriate stratifying variable was not known beforehand, or the information needed to create one was lacking.[3]
Sources
- [1]Stratified sampling - Wikipediasecondary source
- [2]Sample (Stratified) - Rapidminer Documentationdocumentation
- [3]Sampling (statistics) - Wikipediasecondary source
- [4]3.1. Cross-validation: evaluating estimator performance — scikit-learn 1.9.1 documentationdocumentation
- [5]Neyman allocation - Wikipediasecondary source
- [6]Row Samplerdocumentation
- [7]Equal Size Samplingdocumentation
- [8]Configure your Data Set - Tableaudocumentation
- [9]Window Functions – DuckDBdocumentation