मुख्य सामग्री पर जाएँ

Python Polars ट्यूटोरियल: शुरुआती लोगों के लिए सम्पूर्ण मार्गदर्शिका

इस शुरुआती ट्यूटोरियल में जानें कि Python में Polars का उपयोग कैसे करें।
· 11 मि॰ पढ़ें

AI के साथ खोजें

डेटा विश्लेषण की दुनिया में, pandas लंबे समय से Python में टेबलर डेटा संभालने के लिए डेटा प्रोफेशनल्स की डिफॉल्ट पसंद रहा है. 

लेकिन जैसे-जैसे डेटासेट का आकार और जटिलता बढ़ती है, pandas को प्रदर्शन में रुकावटें, मल्टी-कोर का सीमित उपयोग, और मेमोरी से जुड़ी पाबंदियों का सामना करना पड़ सकता है।

यहीं पर Polars एक आधुनिक विकल्प के रूप में उभरता है। Polars एक DataFrame लाइब्रेरी है जो Rust में लिखी गई है और बेहद तेज़ प्रदर्शन, कुशल मेमोरी प्रबंधन, तथा स्केलेबिलिटी पर केंद्रित डिजाइन दर्शन प्रदान करती है।

इस ट्यूटोरियल में, हम साझा करेंगे कि Polars क्या है और Python में कुछ बुनियादी Polars ऑपरेशंस कैसे करें। यदि आप व्यावहारिक अनुभव चाहते हैं, तो मैं Introduction to Polars कोर्स देखने की सलाह देता/देती हूँ।

Python Polars की मुख्य विशेषताएँ

python polars

Polars ऐसी विशिष्ट खूबियाँ प्रदान करता है जो उसे pandas से अलग बनाती हैं:

  • Rust आधार: सिस्टम-स्तरीय सुरक्षा और प्रदर्शन।
  • मल्टी-थ्रेडेड निष्पादन: आधुनिक CPU का पूरा उपयोग।
  • लेज़ी इवैल्यूएशन: जरूरत पड़ने पर ही निष्पादन।
  • स्कीमा प्रवर्तन: सुसंगत डेटा हैंडलिंग सुनिश्चित करता है।
  • उन्नत डेटा टाइप सपोर्ट: समय-संबंधी, श्रेणीबद्ध, और नेस्टेड टाइप्स को नैटिव रूप से संभालता है।

Polars में डेटा टाइप्स

Polars बुनियादी प्रकारों से आगे बढ़कर कई तरह के डेटा टाइप्स सपोर्ट करता है:

  • न्यूमेरिक: Int32, Int64, Float32, Float64.
  • बूलियन: true/false मान।
  • टेम्पोरल: Date, Datetime, Duration, Time.
  • श्रेणीबद्ध: स्मृति-कुशल भंडारण के लिए एन्कोडेड स्ट्रिंग्स।
  • नेस्टेड: List और Struct टाइप्स, JSON-जैसे डेटा के लिए उपयोगी।

pandas पर लाभ

pandas के नए और अधिक आधुनिक विकल्प के रूप में, Polars कई फायदे देता है:

  • बड़े डेटासेट पर तेज़ निष्पादन।
  • अधिक मेमोरी-कुशल।
  • ETL पाइपलाइन्स और प्रोडक्शन के लिए बेहतर अनुकूल।
  • प्रेडिकेट और प्रोजेक्शन पुशडाउन जैसी बिल्ट-इन ऑप्टिमाइज़ेशन।

Python Polars के लिए इंस्टॉलेशन और पर्यावरण सेटअप

अब देखते हैं कि Python में Polars का उपयोग हम खुद कैसे शुरू कर सकते हैं।

Polars का उपयोग करने से पहले, आपको पर्यावरण को सही ढंग से सेटअप करना होगा।

समर्थित प्लेटफ़ॉर्म

Polars Windows, macOS और Linux को सपोर्ट करता है। इसे वर्चुअल एन्वायरनमेंट, सिस्टम Python, या कंटेनराइज्ड वर्कफ़्लो (Docker) के जरिए इंस्टॉल किया जा सकता है।

pip के साथ इंस्टॉलेशन

Python में polars लाइब्रेरी इंस्टॉल करने के लिए, टर्मिनल में निम्नलिखित कमांड चलाएँ।

pip install polars

आपको निम्नलिखित इंस्टॉलेशन संदेश दिखाई देना चाहिए:

installation message

conda के साथ इंस्टॉलेशन

वैकल्पिक रूप से, यदि आप conda एन्वायरनमेंट में काम कर रहे हैं, तो आप वहीं लाइब्रेरी इंस्टॉल कर सकते हैं।

conda install -c conda-forge polars

इंस्टॉलेशन सत्यापित करें

जाँचने के लिए कि इंस्टॉलेशन सफल रहा है या नहीं, निम्न सरल स्क्रिप्ट लिखें:

import polars as pl
print(pl.__version__)

कॉन्फ़िगरेशन और पर्यावरण वेरिएबल्स

Polars आपको अपने Python सत्र शुरू करने से पहले पर्यावरण वेरिएबल्स सेट करके इसके रन होने और आउटपुट दिखाने के तरीकों को ट्यून करने देता है। उदाहरण के लिए:

  • POLARS_MAX_THREADS: थ्रेड्स की संख्या सीमित करें।
  • POLARS_FMT_MAX_COLS: प्रिंट होने वाले कॉलम्स की संख्या नियंत्रित करें।
  • POLARS_FMT_TABLE_WIDTH: DataFrame डिस्प्ले चौड़ाई समायोजित करें।

यहाँ एक उदाहरण है कि Python चलाने से पहले शेल में आप ये वेरिएबल्स कैसे सेट करेंगे:

export POLARS_MAX_THREADS=8
export POLARS_FMT_MAX_COLS=20

प्रदर्शन हेतु एक नमूना CSV डेटासेट बनाना

Polars की विशेषताओं में उतरने से पहले, ऐसा डेटासेट होना उपयोगी है जिसे हम पूरे ट्यूटोरियल में एक समान रूप से उपयोग कर सकें। हम Python के बिल्ट-इन csv मॉड्यूल या pandas का उपयोग करके एक सरल CSV फ़ाइल बना सकते हैं। 

यहाँ एक उदाहरण है जो सिंथेटिक डेटा के साथ transactions.csv फ़ाइल बनाता है:

import csv
import random
from datetime import datetime, timedelta

# Define column names
columns = ["transaction_id", "customer_id", "amount", "transaction_date"]

# Generate synthetic rows
rows = []
start_date = datetime(2023, 1, 1)
for i in range(1, 101):
    customer_id = random.randint(1, 10)
    amount = round(random.uniform(10, 2000), 2)
    date = start_date + timedelta(days=random.randint(0, 90))
    rows.append([i, customer_id, amount, date.strftime("%Y-%m-%d")])

# Write to CSV
with open("transactions.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(columns)
    writer.writerows(rows)

यह स्क्रिप्ट 100 ट्रांज़ैक्शंस का एक डेटासेट बनाती है जिसमें रैंडम अमाउंट, कस्टमर आईडी, और ट्रांज़ैक्शन तारीखें होती हैं। आप अपनी ज़रूरत के अनुसार रेंज और आकार समायोजित कर सकते हैं। 

इस स्क्रिप्ट को सेव करें, एक बार चलाएँ, और इस लेख के उदाहरणों में उपयोग के लिए आपके पास एक CSV फ़ाइल होगी।

Python Polars DataFrames और Series में मुख्य अवधारणाएँ

Polars दो मुख्य एब्स्ट्रैक्शंस पर बना है: Series और DataFrame. 

मिलकर, ये डेटा के साथ काम करने का संरचित और कुशल तरीका प्रदान करते हैं—आत्मा में pandas जैसा, लेकिन Polars के Rust-पावर्ड बैकएंड से ऑप्टिमाइज़्ड। आइए मुख्य अवधारणाओं को समझते हैं।

Series: परिभाषित टाइप वाले 1D एरे

Polars में Series एक एक-आयामी एरे है, जो स्प्रेडशीट या डेटाबेस टेबल के कॉलम जैसा होता है। प्रत्येक Series में होता है:

  • एक नाम (कॉलम लेबल)।
  • एक डेटा टाइप (जैसे Int64, Utf8, Float64, Boolean आदि)।
  • मानों का एक ऑर्डर्ड कलेक्शन।

क्योंकि डेटा टाइप सख्ती से लागू होता है, Polars की Series आमतौर पर Python लिस्ट्स की तुलना में तेज़ और अधिक प्रेडिक्टेबल होती हैं।

उदाहरण:

import polars as pl
# Create a Series of integers
s = pl.Series("numbers", [1, 2, 3, 4, 5])
print(s)

आउटपुट:

shape: (5,)
Series: 'numbers' [i64]
[
    1
    2
    3
    4
    5
]

DataFrame: सीरीज़ का कलेक्शन

DataFrame एक द्वि-आयामी संरचना है जो कई Series को एक स्कीमा के अंतर्गत व्यवस्थित करता है। संकल्पना में, यह SQL या Excel में टेबल जैसा है। रो रिकॉर्ड्स का प्रतिनिधित्व करते हैं, और कॉलम फील्ड्स का।

उदाहरण:

df = pl.DataFrame({
    "id": [1, 2, 3],
    "name": ["Alice", "Bob", "Charlie"],
    "age": [25, 30, 35]
})
print(df)

आउटपुट:

shape: (3, 3)
┌─────┬─────────┬─────┐
│ id  │ name    │ age │
│ --- │ ---     │ --- │
│ i64 │ str     │ i64 │
├─────┼─────────┼─────┤
│ 1   │ Alice   │ 25  │
│ 2   │ Bob     │ 30  │
│ 3   │ Charlie │ 35  │
└─────┴─────────┴─────┘

हर कॉलम एक Series है, और DataFrame अपना स्कीमा लागू करता है।

स्कीमा की भूमिका और सख्त टाइप सुसंगति

Polars की ताकतों में से एक है सख्त स्कीमा प्रवर्तन। प्रत्येक कॉलम का एक फिक्स्ड डेटा टाइप होता है, और Polars सुनिश्चित करता है कि सभी ऑपरेशंस उसका सम्मान करें। यह डायनामिकली टाइप्ड ऑपरेशंस से आने वाली सूक्ष्म बग्स को रोकता है।

उदाहरण के लिए, आप किसी स्ट्रिंग कॉलम को इंटीजर कॉलम में बिना स्पष्ट रूपांतरण के नहीं जोड़ सकते।

उदाहरण:

df = df.with_columns(
    (pl.col("age") + 5).alias("age_plus_5")
)
print(df)

यहाँ, age i64 है, और परिणाम इंटीजर ही रहता है। यदि आप किसी स्ट्रिंग कॉलम को जोड़ने की कोशिश करेंगे, तो Polars चुपचाप फेल होने के बजाय त्रुटि देगा।

नल हैंडलिंग

वास्तविक दुनिया के डेटा में अक्सर मिसिंग वैल्यूज़ होती हैं, और Polars उन्हें संभालने के लिए स्पष्ट टूल्स देता है:

  • fill_null(): नल्स को दिए गए मान से बदलें।
  • drop_nulls(): नल्स वाली रो को हटाएँ।
  • is_null() / is_not_null(): बूलियन जाँचें।

एक्सप्रेशंस: वेक्टराइज़्ड कॉलम ऑपरेशंस

Polars एक एक्सप्रेशन सिस्टम को बढ़ावा देता है, जहाँ ऑपरेशंस पंक्ति-दर-पंक्ति Python लूप्स के बजाय कॉलम पर ट्रांसफॉर्मेशन के रूप में परिभाषित होते हैं। 

ये एक्सप्रेशंस वेक्टराइज़्ड होते हैं, यानी वे पूरे कॉलम पर एक साथ काम करते हैं, जो कहीं अधिक तेज़ है।

मैन्युअल लूपिंग के बजाय, Polars तेज़ वेक्टराइज़्ड गणना बनाता है।

Eager बनाम Lazy निष्पादन

Polars दो मोड में निष्पादन प्रदान करता है:

1. Eager निष्पादन

  • कम्प्यूटेशन तुरंत चलते हैं।
  • pandas जैसा।
  • इंटरैक्टिव एक्सप्लोरेशन और छोटे-से-मध्यम डेटासेट के लिए शानदार।

यहाँ eager निष्पादन का एक उदाहरण है:

df = pl.DataFrame({"x": [1, 2, 3]})
print(df.select(pl.col("x") * 2))  # eager: runs instantly

2. Lazy निष्पादन

  • तुरंत निष्पादन के बजाय एक क्वेरी प्लान बनता है।
  • Polars इस प्लान को अंदर-ही-अंदर ऑप्टिमाइज़ करता है (प्रेडिकेट पुशडाउन, पैरेललाइज़ेशन, प्रोजेक्शन प्रूनिंग)।
  • बड़े डेटासेट और जटिल ट्रांसफॉर्मेशन के लिए आदर्श।

यहाँ lazy निष्पादन का एक उदाहरण है:

lazy_df = pl.DataFrame({"x": [1, 2, 3]}).lazy()
result = lazy_df.select(pl.col("x") * 2).collect()  # execute on collect()
print(result)

यहाँ, .collect() बुलाने तक कुछ भी कंप्यूट नहीं होता। बड़े वर्कफ़्लो में, इससे प्रदर्शन में नाटकीय सुधार हो सकता है।

Python Polars में बुनियादी DataFrame ऑपरेशंस

अब हम उस डेटासेट पर Polars में उपयोग होने वाले कुछ बुनियादी ऑपरेशंस करेंगे जिसे हमने बनाया था।

डेटासेट लोड करना

Polars कई फाइल फ़ॉर्मेट्स और मेमोरी ऑब्जेक्ट्स से डेटा इनजेस्ट कर सकता है। यह आधुनिक डेटा पाइपलाइन्स में इंटीग्रेशन के लिए लचीला बनाता है।

विभिन्न स्रोतों के लिए आप यह ऐसे कर सकते हैं:

पहले बनाए गए CSV डेटासेट से:

import polars as pl

df = pl.read_csv("transactions.csv")
print(df.head())

हम आवश्यकता होने पर Parquet से भी डेटासेट पढ़ सकते हैं।

df_parquet = pl.read_parquet("transactions.parquet")

यदि आपके पास JSON फ़ाइल है, तो आप इसे इस कोड से पढ़ सकते हैं:

df_json = pl.read_json("transactions.json")
#For JSON Lines (NDJSON), use the following instead:
df_json = pl.read_ndjson("transactions.json")

यहाँ बताया गया है कि Arrow Table से डेटासेट कैसे पढ़ें:

import pyarrow as pa

arrow_table = pa.table({
    "transaction_id": [1, 2],
    "customer_id": [5, 7],
    "amount": [150.25, 300.75],
    "transaction_date": ["2023-01-02", "2023-01-03"]
})
df_arrow = pl.from_arrow(arrow_table)

सेलेक्टिंग और फ़िल्टरिंग

अब अपने डेटासेट से विशिष्ट कॉलम या रो चुनते हैं।

कॉलम चुनें

Polars का उपयोग करते समय, एक सामान्य ऑपरेशन उन कॉलम्स का चयन करना है जिन पर आप काम करना चाहते हैं और उन्हें रखना है। 

यहाँ ऐसा कैसे कर सकते हैं:

# Select only transaction_id and amount
df.select(["transaction_id", "amount"])

रो फ़िल्टर करें

आप pandas की तरह अपनी शर्तों के आधार पर रो फ़िल्टर कर सकते हैं।

# Get only high-value transactions above $1,000
high_value = df.filter(pl.col("amount") > 1000)
print(high_value)

एक्सप्रेशन लागू करें

Polars में एक्सप्रेशंस लागू करना डेटा ट्रांसफॉर्मेशन करने के लिए विभिन्न संदर्भों में polars.Expr ऑब्जेक्ट का उपयोग करना शामिल है।

आप इन्हें pl.col() या pl.lit() से बना सकते हैं।

# Add a 10% discount column to simulate promotional pricing
df.select([
    pl.col("transaction_id"),
    pl.col("amount"),
    (pl.col("amount") * 0.9).alias("discounted_amount")
])

एग्रीगेशन

हम group_by का उपयोग करके कस्टमर के हिसाब से खर्च पैटर्न का विश्लेषण कर सकते हैं।

# Total and average spend per customer
agg_df = df.group_by("customer_id").agg([
    pl.sum("amount").alias("total_spent"),
    pl.mean("amount").alias("avg_transaction")
])
print(agg_df)

नमूना आउटपुट:

shape: (10, 3)
┌─────────────┬────────────┬───────────────┐
│ customer_id │ total_spent│ avg_transaction│
│ ---         │ ---        │ ---           │
│ i64         │ f64        │ f64           │
├─────────────┼────────────┼───────────────┤
│ 1           │ 5230.12    │ 523.01        │
│ 2           │ 6120.45    │ 680.05        │
│ ...         │ ...        │ ...           │
└─────────────┴────────────┴───────────────┘

मिसिंग वैल्यूज़ को संभालना

हमारे जेनरेट किए गए डेटासेट में डिफॉल्ट रूप से नल नहीं हैं, लेकिन देखते हैं कि हम उन्हें कैसे हैंडल करेंगे।

मिसिंग वैल्यू भरें

मिसिंग वैल्यूज़ डाउनस्ट्रीम विश्लेषण और डेटा विज़ुअलाइज़ेशन में समस्याएँ पैदा कर सकती हैं। चीज़ों को सुचारू रखने के लिए आपको किसी भी मिसिंग वैल्यू को भरना होगा।

यहाँ मिसिंग वैल्यू भरने का तरीका है:

# Imagine 'amount' has missing values, then replace with 0
df_filled = df.with_columns(
    pl.col("amount").fill_null(0)
)

नल्स हटाएँ

यदि नल्स को हैंडल नहीं किया गया तो वे त्रुटियाँ पैदा कर सकते हैं। उन्हें हटाने का तरीका यहाँ है:

df_no_nulls = df.drop_nulls()

टाइप्स कन्वर्ट करें

किसी डेटासेट में डेटा टाइप्स गलत फॉर्मेट में हो सकते हैं। .cast मेथड का उपयोग करके आप उन्हें ऐसे कन्वर्ट कर सकते हैं:

# Ensure customer_id is treated as string instead of int
df_casted = df.with_columns(
    pl.col("customer_id").cast(pl.Utf8)
)

ऑपरेशंस चेन करना

Polars क्लीनर वर्कफ़्लोज़ के लिए मेथड चेनिंग की अनुमति देता है। यह चेनिंग तरीका आमतौर पर SQL या R प्रोग्रामिंग में tidyverse पैकेज का उपयोग करके किया जाता है।

उदाहरण: मार्च में कुल खर्च के आधार पर शीर्ष कस्टमर ढूंढें

pipeline = (
    df
   .with_columns(pl.col("transaction_date").str.strptime(pl.Date, format="%Y-%m-%d"))
    #.col("date_str").str.to_date(format="%Y-%m-%d")
    .filter(pl.col("transaction_date").dt.month() == 3)  # transactions in March
    .group_by("customer_id")
    .agg(pl.sum("amount").alias("march_spent"))
    .sort("march_spent", descending=True)
)
print(pipeline)

यह पाइपलाइन:

  1. मार्च के ट्रांज़ैक्शंस को फ़िल्टर करती है।
  2. कस्टमर के आधार पर ग्रुप करती है।
  3. खर्च को एग्रीगेट करती है।
  4. कुल खर्च के अनुसार सॉर्ट करती है।

यह चेनिंग तरीका इंटरमीडिएट DataFrames का उपयोग किए बिना पाइपलाइन विश्लेषण करने देता है।

Polars में उन्नत विशेषताएँ और लेज़ी इवैल्यूएशन

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

डिफॉल्ट रूप से, Polars eager मोड में चलता है। इसका मतलब है कि कम्प्यूटेशन तुरंत होते हैं, pandas के समान। हालाँकि लेज़ी मोड अलग तरह से काम करता है:

  • हर ऑपरेशन (filter, select, group_by) तुरंत चलने के बजाय रिकॉर्ड होता है।
  • ट्रांसफॉर्मेशन केवल तब निष्पादित होते हैं जब आप .collect() कॉल करते हैं।
  • यह कार्य को तब तक टाल देता है जब तक Polars पूरी पाइपलाइन का विश्लेषण करके उसे सबसे कुशल तरीके से चला न सके।

यहाँ लेज़ी मोड का उदाहरण है:

import polars as pl

# Load dataset in lazy mode
lazy_df = pl.scan_csv("transactions.csv")

# Build a transformation pipeline
pipeline = (
    lazy_df
    .filter(pl.col("amount") > 1000)                # step 1: filter expensive transactions
    .group_by("customer_id")                         # step 2: group by customer
    .agg(pl.sum("amount").alias("total_spent"))     # step 3: aggregate
)

# Nothing has run yet, computation happens only on collect()
result = pipeline.collect()
print(result)

क्वेरी ऑप्टिमाइज़ेशन

Polars पुशडाउन तकनीकों को लागू करके क्वेरीज़ को ऑप्टिमाइज़ करता है:

  1. प्रेडिकेट पुशडाउन: फ़िल्टर्स को डेटा स्रोत के जितना संभव हो उतना करीब धकेला जाता है। उदाहरण: जब amount > 1000 पर फ़िल्टर किया जाता है, तो Polars सभी रो लोड करने के बाद के बजाय CSV पढ़ते समय ही वह फ़िल्टर लागू करता है।
  2. प्रोजेक्शन पुशडाउन: केवल वे कॉलम मेमोरी में पढ़े जाते हैं जिनकी आपको ज़रूरत है। उदाहरण: यदि आप केवल customer_id और amount चुनते हैं, तो Polars transaction_date को पढ़ना पूरी तरह छोड़ देता है।

बड़े डेटा के लिए स्ट्रीमिंग

जब डेटा मेमोरी में फिट होने के लिए बहुत बड़ा हो, तो Polars स्ट्रीमिंग निष्पादन प्रदान करता है। सब कुछ एक साथ लोड करने के बजाय, Polars डेटा को बैचेज़ में प्रोसेस करता है और मेमोरी उपयोग स्थिर रखता है।

यह विशेष रूप से मल्टी-GB CSV या Parquet फाइलों के लिए उपयोगी है।

उदाहरण (स्ट्रीमिंग मोड):

# Enable streaming execution for huge datasets
stream_result = (
    lazy_df
    .group_by("customer_id")
    .agg(pl.sum("amount").alias("total_spent"))
    .collect(streaming=True)   # execute in streaming mode
)

streaming=True के साथ, Polars विशाल इन-मेमोरी इंटरमीडिएट टेबल्स बनाने से बचता है, जिससे यह बड़े वर्कलोड्स के लिए pandas की तुलना में अधिक स्केलेबल बनता है।

.collect() के साथ निष्पादन और लेज़ी क्वेरीज़ को डिबग करना

.collect() मेथड लेज़ी पाइपलाइन को निष्पादित करने का ट्रिगर है। उससे पहले, आप निम्न से क्वेरी प्लान का निरीक्षण और डिबग कर सकते हैं:

  • .describe_plan(): लॉजिकल प्लान दिखाता है।
  • .describe_optimized_plan(): पुशडाउन और सरलीकरण लागू होने के बाद ऑप्टिमाइज़्ड प्लान दिखाता है।

Python Polars के प्रदर्शन और दक्षता का अनुकूलन

Polars आपके विश्लेषण पाइपलाइन्स के प्रदर्शन को बढ़ाने में मदद कर सकता है।

कुछ सर्वोत्तम प्रथाएँ इस प्रकार हैं:

  • बड़ी पाइपलाइन्स के लिए लेज़ी इवैल्यूएशन का उपयोग करें।
  • टाइप कास्टिंग को न्यूनतम रखें।
  • अनावश्यक इंटरमीडिएट DataFrames का मैटेरियलाइज़ेशन न करें।

Python Polars में जॉइन्स, मर्जिंग, और डेटा संयोजन

वास्तविक दुनिया के विश्लेषण में अक्सर डेटासेट्स को मिलाने की ज़रूरत होती है। Polars ऑप्टिमाइज़्ड निष्पादन के साथ जॉइन ऑपरेशंस का पूरा सूट प्रदान करता है, जिससे बड़ी टेबल्स को मर्ज करना आसान हो जाता है।

समर्थित जॉइन्स

Polars सभी प्रमुख जॉइन प्रकारों को सपोर्ट करता है:

  • इनर जॉइन: केवल मैच हुई रो रखें।
  • लेफ़्ट / राइट जॉइन: एक तरफ की सभी रो रखें।
  • आउटर जॉइन: सभी रो रखें, मिसिंग को नल से भरें।
  • सेमी जॉइन: लेफ़्ट की वे रो रखें जिनका राइट में मैच है।
  • एंटी जॉइन: लेफ़्ट की वे रो रखें जिनका राइट में कोई मैच नहीं है।
  • क्रॉस जॉइन: दोनों टेबल्स का कार्टेशियन प्रोडक्ट।

उदाहरण: ट्रांज़ैक्शंस को कस्टमर मेटाडेटा के साथ जोड़ना

# Create customer metadata DataFrame
customers = pl.DataFrame({
    "customer_id": [1, 2, 3, 4, 5],
    "customer_name": ["Alice", "Bob", "Charlie", "David", "Eva"]
})

# Inner join on customer_id
df_joined = df.join(customers, on="customer_id", how="inner")
print(df_joined.head())

प्रदर्शन और उपयोगिता के लिए Polars बनाम Pandas जॉइन

दोनों क्षेत्रों में Polars, Pandas से बेहतर है:

  • प्रदर्शन: Polars जॉइन Rust में पैरेललिज़्म के साथ इम्प्लीमेंटेड हैं, जिससे बड़े डेटासेट्स पर वे pandas से तेज़ हैं। प्रेडिकेट और प्रोजेक्शन पुशडाउन जॉइन्स पर भी लागू होते हैं, जिससे अनावश्यक डेटा मूवमेंट घटता है।
  • उपयोगिता: Polars में स्पष्ट जॉइन कीज़ की आवश्यकता होती है, जो इंडेक्स एलाइनमेंट पर आकस्मिक जॉइन से बचाता है (pandas में एक आम समस्या)। सेमी और एंटी जॉइन्स Polars में नैटिव हैं, जबकि pandas में उनके लिए वर्कअराउंड चाहिए।

Polars में विंडो फ़ंक्शंस और रोलिंग ऑपरेशंस

विंडो फ़ंक्शंस समूहों के भीतर या ऑर्डर्ड रो पर बिना परिणामों को समेटे गणनाएँ करने देते हैं, SQL विंडो फ़ंक्शंस के समान।

Polars विंडो कॉन्टेक्स्ट्स का उपयोग करके प्रति कस्टमर या प्रति समयावधि आँकड़े निकालने देता है।

यहाँ कुछ उदाहरण हैं जिन विंडो फ़ंक्शंस का आप Polars में उपयोग कर सकते हैं:

  • रोलिंग मीन/सम मूविंग एवरेज के लिए।
  • एक्सपैंडिंग विंडोज़ संचयी आँकड़ों के लिए।
  • रैंकिंग फ़ंक्शंस क्रम-आधारित एनालिटिक्स के लिए।

1. रनिंग फ़ंक्शंस

उदाहरण: कस्टमर रनिंग टोटल्स

df_window = df.with_columns( pl.col("amount") .sort_by("transaction_date") .cum_sum() .over("customer_id") .alias("running_total") )
print(df_window.head())

2. रोलिंग फ़ंक्शंस

रोलिंग फ़ंक्शंस रो या समय की स्लाइडिंग विंडो पर काम करते हैं।

उदाहरण: 7-दिन का रोलिंग ट्रांज़ैक्शन सम

df = df.with_columns(pl.col("transaction_date").str.strptime(pl.Date, format="%Y-%m-%d")
rolling = (
    df.group_by_rolling("transaction_date", period="7d")
      .agg(pl.sum("amount").alias("rolling_7d_sum"))
)
print(rolling.head())

एक्सपैंडिंग विंडोज़ (क्यूम्युलेटिव) और सेंटर-अलाइंड विंडोज़ भी पैरामीटर्स समायोजित करके सपोर्टेड हैं।

3. रैंकिंग फ़ंक्शंस

आप विंडोज़ के भीतर रैंकिंग फ़ंक्शंस और कस्टम एग्रीगेशन का उपयोग कर सकते हैं।

उदाहरण: कस्टमर-वार अमाउंट के आधार पर ट्रांज़ैक्शंस की रैंकिंग

ranked = df.with_columns(
    pl.col("amount").rank("dense", descending=True).over("customer_id").alias("rank")
)
print(ranked.head())

यह प्रत्येक कस्टमर के खर्च की रैंकिंग (1 = उच्चतम) देता है।

विंडो फ़ंक्शंस प्रसंगानुसार गणनाएँ करने देते हैं:

print(
    df.group_by("customer_id").agg(pl.col("amount").cum_sum().alias("cumulative_spent"))
)

Python Polars में SQL क्वेरीज़ का उपयोग

SQL के आदी विश्लेषकों के लिए, Polars एक SQL कॉन्टेक्स्ट प्रदान करता है ताकि आप SQL सिंटैक्स से सीधे DataFrames को क्वेरी कर सकें, और फिर भी Polars की गति का लाभ उठा सकें।

SQL कॉन्टेक्स्ट और DataFrame रजिस्ट्रेशन

शुरू करने के लिए, SQL चलाने से पहले आपको एक DataFrame रजिस्टर करना होगा।

from polars import SQLContext

ctx = SQLContext()
ctx.register("transactions", df)

Polars में सीधे SQL क्वेरी चलाना

आइए देखें कि Python में Polars का उपयोग करके SQL क्वेरी कैसे चलाई जाती है।

उदाहरण: SQL में प्रति कस्टमर कुल खर्च क्वेरी करना

result = ctx.execute("""
    SELECT customer_id, SUM(amount) AS total_spent
    FROM transactions
    GROUP BY customer_id
    ORDER BY total_spent DESC
""").collect()

print(result)

SQL को Polars एक्सप्रेशंस के साथ एकीकृत करना

आप SQL और एक्सप्रेशंस को मिला सकते हैं:

sql_result = ctx.execute("SELECT * FROM transactions WHERE amount > 1500")
df_sql = sql_result.collect()

# Continue with Polars expressions
df_sql = df_sql.with_columns((pl.col("amount") * 0.95).alias("discounted"))

यह SQL-आधारित टूल्स से ट्रांज़िशन कर रही टीमों के लिए उपयोगी है।

विस्तृत इकोसिस्टम के साथ Python Polars का एकीकरण

Polars एक स्टैंडअलोन द्वीप नहीं, बल्कि एक हाई-परफॉर्मेंस DataFrame लाइब्रेरी के रूप में डिज़ाइन किया गया है जो व्यापक Python डेटा इकोसिस्टम के साथ अच्छी तरह काम करता है। यह इंटरऑपरेबिलिटी सुनिश्चित करती है कि विश्लेषक और इंजीनियर मौजूदा टूल्स का लाभ उठाते हुए Polars को चरणबद्ध तरीके से अपना सकें।

इंटीग्रेशन के कुछ क्षेत्र इस प्रकार हैं:

  • पैकेज इंटरऑप: Polars, pandas, NumPy, Arrow के बीच आसानी से कन्वर्ट करें।
  • विज़ुअलाइज़ेशन: matplotlib, seaborn, या plotly से चार्टिंग करें।
  • मशीन लर्निंग: Polars DataFrames को scikit-learn, PyTorch, या TensorFlow पाइपलाइन्स में फ़ीड करें।
  • क्लाउड और DB: Parquet, Arrow के साथ कुशल I/O, और क्लाउड स्टोरेज कनेक्टर्स।
  • Jupyter नोटबुक्स: Polars इंटरएक्टिव एन्वायरनमेंट्स में सुचारू रूप से इंटीग्रेट होता है।

Python Polars उदाहरण और सामान्य उपयोग के मामले

अंत में, देखते हैं कि Polars के कुछ उपयोग के उदाहरण:

1. डेटा क्लीनिंग

df = df.with_columns([
    pl.col("transaction_date").str.strptime(pl.Date, "%Y-%m-%d").alias("txn_date"),
    pl.col("amount").fill_null(strategy="mean")
])

2. ETL पाइपलाइन्स

result = (
    pl.read_csv("transactions.csv")
      .lazy()
      .filter(pl.col("amount") > 1000)
      .group_by("customer_id")
      .agg(pl.sum("amount").alias("total_spent"))
      .collect()
)

3. फ़ाइनेंस

यहाँ ट्रांज़ैक्शन अमाउंट्स के लिए रोलिंग एवरेज का उदाहरण है।

import polars as pl

# Load & parse dates
df = (
    pl.read_csv("transactions.csv")
    .with_columns(pl.col("transaction_date").str.strptime(pl.Date, "%Y-%m-%d"))
)

# (A) Overall: daily totals + 7-day rolling average
daily = (
    df.sort("transaction_date")
      .group_by_dynamic("transaction_date", every="1d")
      .agg(pl.sum("amount").alias("daily_total"))
      .sort("transaction_date")
      .with_columns(
          pl.col("daily_total").rolling_mean(window_size=7).alias("ma7")
      )
)

# (B) Per-customer: daily totals + 7-day rolling average within each customer
daily_by_cust = (
    df.sort("transaction_date")
     .group_by_dynamic(index_column="transaction_date", every="1d", by="customer_id")
      .agg(pl.sum("amount").alias("daily_total"))
      .sort(["customer_id", "transaction_date"])
      .with_columns(
          pl.col("daily_total")
            .rolling_mean(window_size=7)
            .over("customer_id")
            .alias("ma7_per_customer")
      )
)

print(daily.tail())
print(daily_by_cust.filter(pl.col("customer_id")==1).tail())

अपेक्षित परिणाम यहाँ है:

finance example result

4. वैज्ञानिक कंप्यूटिंग

वैज्ञानिक कंप्यूटिंग करते समय, आपको प्रयोगात्मक या सिम्युलेटेड ट्रांज़ैक्शन-जैसे डेटा की लाखों रो को कुशलता से संभालने की आवश्यकता होगी।

यहाँ एक नमूना इम्प्लीमेंटेशन है:

import polars as pl

# Assume a very large Parquet file with columns: id, value, ts (UTC)
# Use lazy scan_* to avoid loading into memory up-front
lazy = (
    pl.scan_parquet("experiments.parquet")           # or: pl.scan_csv("experiments.csv")
      .filter(pl.col("value") > 0)                   # predicate pushdown
      .select(["id", "value", "ts"])                 # projection pushdown
      .with_columns(
          # Example transformations: standardization & bucketize timestamps by hour
          ((pl.col("value") - pl.col("value").mean()) / pl.col("value").std())
              .alias("z_value"),
          pl.col("ts").dt.truncate("1h").alias("ts_hour")
      )
      .group_by(["id", "ts_hour"])
      .agg([
          pl.len().alias("n"),
          pl.mean("z_value").alias("z_mean"),
          pl.std("z_value").alias("z_std")
      ])
      .sort(["id", "ts_hour"])
)

# Execute in streaming mode to keep memory usage low
result = lazy.collect(streaming=True)

# Optionally write out partitioned Parquet for downstream analysis
result.write_parquet("experiments_hourly_stats.parquet")
print(result.head())

अंतिम विचार

Python Polars एक आधुनिक, हाई-परफॉर्मेंस DataFrame लाइब्रेरी प्रदान करता है जो pandas की कई सीमाओं का समाधान करता है। जबकि छोटे, ऐड-हॉक विश्लेषण के लिए pandas लोकप्रिय बना हुआ है, Python में स्केलेबल, कुशल, और विश्वसनीय डेटा प्रोसेसिंग के लिए Polars तेजी से पसंदीदा टूल बन रहा है।

Polars के बारे में और सीखना चाहते हैं? हमारा Introduction to Polars कोर्स या हमारा Introduction to Polars आर्टिकल देखें। हमारा Polars Engine आर्टिकल भी आपको रोचक लग सकता है।

Python Polars FAQs

Polars और Pandas के बीच मुख्य अंतर क्या हैं?

Polars तेज़ और अधिक मेमोरी-कुशल है क्योंकि यह Rust में बना है और कॉलम-आधारित इंजन का उपयोग करता है। यह लेज़ी और ईगर दोनों मोड सपोर्ट करता है, जबकि pandas केवल ईगर मोड में काम करता है। छोटे कार्यों के लिए pandas का उपयोग आसान है, लेकिन बड़े डेटा और प्रदर्शन के लिए Polars बेहतर है।

बड़े डेटासेट को संभालने में Polars, Pandas की तुलना में कैसा है?

Polars बिना सब कुछ मेमोरी में लोड किए बड़े फाइलों को प्रोसेस कर सकता है। यह केवल आवश्यक कॉलम और रो पढ़ता है, और ऑपरेशंस को पैरेलल चलाता है। Pandas पूरा डेटासेट मेमोरी में लोड करता है और आमतौर पर सिंगल-थ्रेड पर काम करता है, जिससे यह धीमा और भारी हो सकता है।

Polars में लेज़ी इवैल्यूएशन की अवधारणा समझाइए?

लेज़ी इवैल्यूएशन का मतलब है कि आप पहले बताते हैं कि क्या करना है, और Polars इंतज़ार करता है। जब आप .collect() कॉल करते हैं, तो Polars सभी स्टेप्स को एक साथ ऑप्टिमाइज़ तरीके से चलाता है। इससे यह तेज़ होता है क्योंकि यह अतिरिक्त काम से बचता है और मेमोरी उपयोग घटाता है।

Polars में कुछ उन्नत डेटा मैनिप्युलेशन तकनीकें क्या हैं?

Polars टाइम सीरीज़ के लिए रोलिंग एवरेज, विंडो फ़ंक्शंस, और समय-आधारित ग्रुपिंग कर सकता है। यह as-of, सेमी, और एंटी जैसे जॉइन्स भी सपोर्ट करता है। Polars लिस्ट्स और स्ट्रक्ट्स के साथ नेस्टेड डेटा संभाल सकता है, पिवट और मेल्ट से टेबल्स को रीशेप कर सकता है, और कंडीशंस के साथ शक्तिशाली एक्सप्रेशंस का उपयोग कर सकता है।

Python इकोसिस्टम के साथ Polars का एकीकरण कैसे होता है?

Polars अन्य टूल्स के साथ अच्छी तरह काम करता है। आप आसानी से डेटा को pandas, NumPy, या Arrow में कन्वर्ट कर सकते हैं मशीन लर्निंग और विज़ुअलाइज़ेशन के लिए। यह CSV, Parquet, और IPC जैसे फ़ॉर्मैट्स को पढ़ने-लिखने को सपोर्ट करता है। यह Jupyter नोटबुक्स में सुचारू रूप से चलता है और कई Python लाइब्रेरीज़ से जुड़ता है।

विषय