Concepts / Model Evaluation with Train and Test Splits

Model Evaluation with Train and Test Splits

Linear models can struggle with skewed features that have many small values and a few very large ones, and transforming such features often improves the fit.

  • Programming

Why a Few Huge Values Cause Trouble

Many real datasets contain a feature whose values are mostly small, with a handful of extremely large values sitting far to the right. Counts, prices, and durations often look like this. The feature may carry useful information about the target, yet a linear model can still struggle with it. This article shows why that happens, how a logarithm-based transformation helps, and how to decide which features are worth transforming.

What do you think happens?

Before we transform anything, consider the expression log(x + 1) when x = 0. What is its value?

  • 0

  • 1

  • It is undefined

  • -1

Reveal answer
Answer:

0

Adding 1 turns x = 0 into 1, and the logarithm of 1 is 0. This is exactly why the form log(x + 1) is used: a plain logarithm of 0 is undefined, but the +1 keeps every value of zero or more inside the range where the logarithm is defined.

Tracing a Skewed Feature

Picture a feature whose values cluster near zero while a few values sit far above the rest. If you plot it, the points form a long tail stretching to the right. Statisticians call this a skewed distribution. Follow the values through a linear model step by step. A linear model fits a straight-line relationship between each feature and the target. When a few values are enormous, they dominate that fit. The many small values are squeezed into a tiny region of the scale, where the model cannot tell them apart well.

Consider a made-up count feature with five observations: 0, 1, 3, 12, and 950. Four of the values are below 13, but the last one is 950. On a raw scale, the gap between 0 and 12 is almost invisible next to the gap between 12 and 950. A straight line that tries to account for the 950 point is pulled far away from the cluster of small values, so the small values receive almost no distinct treatment. The fastest way to see this in practice is to fit a model on the raw data and look at the held-out test score.

Compressing Values with log(x + 1)

A logarithm compresses large values. Once it is applied, the very large values move much closer to the bulk of the data, while the small values, which were crowded together, occupy a wider stretch of the scale. The feature becomes more evenly spread, and a linear relationship can describe it more effectively. The transformation changes the scale of the feature. It does not discard any of its values.

Read the diagram from top to bottom in each column. Before the transform, the raw gap from 12 to 950 is enormous compared with the gap from 0 to 3. After the transform, the largest value is 6.86, and the small values are spread across a visibly wider range relative to it. The 950 observation is still the largest value, but it no longer dominates the scale.

python
Output (expected)
[0.   0.69 1.39 2.56 6.86]
Notes on the code
  • np.log1p(x) computes log(x + 1) for every element of the array in one call
  • Zero stays a valid input, which is why the +1 form is used instead of a plain logarithm
  • np.round is only used here to make the printed output easier to read

Worked Example: Transforming a Count Feature

Worked example

Applying log(x + 1) to a feature with zeros and a large outlier

A feature records the number of visits per customer: 0, 1, 3, 12, and 950. Apply log(x + 1) and describe what happens to the spread.

  1. 1
    Add 1 to each value

    The shifted values are 1, 2, 4, 13, and 951. The zero has become 1, so every value is now at least 1.

  2. 2
    Take the natural logarithm

    The results are approximately 0, 0.69, 1.39, 2.56, and 6.86. The zero maps to exactly 0.

  3. 3
    Compare the gaps

    On the raw scale, the gap between 12 and 950 is 938, which is far larger than the gap between 0 and 12. On the log scale, the gap between 2.56 and 6.86 is 4.30, while the gap between 0 and 2.56 is 2.56. The large value now sits at a more moderate distance from the rest.

  4. 4
    Confirm no value was lost

    There are still five observations in the same order. Only the scale changed.

Result

The feature now has the same five ordered observations, with the very large value pulled closer to the bulk of the data, so a linear relationship can describe it more evenly.

Deciding Which Features to Transform

There is no single transformation that always works. Finding the best transformation for each combination of dataset and model is somewhat of an art. In the source's example, every feature happened to share the same properties, which is rarely true in practice. Usually only a subset of the features should be transformed, and sometimes each feature needs its own transformation.

Feature is skewed?many small values, a fewvery largeModel is linear?for example linear or ridgeTry log(x + 1)compare held-out testscoresLeave valuesunchangedtree-based models usuallyneed no transformyesnoyesno, tree-based
Given a feature's distribution and the model type, which path leads to applying a log transform and which leads to skipping it?

The flowchart captures the main decision. Tree-based models are generally unaffected by these transforms, while linear models often depend on them. The source also notes that binning, polynomials, and interactions can have a large influence on less complex models such as linear models and naive Bayes models. Other models, including SVMs, nearest neighbors, and neural networks, may sometimes benefit, but the effect is usually less predictable. Because the effect is empirical, the practical test is to compare held-out scores with and without the transform.

Reducing Feature Count with Univariate Selection

Transformations change the values of existing features. A second lever is to change how many features the model sees. It is tempting to create many new features, but adding features makes all models more complex and raises the chance of overfitting. When the feature count is high, it can be wise to keep only the most useful features and discard the rest, which can produce simpler models that generalize better.

The source describes three basic strategies: univariate statistics, model-based selection, and iterative selection. All three are supervised, meaning they use the target. Univariate selection scores each feature independently against the target, keeps the top percentile of features, and passes the reduced set to the model. SelectPercentile is the scikit-learn tool for keeping a chosen percentage of the highest-scoring features.

All featuresfull training columnsScore each featureindependent univariatescore against targetKeep top percentilefor example the top 50percentReduced feature setfewer columnsModelfit on reduced features
What happens to the full set of features as each is scored independently, the top percentile is kept, and the reduced set is passed to the model?
python
Notes on the code
  • f_regression is a univariate score function that rates each feature against a numeric target
  • percentile=50 keeps the top half of the features by score
  • fit_transform uses the target, so it is called on the training data only
  • transform applies the already-learned selection to the test data without refitting

Checking Reduced Features on a Held-Out Test Set

Because feature selection uses the target, it is supervised, and it must be fitted only on the training portion of the data. The test set must remain untouched during selection. If the selector saw the test targets, the test score would no longer measure performance on unseen data, and it would look better than the model deserves.

Full datasetall rows and featuresTrain splitused to fit the selectorFit selectoruses training targetsModeltrained on reduced trainingdataTest scoreperformance on unseen dataTest splitkept untouched untilscoringApply selectorno refittingsplitsplitselected columnsreduced featurespredict on test
How does data move from the train/test split through feature selection and into the model so that the test score measures performance on unseen data?

Follow the diagram from the full dataset. The training split is used to fit the selector, which decides which columns survive. The test split then passes through the same learned selection without being used to make any choice. The model is trained on the reduced training data, and the test score reflects how it performs on rows it has never seen. Compare this score against the score from the unreduced features to judge whether the reduction helped.

Mistakes When Transforming and Selecting Features

  • Common mistake

    Applying log(x) directly to a feature that contains zeros

    What it looks like

    np.log(counts) where counts includes 0 produces negative infinity for those rows.

    Why it fails

    The logarithm of zero is undefined, so the zero values cannot be represented after a plain logarithm.

    Do this instead

    Use log(x + 1), written in NumPy as np.log1p(counts), which keeps zero valid.

  • Common mistake

    Transforming every feature by default

    What it looks like

    Applying a log transform to every column, including features that are already evenly spread.

    Why it fails

    The source notes that only a subset of features usually needs transforming, and the best choice is empirical.

    Do this instead

    Inspect each feature's distribution and compare held-out scores with and without the transform.

  • Common mistake

    Expecting tree-based models to benefit from the same transforms

    What it looks like

    Adding a log transform before a tree-based model and expecting a large jump in accuracy.

    Why it fails

    Tree-based models are generally unaffected by these transforms, while linear models often depend on them.

    Do this instead

    Save the transform effort for linear and similar models, and test before assuming any gain.

  • Common mistake

    Fitting feature selection on the full dataset

    What it looks like

    Calling fit_transform on all rows before splitting into train and test.

    Why it fails

    Selection uses the target, so the test targets leak into the choice of features and the test score is no longer a fair check.

    Do this instead

    Fit the selector on the training split only, then call transform on the test split.

  • Common mistake

    Keeping every feature because more features seem more informative, even though extra features increase complexity and overfitting risk

Practice: Choosing a Transform and a Selection Rule

MEDIUM

A dataset has a feature called daily_downloads with values 0, 2, 5, 9, 40, and 2000, and a linear regression model predicts a score. Describe whether you would apply log(x + 1) to daily_downloads, which function you would call in NumPy, and how you would confirm the choice using a held-out test score.

Hints
  • Look for the pattern of many small values with a few very large ones, and check whether the feature contains zeros.
  • A linear model is the kind of model that often depends on this transform, while a tree-based model usually does not.
  • Compare the test score with and without the transform, fitting any selection on the training split only.

Key Takeaways

  • Skewed features, with many small values and a few very large ones, can squeeze most of the data into a small region of the scale, which limits how well a linear model fits.
  • The form log(x + 1), written as np.log1p in NumPy, compresses large values, keeps zeros valid, and preserves the order of the observations.
  • Transform only the features that benefit, decide empirically, and remember that tree-based models usually do not need these transforms.
  • Univariate selection with SelectPercentile reduces the feature count, must be fitted on training data only, and should be checked with a held-out test score.

Related concepts

More concepts starting with M