Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Database Management Systems (DBMS)  Module 14 – Storage engines, NoSQL and analytics

Data preprocessing: scaling, binning, sampling

Rescale values with min-max and z-scores, bin them by equal width or equal frequency, draw random, systematic and stratified samples in SQL, and compress data.

  • Intermediate
  • 30 minutes
  • Examples run with sql.js 1.14.2, Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free core, Pro depth: 11 of 30 minutes free
Free: Two meanings of normalisation · Scaling: min-max and z-scores · Binning: equal width and equal frequency · 4 more sections. With a pass: 3 in-depth parts and 3 interview answers, about 19 minutes.

What you will learn

  • Distinguish data normalisation, which rescales values, from schema normalisation into normal forms
  • Apply min-max and z-score scaling and equal-width and equal-frequency discretisation in SQL
  • Draw simple random, stratified and systematic samples, and explain what PostgreSQL's TABLESAMPLE does
  • Explain lossless and lossy compression of data for analysis

Before you start

Data preprocessing turns raw columns into values an analysis or a model can use, and four transformations do most of the work. Scaling puts columns on a common scale: min-max scaling maps a column onto 0 to 1, and a z-score says how many standard deviations a value lies from the mean. Binning, or discretisation, cuts a numeric column into ranges, either of equal width or holding equal numbers of rows. Sampling picks a subset of the rows that stands for the whole, at random, every k-th row, or a fixed share of each group. Compression stores the data in fewer bytes, either exactly or by giving up some detail. All four run inside a database, in SQL, before the data ever leaves it.

Two meanings of normalisation

In data transformation, normalisation means rescaling values, and that is its meaning in the syllabus line quoted below. In database design it means something else: decomposing tables into normal forms such as 3NF and BCNF to remove redundancy. The two share a name and nothing else. This lesson is about values; the normal forms have a module of their own.

GATE DA

Section 5 of the GATE 2027 DA syllabus names this lesson’s four topics in one phrase, “data transformation such as normalization, discretization, sampling, compression” (GATE 2027 DA syllabus), and this lesson takes them in that order.

Scaling: min-max and z-scores

For a value x in a column with minimum m, maximum M, mean μ and standard deviation σ:

x′=x−mM−mz=x−μσx' = \frac{x - m}{M - m} \qquad z = \frac{x - \mu}{\sigma}

Min-max scaling keeps the shape of the data and squeezes it into 0 to 1. A z-score centres the column on 0 and measures distance in standard deviations, so 2 means “two standard deviations above the mean”. Both are window functions in SQL, and SQLite, whose core has no standard-deviation function, gets the population one as the square root of the mean of squares minus the square of the mean:

Min-max and z-scores of eight customers' monthly spend SQL · scaling.sql
-- Monthly spend of eight customers, in rupees: two ways to put it on a common scale.
CREATE TABLE spend (customer TEXT PRIMARY KEY, rupees INTEGER NOT NULL);
INSERT INTO spend VALUES ('c1', 1200), ('c2', 800), ('c3', 4500), ('c4', 2300),
                         ('c5', 950), ('c6', 3100), ('c7', 1500), ('c8', 2650);

-- Min-max: (x - min) / (max - min), into [0, 1].
-- z-score: (x - mean) / standard deviation, here the population standard deviation, sqrt(mean of x² - mean²).
SELECT customer, rupees,
       printf('%.4f', (rupees - min(rupees) OVER ()) * 1.0 / (max(rupees) OVER () - min(rupees) OVER ())) AS min_max,
       printf('%.4f', (rupees - avg(rupees) OVER ())
                      / sqrt(avg(rupees * rupees) OVER () - avg(rupees) OVER () * avg(rupees) OVER ())) AS z_score
FROM spend ORDER BY rupees;
SELECT avg(rupees) AS mean, printf('%.4f', sqrt(avg(rupees * rupees) - avg(rupees) * avg(rupees))) AS population_sd FROM spend;

Output

┌──────────┬────────┬─────────┬─────────┐
│ customer │ rupees │ min_max │ z_score │
├──────────┼────────┼─────────┼─────────┤
│ c2       │ 800    │ 0.0000  │ -1.1159 │
│ c5       │ 950    │ 0.0405  │ -0.9895 │
│ c1       │ 1200   │ 0.1081  │ -0.7790 │
│ c7       │ 1500   │ 0.1892  │ -0.5263 │
│ c4       │ 2300   │ 0.4054  │ 0.1474  │
│ c8       │ 2650   │ 0.5000  │ 0.4421  │
│ c6       │ 3100   │ 0.6216  │ 0.8211  │
│ c3       │ 4500   │ 1.0000  │ 2.0001  │
└──────────┴────────┴─────────┴─────────┘
┌────────┬───────────────┐
│  mean  │ population_sd │
├────────┼───────────────┤
│ 2125.0 │ 1187.4342     │
└────────┴───────────────┘

Recorded with sql.js 1.14.2 (SQLite 3.49.1) on macOS 26 arm64. To run it yourself: sqlite3 -box :memory: < scaling.sql

Python’s statistics module computes the same numbers independently, with fmean for the mean and pstdev for the population standard deviation (Python: statistics):

The same scaling in Python, as a check Python · scaling_check.py
"""The same min-max and z-scores computed with Python's statistics module, to
check the SQL: fmean for the mean, pstdev for the population standard deviation."""
import math
import statistics

spend = {"c1": 1200, "c2": 800, "c3": 4500, "c4": 2300, "c5": 950, "c6": 3100, "c7": 1500, "c8": 2650}
values = list(spend.values())
lo, hi = min(values), max(values)
mean, sd = statistics.fmean(values), statistics.pstdev(values)

print(f"mean {mean}, population sd {sd:.4f}")
for customer, x in sorted(spend.items(), key=lambda kv: kv[1]):
    print(f"{customer} {x:>5} min-max {(x - lo) / (hi - lo):.4f} z {(x - mean) / sd:.4f}")

# The SQL computed the standard deviation as sqrt(mean of squares - square of mean); compare it with pstdev.
sql_sd = math.sqrt(sum(x * x for x in values) / len(values) - mean * mean)
print(f"largest difference between the two standard deviations: {abs(sql_sd - sd):.1e}")

Output

mean 2125.0, population sd 1187.4342
c2   800 min-max 0.0000 z -1.1159
c5   950 min-max 0.0405 z -0.9895
c1  1200 min-max 0.1081 z -0.7790
c7  1500 min-max 0.1892 z -0.5263
c4  2300 min-max 0.4054 z 0.1474
c8  2650 min-max 0.5000 z 0.4421
c6  3100 min-max 0.6216 z 0.8211
c3  4500 min-max 1.0000 z 2.0001
largest difference between the two standard deviations: 0.0e+00

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 scaling_check.py

Every value agrees to four decimals, and the two standard deviations agree exactly. Customer c3’s spend of 4,500 has a z-score of 2.0001: two standard deviations above the mean of 2,125.

Binning: equal width and equal frequency

Equal-width binning cuts the range into k bins of the same size. Equal-frequency binning puts the same number of rows in each bin, which SQL’s ntile(k) does directly; SQLite’s manual says ntile divides the partition into k groups as evenly as possible (SQLite: window functions). On skewed data the two disagree sharply:

Twelve delivery times in equal-width and equal-frequency bins SQL · binning.sql
-- Delivery times of twelve orders, in minutes: most are quick, a few are very late.
CREATE TABLE delivery (id INTEGER PRIMARY KEY, minutes INTEGER NOT NULL);
INSERT INTO delivery (minutes) VALUES (12), (14), (15), (15), (17), (18), (20), (22), (25), (31), (44), (78);

-- Equal width: 4 bins of (max - min) / 4 = 16.5 minutes each. Equal frequency: ntile(4), 3 orders per bin.
WITH b AS (
  SELECT minutes,
         min(3, CAST((minutes - min(minutes) OVER ()) * 4.0 / (max(minutes) OVER () - min(minutes) OVER ()) AS INTEGER)) + 1 AS width_bin,
         ntile(4) OVER (ORDER BY minutes) AS frequency_bin
  FROM delivery)
SELECT 'equal width' AS method, width_bin AS bin, count(*) AS orders, min(minutes) || '-' || max(minutes) AS minutes
FROM b GROUP BY width_bin
UNION ALL
SELECT 'equal frequency', frequency_bin, count(*), min(minutes) || '-' || max(minutes) FROM b GROUP BY frequency_bin
ORDER BY method DESC, bin;

Output

┌─────────────────┬─────┬────────┬─────────┐
│     method      │ bin │ orders │ minutes │
├─────────────────┼─────┼────────┼─────────┤
│ equal width     │ 1   │ 9      │ 12-25   │
│ equal width     │ 2   │ 2      │ 31-44   │
│ equal width     │ 4   │ 1      │ 78-78   │
│ equal frequency │ 1   │ 3      │ 12-15   │
│ equal frequency │ 2   │ 3      │ 15-18   │
│ equal frequency │ 3   │ 3      │ 20-25   │
│ equal frequency │ 4   │ 3      │ 31-78   │
└─────────────────┴─────┴────────┴─────────┘

Recorded with sql.js 1.14.2 (SQLite 3.49.1) on macOS 26 arm64. To run it yourself: sqlite3 -box :memory: < binning.sql

Twelve delivery times in four equal-width bins hold 9, 2, 0 and 1 orders; in four equal-frequency bins they hold 3 orders each.Equal width: 4 bins of 16.5 minutesEqual frequency: 3 orders per bin12 to 28.5 min9 orders45 to 61.5 min0 orders28.5 to 45 min2 orders61.5 to 78 min1 order12 to 15 min3 orders20 to 25 min3 orders15 to 18 min3 orders31 to 78 min3 orderssame 12 values

The same twelve delivery times, binned two ways

Text description of the diagram

The figure bins the lesson's twelve delivery times, from 12 to 78 minutes, into four bins in two ways.

Equal width, on top: the range from 12 to 78 minutes is cut into four bins of 16.5 minutes. The first bin, 12 to 28.5 minutes, holds 9 orders; the second, 28.5 to 45, holds 2; the third, 45 to 61.5, holds none; the fourth, 61.5 to 78, holds the single late order.

Equal frequency, below: each bin holds 3 orders, so the bins are 12 to 15 minutes, 15 to 18, 20 to 25 and 31 to 78. The bins are narrow where the data is dense and wide where it is sparse. Because two orders took 15 minutes and the bins split at a count, one of them falls in the first bin and the other in the second.

Equal-width bins put 9 of the 12 orders in the first bin and none in the third: the one 78-minute order stretched the range. Equal-frequency bins hold 3 orders each and adapt to the data, but the two 15-minute orders landed in different bins. Binning also changes the type of a column, in the terms Stevens proposed: from a ratio scale, where differences and ratios mean something, to an ordinal one, where only the order of the bins does (Stevens).

Sampling: random, systematic, stratified and cluster

  • A simple random sample gives every row the same chance.
  • A systematic sample takes every k-th row.
  • A stratified sample takes a fixed share of each group, such as each city.
  • A cluster sample picks whole groups, such as whole stores or whole disk blocks, and keeps all their rows.

A sample that must be reproduced, for a report that others will check, needs a fixed rule rather than a fresh random draw. The example keeps a row when a hash of its key falls in the lowest 10 %:

Three samples of about 10 % of 10,000 orders SQL · sampling.sql
-- 10,000 orders from five cities of very different sizes. Three samples of about 10 %, each one repeatable.
CREATE TABLE orders (id INTEGER PRIMARY KEY, city TEXT NOT NULL, amount INTEGER NOT NULL);
WITH RECURSIVE n(i) AS (SELECT 1 UNION ALL SELECT i + 1 FROM n WHERE i < 10000)
INSERT INTO orders
SELECT i, CASE WHEN i % 100 < 50 THEN 'Mumbai' WHEN i % 100 < 75 THEN 'Pune' WHEN i % 100 < 90 THEN 'Nagpur'
               WHEN i % 100 < 97 THEN 'Nashik' ELSE 'Kolhapur' END,
       200 + (i * 7919) % 1800
FROM n;

-- Simple random sample: keep a row when a hash of its key falls in the lowest 10 % (the same rows on every run).
CREATE VIEW random_10 AS SELECT * FROM orders WHERE (id * 2654435761) % 4294967296 < 429496730;
-- Systematic sample: every 10th order.
CREATE VIEW every_10th AS SELECT * FROM orders WHERE id % 10 = 7;
-- Stratified sample: 10 % of each city, ranked inside the city by the same hash.
CREATE VIEW stratified_10 AS
SELECT id, city, amount FROM (
  SELECT *, row_number() OVER (PARTITION BY city ORDER BY (id * 2654435761) % 4294967296) AS r,
         count(*) OVER (PARTITION BY city) AS c FROM orders)
WHERE r <= round(c * 0.10);

SELECT o.city, count(*) AS population,
       (SELECT count(*) FROM random_10 s WHERE s.city = o.city) AS random,
       (SELECT count(*) FROM every_10th s WHERE s.city = o.city) AS systematic,
       (SELECT count(*) FROM stratified_10 s WHERE s.city = o.city) AS stratified
FROM orders o GROUP BY o.city ORDER BY population DESC;
SELECT (SELECT avg(amount) FROM orders) AS population_mean, (SELECT avg(amount) FROM random_10) AS random_mean,
       (SELECT avg(amount) FROM every_10th) AS systematic_mean, (SELECT avg(amount) FROM stratified_10) AS stratified_mean;

Output

┌──────────┬────────────┬────────┬────────────┬────────────┐
│   city   │ population │ random │ systematic │ stratified │
├──────────┼────────────┼────────┼────────────┼────────────┤
│ Mumbai   │ 5000       │ 501    │ 500        │ 500        │
│ Pune     │ 2500       │ 244    │ 200        │ 250        │
│ Nagpur   │ 1500       │ 156    │ 200        │ 150        │
│ Nashik   │ 700        │ 64     │ 0          │ 70         │
│ Kolhapur │ 300        │ 35     │ 100        │ 30         │
└──────────┴────────────┴────────┴────────────┴────────────┘
┌─────────────────┬─────────────┬─────────────────┬─────────────────┐
│ population_mean │ random_mean │ systematic_mean │ stratified_mean │
├─────────────────┼─────────────┼─────────────────┼─────────────────┤
│ 1100.62         │ 1103.812    │ 1102.0          │ 1104.459        │
└─────────────────┴─────────────┴─────────────────┴─────────────────┘

Recorded with sql.js 1.14.2 (SQLite 3.49.1) on macOS 26 arm64. To run it yourself: sqlite3 -box :memory: < sampling.sql

The random and stratified samples kept each city’s share close to the population’s, and the stratified one exactly. The systematic sample went wrong: it has no order from Nashik and more than three times Kolhapur’s share, because the cities repeat in a pattern of 100 rows that its step of 10 keeps hitting in the same places. PostgreSQL has sampling built in: TABLESAMPLE BERNOULLI or SYSTEM after a table name, with REPEATABLE (seed) for the same sample twice (PostgreSQL 18: SELECT).

Compression: lossless and lossy

  • Lossless compression gives back exactly the original: dictionary encoding replaces repeated values by short codes, and run-length encoding stores a value once with the number of times it repeats.
  • Lossy compression gives back an approximation: quantisation rounds values to fewer levels, and dimensionality reduction such as principal component analysis keeps fewer columns that carry most of the variation.

Columnar warehouses lean on the lossless encodings, because a column of one type with many repeats compresses far better than a row of mixed types. Lossy methods are a decision about the analysis, not about storage.

Exercise

Exercise · Medium · SQL

z-scores of daily sales, shop by shop

The table sales (shop, day, amount) holds one row per shop per day. Shops differ in size, so their amounts are compared on a common scale: the z-score of each day's amount within its own shop.

Write one query that returns three columns, shop, day and z: (amount - mean) / sd, where the mean and the standard deviation are those of the shop's amounts, the standard deviation is the population one, and z is rounded to 3 decimals. The rows may come in any order.

Starter code · zscores.sql

-- z-score of each day's amount within its shop: shop, day, z (population standard deviation, 3 decimals).
SELECT shop, day, 0 AS z
FROM sales;
The sample tests · tests.yaml
# Sample tests: each one builds the table, runs your query on it and compares the rows it returns (in any order).
tests:
  - name: "one shop, three days"
    setup: |
      CREATE TABLE sales (shop TEXT NOT NULL, day INTEGER NOT NULL, amount INTEGER NOT NULL, PRIMARY KEY (shop, day));
      INSERT INTO sales VALUES ('Pune', 1, 10), ('Pune', 2, 20), ('Pune', 3, 30);
    expected:
      columns: [shop, day, z]
      rows:
        - [Pune, 1, -1.225]
        - [Pune, 2, 0.0]
        - [Pune, 3, 1.225]
  - name: "two shops on very different scales: each scaled within itself"
    setup: |
      CREATE TABLE sales (shop TEXT NOT NULL, day INTEGER NOT NULL, amount INTEGER NOT NULL, PRIMARY KEY (shop, day));
      INSERT INTO sales VALUES ('Mumbai', 1, 100), ('Mumbai', 2, 200), ('Mumbai', 3, 300), ('Mumbai', 4, 400),
        ('Kochi', 1, 5), ('Kochi', 2, 5), ('Kochi', 3, 8);
    expected:
      columns: [shop, day, z]
      rows:
        - [Mumbai, 1, -1.342]
        - [Mumbai, 2, -0.447]
        - [Mumbai, 3, 0.447]
        - [Mumbai, 4, 1.342]
        - [Kochi, 1, -0.707]
        - [Kochi, 2, -0.707]
        - [Kochi, 3, 1.414]
A hint

A window with PARTITION BY shop gives each row its own shop's aggregates: avg(amount) OVER (PARTITION BY shop) is the shop's mean. SQLite has no standard-deviation function, but the population one is the square root of the mean of the squares minus the square of the mean, and sqrt() is available.

The sample tests run on this device, in your browser (sql.js): nothing is sent to mysmartcopilot.com. The first run downloads SQLite (about 0.7 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Check yourself

Check yourself

5 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.

  1. Question 1 of 5 Monthly spend ranges from 800 to 4,500. What is the min-max scaled value of 2,650? Give 2 decimals.

    Type a number.

    Show the answer to question 1

    Answer: 0.5 (anything from 0.495 to 0.505 counts)

    (2,650 - 800) / (4,500 - 800) = 1,850 / 3,700 = 0.50. The lesson's run shows the same 0.5000 for customer c8.

  2. Question 2 of 5 A column has mean 2,125 and population standard deviation 1,187.4. What is the z-score of 4,500? Give 2 decimals.

    Type a number.

    Show the answer to question 2

    Answer: 2 (anything from 1.995 to 2.005 counts)

    (4,500 - 2,125) / 1,187.4 = 2,375 / 1,187.4 = 2.00: the value lies two standard deviations above the mean.

  3. Question 3 of 5 Delivery times run from 12 to 78 minutes and are cut into 4 equal-width bins numbered 1 to 4. Which bin holds an order that took 44 minutes?

    Type a number.

    Show the answer to question 3

    Answer: 2 bin

    Each bin is (78 - 12) / 4 = 16.5 minutes wide, so bin 2 covers 28.5 up to 45 minutes. 44 is in it: (44 - 12) / 16.5 = 1.94, which rounds down to 1, and bins are numbered from 1.

  4. Question 4 of 5 A data science syllabus lists "normalization" under data transformation. What does the word mean there?

    Choose one answer.

    Show the answer to question 4

    Answer: Rescaling the values of a column, such as min-max scaling or z-scores

    In data transformation, normalisation rescales values onto a common scale. Normal forms are a different idea with the same name: they remove redundancy from a schema.

  5. Question 5 of 5 In the lesson's run, why did the every-10th-row sample contain no order from Nashik at all?

    Choose one answer.

    Show the answer to question 5

    Answer: The cities repeat in a fixed pattern of 100 rows, and every 10th row always lands on the same positions of that pattern

    Rows were assigned to cities by id modulo 100, and ids ending in 7 never fall in Nashik's positions 90 to 96. A systematic sample is only as good as the order of the rows: any cycle that matches its step biases it.

Scaling that survives outliers, constant columns and new data, measured Pro: opens with a Pro, Premium or Ultimate pass

Min-max and z-scores are one line of SQL each, and each breaks on data that every real table contains. This part reproduces three of those breaks, measures a floating-point failure of the usual variance formula, and sets out the rules that keep a scaled column valid when new rows arrive.

In this part:

  • Three traps reproduced: an outlier, a constant column, a missing value
  • Robust scaling, and the variance formula that fails on large values
  • Population or sample standard deviation, and fitting on training rows only

2 runnable examples (Python, SQL) · about 3 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Bins and samples you can reproduce, with their failures measured Pro: opens with a Pro, Premium or Ultimate pass

A bin or a sample that cannot be reproduced cannot be checked, and one that is biased gives wrong answers with confidence. This part fixes the tie problem of equal-frequency bins in SQL, measures three sampling failures in a seeded run, and sizes the samples a stratified design needs.

In this part:

  • Equal-frequency bins that keep ties together
  • Three sampling failures, measured
  • Stratified samples, sized

2 runnable examples (Python, SQL) · about 3 minutes

Opening this part with your pass…Pro part. It opens with the same pass as the part above.

Compression for analysis: dictionary, run-length and quantisation, with sizes Pro: opens with a Pro, Premium or Ultimate pass

How much a column shrinks depends less on the algorithm than on the order and the precision of the data. This part measures dictionary and run-length encoding on a sorted and an unsorted column, quantises a measurement with its largest error, and turns the numbers into a choice.

In this part:

  • Dictionary and run-length encoding, sorted and unsorted, measured
  • Quantisation, and the largest error it allows
  • Delta encoding for sorted numbers, worked
  • Choosing a method

1 runnable example (Python) · about 2 minutes

Opening this part with your pass…Pro part. It opens with the same pass as the part above.

Interview questions

  1. Fresher · Warm-up

    What are the two meanings of "normalisation" in data work, and how do min-max scaling and z-scores differ?

    In database design, normalisation decomposes tables into normal forms such as 3NF to remove redundancy. In data transformation, it rescales the values of a column onto a common scale, which is the sense data-science syllabi use. Min-max scaling maps a column onto 0 to 1 with (x - min) / (max - min), keeping the shape of the data. A z-score, (x - mean) / standard deviation, centres the column on 0 and measures each value in standard deviations, so 2 means two standard deviations above the mean. Min-max is bounded but depends entirely on the two extreme values; z-scores are unbounded and depend on the mean and the spread.

  2. Mid to senior

    A churn model scored 0.91 in testing and 0.78 in production. The pipeline min-max scaled every feature on the full dataset, then split it into training and test sets. What went wrong, and how do you rebuild the pipeline?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  3. Mid to senior

    Analysts need a 1 % sample of a 2-billion-row orders table that keeps each city's share, and the same sample every time the query runs, so that their numbers can be checked. How do you draw it in SQL, and what does it cost?

    Model answer, Pro. First step and follow-ups

  4. Fresher to mid

    A report bins customers' annual income into 5 bands. Incomes are heavily skewed: most are modest and a few are very large. Would you use equal-width or equal-frequency bins, and how would you write them in SQL?

    Model answer, Pro. First step and follow-ups

Key takeaways

  • Normalisation of values rescales them; normalisation of schemas means normal forms. Data-transformation syllabi mean the first.
  • Min-max maps a column onto 0 to 1; a z-score counts standard deviations from the mean. Both are window functions in SQL.
  • Equal-width bins follow the range and equal-frequency bins follow the rows; skewed data separates them sharply.
  • Random, systematic, stratified and cluster samples differ in how rows are chosen; a hash of the key makes a sample repeatable.
  • Lossless compression returns the data exactly, lossy compression approximately, within a bound you state.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.