2025, Oct 18 12:30

Pandas में पूर्णांक पंक्तियों को बाइनरी इंडिकेटर मैट्रिक्स में वेक्टराइज़्ड तरीके से बदलें

जानें कैसे Pandas में stack और get_dummies के साथ बिना लूप पूर्णांक पंक्तियों को बाइनरी इंडिकेटर मैट्रिक्स में बदला जाए: तेज, वेक्टराइज़्ड समाधान। स्केलेबल।

पूर्णांकों की पंक्तियों को बाइनरी इंडिकेटर मैट्रिक्स में बदलना पहली नज़र में वन-हॉट एनकोडिंग जैसा लगता है, लेकिन उद्देश्य यहाँ अलग है: हर मूल पंक्ति के लिए हमें एक ऐसा बाइनरी स्तंभ चाहिए, जो उस पंक्ति में मौजूद स्थानों (इंडेक्स मानों) को चिह्नित करे और बाकी सभी जगह 0 रहे। चुनौती यह है कि यह सब बिना लूप के, एक साथ कई पंक्तियों के लिए कैसे किया जाए।

उदाहरण और एक सरल प्रयास

एक सरल Pandas DataFrame पर विचार करें, जहाँ हर पंक्ति में वे पूर्णांक स्थान हैं जिन्हें हमें फ़्लैग करना है:

import pandas as pd
data = pd.DataFrame({
    "A": [1, 2, 3],
    "B": [4, 5, 6],
    "C": [7, 8, 9],
}, index=[0, 1, 2])

एक पंक्ति के लिए सीधा तरीका यह है कि सभी संभावित स्थानों की रेंज बनाएँ और उस पंक्ति के विरुद्ध सदस्यता जाँच लें। यह एक पंक्ति पर चलता है, लेकिन पूरे फ़्रेम पर स्केल नहीं होता:

src_df = data
out_grid = pd.DataFrame(range(src_df.max(axis=None) + 1)).isin(list(src_df.iloc[0]))

यह तरीका सिर्फ पहली पंक्ति पर काम करता है और सभी पंक्तियों पर एक साथ लागू नहीं हो पाता।

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

दृष्टिकोण बदलें तो वांछित संरचना स्पष्ट हो जाती है। चौड़ी तालिका को लंबी सीरीज़ में बदल दें—फिर पूर्णांक मानों पर वन-हॉट एनकोडिंग लगाएँ और मूल पंक्तियों के आधार पर एग्रीगेट करें। इससे स्थान सुरक्षित रहते हैं और एक ही पास में हर पंक्ति के लिए बाइनरी इंडिकेटर मैट्रिक्स बनाना सहज हो जाता है।

Pandas में वेक्टराइज़्ड समाधान

यहाँ एक संक्षिप्त, पूरी तरह वेक्टराइज़्ड पाइपलाइन है, जो प्रारंभ से अंत तक यह रूपांतरण करती है:

result = pd.get_dummies(data.stack()).groupby(level=0).sum().T

यह चार चरणों में चलता है। पहले, stack डेटा को लंबी Series में बदलता है, जिसका MultiIndex मूल पंक्ति इंडेक्स और पुराने कॉलम लेबल्स से बना होता है। इसके बाद, get_dummies पूर्णांक मानों को वन-हॉट कॉलम में बदलता है। फिर groupby(level=0).sum() इन इंडिकेटर्स को मूल पंक्तियों (MultiIndex के पहले स्तर) के आधार पर समेकित करता है। अंत में, .T ट्रांसपोज़ करता है ताकि पूर्णांक स्थान पंक्ति इंडेक्स बन जाएँ और मूल पंक्तियाँ कॉलम हो जाएँ।

नतीजा इच्छित बाइनरी इंडिकेटर लेआउट से मेल खाता है:

   0  1  2
1  1  0  0
2  0  1  0
3  0  0  1
4  1  0  0
5  0  1  0
6  0  0  1
7  1  0  0
8  0  1  0
9  0  0  1

अंदर की कार्यप्रणाली पर नज़र

यदि स्पष्टता के लिए आप बीच के ऑब्जेक्ट देखना चाहें, तो इसे नामित चरणों में बाँट लें। इससे बिना कोई लूप लिखे पाइपलाइन में डेटा का प्रवाह जाँचना आसान हो जाता है:

s_long = data.stack()
ohe = pd.get_dummies(s_long)
agg = ohe.groupby(level=0).sum()
final = agg.T

stack से बनी लंबी Series मूल पंक्ति इंडेक्स को मूल कॉलम नाम के साथ जोड़ती है। get_dummies पूर्णांक मानों को इंडिकेटर कॉलम में बदलता है। पहले इंडेक्स स्तर पर समूह बनाने से हर मूल पंक्ति के भीतर इंडिकेटर्स का योग हो जाता है। ट्रांसपोज़ करने पर तालिका वांछित उन्मुखीकरण में आ जाती है, जहाँ स्थान इंडेक्स होते हैं।

यह क्यों उपयोगी है

पहले रिसेपिंग और फिर वन-हॉट एनकोडिंग अपनाने से कस्टम लूप और प्रति-पंक्ति तर्क की जरूरत नहीं पड़ती, और सब कुछ Pandas की आदर्श शैली में रहता है। यह रूपांतरण पढ़ने में सरल, डिबग करने में आसान है और किसी भी संख्या की पंक्तियों पर लागू होता है। यदि आप पंक्तियों पर for-लूप या .apply() के बारे में सोच रहे थे, तो यह पैटर्न उसकी आवश्यकता खत्म कर देता है। साथ ही, संख्यात्मक इंडेक्सिंग पर टिके रहने से ऑपरेशंस पूर्वानुमेय और स्पष्ट रहते हैं।

निष्कर्ष

जब आपको ऐसी बाइनरी इंडिकेटर मैट्रिक्स चाहिए जो हर पंक्ति के पूर्णांक स्थान चिन्हित करे, तो stack के साथ लंबा रूप दें, get_dummies से वन-हॉट एनकोड करें, मूल पंक्तियों के आधार पर समेकित करें और फिर ट्रांसपोज़ करें। यह एक ही अभिव्यक्ति pd.get_dummies(data.stack()).groupby(level=0).sum().T समस्या को वेक्टराइज़्ड तरीके से हल करती है और पूरे DataFrame पर स्वाभाविक रूप से स्केल करती है।

यह लेख StackOverflow पर प्रश्न (लेखक: lane-h-rogers) और PaulS के उत्तर पर आधारित है।