Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MRG: deprecate ddof / bias args to corrcoef #5675

Closed

Conversation

matthew-brett
Copy link
Contributor

As discussed on the mailing list, the values for the bias and ddof
arguments to the corrcoef cancel in calculation, and are therefore
pointless and confusing.

Deprecate these arguments and document their pending removal.

This PR also includes a version of the warnings.catch_warnings decorator
that allows warnings to be tested for multiple times without error.

@njsmith
Copy link
Member

njsmith commented Mar 13, 2015

You mean "context manager", not " decorator". Everything else looks good to
me (on a quick skim at least).
On Mar 12, 2015 5:32 PM, "Matthew Brett" notifications@github.com wrote:

As discussed on the mailing list, the values for the bias and ddof
arguments to the corrcoef cancel in calculation, and are therefore
pointless and confusing.

Deprecate these arguments and document their pending removal.

This PR also includes a version of the warnings.catch_warnings decorator

that allows warnings to be tested for multiple times without error.

You can view, comment on, or merge this pull request online at:

#5675
Commit Summary

  • ENH+TST: add decorator for testing warnings
  • BUG: deprecation for ignored corrcoef args

File Changes

Patch Links:


Reply to this email directly or view it on GitHub
#5675.

Warnings can be slippery, because, whenever a warning is
triggered, Python adds a __warningregistry__ member to the *calling*
module.  This makes it impossible to retrigger the warning in this
module, whatever you put in simplefilter.  The `catch_warn_reset`
decorator removes the __warningregistry__ member as the context
manager exits, making it possible to retrigger the warning.
The `ddof` and `bias` arguments to `corrcoef` cancel in the math of the
correlation coefficient, so there is no point in passing these values,
and it is confusing to the user to see these in the docstring.

Remove, deprecate, and test.
@matthew-brett
Copy link
Contributor Author

Thanks - I fixed references to 'decorator'.

The main question that I have is what to do about the 'bias' argument to np.ma.extras.corrcoef. It is before a still-used argument allow_masked.

It might be prudent to plan to make allow_masked a keyword-only argument at the same time as the end of the deprecation period for bias, so intended inputs to bias don't get picked up by allow_masked. This would involve deprecating allow_masked as a positional argument.

arguments had no effect on the return values of the function and can be
safely ignored in this and previous versions of numpy.
"""
if len(args) or kwargs.pop('bias', _DefaultArg) is not _DefaultArg:
Copy link
Member

Choose a reason for hiding this comment

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

We are opening the door to lots of nonsense input going through silently, e.g. extra keyword or positional arguments, bias and ddof being provided as both positional and keyword simultaneously... May not be worth adding all those checks for something we actually want to deprecate, but...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Checking for simultaneous positional and keyword does seem too much for arguments that don't have any effect on the function. We are already warning about their use.

It's easy to check for the length of args and kwargs after parsing though.

"allow_masked" follows "bias" argument, but "bias" will go away at some
point.  Intend that we will make "allow_masked" keyword only at the same
time that we remove "bias".
Raise errors for the wrong number of positional arguments or incorrect
keyword arguments in corrcoef routines.
@matthew-brett
Copy link
Contributor Author

I added a deprecation warning for allow_masked as positional argument as above.

I added checks for number of positional args and unexpected keyword args.

@@ -48,7 +48,7 @@
from numpy import ndarray, array as nxarray
import numpy.core.umath as umath
from numpy.lib.index_tricks import AxisConcatenator
from numpy.linalg import lstsq
from numpy.lib.function_base import _CORRCOEF_MSG_FMT, _DefaultArg
Copy link
Member

Choose a reason for hiding this comment

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

Just repeat the definition here. This import complicates the code, obscures the value of _CORRCOEF_MSG_FMT, and introduces a dependency between modules. The format is temporary anyway. No reason not to also put the private _DefaultArg here also, and for the same reasons.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Willco.

Any suggestions for a good place for _DefaultArg?

Copy link
Member

Choose a reason for hiding this comment

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

Since its use is entirely local, it might be better to just define it in each module in which it is used. It is going to be temporary, at least in the numpy sense of temporary. Otherwise, I might suggest numpy/__init__.py, which already has a couple of global classes. In the latter case a more suggestive name might help.

Rather than importing the small code support fragments from
function_base.py, replicate them to make the code easier to read.
Note that this is the Pearson product-moment correlation.

Note the pending change of allow_masked to keyword-only.
Add ability to add default modules to catch_warn_reset classs, by
inheritance.
@charris
Copy link
Member

charris commented Mar 14, 2015

Both the deprecation and context manager should be mentioned in the release notes. Apropos the context manager, a separate PR might be best. A name closer to the standard catch_warnings would also be good something like catch_and_reset_warnings. I also wonder if it wouldn't be possible to just integrate it into assert_warns?

@charris
Copy link
Member

charris commented Mar 14, 2015

Or maybe catch_and_clear_warnings for added alliteration.

Use inheritance of catch_warn_reset for slightly cleaner context
managers.
@matthew-brett
Copy link
Contributor Author

No problem for separate PR, and renaming of context manager.

Adding to assert_warns would need a new 'modules' argument to assert_warns, at least the way I have written it.

Sckit-image go for a more magic and more nuclear solution, always clearing out all recorded previous warnings for modules in the call stack:

https://github.com/scikit-image/scikit-image/blob/master/skimage/_shared/_warnings.py

@charris
Copy link
Member

charris commented Mar 14, 2015

Google also turned up that nuclear option. So there is no easy way to know what module a warning was raised in when it is caught?

@matthew-brett
Copy link
Contributor Author

I don't know of any way to find out what module the warning was raised in, from the warning itself...

@charris
Copy link
Member

charris commented Mar 14, 2015

Thinking about it, both the format and class could be local to the function, that way everything could be deleted at one go when it comes to that.

@matthew-brett
Copy link
Contributor Author

My worry about putting the class definition and format string in the funciton was that it made the meat of the function harder to read. I can imagine that it might be distracting to see this little piece of uncecessarily repeated work inside the function.

@charris
Copy link
Member

charris commented Mar 14, 2015

Good point. OTOH, if it is outside the function one wonders where else it is used.

Move the format strings into the function, as they are only used in the
function.
@matthew-brett
Copy link
Contributor Author

I was hoping that wondering where else it is used it more typical of the keen-eyed maintainer than the casual developer or user.

I've moved just the string into the function - how about that?

@charris
Copy link
Member

charris commented Mar 14, 2015

OK. Too bad we can't just use None. Hmm..., if the default value of ddof is made 0, I think None would be OK.

@matthew-brett
Copy link
Contributor Author

My worry with None is that it's not possible to tell whether the user passed it, thinking the argument still existed.

@charris
Copy link
Member

charris commented Mar 14, 2015

How about just check for the key, then pop it if present and issue the warning?

@matthew-brett
Copy link
Contributor Author

Your nit-pick is my command.

If this is all good I'll rebase into two PRs.

warnings.warn(fmt.format('ddof'), DeprecationWarning)
if len(kwargs):
raise TypeError(
"corrcoef got an unexpected keyword argument '{0}'".format(
Copy link
Member

Choose a reason for hiding this comment

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

Note that you can break this line

raise TypeError("corrcoef got an unexpected keyword "
                "argument '{0}'".format(list(kwargs)[0])

@charris
Copy link
Member

charris commented Mar 14, 2015

LGTM, go for it. I tossed in another nitpick...

@matthew-brett
Copy link
Contributor Author

OK to rename context manager to catch_clear_warnings ?

@charris
Copy link
Member

charris commented Mar 14, 2015

I'd probably leave the _and_ in there.

@charris
Copy link
Member

charris commented Mar 14, 2015

Although I confess to being a bit unsure why the context manager is needed. Does this fix a problem when the tests are run in interactive mode?

@matthew-brett
Copy link
Contributor Author

I moved the context manager into numpy.testing.utils and added more docstring - does the docstring help explain the problem the context manager is trying to solve?

@matthew-brett
Copy link
Contributor Author

OK to go ahead with 2 PRs from this state?

@@ -1,10 +1,16 @@
from __future__ import division, absolute_import, print_function

import warnings
from warnings import warn, simplefilter
Copy link
Member

Choose a reason for hiding this comment

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

We usually just import warnings and use it in the warnings.warn form.

@charris
Copy link
Member

charris commented Mar 14, 2015

Sure. I won't guarantee no more comments, but I think this is getting close.

@matthew-brett
Copy link
Contributor Author

Maybe the context manager should better be called catch_all_warnings_mods or something else to reflect the fact that it only resets the warnings registry inside the context manager.

@matthew-brett
Copy link
Contributor Author

Or clear_and_catch_warnings

@matthew-brett
Copy link
Contributor Author

OK - I think this is ready now - will split into separate PRs soon.

@matthew-brett
Copy link
Contributor Author

Context manager PR here : #5682

@matthew-brett
Copy link
Contributor Author

Deprecation stuff here : #5683

@charris
Copy link
Member

charris commented Mar 15, 2015

OK, I'll close this now.

@charris charris closed this Mar 15, 2015
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.

4 participants