2017-03-22 1 views
3

J'ai un code pour séquentiellement si chaque paire de coordonnées cartésiennes trouvées dans mon DataFrame tombe dans certaines zones fermées géométriques. Mais c'est plutôt lent, je suppose que ce n'est pas vectorisé. Voici un exemple:accélérer la vérification séquentielle si un point est dans une forme en Python

from matplotlib.patches import Rectangle 

r1 = Rectangle((0,0), 10, 10) 
r2 = Rectangle((50,50), 10, 10) 

df = pd.DataFrame([[1,2],[-1,5], [51,52]], columns=['x', 'y']) 

for j in range(df.shape[0]): 
    coordinates = df.x.iloc[j], df.y.iloc[j] 
    if r1.contains_point(coordinates): 
     df['location'].iloc[j] = 0 
    else r2.contains_point(coordinates): 
     df['location'].iloc[j] = 1 

Quelqu'un peut-il proposer une approche pour l'accélération?

Répondre

3

Il est préférable de convertir les pièces rectangulaires en une matrice et de travailler dessus après avoir déduit la mesure dans laquelle elles sont étalées.

def seqcheck_vect(df): 
    xy = df[["x", "y"]].values 
    e1 = np.asarray(rec1.get_extents()) 
    e2 = np.asarray(rec2.get_extents()) 
    r1m1, r1m2 = np.min(e1), np.max(e1) 
    r2m1, r2m2 = np.min(e2), np.max(e2) 
    out = np.where(((xy >= r1m1) & (xy <= r1m2)).all(axis=1), 0, 
        np.where(((xy >= r2m1) & (xy <= r2m2)).all(axis=1), 1, np.nan)) 
    return df.assign(location=out) 

Pour l'échantillon donné les sorties de fonction:

enter image description here


benchmarks:

def loopy_version(df): 
    for j in range(df.shape[0]): 
     coordinates = df.x.iloc[j], df.y.iloc[j] 
     if rec1.contains_point(coordinates): 
      df.loc[j, "location"] = 0 
     elif rec2.contains_point(coordinates): 
      df.loc[j, "location"] = 1 
     else: 
      pass 
    return df 

essais sur une DF de 10K lignes:

np.random.seed(42) 
df = pd.DataFrame(np.random.randint(0, 100, (10000,2)), columns=list("xy")) 

# check if both give same outcome 
loopy_version(df).equals(seqcheck_vect(df)) 
True 

%timeit loopy_version(df) 
1 loop, best of 3: 3.8 s per loop 

%timeit seqcheck_vect(df) 
1000 loops, best of 3: 1.73 ms per loop 

Ainsi, l'approche vectorisé est d'environ 2200 fois plus rapide par rapport à celui Loopy.

+1

Merci. Je me demande cependant s'il existe une méthode plus générale qui ne repose pas sur un rectangle, mais qui est vectorisée? Votre approche en dépendait si je ne me trompe pas – splinter

+0

Fondamentalement, toute structure ayant une plage de comparaison avec les valeurs présentes dans le 'DF' suivrait une implémentation similaire à celle montrée ci-dessus. Il devrait y avoir un moyen d'en extraire les points de départ et de fin et de stocker le résultat dans un tableau. –

+0

En outre, tous les correctifs ont une méthode '.get_extents()', ce qui ne devrait poser aucun problème, je suppose. –