Beispiel #1
0
def knees(points: np.ndarray,
          t: float,
          cd: Direction,
          cc: Concavity,
          sensitivity: float = 1.0,
          p: PeakDetection = PeakDetection.Kneedle,
          debug: bool = False) -> np.ndarray:
    """Returns the index of the knees point based on the Kneedle method.

    This implementation uses an heuristic to automatically define
    the direction and rotation of the concavity.

    Furthermore, it support three different methods to select the 
    relevant knees:
    1. Kneedle    : classical algorithm
    2. Significant: significant knee peak detection
    3. ZScore     : significant knee peak detection based on zscore

    Args:
        points (np.ndarray): numpy array with the points (x, y)
        t (float): tau of the sliding window used to smooth the curve
        cd (Direction): direction of the concavity
        cc (Concavity): rotation of the concavity
        sensitivity (float): controls the sensitivity of the peak detection (default 1.0)
        p (PeakDetection): selects the peak detection method (default PeakDetection.Kneedle)
        debug (bool): debug flag; when True the algorithm returns more information

    Returns:
        np.ndarray: the indexes of the knee points
    """
    Ds = ema.linear(points, t)

    pmin = Ds.min(axis=0)
    pmax = Ds.max(axis=0)
    Dn = (Ds - pmin) / (pmax - pmin)

    Dd = differences(Dn, cd, cc)

    knees = []

    peaks_idx = pd.all_peaks(Dd)

    if p is PeakDetection.Kneedle:
        knees = pd.kneedle_peak_detection(Dd, peaks_idx, sensitivity)
    elif p is PeakDetection.Significant:
        knees = pd.significant_peaks(Dd, peaks_idx, sensitivity)
    elif p is PeakDetection.ZScore:
        knees = pd.significant_zscore_peaks(Dd, peaks_idx, sensitivity)
    else:
        knees = peaks_idx

    if debug is True:
        return {'knees': knees, 'dd': Dd, 'peaks': pd.all_peaks(Dd)}
    else:
        return knees
Beispiel #2
0
def single_knee(points: np.ndarray, t: float, cd: Direction,
                cc: Concavity) -> int:
    """Returns the index of the knee point based on the Kneedle method.

    Args:
        points (np.ndarray): numpy array with the points (x, y)
        t (float): tau of the side window used to smooth the curve
        cd (Direction): direction of the concavity
        cc (Concavity): rotation of the concavity

    Returns:
        int: the index of the knee point
    """
    Ds = ema.linear(points, t)
    pmin = Ds.min(axis=0)
    pmax = Ds.max(axis=0)
    diff = pmax - pmin
    diff[diff == 0] = 1.0
    Dn = (Ds - pmin) / diff
    Dd = differences(Dn, cd, cc)
    peaks = pd.all_peaks(Dd)
    idx = pd.highest_peak(points, peaks)
    if idx == -1:
        return None
    else:
        return idx
Beispiel #3
0
 def test_all_peaks(self):
     points = np.array([[1.0, 5.0], [2.0, -2.0], [3.0, 3.0], [4.0, 1.0],
                        [5.0, 1.0], [6.0, 4.0], [7.0, 4.0], [8.0, -3.0],
                        [9.0, -3.0], [10.0, -5.0], [11.0, 6.0], [12.0, 3.0],
                        [13.0, 0.0], [14.0, 4.0], [15.0, -2.0], [16.0, 7.0],
                        [17.0, -7.0], [18.0, -3.0], [19.0, 0.0],
                        [20.0, 5.0]])
     result = peak_detection.all_peaks(points)
     desired = np.array([2, 10, 13, 15])
     npt.assert_equal(result, desired)
Beispiel #4
0
 def test_highest_peak(self):
     points = np.array([[1.0, 5.0], [2.0, -2.0], [3.0, 3.0], [4.0, 1.0],
                        [5.0, 1.0], [6.0, 4.0], [7.0, 4.0], [8.0, -3.0],
                        [9.0, -3.0], [10.0, -5.0], [11.0, 6.0], [12.0, 3.0],
                        [13.0, 0.0], [14.0, 4.0], [15.0, -2.0], [16.0, 7.0],
                        [17.0, -7.0], [18.0, -3.0], [19.0, 0.0],
                        [20.0, 5.0]])
     peaks_idx = peak_detection.all_peaks(points)
     result = peak_detection.highest_peak(points, peaks_idx)
     desired = 15
     npt.assert_equal(result, desired)
Beispiel #5
0
 def test_significant_zscore_peaks_iso(self):
     points = np.array([[1.0, 5.0], [2.0, -2.0], [3.0, 3.0], [4.0, 1.0],
                        [5.0, 1.0], [6.0, 4.0], [7.0, 4.0], [8.0, -3.0],
                        [9.0, -3.0], [10.0, -5.0], [11.0, 6.0], [12.0, 3.0],
                        [13.0, 0.0], [14.0, 4.0], [15.0, -2.0], [16.0, 7.0],
                        [17.0, -7.0], [18.0, -3.0], [19.0, 0.0],
                        [20.0, 5.0]])
     peaks_idx = peak_detection.all_peaks(points)
     result = peak_detection.significant_zscore_peaks_iso(points, peaks_idx)
     desired = np.array([2, 10, 15])
     npt.assert_equal(result, desired)
Beispiel #6
0
 def test_zscore_peaks_values(self):
     points = np.array([[1.0, 5.0], [2.0, -2.0], [3.0, 3.0], [4.0, 1.0],
                        [5.0, 1.0], [6.0, 4.0], [7.0, 4.0], [8.0, -3.0],
                        [9.0, -3.0], [10.0, -5.0], [11.0, 6.0], [12.0, 3.0],
                        [13.0, 0.0], [14.0, 4.0], [15.0, -2.0], [16.0, 7.0],
                        [17.0, -7.0], [18.0, -3.0], [19.0, 0.0],
                        [20.0, 5.0]])
     peaks_idx = peak_detection.all_peaks(points)
     result = peak_detection.zscore_peaks_values(points, peaks_idx)
     #np.array([2.12, 2.07, 1.21, 2.71])
     desired = np.array([2.12, 2.08, 1.12, 2.97])
     npt.assert_almost_equal(result, desired, decimal=2)
Beispiel #7
0
 def test_kneedle_peak_detection_00(self):
     points = np.array([[.1, -.5], [.2, 0], [.3, 1.66], [.4, 2.5], [.5, 3],
                        [.6, 3.33], [.7, 3.57], [.8, 3.75], [.9, 3.88]])
     pmin = points.min(axis=0)
     pmax = points.max(axis=0)
     Dn = (points - pmin) / (pmax - pmin)
     x = Dn[:, 0]
     y = Dn[:, 1]
     y_d = y - x
     Dd = np.column_stack((x, y_d))
     peaks_idx = peak_detection.all_peaks(Dd)
     result = peak_detection.kneedle_peak_detection(Dd, peaks_idx)
     desired = np.array([3])
     npt.assert_equal(result, desired)
Beispiel #8
0
def knees(points: np.ndarray, t: float, sensitivity: float, cd: Direction,
          cc: Concavity, p: PeakDetection) -> np.ndarray:
    """Returns the index of the knees point based on the Kneedle method.

    This implementation uses an heuristic to automatically define
    the direction and rotation of the concavity.

    Furthermore, it support three different methods to select the 
    relevant knees:
    1. Kneedle    : classical algorithm
    2. Significant: significant knee peak detection
    3. ZScore     : significant knee peak detection based on zscore

    Args:
        points (np.ndarray): numpy array with the points (x, y)
        t (float): tau of the side window used to smooth the curve
        sensitivity (float): controls the sensitivity of the peak detection
        cd (Direction): direction of the concavity
        cc (Concavity): rotation of the concavity
        p (PeakDetection): selects the peak detection method

    Returns:
        np.ndarray: the indexes of the knee points
    """
    Ds = ema.linear(points, t)

    pmin = Ds.min(axis=0)
    pmax = Ds.max(axis=0)
    Dn = (Ds - pmin) / (pmax - pmin)

    Dd = differences(Dn, cd, cc)

    knees = []

    if p is PeakDetection.Kneedle:
        idx = []
        lmxThresholds = []
        detectKneeForLastLmx = False
        for i in range(1, len(Dd) - 1):
            y0 = Dd[i - 1][1]
            y = Dd[i][1]
            y1 = Dd[i + 1][1]

            if y0 < y and y > y1:
                idx.append(i)
                tlmx = y - sensitivity / (len(Dd) - 1)
                lmxThresholds.append(tlmx)
                detectKneeForLastLmx = True

            if detectKneeForLastLmx:
                if y1 < lmxThresholds[-1]:
                    knees.append(idx[-1])
                    detectKneeForLastLmx = False
        knees = np.array(knees)

    elif p is PeakDetection.Significant:
        peaks_idx = pd.all_peaks(Dd)
        knees = pd.significant_peaks(Dd, peaks_idx, sensitivity)

    elif p is PeakDetection.ZScore:
        peaks_idx = pd.all_peaks(Dd)
        knees = pd.significant_zscore_peaks(Dd, peaks_idx, sensitivity)

    return knees