2025, Oct 01 03:33

Pandas में एक कॉलम को आख़िरी कॉमा पर दो हिस्सों में बाँटें—apply की ValueError से बचें

Pandas में row-wise apply वाली ValueError का हल: str.rsplit(',', n=1) और str.strip() से आख़िरी कॉमा पर कॉलम को दो भागों में तेज़, सुरक्षित, वेक्टराइज़्ड स्प्लिट करें.

एक ही Pandas कॉलम को दो भागों में बाँटना ऊपर-ऊपर से आसान लगता है, जब तक कि एक निर्दोष-सी असाइनमेंट यह त्रुटि न फेंक दे: ValueError: Cannot set a DataFrame with multiple columns to the single column. नीचे इस विफलता के कारणों का छोटा-सा विश्लेषण है और एक भरोसेमंद तरीका, जिससे आप आख़िरी कॉमा पर स्प्लिट कर सकते हैं—भले ही टेक्स्ट में कई कॉमा हों।

Problem

एक फ़ंक्शन है जो छह कॉलम वाले डेटाफ़्रेम को लेता है और row-wise apply का उपयोग कर एक टेक्स्ट कॉलम को दो नए कॉलम में बाँटने की कोशिश करता है. फ़ंक्शन के भीतर यह shape-mismatch त्रुटि के साथ विफल हो जाता है; फ़ंक्शन के बाहर ऐसा नहीं होता. मूल विचार कॉमा खोजकर बाएँ/दाएँ हिस्से काटने का है.

def build_frame():
    df_six = "some data"
    def left_of_comma(txt):
        ln = len(txt)
        rng = range(ln)
        sep = ","
        for i in rng:
            if txt[i] == sep:
                pos = i
        return txt[0:pos]
    def right_of_comma(txt):
        ln = len(txt)
        rng = range(ln)
        sep = ","
        for i in rng:
            if txt[i] == sep:
                pos = i
        return txt[pos+1:]
    df_seven["Column Val1"] = df_six.apply(lambda row: left_of_comma(row["Splittable column"]), axis=1)
    df_eight["Column Val2"] = df_seven.apply(lambda row: right_of_comma(row["Splittable column"]), axis=1)
    df_out = base_df_6c.drop("Splittable Colum", axis=1)
    return df_out

What actually goes wrong

Pandas की यह त्रुटि बताती है कि असाइनमेंट का दायाँ हिस्सा एक-आयामी Series की बजाय DataFrame बन रहा है. ऐसा होते ही उसे एक ही कॉलम में असाइन करना वही exception ट्रिगर करता है. row-wise apply और कस्टम स्ट्रिंग स्कैनिंग पर निर्भर रहना इस काम को नाज़ुक बना देता है. एक सरल, वेक्टराइज़्ड तरीका इस तरह के shape mismatch को पूरी तरह टाल देता है और उन पंक्तियों को भी सही ढंग से संभालता है जिनमें एक से अधिक कॉमा हैं.

Solution: split on the last comma with str.rsplit

जब कॉमा कई हो सकते हैं, तो केवल आख़िरी कॉमा पर विभाजन करने के लिए right-split के साथ n=1 का उपयोग करें. पहला भाग व्याख्या बनता है और दूसरा भाग स्थिति. यदि कॉमा के बाद स्पेस हो सकते हैं, तो उन्हें हटा दें.

df["Column Val1"] = df["Splittable column"].str.rsplit(",", n=1).str[0]
df["Column Val2"] = df["Splittable column"].str.rsplit(",", n=1).str[1]

यदि स्पेस हटाने की ज़रूरत हो:

parts = df["Splittable column"].str.rsplit(",", n=1)
df["Column Val1"] = parts.str[0].str.strip()
df["Column Val2"] = parts.str[1].str.strip()

आप दोनों कॉलम एक साथ भी बना सकते हैं, expand=True के साथ, और फिर strip कर सकते हैं:

df[["Column Val1", "Column Val2"]] = (
    df["Splittable column"].str.rsplit(",", n=1, expand=True)
      .apply(lambda s: s.str.strip())
)

End-to-end example

इस डेटासेट में प्रति पंक्ति कई कॉमा हैं, और आख़िरी फ़ील्ड को status होना चाहिए, जबकि उससे पहले की पूरी सामग्री reason के रूप में रहे.

import pandas as pd
sample = {
    "Index": ["1", "2", "3", "4"],
    "Splittable column": [
        ",FALSE",
        "Not Acceptable,Failed,NAN,FALSE",
        "Not acceptable,FALSE",
        ",FALSE",
    ],
}
df_in = pd.DataFrame(sample)
# विकल्प 1: .str एक्सेसर्स को चेन करें
df_in["Column Val1"] = df_in["Splittable column"].str.rsplit(",", n=1).str[0].str.strip()
df_in["Column Val2"] = df_in["Splittable column"].str.rsplit(",", n=1).str[1].str.strip()
# विकल्प 2: एक ही बार में दो कॉलम में expand करें
# df_in[["Column Val1", "Column Val2"]] = (
#     df_in["Splittable column"].str.rsplit(",", n=1, expand=True)
#           .apply(lambda s: s.str.strip())
# )
# अगर ज़रूरत हो, तो मूल टेक्स्ट कॉलम हटा दें
# df_in.drop(columns="Splittable column", inplace=True)
print(df_in)

यह Column Val2 में FALSE जैसे आख़िरी टोकन को बरक़रार रखता है, और Column Val1 में बायाँ हिस्सा, बीच-बीच के कॉमा सहित, जस का तस रखता है.

Why this matters

बड़े पैमाने पर स्ट्रिंग्स को बाँटना आम काम है, लेकिन apply का इस्तेमाल करते समय गलत आयाम वाले ऑब्जेक्ट असाइन करना एक आम जाल है. str.rsplit जैसे वेक्टराइज़्ड स्ट्रिंग मेथड्स (n=1 के साथ) आपकी मंशा सीधे व्यक्त करते हैं, कई कॉमा वाली पंक्तियों को एकसमान तरीके से संभालते हैं, और असाइनमेंट के दौरान shape से जुड़ी अनपेक्षित समस्याएँ ख़त्म करते हैं. साथ में str.strip() जोड़ने से डिलिमिटर के बाद आने वाली अतिरिक्त whitespace भी साफ़ हो जाती है.

Takeaways

कॉलम बाँटते समय row-wise apply की बजाय वेक्टराइज़्ड स्ट्रिंग ऑपरेशनों को प्राथमिकता दें. कई कॉमा वाले इनपुट के लिए str.rsplit(',', n=1) के साथ आख़िरी कॉमा पर स्प्लिट करें, और यदि डिलिमिटर के बाद स्पेस हो सकते हैं तो str.strip() का उपयोग करें. अगर कभी shape mismatch मिले, तो पहले दाएँ हिस्से को किसी अस्थायी वैरिएबल में रखकर उसके type और shape को जाँचें; साथ ही, अपने फ़ंक्शन में जो डेटा भेजते हैं उसे स्पष्ट और सुसंगत रखना भी अप्रत्याशित व्यवहार से बचाएगा.