Des tableaux qui partagent une clé
Les données réelles arrivent rarement dans un seul tableau. Vos positions sont dans l'un, le secteur de chaque symbole dans un autre, les prix dans un troisième. Ce qui les relie est une clé, ici le symbole. left.merge(right, on="clé") trouve, pour chaque ligne de left, les lignes de right ayant la même clé et les met côte à côte. C'est la même idée qu'une jointure en SQL.
import pandas as pd
positions = pd.DataFrame({"symbol": ["AAPL", "MSFT", "TSLA", "GOOG"], "qty": [100, 50, 20, 10]})
reference = pd.DataFrame({"symbol": ["AAPL", "MSFT", "GOOG", "F"], "sector": ["tech", "tech", "tech", "auto"]})
merged = positions.merge(reference, on="symbol")
print(merged)
# symbol qty sector
# 0 AAPL 100 tech
# 1 MSFT 50 tech
# 2 GOOG 10 techinner, left, right et outer
TSLA a disparu du résultat ci-dessus, et F aussi. Le choix par défaut, how="inner", ne garde que les clés présentes dans les deux tableaux. Dites ce que vous voulez : how="left" garde toutes les lignes du tableau de gauche et complète les valeurs manquantes de droite par NaN, how="right" fait l'inverse, et how="outer" garde les clés des deux. Pour enrichir un tableau, on veut presque toujours left, car il ne perd jamais une ligne en silence.
# how="left" keeps every position; TSLA has no sector, so it gets NaN
left = positions.merge(reference, on="symbol", how="left")
print(left)
# symbol qty sector
# 0 AAPL 100 tech
# 1 MSFT 50 tech
# 2 TSLA 20 NaN
# 3 GOOG 10 tech
# how="outer" keeps the keys of both tables (sorted); quantities become floats because of the NaN
print(positions.merge(reference, on="symbol", how="outer"))
# symbol qty sector
# 0 AAPL 100.0 tech
# 1 F NaN auto
# 2 GOOG 10.0 tech
# 3 MSFT 50.0 tech
# 4 TSLA 20.0 NaNTrouver ce qui ne correspond pas
Un NaN silencieux peut cacher un problème de données, alors vérifiez-le. indicator=True ajoute une colonne _merge qui indique, pour chaque ligne, si la clé a été trouvée dans left_only, right_only ou both. La filtrer répond à des questions comme « quelles positions n'ont pas de prix ? ». Les clés en double sont l'autre piège : si une clé apparaît deux fois à droite, chaque ligne correspondante de gauche est répétée. Passez validate="many_to_one" (ou "one_to_one") et pandas lève une erreur au lieu de changer discrètement le nombre de lignes.
# Which positions have no sector?
check = positions.merge(reference, on="symbol", how="left", indicator=True)
print(check)
# symbol qty sector _merge
# 0 AAPL 100 tech both
# 1 MSFT 50 tech both
# 2 TSLA 20 NaN left_only
# 3 GOOG 10 tech both
print(check.loc[check["_merge"] == "left_only", "symbol"].tolist()) # ['TSLA']# Duplicate keys repeat rows: AAPL has two quotes, so the AAPL position appears twice
quotes = pd.DataFrame({"symbol": ["AAPL", "AAPL", "MSFT"], "price": [184.25, 184.5, 410.1]})
print(len(positions.merge(quotes, on="symbol"))) # 3
# validate turns the surprise into an error
try:
positions.merge(quotes, on="symbol", validate="one_to_one")
except Exception as error:
print(type(error).__name__) # MergeErrorClés de noms différents et colonnes en conflit
Quand la clé porte des noms différents dans les deux tableaux, utilisez left_on="symbol", right_on="ticker" ; les deux colonnes sont conservées. Quand les deux tableaux ont une colonne de même nom qui n'est pas la clé (ici qty), pandas garde les deux et ajoute les suffixes _x et _y. Choisissez-en de plus clairs avec suffixes=("_a", "_b"). Après une jointure externe, les quantités manquantes sont NaN et la colonne est de type flottant : utilisez fillna(0) puis astype("int64") pour retrouver des entiers.
# Different key names: both columns are kept
book_a = pd.DataFrame({"symbol": ["AAPL", "MSFT"], "qty": [100, 50]})
book_b = pd.DataFrame({"ticker": ["MSFT", "TSLA"], "qty": [-20, 30]})
print(book_a.merge(book_b, left_on="symbol", right_on="ticker", how="outer", suffixes=("_a", "_b")))
# symbol qty_a ticker qty_b
# 0 AAPL 100.0 NaN NaN
# 1 MSFT 50.0 MSFT -20.0
# 2 NaN NaN TSLA 30.0
# Same key name, outer join, suffixes, then back to whole numbers
both = book_a.merge(book_b.rename(columns={"ticker": "symbol"}), on="symbol", how="outer", suffixes=("_a", "_b"))
both[["qty_a", "qty_b"]] = both[["qty_a", "qty_b"]].fillna(0).astype("int64")
print(both)
# symbol qty_a qty_b
# 0 AAPL 100 0
# 1 MSFT 50 -20
# 2 TSLA 0 30len() avant et après, utilisez how="left" pour garder toutes les lignes, et ajoutez validate= quand vous croyez les clés uniques.left.merge(right, on="clé")fait correspondre les lignes de deux tableaux qui partagent une clé ;left_on/right_ongèrent des noms différents.how="inner"(défaut) garde les clés des deux,"left"garde toutes les lignes de gauche,"outer"garde toutes les clés.indicator=Truemontre ce qui ne correspond pas ;validate=etsuffixes=protègent des clés en double et des noms en conflit.
À suivre : les rendements simples, qui transforment une série de prix en variation en pourcentage d'une période à l'autre.
Lab : ce qui est noté
- Ajouter le secteur de chaque transaction avec
attach_sector25 pts - Valoriser les positions qui ont un prix avec
value_positions25 pts - Trouver les positions sans prix avec
unpriced_symbols25 pts - Réunir deux livres en un seul tableau avec
combine_books25 pts