Short answer
Start from the decision the model must make, then collect examples of real use that you have the right to use, remove personal details and duplicates, and record where everything came from. In a measured test, the same model scored 100% on a careless split and 90% on an honest one, and it scored no better than chance on French messages it had never been shown.
Follow-up question How do you know the data is enough before you train anything big?
A dataset teaches a job only if it looks like the job. That sounds obvious until you notice how often training data is whatever was easy to collect. A model learns the patterns in its examples, whether or not they are the ones you meant.
This project builds a small dataset for one decision: route each customer message of a fictional bike shop to refunds, shipping, repairs or accounts. All 2,120 raw messages are generated by a script, so no real person's data is involved. The companion script 03_build_dataset.py needs only scikit-learn and takes seconds. If you are preparing text for a language model rather than a routing decision, this guide to preparing a dataset covers the cleaning and storage steps at larger scale.
Step 1: write the job down first
Before collecting anything, fill in this sheet. It is a shorter cousin of the datasheets researchers proposed for documenting a dataset's motivation, composition, collection process and uses.
| Question | Example answer |
|---|---|
| What decision will the model make? | Pick one of four queues |
| What does it see at that moment? | The message text only, no customer history |
| Who writes those inputs? | Customers, in English and French |
| What does a wrong answer cost? | A delay of one transfer between queues |
| Who decides the right label, and how? | Two staff members, written definitions |
| Where may this data come from? | Our own messages, with notice and consent; openly licensed text |
The second-to-last row is often skipped. If two careful people disagree on the label, the model cannot do better than they can.
Step 2: run it through four gates
Each record carries where it came from. The pipeline refuses, cleans, removes duplicates and then splits, keeping a count for every step.
OK_LICENCES = {"own-records-with-consent", "cc0", "cc-by-4.0"}
def pipeline(rows):
kept = [r for r in rows if r["licence"] in OK_LICENCES] # gate 1: rights
for r in kept:
r["text"], r["scrubbed"] = scrub(r["text"]) # gate 2: personal details
seen, out = set(), []
for r in kept:
key = normalize(r["text"]) # gate 3: duplicates
if key not in seen:
seen.add(key)
out.append(r)
return out # gate 4: split by wording family
Measured here on the synthetic data:
| Step | Rows |
|---|---|
| Raw | 2,120 |
| Refused: unknown or unapproved licence | −236 |
| Duplicates removed | −236 |
| Final | 1,648 |
The scrubber used patterns for email addresses, phone numbers and Canadian postal codes. It caught all 279 planted details, with no false alarms. Do not read too much into that perfect score: the script planted only the formats the patterns look for. Names in free text, such as "my neighbour Mara", pass straight through. On real data, have a person read a random sample, and treat scrubbing as a reduction of risk.
The final file ships with a manifest: row counts per label, per licence and a SHA-256 fingerprint, a short code that changes if one byte of the data changes. When a score moves next month, you can tell whether the data moved.
What the gates change, in numbers
Each figure below is an average of five runs. The model is deliberately simple: word counts fed to a logistic regression.
| Test | Accuracy |
|---|---|
| Duplicates kept, random split | 100% |
| Clean data, test on wordings never seen in training | 90.2% |
| Same honest test, 10% of training labels wrong | 72.2% |
| 30% of training labels wrong | 60.5% |
| 50% of training labels wrong | 41.3% |
| French messages, English-only training | 25.0%, exactly chance |
The first two rows use the same recipe. The difference is the split. A careless split puts near-copies of a message on both sides, so the test measures memory. Splitting by wording family, all the variations of one way of asking, gives a much more useful number. scikit-learn has group-aware splitters for this. Real equivalents of a family include one customer, one document, one recording session.
The last row is the most important in a place like Québec. An English-only dataset gave a model that scored 25% on French, the same as a coin with four sides. Accuracy on your test set says nothing about the people who are missing from it.
The legal side, in plain terms
This is general information and not legal advice. Rules differ by country and change; ask a lawyer before relying on any of this for a product.
| Source of data | Question to answer | Usual action |
|---|---|---|
| Your own records about customers or staff | Did the person know it could be used this way? Is it personal information? | Remove identifiers, check your privacy policy, get consent if the use is new |
| Openly licensed text, for example CC0 or CC BY | Which exact licence applies to which file? Must you credit? | Keep the licence and the source with each file |
| Public domain books | Public domain where you are? Added material may not be | Record the edition; remove any added notices |
| A website that you scrape | Terms of use? Copyright? Technical blocks? | Assume no until shown otherwise |
| Other people's published model outputs | Do the terms allow training? | Read them first |
In Canada, the Copyright Act lists fair dealing purposes such as research, private study and education, and text and data mining is not among the listed purposes. It also prohibits getting around technological protection measures, with listed exceptions. In the United States, courts are deciding these questions case by case, and how the material was obtained has mattered.
In Québec, Law 25 has strengthened the rules on personal information and the powers of the Commission d'accès à l'information. A dataset of customer messages very likely holds personal information. Using it to train a model may be a new purpose. Write down your answer, and ask the person responsible for privacy in your organization.
Try it: Take ten real examples of your own task and fill in the job sheet. Note every row where you wrote "not sure", and resolve those before you collect a single further example.
How do you know the data is enough before you train anything big?
Draw a learning curve: train on growing subsets and test on the same honest set. Measured here, averaged over five runs:
| Training rows | Accuracy on unseen wordings |
|---|---|
| 20 | 40.9% |
| 40 | 50.8% |
| 80 | 71.8% |
| 160 | 83.8% |
| 320 | 88.9% |
| 640 | 90.4% |
| All (about 1,370) | 90.2% |
Past about 640 rows, more of the same stopped helping. That is a signal to change what you collect, not how much. A second experiment shows it directly. With about 140 rows, using one wording family per label gave 40.5%; the same number of rows drawn across all the families gave 83.0%. Same size, double the skill.
If the curve is still climbing at your largest size, collect more of the same kind. If it is flat and you need better results, collect what is missing: new wordings, the hard cases, the second language. Then fix label errors, because the noise table shows how costly they are, and only after that consider a larger model. Before you believe any improvement, run the honest testing in project four.
Download the companion code for this series (zip), with every script and the recorded results.
Sources
- Datasheets for Datasets — arXiv, March 23, 2018
- Copyright Act (R.S.C., 1985, c. C-42) — Justice Laws Website, Government of Canada, November 7, 2024
- Entrée en vigueur des nouvelles dispositions de la Loi 25 — Gouvernement du Québec (Secrétariat à la réforme des institutions démocratiques, à l'accès à l'information et à la laïcité), September 22, 2023
From the Guide to Artificial Intelligence, by Robert Scales, published by Holistic Hybrid Inc. Share and adapt it under CC BY-NC-SA 4.0: credit the guide, link to https://guidetoartificialintelligence.com/en/learn/build-dataset-teaches-job-legally/, no commercial use without permission, and keep the same licence.