Un tableau de colonnes étiquetées
Un DataFrame est un tableau à deux dimensions : un ensemble de colonnes, chacune une Series, qui partagent un même index d'étiquettes de lignes. C'est le cheval de trait de l'analyse de données de marché : une ligne par symbole ou par jour, une colonne par champ (prix, volume, rendement). On en construit un à partir d'un dictionnaire de colonnes, pd.DataFrame({"price": [...], "volume": [...]}, index=symbols), ou d'une liste de dictionnaires de lignes. Chaque colonne a son propre dtype (les prix sont float64, les volumes int64), contrairement à un tableau NumPy qui a un seul dtype pour tout.
import pandas as pd
df = pd.DataFrame(
{"price": [184.25, 410.2, 171.0], "volume": [200, 50, 300]},
index=["AAPL", "MSFT", "GOOG"],
)
print(df)
# price volume
# AAPL 184.25 200
# MSFT 410.20 50
# GOOG 171.00 300
print(df.shape, df.columns.tolist()) # (3, 2) ['price', 'volume']
print(df.dtypes.astype(str).to_dict()) # {'price': 'float64', 'volume': 'int64'}
rows = [{"symbol": "AAPL", "price": 184.25}, {"symbol": "MSFT", "price": 410.2}]
print(pd.DataFrame(rows)) # from a list of row dictionaries
# symbol price
# 0 AAPL 184.25
# 1 MSFT 410.20Colonnes, nouvelles colonnes et lignes filtrées
df["price"] est une colonne, une Series ; df[["price"]] avec une liste est un DataFrame d'une colonne. Une nouvelle colonne vient d'une arithmétique sur les colonnes : df.assign(notional=df["price"] * df["volume"]) renvoie un nouveau tableau avec la colonne en plus et laisse df intact (écrire df["notional"] = ... modifie df lui-même). Une condition booléenne sur une colonne filtre les lignes, df[df["volume"] >= 100], et df.sort_values("volume", ascending=False) les ordonne, .head(n) gardant les n premières. Tout cela opère sur des colonnes entières d'un coup : ne bouclez jamais sur les lignes avec iterrows() quand une opération de colonne existe.
import pandas as pd
df = pd.DataFrame(
{"price": [184.25, 410.2, 171.0], "volume": [200, 50, 300]},
index=["AAPL", "MSFT", "GOOG"],
)
bigger = df.assign(notional=df["price"] * df["volume"]) # a new frame
print(bigger)
# price volume notional
# AAPL 184.25 200 36850.0
# MSFT 410.20 50 20510.0
# GOOG 171.00 300 51300.0
print(df.columns.tolist()) # ['price', 'volume'] df is unchanged
print(df[df["volume"] >= 100]) # rows that pass the test
# price volume
# AAPL 184.25 200
# GOOG 171.00 300
print(df.sort_values("volume", ascending=False).head(2)) # the two biggest volumes
# price volume
# GOOG 171.00 300
# AAPL 184.25 200Résumés et coup d'œil sur les données
Regardez toujours un tableau avant de lui faire confiance. df.head() montre les premières lignes, df.shape donne (lignes, colonnes), df.dtypes liste le type de chaque colonne, df.isna().sum() compte les valeurs manquantes par colonne et df.describe() résume les colonnes numériques (effectif, moyenne, écart type, minimum, quartiles, maximum). Les méthodes de colonne comme df.mean() donnent une valeur par colonne ; df.sum(axis=1) en donne une par ligne. Un dtype object ou str là où l'on attendait des nombres signifie en général que du texte s'est glissé dans la colonne.
import pandas as pd
df = pd.DataFrame(
{"price": [184.25, 410.2, 171.0], "volume": [200, 50, 300]},
index=["AAPL", "MSFT", "GOOG"],
)
print(df.describe().loc[["count", "mean", "max"]])
# price volume
# count 3.00 3.000000
# mean 255.15 183.333333
# max 410.20 300.000000
print(df.mean().to_dict()) # {'price': 255.15, 'volume': 183.33333333333334}
print(df.sum(axis=1).tolist()) # [384.25, 460.2, 471.0] one value per row
print(df.isna().sum().to_dict()) # {'price': 0, 'volume': 0}
# Changing a copy never changes the original (pandas 3 copies on write)
cheap = df[df["price"] < 200].copy()
cheap.loc["AAPL", "price"] = 0.0
print(df.loc["AAPL", "price"]) # 184.25import pandas as pd
rows = [
{"symbol": "AAPL", "price": 184.25, "volume": 200},
{"symbol": "MSFT", "price": 410.2, "volume": 50},
]
df = pd.DataFrame(rows).set_index("symbol") # make a column the row labels
print(df)
# price volume
# symbol
# AAPL 184.25 200
# MSFT 410.20 50
print(df.rename(columns={"price": "px"}).columns.tolist()) # ['px', 'volume']
print(df.drop(columns="volume").columns.tolist()) # ['price']
print(df.reset_index().columns.tolist()) # ['symbol', 'price', 'volume']assign, le filtrage booléen et sort_values, qui renvoient tous de nouveaux tableaux. Le bogue classique consiste à écrire une nouvelle colonne dans l'argument, ce qui l'ajoute silencieusement au tableau de l'appelant. Les tests du lab comparent l'argument avant et après précisément pour cela.pd.DataFrame({colonne: valeurs}, index=labels);df["c"]est une Series,df[["c"]]un DataFrame ; chaque colonne a son dtype.assignajoute une colonne à un nouveau tableau ;df[masque]filtre les lignes ;sort_values(...).head(n)prend les n premiers.- Regardez d'abord :
shape,dtypes,head(),describe(),isna().sum(); ne modifiez jamais le tableau de l'appelant.
À suivre : sélectionner des données avec loc et iloc, les deux façons précises de choisir lignes et colonnes par étiquette ou par position.
Lab : ce qui est noté
- Construire un tableau de prix et de volumes avec
make_frame25 pts - Ajouter une colonne de valeur échangée avec
add_notional25 pts - Ne garder que les lignes liquides avec
filter_liquid25 pts - Classer les lignes selon une colonne avec
top_by25 pts