diff options
Diffstat (limited to 'numpy/lib')
-rw-r--r-- | numpy/lib/_iotools.py | 7 | ||||
-rw-r--r-- | numpy/lib/arraysetops.py | 7 | ||||
-rw-r--r-- | numpy/lib/financial.py | 10 | ||||
-rw-r--r-- | numpy/lib/npyio.py | 43 | ||||
-rw-r--r-- | numpy/lib/setup.py | 12 | ||||
-rw-r--r-- | numpy/lib/shape_base.py | 2 | ||||
-rw-r--r-- | numpy/lib/tests/test__iotools.py | 6 | ||||
-rw-r--r-- | numpy/lib/tests/test_financial.py | 41 | ||||
-rw-r--r-- | numpy/lib/tests/test_io.py | 95 | ||||
-rw-r--r-- | numpy/lib/tests/test_twodim_base.py | 31 | ||||
-rw-r--r-- | numpy/lib/twodim_base.py | 8 |
11 files changed, 220 insertions, 42 deletions
diff --git a/numpy/lib/_iotools.py b/numpy/lib/_iotools.py index f2adcda10..316704b42 100644 --- a/numpy/lib/_iotools.py +++ b/numpy/lib/_iotools.py @@ -320,12 +320,13 @@ class NameValidator(object): # Process the case option ..... if (case_sensitive is None) or (case_sensitive is True): self.case_converter = lambda x: x - elif (case_sensitive is False) or ('u' in case_sensitive): + elif (case_sensitive is False) or case_sensitive.startswith('u'): self.case_converter = lambda x: x.upper() - elif 'l' in case_sensitive: + elif case_sensitive.startswith('l'): self.case_converter = lambda x: x.lower() else: - self.case_converter = lambda x: x + msg = 'unrecognized case_sensitive value %s.' % case_sensitive + raise ValueError(msg) # self.replace_space = replace_space diff --git a/numpy/lib/arraysetops.py b/numpy/lib/arraysetops.py index d3b6119f4..cb24eb24e 100644 --- a/numpy/lib/arraysetops.py +++ b/numpy/lib/arraysetops.py @@ -392,12 +392,13 @@ def in1d(ar1, ar2, assume_unique=False, invert=False): else: bool_ar = (sar[1:] == sar[:-1]) flag = np.concatenate((bool_ar, [invert])) - indx = order.argsort(kind='mergesort')[:len(ar1)] + ret = np.empty(ar.shape, dtype=bool) + ret[order] = flag if assume_unique: - return flag[indx] + return ret[:len(ar1)] else: - return flag[indx][rev_idx] + return ret[rev_idx] def union1d(ar1, ar2): """ diff --git a/numpy/lib/financial.py b/numpy/lib/financial.py index baff8b0b6..a7e4e60b6 100644 --- a/numpy/lib/financial.py +++ b/numpy/lib/financial.py @@ -208,11 +208,11 @@ def pmt(rate, nper, pv, fv=0, when='end'): """ when = _convert_when(when) (rate, nper, pv, fv, when) = map(np.asarray, [rate, nper, pv, fv, when]) - temp = (1+rate)**nper - miter = np.broadcast(rate, nper, pv, fv, when) - zer = np.zeros(miter.shape) - fact = np.where(rate == zer, nper + zer, - (1 + rate*when)*(temp - 1)/rate + zer) + temp = (1 + rate)**nper + mask = (rate == 0.0) + np.copyto(rate, 1.0, where=mask) + z = np.zeros(np.broadcast(rate, nper, pv, fv, when).shape) + fact = np.where(mask != z, nper + z, (1 + rate*when)*(temp - 1)/rate + z) return -(fv + pv*temp) / fact def nper(rate, pmt, pv, fv=0, when='end'): diff --git a/numpy/lib/npyio.py b/numpy/lib/npyio.py index 9d539d6ac..0632ba1f8 100644 --- a/numpy/lib/npyio.py +++ b/numpy/lib/npyio.py @@ -621,6 +621,13 @@ def _savez(file, args, kwds, compress): def _getconv(dtype): """ Find the correct dtype converter. Adapted from matplotlib """ + + def floatconv(x): + x.lower() + if b'0x' in x: + return float.fromhex(asstr(x)) + return float(x) + typ = dtype.type if issubclass(typ, np.bool_): return lambda x: bool(int(x)) @@ -631,7 +638,7 @@ def _getconv(dtype): if issubclass(typ, np.integer): return lambda x: int(float(x)) elif issubclass(typ, np.floating): - return float + return floatconv elif issubclass(typ, np.complex): return complex elif issubclass(typ, np.bytes_): @@ -706,6 +713,10 @@ def loadtxt(fname, dtype=float, comments='#', delimiter=None, `genfromtxt` function provides more sophisticated handling of, e.g., lines with missing values. + .. versionadded:: 1.10.0 + The strings produced by the Python float.hex method can be used as + input for floats. + Examples -------- >>> from StringIO import StringIO # StringIO behaves like a file object @@ -1204,7 +1215,8 @@ def genfromtxt(fname, dtype=float, comments='#', delimiter=None, usecols=None, names=None, excludelist=None, deletechars=None, replace_space='_', autostrip=False, case_sensitive=True, defaultfmt="f%i", - unpack=None, usemask=False, loose=True, invalid_raise=True): + unpack=None, usemask=False, loose=True, invalid_raise=True, + max_rows=None): """ Load data from a text file, with missing values handled as specified. @@ -1285,6 +1297,12 @@ def genfromtxt(fname, dtype=float, comments='#', delimiter=None, If True, an exception is raised if an inconsistency is detected in the number of columns. If False, a warning is emitted and the offending lines are skipped. + max_rows : int, optional + The maximum number of rows to read. Must not be used with skip_footer + at the same time. If given, the value must be at least 1. Default is + to read the entire file. + + .. versionadded:: 1.10.0 Returns ------- @@ -1353,6 +1371,14 @@ def genfromtxt(fname, dtype=float, comments='#', delimiter=None, dtype=[('intvar', '<i8'), ('fltvar', '<f8'), ('strvar', '|S5')]) """ + if max_rows is not None: + if skip_footer: + raise ValueError( + "The keywords 'skip_footer' and 'max_rows' can not be " + "specified at the same time.") + if max_rows < 1: + raise ValueError("'max_rows' must be at least 1.") + # Py3 data conversions to bytes, for convenience if comments is not None: comments = asbytes(comments) @@ -1451,7 +1477,11 @@ def genfromtxt(fname, dtype=float, comments='#', delimiter=None, names = validate_names(names) # Get the dtype if dtype is not None: - dtype = easy_dtype(dtype, defaultfmt=defaultfmt, names=names) + dtype = easy_dtype(dtype, defaultfmt=defaultfmt, names=names, + excludelist=excludelist, + deletechars=deletechars, + case_sensitive=case_sensitive, + replace_space=replace_space) # Make sure the names is a list (for 2.5) if names is not None: names = list(names) @@ -1647,8 +1677,8 @@ def genfromtxt(fname, dtype=float, comments='#', delimiter=None, # Skip an empty line if nbvalues == 0: continue - # Select only the columns we need if usecols: + # Select only the columns we need try: values = [values[_] for _ in usecols] except IndexError: @@ -1661,7 +1691,10 @@ def genfromtxt(fname, dtype=float, comments='#', delimiter=None, append_to_rows(tuple(values)) if usemask: append_to_masks(tuple([v.strip() in m - for (v, m) in zip(values, missing_values)])) + for (v, m) in zip(values, + missing_values)])) + if len(rows) == max_rows: + break if own_fhd: fhd.close() diff --git a/numpy/lib/setup.py b/numpy/lib/setup.py new file mode 100644 index 000000000..d342410b8 --- /dev/null +++ b/numpy/lib/setup.py @@ -0,0 +1,12 @@ +from __future__ import division, print_function + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + + config = Configuration('lib', parent_package, top_path) + config.add_data_dir('tests') + return config + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/lib/shape_base.py b/numpy/lib/shape_base.py index 70fa3ab03..2d18c5bc8 100644 --- a/numpy/lib/shape_base.py +++ b/numpy/lib/shape_base.py @@ -711,7 +711,7 @@ def kron(a, b): Notes ----- - The function assumes that the number of dimenensions of `a` and `b` + The function assumes that the number of dimensions of `a` and `b` are the same, if necessary prepending the smallest with ones. If `a.shape = (r0,r1,..,rN)` and `b.shape = (s0,s1,...,sN)`, the Kronecker product has shape `(r0*s0, r1*s1, ..., rN*SN)`. diff --git a/numpy/lib/tests/test__iotools.py b/numpy/lib/tests/test__iotools.py index 92ca1c973..060f815d5 100644 --- a/numpy/lib/tests/test__iotools.py +++ b/numpy/lib/tests/test__iotools.py @@ -7,7 +7,8 @@ from datetime import date import numpy as np from numpy.compat import asbytes, asbytes_nested from numpy.testing import ( - run_module_suite, TestCase, assert_, assert_equal, assert_allclose + run_module_suite, TestCase, assert_, assert_equal, assert_allclose, + assert_raises ) from numpy.lib._iotools import ( LineSplitter, NameValidator, StringConverter, @@ -93,6 +94,9 @@ class TestNameValidator(TestCase): test = NameValidator(case_sensitive='lower').validate(names) assert_equal(test, ['a', 'a_1', 'b', 'c']) + # check exceptions + assert_raises(ValueError, NameValidator, case_sensitive='foobar') + def test_excludelist(self): "Test excludelist" names = ['dates', 'data', 'Other Data', 'mask'] diff --git a/numpy/lib/tests/test_financial.py b/numpy/lib/tests/test_financial.py index a4b9cfe2e..baa785424 100644 --- a/numpy/lib/tests/test_financial.py +++ b/numpy/lib/tests/test_financial.py @@ -2,7 +2,8 @@ from __future__ import division, absolute_import, print_function import numpy as np from numpy.testing import ( - run_module_suite, TestCase, assert_, assert_almost_equal + run_module_suite, TestCase, assert_, assert_almost_equal, + assert_allclose ) @@ -13,35 +14,37 @@ class TestFinancial(TestCase): def test_irr(self): v = [-150000, 15000, 25000, 35000, 45000, 60000] - assert_almost_equal(np.irr(v), - 0.0524, 2) + assert_almost_equal(np.irr(v), 0.0524, 2) v = [-100, 0, 0, 74] - assert_almost_equal(np.irr(v), - -0.0955, 2) + assert_almost_equal(np.irr(v), -0.0955, 2) v = [-100, 39, 59, 55, 20] - assert_almost_equal(np.irr(v), - 0.28095, 2) + assert_almost_equal(np.irr(v), 0.28095, 2) v = [-100, 100, 0, -7] - assert_almost_equal(np.irr(v), - -0.0833, 2) + assert_almost_equal(np.irr(v), -0.0833, 2) v = [-100, 100, 0, 7] - assert_almost_equal(np.irr(v), - 0.06206, 2) + assert_almost_equal(np.irr(v), 0.06206, 2) v = [-5, 10.5, 1, -8, 1] - assert_almost_equal(np.irr(v), - 0.0886, 2) + assert_almost_equal(np.irr(v), 0.0886, 2) def test_pv(self): - assert_almost_equal(np.pv(0.07, 20, 12000, 0), - -127128.17, 2) + assert_almost_equal(np.pv(0.07, 20, 12000, 0), -127128.17, 2) def test_fv(self): - assert_almost_equal(np.fv(0.075, 20, -2000, 0, 0), - 86609.36, 2) + assert_almost_equal(np.fv(0.075, 20, -2000, 0, 0), 86609.36, 2) def test_pmt(self): - assert_almost_equal(np.pmt(0.08/12, 5*12, 15000), - -304.146, 3) + res = np.pmt(0.08/12, 5*12, 15000) + tgt = -304.145914 + assert_allclose(res, tgt) + # Test the edge case where rate == 0.0 + res = np.pmt(0.0, 5*12, 15000) + tgt = -250.0 + assert_allclose(res, tgt) + # Test the case where we use broadcast and + # the arguments passed in are arrays. + res = np.pmt([[0.0, 0.8],[0.3, 0.8]],[12, 3],[2000, 20000]) + tgt = np.array([[-166.66667, -19311.258],[-626.90814, -19311.258]]) + assert_allclose(res, tgt) def test_ppmt(self): np.round(np.ppmt(0.1/12, 1, 60, 55000), 2) == 710.25 diff --git a/numpy/lib/tests/test_io.py b/numpy/lib/tests/test_io.py index 81bddfadd..7054ab1fe 100644 --- a/numpy/lib/tests/test_io.py +++ b/numpy/lib/tests/test_io.py @@ -694,6 +694,19 @@ class TestLoadTxt(TestCase): res = np.loadtxt(c, dtype=np.int64) assert_equal(res, tgt) + def test_from_float_hex(self): + # IEEE doubles and floats only, otherwise the float32 + # conversion may fail. + tgt = np.logspace(-10, 10, 5).astype(np.float32) + tgt = np.hstack((tgt, -tgt)).astype(np.float) + inp = '\n'.join(map(float.hex, tgt)) + c = TextIO() + c.write(inp) + for dt in [np.float, np.float32]: + c.seek(0) + res = np.loadtxt(c, dtype=dt) + assert_equal(res, tgt, err_msg="%s" % dt) + def test_universal_newline(self): f, name = mkstemp() os.write(f, b'1 21\r3 42\r') @@ -1107,13 +1120,13 @@ M 33 21.99 def test_dtype_with_converters_and_usecols(self): dstr = "1,5,-1,1:1\n2,8,-1,1:n\n3,3,-2,m:n\n" dmap = {'1:1':0, '1:n':1, 'm:1':2, 'm:n':3} - dtyp = [('E1','i4'),('E2','i4'),('E3','i2'),('N', 'i1')] + dtyp = [('e1','i4'),('e2','i4'),('e3','i2'),('n', 'i1')] conv = {0: int, 1: int, 2: int, 3: lambda r: dmap[r.decode()]} test = np.recfromcsv(TextIO(dstr,), dtype=dtyp, delimiter=',', names=None, converters=conv) control = np.rec.array([[1,5,-1,0], [2,8,-1,1], [3,3,-2,3]], dtype=dtyp) assert_equal(test, control) - dtyp = [('E1','i4'),('E2','i4'),('N', 'i1')] + dtyp = [('e1','i4'),('e2','i4'),('n', 'i1')] test = np.recfromcsv(TextIO(dstr,), dtype=dtyp, delimiter=',', usecols=(0,1,3), names=None, converters=conv) control = np.rec.array([[1,5,0], [2,8,1], [3,3,3]], dtype=dtyp) @@ -1514,6 +1527,30 @@ M 33 21.99 ctrl = np.array((1, 2, 3.14), dtype=ctrl_dtype) assert_equal(test, ctrl) + def test_replace_space_known_dtype(self): + "Test the 'replace_space' (and related) options when dtype != None" + txt = "A.A, B (B), C:C\n1, 2, 3" + # Test default: replace ' ' by '_' and delete non-alphanum chars + test = np.genfromtxt(TextIO(txt), + delimiter=",", names=True, dtype=int) + ctrl_dtype = [("AA", int), ("B_B", int), ("CC", int)] + ctrl = np.array((1, 2, 3), dtype=ctrl_dtype) + assert_equal(test, ctrl) + # Test: no replace, no delete + test = np.genfromtxt(TextIO(txt), + delimiter=",", names=True, dtype=int, + replace_space='', deletechars='') + ctrl_dtype = [("A.A", int), ("B (B)", int), ("C:C", int)] + ctrl = np.array((1, 2, 3), dtype=ctrl_dtype) + assert_equal(test, ctrl) + # Test: no delete (spaces are replaced by _) + test = np.genfromtxt(TextIO(txt), + delimiter=",", names=True, dtype=int, + deletechars='') + ctrl_dtype = [("A.A", int), ("B_(B)", int), ("C:C", int)] + ctrl = np.array((1, 2, 3), dtype=ctrl_dtype) + assert_equal(test, ctrl) + def test_incomplete_names(self): "Test w/ incomplete names" data = "A,,C\n0,1,2\n3,4,5" @@ -1641,6 +1678,60 @@ M 33 21.99 self.assertTrue(isinstance(test, np.recarray)) assert_equal(test, control) + def test_max_rows(self): + # Test the `max_rows` keyword argument. + data = '1 2\n3 4\n5 6\n7 8\n9 10\n' + txt = TextIO(data) + a1 = np.genfromtxt(txt, max_rows=3) + a2 = np.genfromtxt(txt) + assert_equal(a1, [[1, 2], [3, 4], [5, 6]]) + assert_equal(a2, [[7, 8], [9, 10]]) + + # max_rows must be at least 1. + assert_raises(ValueError, np.genfromtxt, TextIO(data), max_rows=0) + + # An input with several invalid rows. + data = '1 1\n2 2\n0 \n3 3\n4 4\n5 \n6 \n7 \n' + + test = np.genfromtxt(TextIO(data), max_rows=2) + control = np.array([[1., 1.], [2., 2.]]) + assert_equal(test, control) + + # Test keywords conflict + assert_raises(ValueError, np.genfromtxt, TextIO(data), skip_footer=1, + max_rows=4) + + # Test with invalid value + assert_raises(ValueError, np.genfromtxt, TextIO(data), max_rows=4) + + # Test with invalid not raise + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + + test = np.genfromtxt(TextIO(data), max_rows=4, invalid_raise=False) + control = np.array([[1., 1.], [2., 2.], [3., 3.], [4., 4.]]) + assert_equal(test, control) + + test = np.genfromtxt(TextIO(data), max_rows=5, invalid_raise=False) + control = np.array([[1., 1.], [2., 2.], [3., 3.], [4., 4.]]) + assert_equal(test, control) + + # Structured array with field names. + data = 'a b\n#c d\n1 1\n2 2\n#0 \n3 3\n4 4\n5 5\n' + + # Test with header, names and comments + txt = TextIO(data) + test = np.genfromtxt(txt, skip_header=1, max_rows=3, names=True) + control = np.array([(1.0, 1.0), (2.0, 2.0), (3.0, 3.0)], + dtype=[('c', '<f8'), ('d', '<f8')]) + assert_equal(test, control) + # To continue reading the same "file", don't use skip_header or + # names, and use the previously determined dtype. + test = np.genfromtxt(txt, max_rows=None, dtype=test.dtype) + control = np.array([(4.0, 4.0), (5.0, 5.0)], + dtype=[('c', '<f8'), ('d', '<f8')]) + assert_equal(test, control) + def test_gft_using_filename(self): # Test that we can load data from a filename as well as a file object wanted = np.arange(6).reshape((2, 3)) diff --git a/numpy/lib/tests/test_twodim_base.py b/numpy/lib/tests/test_twodim_base.py index 739061a5d..b65a8df97 100644 --- a/numpy/lib/tests/test_twodim_base.py +++ b/numpy/lib/tests/test_twodim_base.py @@ -265,6 +265,37 @@ class TestHistogram2d(TestCase): a, edge1, edge2 = histogram2d([], [], bins=4) assert_array_max_ulp(a, np.zeros((4, 4))) + def test_binparameter_combination(self): + x = array( + [0, 0.09207008, 0.64575234, 0.12875982, 0.47390599, + 0.59944483, 1]) + y = array( + [0, 0.14344267, 0.48988575, 0.30558665, 0.44700682, + 0.15886423, 1]) + edges = (0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1) + H, xe, ye = histogram2d(x, y, (edges, 4)) + answer = array( + [[ 2., 0., 0., 0.], + [ 0., 1., 0., 0.], + [ 0., 0., 0., 0.], + [ 0., 0., 0., 0.], + [ 0., 1., 0., 0.], + [ 1., 0., 0., 0.], + [ 0., 1., 0., 0.], + [ 0., 0., 0., 0.], + [ 0., 0., 0., 0.], + [ 0., 0., 0., 1.]]) + assert_array_equal(H, answer) + assert_array_equal(ye, array([0., 0.25, 0.5, 0.75, 1])) + H, xe, ye = histogram2d(x, y, (4, edges)) + answer = array( + [[ 1., 1., 0., 1., 0., 0., 0., 0., 0., 0.], + [ 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.], + [ 0., 1., 0., 0., 1., 0., 0., 0., 0., 0.], + [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.]]) + assert_array_equal(H, answer) + assert_array_equal(xe, array([0., 0.25, 0.5, 0.75, 1])) + class TestTri(TestCase): def test_dtype(self): diff --git a/numpy/lib/twodim_base.py b/numpy/lib/twodim_base.py index 24dc3cced..464ffd914 100644 --- a/numpy/lib/twodim_base.py +++ b/numpy/lib/twodim_base.py @@ -589,16 +589,18 @@ def histogram2d(x, y, bins=10, range=None, normed=False, weights=None): y : array_like, shape (N,) An array containing the y coordinates of the points to be histogrammed. - bins : int or [int, int] or array_like or [array, array], optional + bins : int or array_like or [int, int] or [array, array], optional The bin specification: * If int, the number of bins for the two dimensions (nx=ny=bins). - * If [int, int], the number of bins in each dimension - (nx, ny = bins). * If array_like, the bin edges for the two dimensions (x_edges=y_edges=bins). + * If [int, int], the number of bins in each dimension + (nx, ny = bins). * If [array, array], the bin edges in each dimension (x_edges, y_edges = bins). + * A combination [int, array] or [array, int], where int + is the number of bins and array is the bin edges. range : array_like, shape(2,2), optional The leftmost and rightmost edges of the bins along each dimension |