1
votes

Python: comment utiliser correctement apply ()?

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>


2 commentaires

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.


3 Réponses :


1
votes

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)


0 commentaires

1
votes

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)


0 commentaires

0
votes

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)) 

Voici la sortie


0 commentaires