Dos formas de señalar datos: por etiqueta y por posición
Un DataFrame se direcciona de dos formas, y confundirlas es el error más común de pandas. .loc selecciona por etiqueta: etiquetas de fila del índice, nombres de columna. .iloc selecciona por posición entera, contada desde 0, como en una lista o un arreglo NumPy. Ambos toman [filas, columnas]: df.loc["AAPL", "price"] es un valor, df.iloc[0, 0] es el valor de la primera fila y la primera columna. Omite la segunda parte para tomar filas enteras: df.loc["AAPL"] es la fila AAPL como Series.
import pandas as pd
df = pd.DataFrame(
{"price": [184.25, 410.2, 171.0, 251.0],
"volume": [200, 50, 300, 120],
"sector": ["tech", "tech", "tech", "auto"]},
index=["AAPL", "MSFT", "GOOG", "TSLA"],
)
print(df.loc["AAPL", "price"], df.iloc[0, 0]) # 184.25 184.25 same cell, two addresses
print(df.loc["TSLA"].to_dict()) # {'price': 251.0, 'volume': 120, 'sector': 'auto'}
print(df.iloc[-1].to_dict()) # the same row: position -1 is the last
print(df.loc[["TSLA", "AAPL"], "price"]) # a list of labels picks in that order
# TSLA 251.00
# AAPL 184.25
# Name: price, dtype: float64
try:
df.loc["XXX", "price"] # a label that does not exist
except KeyError as error:
print("KeyError", error) # KeyError 'XXX'Porciones: las porciones de etiquetas incluyen el final
Las porciones se comportan distinto en los dos sistemas. Una porción de posición df.iloc[1:3] sigue la regla de Python y excluye el final: las posiciones 1 y 2. Una porción de etiquetas df.loc["MSFT":"TSLA"] incluye ambas etiquetas extremas, porque una etiqueta no tiene un «siguiente» natural. Las porciones de etiquetas siguen el orden actual del índice, que no tiene por qué estar ordenado. Para columnas, pasa una lista (["price", "volume"]) para tomarlas en el orden dado. Olvidar en qué sistema estás da resultados desfasados en uno, sin ningún error.
import pandas as pd
df = pd.DataFrame(
{"price": [184.25, 410.2, 171.0, 251.0], "volume": [200, 50, 300, 120]},
index=["AAPL", "MSFT", "GOOG", "TSLA"],
)
print(df.iloc[1:3]) # positions 1 and 2: the end is excluded
# price volume
# MSFT 410.2 50
# GOOG 171.0 300
print(df.loc["MSFT":"TSLA", ["volume", "price"]]) # labels MSFT..TSLA: the end is included
# volume price
# MSFT 50 410.2
# GOOG 300 171.0
# TSLA 120 251.0
print(df.iloc[:, 0].tolist()) # the first column, by position
# [184.25, 410.2, 171.0, 251.0]Condiciones y asignación con loc
.loc también acepta una máscara booleana para las filas: df.loc[df["volume"] > 100, "price"] es la columna de precios de las filas que pasan la prueba, en un paso. Y .loc es como se asigna a una parte elegida: df.loc["MSFT", "price"] = 1.0 cambia una celda y df.loc[df["volume"] < 100, "volume"] = 0 cambia todas las filas que coinciden. Evita formas encadenadas como df[df["volume"] < 100]["volume"] = 0: actúan sobre una copia temporal. En pandas 3 un marco derivado nunca cambia el original, así que para modificar una tabla dentro de una función, haz primero df.copy(), asigna con .loc y devuelve la copia.
import pandas as pd
df = pd.DataFrame(
{"price": [184.25, 410.2, 171.0, 251.0], "volume": [200, 50, 300, 120]},
index=["AAPL", "MSFT", "GOOG", "TSLA"],
)
print(df.loc[df["volume"] > 100, "price"]) # a Boolean mask for rows, a label for the column
# AAPL 184.25
# GOOG 171.00
# TSLA 251.00
# Name: price, dtype: float64
def with_price(frame, symbol, price):
out = frame.copy() # never edit the caller's table
out.loc[symbol, "price"] = price
return out
changed = with_price(df, "MSFT", 1.0)
print(changed.loc["MSFT", "price"], df.loc["MSFT", "price"]) # 1.0 410.2
fixed = df.copy()
fixed.loc[fixed["volume"] < 100, "volume"] = 0 # assign to all matching rows at once
print(fixed["volume"].tolist()) # [200, 0, 300, 120]import pandas as pd
# Integer labels are labels, not positions: a classic trap
d = pd.DataFrame({"x": [1.0, 2.0, 3.0]}, index=[10, 20, 30])
print(d.loc[20, "x"], d.iloc[0, 0]) # 2.0 1.0 label 20 is the second row
print(d.loc[10:20]["x"].tolist()) # [1.0, 2.0] labels 10 through 20, end included
print(d.iloc[0:2]["x"].tolist()) # [1.0, 2.0] positions 0 and 1, end excluded
try:
d.loc[0, "x"] # there is no label 0, even though position 0 exists
except KeyError as error:
print("KeyError", error) # KeyError 0.loc cuando conozcas los nombres (un símbolo, una fecha, una columna) y .iloc solo cuando la posición es el punto («la última fila», «las tres primeras»). El código basado en etiquetas sigue funcionando cuando se reordenan las filas; el basado en posiciones empieza en silencio a elegir otras filas. El simple df[...] es un atajo con varios significados (columna, lista de columnas, máscara de filas), así que en funciones importantes escribe .loc o .iloc explícitamente. El lab pide uno u otro a propósito.df.loc[etiqueta_fila, etiqueta_col]por etiqueta;df.iloc[pos_fila, pos_col]por posición desde 0.- Las porciones
ilocexcluyen el final; las de etiquetasloclo incluyen; una etiqueta ausente lanzaKeyError. df.loc[máscara, "col"]filtra y elige; asigna con.locsobre una.copy()y devuélvela.
A continuación: groupby y agregación, que dividen una tabla en grupos y resumen cada uno.
Lab: qué se califica
- Buscar un precio por símbolo con
price_of25 pts - Tomar las filas entre dos símbolos con
label_range25 pts - Tomar filas por posición con
position_range25 pts - Corregir un precio en una copia con
set_price25 pts