Duas formas de apontar para dados: por rótulo e por posição
Um DataFrame pode ser endereçado de duas formas, e confundi-las é o bug mais comum do pandas. .loc seleciona por rótulo: rótulos de linha do índice, nomes de coluna. .iloc seleciona por posição inteira, contada de 0, como em uma lista ou array NumPy. Ambos recebem [linhas, colunas]: df.loc["AAPL", "price"] é um valor, df.iloc[0, 0] é o valor da primeira linha e primeira coluna. Omita a segunda parte para pegar linhas inteiras: df.loc["AAPL"] é a linha 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'Fatias: fatias de rótulos incluem o fim
As fatias se comportam de forma diferente nos dois sistemas. Uma fatia de posição df.iloc[1:3] segue a regra do Python e exclui o fim: as posições 1 e 2. Uma fatia de rótulos df.loc["MSFT":"TSLA"] inclui os dois rótulos das pontas, porque um rótulo não tem um «próximo» natural. Fatias de rótulos seguem a ordem atual do índice, que não precisa estar ordenado. Para colunas, passe uma lista (["price", "volume"]) para pegá-las na ordem dada. Esquecer em que sistema você está dá resultados deslocados de um, sem nenhum erro.
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]Condições e atribuição com loc
.loc também aceita uma máscara booleana para as linhas: df.loc[df["volume"] > 100, "price"] é a coluna de preços das linhas que passam no teste, em um passo. E .loc é como se atribui a uma parte escolhida: df.loc["MSFT", "price"] = 1.0 muda uma célula e df.loc[df["volume"] < 100, "volume"] = 0 muda todas as linhas que combinam. Evite formas encadeadas como df[df["volume"] < 100]["volume"] = 0: elas agem sobre uma cópia temporária. No pandas 3 um quadro derivado nunca altera o original, então para modificar uma tabela dentro de uma função, faça primeiro df.copy(), atribua com .loc e devolva a cópia.
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 quando souber os nomes (um símbolo, uma data, uma coluna) e .iloc só quando a posição é o ponto («a última linha», «as três primeiras»). O código baseado em rótulos continua funcionando quando as linhas são reordenadas; o baseado em posições passa em silêncio a escolher outras linhas. O simples df[...] é um atalho com vários significados (coluna, lista de colunas, máscara de linhas), então em funções importantes escreva .loc ou .iloc explicitamente. O lab pede um ou outro de propósito.df.loc[rótulo_linha, rótulo_col]por rótulo;df.iloc[pos_linha, pos_col]por posição a partir de 0.- Fatias
ilocexcluem o fim; fatias de rótulosloco incluem; um rótulo ausente geraKeyError. df.loc[máscara, "col"]filtra e escolhe; atribua com.locsobre uma.copy()e devolva-a.
A seguir: groupby e agregação, que dividem uma tabela em grupos e resumem cada um.
Lab: o que é avaliado
- Buscar um preço por símbolo com
price_of25 pts - Pegar as linhas entre dois símbolos com
label_range25 pts - Pegar linhas por posição com
position_range25 pts - Corrigir um preço numa cópia com
set_price25 pts