diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 9b70bda82e247..b30b2c885be40 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -468,6 +468,7 @@ Other API Changes - :meth:`PeriodIndex.tz_convert` and :meth:`PeriodIndex.tz_localize` have been removed (:issue:`21781`) - :class:`Index` subtraction will attempt to operate element-wise instead of raising ``TypeError`` (:issue:`19369`) - :class:`pandas.io.formats.style.Styler` supports a ``number-format`` property when using :meth:`~pandas.io.formats.style.Styler.to_excel` (:issue:`22015`) +- :meth:`DataFrame.corr` and :meth:`Series.corr` now raise a ``ValueError`` along with a helpful error message instead of a ``KeyError`` when supplied with an invalid method (:issue:`22298`) .. _whatsnew_0240.deprecations: diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 700562386c838..42a6795935cdc 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -6658,7 +6658,7 @@ def corr(self, method='pearson', min_periods=1): elif method == 'spearman': correl = libalgos.nancorr_spearman(ensure_float64(mat), minp=min_periods) - else: + elif method == 'kendall': if min_periods is None: min_periods = 1 mat = ensure_float64(mat).T @@ -6682,6 +6682,10 @@ def corr(self, method='pearson', min_periods=1): c = corrf(ac, bc) correl[i, j] = c correl[j, i] = c + else: + raise ValueError("method must be either 'pearson', " + "'spearman', or 'kendall', '{method}' " + "was supplied".format(method=method)) return self._constructor(correl, index=idx, columns=cols) diff --git a/pandas/core/series.py b/pandas/core/series.py index 4b4fccccda4a0..8bf87e0ede664 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1931,8 +1931,14 @@ def corr(self, other, method='pearson', min_periods=None): this, other = self.align(other, join='inner', copy=False) if len(this) == 0: return np.nan - return nanops.nancorr(this.values, other.values, method=method, - min_periods=min_periods) + + if method in ['pearson', 'spearman', 'kendall']: + return nanops.nancorr(this.values, other.values, method=method, + min_periods=min_periods) + + raise ValueError("method must be either 'pearson', " + "'spearman', or 'kendall', '{method}' " + "was supplied".format(method=method)) def cov(self, other, min_periods=None): """ diff --git a/pandas/tests/frame/test_analytics.py b/pandas/tests/frame/test_analytics.py index f72cf8cdaafe9..f06c8336373ca 100644 --- a/pandas/tests/frame/test_analytics.py +++ b/pandas/tests/frame/test_analytics.py @@ -130,6 +130,14 @@ def test_corr_cov_independent_index_column(self): assert result.index is not result.columns assert result.index.equals(result.columns) + def test_corr_invalid_method(self): + # GH PR #22298 + df = pd.DataFrame(np.random.normal(size=(10, 2))) + msg = ("method must be either 'pearson', 'spearman', " + "or 'kendall'") + with tm.assert_raises_regex(ValueError, msg): + df.corr(method="____") + def test_cov(self): # min_periods no NAs (corner case) expected = self.frame.cov() diff --git a/pandas/tests/series/test_analytics.py b/pandas/tests/series/test_analytics.py index 09e89115e120e..dccc12643a6ad 100644 --- a/pandas/tests/series/test_analytics.py +++ b/pandas/tests/series/test_analytics.py @@ -778,6 +778,15 @@ def test_corr_rank(self): tm.assert_almost_equal(A.corr(B, method='kendall'), kexp) tm.assert_almost_equal(A.corr(B, method='spearman'), sexp) + def test_corr_invalid_method(self): + # GH PR #22298 + s1 = pd.Series(np.random.randn(10)) + s2 = pd.Series(np.random.randn(10)) + msg = ("method must be either 'pearson', 'spearman', " + "or 'kendall'") + with tm.assert_raises_regex(ValueError, msg): + s1.corr(s2, method="____") + def test_cov(self): # full overlap tm.assert_almost_equal(self.ts.cov(self.ts), self.ts.std() ** 2)