2025, Sep 29 13:33
groupby के बाद MultiIndex में .loc और .xs से मान चुनने की गाइड
pandas में groupby के बाद बने MultiIndex से मान चुनना सीखें: Setpoint 80 पर zone1 का mean .loc[('zone1', 80)] और .xs से निकालें, KeyError से बचें आसानी से
जब आप pandas में कई कुंजियों के साथ डेटा को समूहित करते हैं, तो परिणाम MultiIndex होता है। यह शक्तिशाली है, लेकिन यह पंक्तियों को चुनने का तरीका भी बदल देता है। एक आम उलझन यही है: zone और Setpoint पर समूह बनाने के बाद, Setpoint 80 पर zone1 का एकल मान कैसे निकालें? नीचे सही और स्थिर तरीके से यही चयन करने के लिए एक संक्षिप्त मार्गदर्शिका दी गई है।
सेटअप दोहराना
पर्यावरण है Python 3.9.2 और JupyterLab में pandas 2.3.2। मान लें कि आपके पास पहले से zone, data और Setpoint कॉलम वाला एक DataFrame है, और फिर आपने zone और Setpoint के आधार पर औसत निकाल लिया है। समेकन के लिए कोड कुछ ऐसा होगा:
# sensor_df नामक मौजूदा DataFrame से शुरुआत
# कॉलम: 'zone', 'Setpoint', 'data'
agg_mean = sensor_df[["zone", "Setpoint", "data"]] \
    .groupby(["zone", "Setpoint"]) \
    .mean()
यह एक ऐसा DataFrame बनाता है जिसकी पंक्ति-सूची (row index) दो स्तरों—zone और Setpoint—के साथ MultiIndex होती है, और एकल कॉलम का नाम data होता है।
यदि आप किसी एक zone को काटकर देखें:
zone1_slice = agg_mean.loc["zone1"]
तो आप देखेंगे कि अब शेष index Setpoint के मान हैं (40, 50, …, 110) और अभी भी एक ही कॉलम है जिसका नाम data है।
वास्तव में हो क्या रहा है
groupby(...).mean() के बाद आउटपुट की पंक्तियों पर MultiIndex होता है: पहला स्तर zone है, दूसरा स्तर Setpoint। तालिका के “ऊपर” जो data लेबल दिखता है, वह कॉलम का नाम है, index लेबल नहीं। जब आप agg_mean.loc["zone1"] करते हैं, तो आप MultiIndex के एक स्तर का चयन करते हैं और आपके पास ऐसा DataFrame बचता है जिसका index Setpoint के मान होते हैं। यानी 80 एक index लेबल है, कॉलम नहीं—और उसी तरह से एक्सेस करना होगा।
इसीलिए नीचे जैसे प्रयास असफल होते हैं:
# 80 यहाँ कोई कॉलम नाम नहीं है
zone1_slice[80]  # KeyError: 80
# .at एक indexer है; इसे Series/DataFrame पर [] या [, ] के साथ उपयोग करें, फ़ंक्शन की तरह कॉल न करें
zone1_slice.at(80)  # TypeError
# .loc/.iloc indexer हैं; गोल कोष्ठक नहीं, चौकोर ब्रैकेट का उपयोग करें
zone1_slice.loc(80)   # KeyError / ValueError
zone1_slice.iloc(80)  # वही समस्या
# groupby के बाद 'Setpoint' कोई कॉलम नहीं; यह index का एक स्तर है
zone1_slice.loc(zone1_slice["Setpoint"] == 80)  # KeyError: Setpoint
साधारण नियम: index पर मौजूद लेबल के लिए .loc[...] का उपयोग करें; MultiIndex के लिए, index स्तरों से मेल खाता हुआ tuple पास करें; और सभी अन्य स्तरों पर किसी एक स्तर से स्लाइस करने के लिए .xs(..., level="...") इस्तेमाल करें।
समाधान: MultiIndex स्तर के आधार पर चयन
यदि आप सभी zones के लिए Setpoint 80 का औसत चाहते हैं, तो Setpoint स्तर पर cross-section लें:
agg_mean.xs(80, level="Setpoint")
# ऐसा DataFrame देता है जिसका index 'zone' और कॉलम 'data' है, उदाहरण:
#             data
# zone            
# zone1  80.045247
# zone3  80.043304
# zone4  80.034280
यदि आपको Setpoint 80 पर zone1 के लिए एकल मान चाहिए, तो .loc और एक tuple के साथ दोनों स्तरों को एक साथ इंडेक्स करें:
agg_mean.loc(("zone1", 80))
# एक-पंक्ति वाली Series लौटती है:
# data    80.045247
agg_mean.loc(("zone1", 80), "data")
# scalar लौटता है:
# 80.045247
आप चेन करके भी चयन कर सकते हैं, पर ध्यान रखें कि इससे मध्यवर्ती ऑब्जेक्ट बनते हैं। उदाहरण के लिए, ये परिणाम में समान हैं:
agg_mean["data"]["zone1"][80]
agg_mean.loc["zone1"].loc[80]["data"]
सीधा tuple रूप agg_mean.loc(("zone1", 80), "data") अधिक स्पष्ट है और, सबसे बढ़कर, अतिरिक्त मध्यवर्ती ऑब्जेक्ट्स से बचाता है।
यह क्यों मायने रखता है
MultiIndex कई प्रचलित pandas कार्यप्रवाहों का केंद्र है, खासकर groupby के बाद। यह समझना कि grouping की keys कॉलम नहीं, बल्कि index के स्तर बन जाती हैं, चयन को पूर्वानुमेय और स्पष्ट बना देता है। इससे indexer के साथ trial-and-error घटता है, KeyError जैसी दिक्कतों से बचते हैं, और आपका कोड अधिक साफ़ तथा मध्यवर्ती आवंटन के लिहाज से कम फालतू बनता है।
मुख्य बातें
कई कुंजियों के साथ groupby के बाद, सोच index स्तरों के संदर्भ में रखें। जब सभी स्तरों के सही लेबल पता हों, तो .loc[(level1, level2)] इस्तेमाल करें। किसी एक स्तर के आधार पर बाकी सभी में स्लाइस करने के लिए .xs(label, level="LevelName") उपयोग करें। और याद रखें: जो लेबल आपको संख्याओं के ऊपर दिखता है, वह कॉलम का नाम है; बाईं ओर जो लेबल हैं, वे index हैं। इस मानसिक मॉडल के साथ, एकल मान निकालना—जैसे Setpoint 80 पर zone1 के लिए mean data—एक लाइन में हो जाता है।
यह लेख StackOverflow पर प्रश्न (लेखक: Brian A. Henning) और mozway के उत्तर पर आधारित है।