{"course":{"slug":"machine-learning-foundations","title":"Machine Learning, Foundations","url":"https://addaly.com/learn/machine-learning-foundations","level":"intermediate","track":"start"},"lesson":{"slug":"the-shape-of-a-dataset","title":"What a row is, and why that decision is the whole project","url":"https://addaly.com/learn/machine-learning-foundations/the-shape-of-a-dataset","position":3,"of":92,"minutes":9,"answer":"Decide what one row is and when the target becomes knowable before you write any code, because every split, metric and deployment decision inherits that choice silently.","keyIdea":"Decide what one row is and when the target becomes knowable before you write any code, because every split, metric and deployment decision inherits that choice silently."},"body":{"format":"markdown","text":"## The two objects\n\nAlmost all of classical machine learning operates on two objects. A matrix `X` with one row per thing and one column per measurement, and a vector `y` with one entry per row: the answer you want the model to produce.\n\n```python\nimport numpy as np\nX = np.array([[35, 42000, 3],\n              [51, 88000, 0],\n              [24, 19000, 7]])   # age, annual income, late payments\ny = np.array([0, 0, 1])          # defaulted within 12 months?\nX.shape, y.shape   # ((3, 3), (3,))\n```\n\nThat is it. Three rows, three columns, three labels. Everything later in this course (trees, boosting, neural networks) is a different way of turning the left object into a guess at the right one.\n\nThe interesting part is not the code. It is the sentence you had to commit to before you could type it.\n\n## \"One row is one ____\"\n\nFinish that sentence out loud before you write anything. It is called the **unit of analysis**, or the *grain*, and getting it wrong is the most expensive mistake in this course because nothing downstream complains.\n\nA bank asks: *can we predict default?* There are at least four honest datasets hiding in that question.\n\n- One row is **one customer**. Then a customer with eleven loans appears once, and you must decide what \"defaulted\" means across eleven loans.\n- One row is **one loan**. Then the same customer appears eleven times, and eleven rows share almost every column. Your model will learn that customer, and when you split the data randomly, that customer appears on both sides of the split. The score comes out beautifully and means nothing.\n- One row is **one customer-month**. Now you can predict *default in the next 30 days*, which is a different and often more useful product.\n- One row is **one application**, including the ones you rejected. This is the only grain that can answer *should we have approved it*, and it is the one you almost never have labels for, because rejected applicants never got the chance to repay.\n\nThose four datasets have different sizes, different targets, different splits and different deployments. Choosing between them is a product decision wearing a data costume.\n\n## The target needs a clock\n\n`y` is not a column you find. It is a definition you write, and it has to contain a moment.\n\n\"Churned\" is not a label. \"Had no transaction in the 60 days following the observation date\" is a label. \"Fraud\" is not a label; \"was charged back within 90 days\" is. The moment matters because the label has to be *knowable later than the features and not before*, and because a shorter window gives you more labelled rows but a noisier target, while a longer one gives cleaner labels and less recent data. There is no right answer, only a stated one.\n\nWrite it as one line at the top of the notebook:\n\n> **Row:** one loan application. **Features:** everything known at the moment of submission. **Target:** 1 if 90 days past due within 12 months of disbursal, else 0. **Excluded:** anything recorded after disbursal.\n\nThat last clause is the one that saves you. We will return to it in the leakage lesson, but the guard is written here, at the point where the dataset is defined.\n\n## Columns have types, and the type changes the maths\n\nThree kinds of column behave differently and need different treatment later:\n\n- **Numerical**: age, income, distance. Order and distance both mean something. `income - 1000` is meaningful.\n- **Categorical**: city, product code, device. Values are names. `Mumbai + 1` is nonsense, and the moment you store cities as 0, 1, 2 you have told a linear model that Chennai sits between Mumbai and Delhi.\n- **Ordinal**: education level, star rating, T-shirt size. Order means something, distance does not. The gap between 1 star and 2 is not the gap between 4 and 5.\n\nAn ID column belongs to none of these and should almost never be a feature. A model that gets `customer_id` will happily memorise it.\n\n## Shape errors are the beginner's rite of passage\n\nMost first-week errors are shape errors, and the message is usually accurate but blunt. Two habits fix nearly all of them: print `X.shape` and `y.shape` after every transformation, and keep the convention that rows are samples and columns are features: scikit-learn assumes it everywhere, and a transposed matrix trains without complaint and predicts nonsense.\n\nA single sample has to be reshaped to a matrix of one row before you can predict on it:\n\n```python\nmodel.predict(np.array([[35, 42000, 3]]))   # note the double brackets\n```\n\n## The limitation\n\nThis rectangle is a strong assumption, and it is where a lot of real data does not fit. Text, images, audio, graphs and event streams are not naturally rectangular. What we do (and this is worth seeing clearly rather than absorbing by osmosis) is *force* them into the rectangle: counts of words, pixels flattened into columns, an event log aggregated into \"number of logins in the last 7 days\". Every one of those is a lossy choice made by a person, and most of the accuracy in a classical project comes from making those choices well rather than from the algorithm that eats the result.\n\nDeep learning's claim, which we will reach in module 8, is that it can learn the flattening itself. It is a real claim. It is also why it needs so much more data."},"check":{"question":"A team building a hospital readmission model has one row per hospital *visit*, and patients often visit many times. They split the rows randomly into train and test, and get 0.94 AUC. What is the mechanism that most likely inflated that score?","options":[{"text":"Visits are not independent: the same patient's rows land in both train and test, so the model can recognise the patient rather than the medical pattern.","correct":true},{"text":"AUC is the wrong metric for medical data, and accuracy would have shown the true, lower performance.","correct":false,"tempting":"Blames the metric for a data-splitting fault; the same contamination would inflate accuracy, F1 and every other score equally."},{"text":"The dataset has too many columns relative to the number of visits, so the model overfits the feature space.","correct":false,"tempting":"Describes ordinary overfitting, which would show up as a train-test gap. Here the test set itself is compromised, so the gap never appears."},{"text":"Readmission is a rare event, so the majority class dominates and the score is meaningless.","correct":false,"tempting":"Class imbalance distorts accuracy, but AUC is comparatively robust to base rate and would not be lifted to 0.94 by imbalance alone."}]},"prev":{"slug":"supervised-and-unsupervised","title":"With answers, and without","url":"https://addaly.com/learn/machine-learning-foundations/supervised-and-unsupervised"},"next":{"slug":"what-a-loss-function-encodes","title":"The loss is where you state what a mistake costs","url":"https://addaly.com/learn/machine-learning-foundations/what-a-loss-function-encodes"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'What a row is, and why that decision is the whole project', in Machine Learning, Foundations. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/machine-learning-foundations/the-shape-of-a-dataset (Accessed: 13 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"What a row is, and why that decision is the whole project","courseTitle":"Machine Learning, Foundations","module":{"index":1,"slug":"what-learning-is","title":"What learning is, and what it is not"},"answer":null,"keyIdea":"Decide what one row is and when the target becomes knowable before you write any code, because every split, metric and deployment decision inherits that choice silently.","hero":{"kind":"plate","image":null,"alt":null,"caption":null},"blocks":[{"t":"h2","id":"the-two-objects","runs":[{"text":"The two objects"}]},{"t":"p","runs":[{"text":"Almost all of classical machine learning operates on two objects. A matrix "},{"text":"X","code":true},{"text":" with one row per thing and one column per measurement, and a vector "},{"text":"y","code":true},{"text":" with one entry per row: the answer you want the model to produce."}]},{"t":"code","lang":"python","label":"Python","text":"import numpy as np\nX = np.array([[35, 42000, 3],\n              [51, 88000, 0],\n              [24, 19000, 7]])   # age, annual income, late payments\ny = np.array([0, 0, 1])          # defaulted within 12 months?\nX.shape, y.shape   # ((3, 3), (3,))"},{"t":"p","runs":[{"text":"That is it. Three rows, three columns, three labels. Everything later in this course (trees, boosting, neural networks) is a different way of turning the left object into a guess at the right one."}]},{"t":"p","runs":[{"text":"The interesting part is not the code. It is the sentence you had to commit to before you could type it."}]},{"t":"h2","id":"one-row-is-one","runs":[{"text":"“One row is one ____”"}]},{"t":"p","runs":[{"text":"Finish that sentence out loud before you write anything. It is called the "},{"text":"unit of analysis","b":true},{"text":", or the "},{"text":"grain","i":true},{"text":", and getting it wrong is the most expensive mistake in this course because nothing downstream complains."}]},{"t":"p","runs":[{"text":"A bank asks: "},{"text":"can we predict default?","i":true},{"text":" There are at least four honest datasets hiding in that question."}]},{"t":"ul","items":[[{"text":"One row is "},{"text":"one customer","b":true},{"text":". Then a customer with eleven loans appears once, and you must decide what “defaulted” means across eleven loans."}],[{"text":"One row is "},{"text":"one loan","b":true},{"text":". Then the same customer appears eleven times, and eleven rows share almost every column. Your model will learn that customer, and when you split the data randomly, that customer appears on both sides of the split. The score comes out beautifully and means nothing."}],[{"text":"One row is "},{"text":"one customer-month","b":true},{"text":". Now you can predict "},{"text":"default in the next 30 days","i":true},{"text":", which is a different and often more useful product."}],[{"text":"One row is "},{"text":"one application","b":true},{"text":", including the ones you rejected. This is the only grain that can answer "},{"text":"should we have approved it","i":true},{"text":", and it is the one you almost never have labels for, because rejected applicants never got the chance to repay."}]]},{"t":"p","runs":[{"text":"Those four datasets have different sizes, different targets, different splits and different deployments. Choosing between them is a product decision wearing a data costume."}]},{"t":"h2","id":"the-target-needs-a-clock","runs":[{"text":"The target needs a clock"}]},{"t":"p","runs":[{"text":"y","code":true},{"text":" is not a column you find. It is a definition you write, and it has to contain a moment."}]},{"t":"p","runs":[{"text":"“Churned” is not a label. “Had no transaction in the 60 days following the observation date” is a label. “Fraud” is not a label; “was charged back within 90 days” is. The moment matters because the label has to be "},{"text":"knowable later than the features and not before","i":true},{"text":", and because a shorter window gives you more labelled rows but a noisier target, while a longer one gives cleaner labels and less recent data. There is no right answer, only a stated one."}]},{"t":"p","runs":[{"text":"Write it as one line at the top of the notebook:"}]},{"t":"quote","runs":[{"text":"Row:","b":true},{"text":" one loan application. "},{"text":"Features:","b":true},{"text":" everything known at the moment of submission. "},{"text":"Target:","b":true},{"text":" 1 if 90 days past due within 12 months of disbursal, else 0. "},{"text":"Excluded:","b":true},{"text":" anything recorded after disbursal."}]},{"t":"p","runs":[{"text":"That last clause is the one that saves you. We will return to it in the leakage lesson, but the guard is written here, at the point where the dataset is defined."}]},{"t":"h2","id":"columns-have-types-and-the-type-changes-the-maths","runs":[{"text":"Columns have types, and the type changes the maths"}]},{"t":"p","runs":[{"text":"Three kinds of column behave differently and need different treatment later:"}]},{"t":"ul","items":[[{"text":"Numerical","b":true},{"text":": age, income, distance. Order and distance both mean something. "},{"text":"income - 1000","code":true},{"text":" is meaningful."}],[{"text":"Categorical","b":true},{"text":": city, product code, device. Values are names. "},{"text":"Mumbai + 1","code":true},{"text":" is nonsense, and the moment you store cities as 0, 1, 2 you have told a linear model that Chennai sits between Mumbai and Delhi."}],[{"text":"Ordinal","b":true},{"text":": education level, star rating, T-shirt size. Order means something, distance does not. The gap between 1 star and 2 is not the gap between 4 and 5."}]]},{"t":"p","runs":[{"text":"An ID column belongs to none of these and should almost never be a feature. A model that gets "},{"text":"customer_id","code":true},{"text":" will happily memorise it."}]},{"t":"h2","id":"shape-errors-are-the-beginner-s-rite-of-passage","runs":[{"text":"Shape errors are the beginner’s rite of passage"}]},{"t":"p","runs":[{"text":"Most first-week errors are shape errors, and the message is usually accurate but blunt. Two habits fix nearly all of them: print "},{"text":"X.shape","code":true},{"text":" and "},{"text":"y.shape","code":true},{"text":" after every transformation, and keep the convention that rows are samples and columns are features: scikit-learn assumes it everywhere, and a transposed matrix trains without complaint and predicts nonsense."}]},{"t":"p","runs":[{"text":"A single sample has to be reshaped to a matrix of one row before you can predict on it:"}]},{"t":"code","lang":"python","label":"Python","text":"model.predict(np.array([[35, 42000, 3]]))   # note the double brackets"},{"t":"h2","id":"the-limitation","runs":[{"text":"The limitation"}],"role":"limit"},{"t":"p","runs":[{"text":"This rectangle is a strong assumption, and it is where a lot of real data does not fit. Text, images, audio, graphs and event streams are not naturally rectangular. What we do (and this is worth seeing clearly rather than absorbing by osmosis) is "},{"text":"force","i":true},{"text":" them into the rectangle: counts of words, pixels flattened into columns, an event log aggregated into “number of logins in the last 7 days”. Every one of those is a lossy choice made by a person, and most of the accuracy in a classical project comes from making those choices well rather than from the algorithm that eats the result."}]},{"t":"p","runs":[{"text":"Deep learning’s claim, which we will reach in module 8, is that it can learn the flattening itself. It is a real claim. It is also why it needs so much more data."}]}],"check":{"question":[{"text":"A team building a hospital readmission model has one row per hospital "},{"text":"visit","i":true},{"text":", and patients often visit many times. They split the rows randomly into train and test, and get 0.94 AUC. What is the mechanism that most likely inflated that score?"}],"options":[{"text":[{"text":"Visits are not independent: the same patient’s rows land in both train and test, so the model can recognise the patient rather than the medical pattern."}],"correct":true,"tempting":null},{"text":[{"text":"AUC is the wrong metric for medical data, and accuracy would have shown the true, lower performance."}],"correct":false,"tempting":[{"text":"Blames the metric for a data-splitting fault; the same contamination would inflate accuracy, F1 and every other score equally."}]},{"text":[{"text":"The dataset has too many columns relative to the number of visits, so the model overfits the feature space."}],"correct":false,"tempting":[{"text":"Describes ordinary overfitting, which would show up as a train-test gap. Here the test set itself is compromised, so the gap never appears."}]},{"text":[{"text":"Readmission is a rare event, so the majority class dominates and the score is meaningless."}],"correct":false,"tempting":[{"text":"Class imbalance distorts accuracy, but AUC is comparatively robust to base rate and would not be lifted to 0.94 by imbalance alone."}]}],"order":[1,2,0,3],"why":null},"prev":{"slug":"supervised-and-unsupervised","title":"With answers, and without","minutes":7},"next":{"slug":"what-a-loss-function-encodes","title":"The loss is where you state what a mistake costs","minutes":9}}}