Tasos
Digamos que tengo un dataframe como este
import pandas as pd
df = pd.DataFrame([[1, 2, 1], [1, 3, 2], [4, 6, 3], [4, 3, 4], [5, 4, 5]], columns=['A', 'B', 'C'])
>> df
A B C
0 1 2 1
1 1 3 2
2 4 6 3
3 4 3 4
4 5 4 5
La tabla original es más complicada con más columnas y filas.
Quiero obtener la primera fila que cumpla con algunos criterios. Ejemplos:
- Obtener la primera fila donde A > 3 (devuelve la fila 2)
- Obtenga la primera fila donde A > 4 Y B > 3 (devuelve la fila 4)
- Obtener la primera fila donde A > 3 Y (B > 3 O C > 2) (devuelve la fila 2)
Pero, si no hay ninguna fila que cumpla con los criterios específicos, entonces quiero obtener la primera después de ordenarla descendiendo por A (u otros casos por B, C, etc.)
- Obtenga la primera fila donde A > 6 (devuelve la fila 4 ordenándola por A desc y obtiene la primera)
Pude hacerlo iterando en el marco de datos (sé que es una mierda: P). Entonces, prefiero una forma más pitónica de resolverlo.
este tutorial es muy bueno para rebanar pandas. Asegúrate de comprobarlo. En algunos fragmentos… Para dividir un marco de datos con una condición, utilice este formato:
>>> df[condition]
Esto devolverá una porción de su marco de datos que puede indexar usando iloc
. Aquí están sus ejemplos:
-
Obtener la primera fila donde A > 3 (devuelve la fila 2)
>>> df[df.A > 3].iloc[0] A 4 B 6 C 3 Name: 2, dtype: int64
Si lo que realmente quiere es el número de fila, en lugar de usar iloc
podría ser df[df.A > 3].index[0]
.
-
Obtener la primera fila donde A > 4 Y B > 3:
>>> df[(df.A > 4) & (df.B > 3)].iloc[0] A 5 B 4 C 5 Name: 4, dtype: int64
-
Obtener la primera fila donde A > 3 Y (B > 3 O C > 2) (devuelve la fila 2)
>>> df[(df.A > 3) & ((df.B > 3) | (df.C > 2))].iloc[0] A 4 B 6 C 3 Name: 2, dtype: int64
Ahora, con su último caso, podemos escribir una función que maneje el caso predeterminado de devolver el marco ordenado descendente:
>>> def series_or_default(X, condition, default_col, ascending=False):
... sliced = X[condition]
... if sliced.shape[0] == 0:
... return X.sort_values(default_col, ascending=ascending).iloc[0]
... return sliced.iloc[0]
>>>
>>> series_or_default(df, df.A > 6, 'A')
A 5
B 4
C 5
Name: 4, dtype: int64
Como era de esperar, devuelve la fila 4.
-
En caso de que su marco de datos sea muy grande, ¿no es un desperdicio? Está calculando una serie completa solo para extraer su primer elemento.
– BolígrafoBen
19 de febrero de 2019 a las 23:23
Para coincidencias existentes, utilice query
:
df.query(' A > 3' ).head(1)
Out[33]:
A B C
2 4 6 3
df.query(' A > 4 and B > 3' ).head(1)
Out[34]:
A B C
4 5 4 5
df.query(' A > 3 and (B > 3 or C > 2)' ).head(1)
Out[35]:
A B C
2 4 6 3
ZeFeng Zhu
Para el punto que ‘devuelve el valor tan pronto como encuentra la primera fila/registro que cumple con los requisitos y NO iterando otras filas’, el siguiente código funcionaría:
def pd_iter_func(df):
for row in df.itertuples():
# Define your criteria here
if row.A > 4 and row.B > 3:
return row
Es más eficiente que Boolean Indexing
cuando se trata de un marco de datos grande.
Para hacer que la función anterior sea más aplicable, se pueden implementar funciones lambda:
def pd_iter_func(df: DataFrame, criteria: Callable[[NamedTuple], bool]) -> Optional[NamedTuple]:
for row in df.itertuples():
if criteria(row):
return row
pd_iter_func(df, lambda row: row.A > 4 and row.B > 3)
Como se menciona en la respuesta a la pregunta del ‘espejo’, pandas.Series.idxmax
también sería una buena elección.
def pd_idxmax_func(df, mask):
return df.loc[mask.idxmax()]
pd_idxmax_func(df, (df.A > 4) & (df.B > 3))
-
Me gusta itertuples(). Pero con idxmax(), ¿no se evalúa el máximo en cada fila antes de ejecutar idxmax()?
– Zachary Ryan Smith
23 de diciembre de 2020 a las 12:15
pabtorre
puedes encargarte de los primeros 3 artículos con rebanado y cabeza:
df[df.A>=4].head(1)
df[(df.A>=4)&(df.B>=3)].head(1)
df[(df.A>=4)&((df.B>=3) * (df.C>=2))].head(1)
La condición en caso de que no vuelva nada se puede manejar con un intento o un si…
try:
output = df[df.A>=6].head(1)
assert len(output) == 1
except:
output = df.sort_values('A',ascending=False).head(1)
La primera fila A> 4 es 4, ¿puede verificar las pruebas que está buscando?
– Zeugma
17/11/2016 a las 16:31
indexación booleana?
– Kartik
17/11/2016 a las 16:31
@Boud Lo siento por eso. Error de tecleado 🙁
– Tasas
17/11/2016 a las 16:33
La indexación booleana probablemente sea más de lo que desea, ya que debe ejecutarse en todo el DataFrame. Si la primera fila es la que desea, debería poder averiguarlo de inmediato, independientemente del tamaño del DataFrame.
– BolígrafoBen
17 de noviembre de 2016 a las 16:36
¿Hay alguna forma específica en que los criterios se relacionen con la columna que desea ordenar? ¿O es diferente? Si tiene una lista de criterios, puede usar la respuesta de @ Boud para seleccionar las filas, y si el resultado no tiene filas, puede usar
argmax
para devolver la fila más grande.– Kartik
17 de noviembre de 2016 a las 16:41