Pandas Merge - Évitez les pièges courants et fusionnez vos DataFrames

Léon Weiss .

18 mai 2026

Le code Python utilise pandas pour charger un fichier CSV dans un DataFrame. Le DataFrame est ensuite profilé automatiquement, montrant des statistiques et des visualisations pour les données.

Fusionner des tables est une opération banale en apparence, mais c’est souvent là que les jeux de données se déforment: doublons inattendus, lignes perdues, clés mal alignées ou colonnes qui se superposent mal. Derrière la requête pandas merge dataframes, on cherche surtout une réponse simple: comment combiner proprement plusieurs DataFrames à partir d’une colonne commune ou d’un index. Je vais aller droit au but avec les bons cas d’usage, des exemples concrets et les pièges qui font perdre du temps.

Les points à retenir avant de fusionner des DataFrames

  • merge() est l’outil principal pour relier deux tables sur une clé commune, comme en SQL.
  • how= change complètement le résultat: inner, left, right, outer et cross ne répondent pas au même besoin.
  • validate= évite les fusions silencieusement fausses en vérifiant la cardinalité des clés.
  • Les valeurs nulles peuvent se matcher entre elles dans pandas, ce qui surprend souvent les débutants.
  • join() devient plus lisible quand l’index porte déjà la clé métier.

Comprendre ce que merge() fait vraiment

Je pars d’une idée simple: une fusion n’ajoute pas “juste” des colonnes, elle met en relation deux ensembles de lignes. Avec merge(), pandas cherche les correspondances sur une ou plusieurs clés et reconstruit un DataFrame résultat selon la logique de jointure choisie. Si les colonnes de gauche et de droite contiennent la même clé, l’index d’origine n’est généralement pas le centre de la décision; c’est la clé de jointure qui pilote tout.

Je préfère d’ailleurs expliciter la clé avec on= plutôt que de laisser pandas deviner la colonne commune: le code est plus lisible et les erreurs d’intention apparaissent plus vite. C’est aussi la bonne manière de documenter, sans commentaire, ce que la fusion est censée relier.

C’est pour cela que cette opération ressemble davantage à une jointure de base de données qu’à une concaténation. Pour un besoin de mise en regard entre commandes et clients, ou entre événements et métadonnées, c’est la bonne brique. Si votre but est seulement d’empiler des lignes, ce n’est pas le bon outil, et je reviens sur ce point plus loin.

En pratique, le bon réflexe consiste à identifier d’abord la relation entre les tables: une ligne de gauche doit-elle trouver zéro, une ou plusieurs lignes à droite ? La réponse dicte le type de jointure et évite les surprises de cardinalité. Une fois cette logique claire, le choix du mode de fusion devient beaucoup plus simple.

Visualisation des données de pandas : deux graphiques superposés montrent l'utilisation horaire des utilisateurs enregistrés et occasionnels, segmentée par saison.

Choisir le bon type de jointure

Le paramètre how change la philosophie de la fusion. C’est lui qui décide si vous gardez seulement les correspondances, si vous conservez toutes les lignes de gauche, ou si vous voulez une vue complète des deux côtés. Quand une fusion donne un résultat “bizarre”, c’est très souvent parce que le mode n’était pas le bon, pas parce que pandas a mal travaillé.

Mode Effet concret Quand je l’utilise
inner Garde uniquement les clés présentes des deux côtés Rapprochement strict, filtrage, nettoyage de données
left Garde toutes les lignes de gauche et complète avec les correspondances à droite Enrichir une table principale sans perdre de lignes
right Symétrique de left Cas plus rare, quand la table de droite est la référence
outer Garde tout des deux côtés Audit, consolidation, comparaison de complétude
cross Produit cartésien de toutes les lignes Générer toutes les combinaisons possibles, jamais sur de gros volumes sans raison solide

Sur les versions récentes de pandas, il existe aussi left_anti et right_anti pour conserver uniquement les clés absentes de l’autre côté. Je les garde pour des contrôles ciblés, pas pour la jointure métier standard.

Avec ce cadre, il devient facile de passer du principe à un cas concret sur des clés métiers.

Fusionner sur une colonne commune sans surprise

Le cas le plus fréquent, c’est une clé simple: client_id, order_id, user_id, sku. Supposons que j’aie une table de commandes et une table de clients. Si je veux enrichir les commandes sans perdre de ligne, je pars généralement sur un left join et j’ajoute validate tout de suite. C’est le moyen le plus rapide de repérer une incohérence de données avant qu’elle ne se propage.

import pandas as pd

commandes = pd.DataFrame({
    "commande_id": [101, 102, 103, 104],
    "client_id": [1, 2, 2, 4],
    "montant": [120, 80, 42, 200],
})

clients = pd.DataFrame({
    "client_id": [1, 2, 3],
    "nom": ["Amina", "Louis", "Camille"],
    "ville": ["Paris", "Lyon", "Nantes"],
})

resultat = commandes.merge(
    clients,
    on="client_id",
    how="left",
    validate="many_to_one",
    indicator=True,
    suffixes=("_commande", "_client"),
)

Dans ce cas, la commande liée au client 4 reste bien présente, mais les colonnes issues de clients seront vides pour cette ligne. La colonne _merge aide à voir immédiatement ce qui a matché (both) et ce qui n’a pas trouvé de correspondance (left_only). Si une clé attendue doit être unique à droite, validate="many_to_one" vous protège contre une table client dupliquée.

Je conseille aussi de nommer explicitement les suffixes dès qu’il existe un risque de collision entre colonnes. Attendre l’erreur finale pour découvrir deux colonnes ville_x et ville_y n’apporte rien de bon. Avec un jeu de données réel, ce petit détail améliore beaucoup la lisibilité. Quand la clé n’est plus une seule colonne, la logique reste la même, mais la syntaxe mérite un peu plus d’attention.

Joindre sur plusieurs colonnes ou sur l’index

Beaucoup de cas métier ne tiennent pas sur une seule clé. Un tarif peut dépendre du pays et de la ville, un événement de la date et de l’utilisateur, un catalogue de plusieurs attributs. Dans ce cas, merge() accepte une liste de colonnes, et je l’utilise quand la combinaison des clés est la vraie identité de la ligne.

ventes = pd.DataFrame({
    "pays": ["FR", "FR", "BE"],
    "ville": ["Paris", "Lyon", "Bruxelles"],
    "ca": [1500, 980, 720],
})

geo = pd.DataFrame({
    "pays": ["FR", "FR", "BE"],
    "ville": ["Paris", "Lyon", "Bruxelles"],
    "population": [2148000, 522000, 191000],
})

resultat = ventes.merge(geo, on=["pays", "ville"], how="inner")

Si les colonnes ne portent pas le même nom des deux côtés, left_on et right_on permettent de relier les tables sans renommer les sources à l’avance.

resultat = ventes.merge(
    tarifs,
    left_on=["pays", "ville"],
    right_on=["country", "city"],
    how="left",
)

Le point important ici, c’est la cohérence stricte des clés: même ordre, même orthographe, même type. Si la colonne pays contient des codes texte d’un côté et des catégories de l’autre, pandas peut refuser la fusion ou produire un résultat trompeur selon le contexte. Je convertis donc les types avant la jointure quand je sais que les sources n’ont pas été normalisées de la même manière.

Quand l’index est déjà la bonne clé

Si vos DataFrames partagent déjà un index métier, join() est souvent plus propre qu’un merge() classique. C’est particulièrement vrai quand plusieurs tables sont alignées sur le même identifiant et que vous voulez ajouter des colonnes sans réécrire la clé à chaque appel.

base = pd.DataFrame(
    {"segment": ["A", "B", "C"]},
    index=[1, 2, 3],
)

score = pd.DataFrame(
    {"score": [0.8, 0.4, 0.9]},
    index=[1, 2, 3],
)

resultat = base.join(score, how="left")

Je retiens une règle simple: si la clé vit dans les colonnes, je commence par merge() ; si la clé vit dans l’index, join() devient souvent plus lisible. Cette distinction évite des reset_index() et set_index() inutiles. Le vrai sujet, ensuite, c’est d’éviter les erreurs silencieuses qui faussent le résultat.

Éviter les pièges qui faussent le résultat

Les fusions ratées sont rarement dues à une seule grosse erreur. Elles viennent plus souvent d’un détail discret: types incompatibles, doublons cachés, valeurs manquantes ou cardinalité mal comprise. C’est là que je passe un peu plus de temps, parce qu’un résultat “plausible” peut être faux sans déclencher d’exception.

Les clés doivent être du même type

1 et "1" ne sont pas la même clé. Si une colonne est stockée en entier et l’autre en chaîne de caractères, la fusion ne matchera pas comme vous l’imaginez. J’aligne donc les types avant l’opération: astype("string"), astype("Int64"), ou une normalisation plus spécifique selon le cas.

Les doublons peuvent multiplier les lignes

Une jointure n’additionne pas seulement des colonnes, elle peut aussi multiplier les lignes. Si une clé apparaît deux fois à gauche et trois fois à droite, vous obtenez six lignes pour cette clé. Ce comportement est correct, mais il faut le vouloir. Pour le contrôler, validate reste mon garde-fou préféré: one_to_one, one_to_many, many_to_one ou many_to_many.

Lire aussi : Shebang Python - Le guide complet pour des scripts fiables

Les valeurs nulles se comportent différemment de SQL

Dans pandas, des valeurs nulles sur les clés peuvent être mises en correspondance entre elles. C’est une différence importante avec beaucoup de jointures SQL et cela surprend encore souvent. Quand je ne veux pas de ce comportement, je filtre explicitement les clés manquantes avant la fusion.

Un autre point simple mais utile: si une partie du résultat vous paraît trop grande, suspectez d’abord une relation plusieurs-à-plusieurs ou un cross involontaire. C’est plus fréquent qu’on ne le pense sur de vrais jeux de données. Une fois ces pièges écartés, le choix de l’outil devient beaucoup plus clair.

Choisir entre merge, join et concat

Je vois souvent ces trois fonctions utilisées comme si elles faisaient la même chose. En réalité, chacune répond à un problème différent. Les confondre rallonge le code et rend les bugs plus difficiles à lire.

Fonction Ce qu’elle fait Quand je la choisis
merge() Joint sur des colonnes ou des index avec une logique SQL Quand j’ai une vraie clé commune et besoin de flexibilité
join() Aligne surtout sur l’index, avec une syntaxe concise Quand l’index porte déjà l’identifiant métier ou quand j’enchaîne plusieurs tables indexées
concat() Empile des objets le long des lignes ou des colonnes Quand je n’ai pas de relation de jointure et que je veux simplement assembler des blocs homogènes

La règle pratique que j’applique est simple: si je dois “retrouver” des lignes d’une table dans une autre, je pense merge() ; si je veux seulement assembler des morceaux compatibles, je pense concat(). Quand les données sont déjà indexées proprement, join() m’évite un peu de bruit syntaxique. Cette décision paraît mineure, mais elle fait gagner du temps sur tous les scripts un peu sérieux.

Le contrôle final que je fais avant d’exécuter une fusion

Avant de lancer une jointure sur des données réelles, je vérifie toujours la même liste. Ce réflexe prend moins d’une minute et évite des heures de débogage quand la table grossit ou quand une source amont change discrètement.

  • La clé a-t-elle exactement le même type des deux côtés ?
  • La relation attendue est-elle 1:1, 1:m ou m:1 ?
  • Ai-je besoin de conserver toutes les lignes de gauche ou seulement les correspondances ?
  • Une colonne de contrôle comme _merge m’aiderait-elle à repérer les absences ?
  • Les colonnes qui se chevauchent ont-elles des suffixes explicites ?
  • L’index est-il déjà la bonne clé, auquel cas join() serait plus lisible ?

Quand je veux aller vite sans sacrifier la fiabilité, je commence par une fusion simple, j’ajoute validate, puis je regarde le résultat avec un échantillon et une vérification de cardinalité. C’est souvent suffisant pour transformer une jointure fragile en étape de préparation de données robuste, et c’est exactement ce qu’on attend d’un pipeline Python propre.

Questions fréquentes

`merge()` joint sur des clés (colonnes/index) avec une logique SQL. `join()` aligne principalement sur l'index. `concat()` empile des DataFrames (lignes ou colonnes) sans relation de jointure, pour assembler des blocs homogènes.
Utilisez `validate` pour vérifier la cardinalité des clés (ex: "one_to_one", "many_to_one"). Cela prévient les fusions incorrectes dues à des doublons inattendus ou des relations de données mal comprises, évitant ainsi des résultats faussés.
Les clés doivent avoir le même type. Si une est numérique et l'autre textuelle, la fusion échouera. Convertissez-les explicitement (ex: `df['col'].astype('string')` ou `astype('Int64')`) avant l'opération pour assurer la correspondance.
Une multiplication excessive de lignes est souvent due à des doublons dans vos clés de jointure ou à une relation "many-to-many" inattendue. Vérifiez la cardinalité de vos clés et utilisez `validate` pour identifier ces problèmes avant la fusion.
Oui, dans pandas, les valeurs nulles sur les clés peuvent correspondre entre elles, contrairement à SQL. Si vous ne souhaitez pas ce comportement, filtrez explicitement les clés manquantes avant la fusion pour éviter des correspondances indésirables.
Évaluer l'article

Moyenne: 0.0 / 5 · 0 évaluations

Tags

pandas merge dataframes joindre deux dataframes pandas fusionner dataframes python pandas merge left join pandas merge inner join pandas concat vs merge
Autor Léon Weiss
Léon Weiss
Je m'appelle Léon Weiss et je suis développeur web avec trois ans d'expérience dans le domaine. Mon parcours a commencé par une curiosité insatiable pour la programmation et la création de solutions numériques. Je me suis rapidement spécialisé dans des technologies telles que JavaScript, le développement backend, et les bases de données NoSQL, tout en accordant une attention particulière à la sécurité des applications. J'apprécie particulièrement expliquer des concepts complexes de manière accessible, ce qui me permet d'aider les lecteurs à surmonter les défis qu'ils rencontrent dans leur apprentissage. Je m'efforce de fournir des informations utiles, précises et à jour, en vérifiant mes sources et en suivant les tendances du secteur. Mon objectif est de rendre le développement web plus compréhensible et d'accompagner chacun dans son parcours, qu'il soit débutant ou développeur confirmé.
Commentaires (0)
Ajouter un commentaire