Beispiel #1
0
    def test_polyvander3d(self):
        # also tests polyval3d for non-square coefficient array
        x1, x2, x3 = self.x
        c = np.random.random((2, 3, 4))
        van = poly.polyvander3d(x1, x2, x3, [1, 2, 3])
        tgt = poly.polyval3d(x1, x2, x3, c)
        res = np.dot(van, c.flat)
        assert_almost_equal(res, tgt)

        # check shape
        van = poly.polyvander3d([x1], [x2], [x3], [1, 2, 3])
        assert_(van.shape == (1, 5, 24))
Beispiel #2
0
    def test_polyvander3d(self) :
        # also tests polyval3d for non-square coefficient array
        x1, x2, x3 = self.x
        c = np.random.random((2, 3, 4))
        van = poly.polyvander3d(x1, x2, x3, [1, 2, 3])
        tgt = poly.polyval3d(x1, x2, x3, c)
        res = np.dot(van, c.flat)
        assert_almost_equal(res, tgt)

        # check shape
        van = poly.polyvander3d([x1], [x2], [x3], [1, 2, 3])
        assert_(van.shape == (1, 5, 24))
Beispiel #3
0
def polyfit3d(x, y, z, f, deg, mask=None):
    """
    Given coordinates and values, fit a polynomial and return parameters.

    Parameters
    ----------
    x : 1D array of coordinates
    y : 1D array of coordinates
    z : 1D array of coordinates
    f : 1D array of expression results / data
    deg : degree of polynomial to fit

    Optional Parameters
    -------------------
    mask : 3D array of booleans to exclude factors of full polynomial

    Returns
    -------
    3D array with polynomial factors.
    """

    from numpy.polynomial import polynomial
    import numpy as np
    x = np.asarray(x)
    y = np.asarray(y)
    z = np.asarray(z)
    f = np.asarray(f)
    try:
        len(deg)
    except:
        deg = [deg, deg, deg]
    deg = np.asarray(deg)
    vander = polynomial.polyvander3d(x, y, z, deg)
    # apply mask to delete terms if desired
    if mask != None:
        mask = np.asarray(mask).flatten()
        print('old', vander.shape)
        vander = vander.transpose()[mask].transpose()
        print('new', vander.shape)
#    vander = vander.reshape((-1,vander.shape[-1]))
#    f = f.reshape((vander.shape[0],))
    c = np.linalg.lstsq(vander, f)[0]
    # insert zeroes to deleted terms if a mask was applied to keep matrix order
    if mask != None:
        cc = np.zeros(mask.size)
        j = 0
        for i, item in enumerate(mask):
            if item:
                cc[i] = c[j]
                j += 1
    else:
        cc = c
    return cc.reshape(deg + 1)
Beispiel #4
0
def newtForwardTransform(orders, locations, functionVals):
    if len(locations.shape)==1:
        return np.array(poly.polyfit(locations, functionVals, orders[0]))
    else:
        if locations.shape[1]==2:
            V=poly.polyvander2d(locations[:,0], locations[:,1], orders)
        elif locations.shape[1]==3:
            V=poly.polyvander3d(locations[:,0],locations[:,1],locations[:,2], orders)
        elif locations.shape[1]==4:
            V=newtVander4d(locations,orders)
        elif locations.shape[1]==5:
            V=newtVander5d(locations,orders)
        else:
            raise NotImplementedError # there's a bad startup joke about this being good enough for the paper.
        ret, _, _, _=npl.lstsq(V, functionVals, rcond=None)
        return np.reshape(ret, (np.array(orders)+1).flatten())
Beispiel #5
0
def polyfit3d(x, y, z, f, deg, method=None):
    # https://stackoverflow.com/questions/7997152/python-3d-polynomial-surface-fit-order-dependent
    # https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.polynomials.polynomial.html
    if method is None:
        method = 'ols'
    deg = np.array(deg) if utils.iterable(deg) else np.repeat(deg, 3)
    vander = polynomial.polyvander3d(x, y, z, deg)
    vander = vander.reshape(-1, vander.shape[-1])
    if method == 'ols':
        c = np.linalg.lstsq(vander, f.ravel(), rcond=None)[0]
    elif method == 'ridge':
        model = linear_model.Ridge(fit_intercept=False)
        model.fit(vander, f.ravel())
        c = model.coef_
    elif method == 'lasso':
        model = linear_model.Lasso(fit_intercept=False)
        model.fit(vander, f.ravel())
        c = model.coef_
    c = c.reshape(deg + 1)
    return c
Beispiel #6
0
def polyfit3d(x, y, z, m, deg=1, grid=True, weight=None):
    '''
    polyfit3d(x, y, z, m, deg=1, grid=True, weight=None):

    Fit a polynomial function to 3d coordiantes (x,y,z) with <deg>,
    m is target data.

    Input:
        <x>,<y>,<z>: must be 3d arrays (if <grid> is True), or 1d (if <grid> is False)
        <m>: target data value, can be 1d or 3d. If 3d, we flatten it to 1d
        <deg>: int, the highest polynomial order to use, default:1
        <grid>: boolean, optional. Whether x, y, z is a grid format. Then we
            convert it to normal array format. This is useful if we fit a polynomial
            to a 3d volume. In this case, m.size = x.size * y.size * z.size
        <weight>: same size with m, weight assigned for each data point.
                Note if <weight> then the total number of dots can not be too big, better<100
                otherwise
    Output:
        <coef>: 1d array, derived coefficients. See Note note below for the order
            of coef
        <predm>:1d array, predicted m values. or 3d arrays if <grid>=True
        <V>: power item matrix
        <residual>: a scalar, (weighted) residual of the model fitting

    We use numpy.polynomial.polynomial.polyvander to construct the polynomial
    arrays V. However, this function construct a full array that only
    constrains the highest power for individual item (x, or, y). This leads to
    highest power in V to 2*<deg>, exceeding the order constraint. For example, input <deg>=2,
    then the item with highest order will be x2*y2. The highest order is 2*2 = 4.
    We use the numpy.tril to select appropriate item for fitting.

    Then polyfit3d is equivalent to sole the linear regression
    weight. We use scipy.linalg.lstsq to solve the equation

    The order of coef is correspond to the order of power items in
    the column of V. Thus np.dot(V,coef) should give the <predz>

    Note that the order is flattened version of mask. For example.
    If <deg>=2, x,y,z power should be [0, 1, 2]. The the order (x,y,z) should be (0,0,1)
    (0,0,2), ... (2,2,0),(2,2,1),(2,2,2). Note that this is *DIFFERENT*
    from the output of numpy.polyfit, which the coefficient order is from high
    to low to their corresponding power item.

    x,y,z,m can have nan or inf value. We use np.isfinite to identify them
    and we do not include them when computing weight, We directly return nan
    values in <predm>

    Example:
    x,y,z = np.mgrid[1:100:10j, 1:100:10j, 1:100:10j]
    m = x + 2*x**2 + 3*y**2 + 4*z**2 + 5 + 10*np.random.randn(*x.shape)
    coef, predm, _, _ = rz.stats.polyfit3d(x.flatten(),y.flatten(),z.flatten(),m.flatten(),deg=2, grid=False)
    plt.subplot(121)
    plt.imshow(rz.imageprocess.makeimagestack(m))
    plt.subplot(122)
    plt.imshow(rz.imageprocess.makeimagestack(predm.reshape(*m.shape)))
    plt.subplot
    plt.scatter(m.flatten(), predm.flatten())



    History:
        20180628 RZ add weights functionality, switch to directly solve the equation
        20180510 RZ created it

    '''

    import numpy as np
    import scipy.linalg as linalg
    import scipy.sparse as sparse
    from numpy.polynomial.polynomial import polyvander3d

    # check input
    assert isinstance(
        x, np.ndarray) and x.ndim in (1, 3), 'x is not 1d np.npdarray!'
    assert isinstance(
        y, np.ndarray) and y.ndim in (1, 3), 'y is not 1d np.npdarray!'
    assert isinstance(
        z, np.ndarray) and z.ndim in (1, 3), 'z is not 1d np.npdarray!'
    assert isinstance(m, np.ndarray), 'm must be an array'
    m = m.flatten()

    # convert if grid=True
    if grid:
        xsize, ysize, zsize = x.size, y.size, z.size
        xx, yy, zz = np.meshgrid(x, y, z)
        x, y, z = xx.flatten(), yy.flatten(), zz.flatten()

    # deal with nan and inf values
    valid = np.isfinite(x) & np.isfinite(y) & np.isfinite(z) & np.isfinite(m)

    # obtain polymial order array V
    V = polyvander3d(x, y, z, deg=[deg, deg, deg])

    # we want to set the lower right triangle of V to zero since those item exceeds
    # the highest order
    ii, jj, kk = np.mgrid[0:(deg + 1), 0:(deg + 1), 0:(deg + 1)]
    tt = ii + jj + kk
    mask = tt.flatten() <= deg

    # remove the item that exceeds the order
    V = V[:, mask]  # V is a point x num power time matrix

    # set the weight matrix
    if weight:
        W = sparse.diags(weight[valid])
        # directly solve the equation
        coef = linalg.inv(
            V[valid, :].T @ W @ V[valid, :]) @ V[valid, :].T @ W * m[valid]
        # we reverse the order of coef and V to match output of coef
        # with power from high to low. The last one is the constant term.
        predm = np.dot(V, coef)
        residual = (weight[valid] * (predm[valid] - m[valid])**2).sum()
    else:
        coef, residual, _, _ = linalg.lstsq(V[valid, :], m[valid])
        predm = np.dot(V, coef)

    if grid:  # if grid case, we output a multi array
        predm = predm.reshape(xsize, ysize, zsize)

    return coef, predm, V, residual
Beispiel #7
0
def indeterminate(q, degree):
    return polyvander3d(q[0], q[1], q[2], [degree, degree, degree])[0]