2025, Oct 20 08:30

pandas में दो CSV फ़ाइलों का साफ़ left join: अनमिल पंक्तियाँ रखें, N/A भरें

जानें कैसे pandas में दो CSV को सुरक्षित रूप से जोड़ें: left join के साथ सभी shipments रखें, merge के बाद fillna से N/A भरें। स्पष्ट उदाहरण और सर्वोत्तम प्रथाएँ।

pandas में दो CSV फ़ाइलों को मिलाएँ, बिना अनमिल पंक्तियाँ खोए: N/A भराव के साथ साफ़-सुथरा left join

जब आप एक डेटासेट को दूसरे के गुणों से समृद्ध करते हैं, pandas की एक छोटी-सी डिफ़ॉल्ट सेटिंग चुपचाप उन पंक्तियों को हटा सकती है जिन्हें आप रखना चाहते थे। लक्ष्य बिलकुल स्पष्ट है: shipment रिकॉर्ड्स को product metadata से product_code पर जोड़ना, प्रोडक्ट गायब होने पर भी सभी shipments को बनाए रखना, और अनुपस्थित विवरणों को N/A से भरना।

समस्या की रूपरेखा

दो साधारण सारणीबद्ध इनपुट इस स्थिति को समझाते हैं। एक में shipments हैं, दूसरे में product के विवरण और category। अपेक्षित आउटपुट हर shipment को सुरक्षित रखता है और जहाँ मेल मिले, वहाँ description/category जोड़ देता है।

shipment_id,product_code,quantity,date
S001,P123,10,2025-07-01
S002,P456,5,2025-07-02
S003,P789,8,2025-07-03
product_code,description,category
P123,Widget A,Tools
P456,Widget B,Hardware

अपेक्षित परिणाम:

shipment_id,product_code,quantity,date,description,category
S001,P123,10,2025-07-01,Widget A,Tools
S002,P456,5,2025-07-02,Widget B,Hardware
S003,P789,8,2025-07-03,N/A,N/A

जो जोखिम अक्सर छिपा रह जाता है: एक न्यूनतम उदाहरण

डिफ़ॉल्ट merge का उपयोग करने पर अनमिल shipment P789 हट जाता है, जबकि इस परिदृश्य में आपको उसे रखना था।

import pandas as pd
ship_data = [
    ["S001", "P123", 10, "2025-07-01"],
    ["S002", "P456", 5, "2025-07-02"],
    ["S003", "P789", 8, "2025-07-03"]
]
cols_ship = ["shipment_id", "product_code", "quantity", "date"]
frame_ship = pd.DataFrame(ship_data, columns=cols_ship)
item_data = [
    ["P123", "Widget A", "Tools"],
    ["P456", "Widget B", "Hardware"]
]
cols_item = ["product_code", "description", "category"]
frame_item = pd.DataFrame(item_data, columns=cols_item)
# डिफ़ॉल्ट मर्ज: जिन पंक्तियों का मिलान नहीं होता, वे हट जाती हैं
inner_joined = pd.merge(frame_ship, frame_item)
print(inner_joined)

असल में हो क्या रहा है

pandas.merge का डिफ़ॉल्ट व्यवहार उन पंक्तियों को हटा देता है जिन्हें दूसरे DataFrame में जोड़ी नहीं मिलती। यानी, जब तक आप अलग से नहीं कहते, अनमिल पंक्तियाँ शामिल नहीं की जातीं। left join चुनते ही pandas बाएँ DataFrame की हर पंक्ति को रखता है; दाएँ तरफ़ मेल न मिलने पर नई कॉलमों में NaN भरता है। इसके बाद आप उन NaN मानों को N/A से बदल सकते हैं ताकि आउटपुट अपेक्षित प्रारूप में आ जाए।

एक बारीकी और ध्यान देने योग्य है: अगर दोनों DataFrame में कई कॉलम एक ही नाम से मौजूद हों, तो pandas सभी समान नाम वाले कॉलमों पर मेल कराने की कोशिश कर सकता है। किसी ख़ास key तक सीमित रहने के लिए left_on और right_on के जरिए उसे स्पष्ट रूप से बताना बेहतर है।

समाधान: left join + fillna

उपाय सीधा है: product_code पर left merge करें, फिर गुम मानों को N/A से भरें।

import pandas as pd
ship_data = [
    ["S001", "P123", 10, "2025-07-01"],
    ["S002", "P456", 5, "2025-07-02"],
    ["S003", "P789", 8, "2025-07-03"]
]
cols_ship = ["shipment_id", "product_code", "quantity", "date"]
frame_ship = pd.DataFrame(ship_data, columns=cols_ship)
item_data = [
    ["P123", "Widget A", "Tools"],
    ["P456", "Widget B", "Hardware"]
]
cols_item = ["product_code", "description", "category"]
frame_item = pd.DataFrame(item_data, columns=cols_item)
# सही: सभी शिपमेंट रखें और बिना मिलान वाले मान भरें
result_all_cols = (
    pd.merge(frame_ship, frame_item, how="left")
      .fillna("N/A")
)
print(result_all_cols)

अगर आपको product तालिका से सिर्फ़ category चाहिए, तो कॉलम के उपसमूह के साथ merge करें। यह बेहतर हो सकता है क्योंकि इससे frame_item का मूल DataFrame बदले बिना काम हो जाता है।

result_category_only = (
    pd.merge(frame_ship, frame_item[["product_code", "category"]], how="left")
      .fillna("N/A")
)
print(result_category_only)

यदि आपके DataFrame में एक जैसे नाम के कई कॉलम हैं और आपको किसी विशेष कॉलम पर merge करना है, तो उसे स्पष्ट रूप से बताइए।

result_explicit_key = (
    pd.merge(
        frame_ship,
        frame_item,
        how="left",
        left_on="product_code",
        right_on="product_code"
    ).fillna("N/A")
)

यह क्यों मायने रखता है

डेटा समृद्धि का उद्देश्य जोड़ना होता है, घटाना नहीं। सिर्फ इसलिए shipments का हट जाना कि संबंधित product नहीं मिला, मकसद को बिगाड़ देता है और आगे की रिपोर्टिंग को तिरछा कर सकता है। left join पूरे shipment डेटा को सुरक्षित रखता है और कमी को N/A के रूप में स्पष्ट करता है, जिससे पारदर्शिता और ऑडिट दोनों आसान होते हैं।

समापन

जब एक तालिका के रिकॉर्ड्स को दूसरी के गुणों से बढ़ाएँ, तो हर स्रोत पंक्ति को सुरक्षित रखने के लिए left merge अपनाएँ और तुरंत fillna("N/A") के साथ गुम मानों को मानकीकृत करें। यदि दोनों तरफ़ समान नाम वाले कई कॉलम हैं, तो left_on और right_on से join key तय कर दें। और अगर दाएँ तालिका से सिर्फ़ कुछ कॉलम चाहिए, तो उसी उपसमूह पर merge करें ताकि आउटपुट सुथरा रहे।

यह लेख StackOverflow पर एक प्रश्न (लेखक: user21677098) और Ranger के उत्तर पर आधारित है।