2025, Nov 01 16:31

Pandas में शर्त आधारित forward-fill: colA=3 से colC फैलाएँ

Pandas DataFrame में mask के साथ forward-fill सीखें: colA=3 के colC को colA=4 पंक्तियों में फैलाएँ, colB को बदले बिना. स्पष्ट और दोहराने योग्य समाधान, कोड सहित.

पंक्तियों में शर्त लगाकर मान भरना डेटा की सफाई का एक आम काम है। यहाँ उद्देश्य सीधा है: जिन पंक्तियों में colA 4 के बराबर है, वहाँ colC को उस सबसे हालिया colC से बदलना है जो colA 3 होने पर दिखा था। colB कॉलम को बिल्कुल नहीं छेड़ना है।

समस्या दिखाने वाला न्यूनतम उदाहरण

डेटा तीन कॉलम वाला Pandas DataFrame है। जिन पंक्तियों में colA बराबर 3 है, वे मान वह देते हैं जिन्हें आगे फैलाना है; जिन पंक्तियों में colA बराबर 4 है, उनके colC में वही फैला हुआ मान आना चाहिए।

from pandas import DataFrame as Frame
source_df = Frame({
    'colA': [3, 4, 4, 4, 3, 4, 4, 3, 4],
    'colB': ['air', 'ground', 'ground', 'ground', 'air', 'ground', 'air', 'ground', 'ground'],
    'colC': ['00JTHYU1', '00JTHYU0', '00JTHYU0', '00JTHYU0', '00JTHYU4', '00JTHYU0', '00JTHYU0', '00JTHYU7', '00JTHYU0']
})
print(source_df)

इच्छित परिणाम: जिन पंक्तियों में colA 4 के बराबर है, उनका colC उस आखिरी colC पर सेट होना चाहिए जहाँ colA 3 था, जबकि colB बिल्कुल वैसा ही बना रहे।

वास्तव में मामला क्या है

colC पर सीधे ffill करने से सही नतीजा नहीं मिलेगा, क्योंकि वह उन पंक्तियों से भी आगे भर देगा जिन्हें एंकर नहीं बनना चाहिए। इरादा यह है कि केवल वे पंक्तियाँ स्रोत बनें जहाँ colA 3 के बराबर है, बाकी पंक्तियाँ स्रोत के रूप में न गिनी जाएँ। इसलिए colC को ऐसे मास्क करना पड़ेगा कि सिर्फ colA = 3 से जुड़े मान “एंकर” की तरह रहें; बाकी सबको भरते समय missing माना जाए।

समाधान

तरीका यह है: एक masked Series बनाइए जो colA 3 होने पर colC को रखे और अन्य जगह NaN हो, उस masked Series पर forward-fill चलाइए, और फिर फैले हुए मानों को सख्ती से केवल उन पंक्तियों में वापस लिखिए जहाँ colA 4 है।

from pandas import DataFrame as Frame
data_tbl = Frame({
    'colA': [3, 4, 4, 4, 3, 4, 4, 3, 4],
    'colB': ['air', 'ground', 'ground', 'ground', 'air', 'ground', 'air', 'ground', 'ground'],
    'colC': ['00JTHYU1', '00JTHYU0', '00JTHYU0', '00JTHYU0', '00JTHYU4', '00JTHYU0', '00JTHYU0', '00JTHYU7', '00JTHYU0']
})
anchor_vals = data_tbl['colC'].where(data_tbl['colA'] == 3)
spread_vals = anchor_vals.ffill()
data_tbl.loc[data_tbl['colA'] == 4, 'colC'] = spread_vals
print(data_tbl)

इससे इच्छित परिणाम मिलता है: 4 के हर समूह को सबसे ताजा 3 से colC विरासत में मिल जाता है, और colB सुरक्षित रहता है।

   colA    colB      colC
0     3     air  00JTHYU1
1     4  ground  00JTHYU1
2     4  ground  00JTHYU1
3     4  ground  00JTHYU1
4     3     air  00JTHYU4
5     4  ground  00JTHYU4
6     4     air  00JTHYU4
7     3  ground  00JTHYU7
8     4  ground  00JTHYU7

यह बारीकी क्यों अहम है

मास्क के बिना forward-fill करना सुविधाजनक लगता है, लेकिन इससे non-anchor पंक्तियाँ भी परिणाम को प्रभावित कर सकती हैं और आपके डेटा का आशय बदल सकता है। मास्किंग इरादे को साफ कर देती है: केवल वे पंक्तियाँ जहाँ colA 3 के बराबर है, तय करती हैं कि क्या फैलना चाहिए। यही फर्क है त्वरित जुगाड़ और ठोस, ऑडिट‑योग्य रूपांतरण में।

मुख्य बातें

जब भी किसी शर्त के आधार पर मान आगे ले जाने हों, पहले एक सशर्त source series बनाइए, उसे forward-fill कीजिए, और फिर केवल जहाँ ज़रूरत हो वहीं असाइन कीजिए। यह पढ़ने में सरल है, समझने में आसान है, colB जैसे कॉलम अपरिवर्तित रहते हैं, और यह सुनिश्चित करता है कि colA 4 के बराबर होने पर colC हमेशा उस नवीनतम मान को दर्शाए जो colA 3 पर स्थापित हुआ था।

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