J'ai un dataframe geopandas qui contient des points
for i in df.index: val = returnValuePoints(df, data, i)
pour chaque point Je voudrais appliquer cette fonction:
def returnValuePoints(df, i): points_list = [ (df['geometry'][i].x, df['geometry'][i].y) ] #list of X,Y coordinates for point in points_list: col = int((point[0] - xOrigin) / pixelWidth) row = int((yOrigin - point[1] ) / pixelHeight) return (row, col)
ce quoi Je fais:
df: geometry 0 POINT (806470.3646198167 2064879.919354021) 1 POINT (792603.391127742 2170760.8355139) 2 POINT (787263.3037740411 2050925.953643546) 3 POINT (809203.6762813283 2160874.194588484) 4 POINT (781668.2687635225 2051524.634389534)
Comment puis-je éviter la boucle et appliquer cette fonction à toutes les lignes avec apply()
p>
3 Réponses :
Vous devez d'abord restructurer votre méthode pour qu'elle prenne des valeurs que vous pouvez transmettre à l'aide de la fonction lambda dans le apply (pensez à la façon dont vous voudriez opérer sur les valeurs d'une ligne individuelle):
val = df.apply(lambda x: returnValuePoints(x.geometry.x, x.geometry.y), axis=1)
Un avertissement concernant le code ci-dessous: je ne l'ai pas testé, car je n'ai pas accès à un environnement geopandas. Cependant, j'imagine que cela devrait fonctionner.
Je ne pense pas que vous souhaitiez réellement utiliser une application ici. En utilisant les méthodes geopandas, vous pouvez obtenir un geopandas GeoSeries
de points en appliquant quelques transformations affines:
Tout d'abord, vous traduisez
la série de points par xOrigin, yOrigin
:
list(df[['x_val', 'y_val']].itertuples(index=False, name=None))
Ensuite, vous pouvez tous les deux faire la réflexion sur l'axe des abscisses et la mise à l'échelle par pixelWidth, pixelHeight
avec une scale
:
df['x_val'] = x_val df['y_val'] = y_val
Multiplier par -1 ici fait la réflexion. Si à la place vous voulez faire (point [1] - yOrigin)
, vous pouvez remplacer le -1 par 1.
Cela vous donnera un code GeoSeries >. Si vous voulez une série de paires de points entiers , vous devrez faire un peu plus de travail. Le code ci-dessous vous donnera deux entiers
Series
avec les valeurs x et y (version geopandas> 0.3.0 requise):
x_val = scaled_translated.x.astype(int) y_val = scaled_translated.y.astype(int)
Vous pouvez alors , disons, mettez-les dans votre bloc de données d'origine:
scaled_translated = translated.scale(xfact=1/pixelWidth, yfact=-1/pixelHeight)
et si vous voulez vraiment une liste de tuples (je pense que vous ne devriez probablement pas ! Vous perdez tous les avantages des pandas!) Vous pouvez faire:
translated = df['geometry'].translate(xoff=-1*xOrigin, yoff=-1*yOrigin)
Je vais vous montrer un exemple.
import pandas as pd # reading csv s = pd.read_csv("stock.csv", squeeze = True) # defining function to check price def fun(num): if num<200: return "Low" elif num>= 200 and num<400: return "Normal" else: return "High" # passing function to apply and storing returned series in new new = s.apply(fun) # printing first 3 element print(new.head(3)) # printing elements somewhere near the middle of series print(new[1400], new[1500], new[1600]) # printing last 3 elements print(new.tail(3))
Je pense que vous ne voulez probablement pas utiliser apply ici. Il existe probablement un moyen vectorisé de le faire, mais je ne connais pas très bien les géopandas.
Cela ressemble à un combo d'une réflexion sur l'axe y (bien que je ne serais pas surpris si c'est un accident!), Une traduction par
xOrigin, yOrigin
et un facteur de mise à l'échelle.