2016-12-30 1 views
2

J'ai un Pandas DataFrame qui contient deux ensembles de coordonnées (lat1, lon1, lat2, lon2). J'ai une fonction qui calcule la distance en utilisant ces coordonnées. Mais certaines des lignes de la base de données ne sont pas valides. Je voudrais appliquer ma fonction uniquement aux lignes valides et enregistrer le résultat de la fonction dans une colonne 'dist' (la colonne existe déjà dans la structure de données). Je veux quelque chose comme ça SQL:Pandas: remplit conditionnellement une colonne à l'aide d'une fonction basée sur d'autres valeurs de colonnes

UPDATE dataframe 
SET dist=calculate_dist(lat1, lon1, lat2, lon2) 
WHERE lat1 IS NOT NULL AND lat2 IS NOT NULL AND user_id>100; 

Comment puis-je y parvenir? J'ai essayé d'utiliser df = df.apply(calculate_dist, axis=1) mais avec cette approche j'ai besoin de traiter toutes les lignes, pas seulement les lignes qui correspondent à mes conditions, et j'ai besoin d'une instruction if dans la fonction calculate_dist qui ignore les lignes invalides. Y a-t-il un meilleur moyen?

Je sais que des questions similaires sont déjà apparues sur StackOverflow mais je n'ai trouvé aucune question qui utilise à la fois une fonction et une sélection conditionnelle de lignes.

Répondre

5

Je pense que vous avez besoin Filtrer par boolean indexing premier:

mask = (df.lat1.notnull()) & (df.lat2.notnull()) & (df.user_id>100) 

df['dist'] = df[mask].apply(calculate_dist, axis=1) 

Exemple:

df = pd.DataFrame({'lat1':[1,2,np.nan,1], 
        'lon1':[4,5,6,2], 
        'lat2':[7,np.nan,9,3], 
        'lon2':[1,3,5,1], 
        'user_id':[200,30,60,50]}) 

print (df) 
    lat1 lat2 lon1 lon2 user_id 
0 1.0 7.0  4  1  200 
1 2.0 NaN  5  3  30 
2 NaN 9.0  6  5  60 
3 1.0 3.0  2  1  50 

#function returning Series 
def calculate_dist(x): 
    return x.lat2 - x.lat1 

mask = (df.lat1.notnull()) & (df.lat2.notnull()) & (df.user_id>100) 
df['dist'] = df[mask].apply(calculate_dist, axis=1) 
print (df) 
    lat1 lat2 lon1 lon2 user_id dist 
0 1.0 7.0  4  1  200 6.0 
1 2.0 NaN  5  3  30 NaN 
2 NaN 9.0  6  5  60 NaN 
3 1.0 3.0  2  1  50 NaN 
+0

Il fonctionne, je vous remercie. – JustAC0der