Esempio n. 1
0
def get_neighbourhood(x: np.ndarray,
                      y: np.ndarray,
                      a: int,
                      b: int,
                      t: float = 0.7) -> tuple:
    """Get the neighbourhood (closest points) from a to b.

    The neighbourhood is defined as the longest straitgh line (defined by R2).

    Args:
        x (np.ndarray): the value of the points in the x axis coordinates
        y (np.ndarray): the value of the points in the y axis coordinates
        a (int): the initial point of the search
        b (int): the left limit of the search
        t (float): R2 threshold

    Returns:
        tuple: (neighbourhood index, r2, slope)
    """

    r2 = 1.0
    i = a - 1
    _, slope = lf.linear_fit(x[i:a + 1], y[i:a + 1])

    while r2 > t and i > b:
        previous_res = (i, r2, slope)
        i -= 1
        coef = lf.linear_fit(x[i:a + 1], y[i:a + 1])
        r2 = lf.linear_r2(x[i:a + 1], y[i:a + 1], coef)
        _, slope = coef

    if r2 > t:
        return i, r2, slope
    else:
        return previous_res
Esempio n. 2
0
def get_neighbourhood_binary(x: np.ndarray,
                             y: np.ndarray,
                             a: int,
                             b: int,
                             t=0.9) -> int:
    """
    Get the index of the point within the range [b, a] where the R2 is close to the threshold.

    This version uses a inaccurate binary search to speedup the search.

    Args:
        x (np.ndarray): the value of the points in the x axis coordinates
        y (np.ndarray): the value of the points in the y axis coordinates
        a (int): the initial point of the search
        b (int): the left limit of the search
        t (float): R2 threshold (default 0.9)

    Returns:
        int: index of the point
    """

    i = b
    right = a

    while abs(i - right) > 1:
        coef = lf.linear_fit(x[i:a + 1], y[i:a + 1])
        r2 = lf.linear_r2(x[i:a + 1], y[i:a + 1], coef)

        if r2 < t:
            i = int((i + right) / 2.0)
        else:
            right = i
            i = int((b + right) / 2.0)

    return i
Esempio n. 3
0
def get_neighbourhood_fast(x: np.ndarray,
                           y: np.ndarray,
                           a: int,
                           b: int,
                           t: float = 0.9) -> tuple:
    """
    Get the neighbourhood (closest points) from a to b.

    The neighbourhood is defined as the longest straitgh line (defined by R2).
    This version uses a inaccurate binary search to speedup the search.

    Args:
        x (np.ndarray): the value of the points in the x axis coordinates
        y (np.ndarray): the value of the points in the y axis coordinates
        a (int): the initial point of the search
        b (int): the left limit of the search
        t (float): R2 threshold (default 0.9)

    Returns:
        tuple: (neighbourhood index, r2, slope)
    """
    # speedup when the search using an inaccurate binary search
    i = get_neighbourhood_binary(x, y, a, b, t)
    b, slope = lf.linear_fit(x[i:a + 1], y[i:a + 1])
    r2 = lf.linear_r2(x[i:a + 1], y[i:a + 1], (b, slope))
    previous_res = (i, r2, slope)

    # Linear search to improve accuracy
    while r2 < t and i < a:
        i += 1
        coef = lf.linear_fit(x[i:a + 1], y[i:a + 1])
        r2 = lf.linear_r2(x[i:a + 1], y[i:a + 1], coef)
        _, slope = coef
        previous_res = (i, r2, slope)

    return previous_res
Esempio n. 4
0
def get_knee(x: np.ndarray, y: np.ndarray, fit=Fit.point_fit) -> int:
    """
    Returns the index of the knee point based on menger curvature.

    This method uses the iterative refinement.

    Args:
        x (np.ndarray): the value of the points in the x axis coordinates
        y (np.ndarray): the value of the points in the y axis coordinates
        fit (Fit): select between point fit and best fit

    Returns:
        int: the index of the knee point
    """

    index = 2
    length = x[-1] - x[0]
    left_length = x[index] - x[0]
    right_length = x[-1] - x[index]

    if fit is Fit.best_fit:
        coef_left, r_left, *_ = np.polyfit(x[0:index + 1],
                                           y[0:index + 1],
                                           1,
                                           full=True)
        coef_right, r_rigth, *_ = np.polyfit(x[index:],
                                             y[index:],
                                             1,
                                             full=True)
        error = r_left[0] * (left_length /
                             length) + r_rigth[0] * (right_length / length)
        #error = (r_left[0] + r_rigth[0]) / 2.0
    else:
        coef_left = lf.linear_fit(x[0:index + 1], y[0:index + 1])
        coef_right = lf.linear_fit(x[index:], y[index:])
        r_left = lf.linear_residuals(x[0:index + 1], y[0:index + 1], coef_left)
        r_rigth = lf.linear_residuals(x[index:], y[index:], coef_right)
        error = r_left * (left_length / length) + r_rigth * (right_length /
                                                             length)
        #error = (r_left + r_rigth) / 2.0

    #logger.info("Error(%s) = %s", index, error)

    for i in range(index + 1, len(x) - 2):
        left_length = x[i] - x[0]
        right_length = x[-1] - x[i]

        if fit is Fit.best_fit:
            i_coef_left, r_left, *_ = np.polyfit(x[0:i + 1],
                                                 y[0:i + 1],
                                                 1,
                                                 full=True)
            i_coef_right, r_rigth, *_ = np.polyfit(x[i:], y[i:], 1, full=True)
            current_error = r_left[0] * (left_length / length) + r_rigth[0] * (
                right_length / length)
            #current_error = (r_left[0] + r_rigth[0]) / 2.0
        else:
            i_coef_left = lf.linear_fit(x[0:i + 1], y[0:i + 1])
            i_coef_right = lf.linear_fit(x[i:], y[i:])
            r_left = lf.linear_residuals(x[0:i + 1], y[0:i + 1], i_coef_left)
            r_rigth = lf.linear_residuals(x[i:], y[i:], i_coef_right)
            current_error = r_left * (left_length / length) + r_rigth * (
                right_length / length)
            #current_error = (r_left + r_rigth) / 2.0

        #logger.info("Error(%s) = %s", i, error)

        if current_error < error:
            error = current_error
            index = i
            coef_left = i_coef_left
            coef_right = i_coef_right

    return (index, coef_left, coef_right)
Esempio n. 5
0
def accuracy_trace(points: np.ndarray, knees: np.ndarray) -> tuple:
    """Compute the accuracy heuristic for a set of knees.

    The heuristic is based on the average distance of X and Y axis, the slope and the R2.
    In this version it is used the points from the current knee to the previous.

    Args:
        points (np.ndarray): numpy array with the points (x, y)
        knees (np.ndarray): knees indexes

    Returns:
        tuple: (average_x, average_y, average_slope, average_coeffients, cost)
    """
    x = points[:, 0]
    y = points[:, 1]

    distances_x = []
    distances_y = []
    slopes = []
    coeffients = []

    total_x = math.fabs(x[-1] - x[0])
    total_y = math.fabs(y[-1] - y[0])

    previous_knee_x = x[knees[0]]
    previous_knee_y = y[knees[0]]

    delta_x = x[0] - previous_knee_x
    delta_y = y[0] - previous_knee_y
    distances_x.append(math.fabs(delta_x))
    distances_y.append(math.fabs(delta_y))

    coef = lf.linear_fit(x[0:knees[0] + 1], y[0:knees[0] + 1])
    r2 = lf.linear_r2(x[0:knees[0] + 1], y[0:knees[0] + 1], coef)
    coeffients.append(r2)
    _, slope = coef
    slopes.append(math.fabs(slope))

    for i in range(1, len(knees)):
        knee_x = x[knees[i]]
        knee_y = y[knees[i]]

        delta_x = previous_knee_x - knee_x
        delta_y = previous_knee_y - knee_y

        coef = lf.linear_fit(x[knees[i - 1]:knees[i] + 1],
                             y[knees[i - 1]:knees[i] + 1])
        r2 = lf.linear_r2(x[knees[i - 1]:knees[i] + 1],
                          y[knees[i - 1]:knees[i] + 1], coef)

        distances_x.append(math.fabs(delta_x))
        distances_y.append(math.fabs(delta_y))
        _, slope = coef
        slopes.append(math.fabs(slope))
        coeffients.append(r2)

        previous_knee_x = knee_x
        previous_knee_y = knee_y

    distances_x = np.array(distances_x) / total_x
    distances_y = np.array(distances_y) / total_y
    slopes = np.array(slopes)
    slopes = slopes / slopes.max()

    coeffients = np.array(coeffients)
    coeffients = coeffients / coeffients.max()

    coeffients[coeffients < 0] = 0.0
    p = slopes * distances_y * coeffients
    #p = slopes * distances_y

    average_x = np.average(distances_x)
    average_y = np.average(distances_y)
    average_slope = np.average(slopes)
    average_coeffients = np.average(coeffients)

    cost = average_x / np.average(p)

    return average_x, average_y, average_slope, average_coeffients, cost