Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add optional parameter to return raw data for diabetes dataset - #16605

Merged
glemaitre merged 22 commits into
scikit-learn:mainfrom
happilyeverafter95:load_diabetes
Dec 17, 2021
Merged

Add optional parameter to return raw data for diabetes dataset#16605
glemaitre merged 22 commits into
scikit-learn:mainfrom
happilyeverafter95:load_diabetes

Conversation

@happilyeverafter95

@happilyeverafter95 happilyeverafter95 commented Mar 1, 2020

Copy link
Copy Markdown
Contributor

Issue

Diabetes dataset from sklearn.datasets had incorrect values (the target is fine).

For instance:

from sklearn.datasets import load_diabetes

load_diabetes().data

returns

array([[ 0.03807591,  0.05068012,  0.06169621, ..., -0.00259226,
         0.01990842, -0.01764613],
       [-0.00188202, -0.04464164, -0.05147406, ..., -0.03949338,
        -0.06832974, -0.09220405],
       [ 0.08529891,  0.05068012,  0.04445121, ..., -0.00259226,
         0.00286377, -0.02593034],
       ...,
       [ 0.04170844,  0.05068012, -0.01590626, ..., -0.01107952,
        -0.04687948,  0.01549073],
       [-0.04547248, -0.04464164,  0.03906215, ...,  0.02655962,
         0.04452837, -0.02593034],
       [-0.04547248, -0.04464164, -0.0730303 , ..., -0.03949338,
        -0.00421986,  0.00306441]])

What does this implement/fix? Explain your changes.

The compressed csv file was incorrect https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/datasets/data/diabetes_data.csv.gz

I uploaded data from the source file indicated in the description (https://www4.stat.ncsu.edu/~boos/var.select/diabetes.tab.txt)

Testing the same code locally yields:

array([[ 59.    ,   2.    ,  32.1   , ...,   4.8598,  87.    , 151.    ],
       [ 48.    ,   1.    ,  21.6   , ...,   3.8918,  69.    ,  75.    ],
       [ 72.    ,   2.    ,  30.5   , ...,   4.6728,  85.    , 141.    ],
       ...,
       [ 60.    ,   2.    ,  24.9   , ...,   4.1271,  95.    , 132.    ],
       [ 36.    ,   1.    ,  30.    , ...,   5.1299,  85.    , 220.    ],
       [ 36.    ,   1.    ,  19.6   , ...,   4.5951,  92.    ,  57.    ]])

Any other comments?

@happilyeverafter95 happilyeverafter95 changed the title Fix load_diabetes Fix load_diabetes dataset Mar 1, 2020
@jnothman

jnothman commented Mar 1, 2020 via email

Copy link
Copy Markdown
Member

@happilyeverafter95

happilyeverafter95 commented Mar 1, 2020

Copy link
Copy Markdown
Contributor Author

The dataset description included here says that each column has been scaled and centred, which accounts for this difference. I agree that there would be benefit in allowing the user to retrieve the raw values. Apart from anything else, there is some data leakage in scaling across training and test data. But this should be done by providing a parameter to optionally return standardized values (default True to preserve current behaviour).

My bad, I completely missed that part from the description. In addition to the leakage issue, not all the columns (for ex gender) makes sense to be scaled and centered. I can augment this pr to return raw vs scaled / centered based on an optional parameter

@happilyeverafter95 happilyeverafter95 changed the title Fix load_diabetes dataset Add optional parameter to return raw data for diabetes dataset Mar 2, 2020
@happilyeverafter95

Copy link
Copy Markdown
Contributor Author

Thanks @jnothman for feedback. I followed your suggestion and added an optional parameter standardized (defaults to True to preserve current behavior) which when set to False will load the raw data for the features.

@ogrisel

ogrisel commented Mar 3, 2020

Copy link
Copy Markdown
Member

Thanks! Could you please add a new test to check that the new option works as described?

For instance a new test that loads that when fetching the un-standardized data and standardizing our-selves we get a resulting data matrix that is close to the one we fetch when we call load_diabetes with standardized=True.

@happilyeverafter95

Copy link
Copy Markdown
Contributor Author

Thanks! Could you please add a new test to check that the new option works as described?

For instance a new test that loads that when fetching the un-standardized data and standardizing our-selves we get a resulting data matrix that is close to the one we fetch when we call load_diabetes with standardized=True.

I created a new test called load_diabetes_raw that checks for similar things as the other test for this dataset.

@ogrisel

ogrisel commented Mar 6, 2020

Copy link
Copy Markdown
Member

I would like to have a test that checks that the standardized values are what they are supposed to be but it does not seem to be the case. For instance the following test:

def test_load_diabetes_raw():
    diabetes_raw = load_diabetes(standardized=False)
    assert diabetes_raw.data.shape == (442, 10)
    assert diabetes_raw.target.size, 442
    assert len(diabetes_raw.feature_names) == 10
    assert diabetes_raw.DESCR

    diabetes_default = load_diabetes()

    np.testing.assert_allclose(
        scale(diabetes_raw.data),
        diabetes_default.data
    )

fails with:

    def test_load_diabetes_raw():
        diabetes_raw = load_diabetes(standardized=False)
        assert diabetes_raw.data.shape == (442, 10)
        assert diabetes_raw.target.size, 442
        assert len(diabetes_raw.feature_names) == 10
        assert diabetes_raw.DESCR
    
        diabetes_default = load_diabetes()
    
        n_samples = diabetes_raw.data.shape[0]
>       np.testing.assert_allclose(
            scale(diabetes_raw.data),
            diabetes_default.data
        )
E       AssertionError: 
E       Not equal to tolerance rtol=1e-07, atol=0
E       
E       Mismatched elements: 4420 / 4420 (100%)
E       Max absolute difference: 3.98049016
E       Max relative difference: 23.64621268
E        x: array([[ 0.8005  ,  1.065488,  1.297088, ..., -0.054499,  0.418531,
E               -0.370989],
E              [-0.039567, -0.938537, -1.08218 , ..., -0.830301, -1.436589,...
E        y: array([[ 0.038076,  0.05068 ,  0.061696, ..., -0.002592,  0.019908,
E               -0.017646],
E              [-0.001882, -0.044642, -0.051474, ..., -0.039493, -0.06833 ,...

I haven't had a deeper look but there is something wrong either in our data files or in the assumptions we make about them.

@happilyeverafter95

happilyeverafter95 commented Mar 8, 2020

Copy link
Copy Markdown
Contributor Author

Ah, from the dataset description:

Each of these 10 feature variables have been mean centered and scaled by the standard deviation times `n_samples` (i.e. the sum of squares of each column totals 1)

So looks like we would need to divide the raw values by 442 ** 0.5 after scaling it.

Adjusting for precision loss, this test no longer fails:

    np.testing.assert_allclose(
        scale(diabetes_raw.data) / (442 ** 0.5),
        diabetes_default.data,
        atol=1e-04
    )

@ogrisel ogrisel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification!

But now I have the following concern:

Comment thread sklearn/datasets/_base.py Outdated

standardized : bool, default=True
If True, the feature variables are mean centered and scaled by the
standard deviation times `n_samples`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this should be "standard deviation times the square root of n_samples.", no?

This is weird to call this "standardized" because it does not not match the usual Standardization we implement in StandardScaler.

Maybe we should rename this standardized parameter to a more neutral name such as preprocessed or scaled.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I changed the description to reflect standard deviation times the square root of n_samples and renamed the parameter to scaled.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just realized that I took the description from descr/diabetes.rst, so I updated that one too

@jnothman jnothman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy with this, but do we think it's necessary to distribute both diabetes_data_raw.csv.gz and diabetes_data.csv.gz, rather than just distributing one and scaling the data on the fly?

@cmarmo cmarmo added the Needs Decision Requires decision label Aug 25, 2020
Base automatically changed from master to main January 22, 2021 10:52
@rth

rth commented Aug 6, 2021

Copy link
Copy Markdown
Member

do we think it's necessary to distribute both diabetes_data_raw.csv.gz and diabetes_data.csv.gz, rather than just distributing one and scaling the data on the fly?

+1 for doing this.

@rth rth removed the Needs Decision Requires decision label Aug 6, 2021
@rth

rth commented Aug 6, 2021

Copy link
Copy Markdown
Member

I removed the (scaled) diabetes_data.csv.gz file and switched to relying on on the unscaled data diabetes_data_raw.csv.gzonly. This made a few docstests fail though, since the two versions of the data are only equal within a 1e-4 absolute tolerance. Fixed the corresponding doctests. In the end however, technically this would change slightly the exact values returned by load_diabetes .

I'm not sure whether we should go ahead (and consider this to be a fix) or not. In any case, I think shipping two versions of the data that's are not equal within float64 tolerance (which is much less that 1e-4) is not ideal.

@rth
rth requested a review from glemaitre August 6, 2021 14:59
@glemaitre

Copy link
Copy Markdown
Member

If we only have 2 docstring failings, then I think that we can use the proposed option to rescale the dataset.
It seems better than using a CSV with truncated floating precision.

@glemaitre glemaitre left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Waiting to see if there are some remaining failures but otherwise I will merge this one.

@glemaitre glemaitre self-assigned this Dec 17, 2021
@glemaitre glemaitre removed their assignment Dec 17, 2021
@glemaitre
glemaitre merged commit 379919d into scikit-learn:main Dec 17, 2021
@glemaitre

Copy link
Copy Markdown
Member

So all tests are passing now. I am merging. Thanks to all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants