Skip to content

Commit eb1b59f

Browse files
committed
BUG: address GH #135 and implement some setting on mixed-type DataFrame using .ix
1 parent dc990ae commit eb1b59f

File tree

4 files changed

+49
-11
lines changed

4 files changed

+49
-11
lines changed

pandas/core/frame.py

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ def f(self, other):
101101
class DataFrame(NDFrame):
102102
_auto_consolidate = True
103103
_verbose_info = True
104+
_het_axis = 1
104105

105106
_AXIS_NUMBERS = {
106107
'index' : 0,

pandas/core/indexing.py

+30-6
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,6 @@ def _getitem_xs(self, idx, axis=0):
3636
return self.obj.xs(idx, axis=axis, copy=True)
3737

3838
def __setitem__(self, key, value):
39-
# also has the side effect of consolidating in-place
40-
if self.obj._is_mixed_type:
41-
raise IndexingError('setting on mixed-type frames not '
42-
'yet supported')
43-
4439
if isinstance(key, tuple):
4540
if len(key) > self.ndim:
4641
raise IndexingError('only tuples of length <= %d supported',
@@ -54,7 +49,31 @@ def __setitem__(self, key, value):
5449
else:
5550
indexer = self._convert_to_indexer(key)
5651

57-
self.obj.values[indexer] = value
52+
self._setitem_with_indexer(indexer, value)
53+
54+
def _setitem_with_indexer(self, indexer, value):
55+
# also has the side effect of consolidating in-place
56+
if self.obj._is_mixed_type:
57+
if not isinstance(indexer, tuple):
58+
indexer = self._tuplify(indexer)
59+
60+
het_axis = self.obj._het_axis
61+
het_idx = indexer[het_axis]
62+
63+
if isinstance(het_idx, (int, long)):
64+
het_idx = [het_idx]
65+
66+
if not np.isscalar(value):
67+
raise IndexingError('setting on mixed-type frames only '
68+
'allowedwith scalar values')
69+
70+
plane_indexer = indexer[:het_axis] + indexer[het_axis+1:]
71+
item_labels = self.obj._get_axis(het_axis)
72+
for item in item_labels[het_idx]:
73+
data = self.obj[item]
74+
data.values[plane_indexer] = value
75+
else:
76+
self.obj.values[indexer] = value
5877

5978
def _getitem_tuple(self, tup):
6079
# a bit kludgy
@@ -205,6 +224,11 @@ def _convert_to_indexer(self, obj, axis=0):
205224
return obj
206225
return index.get_loc(obj)
207226

227+
def _tuplify(self, loc):
228+
tup = [slice(None, None) for _ in range(self.ndim)]
229+
tup[0] = loc
230+
return tuple(tup)
231+
208232
def _get_slice_axis(self, slice_obj, axis=0):
209233
obj = self.obj
210234

pandas/core/panel.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def panel_index(time, panels, names=['time', 'panel']):
4444
Parameters
4545
----------
4646
time : array-like
47-
Time index, does not have to repeat
47+
Time index, does not have to repeat
4848
panels : array-like
4949
Panel index, does not have to repeat
5050
names : list, optional
@@ -63,8 +63,8 @@ def panel_index(time, panels, names=['time', 'panel']):
6363
>>> panel_idx
6464
MultiIndex([(1960, 'A'), (1961, 'A'), (1962, 'A'), (1960, 'B'), (1961, 'B'),
6565
(1962, 'B'), (1960, 'C'), (1961, 'C'), (1962, 'C')], dtype=object)
66-
67-
or
66+
67+
or
6868
6969
>>> import numpy as np
7070
>>> years = np.repeat(range(1960,1963), 3)
@@ -166,6 +166,7 @@ class Panel(NDFrame):
166166

167167
# major
168168
_default_stat_axis = 1
169+
_het_axis = 0
169170

170171
items = AxisProperty(0)
171172
major_axis = AxisProperty(1)

pandas/tests/test_frame.py

+14-2
Original file line numberDiff line numberDiff line change
@@ -409,8 +409,12 @@ def test_fancy_index_int_labels_exceptions(self):
409409
(slice(None, None), 'E'), 1)
410410

411411
def test_setitem_fancy_mixed_2d(self):
412-
self.assertRaises(Exception, self.mixed_frame.ix.__setitem__,
413-
(slice(0, 5), ['C', 'B', 'A']), 5)
412+
self.mixed_frame.ix[:5, ['C', 'B', 'A']] = 5
413+
result = self.mixed_frame.ix[:5, ['C', 'B', 'A']]
414+
self.assert_((result.values == 5).all())
415+
416+
self.mixed_frame.ix[5] = np.nan
417+
self.assert_(isnull(self.mixed_frame.ix[5]).all())
414418

415419
def test_getitem_fancy_1d(self):
416420
f = self.frame
@@ -591,6 +595,14 @@ def test_getitem_setitem_fancy_exceptions(self):
591595
self.assertRaises(Exception, ix.__getitem__, mask)
592596
self.assertRaises(Exception, ix.__setitem__, mask, 1.)
593597

598+
def test_setitem_single_column_mixed(self):
599+
df = DataFrame(randn(5, 3), index=['a', 'b', 'c', 'd', 'e'],
600+
columns=['foo', 'bar', 'baz'])
601+
df['str'] = 'qux'
602+
df.ix[::2, 'str'] = nan
603+
expected = [nan, 'qux', nan, 'qux', nan]
604+
assert_almost_equal(df['str'].values, expected)
605+
594606
def test_setitem_fancy_exceptions(self):
595607
pass
596608

0 commit comments

Comments
 (0)