Skip to content

Commit

Permalink
unit tests for fancy setitem pass
Browse files Browse the repository at this point in the history
  • Loading branch information
wesm committed Jun 27, 2011
1 parent c8657e2 commit 1a3fd35
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 22 deletions.
90 changes: 78 additions & 12 deletions pandas/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,24 +108,63 @@ def __setitem__(self, key, value):
if self.frame._is_mixed_type:
raise Exception('setting on mixed-type frames not yet supported')

frame = self.frame
if isinstance(key, slice):
return key
elif isinstance(key, tuple):
if isinstance(key, tuple):
if len(key) != 2:
raise Exception('only length 2 tuple supported')

x, y = key
return frame._fancy_setitem_tuple(x, y, value)
elif _is_list_like(key):
return frame._fancy_setitem(key, value, axis=0)
xidx = self._convert_to_indexer(x, axis=0)
yidx = self._convert_to_indexer(y, axis=1)
indexer = _maybe_convert_ix(xidx, yidx)
else:
return frame._fancy_setitem_axis(key, value, axis=0)
indexer = self._convert_to_indexer(key)

def _convert_indexer(self, obj):
self.frame.values[indexer] = value

def _convert_to_indexer(self, obj, axis=0):
"""
Convert indexing key into something we can use to do actual fancy
indexing on an ndarray
Examples
ix[:5] -> slice(0, 5)
ix[[1,2,3]] -> [1,2,3]
ix[['foo', 'bar', 'baz']] -> [i, j, k] (indices of foo, bar, baz)
Going by Zen of Python?
"In the face of ambiguity, refuse the temptation to guess."
Going to raise AmbiguousIndexError with integer labels?
"""
index = self.frame._get_axis(axis)
is_int_index = _is_integer_index(index)
if isinstance(obj, slice):
return obj
elif _is_list_like(key):
pass
if _is_label_slice(index, obj):
i, j = index.slice_locs(obj.start, obj.stop)
return slice(i, j)
else:
return obj
elif _is_list_like(obj):
obj = np.asarray(obj)

if _is_integer_dtype(obj):
if is_int_index:
raise AmbiguousIndexError('integer labels')

# retrieve the indices corresponding
return obj
else:
indexer, mask = index.get_indexer(obj)
if not mask.all():
raise Exception('%s not in index' % obj[-mask])

return indexer
else:
if _is_int_like(obj):
if is_int_index:
raise AmbiguousIndexError('integer labels')
return obj
return index.get_loc(obj)

def _fancy_getitem_tuple(self, rowkey, colkey):
# to avoid wasted computation
Expand Down Expand Up @@ -210,6 +249,33 @@ def _get_slice_axis(self, slice_obj, axis=0):
return DataFrame(new_values, index=new_index,
columns=new_columns)

def _maybe_convert_ix(*args):
"""
We likely want to take the cross-product
"""
ixify = True
for arg in args:
if not isinstance(arg, (np.ndarray, list)):
ixify = False

if ixify:
return np.ix_(*args)
else:
return args

def _is_integer_dtype(arr):
return issubclass(arr.dtype.type, np.integer)

def _is_integer_index(index):
# make an educated and not too intelligent guess
if len(index) == 0:
return False
else:
return _is_int_like(index[0])

def _is_int_like(val):
return isinstance(val, (int, np.integer))

def _is_label_like(key):
# select a label or row
return not isinstance(key, slice) and not _is_list_like(key)
Expand Down
9 changes: 0 additions & 9 deletions pandas/core/tests/foo.py

This file was deleted.

2 changes: 1 addition & 1 deletion pandas/core/tests/test_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ def test_setitem_fancy_2d(self):
expected['B'][:5] = values[:, 1]
assert_frame_equal(frame, expected)

frame.ix[:5, [0, 1]] = values
frame2.ix[:5, [0, 1]] = values
assert_frame_equal(frame2, expected)

# case 6: slice rows with labels, inclusive!
Expand Down

0 comments on commit 1a3fd35

Please sign in to comment.