Skip to content
Browse files

Merge branch 'lix_setitem'

  • Loading branch information...
2 parents 3a68b19 + 3bc0147 commit c17a1a7ffdfa397326e2ec85a3e8a6db34408b18 @kwgoodman committed Jun 25, 2012
Showing with 169 additions and 30 deletions.
  1. +6 −6 README.rst
  2. +5 −0 RELEASE.rst
  3. +81 −16 la/deflarry.py
  4. +77 −8 la/tests/lix_test.py
View
12 README.rst
@@ -70,7 +70,7 @@ Install
Requirements:
======================== ====================================================
-la Python, NumPy 1.5.1-1.6.1, Bottleneck 0.5.0
+la Python, NumPy 1.5.1-1.6.2, Bottleneck 0.6.0
Unit tests nose
======================== ====================================================
@@ -79,7 +79,7 @@ Optional:
============================= ================================================
Archive larrys in HDF5 h5py, HDF 1.8
Compile for speed boost gcc or MinGW
-lar.ranking(norm='gaussian') SciPy 0.8.0, 0.9.0
+lar.ranking(norm='gaussian') SciPy 0.8, 0.9, 0.10
============================= ================================================
You can download the `latest version of la <http://pypi.python.org/pypi/la>`_
@@ -122,9 +122,9 @@ After you have installed ``la``, run the suite of unit tests::
>>> import la
>>> la.test()
<snip>
- Ran 3002 tests in 9.225s
+ Ran 3012 tests in 9.225s
OK
- <nose.result.TextTestResult run=3002 errors=0 failures=0>
+ <nose.result.TextTestResult run=3012 errors=0 failures=0>
The ``la`` package contains C extensions that speed up common alignment
operations such as adding two unaligned larrys. If the C extensions don't
@@ -135,8 +135,8 @@ Python functions::
>>> la.info()
la version 0.7.0
la file /usr/local/lib/python2.6/dist-packages/la/__init__.pyc
- NumPy 1.6.1
- Bottleneck 0.5.0
+ NumPy 1.6.2
+ Bottleneck 0.6.0
HDF5 archiving Available (h5py 2.0.0)
listmap Faster C version
listmap_fill Faster C version
View
5 RELEASE.rst
@@ -21,6 +21,11 @@ la 0.7
- larry.merge() when update=True, larry.morph(), larry.morph_like()
- larry.take()
- larry.sortaxis()
+- larry.nan_replace()
+
+**Enhancements**
+
+- Added setitem ability to label indexing (lix)
**Breakage from la 0.6**
View
97 la/deflarry.py
@@ -1926,7 +1926,7 @@ def lix(self):
array([1, 4])
"""
- return Getitemlabel(self)
+ return Lix(self)
def __setitem__(self, index, value):
"""
@@ -3918,8 +3918,8 @@ def nan_replace(self, replace_with=0):
"""
y = self.copy()
- np.putmask(y.x, np.isnan(y.x), replace_with)
- return y
+ bn.replace(y.x, np.nan, replace_with)
+ return y
# Size, shape, type ------------------------------------------------------
@@ -4848,13 +4848,15 @@ def __repr__(self):
# Label indexing support functions for the lix method ------------------------
-class Getitemlabel(object):
+class Lix(object):
"Utility class for the lix method."
def __init__(self2, self):
self2.lar = self
def __getitem__(self2, index):
+ # Note: setitem uses the same (slightly modified) code
+ # So if you update this code update setitem as well
y = self2.lar
if y.shape == (0,):
return self2.lar
@@ -4866,12 +4868,12 @@ def __getitem__(self2, index):
if typ == list:
# Example: lar.lix[['a', 'b', 'c']]
index2 = labels2indices(y.label[0], index)
- if len(index) == 1:
+ if len(index) == 1:
index2 = index2[0]
- return y[index2]
+ return y[index2]
elif typ == slice:
# Examples: lar.lix[['a']:], lar.lix[['a']:['b']],
- # lar.lix[['a']:['b']:2], lar.lix[2:['b']]
+ # lar.lix[['a']:['b']:2], lar.lix[2:['b']]
return y[slicemaker(index, y.labelindex, 0)]
elif typ == tuple:
index2 = []
@@ -4881,35 +4883,99 @@ def __getitem__(self2, index):
elif len(index) < y.ndim:
index3 = list(index) + [slice(None)] * (y.ndim - len(index))
else:
- raise IndexError, 'Invalid index'
+ raise IndexError, 'Invalid index'
for ax, idx in enumerate(index3):
typ = type(idx)
if typ == list:
idx2 = labels2indices(y.label[ax], idx)
- if len(idx) > 1:
+ if len(idx) > 1:
label.append(idx)
index2.append(idx2)
- elif typ == slice:
+ elif typ == slice:
s = slicemaker(idx, y.labelindex, ax)
slar = range(*s.indices(y.shape[ax]))
lab = y.label[ax][s]
if len(lab) > 1:
- label.append(lab)
+ label.append(lab)
index2.append(slar)
elif isscalar(idx):
- index2.append([idx])
+ index2.append([idx])
else:
raise IndexError, 'Unsupported indexing operation.'
x = np.squeeze(y.x[np.ix_(*index2)])
if x.ndim == 0:
return x[()]
else:
- return larry(x, label)
+ return larry(x, label)
elif isscalar(index):
# Example: lar.lix[0]
- return y[index]
+ return y[index]
else:
- raise IndexError, 'Unsupported indexing operation.'
+ raise IndexError, 'Unsupported indexing operation.'
+
+ def __setitem__(self2, index, value):
+ # Note: getitem uses the same (slightly modified) code
+ # So if you update this code update getitem as well
+ y = self2.lar
+ if y.shape == (0,):
+ raise IndexError('index out of bounds')
+ elif 0 in y.shape:
+ msg = 'lix does not support shapes that contain 0 '
+ msg += 'such as (0,) and (2, 0 ,3).'
+ raise ValueError, msg
+ typ = type(index)
+ if typ == list:
+ # Example: lar.lix[['a', 'b', 'c']]
+ index2 = labels2indices(y.label[0], index)
+ if len(index) == 1:
+ index2 = index2[0]
+ y[index2] = value
+ elif typ == slice:
+ # Examples: lar.lix[['a']:], lar.lix[['a']:['b']],
+ # lar.lix[['a']:['b']:2], lar.lix[2:['b']]
+ y[slicemaker(index, y.labelindex, 0)] = value
+ elif typ == tuple:
+ index2 = []
+ label = []
+ if len(index) == y.ndim:
+ index3 = index
+ elif len(index) < y.ndim:
+ index3 = list(index) + [slice(None)] * (y.ndim - len(index))
+ else:
+ raise IndexError, 'Invalid index'
+ for ax, idx in enumerate(index3):
+ typ = type(idx)
+ if typ == list:
+ idx2 = labels2indices(y.label[ax], idx)
+ if len(idx) > 1:
+ label.append(idx)
+ index2.append(idx2)
+ elif typ == slice:
+ s = slicemaker(idx, y.labelindex, ax)
+ slar = range(*s.indices(y.shape[ax]))
+ lab = y.label[ax][s]
+ if len(lab) > 1:
+ label.append(lab)
+ index2.append(slar)
+ elif isscalar(idx):
+ index2.append([idx])
+ else:
+ raise IndexError, 'Unsupported indexing operation.'
+ if isinstance(value, larry):
+ if value.ndim != len(index2):
+ raise IndexError, '`value` has wrong ndim'
+ for ax, ix2 in enumerate(index2):
+ lab = [y.label[ax][i] for i in ix2]
+ if lab != value.label[ax]:
+ raise IndexError, 'larry labels are not aligned'
+ y.x[np.ix_(*index2)] = value.x
+ else:
+ y.x[np.ix_(*index2)] = value
+ elif isscalar(index):
+ # Example: lar.lix[0]
+ y[index] = value
+ else:
+ raise IndexError, 'Unsupported indexing operation.'
def slicemaker(index, labelindex, axis):
"Convert a slice that may contain labels to a slice with indices."
@@ -4944,4 +5010,3 @@ def labels2indices(label, labels):
except ValueError:
raise ValueError, 'Could not map label to index value.'
return indices
-
View
85 la/tests/lix_test.py
@@ -1,10 +1,14 @@
"Unit tests of larry's indexing by label method, lix"
+from nose.tools import assert_raises
+
import numpy as np
from numpy.testing import assert_equal
+import la
from la import larry
from la.util.misc import isscalar
+from la.util.testing import assert_larry_equal as ale
S = slice
N = None
@@ -106,11 +110,76 @@ def test_lix(si=si):
msg = '\nlix fail on shape %s and index %s\n'
yield assert_equal, actual, desired, msg % (str(shape), str(index))
-
-
-
-
-
-
-
-
+# ---------------------------------------------------------------------------
+# Test lix setitem
+
+def lix_setitem_test_01():
+ actual = la.lrange(label=[['a', 'b']])
+ actual.lix[['a']] = 9
+ desired = la.lrange(label=[['a', 'b']])
+ desired[0] = 9
+ ale(actual, desired)
+
+def lix_setitem_test_02():
+ actual = la.lrange(label=[['a', 'b'], ['c', 'd']])
+ actual.lix[['a']] = 9
+ desired = la.lrange(label=[['a', 'b'], ['c', 'd']])
+ desired[0] = 9
+ ale(actual, desired)
+
+def lix_setitem_test_03():
+ actual = la.lrange(label=[['a', 'b'], ['c', 'd']])
+ actual.lix[0] = 9
+ desired = la.lrange(label=[['a', 'b'], ['c', 'd']])
+ desired[0] = 9
+ ale(actual, desired)
+
+def lix_setitem_test_04():
+ actual = la.lrange(label=[['a', 'b'], ['c', 'd']])
+ actual.lix[['a']:['b']] = 9
+ desired = la.lrange(label=[['a', 'b'], ['c', 'd']])
+ desired[0:1] = 9
+ ale(actual, desired)
+
+def lix_setitem_test_05():
+ actual = la.lrange(label=[['a', 'b'], ['c', 'd']])
+ actual.lix[['b'], ['d']] = 9
+ desired = la.lrange(label=[['a', 'b'], ['c', 'd']])
+ desired[1, 1] = 9
+ ale(actual, desired)
+
+def lix_setitem_test_06():
+ actual = la.lrange(label=[['a', 'b', 'c'], ['1', '2', '3']])
+ actual.lix[['a', 'b'], ['1', '2']] = 9
+ desired = la.lrange(label=[['a', 'b', 'c'], ['1', '2', '3']])
+ desired[:2, :2] = 9
+ ale(actual, desired)
+
+def lix_setitem_test_07():
+ actual = la.lrange(label=[['a', 'b', 'c'], ['1', '2', '3']])
+ actual.lix[['a', 'b'], ['1', '2']] = np.arange(4).reshape(2, 2)
+ desired = la.lrange(label=[['a', 'b', 'c'], ['1', '2', '3']])
+ desired[:2, :2] = np.arange(4).reshape(2, 2)
+ ale(actual, desired)
+
+def lix_setitem_test_08():
+ actual = la.lrange(label=[['a', 'b'], ['c', 'd']])
+ actual.lix[['a']] = la.larry([9, 10], [['c', 'd']])
+ desired = la.lrange(label=[['a', 'b'], ['c', 'd']])
+ desired[0] = [9, 10]
+ ale(actual, desired)
+
+def lix_setitem_test_09():
+ def lixit(lar, index, value):
+ lar.lix[index] = value
+ actual = la.lrange(label=[['a', 'b'], ['c', 'd']])
+ index = ['a']
+ value = la.larry([10, 9], [['d', 'c']])
+ assert_raises(IndexError, lixit, actual, index, value)
+
+def lix_setitem_test_10():
+ actual = la.lrange(label=[['a', 'b'], ['c', 'd']])
+ actual.lix[:,['d']] = la.larry([[9], [10]], [['a', 'b'],['d']])
+ desired = la.lrange(label=[['a', 'b'], ['c', 'd']])
+ desired[:,-1] = [9, 10]
+ ale(actual, desired)

0 comments on commit c17a1a7

Please sign in to comment.
Something went wrong with that request. Please try again.