Permalink
Browse files

Merge branch 'stroxler-alignaxis'

  • Loading branch information...
kwgoodman committed Feb 7, 2012
2 parents 790bd26 + db66701 commit 721010e989e3b9c3225cc863adb8f4f470c77312
Showing with 301 additions and 7 deletions.
  1. +2 −2 README.rst
  2. +1 −0 RELEASE.rst
  3. +4 −0 doc/source/ref_flarry.rst
  4. +147 −3 la/flarry.py
  5. +147 −2 la/tests/flarry_test.py
View
@@ -118,9 +118,9 @@ After you have installed ``la``, run the suite of unit tests::
>>> import la
>>> la.test()
<snip>
- Ran 3038 tests in 1.308s
+ Ran 3047 tests in 1.408s
OK
- <nose.result.TextTestResult run=3038 errors=0 failures=0>
+ <nose.result.TextTestResult run=3047 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
View
@@ -15,6 +15,7 @@ la 0.6
- la.isaligned() returns True if two larrys are aligned along specified axis
- la.sortby() sorts a larry by a row or column specified by its label
+- la.align_axis() aligns multiple larrys along (possibly) different axes
**Enhancements**
@@ -31,6 +31,10 @@ The alignment functions help you align one of more larrys.
.. autofunction:: la.align_raw
+------------
+
+.. autofunction:: la.align_axis
+
------------
.. autofunction:: la.isaligned
View
@@ -7,9 +7,9 @@
from la.farray import covMissing
from la.missing import missing_marker, ismissing
-__all__ = ['align', 'align_raw', 'isaligned', 'union', 'intersection',
- 'binaryop', 'add', 'sortby', 'subtract', 'multiply', 'divide',
- 'unique', 'stack', 'panel', 'cov', 'rand', 'randn']
+__all__ = ['align', 'align_axis', 'align_raw', 'isaligned', 'union',
+ 'intersection', 'binaryop', 'add', 'sortby', 'subtract', 'multiply',
+ 'divide', 'unique', 'stack', 'panel', 'cov', 'rand', 'randn']
# Alignment -----------------------------------------------------------------
@@ -375,6 +375,150 @@ def align_raw(lar1, lar2, join='inner', cast=True):
return x1, x2, label, x1isview, x2isview
+def align_axis(lars, axis=0, join='inner', flag=False):
+ """
+ Align many larrys along potentially different axes.
+
+ Parameters
+ ----------
+ lars : array_like
+ A collection (list, tuple, set, array, etc.) of larrys to align.
+ axis : {int, array_like}, optional
+ An integer indicating which axis along which to align the larrys in
+ `lars`, or a sequence of integers of the same length as `lars`
+ indicating which axis to use for each entry in `lars`.
+ join : {'inner', 'outer', 'left', 'right'}, optional
+ If 'inner', then labels present in every larry will be kept. If
+ 'outer', all labels appearing in any array are kept, and additional
+ entries are added to larrys containing fewer labels. See la.morph() for
+ rules on how this is done. If 'right' or 'left' then the labels of the
+ output will match those of either the first or last entry of `lars`,
+ respectively
+
+ Returns
+ -------
+ (lar1, lar2, ...) : tuple
+ Tuple of larrys, one corresponding to each entry of lars. None of the
+ output refer to input, and the labels of the output do not refer to one
+ another.
+
+ Examples
+ --------
+
+ Create three larrys:
+
+ >>> l1 = la.larry([1, 2, 3, 4], [['a', 'b', 'c', 'd']])
+ >>> l2 = la.larry([[4, 5], [6, 7]], [['x', 'y'], ['c', 'd']])
+ >>> l3 = la.larry([8, 9, 10], [['c', 'd', 'e']])
+
+ Align the first axis of the first larry with the second axis of the
+ second larry using an inner join:
+
+ >>> a1, a2 = la.align_axis([l1, l2], axis=[0, 1])
+ >>> a1
+ label_0
+ c
+ d
+ x
+ array([3, 4])
+ >>> a2
+ label_0
+ x
+ y
+ label_1
+ c
+ d
+ x
+ array([[4, 5],
+ [6, 7]])
+
+ Align the first axis of two larrys with an outer join:
+
+ >>> a1, a2 = la.align_axis([l1, l3], join='outer')
+ >>> a1
+ label_0
+ a
+ b
+ c
+ d
+ e
+ x
+ array([ 1., 2., 3., 4., nan])
+ >>> a2
+ label_0
+ a
+ b
+ c
+ d
+ e
+ x
+ array([ nan, nan, 8., 9., 10.])
+
+ Align multiple larrys with an inner join:
+
+ >>> a1, a2, a3 = la.align_axis([l1, l2, l3], axis=[0, 1, 0])
+ >>> a1
+ label_0
+ c
+ d
+ x
+ array([3, 4])
+ >>> a2
+ label_0
+ x
+ y
+ label_1
+ c
+ d
+ x
+ array([[4, 5],
+ [6, 7]])
+ >>> a3
+ label_0
+ c
+ d
+ x
+ array([8, 9])
+
+ """
+
+ # Input checks and preprocessing
+ nlar = len(lars)
+ if isinstance(axis, int):
+ axis = [axis for j in range(nlar)]
+ for j, lar in enumerate(lars):
+ if not isinstance(lar, larry):
+ raise ValueError("Inputs must be larry.")
+ if (axis[j] >= lar.ndim) or (axis[j] < -lar.ndim):
+ raise ValueError("Axis out of range for input larry %d" % j)
+ if join not in ['inner', 'outer', 'left', 'right']:
+ raise ValueError("Value of `join` not recognized.")
+
+ # Alignment
+ if join == 'left':
+ label = lars[0].label[axis[0]]
+ elif join == 'right':
+ label = lars[-1].label[axis[-1]]
+ else:
+ labels = [set(lar.label[axis[j]]) for j, lar in enumerate(lars)]
+ label = labels[0]
+ if join == 'inner':
+ for new_label in labels[1:]:
+ label &= new_label
+ elif join == 'outer':
+ for new_label in labels[1:]:
+ label |= new_label
+ label = list(label)
+ label.sort()
+ lars_out = []
+
+ # Create output
+ for j, lar in enumerate(lars):
+ lab = list(label)
+ lars_out.append(lar.morph(lab, axis[j]))
+
+ return tuple(lars_out)
+
def isaligned(lar1, lar2, axis=None):
"""
Return True if labels of two given larrys are aligned along specified axis.
View
@@ -9,7 +9,8 @@
from la import larry, rand
from la import (union, intersection, panel, stack, cov, align, isaligned,
- binaryop, add, subtract, multiply, divide, unique, sortby)
+ binaryop, add, subtract, multiply, divide, unique, sortby,
+ align_axis)
from la.util.testing import assert_larry_equal as ale
@@ -515,7 +516,151 @@ def test_2d11(self):
ale(a1, d1, msg % 'left', original=y1)
ale(a2, d2, msg % 'right', original=y2)
-
+class Test_align_axis(unittest.TestCase):
+ "Test align_axis on larrys"
+
+ def test_align_axis_1(self):
+ y1 = larry([[0.1, 0.2], [0.3, 0.4], [0.7, 0.8]])
+ y2 = larry([[0.1, 0.2, 0.5], [0.3, 0.4, 0.6]])
+ a1, a2 = align_axis([y1, y2], axis=1, join='outer')
+ d1 = larry([[0.1, 0.2, np.nan], [0.3, 0.4, np.nan],
+ [0.7, 0.8, np.nan]])
+ d2 = larry([[0.1, 0.2, 0.5], [0.3, 0.4, 0.6]])
+ msg = "align_axis fail on %s larry"
+ ale(a1, d1, msg % 'left', original=y1)
+ ale(a2, d2, msg % 'right', original=y2)
+
+ def test_align_axis_2(self):
+ "align 2d test #10"
+ y1 = larry([[1, 2], [3, 4], [7, 8]])
+ y2 = larry([[1, 2, 5], [3, 4, 6]])
+ a1, a2 = align_axis([y1, y2], axis=0, join='inner')
+ d1 = larry([[1, 2], [3, 4]])
+ d2 = larry([[1, 2, 5], [3, 4, 6]])
+ msg = "align_axis fail on %s larry"
+ ale(a1, d1, msg % 'left', original=y1)
+ ale(a2, d2, msg % 'right', original=y2)
+
+ def test_align_axis_3(self):
+ y1 = larry([1.0, 2.0, 3.0, 4.0], [[1, 2, 3, 4]])
+ y2 = larry([5.0, 6.0], [[2, 3]])
+ y3 = larry([7.0, 8.0, 9.0], [[2, 3, 5]])
+ a1, a2, a3 = align_axis([y1, y2, y3])
+ dlab = [[2, 3]]
+ d1 = larry([2.0, 3.0], dlab)
+ d2 = larry([5.0, 6.0], dlab)
+ d3 = larry([7.0, 8.0], dlab)
+ msg = "align_axis fail on %s larry"
+ ale(a1, d1, msg % '1st', original=y1)
+ ale(a2, d2, msg % '2nd', original=y2)
+ ale(a3, d3, msg % '3rd', original=y3)
+
+ def test_align_axis_4(self):
+ y1 = larry([1.0, 2.0, 3.0, 4.0], [[1, 2, 3, 4]])
+ y2 = larry([5.0, 6.0], [[2, 3]])
+ y3 = larry([7.0, 8.0, 9.0], [[2, 3, 5]])
+ a1, a2, a3 = align_axis([y1, y2, y3], join='outer')
+ dlab = [[1, 2, 3, 4, 5]]
+ d1 = larry([1.0, 2.0, 3.0, 4.0, nan], dlab)
+ d2 = larry([nan, 5.0, 6.0, nan, nan], dlab)
+ d3 = larry([nan, 7.0, 8.0, nan, 9.0], dlab)
+ msg = "align_axis fail on %s larry"
+ ale(a1, d1, msg % '1st', original=y1)
+ ale(a2, d2, msg % '2nd', original=y2)
+ ale(a3, d3, msg % '3rd', original=y3)
+
+ def test_align_axis_5(self):
+ y1 = larry([[1.0, 2.0],
+ [3.0, 4.0],
+ [5.0, 6.0]], [['a', 'b', 'c'], [1, 2]])
+ y2 = larry([['x'], ['y'], ['z']], [['a', 'b', 'cc'], [1]])
+ y3 = larry([50, 51, 52], [['aa', 'b', 'c']])
+ a1, a2, a3 = align_axis([y1, y2, y3], axis=0, join='inner')
+ d1 = larry([[3.0, 4.0]], [['b'], [1, 2]])
+ d2 = larry([['y']], [['b'], [1]])
+ d3 = larry([51], [['b']])
+ msg = "align_axis fail on %s larry"
+ ale(a1, d1, msg % '1st', original=y1)
+ ale(a2, d2, msg % '2nd', original=y2)
+ ale(a3, d3, msg % '3rd', original=y3)
+
+ def test_align_axis_6(self):
+ y1 = larry([[1.0, 2.0],
+ [3.0, 4.0],
+ [5.0, 6.0]], [['a', 'b', 'c'], [1, 2]])
+ y2 = larry([['x'], ['y'], ['z']], [['a', 'b', 'cc'], [1]])
+ y3 = larry([50, 51, 52], [['aa', 'b', 'c']])
+ a1, a2, a3 = align_axis([y1, y2, y3], axis=0, join='outer')
+ d1 = larry([[1.0, 2.0],
+ [nan, nan],
+ [3.0, 4.0],
+ [5.0, 6.0],
+ [nan, nan]],
+ label = [['a', 'aa', 'b', 'c', 'cc'], [1, 2]])
+ d2 = larry([['x'], [''], ['y'], [''], ['z']],
+ [['a', 'aa', 'b', 'c', 'cc'], [1]])
+ d3 = larry([nan, 50.0, 51.0, 52.0, nan], [['a', 'aa', 'b', 'c', 'cc']])
+ msg = "align_axis fail on %s larry"
+ ale(a1, d1, msg % '1st', original=y1)
+ ale(a2, d2, msg % '2nd', original=y2)
+ ale(a3, d3, msg % '3rd', original=y3)
+
+ def test_align_axis_7(self):
+ y1 = larry([[1.0, 2.0],
+ [3.0, 4.0],
+ [5.0, 6.0]], [['a', 'b', 'c'], [1, 2]])
+ y2 = larry([['x'], ['y'], ['z']], [['a', 'b', 'cc'], [1]])
+ y3 = larry([50, 51, 52], [['aa', 'b', 'c']])
+ a1, a2, a3 = align_axis([y1, y2, y3], axis=0, join='left')
+ d1 = larry([[1.0, 2.0],
+ [3.0, 4.0],
+ [5.0, 6.0]], [['a', 'b', 'c'], [1, 2]])
+ d2 = larry([['x'], ['y'], ['']],
+ [['a', 'b', 'c'], [1]])
+ d3 = larry([nan, 51.0, 52.0], [['a', 'b', 'c']])
+ msg = "align_axis fail on %s larry"
+ ale(a1, d1, msg % '1st', original=y1)
+ ale(a2, d2, msg % '2nd', original=y2)
+ ale(a3, d3, msg % '3rd', original=y3)
+
+ def test_align_axis_8(self):
+ y1 = larry([[1.0, 2.0],
+ [3.0, 4.0],
+ [5.0, 6.0]], [['a', 'b', 'c'], [1, 2]])
+ y2 = larry([['x'], ['y'], ['z']], [['a', 'b', 'cc'], [1]])
+ y3 = larry([50, 51, 52], [['aa', 'b', 'c']])
+ a3, a2, a1 = align_axis([y3, y2, y1], axis=0, join='right')
+ d1 = larry([[1.0, 2.0],
+ [3.0, 4.0],
+ [5.0, 6.0]], [['a', 'b', 'c'], [1, 2]])
+ d2 = larry([['x'], ['y'], ['']],
+ [['a', 'b', 'c'], [1]])
+ d3 = larry([nan, 51.0, 52.0], [['a', 'b', 'c']])
+ msg = "align_axis fail on %s larry"
+ ale(a1, d1, msg % '1st', original=y1)
+ ale(a2, d2, msg % '2nd', original=y2)
+ ale(a3, d3, msg % '3rd', original=y3)
+
+ def test_align_axis_9(self):
+ y1 = larry([[1.0, 2.0],
+ [3.0, 4.0],
+ [5.0, 6.0]], [['a', 'b', 'c'], [1, 2]])
+ y1 = y1.T
+ y2 = larry([['x'], ['y'], ['z']], [['a', 'b', 'cc'], [1]])
+ y3 = larry([50, 51, 52], [['aa', 'b', 'c']])
+ a1, a2, a3 = align_axis([y1, y2, y3], axis=[1, 0, 0], join='left')
+ d1 = larry([[1.0, 2.0],
+ [3.0, 4.0],
+ [5.0, 6.0]], [['a', 'b', 'c'], [1, 2]])
+ d1 = d1.T
+ d2 = larry([['x'], ['y'], ['']],
+ [['a', 'b', 'c'], [1]])
+ d3 = larry([nan, 51.0, 52.0], [['a', 'b', 'c']])
+ msg = "align_axis fail on %s larry"
+ ale(a1, d1, msg % '1st', original=y1)
+ ale(a2, d2, msg % '2nd', original=y2)
+ ale(a3, d3, msg % '3rd', original=y3)
+
class Test_binaryop(unittest.TestCase):
"Test la.binaryop()"

0 comments on commit 721010e

Please sign in to comment.