Python >> Tutoriel Python >  >> Python Tag >> NumPy

Intervalle de recherche numpy qui a au moins k points

Après un peu de lutte, j'ai trouvé cette solution.

D'abord un peu d'explications, et ordre des pensées :

  • Idéalement, nous voudrions définir une taille de fenêtre et la faire glisser du point acceptable le plus à gauche jusqu'au point acceptable le plus à droite, et commencer à compter lorsque min_points sont dans la fenêtre, et finissent de compter quand min_points plus à l'intérieur (imaginez-le comme un opérateur de convulsion ou autre)
  • le piège de base est que nous voulons discrétiser le glissement, donc l'astuce ici est de vérifier uniquement lorsque le nombre de points peut tomber en dessous ou au-dessus de min_points , ce qui signifie à chaque occurrence de l'élément ou window_size en dessous (comme optional_starts reflète)
  • puis itérer sur optional_starts et échantillonner la première fois que la condition est remplie et la dernière fois que la condition est remplie pour chaque intervalle

donc le code suivant a été écrit comme décrit ci-dessus :

def consist_at_least(start, points, min_points, window_size):
    a = [point for point in points if start <= point <= start + window_size]
    return len(a)>=min_points
    


points = [1.4,1.8,   11.3,11.8,12.3,13.2,  18.2,18.3,18.4,18.5]
min_points = 4
window_size = 3
total_interval = [0,20]
optional_starts = points + [item-window_size for item in points if item-window_size>=total_interval[0]] + [total_interval[0] + window_size] + [total_interval[1] - window_size] + [total_interval[0]]
optional_starts = [item for item in optional_starts if item<=total_interval[1]-window_size]
intervals = []
potential_ends = []
for start in sorted(optional_starts):
    is_start_interval = len(intervals)%2 == 0
    if consist_at_least(start, points, min_points, window_size):
        if is_start_interval:
            intervals.append(start)
        else:
            potential_ends.append(start)
    elif len(potential_ends)>0 :
        intervals.append(potential_ends[-1])
        potential_ends = []
if len(potential_ends)>0:
    intervals.append(potential_ends[-1])

print(intervals)

sortie :

[10.2, 11.3, 15.5, 17]

Chacun des 2 éléments consécutifs reflète le début et la fin de l'intervalle


Ainsi, après avoir donné des informations supplémentaires concernant la nature des "intervalles", je propose la solution suivante, qui suppose des distances inter-intervalles d'au moins window_size :

import numpy as np


def get_start_windows(inter, ws, p, mp):

    # Initialize list of suitable start ranges
    start_ranges = []

    # Determine possible intervals w.r.t. to window size
    int_start = np.insert(np.array([0, p.shape[0]]), 1,
                          (np.argwhere(np.diff(p) > ws) + 1).squeeze()).tolist()

    # Iterate found intervals
    for i in np.arange(len(int_start)-1):

        # The actual interval
        int_ = p[int_start[i]:int_start[i+1]]

        # If interval has less than minimum points, reject
        if int_.shape[0] < mp:
            continue

        # Determine first and last possible starting point
        first = max(inter[0], int_[mp-1] - ws)
        last = min(int_[-mp], inter[1] - ws)

        # Add to list of suitable start ranges
        start_ranges.append((first, last))

    return start_ranges


# Example 1
interval = [0, 20]
window_size = 3.0
min_points = 4
points = [1.4, 1.8, 11.3, 11.8, 12.3, 13.2, 18.2, 18.3, 18.4, 18.5]
print(get_start_windows(interval, window_size, np.array(points), min_points))

# Example 2
points = [1.4, 1.8, 1.9, 2.1, 11.3, 11.8, 12.3, 13.2, 18.2, 18.3, 18.4, 18.5]
print(get_start_windows(interval, window_size, np.array(points), min_points))

# Example 3
points = [1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 3.49]
print(get_start_windows(interval, window_size, np.array(points), min_points))

(Le code est peut-être optimisé, je n'y ai pas prêté attention...)

Sortie :

[(10.2, 11.3), (15.5, 17.0)]
[(0, 1.4), (10.2, 11.3), (15.5, 17.0)]
[(0, 1.9)]

Espérons que les cas souhaités soient couverts par cette solution.

-------------------------------------
System information
-------------------------------------
Platform:   Windows-10-10.0.16299-SP0
Python:     3.8.5
NumPy:      1.19.2
-------------------------------------