Comment les dtypes déterminent-ils la mémoire d’un DataFrame ?

Questions d’entrevue Python et Pandas

Intermédiairepandas

Le réflexe

Avant d’optimiser un groupby, vous affichez ce que le tableau coûte vraiment :

python
df.dtypes
df.memory_usage(deep=True).sort_values(ascending=False)

Sans deep=True, Pandas compte les pointeurs des colonnes object, pas les chaînes Python derrière. Le rapport « 80 Mo » peut cacher 2 Go.

Ce qui coûte

object sur du texte. Chaque cellule est un PyObject. Huit octets de pointeur, plus la chaîne, plus l’overhead de l’allocateur. Mille codes pays distincts répétés sur dix millions de lignes : vous payez dix millions de chaînes.

float64 pour des entiers troués. Une seule valeur manquante force souvent l’inférence CSV vers float64 : 8 octets, plus des 12.0 qui n’étaient pas des décimales. Le dtype nullable Int64 (majuscule) garde l’entier et le NA sans passer par le flottant — plus correct, pas toujours plus petit.

int64 / float64 par défaut. Un identifiant sur 0–50 000 tient en uint32 ou int32. Un indicateur 0/1 tient en int8 ou boolean. Le downcast n’est pas de la micro-optimisation : sur cinquante colonnes, il décide si le job tient en RAM.

Les timestamps. datetime64[ns] est compact et vectorisé. Une date laissée en object est le pire des deux mondes : lente, et volumineuse.

Ce que vous faites, dans l’ordre

  1. Déclarer les types à la lecture, surtout en CSV. L’inférence parcourt les données, se trompe, et fige un object.
  2. Passer en category une colonne dont la cardinalité est basse devant le nombre de lignes — pays, canal, statut. La mémoire devient un entier de code plus la table des modalités.
  3. astype("string") (nullable) plutôt que object pour du texte vraiment distinct : plus sûr sur les NA, pas forcément plus léger.
  4. Mesurer encore après transformation. Un get_dummies mal placé peut détruire le gain du category.
python
df = pd.read_csv(
    "ventes.csv",
    usecols=["date", "pays", "montant"],
    dtype={"pays": "category", "montant": "float32"},
    parse_dates=["date"],
)

Le tutoriel nettoyer des données sales commence par dtype="string" justement pour empêcher un code postal de devenir float.

La phrase qui clôt

La mémoire d’un DataFrame n’est pas « le nombre de lignes × une constante ». C’est la somme des représentations. Tant que les dtypes sont faux, toute discussion de performance est prématurée.

Toutes les questions Python et Pandas