अध्याय 10

DataFrames को जोड़ना — concat से ऊपर-नीचे जोड़ना, merge से मिलाना

अलग-अलग टेबल्स को एक साथ लाना: concat से एक ही तरह के महीनों का डेटा ऊपर-नीचे जोड़ना, और merge से दूसरी टेबल से जानकारी मिलाना — सही तरह का merge चुनना, कौन सी पंक्तियाँ मेल नहीं खातीं यह देखना, और डुप्लिकेट की (duplicate key) से अनजाने में पंक्तियाँ बढ़ने से रोकना।

50 मिनटPython 3.12
  1. 1समस्या
  2. 2समझें
  3. 3उदाहरण
  4. 4अनुमान
  5. 5स्वयं करें
  6. 6चुनौती

वह समस्या जिसे हम हल कर रहे हैं

दुकान का डेटा कभी भी एक ही फ़ाइल में नहीं रहता। कभी भी नहीं।

मार्च के ऑर्डर्स orders.csv में हैं, वही टेबल जिसे आप अध्याय चार से इस्तेमाल करते आ रहे हैं। अप्रैल के ऑर्डर्स इस हफ़्ते एक अलग एक्सपोर्ट orders_april.csv के रूप में आए हैं। प्रत्येक उत्पाद पर दुकान की क्या लागत (cost) आती है — और कौन सा आपूर्तिकर्ता (supplier) उसे बेचता है — यह जानकारी क्रय टीम (purchasing team) अपनी फ़ाइल products.csv में रखती है। ऑर्डर्स की फ़ाइल में किसी ने लागत नहीं रखी, क्योंकि लागत किसी उत्पाद का तथ्य है, किसी ऑर्डर का नहीं।

अब दुकान का मालिक एक सवाल पूछता है: मार्च और अप्रैल मिलाकर प्रत्येक सप्लायर ने कुल कितना लाभ (profit) कमा कर दिया?

कोई भी एक फ़ाइल इसका उत्तर नहीं दे सकती। लाभ की गणना के लिए मात्रा और बिक्री मूल्य (ऑर्डर्स में), लागत (उत्पाद फ़ाइल में), और सप्लायर (वह भी उत्पाद फ़ाइल में) की आवश्यकता होती है। और ऑर्डर्स तो दो महीनों में बँटे हुए हैं।

स्प्रेडशीट में आप मार्च की पंक्तियों के नीचे अप्रैल की पंक्तियाँ कॉपी-पेस्ट करेंगे, फिर प्रत्येक पंक्ति की लागत खींचने के लिए एक नए कॉलम में VLOOKUP लिखेंगे, उसे नीचे तक ड्रैग करेंगे, और उम्मीद करेंगे कि सब ठीक रहे। पांडास यही दो काम मात्र दो लाइनों में कर देता है:

  • stack करना: एक ही प्रकार की पंक्तियाँ रखने वाली टेबल्स को — जैसे मार्च और अप्रैल — एक लंबी टेबल में ऊपर-नीचे जोड़ना: pd.concat
  • match करना: एक साझे कॉलम के आधार पर एक टेबल की प्रत्येक पंक्ति का दूसरी टेबल की सही पंक्ति से मिलान करना — प्रत्येक ऑर्डर को उसके उत्पाद से जोड़ना — और दूसरी टेबल के कॉलम साथ लाना: pd.merge

कोड की ये पंक्तियाँ बहुत छोटी हैं। लेकिन यह अध्याय इसलिए महत्वपूर्ण है क्योंकि बिना किसी एरर के यहाँ बड़ी ग़लतियाँ हो सकती हैं: एक merge चुपचाप उन ऑर्डर्स को हटा (drop) सकता है जिनका उत्पाद लुकअप टेबल में नहीं है, या जब लुकअप टेबल में कोई उत्पाद दो बार सूचीबद्ध हो तो ऑर्डर्स को चुपचाप दोगुना या कई गुना (duplicate) कर सकता है। दोनों ही स्थितियाँ ऐसा कुल योग देती हैं जो देखने में बिल्कुल सही लगता है लेकिन वास्तव में गलत होता है। इसलिए इस अध्याय का अधिकांश भाग merge से पहले और बाद में यह जानने के बारे में है कि आपके पास ठीक कितनी पंक्तियाँ होनी चाहिए — और उसकी जांच कैसे करें।

इस अध्याय के अंत में आप कर पाएंगे

  • दो ऑपरेशनों में अंतर समझना: पंक्तियों को ऊपर-नीचे जोड़ना (concat) और किसी 'की' पर मिलान करना (merge)
  • pd.concat से टेबल्स को जोड़ना, ignore_index=True से दोहराए गए इंडेक्स को ठीक करना, और बेमेल कॉलम होने पर क्या होता है यह देखना
  • pd.merge से किसी 'की' पर दो टेबल्स को जोड़ना, और ज़रूरत के अनुसार how="inner", "left", "right" या "outer" का सोच-समझकर चयन करना
  • indicator=True से merge का ऑडिट करना और validate="many_to_one" से उसे सुरक्षित करना
  • डुप्लिकेट कीज़ से होने वाले रो विस्फोट (row explosion) को पहचानना और ठीक करना
  • अलग-अलग नामों वाली कीज़ पर left_on/right_on से merge करना, और टकराने वाले कॉलम नामों को suffixes से संभालना
  • merge की सामान्य त्रुटियों को पहचानना — की-टाइप का बेमेल होना, की-कॉलम का गायब होना — और उन अदृश्य गलतियों को पकड़ना जो कोई एरर नहीं देतीं

ज़रूरी शर्तें: कॉलम जोड़ना।


पहले फ़ाइलें बना लें

इस अध्याय में चार छोटी फ़ाइलों का उपयोग किया गया है। इन्हें अपनी स्क्रिप्ट के पास ही रखें।

orders.csv — मार्च, पिछले अध्यायों वाली वही फ़ाइल:

text
order_id,date,branch,product,category,quantity,price
1001,2024-03-01,north,pen,stationery,12,15.0
1002,2024-03-01,south,notebook,stationery,5,60.0
1003,2024-03-02,north,bag,accessories,2,850.0
1004,2024-03-02,east,bottle,accessories,7,120.0
1005,2024-03-03,north,eraser,stationery,30,8.0
1006,2024-03-03,south,bag,accessories,1,850.0
1007,2024-03-04,east,pen,stationery,20,15.0
1008,2024-03-04,north,bottle,accessories,4,120.0

orders_april.csv — अप्रैल, वही कॉलम। स्टेपलर (stapler) पर ध्यान दें: दुकान ने इसे अप्रैल में बेचना शुरू किया।

text
order_id,date,branch,product,category,quantity,price
1009,2024-04-01,north,pen,stationery,15,15.0
1010,2024-04-01,east,notebook,stationery,3,60.0
1011,2024-04-02,south,stapler,stationery,6,95.0
1012,2024-04-02,north,bag,accessories,1,850.0

products.csv — प्रति उत्पाद एक पंक्ति, क्रय टीम द्वारा रखी गई। वास्तविक जीवन की तरह यहाँ भी जानबूझकर दो चीजें "अधूरी" हैं: नया स्टेपलर अभी इसमें नहीं जोड़ा गया है, और एक मार्कर (marker) ऐसा है जिसे दुकान ने कभी नहीं बेचा।

text
product,cost,supplier
pen,9.0,Alpha
notebook,40.0,Alpha
bag,600.0,Bravo
bottle,80.0,Bravo
eraser,5.0,Alpha
marker,25.0,Alpha

branches.csv — दुकान की तीनों शाखाओं का प्रबंधन कौन करता है। इस कॉलम का नाम branch नहीं बल्कि branch_name है, क्योंकि यह फ़ाइल किसी अन्य व्यक्ति ने बनाई थी।

text
branch_name,manager
north,Mira
south,Omar
east,Lena

कोड लिखने से पहले

टेबल्स को जोड़ना वह चरण है जहाँ जल्दबाज़ी में लिखा कोड अक्सर सबसे ज़्यादा आत्मविश्वास से भरा गलत उत्तर देता है। इसलिए योजना पहले बनती है, और इसमें ज़्यादातर वे सवाल होते हैं जिनका जवाब आप डेटा देखकर तय करते हैं।

1. सवाल को एक वाक्य में कहें

"मार्च और अप्रैल मिलाकर सप्लायर प्रति लाभ।" यह एक वाक्य ही अंतिम टेबल का स्वरूप बता देता है: प्रति सप्लायर एक पंक्ति, प्रति पंक्ति एक संख्या। दो सप्लायर हैं, Alpha और Bravo, इसलिए परिणाम में लगभग दो पंक्तियाँ होनी चाहिए। यदि तीन या एक पंक्ति बनती है, तो रास्ते में कुछ गड़बड़ हुई है।

2. तय करें कि प्रत्येक टेबल-जोड़ी को किस ऑपरेशन की ज़रूरत है

जोड़ने के केवल दो मुख्य प्रकार हैं, और परीक्षण बहुत सरल है: क्या दोनों टेबल्स में एक ही प्रकार की पंक्तियाँ हैं, या एक ही चीज़ के अलग-अलग विवरण हैं?

  • समान कॉलम, अलग पंक्तियाँ — मार्च ऑर्डर्स + अप्रैल ऑर्डर्स। pd.concat([a, b]) का उपयोग करें। परिणाम नीचे की ओर बढ़ता है: अधिक पंक्तियाँ, वही कॉलम।
  • एक साझा 'की' (key) कॉलम, अलग विवरण — ऑर्डर्स + उत्पाद, जो product से जुड़े हैं। pd.merge(a, b, on="product") का उपयोग करें। परिणाम दाएं की ओर बढ़ता है: पंक्तियों की वही संख्या, अधिक कॉलम।

मार्च और अप्रैल दोनों "ऑर्डर्स" हैं — वही कॉलम, अधिक पंक्तियाँ — इसलिए उन्हें ऊपर-नीचे जोड़ा जाता है (stack)। ऑर्डर्स और उत्पाद अलग-अलग चीज़ें हैं जो उत्पाद के नाम से जुड़ी हैं, इसलिए उनका मिलान किया जाता है (match)।

3. जोड़ने से पहले हर टेबल को देखें

आपने अध्याय तीन में सीखा था कि फ़ाइल पढ़ते ही उसकी जांच कर लेनी चाहिए। कई फ़ाइलों के साथ यह आदत अनिवार्य हो जाती है: परिणाम के आकार का अनुमान लगाने के लिए आपको हर एक टेबल के आकार (shape) की जानकारी चाहिए।

python
import pandas as pd

march = pd.read_csv("orders.csv")
april = pd.read_csv("orders_april.csv")
products = pd.read_csv("products.csv")

for name, df in [("march", march), ("april", april), ("products", products)]:
    print(name, df.shape, list(df.columns))
text
march (8, 7) ['order_id', 'date', 'branch', 'product', 'category', 'quantity', 'price']
april (4, 7) ['order_id', 'date', 'branch', 'product', 'category', 'quantity', 'price']
products (6, 3) ['product', 'cost', 'supplier']

मार्च और अप्रैल दोनों में बिल्कुल वही सात कॉलम उसी क्रम में हैं — ऊपर-नीचे जोड़ने के लिए बिल्कुल उपयुक्त। products उनके साथ ठीक एक कॉलम नाम साझा करता है: product। यही वह की (key) है, जिस कॉलम के आधार पर मिलान किया जाएगा।

जांचें कि 'की' का प्रकार (dtype) दोनों तरफ समान है या नहीं। एक ऐसी 'की' जो एक टेबल में संख्या हो और दूसरी में टेक्स्ट, कभी मेल नहीं खा सकती:

python
print(march["product"].dtype, products["product"].dtype)
text
str str

दोनों str हैं। इनकी तुलना की जा सकती है।

4. जांचें कि लुकअप टेबल की 'की' (key) यूनिक (unique) है

यह इस पूरे अध्याय की सबसे महत्वपूर्ण जांच है। प्रत्येक ऑर्डर के लिए एक लागत की आवश्यकता है। यदि products.csv में pen दो बार सूचीबद्ध है, तो पेन का प्रत्येक ऑर्डर दो बार मेल खाएगा और परिणाम में दो बार दिखाई देगा।

python
print(products["product"].is_unique)
print(products["product"].duplicated().sum())
text
True
0

is_unique का मान True है और शून्य डुप्लिकेट हैं: प्रति उत्पाद एक पंक्ति। प्रत्येक ऑर्डर अधिकतम एक उत्पाद पंक्ति से मेल खा सकता है।

5. जांचें कि किन 'कीज़' (keys) का कोई साथी नहीं मिलेगा

merge करने से पहले पूछें: क्या ऐसे ऑर्डर्स हैं जिनका उत्पाद products.csv में नहीं है, और ऐसे उत्पाद जिनका किसी ने ऑर्डर नहीं दिया? फ़िल्टरिंग अध्याय का isin दोनों का उत्तर देता है:

python
orders = pd.concat([march, april], ignore_index=True)

no_cost = ~orders["product"].isin(products["product"])
print(orders.loc[no_cost, ["order_id", "product"]])

never_sold = ~products["product"].isin(orders["product"])
print(products.loc[never_sold, "product"].tolist())
text
order_id  product
10      1011  stapler
['marker']

एक ऑर्डर — स्टेपलर, 1011 — का रिकॉर्ड में कोई लागत मूल्य नहीं है। एक उत्पाद, मार्कर, कभी नहीं बिका। अब आप merge करने से पहले जानते हैं कि merge को किन परिस्थितियों से निपटना होगा।

6. परिणाम का अनुमान लगाएं, फिर निर्णय लें

अनुमान को संख्याओं में लिख लें:

  • orders में 8 + 4 = 12 पंक्तियाँ हैं।
  • products में प्रति उत्पाद एक पंक्ति है, इसलिए मिलान ऑर्डर्स की संख्या बढ़ा नहीं सकता।
  • यदि प्रत्येक ऑर्डर रखा जाता है, तो मर्ज की गई टेबल में 12 पंक्तियाँ होंगी, और उनमें से एक (स्टेपलर) की लागत नहीं होगी।
  • यदि केवल मेल खाने वाले ऑर्डर्स रखे जाते हैं, तो इसमें 11 पंक्तियाँ होंगी।

आप क्या चाहते हैं? लाभ की रिपोर्ट के लिए स्टेपलर ऑर्डर को चुपचाप हटा देने से बिक्री कम दिखाई देगी। बेहतर है कि उसे रखा जाए, देखा जाए कि उसकी लागत गायब है, और निर्णय लिया जाए — जो कि ठीक वही विकल्प है जिसे how= आर्ग्युमेंट तय करता है। merge के बाद, सबसे पहली चीज़ जो आप प्रिंट करते हैं वह आकार (shape) है, और आप उसकी तुलना इस अनुमान से करते हैं।

यही पूरी योजना है: एक वाक्य का सवाल, प्रत्येक जोड़ी के लिए ऑपरेशन, प्रत्येक टेबल का मुआयना, 'की' की विशिष्टता, बेमेल कीज़, और अपेक्षित पंक्तियों की संख्या। अध्याय का शेष भाग वे उपकरण हैं जो इसे क्रियान्वित करते हैं।


pd.concat के साथ पंक्तियों को ऊपर-नीचे जोड़ना (Stacking)

pd.concat टेबल्स की एक लिस्ट लेता है और उन्हें एक के नीचे एक रख देता है:

python
import pandas as pd

march = pd.read_csv("orders.csv")
april = pd.read_csv("orders_april.csv")

both = pd.concat([march, april])
print(both.shape)
print(both[["order_id", "date", "product", "quantity"]])
text
(12, 7)
   order_id        date   product  quantity
0      1001  2024-03-01       pen        12
1      1002  2024-03-01  notebook         5
2      1003  2024-03-02       bag         2
3      1004  2024-03-02    bottle         7
4      1005  2024-03-03    eraser        30
5      1006  2024-03-03       bag         1
6      1007  2024-03-04       pen        20
7      1008  2024-03-04    bottle         4
0      1009  2024-04-01       pen        15
1      1010  2024-04-01  notebook         3
2      1011  2024-04-02   stapler         6
3      1012  2024-04-02       bag         1

बारह पंक्तियाँ, वही सात कॉलम। पांडास ने कॉलमों को उनकी स्थिति के बजाय नाम के आधार पर संरेखित किया — यदि अप्रैल की फ़ाइल में कॉलम किसी अन्य क्रम में होते, तब भी वे सही शीर्षकों के नीचे ही आते।

लेकिन बाईं ओर इंडेक्स देखें। इंडेक्स 0 से 7 तक चलता है, फिर दोबारा 0 से शुरू होता है। concat ने प्रत्येक टेबल का अपना इंडेक्स सुरक्षित रखा, इसलिए लेबल 0 से 3 अब दो बार दिखाई दे रहे हैं। यह सिर्फ दिखने की समस्या नहीं है:

python
print(both.loc[0, ["order_id", "date"]])
text
order_id        date
0      1001  2024-03-01
0      1009  2024-04-01

आपने पंक्ति 0 मांगी और आपको दो पंक्तियाँ मिलीं। कोई भी कोड जो यह मानकर चलता है कि एक लेबल का मतलब एक पंक्ति है — जैसे loc, इंडेक्स पर बाद का कोई merge, या किसी एक सेल को अपडेट करना — अब कुछ ऐसा करेगा जो आपका इरादा नहीं था। आप इसे जांच सकते हैं:

python
print(both.index.is_unique)
text
False

ignore_index=True — पंक्तियों को दोबारा नंबर देना

जब पुराना इंडेक्स केवल पंक्ति संख्या (एक RangeIndex, जैसा कि अब तक के प्रत्येक read_csv में हुआ है) था, तो उसका कोई विशेष अर्थ नहीं होता, इसलिए उसे छोड़ दें और concat को परिणाम में शून्य से नए नंबर देने दें:

python
orders = pd.concat([march, april], ignore_index=True)
print(orders.index.is_unique)
print(orders[["order_id", "date", "product"]].tail(5))
text
True
    order_id        date   product
7       1008  2024-03-04    bottle
8       1009  2024-04-01       pen
9       1010  2024-04-01  notebook
10      1011  2024-04-02   stapler
11      1012  2024-04-02       bag

अब लेबल 0 से 11 तक चलते हैं, प्रत्येक ठीक एक बार। फ़ाइलों को जोड़ते समय ignore_index=True को अपना डिफ़ॉल्ट नियम बना लें; इसे केवल तभी छोड़ें जब इंडेक्स का कोई खास अर्थ हो (उदाहरण के लिए, set_index("order_id") के बाद, जहाँ ऑर्डर आईडी पहले से ही यूनिक हैं)।

ट्रैक रखें कि हर पंक्ति कहाँ से आई है

जोड़ने के बाद टेबल में ऐसा कुछ नहीं होता जिससे पता चले कि कोई पंक्ति किस महीने की है। यहाँ तारीख से पता चल रहा है, लेकिन अक्सर ऐसा नहीं होता। कॉनकेटेनेट करने से पहले एक कॉलम जोड़ें — पिछले अध्याय की तकनीक — और यह जानकारी पंक्तियों के साथ सुरक्षित रहेगी:

python
march["month"] = "March"
april["month"] = "April"
orders = pd.concat([march, april], ignore_index=True)

print(orders["month"].value_counts())
text
month
March    8
April    4
Name: count, dtype: int64

यह गणना जांच का भी काम करती है: 8 + 4 = 12, कुछ भी नहीं खोया।

जब कॉलम मेल नहीं खाते

Concat कॉलमों को नाम से मिलाता है। जो कॉलम केवल कुछ टेबल्स में मौजूद होता है, वह भी परिणाम में दिखाई देता है — और जिन टेबल्स में वह नहीं था उनकी पंक्तियों में वहाँ NaN आ जाता है। मान लीजिए कि एक विशेष ऑर्डर हाथ से टाइप किया गया था, जिसमें discount कॉलम था लेकिन date, product, category या price नहीं थे:

python
manual = pd.DataFrame({
    "order_id": [2001],
    "branch": ["north"],
    "quantity": [3],
    "discount": [0.1],
})

mixed = pd.concat([march.head(2), manual], ignore_index=True)
print(mixed[["order_id", "branch", "price", "discount"]])
print(mixed.isna().sum())
text
order_id branch  price  discount
0      1001  north   15.0       NaN
1      1002  south   60.0       NaN
2      2001  north    NaN       0.1
order_id    0
date        1
branch      0
product     1
category    1
quantity    0
price       1
month       1
discount    2
dtype: int64

कोई एरर नहीं। परिणाम में सभी कॉलमों का संघ (union) बनता है, और रिक्त स्थान NaN से भर जाते हैं। इसीलिए कॉनकेटेनेट करने के बाद भी उसी isna().sum() की आवश्यकता होती है जो आपने मिसिंग डेटा वाले अध्याय में सीखी थी: किसी एक फ़ाइल में अलग तरह से लिखा गया कॉलम नाम (जैसे quantity के मुकाबले Quantity) फेल नहीं होता, बल्कि दो आधे-खाली कॉलम बना देता है। यदि concat के बाद कॉलमों की संख्या किसी भी इनपुट से अधिक हो जाती है, तो समझ लें कि कुछ कॉलम ठीक से मेल नहीं खाए।

axis=1 — और आमतौर पर आपको इसकी ज़रूरत क्यों नहीं होती

pd.concat([a, b], axis=1) टेबल्स को ऊपर-नीचे जोड़ने के बजाय अगल-बगल रखता है, और पंक्तियों का मिलान इंडेक्स लेबल के आधार पर करता है। "ऑर्डर्स में उत्पाद के कॉलम जोड़ें" के लिए यह आकर्षक लग सकता है, लेकिन यह उत्पाद के नाम को बिल्कुल नहीं देखता — एक टेबल की पंक्ति 0 दूसरी टेबल की पंक्ति 0 के बगल में आ जाती है, भले ही उनमें कुछ भी हो। किसी कॉलम पर मिलान करने के लिए हमेशा merge का उपयोग करें।


pd.merge के साथ पंक्तियों का मिलान करना

merge दो टेबल्स और एक 'की' (key) लेता है। बाईं टेबल की प्रत्येक पंक्ति के लिए, यह दाईं टेबल में समान 'की' मान वाली पंक्तियाँ ढूंढता है, और उनके कॉलमों को एक साथ जोड़ देता है:

python
products = pd.read_csv("products.csv")

merged = pd.merge(orders, products, on="product")
print(merged.shape)
print(merged[["order_id", "product", "quantity", "price", "cost", "supplier"]])
text
(11, 10)
    order_id   product  quantity  price   cost supplier
0       1001       pen        12   15.0    9.0    Alpha
1       1002  notebook         5   60.0   40.0    Alpha
2       1003       bag         2  850.0  600.0    Bravo
3       1004    bottle         7  120.0   80.0    Bravo
4       1005    eraser        30    8.0    5.0    Alpha
5       1006       bag         1  850.0  600.0    Bravo
6       1007       pen        20   15.0    9.0    Alpha
7       1008    bottle         4  120.0   80.0    Bravo
8       1009       pen        15   15.0    9.0    Alpha
9       1010  notebook         3   60.0   40.0    Alpha
10      1012       bag         1  850.0  600.0    Bravo

प्रत्येक ऑर्डर के पास अब उसकी लागत और सप्लायर आ गए हैं, बिना किसी लूप के और बिना इस बात की परवाह किए कि किसी फ़ाइल में पंक्तियों का क्रम क्या था। 'की' कॉलम product एक ही बार आता है, क्योंकि यह दोनों तरफ समान था।

अब आकार की तुलना योजना से करें। हमने सब कुछ सुरक्षित रहने पर 12 पंक्तियों का अनुमान लगाया था — और हमारे पास 11 हैं। स्टेपलर ऑर्डर 1011 गायब हो गया है। कोई चेतावनी नहीं, कोई एरर नहीं।

यह कोई बग नहीं है। यह डिफ़ॉल्ट प्रकार का merge है, how="inner", जो वही कर रहा है जिसके लिए उसे परिभाषित किया गया है: केवल वही कीज़ रखना जो दोनों टेबल्स में पाई जाती हैं। स्टेपलर products में नहीं है, इसलिए उसका ऑर्डर नहीं बचता; मार्कर orders में नहीं है, इसलिए वह भी नहीं दिखता। यदि आपने 12 पंक्तियों का पहले से अनुमान न लगाया होता, तो आपको इस छूटी हुई बिक्री का कभी पता ही नहीं चलता।

चार प्रकार के merge

how= आर्ग्युमेंट यह तय करता है कि उन पंक्तियों का क्या होगा जिनकी 'की' का दूसरी तरफ कोई साथी नहीं है। कीज़ के दो सेटों की कल्पना करें:

  • how="inner" (डिफ़ॉल्ट) केवल दोनों टेबल्स में मिलने वाली कीज़ रखता है। दोनों तरफ की बेमेल पंक्तियाँ हटा दी जाती हैं। जब आपको केवल पूर्ण रिकॉर्ड चाहिए हों तब इसका उपयोग करें।
  • how="left" बाईं टेबल की प्रत्येक पंक्ति को सुरक्षित रखता है। बिना साथी वाली बाईं पंक्तियों को दाईं टेबल के कॉलमों में NaN मिलता है; बेमेल दाईं पंक्तियाँ हटा दी जाती हैं। मुख्य टेबल में नई जानकारी जोड़ने के लिए इसका उपयोग करें — यह सबसे आम विकल्प है।
  • how="right" इसका उल्टा रूप है: दाईं टेबल की प्रत्येक पंक्ति रखी जाती है, बेमेल बाईं पंक्तियाँ हटा दी जाती हैं।
  • how="outer" दोनों तरफ की प्रत्येक 'की' रखता है, और रिक्तियों को NaN से भरता है। दो सूचियों का आपस में मिलान और ऑडिट करने के लिए इसका उपयोग करें।

खुद से पूछने वाला सवाल यह है: किस टेबल की पंक्तियाँ किसी भी हाल में गायब नहीं होनी चाहिए? यहाँ, ऑर्डर्स टेबल। प्रत्येक ऑर्डर एक वास्तविक बिक्री है; उत्पाद फ़ाइल केवल एक लुकअप है। इसलिए सही merge एक left merge है, जिसमें ऑर्डर्स बाईं ओर हों:

python
merged = pd.merge(orders, products, on="product", how="left")
print(merged.shape)
print(merged[["order_id", "product", "cost", "supplier"]])
text
(12, 10)
    order_id   product   cost supplier
0       1001       pen    9.0    Alpha
1       1002  notebook   40.0    Alpha
2       1003       bag  600.0    Bravo
3       1004    bottle   80.0    Bravo
4       1005    eraser    5.0    Alpha
5       1006       bag  600.0    Bravo
6       1007       pen    9.0    Alpha
7       1008    bottle   80.0    Bravo
8       1009       pen    9.0    Alpha
9       1010  notebook   40.0    Alpha
10      1011   stapler    NaN      NaN
11      1012       bag  600.0    Bravo

बारह पंक्तियाँ, जैसा कि अनुमान लगाया गया था। स्टेपलर का ऑर्डर अभी भी मौजूद है, लागत और सप्लायर के लिए NaN के साथ — जो कि पूरी तरह पारदर्शी है: लागत अज्ञात है, और आप इसे स्पष्ट रूप से देख सकते हैं। एक दिखाई देने वाली अनुपलब्ध वैल्यू (missing value) उस पूरी तरह गायब पंक्ति से लाख गुना बेहतर है जिसे आप देख ही नहीं सकते। यहाँ से मिसिंग डेटा अध्याय के उपकरण लागू होते हैं: आप isna().sum() से रिक्तियों की गिनती कर सकते हैं, क्रय टीम से पता चलने पर लागत भर सकते हैं, या इस ऑर्डर की अलग से रिपोर्ट कर सकते हैं।

एक right merge इसका ठीक उल्टा दर्पण है — हर उत्पाद सुरक्षित रहता है, और बिना किसी ऑर्डर वाला मार्कर भी शामिल होता है:

python
right = pd.merge(orders, products, on="product", how="right")
print(right.shape)
print(right[["order_id", "product", "cost"]].tail(3))
text
(12, 10)
    order_id product  cost
9     1008.0  bottle  80.0
10    1005.0  eraser   5.0
11       NaN  marker  25.0

ध्यान दें कि order_id पूर्ण संख्याओं से बदलकर 1008.0, 1005.0 इत्यादि हो गया। मार्कर की पंक्ति में कोई ऑर्डर आईडी नहीं है, इसलिए कॉलम में अब एक NaN आ गया है — और जैसा कि आपने मिसिंग डेटा वाले अध्याय में देखा था, जिस पूर्णांक कॉलम में NaN आता है वह float64 बन जाता है। यदि merge के बाद अचानक आईडी के पीछे .0 जुड़ जाए, तो समझ लें कि कुछ पंक्तियों को अपना साथी नहीं मिला।

indicator=True — देखें कि हर पंक्ति कहाँ से आई है

एक outer merge दोनों तरफ की हर चीज़ को बनाए रखता है। indicator=True जोड़ें और पांडास एक नया कॉलम _merge जोड़ देता है, जो प्रत्येक पंक्ति के लिए बताता है कि उसकी 'की' दोनों टेबल्स में पाई गई (both), केवल बाईं ओर (left_only), या केवल दाईं ओर (right_only):

python
audit = pd.merge(orders, products, on="product", how="outer", indicator=True)
print(audit[["order_id", "product", "cost", "_merge"]])
print(audit["_merge"].value_counts())
text
order_id   product   cost      _merge
0     1003.0       bag  600.0        both
1     1006.0       bag  600.0        both
2     1012.0       bag  600.0        both
3     1004.0    bottle   80.0        both
4     1008.0    bottle   80.0        both
5     1005.0    eraser    5.0        both
6        NaN    marker   25.0  right_only
7     1002.0  notebook   40.0        both
8     1010.0  notebook   40.0        both
9     1001.0       pen    9.0        both
10    1007.0       pen    9.0        both
11    1009.0       pen    9.0        both
12    1011.0   stapler    NaN   left_only
_merge
both          11
left_only      1
right_only     1
Name: count, dtype: int64

यह इस merge का अपना रिपोर्ट कार्ड है। ग्यारह पंक्तियाँ मेल खा गईं; एक ऑर्डर का कोई उत्पाद रिकॉर्ड नहीं है (left_only: स्टेपलर); एक उत्पाद का कोई ऑर्डर नहीं है (right_only: मार्कर)। यह वही जानकारी है जो योजना के चरण 5 में थी, जिसे खुद merge ऑपरेशन ने तैयार कर दिया है।

Outer merge ने ऑर्डर्स के मूल क्रम को बनाए रखने के बजाय पंक्तियों को 'की' के आधार पर सॉर्ट भी कर दिया — bag, bottle, eraser, …। Inner और left merge बाईं टेबल का क्रम बनाए रखते हैं; outer इसका वादा नहीं करता। यदि क्रम महत्वपूर्ण है, तो अध्याय सात की तरह merge के बाद सॉर्ट करें।

_merge कॉलम साधारण डेटा है, इसलिए आप इस पर फ़िल्टर लगा सकते हैं। केवल समस्याओं को सूचीबद्ध करना एक लाइन का काम है:

python
problems = audit[audit["_merge"] != "both"]
print(problems[["order_id", "product", "_merge"]])
text
order_id  product      _merge
6        NaN   marker  right_only
12    1011.0  stapler   left_only

जब भी आप ऐसा डेटा merge करें जो आपने खुद तैयार नहीं किया है, तो इस प्रकार का ऑडिट ज़रूर चलाएं। जब समस्याओं की सूची खाली हो, तो आपके पास इस बात का प्रमाण होता है कि दोनों फ़ाइलें पूरी तरह सहमत हैं।


अदृश्य ख़तरा: डुप्लिकेट कीज़ (Duplicate keys)

अब तक products में प्रति उत्पाद एक पंक्ति थी। मान लीजिए कि क्रय टीम थोड़ी अधिक लागत पर पेन का दूसरा सप्लायर जोड़ती है और सूची में एक पंक्ति जोड़ देती है, जिससे pen दो बार आ जाता है:

python
products_dup = pd.concat(
    [products, pd.DataFrame({"product": ["pen"], "cost": [10.0], "supplier": ["Gamma"]})],
    ignore_index=True,
)
print(products_dup["product"].is_unique)

exploded = pd.merge(march, products_dup, on="product", how="left")
print(march.shape, "->", exploded.shape)
print(exploded[["order_id", "product", "quantity", "cost", "supplier"]])
text
False
(8, 8) -> (10, 10)
   order_id   product  quantity   cost supplier
0      1001       pen        12    9.0    Alpha
1      1001       pen        12   10.0    Gamma
2      1002  notebook         5   40.0    Alpha
3      1003       bag         2  600.0    Bravo
4      1004    bottle         7   80.0    Bravo
5      1005    eraser        30    5.0    Alpha
6      1006       bag         1  600.0    Bravo
7      1007       pen        20    9.0    Alpha
8      1007       pen        20   10.0    Gamma
9      1008    bottle         4   80.0    Bravo

मार्च में 8 ऑर्डर्स थे; merge ने 10 पंक्तियाँ लौटा दीं। ऑर्डर 1001 और 1007 — पेन के दो ऑर्डर्स — प्रत्येक दो बार दिखाई देते हैं, प्रति पेन पंक्ति एक बार। कुछ भी विफल नहीं हुआ। लेकिन अब मात्रा का योग करें और पेन दो बार गिने गए हैं: 32 अतिरिक्त पेन जो कभी बेचे ही नहीं गए।

python
print(march["quantity"].sum(), exploded["quantity"].sum())
text
81 113

81 के मुकाबले 113। इसे रो विस्फोट (row explosion) कहा जाता है, और यह सबसे नुकसानदेह merge त्रुटि है क्योंकि इसका परिणाम बिल्कुल सामान्य दिखता है। इसके पीछे का नियम: merge बाईं ओर की प्रत्येक मेल खाने वाली पंक्ति को दाईं ओर की प्रत्येक मेल खाने वाली पंक्ति के साथ जोड़ता है। One-to-one या many-to-one में पंक्तियों की संख्या समान रहती है; लेकिन दोनों तरफ दोहराई गई 'की' इसे गुणा कर देती है।

पंक्तियाँ बढ़ाने वाला merge कभी खुद से यह बात नहीं बताता। इसका एकमात्र लक्षण वह कुल योग है जो बहुत बड़ा होता है, और बहुत बड़ा कुल योग शायद ही कभी गलत नज़र आता है। हर merge से पहले और बाद में len() की तुलना करें — यही वह एकमात्र जांच है जो इसे पकड़ती है।

validate= — पांडास से खुद जांच करवाएं

आप उस संबंध को कोड में स्पष्ट रूप से बता सकते हैं जिसकी आप अपेक्षा करते हैं, और यदि डेटा उस नियम को तोड़ता है तो पांडास merge करने से मना कर देगा। कई ऑर्डर्स एक ही उत्पाद साझा करते हैं, इसलिए यह merge many-to-one होना चाहिए:

python
try:
    pd.merge(march, products_dup, on="product", how="left", validate="many_to_one")
except Exception as error:
    print(type(error).__name__ + ":", error)
text
MergeError: Merge keys are not unique in right dataset; not a many-to-one merge

Duplicates in right:
 product
    pen ...

एक MergeError, और यह दोषी 'की' को भी सूचीबद्ध करता है। अन्य संभावित मान "one_to_one", "one_to_many" और "many_to_many" हैं। validate= लिखने में कोई अतिरिक्त प्रयास नहीं लगता और यह एक मूक गलत उत्तर को एक स्पष्ट एरर में बदल देता है, इसलिए लुकअप टेबल के साथ हर merge में इसे ज़रूर शामिल करें।

समाधान: तय करें कि कौन सा डुप्लिकेट सही है

एरर आपको यह बताता है कि कुछ गलत है; लेकिन क्या सही है यह तय करना आपका काम है। पहले डुप्लिकेट्स को देखें:

python
print(products_dup[products_dup["product"].duplicated(keep=False)])
text
product  cost supplier
0     pen   9.0    Alpha
6     pen  10.0    Gamma

duplicated(keep=False) प्रत्येक प्रति को चिह्नित करता है, केवल दूसरी को नहीं। अब एक व्यावसायिक निर्णय लेना होगा। यदि नवीनतम पंक्ति पुरानी पंक्ति का स्थान लेती है, तो अंतिम प्रति रखें:

python
products_clean = products_dup.drop_duplicates(subset="product", keep="last")
fixed = pd.merge(march, products_clean, on="product", how="left", validate="many_to_one")
print(fixed.shape)
print(fixed.loc[fixed["product"] == "pen", ["order_id", "cost", "supplier"]])
text
(8, 10)
   order_id  cost supplier
0      1001  10.0    Gamma
6      1007  10.0    Gamma

वापस 8 पंक्तियों पर, प्रति ऑर्डर एक। यदि इसके बजाय दोनों सप्लायर वास्तव में पेन बेचते हैं और किसी ऑर्डर में यह दर्ज होता है कि किस सप्लायर का पेन है, तो supplier ऑर्डर्स में भी होना चाहिए, और merge की 'की' दो कॉलम बन जाएगी: on=["product", "supplier"]। कोड यह निर्णय नहीं ले सकता; योजना ले सकती है।


जब की (key) कॉलम के नाम अलग हों

branches.csv अपने कॉलम को branch_name कहता है, जबकि ऑर्डर्स उसे branch कहते हैं। on= को दोनों तरफ एक ही नाम चाहिए होता है, इसलिए left_on= और right_on= का उपयोग करके प्रत्येक पक्ष का अलग-अलग नाम दें:

python
branches = pd.read_csv("branches.csv")

with_manager = pd.merge(orders, branches, left_on="branch", right_on="branch_name", how="left")
print(list(with_manager.columns))
text
['order_id', 'date', 'branch', 'product', 'category', 'quantity', 'price', 'month', 'branch_name', 'manager']

दोनों 'की' कॉलम रखे जाते हैं, क्योंकि पांडास यह नहीं जान सकता कि आप उन्हें एक ही कॉलम मानते हैं। branch और branch_name में अब एक जैसे मान हैं, इसलिए एक को हटा दें:

python
with_manager = with_manager.drop(columns="branch_name")
print(with_manager[["order_id", "branch", "manager"]].head(4))
text
order_id branch manager
0      1001  north    Mira
1      1002  south    Omar
2      1003  north    Mira
3      1004   east    Lena

इसका दूसरा विकल्प merge से पहले नाम बदलना है — branches.rename(columns={"branch_name": "branch"}) — और फिर सीधे on="branch" का उपयोग करना। दोनों ही तरीके अच्छे हैं; पहले नाम बदलने से बाद में कॉलम हटाने की ज़रूरत नहीं पड़ती।


जब दोनों टेबल्स में एक ही नाम का कॉलम हो

यदि कोई ऐसा कॉलम जो 'की' नहीं है दोनों टेबल्स में मौजूद हो, तो पांडास एक टेबल में price नाम के दो कॉलम नहीं रख सकता, इसलिए वह उनके नाम में _x (बाईं ओर) और _y (दाईं ओर) प्रत्यय जोड़कर बदल देता है। मान लीजिए एक सूची-मूल्य टेबल है जो अपने कॉलम को भी price कहती है:

python
list_prices = pd.DataFrame({"product": ["pen", "bag"], "price": [14.0, 800.0]})

compared = pd.merge(march, list_prices, on="product")
print(compared[["order_id", "product", "price_x", "price_y"]])
text
order_id product  price_x  price_y
0      1001     pen     15.0     14.0
1      1003     bag    850.0    800.0
2      1006     bag    850.0    800.0
3      1007     pen     15.0     14.0

price_x और price_y काम तो करते हैं, लेकिन तीन हफ़्ते बाद किसी को याद नहीं रहेगा कि कौन सा क्या है। suffixes= के साथ उन्हें खुद स्पष्ट नाम दें:

python
compared = pd.merge(march, list_prices, on="product", suffixes=("_sold", "_list"))
print(compared[["order_id", "price_sold", "price_list"]])
text
order_id  price_sold  price_list
0      1001        15.0        14.0
1      1003       850.0       800.0
2      1006       850.0       800.0
3      1007        15.0        14.0

अब कॉलम अपना स्पष्ट अर्थ बताते हैं, और प्रत्येक ऑर्डर पर दी गई छूट बस price_list - price_sold है। (बाद में जो कोड compared["price"] मांगेगा उसे KeyError मिलेगा, क्योंकि merge के बाद किसी भी कॉलम का वह सटीक नाम नहीं रह जाता — इसलिए नाम सोच-समझकर चुनना ज़रूरी है।)


join — इंडेक्स के आधार पर संक्षेप में merge करना

DataFrames में एक .join() मेथड भी होता है। यह एक ऐसा merge है जो दाईं टेबल के इंडेक्स को अपनी 'की' के रूप में उपयोग करता है — यह तब सुविधाजनक होता है जब लुकअप टेबल पहले से ही 'की' द्वारा इंडेक्स की गई हो:

python
by_product = products.set_index("product")

joined = orders.join(by_product, on="product")
print(joined[["order_id", "product", "cost", "supplier"]].head(3))
text
order_id   product   cost supplier
0      1001       pen    9.0    Alpha
1      1002  notebook   40.0    Alpha
2      1003       bag  600.0    Bravo

join डिफ़ॉल्ट रूप से how="left" पर काम करता है। यह वही काम करता है जो pd.merge(..., how="left"); लेकिन merge अधिक व्यापक उपकरण है, और इस पूरे कोर्स में उसी का उपयोग किया गया है।


एक संपूर्ण उदाहरण

वापस दुकान मालिक के सवाल पर आते हैं: मार्च और अप्रैल में प्रत्येक सप्लायर से मिलने वाला लाभ, जिसमें हर एक ऑर्डर का सही हिसाब हो।

supplier_profit.py:

python
import pandas as pd

march = pd.read_csv("orders.csv")
april = pd.read_csv("orders_april.csv")
products = pd.read_csv("products.csv")

# 1. Stack the two months, remembering where each row came from.
march["month"] = "March"
april["month"] = "April"
orders = pd.concat([march, april], ignore_index=True)
print("orders:", orders.shape)

# 2. The lookup key must be unique, or the merge will duplicate orders.
assert products["product"].is_unique

# 3. Attach cost and supplier to every order. Keep every order.
sales = pd.merge(
    orders, products, on="product", how="left",
    validate="many_to_one", indicator=True,
)
print("after merge:", sales.shape)
assert len(sales) == len(orders)

# 4. Report the orders that found no product row, then set them aside.
unmatched = sales[sales["_merge"] == "left_only"]
print("no cost on file:", unmatched["order_id"].tolist(), unmatched["product"].tolist())
sales = sales[sales["_merge"] == "both"].drop(columns="_merge")

# 5. Profit per row, then per supplier and month.
sales["profit"] = sales["quantity"] * (sales["price"] - sales["cost"])
report = (
    sales.groupby(["supplier", "month"], as_index=False)["profit"]
    .sum()
    .sort_values(["supplier", "profit"], ascending=[True, False])
    .reset_index(drop=True)
)
print()
print(report)
print()
print(sales.groupby("supplier")["profit"].sum().sort_values(ascending=False))
text
orders: (12, 8)
after merge: (12, 11)
no cost on file: [1011] ['stapler']

  supplier  month  profit
0    Alpha  March   382.0
1    Alpha  April   150.0
2    Bravo  March  1190.0
3    Bravo  April   250.0

supplier
Bravo    1440.0
Alpha     532.0
Name: profit, dtype: float64

इसे इस तरह क्यों लिखा गया है:

  • प्रत्येक संयोजन चरण के बाद आकार (shape) की पुष्टि की गई है। orders: (12, 8) ऊपर-नीचे जोड़ने की पुष्टि करता है (8 + 4 पंक्तियाँ, 7 कॉलम + month)। after merge: (12, 11) पुष्टि करता है कि कुछ भी गायब या डुप्लिकेट नहीं हुआ — 3 नए कॉलम: cost, supplier, _merge। आकार जांचना इस बात का सबसे सस्ता और प्रभावी प्रमाण है कि प्रत्येक चरण ने योजना के अनुसार काम किया।
  • मान्यताओं को कोड के रूप में लिखा गया है। assert products["product"].is_unique और validate="many_to_one" दोनों रो विस्फोट से रक्षा करते हैं; assert len(sales) == len(orders) योजना के अनुमान की रक्षा करता है। यदि कोई अगले महीने की उत्पाद फ़ाइल डुप्लिकेट के साथ भेजता है, तो स्क्रिप्ट बढ़ा-चढ़ाकर लाभ दिखाने के बजाय वहीं रुक जाएगी।
  • how="left" स्टेपलर के ऑर्डर को सुरक्षित रखता है, और indicator=True उसका नाम बताता है। स्क्रिप्ट इसे चुपचाप नहीं हटाती; यह [1011] ['stapler'] प्रिंट करती है, ताकि मालिक को पता रहे कि जब तक क्रय टीम लागत नहीं जोड़ती, तब तक अप्रैल के योग में एक बिक्री गायब है। यह पंक्ति उत्तर का हिस्सा है, कोई डिबग कचरा नहीं।
  • month कॉलम concat से पहले जोड़ा गया था। अन्यथा रिपोर्ट में महीने-वार विभाजन के लिए तारीखों को पार्स और रूपांतरित करना पड़ता — जो संभव तो था, लेकिन उसी परिणाम के लिए अधिक मेहनत का काम होता।
  • लाभ की गणना merge के बाद की जाती है, क्योंकि इसके लिए दोनों फ़ाइलों के कॉलम चाहिए। यह स्वाभाविक क्रम है: संयोजन करें, फिर कॉलम जोड़ें (अध्याय नौ), फिर समूहित करें (अध्याय आठ), फिर सॉर्ट करें (अध्याय सात)।

उत्तर: Bravo ने 1,440 का लाभ दिया और Alpha ने 532, जबकि अप्रैल की एक बिक्री अभी भी अपनी लागत की प्रतीक्षा कर रही है। Bravo कम वस्तुएं बेचता है, लेकिन पेन और इरेज़र की तुलना में बैग और बोतलों पर प्रति वस्तु मार्जिन कहीं अधिक होता है।


जब यह काम न करे

ValueError: You are trying to merge on int64 and str columns for key 'order_id'. If you wish to proceed you should use pd.concat

दोनों तरफ 'की' का डेटा टाइप अलग है। यहाँ एक डिलीवरी फ़ाइल है जिसके ऑर्डर आईडी के आगे # लगाकर निर्यात किया गया था। इसे deliveries.csv के रूप में सहेजें — इसका उपयोग "आपकी बारी" में भी किया गया है। (यदि आपके पास मिसिंग डेटा अध्याय से उसी नाम का राइडर्स लॉग अभी भी है, तो उसे बदल दें; यह एक अलग फ़ाइल है।)

text
order_id,status
#1001,delivered
#1002,delivered
#1003,returned
#1005,delivered
#1006,pending
python
import pandas as pd

march = pd.read_csv("orders.csv")
deliveries = pd.read_csv("deliveries.csv")
print(march["order_id"].dtype, deliveries["order_id"].dtype)

try:
    pd.merge(march, deliveries, on="order_id", how="left")
except ValueError as error:
    print("ValueError:", error)
text
int64 str
ValueError: You are trying to merge on int64 and str columns for key 'order_id'. If you wish to proceed you should use pd.concat

1001 और "#1001" अलग-अलग वैल्यूज़ हैं, और पांडास कोई अनुमान लगाने से मना कर देता है। (pd.concat के बारे में संकेत एक अलग स्थिति के लिए है; इसे अनदेखा करें।) इसका उपाय कीज़ को एक ही प्रकार और एक ही टेक्स्ट में बदलना है — # हटाएं, फिर बदलें:

python
deliveries["order_id"] = deliveries["order_id"].str.removeprefix("#").astype("int64")
status = pd.merge(march, deliveries, on="order_id", how="left")
print(status[["order_id", "product", "status"]])
text
order_id   product     status
0      1001       pen  delivered
1      1002  notebook  delivered
2      1003       bag   returned
3      1004    bottle        NaN
4      1005    eraser  delivered
5      1006       bag    pending
6      1007       pen        NaN
7      1008    bottle        NaN

जिन ऑर्डर्स का कोई डिलीवरी रिकॉर्ड नहीं है, उन्हें status के लिए NaN मिलता है — left merge उन्हें सुरक्षित रखता है, जो कि बिल्कुल वही है जो आप तब चाहते हैं जब सवाल हो "कौन से ऑर्डर्स डिलीवर नहीं हुए हैं?"

MergeError: Merge keys are not unique in right dataset; not a many-to-one merge आपने validate="many_to_one" का उपयोग किया और दाईं टेबल में एक 'की' दोहराई गई है। संदेश में डुप्लिकेट्स सूचीबद्ध हैं। एरर को हटाने के लिए validate को न हटाएं — बल्कि duplicated(keep=False) के साथ डुप्लिकेट पंक्तियों को देखें और तय करें कि कौन सी सही है, जैसा कि रो-विस्फोट अनुभाग में दिखाया गया था।

KeyError: 'branch' on= में दिया गया कॉलम किसी एक टेबल में मौजूद नहीं है:

python
branches = pd.read_csv("branches.csv")

try:
    pd.merge(march, branches, on="branch")
except KeyError as error:
    print("KeyError:", error)
text
KeyError: 'branch'

branches इसे branch_name कहता है। दोनों टेबल्स के लिए list(df.columns) प्रिंट करें; left_on="branch", right_on="branch_name" का उपयोग करें, या एक तरफ का नाम बदलें। कॉलम नाम के अंत में एक अतिरिक्त स्पेस ("branch ") भी यही एरर देता है और केवल लिस्ट रूप में ही दिखाई देता है।

merge तो चल गया, लेकिन नए कॉलम सभी NaN हैं कोई एरर नहीं, और हर पंक्ति बेमेल रही। कीज़ देखने में समान लगती हैं लेकिन होती नहीं हैं: अंत में स्पेस के साथ "north ", बड़े अक्षर के साथ "South", या एक फ़ाइल में टेक्स्ट के रूप में और दूसरी में उपसर्ग (prefix) के साथ वही आईडी। merge करने से पहले isin से जांचें:

python
branches_messy = pd.DataFrame({"branch_name": ["north ", "South", "east"], "manager": ["Mira", "Omar", "Lena"]})

print(march["branch"].isin(branches_messy["branch_name"]).sum(), "of", len(march), "orders match")

branches_messy["branch_name"] = branches_messy["branch_name"].str.strip().str.lower()
print(march["branch"].isin(branches_messy["branch_name"]).sum(), "of", len(march), "orders match")
text
2 of 8 orders match
8 of 8 orders match

सफाई से पहले आठ में से दो मेल खाते थे, बाद में आठ में से आठ। merge करने से पहले दोनों तरफ 'की' को एक ही तरह से साफ करें — str.strip() और एक समान केस (case)।

merge के बाद पंक्तियों की संख्या बढ़ गई दाईं टेबल में डुप्लिकेट 'की' है; ऊपर "अदृश्य ख़तरा" देखें। हर merge से पहले और बाद में len() की तुलना करें, और validate= का उपयोग करें।

merge के बाद पंक्तियाँ गायब हो गईं आपने डिफ़ॉल्ट how="inner" का उपयोग किया, और कुछ कीज़ का कोई साथी नहीं था। मुख्य टेबल को बाईं ओर रखकर how="left" का उपयोग करें, और कौन सी पंक्तियाँ बेमेल थीं यह देखने के लिए indicator=True का उपयोग करें।

TypeError: concat() takes 1 positional argument but 2 were given

python
try:
    pd.concat(march, deliveries)
except TypeError as error:
    print("TypeError:", error)
text
TypeError: concat() takes 1 positional argument but 2 were given

concat एक आर्ग्युमेंट लेता है, जो कि टेबल्स की एक लिस्ट होती है। pd.concat([march, april]) लिखें — यहाँ वर्गाकार कोष्ठक [] ही मुख्य बात है।

concat के बाद दोहराया गया इंडेक्स, और loc दो पंक्तियाँ लौटाता है प्रत्येक इनपुट ने अपना 0, 1, 2, … बनाए रखा। ignore_index=True जोड़ें।