Ejemplo n.º 1
0
def inverse_exp_coord(beta1, beta2):
    """
    Calculate the inverse exponential to obtain a shooting vector from
    beta1 to beta2 in shape space of open curves

    :param beta1: numpy ndarray of shape (2,M) of M samples
    :param beta2: numpy ndarray of shape (2,M) of M samples

    :rtype: numpy ndarray
    :return v: shooting vectors
    :return dist: distance

    """
    T = beta1.shape[1]
    centroid1 = calculatecentroid(beta1)
    beta1 = beta1 - tile(centroid1, [T, 1]).T
    centroid2 = calculatecentroid(beta2)
    beta2 = beta2 - tile(centroid2, [T, 1]).T

    q1 = curve_to_q(beta1)

    # Iteratively optimize over SO(n) x Gamma
    for i in range(0, 1):
        # Optimize over SO(n)
        beta2, O_hat, tau = find_rotation_and_seed_coord(beta1, beta2)
        q2 = curve_to_q(beta2)

        # Optimize over Gamma
        gam = optimum_reparam_curve(q2, q1, 0.0)
        gamI = uf.invertGamma(gam)
        # Applying optimal re-parameterization to the second curve
        beta2 = group_action_by_gamma_coord(beta2, gamI)

    # Optimize over SO(n)
    beta2, O_hat, tau = find_rotation_and_seed_coord(beta1, beta2)
    q2n = curve_to_q(beta2)

    # Compute geodesic distance
    q1dotq2 = innerprod_q2(q1, q2n)
    dist = arccos(q1dotq2)

    # Compute shooting vector
    if q1dotq2 > 1:
        q1dotq2 = 1

    u = q2n - q1dotq2 * q1
    normu = sqrt(innerprod_q2(u, u))

    if normu > 1e-4:
        v = u * arccos(q1dotq2) / normu
    else:
        v = zeros((2, T))

    return (v, dist)
Ejemplo n.º 2
0
def find_C(C, qn, vec, q0, m, mu_psi):
    qhat, gamhat, a, U, s, mu_g = jointfPCAd(qn, vec, C, m, mu_psi)
    (M,N) = qn.shape
    time = np.linspace(0,1,M-1)

    d = np.zeros(N)
    for i in range(0,N):
        tmp = uf.warp_q_gamma(time, qhat[0:(M-1),i], uf.invertGamma(gamhat[:,i]))
        d[i] = trapz((tmp-q0[:,i])*(tmp-q0[:,i]), time)

    out = sum(d*d)/N

    return out
Ejemplo n.º 3
0
def oc_srvf_align(beta, mode='O'):
    """
    This claculates the mean of a set of curves and aligns them
    :param beta: numpy ndarray of shape (n, M, N) describing N curves
    in R^M
    :param mode: Open ('O') or closed curve ('C') (default 'O')

    :rtype: tuple of numpy array
    :return betan: aligned curves
    :return qn: aligned srvf
    :return betamean: mean curve
    :return mu: mean srvf
    """
    n, T, N = beta.shape
    # find mean
    mu, betamean, v, q = curve_karcher_mean(beta, mode=mode)

    qn = zeros((n, T, N))
    betan = zeros((n, T, N))
    centroid2 = cf.calculatecentroid(betamean)
    betamean = betamean - tile(centroid2, [T, 1]).T
    q_mu = cf.curve_to_q(betamean)
    # align to mean
    for ii in range(0, N):
        beta1 = beta[:, :, ii]
        centroid1 = cf.calculatecentroid(beta1)
        beta1 = beta1 - tile(centroid1, [T, 1]).T

        # Iteratively optimize over SO(n) x Gamma
        for i in range(0, 1):
            # Optimize over SO(n)
            beta1, O_hat, tau = cf.find_rotation_and_seed_coord(betamean,
                                                                beta1)
            q1 = cf.curve_to_q(beta1)

            # Optimize over Gamma
            gam = cf.optimum_reparam_curve(q1, q_mu, 0.0)
            gamI = uf.invertGamma(gam)
            # Applying optimal re-parameterization to the second curve
            beta1 = cf.group_action_by_gamma_coord(beta1, gamI)

        # Optimize over SO(n)
        beta1, O_hat, tau = cf.find_rotation_and_seed_coord(betamean, beta1)
        qn[:, :, ii] = cf.curve_to_q(beta1)
        betan[:, :, ii] = beta1

    align_results = collections.namedtuple('align', ['betan', 'qn', 'betamean', 'mu'])
    out = align_results(betan, qn, betamean, q_mu)
    return out
Ejemplo n.º 4
0
def geod_sphere(beta1, beta2, k=5):
    """
    This function caluclates the geodecis between open curves beta1 and
    beta2 with k steps along path

    :param beta1: numpy ndarray of shape (2,M) of M samples
    :param beta2: numpy ndarray of shape (2,M) of M samples
    :param k: number of samples along path (Default = 5)

    :rtype: numpy ndarray
    :return dist: geodesic distance
    :return path: geodesic path
    :return O: rotation matrix

    """
    lam = 0.0
    elastic = 1
    rotation = 1
    returnpath = 1
    n, T = beta1.shape

    beta1 = cf.resamplecurve(beta1, T)
    beta2 = cf.resamplecurve(beta2, T)

    centroid1 = cf.calculatecentroid(beta1)
    beta1 = beta1 - tile(centroid1, [T, 1]).T
    centroid2 = cf.calculatecentroid(beta2)
    beta2 = beta2 - tile(centroid2, [T, 1]).T

    q1 = cf.curve_to_q(beta1)
    if rotation:
        beta2, O1, tau = cf.find_rotation_and_seed_coord(beta1, beta2)
        q2 = cf.curve_to_q(beta2)
    else:
        O1 = eye(2)
        q2 = cf.curve_to_q(beta2)

    if elastic:
        # Find the optimal coorespondence
        gam = cf.optimum_reparam_curve(q2, q1, lam)
        gamI = uf.invertGamma(gam)
        # Applying optimal re-parameterization to the second curve
        beta2n = cf.group_action_by_gamma_coord(beta2, gamI)
        q2n = cf.curve_to_q(beta2n)

        if rotation:
            beta2n, O2, tau = cf.find_rotation_and_seed_coord(beta1, beta2n)
            centroid2 = cf.calculatecentroid(beta2n)
            beta2n = beta2n - tile(centroid2, [T, 1]).T
            q2n = cf.curve_to_q(beta2n)
            O = O1.dot(O2)
    else:
        q2n = q2
        O = O1

    # Forming geodesic between the registered curves
    dist = arccos(cf.innerprod_q2(q1, q2n))

    if returnpath:
        PsiQ = zeros((n, T, k))
        PsiX = zeros((n, T, k))
        for tau in range(0, k):
            s = dist * tau / (k - 1.)
            PsiQ[:, :, tau] = (sin(dist-s)*q1+sin(s)*q2n)/sin(dist)
            PsiX[:, :, tau] = cf.q_to_curve(PsiQ[:, :, tau])

        path = PsiQ
    else:
        path = 0

    return(dist, path, O)
Ejemplo n.º 5
0
def init_path_rand(beta1, beta_mid, beta2, T=100, k=5):
    """
    Initializes a path in \cal{C}. beta1, beta_mid beta2 are already
    standardized curves. Creates a path from beta1 to beta_mid to beta2 in
    shape space, then projects to the closed shape manifold.

    :param beta1: numpy ndarray of shape (2,M) of M samples (first curve)
    :param betamid: numpy ndarray of shape (2,M) of M samples (mid curve)
    :param beta2: numpy ndarray of shape (2,M) of M samples (end curve)
    :param T: Number of samples of curve (Default = 100)
    :param k: number of samples along path (Default = 5)

    :rtype: numpy ndarray
    :return alpha: a path between two q-functions
    :return beta:  a path between two curves
    :return O: rotation matrix

    """
    alpha = zeros((2, T, k))
    beta = zeros((2, T, k))

    q1 = cf.curve_to_q(beta1)
    q_mid = cf.curve_to_q(beta_mid)

    # find optimal rotation of q2
    beta2, O1, tau1 = cf.find_rotation_and_seed_coord(beta1, beta2)
    q2 = cf.curve_to_q(beta2)

    # find the optimal coorespondence
    gam = cf.optimum_reparam_curve(q2, q1)
    gamI = uf.invertGamma(gam)

    # apply optimal reparametrization
    beta2n = cf.group_action_by_gamma_coord(beta2, gamI)

    # find optimal rotation of q2
    beta2n, O2, tau1 = cf.find_rotation_and_seed_coord(beta1, beta2n)
    centroid2 = cf.calculatecentroid(beta2n)
    beta2n = beta2n - tile(centroid2, [T, 1]).T
    q2n = cf.curve_to_q(beta2n)
    O = O1.dot(O2)

    # Initialize a path as a geodesic through q1 --- q_mid --- q2
    theta1 = arccos(cf.innerprod_q2(q1, q_mid))
    theta2 = arccos(cf.innerprod_q2(q_mid, q2n))
    tmp = arange(2, int((k - 1) / 2) + 1)
    t = zeros(tmp.size)
    alpha[:, :, 0] = q1
    beta[:, :, 0] = beta1

    i = 0
    for tau in range(2, int((k - 1) / 2) + 1):
        t[i] = (tau - 1.0) / ((k - 1) / 2.0)
        qnew = (1 / sin(theta1)) * (sin((1 - t[i]) * theta1) * q1 + sin(t[i] * theta1) * q_mid)
        alpha[:, :, tau - 1] = cf.project_curve(qnew)
        x = cf.q_to_curve(alpha[:, :, tau - 1])
        a = -1 * cf.calculatecentroid(x)
        beta[:, :, tau - 1] = x + tile(a, [T, 1]).T
        i += 1

    alpha[:, :, int((k - 1) / 2)] = q_mid
    beta[:, :, int((k - 1) / 2)] = beta_mid

    i = 0
    for tau in range(int((k - 1) / 2) + 1, k - 1):
        qnew = (1 / sin(theta2)) * (sin((1 - t[i]) * theta2) * q_mid + sin(t[i] * theta2) * q2n)
        alpha[:, :, tau] = cf.project_curve(qnew)
        x = cf.q_to_curve(alpha[:, :, tau])
        a = -1 * cf.calculatecentroid(x)
        beta[:, :, tau] = x + tile(a, [T, 1]).T
        i += 1

    alpha[:, :, k - 1] = q2n
    beta[:, :, k - 1] = beta2n

    return (alpha, beta, O)
Ejemplo n.º 6
0
def geod_sphere(beta1, beta2, k=5):
    """
    This function caluclates the geodecis between open curves beta1 and
    beta2 with k steps along path

    :param beta1: numpy ndarray of shape (2,M) of M samples
    :param beta2: numpy ndarray of shape (2,M) of M samples
    :param k: number of samples along path (Default = 5)

    :rtype: numpy ndarray
    :return dist: geodesic distance
    :return path: geodesic path
    :return O: rotation matrix

    """
    lam = 0.0
    elastic = 1
    rotation = 1
    returnpath = 1
    n, T = beta1.shape

    beta1 = cf.resamplecurve(beta1, T)
    beta2 = cf.resamplecurve(beta2, T)

    centroid1 = cf.calculatecentroid(beta1)
    beta1 = beta1 - tile(centroid1, [T, 1]).T
    centroid2 = cf.calculatecentroid(beta2)
    beta2 = beta2 - tile(centroid2, [T, 1]).T

    q1 = cf.curve_to_q(beta1)
    if rotation:
        beta2, O1, tau = cf.find_rotation_and_seed_coord(beta1, beta2)
        q2 = cf.curve_to_q(beta2)
    else:
        O1 = eye(2)
        q2 = cf.curve_to_q(beta2)

    if elastic:
        # Find the optimal coorespondence
        gam = cf.optimum_reparam_curve(q2, q1, lam)
        gamI = uf.invertGamma(gam)
        # Applying optimal re-parameterization to the second curve
        beta2n = cf.group_action_by_gamma_coord(beta2, gamI)
        q2n = cf.curve_to_q(beta2n)

        if rotation:
            beta2n, O2, tau = cf.find_rotation_and_seed_coord(beta1, beta2n)
            centroid2 = cf.calculatecentroid(beta2n)
            beta2n = beta2n - tile(centroid2, [T, 1]).T
            q2n = cf.curve_to_q(beta2n)
            O = O1.dot(O2)
    else:
        q2n = q2
        O = O1

    # Forming geodesic between the registered curves
    dist = arccos(cf.innerprod_q2(q1, q2n))

    if returnpath:
        PsiQ = zeros((n, T, k))
        PsiX = zeros((n, T, k))
        for tau in range(0, k):
            s = dist * tau / (k - 1.0)
            PsiQ[:, :, tau] = (sin(dist - s) * q1 + sin(s) * q2n) / sin(dist)
            PsiX[:, :, tau] = cf.q_to_curve(PsiQ[:, :, tau])

        path = PsiQ
    else:
        path = 0

    return (dist, path, O)
Ejemplo n.º 7
0
def find_C_sub(time, qhat, gamhat, q0):
    tmp = uf.warp_q_gamma(time, qhat, uf.invertGamma(gamhat))
    d = trapz((tmp - q0) * (tmp - q0), time)

    return d
Ejemplo n.º 8
0
def gauss_model(fn, time, qn, gam, n=1, sort_samples=False):
    """
    This function models the functional data using a Gaussian model
    extracted from the principal components of the srvfs

    :param fn: numpy ndarray of shape (M,N) of N aligned functions with
     M samples
    :param time: vector of size M describing the sample points
    :param qn: numpy ndarray of shape (M,N) of N aligned srvfs with M samples
    :param gam: warping functions
    :param n: number of random samples
    :param sort_samples: sort samples (default = T)
    :type n: integer
    :type sort_samples: bool
    :type fn: np.ndarray
    :type qn: np.ndarray
    :type gam: np.ndarray
    :type time: np.ndarray

    :rtype: tuple of numpy array
    :return fs: random aligned samples
    :return gams: random warping functions
    :return ft: random samples
    """

    # Parameters
    eps = np.finfo(np.double).eps
    binsize = np.diff(time)
    binsize = binsize.mean()
    M = time.size

    # compute mean and covariance in q-domain
    mq_new = qn.mean(axis=1)
    mididx = np.round(time.shape[0] / 2)
    m_new = np.sign(fn[mididx, :]) * np.sqrt(np.abs(fn[mididx, :]))
    mqn = np.append(mq_new, m_new.mean())
    qn2 = np.vstack((qn, m_new))
    C = np.cov(qn2)

    q_s = np.random.multivariate_normal(mqn, C, n)
    q_s = q_s.transpose()

    # compute the correspondence to the original function domain
    fs = np.zeros((M, n))
    for k in range(0, n):
        fs[:, k] = uf.cumtrapzmid(time, q_s[0:M, k] * np.abs(q_s[0:M, k]),
                                  np.sign(q_s[M, k]) * (q_s[M, k] ** 2),
                                  mididx)

    fbar = fn.mean(axis=1)
    fsbar = fs.mean(axis=1)
    err = np.transpose(np.tile(fbar-fsbar, (n,1)))
    fs += err

    # random warping generation
    rgam = uf.randomGamma(gam, n)
    gams = np.zeros((M, n))
    for k in range(0, n):
        gams[:, k] = uf.invertGamma(rgam[:, k])

    # sort functions and warping
    if sort_samples:
        mx = fs.max(axis=0)
        seq1 = mx.argsort()

        # compute the psi-function
        fy = np.gradient(rgam, binsize)
        psi = fy / np.sqrt(abs(fy) + eps)
        ip = np.zeros(n)
        len = np.zeros(n)
        for i in range(0, n):
            tmp = np.ones(M)
            ip[i] = tmp.dot(psi[:, i] / M)
            len[i] = np.acos(tmp.dot(psi[:, i] / M))

        seq2 = len.argsort()

        # combine x-variability and y-variability
        ft = np.zeros((M, n))
        for k in range(0, n):
            ft[:, k] = np.interp(gams[:, seq2[k]], np.arange(0, M) /
                                 np.double(M - 1), fs[:, seq1[k]])
            tmp = np.isnan(ft[:, k])
            while tmp.any():
                rgam2 = uf.randomGamma(gam, 1)
                ft[:, k] = np.interp(gams[:, seq2[k]], np.arange(0, M) /
                                     np.double(M - 1), uf.invertGamma(rgam2))
    else:
        # combine x-variability and y-variability
        ft = np.zeros((M, n))
        for k in range(0, n):
            ft[:, k] = np.interp(gams[:, k], np.arange(0, M) /
                                 np.double(M - 1), fs[:, k])
            tmp = np.isnan(ft[:, k])
            while tmp.any():
                rgam2 = uf.randomGamma(gam, 1)
                ft[:, k] = np.interp(gams[:, k], np.arange(0, M) /
                                     np.double(M - 1), uf.invertGamma(rgam2))

    samples = collections.namedtuple('samples', ['fs', 'gams', 'ft'])
    out = samples(fs, rgam, ft)
    return out
Ejemplo n.º 9
0
def init_path_rand(beta1, beta_mid, beta2, T=100, k=5):
    r"""
    Initializes a path in :math:`\cal{C}`. beta1, beta_mid beta2 are already
    standardized curves. Creates a path from beta1 to beta_mid to beta2 in
    shape space, then projects to the closed shape manifold.

    :param beta1: numpy ndarray of shape (2,M) of M samples (first curve)
    :param betamid: numpy ndarray of shape (2,M) of M samples (mid curve)
    :param beta2: numpy ndarray of shape (2,M) of M samples (end curve)
    :param T: Number of samples of curve (Default = 100)
    :param k: number of samples along path (Default = 5)

    :rtype: numpy ndarray
    :return alpha: a path between two q-functions
    :return beta:  a path between two curves
    :return O: rotation matrix

    """
    alpha = zeros((2, T, k))
    beta = zeros((2, T, k))

    q1 = cf.curve_to_q(beta1)[0]
    q_mid = cf.curve_to_q(beta_mid)[0]

    # find optimal rotation of q2
    beta2, O1, tau1 = cf.find_rotation_and_seed_coord(beta1, beta2)
    q2 = cf.curve_to_q(beta2)[0]

    # find the optimal coorespondence
    gam = cf.optimum_reparam_curve(q2, q1)
    gamI = uf.invertGamma(gam)

    # apply optimal reparametrization
    beta2n = cf.group_action_by_gamma_coord(beta2, gamI)

    # find optimal rotation of q2
    beta2n, O2, tau1 = cf.find_rotation_and_seed_coord(beta1, beta2n)
    centroid2 = cf.calculatecentroid(beta2n)
    beta2n = beta2n - tile(centroid2, [T, 1]).T
    q2n = cf.curve_to_q(beta2n)[0]
    O = O1 @ O2

    # Initialize a path as a geodesic through q1 --- q_mid --- q2
    theta1 = arccos(cf.innerprod_q2(q1, q_mid))
    theta2 = arccos(cf.innerprod_q2(q_mid, q2n))
    tmp = arange(2, int((k - 1) / 2) + 1)
    t = zeros(tmp.size)
    alpha[:, :, 0] = q1
    beta[:, :, 0] = beta1

    i = 0
    for tau in range(2, int((k - 1) / 2) + 1):
        t[i] = (tau - 1.) / ((k - 1) / 2.)
        qnew = (1 / sin(theta1)) * (sin(
            (1 - t[i]) * theta1) * q1 + sin(t[i] * theta1) * q_mid)
        alpha[:, :, tau - 1] = cf.project_curve(qnew)
        x = cf.q_to_curve(alpha[:, :, tau - 1])
        a = -1 * cf.calculatecentroid(x)
        beta[:, :, tau - 1] = x + tile(a, [T, 1]).T
        i += 1

    alpha[:, :, int((k - 1) / 2)] = q_mid
    beta[:, :, int((k - 1) / 2)] = beta_mid

    i = 0
    for tau in range(int((k - 1) / 2) + 1, k - 1):
        qnew = (1 / sin(theta2)) * (sin(
            (1 - t[i]) * theta2) * q_mid + sin(t[i] * theta2) * q2n)
        alpha[:, :, tau] = cf.project_curve(qnew)
        x = cf.q_to_curve(alpha[:, :, tau])
        a = -1 * cf.calculatecentroid(x)
        beta[:, :, tau] = x + tile(a, [T, 1]).T
        i += 1

    alpha[:, :, k - 1] = q2n
    beta[:, :, k - 1] = beta2n

    return (alpha, beta, O)
Ejemplo n.º 10
0
def find_rotation_and_seed_q(q1, q2, closed=0, rotation=True, method="DP"):
    """
    This function returns a candidate list of optimally oriented and
    registered (seed) srvs w.r.t. q1

    :param q1: numpy ndarray of shape (2,M) of M samples
    :param q2: numpy ndarray of shape (2,M) of M samples
    :param closed: Open (0) or Closed (1)
    :param rotation: find rotation (default=True)
    :param method: method to apply optimization (default="DP") options are "DP" or "RBFGS"

    :rtype: numpy ndarray
    :return q2best: optimal aligned q2 to q1 
    :return Rbest: rotation matrix
    :return gamIbest: warping function
    """

    n, T = q1.shape
    scl = 4.
    minE = 4000
    if closed == 1:
        end_idx = int(floor(T/scl))
        scl = 4
    else:
        end_idx = 0
    
    for ctr in range(0, end_idx+1):
        if closed == 1:
            q2n = shift_f(q2, scl*ctr)
        else:
            q2n = q2
        
        if rotation:
            q2new, R = find_best_rotation(q1, q2n)
        else:
            q2new = q2n.copy()
            R = eye(n)

        # Reparam
        if norm(q1-q2new,'fro') > 0.0001:
            gam = optimum_reparam_curve(q2new, q1, 0.0, method)
            gamI = uf.invertGamma(gam)
            q2new = group_action_by_gamma(q2new,gamI)
            if closed == 1:
                q2new = project_curve(q2new)
        else:
            gamI = linspace(0,1,T)
        
        tmp = innerprod_q2(q1,q2new)
        if tmp > 1:
            tmp = 1
        if tmp < -1:
            tmp = -1
        Ec = arccos(tmp)
        if Ec < minE:
            Rbest = R
            q2best = q2new
            gamIbest = gamI
            minE = Ec

    return (q2best, Rbest, gamIbest)
Ejemplo n.º 11
0
def gauss_model(fn, time, qn, gam, n=1, sort_samples=False):
    """
    This function models the functional data using a Gaussian model
    extracted from the principal components of the srvfs

    :param fn: numpy ndarray of shape (M,N) of N aligned functions with
     M samples
    :param time: vector of size M describing the sample points
    :param qn: numpy ndarray of shape (M,N) of N aligned srvfs with M samples
    :param gam: warping functions
    :param n: number of random samples
    :param sort_samples: sort samples (default = T)
    :type n: integer
    :type sort_samples: bool
    :type fn: np.ndarray
    :type qn: np.ndarray
    :type gam: np.ndarray
    :type time: np.ndarray

    :rtype: tuple of numpy array
    :return fs: random aligned samples
    :return gams: random warping functions
    :return ft: random samples
    """

    # Parameters
    eps = np.finfo(np.double).eps
    binsize = np.diff(time)
    binsize = binsize.mean()
    M = time.size

    # compute mean and covariance in q-domain
    mq_new = qn.mean(axis=1)
    mididx = np.round(time.shape[0] / 2)
    m_new = np.sign(fn[mididx, :]) * np.sqrt(np.abs(fn[mididx, :]))
    mqn = np.append(mq_new, m_new.mean())
    qn2 = np.vstack((qn, m_new))
    C = np.cov(qn2)

    q_s = np.random.multivariate_normal(mqn, C, n)
    q_s = q_s.transpose()

    # compute the correspondence to the original function domain
    fs = np.zeros((M, n))
    for k in range(0, n):
        fs[:, k] = uf.cumtrapzmid(time, q_s[0:M, k] * np.abs(q_s[0:M, k]),
                                  np.sign(q_s[M, k]) * (q_s[M, k]**2))

    # random warping generation
    rgam = uf.randomGamma(gam, n)
    gams = np.zeros((M, n))
    for k in range(0, n):
        gams[:, k] = uf.invertGamma(rgam[:, k])

    # sort functions and warping
    if sort_samples:
        mx = fs.max(axis=0)
        seq1 = mx.argsort()

        # compute the psi-function
        fy = np.gradient(rgam, binsize)
        psi = fy / np.sqrt(abs(fy) + eps)
        ip = np.zeros(n)
        len = np.zeros(n)
        for i in range(0, n):
            tmp = np.ones(M)
            ip[i] = tmp.dot(psi[:, i] / M)
            len[i] = np.acos(tmp.dot(psi[:, i] / M))

        seq2 = len.argsort()

        # combine x-variability and y-variability
        ft = np.zeros((M, n))
        for k in range(0, n):
            ft[:, k] = np.interp(gams[:, seq2[k]],
                                 np.arange(0, M) / np.double(M - 1),
                                 fs[:, seq1[k]])
            tmp = np.isnan(ft[:, k])
            while tmp.any():
                rgam2 = uf.randomGamma(gam, 1)
                ft[:, k] = np.interp(gams[:, seq2[k]],
                                     np.arange(0, M) / np.double(M - 1),
                                     uf.invertGamma(rgam2))
    else:
        # combine x-variability and y-variability
        ft = np.zeros((M, n))
        for k in range(0, n):
            ft[:, k] = np.interp(gams[:, k],
                                 np.arange(0, M) / np.double(M - 1), fs[:, k])
            tmp = np.isnan(ft[:, k])
            while tmp.any():
                rgam2 = uf.randomGamma(gam, 1)
                ft[:, k] = np.interp(gams[:, k],
                                     np.arange(0, M) / np.double(M - 1),
                                     uf.invertGamma(rgam2))

    samples = collections.namedtuple('samples', ['fs', 'gams', 'ft'])
    out = samples(fs, rgam, ft)
    return out
Ejemplo n.º 12
0
    def gauss_model(self, n=1, sort_samples=False):
        """
        This function models the functional data using a Gaussian model
        extracted from the principal components of the srvfs

        :param n: number of random samples
        :param sort_samples: sort samples (default = T)
        :type n: integer
        :type sort_samples: bool
        """
        fn = self.fn
        time = self.time
        qn = self.qn
        gam = self.gam

        # Parameters
        eps = np.finfo(np.double).eps
        binsize = np.diff(time)
        binsize = binsize.mean()
        M = time.size

        # compute mean and covariance in q-domain
        mq_new = qn.mean(axis=1)
        mididx = np.round(time.shape[0] / 2)
        m_new = np.sign(fn[mididx, :]) * np.sqrt(np.abs(fn[mididx, :]))
        mqn = np.append(mq_new, m_new.mean())
        qn2 = np.vstack((qn, m_new))
        C = np.cov(qn2)

        q_s = np.random.multivariate_normal(mqn, C, n)
        q_s = q_s.transpose()

        # compute the correspondence to the original function domain
        fs = np.zeros((M, n))
        for k in range(0, n):
            fs[:, k] = uf.cumtrapzmid(time, q_s[0:M, k] * np.abs(q_s[0:M, k]),
                                      np.sign(q_s[M, k]) * (q_s[M, k]**2),
                                      mididx)
        fbar = fn.mean(axis=1)

        fsbar = fs.mean(axis=1)
        err = np.transpose(np.tile(fbar - fsbar, (n, 1)))
        fs += err

        # random warping generation
        rgam = uf.randomGamma(gam, n)
        gams = np.zeros((M, n))
        for k in range(0, n):
            gams[:, k] = uf.invertGamma(rgam[:, k])

        # sort functions and warping
        if sort_samples:
            mx = fs.max(axis=0)
            seq1 = mx.argsort()

            # compute the psi-function
            fy = np.gradient(rgam, binsize)
            psi = fy / np.sqrt(abs(fy) + eps)
            ip = np.zeros(n)
            len = np.zeros(n)
            for i in range(0, n):
                tmp = np.ones(M)
                ip[i] = tmp.dot(psi[:, i] / M)
                len[i] = np.arccos(tmp.dot(psi[:, i] / M))

            seq2 = len.argsort()

            # combine x-variability and y-variability
            ft = np.zeros((M, n))
            for k in range(0, n):
                ft[:, k] = np.interp(gams[:, seq2[k]],
                                     np.arange(0, M) / np.double(M - 1),
                                     fs[:, seq1[k]])
                tmp = np.isnan(ft[:, k])
                while tmp.any():
                    rgam2 = uf.randomGamma(gam, 1)
                    ft[:, k] = np.interp(gams[:, seq2[k]],
                                         np.arange(0, M) / np.double(M - 1),
                                         uf.invertGamma(rgam2))
        else:
            # combine x-variability and y-variability
            ft = np.zeros((M, n))
            for k in range(0, n):
                ft[:, k] = np.interp(gams[:, k],
                                     np.arange(0, M) / np.double(M - 1), fs[:,
                                                                            k])
                tmp = np.isnan(ft[:, k])
                while tmp.any():
                    rgam2 = uf.randomGamma(gam, 1)
                    ft[:, k] = np.interp(gams[:, k],
                                         np.arange(0, M) / np.double(M - 1),
                                         uf.invertGamma(rgam2))

        self.rsamps = True
        self.fs = fs
        self.gams = rgam
        self.ft = ft
        self.qs = q_s[0:M, :]

        return