Topic 2.1
Kinds of Data
In one line
Data comes in four kinds: quantitative (amounts), ordinal (ordered labels), categorical (unordered labels) and time. The kind decides what you may do with a column: sort it, average it, compare it, or only count it.
Think of it like this
A school form. Age is a number you can add and compare. Shirt size (S, M, L) has an order but no real gap between steps. Favourite colour has no order at all. Birthday is a point on a calendar. You would never average the colours, and you would not sort the sizes alphabetically, because L comes before M and S in the alphabet. Each kind of answer allows different things.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- quantitative
- Data that is an amount, so you can add, subtract and compare it: rides, minutes, temperature.
- categorical (nominal)
- Labels with no order, like station names. You can count and group them.
- ordinal
- Labels with an order but no fixed gaps, like Monday to Sunday.
- time data
- Dates and times: ordered, with a unit and special rules such as month lengths.
- ISO date
- A date written year-month-day, like 2025-03-09. It sorts correctly even as text.
- missing value
- A value that was not recorded. It is unknown, which is different from zero.
- identifier (ID)
- A label that names one thing, such as S01. It may contain digits but is not a number.
Step by step
01Sort each column into a kind
The first example takes a few real rows from stations.csv and daily.csv and tags each column with its kind. For each kind it lists what you may do: sort, compare, average, count.
Notice docks and rides (quantitative), district (categorical), weekday (ordinal), opened and date (time), and id (a label made of letters and digits).
02See what goes wrong with the wrong kind
The second example makes five classic mistakes on real rows from daily-dirty.csv and prints the result of each: a text sort of dates, an alphabetical weekday order, a missing value counted as 0, an ID treated as a number, and a number sort without a compare function.
None of them throws an error. Each one produces a plausible-looking wrong answer, which is why you check the kind before you draw.
03Decide what to do with a missing value
Line 3 of the second example shows the choice. Reading the empty cell as a number turns it into 0 and the mean falls from 1,730.75 to 1,384.6. Leaving it out keeps the mean honest, but now you have four days, not five, and you should say so.
Three honest options exist: leave a gap in the chart, drop the row, or fill the value in and mark it as estimated. Never fill it silently.
04Match the kind to the chart
Quantitative values suit position and length. Categories suit separate groups along one axis, with a sort order you choose on purpose. Ordinal values keep their fixed order. Time goes along an axis from left to right. The next two topics build on this.
Try it yourself
- 1
Add the missing value to the mean
In the second example, change the empty string in
cellsto"1700". The two means become equal, because there is no gap to mishandle. The gap is what makes the choice matter. - 2
Meet the dirty cells
In the second example, add this line before line 5:
console.log("6. dirty cells as numbers:", ["2,016", "n/a", "-1", ""].map(Number), "| null ->", Number(null), "| undefined ->", Number(undefined));. The Console prints6. dirty cells as numbers: [ NaN, NaN, -1, 0 ] | null -> 0 | undefined -> NaN. Two cells becameNaN(which a chart cannot draw), one became a believable-1, and the empty cell andnullbecame a quiet, believable0. Only theNaNs announce themselves.
Code & diagrams
Time and ordinal data can be sorted, but only quantitative data is averaged. Categorical data can only be counted and grouped.
Preview
Console
Nothing logged yet.Expected console output
id (categorical): never average this
name (categorical): never average this
district (categorical): never average this
opened (time): never average this
weekday (ordinal): never average thisNothing here throws an error. Every line gives an answer that looks reasonable and is wrong.
Console
(nothing was printed)Expected console output
1. dates sorted as text: [ '13/03/2025', '2025-03-02', '2025-03-09', '2025-03-10' ]
2. weekdays sorted as text: [ 'Fri', 'Mon', 'Sat', 'Sun', 'Thu', 'Tue', 'Wed' ]
weekdays in their real order: [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ]
3. empty cell read as a number: 0 -> mean 1384.6
empty cell left out: mean 1730.75
4. an ID as a number: 7790 - and back to text: 7790
5. numbers sorted without a compare function: [ 2979, 3742, 439 ]
numbers sorted properly: [ 439, 2979, 3742 ]Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Sort numbers without a compare function
In the second example, use only [3742, 439, 2979].sort() and read line 5 of the Console.
Myth vs fact
Myth
If a column is made of digits, it is a number.
Fact
Station codes, postcodes and phone numbers are labels. Ask: does adding two of them mean anything? If not, it is a label.
Myth
A missing value can be replaced by zero safely.
Fact
Zero is a real measurement ("nothing happened"). Missing means "we don't know". Mixing them drags averages down and draws false dives.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
Interval scales (temperature in °C, dates) have meaningful differences but no true zero, so ratios are meaningless; ratio scales (counts, minutes, kilometres) have a true zero. This is why a bar chart of temperature, with bars from 0 °C, is a quiet lie: 0 °C is not "no temperature". Use dots or a line for it.
- ▸
Ordinal data hides a trap: "low / medium / high" looks evenly spaced, but the gaps are not equal. Averaging them (mean of 1, 2, 3) is common and shaky; the median or the counts per level are safer.
Remember this
- 1
The problem this solves: a chart is built from columns of data. If you treat a column as the wrong kind, the chart looks fine and says something false: an average of station numbers, dates sorted as text, weekdays in alphabetical order. Knowing the kind first tells you which chart and which operations make sense.
- 2
Quantitative data is an amount you can add, subtract and compare: rides, minutes, kilometres, temperature, docks. Two sub-kinds matter. A count (rides) starts at zero and zero means "none". A measurement on a scale without a true zero (temperature in °C) has differences that make sense, but ratios do not: 20 °C is not "twice as warm" as 10 °C. Bars, which show ratios, suit counts; lines and dots suit both.
- 3
Categorical data (also called nominal) is labels with no order: station names, districts, bike types. You can count them and group by them, but not sort them in a meaningful way (alphabetical is only a convenience) and not average them. Ordinal data is labels that do have an order but no fixed gap between steps: weekdays Monday to Sunday, battery low / medium / full. Keep the real order (a list you write), never the alphabetical one.
- 4
Time data (dates and times) is its own kind because it has a natural order, a unit (day, month) and special rules: months have different lengths, clocks change in summer, and
2025-03-09is a date while"13/03/2025"is only text until you parse it. Dates in ISO form (2025-03-09) sort correctly as text; other formats do not. Topic 4.3 goes deep on time zones. - 5
Missing values are not zero. A day with no sensor reading is not a day with a reading of 0. In the Lumen data, Westpark's three stations opened on 2025-05-10, so its January to April figures are not "0 rides": the stations did not exist. (The file
station-month.csvstores 0 for those months. Here the 0 means "not open yet", and a chart must not treat it as a quiet month.) Drawing missing as zero pulls averages down and draws a line that dives to the floor. Decide on purpose: leave a gap, drop the row, or fill it in and say so (Topic 4.4). - 6
Cells that look like numbers but are not. Real exports hold
"2,016"(a thousands separator),"n/a", an empty cell, and codes such as-1for "the sensor failed".Number("2,016")isNaN,Number("n/a")isNaN,Number("")andNumber(null)are0, and-1is a perfectly valid number that quietly drags an average down. Each looks different and needs a different fix. Topic 4.4 cleans all of them on the realdaily-dirty.csv.
Explain it without notes
Name the four kinds of data and one Lumen column for each.
Why is a station ID such as S01 not a number even though it contains digits?
Why is a missing value not the same as zero? Give a Lumen example.
Practice
Write isNumberColumn(values) that returns true only if every non-empty value converts to a finite number and none starts with a zero followed by another digit (like "07790"). Test with ["12", "20"], ["07790", "09250"], ["S01", "S02"].
Write meanOf(values) for an array of strings that returns the mean of the numeric ones, skips empty strings and "n/a", and returns null when nothing numeric is left. Test with ["1539", "1519", "1950", "", "1915"] and ["", "n/a"].
Trade-offs
- ↔
Guessing a column's kind from its values is quick but wrong at the edges (IDs with leading zeros, years as numbers). Declaring the kind per column costs a few lines and removes the guesswork.
Done when you can
I can name the four kinds of data and give a Lumen column for each.
I can say what each kind allows: sort, compare, average, count.
I can spot an ID, a date written as text and a missing value before I draw.
I know why unsorted weekdays and alphabetical dates give a wrong chart.