diff --git a/doc/source/whatsnew/v0.16.0.txt b/doc/source/whatsnew/v0.16.0.txt index 0eeee8ccfddf6..4790017727005 100644 --- a/doc/source/whatsnew/v0.16.0.txt +++ b/doc/source/whatsnew/v0.16.0.txt @@ -454,6 +454,15 @@ Other API Changes To reproduce the old behavior, simply add more precision to the label (e.g., use ``2000-02-01`` instead of ``2000-02``). +- A Spurious ``SettingWithCopy`` Warning was generated when setting a new item in a frame in some cases (:issue:`8730`) + + The following would previously report a ``SettingWithCopy`` Warning. + + .. ipython:: python + + df1 = DataFrame({'x': Series(['a','b','c']), 'y': Series(['d','e','f'])}) + df2 = df1[['x']] + df2['y'] = ['g', 'h', 'i'] .. _whatsnew_0160.deprecations: diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 90a6cf60fa76b..4029aaec78a4a 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -1265,6 +1265,14 @@ def _check_setitem_copy(self, stacklevel=4, t='setting', force=False): except: pass + # we might be a false positive + try: + if self.is_copy().shape == self.shape: + self.is_copy = None + return + except: + pass + # a custom message if isinstance(self.is_copy, string_types): t = self.is_copy @@ -1344,8 +1352,9 @@ def take(self, indices, axis=0, convert=True, is_copy=True): result = self._constructor(new_data).__finalize__(self) # maybe set copy if we didn't actually change the index - if is_copy and not result._get_axis(axis).equals(self._get_axis(axis)): - result._set_is_copy(self) + if is_copy: + if not result._get_axis(axis).equals(self._get_axis(axis)): + result._set_is_copy(self) return result diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py index dc77ab8190e41..a633524343a49 100644 --- a/pandas/tests/test_indexing.py +++ b/pandas/tests/test_indexing.py @@ -3751,14 +3751,6 @@ def f(): assert_series_equal(s,df.iloc[:,0].order()) assert_series_equal(s,df[0].order()) - # operating on a copy - df = pd.DataFrame({'a': list(range(4)), 'b': list('ab..'), 'c': ['a', 'b', np.nan, 'd']}) - mask = pd.isnull(df.c) - - def f(): - df[['c']][mask] = df[['b']][mask] - self.assertRaises(com.SettingWithCopyError, f) - # false positives GH6025 df = DataFrame ({'column1':['a', 'a', 'a'], 'column2': [4,8,9] }) str(df) @@ -3790,6 +3782,24 @@ def f(): df['C'][2] = 'foo' self.assertRaises(com.SettingWithCopyError, f) + def test_setting_with_copy_bug(self): + + # operating on a copy + df = pd.DataFrame({'a': list(range(4)), 'b': list('ab..'), 'c': ['a', 'b', np.nan, 'd']}) + mask = pd.isnull(df.c) + + def f(): + df[['c']][mask] = df[['b']][mask] + self.assertRaises(com.SettingWithCopyError, f) + + # invalid warning as we are returning a new object + # GH 8730 + df1 = DataFrame({'x': Series(['a','b','c']), 'y': Series(['d','e','f'])}) + df2 = df1[['x']] + + # this should not raise + df2['y'] = ['g', 'h', 'i'] + def test_detect_chained_assignment_warnings(self): # warnings