Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

208
Visualizações
Pandas usando apply lambda con dos operadores diferentes

Esta pregunta es muy similar a una que publiqué antes con solo un cambio. En lugar de hacer solo la diferencia absoluta para todas las columnas, también quiero encontrar la diferencia de magnitud para la columna 'Z', por lo que si la Z actual es 1.1x mayor que la anterior, manténgala.

(más contexto al problema)

Pandas que usan los valores de clasificación anteriores para filtrar la fila actual

 df = pd.DataFrame({ 'rank': [1, 1, 2, 2, 3, 3], 'x': [0, 3, 0, 3, 4, 2], 'y': [0, 4, 0, 4, 5, 5], 'z': [1, 3, 1.2, 3.25, 3, 6], }) print(df) # rank xyz # 0 1 0 0 1.00 # 1 1 3 4 3.00 # 2 2 0 0 1.20 # 3 2 3 4 3.25 # 4 3 4 5 3.00 # 5 3 2 5 6.00

Esto es lo que quiero que sea la salida

 output = pd.DataFrame({ 'rank': [1, 1, 2, 3], 'x': [0, 3, 0, 2], 'y': [0, 4, 0, 5], 'z': [1, 3, 1.2, 6], }) print(output) # rank xyz # 0 1 0 0 1.0 # 1 1 3 4 3.0 # 2 2 0 0 1.2 # 5 3 2 5 6.00

básicamente, lo que quiero que suceda es si el rango anterior tiene filas con x, y (+- 1 en ambos sentidos) Y z (<1.1z) para eliminarlo.

Entonces, para el rango de filas 1 CUALQUIER fila en el rango 2 que tenga cualquier combinación de x = (-1-1), y = (-1-1), z= (<1.1) O x = (2-5), y = (3-5), z= (<3.3) Quiero que se elimine

over 4 years ago · Santiago Trujillo
5 Respostas
Responde à pergunta

0

Solo toma un ajuste al término z de la ecuación lamda de la publicación vinculada:

 return d.apply(lambda s: abs(d_prev-s)[['x', 'y', 'z']].le([1,1,.1*d_prev['z']]).all(1).any(), axis=1)

Aquí está el código completo que funciona para mí:

 df = pd.DataFrame({ 'rank': [1, 1, 2, 2, 2, 3, 3], 'x': [0, 3, 0, 3, 3, 4, 2], 'y': [0, 4, 0, 4, 4, 5, 5], 'z': [1, 3, 1.2, 3.3, 3.31, 3, 6], }) def check_previous_group(rank, d, groups): if not rank-1 in groups.groups: # check is a previous group exists, else flag all rows False (ie not to be dropped) return pd.Series(False, index=d.index) else: # get previous group (rank-1) d_prev = groups.get_group(rank-1) # get the absolute difference per row with the whole dataset # of the previous group: abs(d_prev-s) # if all differences are within 1/1/0.1*z for x/y/z # for at least one rows of the previous group # then flag the row to be dropped (True) return d.apply(lambda s: abs(d_prev-s)[['x', 'y', 'z']].le([1,1,.1*d_prev['z']]).all(1).any(), axis=1) groups = df.groupby('rank') mask = pd.concat([check_previous_group(rank, d, groups) for rank,d in groups]) df[~mask]
over 4 years ago · Santiago Trujillo Relatório

0

Necesitas modificar ligeramente mi código anterior :

 def check_previous_group(rank, d, groups): if not rank-1 in groups.groups: # check is a previous group exists, else flag all rows False (ie not to be dropped) return pd.Series(False, index=d.index) else: # get previous group (rank-1) d_prev = groups.get_group(rank-1) # get the absolute difference per row with the whole dataset # of the previous group: abs(d_prev-s) # if all differences are within 1/1/0.1*z for x/y/z # for at least one rows of the previous group # then flag the row to be dropped (True) return d.apply(lambda s: abs(d_prev-s)[['x', 'y', 'z']].le([1,1,.1*s['z']]).all(1).any(), axis=1) groups = df.groupby('rank') mask = pd.concat([check_previous_group(rank, d, groups) for rank,d in groups]) df[~mask]

producción:

 rank xyz 0 1 0 0 1.0 1 1 3 4 3.0 2 2 0 0 1.2 5 3 2 5 6.0
over 4 years ago · Santiago Trujillo Relatório

0

Esto funciona para mí en Python 3.8.6

 import pandas as pd dfg = df.groupby("rank") def filter_func(dfg): for g in dfg.groups.keys(): if g-1 in dfg.groups.keys(): yield ( pd.merge( dfg.get_group(g).assign(id = lambda df: df.index), dfg.get_group(g-1), how="cross", suffixes=("", "_prev") ).assign( cond = lambda df: ~( (df.x - df.x_prev).abs().le(1) & (df.y - df.y_prev).abs().le(1) & df.z.divide(df.z_prev).lt(1.1) ) ) ).groupby("id").agg( { **{"cond": "all"}, **{k: "first" for k in df.columns} }).loc[lambda df: df.cond].drop(columns = ["cond"]) else: yield dfg.get_group(g) pd.concat( filter_func(dfg), ignore_index=True )

El resultado parece coincidir con lo que esperaba:

 rank xyz 0 1 0 0 1.0 1 1 3 4 3.0 2 2 0 0 1.2 3 3 2 5 6.0

Pequeña edición: en su pregunta parece que le importa el índice de fila. La solución que publiqué simplemente ignora esto, pero si desea conservarlo, simplemente guárdelo como una columna adicional en el marco de datos.

over 4 years ago · Santiago Trujillo Relatório

0

Aquí hay una solución usando numpy broadcasting :

 # Initially, no row is dropped df['drop'] = False for r in range(df['rank'].min(), df['rank'].max()): # Find the x_min, x_max, y_min, y_max, z_max of the current rank cond = df['rank'] == r x, y, z = df.loc[cond, ['x','y','z']].to_numpy().T x_min, x_max = x + [[-1], [1]] # use numpy broadcasting to ±1 in one command y_min, y_max = y + [[-1], [1]] z_max = z * 1.1 # Find the x, y, z of the next rank. Raise them one dimension # so that we can make a comparison matrix again x_min, x_max, ... cond = df['rank'] == r + 1 if not cond.any(): continue x, y, z = df.loc[cond, ['x','y','z']].to_numpy().T[:, :, None] # Condition to drop a row drop = ( (x_min <= x) & (x <= x_max) & (y_min <= y) & (y <= y_max) & (z <= z_max) ).any(axis=1) df.loc[cond, 'drop'] = drop # Result df[~df['drop']]

Condensado

Una versión aún más condensada (y probablemente más rápida). Esta es una muy buena manera de desconcertar a tus futuros compañeros de equipo cuando lean el código:

 r, x, y, z = df[['rank', 'x', 'y', 'z']].T.to_numpy() rr, xx, yy, zz = [col[:,None] for col in [r, x, y, z]] drop = ( (rr == r + 1) & (x-1 <= xx) & (xx <= x+1) & (y-1 <= yy) & (yy <= y+1) & (zz <= z*1.1) ).any(axis=1) # Result df[~drop]

Lo que esto hace es comparar cada fila en df entre sí (incluido él mismo) y devolver True (es decir, descartar) si:

  • El rango de la fila actual == el rank de la otra fila rank + 1 ; y
  • Los x, y, z de la fila actual se encuentran dentro del rango especificado de los x, y, z de la otra fila
over 4 years ago · Santiago Trujillo Relatório

0

He modificado la función de mozway para que funcione de acuerdo a tus requerimientos.

 # comparing 'equal' float values, may go wrong, that's why I am using this constant DELTA=0.1**12 def check_previous_group(rank, d, groups): if not rank-1 in groups.groups: # check if a previous group exists, else flag all rows False (ie not to be dropped) #return pd.Series(False, index=d.index) return pd.Series(False, index=d.index) else: # get previous group (rank-1) d_prev = groups.get_group(rank-1) # get the absolute difference per row with the whole dataset # of the previous group: abs(d_prev-s) # if differences in x and y are within 1 and z < 1.1*x # for at least one row of the previous group # then flag the row to be dropped (True) return d.apply(lambda s: (abs(d_prev-s)[['x', 'y']].le([1,1]).all(1)& (s['z']<1.1*d_prev['x']-DELTA)).any(), axis=1)

pruebas,

 >>> df = pd.DataFrame({ 'rank': [1, 1, 2, 2, 3, 3], 'x': [0, 3, 0, 3, 4, 2], 'y': [0, 4, 0, 4, 5, 5], 'z': [1, 3, 1.2, 3.25, 3, 6], }) >>> df rank xyz 0 1 0 0 1.00 1 1 3 4 3.00 2 2 0 0 1.20 3 2 3 4 3.25 4 3 4 5 3.00 5 3 2 5 6.00 >>> groups = df.groupby('rank') >>> mask = pd.concat([check_previous_group(rank, d, groups) for rank,d in groups]) >>> df[~mask] rank xyz 0 1 0 0 1.0 1 1 3 4 3.0 2 2 0 0 1.2 5 3 2 5 6.0
 >>> df = pd.DataFrame({ 'rank': [1, 1, 2, 2, 3, 3], 'x': [0, 3, 0, 3, 4, 2], 'y': [0, 4, 0, 4, 5, 5], 'z': [1, 3, 1.2, 3.3, 3, 6], }) >>> df rank xyz 0 1 0 0 1.0 1 1 3 4 3.0 2 2 0 0 1.2 3 2 3 4 3.3 4 3 4 5 3.0 5 3 2 5 6.0 >>> groups = df.groupby('rank') >>> mask = pd.concat([check_previous_group(rank, d, groups) for rank,d in groups]) >>> df[~mask] rank xyz 0 1 0 0 1.0 1 1 3 4 3.0 2 2 0 0 1.2 3 2 3 4 3.3 5 3 2 5 6.0
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda