2025, Oct 08 01:31

Polars v1.32+ में map_batches UDF के int8 arrays के लिए सही return_dtype

Polars v1.32+ में map_batches UDF के int8 arrays के लिए सही return_dtype कैसे दें: फिक्स्ड आकार पर pl.Array(pl.Int8, size), वरना pl.List(pl.Int8). त्रुटियों से बचें

Polars v1.32+ में arrays लौटाने वाले map_batches UDFs की सही टाइपिंग

समस्या

जब आप Polars डेटाफ़्रेम पर map_batches के माध्यम से किसी उपयोक्ता‑परिभाषित फ़ंक्शन (UDF) को लागू करते हैं, तो फ़ंक्शन int8 प्रकार का एक array लौटाता है। Polars v1.32 से map_batches के लिए return_dtype आर्ग्युमेंट अनिवार्य हो गया है। पहली नजर में return_dtype=pl.Array[pl.Int8] जैसा प्रयास काम नहीं करता। इस बदलाव से पहले स्कीमा में पहले से shape की जानकारी रहती थी, उदाहरण के लिए:

Schema([(...),
        ('signals', Array(Int8, shape=(9,)))])

'signals' कॉलम के मान एक ऐसे UDF से बनते हैं जो numpy array लौटाता है, और इस UDF को समूहों पर भी लागू किया जा सकता है।

कोड में समस्या दोहराना

नीचे दिया गया पैटर्न समस्या को दिखाता है। UDF dtype int8 का numpy array बनाता है, और map_batches को स्क्वेयर‑ब्रैकेट [] सिंटैक्स से array प्रकार लौटाने को कहा जाता है—लेकिन यह विफल हो जाता है:

import polars as pl
# dtype int8 वाला एक numpy array लौटाता है
def build_vector(batch):
    ...
# रिटर्न वैल्यू का गलत टाइपिंग
result = frame.with_columns(
    pl.col("signals").map_batches(build_vector, return_dtype=pl.Array[pl.Int8])
)

यह क्यों होता है

Polars दो तरह के नेस्टेड टाइप्स अलग-अलग रखता है: Array और List। Array एक फिक्स्ड‑साइज़, टाइप किया हुआ array है, जिसमें अंदरूनी dtype के साथ‑साथ सटीक लंबाई देना जरूरी होता है। List एक वैरिएबल‑लेंथ, टाइप की हुई सूची है। Polars v1.32 और उसके बाद के संस्करणों में map_batches को स्पष्ट और पूर्ण return_dtype चाहिए—Array के मामले में इसका मतलब है कि आपको तत्व का प्रकार और निश्चित आकार दोनों बताने होंगे। pl.Array[pl.Int8] देने से निश्चित आकार नहीं मिलता, इसलिए यह मान्य नहीं है। List को Array के स्थान पर रखना समान नहीं है, और जहाँ Array अपेक्षित है वहाँ List देने पर त्रुटि आती है:

polars.exceptions.InvalidOperationError: expected Array type, got: list[i8]

समाधान

जब UDF एक निश्चित आकार का array लौटाता है, तो polars.datatypes.Array के साथ array की लंबाई स्पष्ट रूप से बताएं। सिंटैक्स है: pl.Array(inner_dtype, size)। तीन int8 तत्वों वाले array के लिए यह इस तरह दिखेगा:

import polars as pl
# निश्चित लंबाई वाला dtype int8 का numpy array लौटाता है
def build_vector(batch):
    ...
out_type = pl.Array(pl.Int8, 3)
fixed = frame.with_columns(
    pl.col("signals").map_batches(build_vector, return_dtype=out_type)
)

यदि आपके डेटा में निश्चित लंबाई 9 है, तो size को 9 रखें ताकि वह उस स्कीमा से मेल खाए जो Array(Int8, shape=(9,)) जैसा दिखता था।

जब लंबाई पहले से ज्ञात न हो, तो आउटपुट को Array की जगह int8 वाली List के रूप में टाइप करें:

import polars as pl
# परिवर्तनीय लंबाई वाला dtype int8 का numpy array लौटाता है
def build_vector(batch):
    ...
list_type = pl.List(pl.Int8)
variable = frame.with_columns(
    pl.col("signals").map_batches(build_vector, return_dtype=list_type)
)

ध्यान रहे, List और Array अलग प्रकार हैं। यदि आगे की किसी प्रक्रिया को Array चाहिए और उसे List मिलती है, तो Polars उसी तरह की त्रुटि बताएगा जैसा ऊपर दिखाया गया।

यह क्यों मायने रखता है

v1.32+ में map_batches के लिए Polars को रिटर्न टाइप स्पष्ट चाहिए, और Array जैसे नेस्टेड टाइप्स को पूरी तरह परिभाषित करना होता है। इससे स्कीमा में अस्पष्टता नहीं रहती और UDF का व्यवहार पूर्वानुमेय बनता है—खासकर तब, जब UDFs numpy arrays लौटाते हैं और गणनाएँ समूहों पर चलती हैं।

मुख्य बातें

यदि आपका UDF फिक्स्ड‑साइज़ वाले int8 arrays बनाता है, तो सटीक लंबाई के साथ return_dtype को pl.Array(pl.Int8, size) पर सेट करें। लंबाई तय न हो तो pl.List(pl.Int8) अपनाएँ, और यह भी सुनिश्चित करें कि आगे की एक्सप्रेशंस Array नहीं, List की अपेक्षा करें। अपग्रेड के बाद स्कीमा की जाँच कर लें ताकि वह डाउनस्ट्रीम लॉजिक की ज़रूरतों से मेल खाए।

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