Repository: pandas-dev/pandas

Issue:
BUG: fancy setitem on a mixed-frame with a series fails
```
In [35]: df = pandas.DataFrame({'x':range(10), 'y':range(10,20),'z' : 'bar'})

In [36]: df.ix[df.x % 2 == 0, 'y'] = df.ix[df.x % 2 == 0, 'y'].values * 100

In [37]: df
Out[37]: 
   x     y    z
0  0  1000  bar
1  1    11  bar
2  2  1000  bar
3  3    13  bar
4  4  1000  bar
5  5    15  bar
6  6  1000  bar
7  7    17  bar
8  8  1000  bar
9  9    19  bar
```



Discussion:

Resolving patch:
diff --git a/pandas/core/common.py b/pandas/core/common.py
--- a/pandas/core/common.py
+++ b/pandas/core/common.py
@@ -851,6 +851,7 @@ def _maybe_upcast_indexer(result, indexer, other, dtype=None):
         return the result and a changed flag
         """
 
+    original_dtype = result.dtype
     def changeit():
         # our type is wrong here, need to upcast
         r, fill_value = _maybe_upcast(result, fill_value=other, dtype=dtype, copy=True)
@@ -861,9 +862,11 @@ def changeit():
             # if we hit this then we still have an incompatible type
             r[indexer] = fill_value
 
+        # if we have changed to floats, might want to cast back if we can
+        r = _possibly_downcast_to_dtype(r,original_dtype)
         return r, True
 
-    new_dtype, fill_value = _maybe_promote(result.dtype,other)
+    new_dtype, fill_value = _maybe_promote(original_dtype,other)
     if new_dtype != result.dtype:
         return changeit()
 
diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py
--- a/pandas/core/indexing.py
+++ b/pandas/core/indexing.py
@@ -143,7 +143,7 @@ def setter(item, v):
                         else:
                             setter(item, np.nan)
 
-                # we have an equal len ndarray
+                # we have an equal len ndarray to our labels
                 elif isinstance(value, np.ndarray) and value.ndim == 2:
                     if len(labels) != value.shape[1]:
                         raise ValueError('Must have equal len keys and value when'
@@ -153,7 +153,8 @@ def setter(item, v):
                         setter(item, value[:,i])
 
                 # we have an equal len list/ndarray
-                elif len(labels) == 1 and len(self.obj[labels[0]]) == len(value):
+                elif len(labels) == 1 and (
+                    len(self.obj[labels[0]]) == len(value) or len(plane_indexer[0]) == len(value)):
                     setter(labels[0], value)
 
                 # per label values


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
@@ -938,12 +938,6 @@ def test_getitem_setitem_non_ix_labels(self):
         assert_frame_equal(result, expected)
         assert_frame_equal(result2, expected)
 
-    def test_ix_assign_column_mixed(self):
-        # GH #1142
-        orig = self.mixed_frame.ix[:, 'B'].copy()
-        self.mixed_frame.ix[:, 'B'] = self.mixed_frame.ix[:, 'B'] + 1
-        assert_series_equal(self.mixed_frame.B, orig + 1)
-
     def test_ix_multi_take(self):
         df = DataFrame(np.random.randn(3, 2))
         rs = df.ix[df.index == 0, :]
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
@@ -881,7 +881,7 @@ def test_multi_assign(self):
 
         expected = DataFrame({'FC':['a',np.nan,'a','b','a','b'],
                               'PF':[0,0,0,0,1,1],
-                              'col1':Series([0,1,4,6,8,10],dtype='float64'),
+                              'col1':Series([0,1,4,6,8,10]),
                               'col2':[12,7,16,np.nan,20,22]})
         
 
@@ -898,6 +898,27 @@ def test_multi_assign(self):
         df2.ix[mask, cols]= dft.ix[mask, cols].values
         assert_frame_equal(df2,expected)
 
+    def test_ix_assign_column_mixed(self):
+        # GH #1142
+        df = DataFrame(tm.getSeriesData())
+        df['foo'] = 'bar'
+
+        orig = df.ix[:, 'B'].copy()
+        df.ix[:, 'B'] = df.ix[:, 'B'] + 1
+        assert_series_equal(df.B, orig + 1)
+
+        # GH 3668, mixed frame with series value
+        df = DataFrame({'x':range(10), 'y':range(10,20),'z' : 'bar'})
+        expected = df.copy()
+        expected.ix[0, 'y'] = 1000
+        expected.ix[2, 'y'] = 1200
+        expected.ix[4, 'y'] = 1400
+        expected.ix[6, 'y'] = 1600
+        expected.ix[8, 'y'] = 1800
+
+        df.ix[df.x % 2 == 0, 'y'] = df.ix[df.x % 2 == 0, 'y'] * 100
+        assert_frame_equal(df,expected)
+
     def test_iloc_mask(self):
 
         # GH 3631, iloc with a mask (of a series) should raise