Repository: pandas-dev/pandas

Issue:
print df.ix[..,..] changes dataframe?
These two codeblocks result in different dataframes:

``` python
import pandas as pd
import numpy as np
cont = ['one', 'two','three', 'four', 'five', 'six', 'seven']
dfb = pd.DataFrame({'a' : cont, "b":cont[3:]+cont[:3] ,'c' : np.arange(7)})
#print dfb.ix[0,"c"]
dfb.ix[7,'c'] = 1
print dfb
print dfb.ix[7,"c"]
print dfb.ix[0,"c"]

       a      b  c
0    one   four  0
1    two   five  1
2  three    six  2
3   four  seven  3
4   five    one  4
5    six    two  5
6  seven  three  6
7    NaN    NaN  1
1.0
0.0
```

and 

``` python
import pandas as pd
import numpy as np
cont = ['one', 'two','three', 'four', 'five', 'six', 'seven']
dfb = pd.DataFrame({'a' : cont, "b":cont[3:]+cont[:3] ,'c' : np.arange(7)})
print dfb.ix[0,"c"]
dfb.ix[7,'c'] = 1
print dfb
print dfb.ix[7,"c"]
print dfb.ix[0,"c"]

0
       a      b   c
0    one   four   0
1    two   five   1
2  three    six   2
3   four  seven   3
4   five    one   4
5    six    two   5
6  seven  three   6
7    NaN    NaN NaN
nan
0.0
```

pd.**version** = '0.12.0-922-gac1609e'

In the first case I also don't understand why the last column is changed to a float when I set an int.



Discussion:
I don't have time to look at this today, but I'm guessing it has something to do with ix maybe caching something on the Series. The change to a float is a nice pointer, because it suggests that the column was astyped to float when it gained a missing value and never changed back.  Or @jreback will come in and fix it in 30 seconds with his hands tied behind his back blind-folded. :)


Resolving patch:
diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py
--- a/pandas/core/indexing.py
+++ b/pandas/core/indexing.py
@@ -189,9 +189,13 @@ def _setitem_with_indexer(self, indexer, value):
                         return self.obj
 
                     # reindex the axis
+                    # make sure to clear the cache because we are
+                    # just replacing the block manager here
+                    # so the object is the same
                     index = self.obj._get_axis(i)
                     labels = _safe_append_to_index(index, key)
                     self.obj._data = self.obj.reindex_axis(labels,i)._data
+                    self.obj._maybe_update_cacher(clear=True)
 
                     if isinstance(labels,MultiIndex):
                         self.obj.sortlevel(inplace=True)
@@ -223,7 +227,8 @@ def _setitem_with_indexer(self, indexer, value):
                     if len(self.obj.values):
                         new_values = np.concatenate([self.obj.values, new_values])
 
-                    self.obj._data = self.obj._constructor(new_values, index=new_index, name=self.obj.name)
+                    self.obj._data = self.obj._constructor(new_values,
+                                                           index=new_index, name=self.obj.name)._data
                     self.obj._maybe_update_cacher(clear=True)
                     return self.obj
 


Test patch:
diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py
--- a/pandas/tests/test_frame.py
+++ b/pandas/tests/test_frame.py
@@ -3539,24 +3539,6 @@ def test_operators_timedelta64(self):
         self.assertTrue(df['off1'].dtype == 'timedelta64[ns]')
         self.assertTrue(df['off2'].dtype == 'timedelta64[ns]')
 
-    def test__slice_consolidate_invalidate_item_cache(self):
-        # #3970
-        df = DataFrame({ "aa":lrange(5), "bb":[2.2]*5})
-
-        # Creates a second float block
-        df["cc"] = 0.0
-
-        # caches a reference to the 'bb' series
-        df["bb"]
-
-        # repr machinery triggers consolidation
-        repr(df)
-
-        # Assignment to wrong series
-        df['bb'].iloc[0] = 0.17
-        df._clear_item_cache()
-        self.assertAlmostEqual(df['bb'][0], 0.17)
-
     def test_new_empty_index(self):
         df1 = DataFrame(randn(0, 3))
         df2 = DataFrame(randn(0, 3))
diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py
--- a/pandas/tests/test_indexing.py
+++ b/pandas/tests/test_indexing.py
@@ -1645,6 +1645,41 @@ def test_cache_updating(self):
         result = df.loc[(0,0),'z']
         self.assert_(result == 2)
 
+    def test_slice_consolidate_invalidate_item_cache(self):
+        # #3970
+        df = DataFrame({ "aa":lrange(5), "bb":[2.2]*5})
+
+        # Creates a second float block
+        df["cc"] = 0.0
+
+        # caches a reference to the 'bb' series
+        df["bb"]
+
+        # repr machinery triggers consolidation
+        repr(df)
+
+        # Assignment to wrong series
+        df['bb'].iloc[0] = 0.17
+        df._clear_item_cache()
+        self.assertAlmostEqual(df['bb'][0], 0.17)
+
+    def test_setitem_cache_updating(self):
+        # GH 5424
+        cont = ['one', 'two','three', 'four', 'five', 'six', 'seven']
+
+        for do_ref in [False,False]:
+            df = DataFrame({'a' : cont, "b":cont[3:]+cont[:3] ,'c' : np.arange(7)})
+
+            # ref the cache
+            if do_ref:
+                df.ix[0,"c"]
+
+            # set it
+            df.ix[7,'c'] = 1
+
+            self.assert_(df.ix[0,'c'] == 0.0)
+            self.assert_(df.ix[7,'c'] == 1.0)
+
     def test_floating_index_doc_example(self):
 
         index = Index([1.5, 2, 3, 4.5, 5])