Pandas & NumPy Academy · पाठ

मेमोरी घटाने के लिए कुशल डेटा प्रकार

संख्यात्मक कॉलमों को int32/float32 में डाउनकास्ट करें और string कॉलमों को Categorical में बदलकर DataFrame की मेमोरी 70% तक घटाएँ।

पाठ 3, कुल 4 में से13 चरण

मेमोरी घटाने के लिए कुशल डेटा प्रकार, CoddyKit पर Pandas & NumPy Academy का एक निःशुल्क पाठ है। यह 4 में से 3वाँ पाठ है। आप नीचे पूरा पाठ निःशुल्क पढ़ सकते हैं—फिर अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर के साथ ब्राउज़र में इसका व्यावहारिक अभ्यास कर सकते हैं। यह Pandas & NumPy Academy सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। Pandas & NumPy Academy पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

डेटा प्रकार प्रदर्शन को कैसे प्रभावित करते हैं

पैंडस में प्रत्येक कॉलम का एक dtype (डेटा प्रकार) होता है, जो निर्धारित करता है कि मान मेमोरी में कैसे संग्रहीत होंगे और कार्य कितनी तेज़ी से चलेंगे। डेटा लोड करते समय पैंडस डिफ़ॉल्ट रूप से बड़े प्रकारों का उपयोग करता है: int64 (प्रति मान 8 बाइट), float64 (8 बाइट) और object (परिवर्तनशील, प्रत्येक स्ट्रिंग के लिए अक्सर 50-200 बाइट)। लाखों पंक्तियों के लिए छोटे प्रकार चुनने से मेमोरी 50-80% तक कम हो सकती है और बेहतर कैश उपयोग के कारण कार्य 2-5 गुना तेज़ हो सकते हैं।

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({
    'id': np.arange(1000000, dtype='int64'),
    'score': np.random.uniform(0, 100, 1000000).astype('float64'),
    'category': np.random.choice(['A','B','C','D'], 1000000)
})

mem = df.memory_usage(deep=True)
print('Memory per column:')
print(mem)
print(f'Total: {mem.sum() / 1e6:.1f} MB')

पूर्णांक कॉलम को डाउनकास्ट करना

यदि किसी कॉलम में ऐसे पूर्णांक मान हैं जो छोटी सीमा में समा जाते हैं, तो उसे int64 से छोटे पूर्णांक प्रकार में डाउनकास्ट करें। pd.to_numeric(series, downcast='integer') स्वचालित रूप से ऐसा सबसे छोटा पूर्णांक प्रकार चुनता है जिसमें सभी मान समा सकें: int8 (–128 से 127, 1 बाइट), int16 (–32768 से 32767, 2 बाइट), int32 (±2 बिलियन, 4 बाइट), या आवश्यकता होने पर int64 ही रखता है। int8 कॉलम, int64 की तुलना में 8 गुना कम मेमोरी उपयोग करता है।

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({
    'age': np.random.randint(18, 90, 500000).astype('int64'),
    'score': np.random.randint(0, 100, 500000).astype('int64'),
    'large_id': np.random.randint(0, 2**31, 500000).astype('int64')
})

# Downcast integers
for col in df.select_dtypes('int64').columns:
    df[col] = pd.to_numeric(df[col], downcast='integer')

print('Dtypes after downcasting:')
print(df.dtypes)
print(f'\nMemory: {df.memory_usage(deep=True).sum()/1e6:.2f} MB')

दशमलव कॉलम को डाउनकास्ट करना

pd.to_numeric(series, downcast='float'), जहाँ सटीकता इसकी अनुमति देती है, float64 को float32 में बदलता है (8 के बजाय 4 बाइट)। float32 में float64 के 15 अंकों की तुलना में लगभग 7 दशमलव अंकों की सटीकता होती है। अधिकांश विश्लेषणात्मक कार्यों (प्रतिशत, कीमतें, सामान्यीकृत विशेषताएँ) के लिए float32 की सटीकता पर्याप्त होती है। अधिक सटीकता की आवश्यकता वाले वैज्ञानिक कंप्यूटिंग कार्यों के लिए float64 ही रखें। दशमलव सटीकता आधी करने से मेमोरी आधी होती है और कैश प्रदर्शन बेहतर होता है।

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({'lat': np.random.uniform(-90, 90, 1000000),
                   'lon': np.random.uniform(-180, 180, 1000000),
                   'temp': np.random.uniform(-40, 50, 1000000)})

print('Before:', df.dtypes.unique())
print(f'Memory: {df.memory_usage(deep=True).sum()/1e6:.1f} MB')

for col in df.select_dtypes('float64').columns:
    df[col] = pd.to_numeric(df[col], downcast='float')

print('After:', df.dtypes.unique())
print(f'Memory: {df.memory_usage(deep=True).sum()/1e6:.1f} MB')

Categorical डेटा प्रकार

दोहराए गए मानों वाले स्ट्रिंग कॉलम के लिए Categorical डेटा प्रकार मेमोरी की सबसे बड़ी बचत करता है। एक ही स्ट्रिंग (जैसे 'Electronics') को हज़ारों बार संग्रहीत करने के बजाय, पैंडस विशिष्ट मानों की एक शब्दकोश और प्रत्येक पंक्ति के लिए एक छोटा पूर्णांक कोड संग्रहीत करता है। 1 मिलियन पंक्तियों और केवल 50 विशिष्ट श्रेणियों वाला कॉलम लगभग 50 MB (object डेटा प्रकार) से घटकर लगभग 1 MB (Categorical) रह जाता है — यानी मेमोरी में 50 गुना कमी।

import pandas as pd
import numpy as np

np.random.seed(0)
categories = ['Electronics', 'Clothing', 'Books', 'Food', 'Furniture',
              'Sports', 'Toys', 'Health', 'Garden', 'Automotive']

df = pd.DataFrame({'product_cat': np.random.choice(categories, 1000000)})

mem_before = df.memory_usage(deep=True).sum()
df['product_cat'] = df['product_cat'].astype('category')
mem_after = df.memory_usage(deep=True).sum()

print(f'Object dtype: {mem_before/1e6:.1f} MB')
print(f'Categorical:  {mem_after/1e6:.2f} MB')
print(f'Reduction: {mem_before/mem_after:.0f}x')

Categorical मेमोरी कब बचाता है

Categorical डेटा प्रकार तभी मेमोरी बचाता है जब कॉलम में कुल पंक्तियों की तुलना में बहुत कम विशिष्ट मान हों। संतुलन-बिंदु तब होता है जब विशिष्ट मानों और कुल पंक्तियों का अनुपात (cardinality) लगभग 50% से अधिक हो: यदि प्रत्येक पंक्ति में एक विशिष्ट स्ट्रिंग हो, तो Categorical वास्तव में object डेटा प्रकार से अधिक मेमोरी उपयोग करता है, क्योंकि यह कोड सारणी और श्रेणियों की सारणी दोनों संग्रहीत करता है। बदलने से पहले हमेशा df['col'].nunique() / len(df) जाँचें — 0.5 से कम (और आदर्श रूप से 0.05 से कम) अनुपात का अर्थ है कि Categorical लाभदायक होगा।

import pandas as pd
import numpy as np

def memory_gain(df, col):
    n = len(df)
    n_unique = df[col].nunique()
    ratio = n_unique / n
    mem_obj = df[col].memory_usage(deep=True)
    df2 = df.copy()
    df2[col] = df2[col].astype('category')
    mem_cat = df2[col].memory_usage(deep=True)
    print(f'{col}: {n_unique} unique / {n} total (ratio={ratio:.3f})')
    print(f'  Object: {mem_obj/1e6:.2f} MB → Categorical: {mem_cat/1e6:.2f} MB')
    print(f'  {"Saves" if mem_cat < mem_obj else "Wastes"} {abs(mem_obj-mem_cat)/1e6:.2f} MB')

np.random.seed(0)
df = pd.DataFrame({
    'low_card': np.random.choice(['A','B','C'], 500000),   # low cardinality
    'high_card': [f'id_{i}' for i in range(500000)]         # high cardinality
})
memory_gain(df, 'low_card')
memory_gain(df, 'high_card')

Categorical, GroupBy प्रदर्शन बढ़ाता है

मेमोरी बचाने के अलावा, Categorical डेटा प्रकार groupby कार्यों को तेज़ भी करता है, क्योंकि समूह की सीमाएँ खोजने के लिए पैंडस स्ट्रिंग को हैश करने के बजाय सीधे पूर्णांक कोड का उपयोग कर सकता है। लाखों पंक्तियों वाले DataFrames में, जिन्हें कम-कार्डिनैलिटी वाले स्ट्रिंग कॉलम (जैसे क्षेत्र, उत्पाद श्रेणी या स्थिति) के आधार पर समूहित किया गया हो, groupby से पहले उन कॉलम को Categorical में बदलने पर गति 2-5 गुना बढ़ सकती है।

import pandas as pd
import numpy as np
import timeit

np.random.seed(0)
df = pd.DataFrame({
    'region': np.random.choice(['North','South','East','West'], 1000000),
    'sales': np.random.randn(1000000)
})

# Object dtype groupby
t1 = timeit.timeit(lambda: df.groupby('region')['sales'].mean(), number=50)

# Categorical dtype groupby
df2 = df.copy()
df2['region'] = df2['region'].astype('category')
t2 = timeit.timeit(lambda: df2.groupby('region')['sales'].mean(), number=50)

print(f'Object dtype groupby: {t1/50*1000:.2f} ms')
print(f'Categorical groupby:  {t2/50*1000:.2f} ms')
print(f'Speedup: {t1/t2:.1f}x')

फ़्लैग कॉलम के लिए boolean डेटा प्रकार का उपयोग

द्विआधारी कॉलम (True/False, 0/1, yes/no) अक्सर object या int64 के रूप में संग्रहीत होते हैं। इन्हें bool डेटा प्रकार में बदलने पर प्रति मान केवल 1 बाइट उपयोग होता है (int64 के 8 बाइट या 'yes'/'no' स्ट्रिंग के 50 से अधिक बाइट के बजाय)। यह सुनिश्चित करने के बाद कि कॉलम में केवल 0/1 या True/False मान हैं, astype(bool) का उपयोग करें। बूलियन कॉलम तेज़ फ़िल्टरिंग भी सक्षम करते हैं, क्योंकि पैंडस आंतरिक रूप से बिटवाइज़ कार्यों का उपयोग कर सकता है।

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({
    'is_premium': np.random.choice([0, 1], 1000000).astype('int64'),
    'has_discount': np.random.choice(['yes', 'no'], 1000000)
})

print('Before:')
print(df.dtypes)
print(f'Memory: {df.memory_usage(deep=True).sum()/1e6:.1f} MB')

df['is_premium'] = df['is_premium'].astype(bool)
df['has_discount'] = df['has_discount'].map({'yes': True, 'no': False}).astype(bool)

print('\nAfter:')
print(df.dtypes)
print(f'Memory: {df.memory_usage(deep=True).sum()/1e6:.2f} MB')

डेटा प्रकार अनुकूलन को स्वचालित करना

एक ऐसी पुनःप्रयोग योग्य optimise_dtypes(df) फ़ंक्शन लिखिए, जो सभी अनुकूलन अपने-आप लागू करे: पूर्णांकों को डाउनकास्ट करना, फ़्लोट संख्याओं को डाउनकास्ट करना, कम विशिष्टता वाली ऑब्जेक्ट प्रविष्टियों को Categorical में बदलना और 0/1 पूर्णांकों को बूल में बदलना। डेटा लोड करते समय इस फ़ंक्शन को चलाइए, ताकि शुरुआत से ही मेमोरी का न्यूनतम उपयोग हो। इससे यह सुनिश्चित होता है कि एक ही डेटासेट लोड करने वाले टीम के प्रत्येक सदस्य को अनुकूलित संस्करण मिले, और उन्हें हर चरण को मैन्युअल रूप से लागू करना याद न रखना पड़े।

import pandas as pd
import numpy as np

def optimise_dtypes(df, cat_threshold=0.5):
    '''Reduce DataFrame memory by choosing smaller dtypes.'''
    for col in df.columns:
        col_type = df[col].dtype
        if col_type == 'int64':
            df[col] = pd.to_numeric(df[col], downcast='integer')
        elif col_type == 'float64':
            df[col] = pd.to_numeric(df[col], downcast='float')
        elif col_type == 'object':
            cardinality = df[col].nunique() / len(df)
            if cardinality < cat_threshold:
                df[col] = df[col].astype('category')
    return df

# Test
np.random.seed(0)
df = pd.DataFrame({'a': np.random.randint(0,100,500000),
                   'b': np.random.randn(500000),
                   'c': np.random.choice(['X','Y','Z'],500000)})

before = df.memory_usage(deep=True).sum()
df = optimise_dtypes(df)
after = df.memory_usage(deep=True).sum()
print(f'Before: {before/1e6:.2f} MB → After: {after/1e6:.2f} MB ({before/after:.1f}x reduction)')

ऋणात्मक न होने वाले डेटा के लिए अनसाइन्ड पूर्णांक प्रकार

जब किसी कॉलम में केवल ऋणात्मक न होने वाले पूर्णांक हों, जैसे ID, गणनाएँ या मात्राएँ, तो अनसाइन्ड पूर्णांक प्रकार का उपयोग कीजिए: uint8 (0–255), uint16 (0–65535), uint32 (0–4 बिलियन) या uint64। अनसाइन्ड प्रकार अपने साइन वाले समकक्षों के समान ही बाइट आकार लेते हैं, लेकिन धनात्मक सीमा में उससे दोगुने तक बड़े मान रख सकते हैं। उदाहरण के लिए, 0 से 60,000 तक के उत्पाद ID के लिए int32 (4 बाइट) के बजाय uint16 (2 बाइट) पर्याप्त है। यह सुनिश्चित करने के बाद कि कॉलम में कोई ऋणात्मक मान नहीं है, astype('uint16') का उपयोग कीजिए।

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({
    'product_id': np.random.randint(0, 50000, 1000000).astype('int64'),
    'quantity': np.random.randint(0, 255, 1000000).astype('int64')
})

print('Before (int64):', df.memory_usage(deep=True).sum() / 1e6, 'MB')

# product_id fits in uint16 (0-65535)
df['product_id'] = df['product_id'].astype('uint16')
# quantity fits in uint8 (0-255)
df['quantity'] = df['quantity'].astype('uint8')

print('After (uint16+uint8):', df.memory_usage(deep=True).sum() / 1e6, 'MB')
print('\nDtypes:', df.dtypes.to_dict())

हर अनुकूलन चरण के बाद मेमोरी की जाँच

अनुकूलन एक-एक करके लागू कीजिए और हर चरण के बाद मेमोरी की जाँच कीजिए। इससे ठीक-ठीक पता चलता है कि प्रत्येक तकनीक का कितना योगदान है। एक सामान्य बड़े DataFrame का आकार 2 GB (सभी डिफ़ॉल्ट डेटा प्रकारों के साथ) से घटकर 600 MB (पूर्णांकों को डाउनकास्ट करने पर), फिर 300 MB (फ़्लोट संख्याओं को डाउनकास्ट करने पर) और अंत में 200 MB (स्ट्रिंग कॉलम के लिए Categorical पर) हो सकता है। इस विभाजन का दस्तावेज़ीकरण करने से उन टीम सदस्यों को अतिरिक्त जटिलता समझाना आसान होता है, जिन्हें कोडबेस में अपरिचित डेटा प्रकार दिखाई देते हैं।

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({
    'user_id': np.random.randint(0, 99999, 1000000).astype('int64'),
    'age': np.random.randint(18, 80, 1000000).astype('int64'),
    'revenue': np.random.uniform(0, 5000, 1000000).astype('float64'),
    'country': np.random.choice(['US','UK','DE','FR','JP'], 1000000),
    'tier': np.random.choice(['free','basic','pro','enterprise'], 1000000)
})

def mem_mb(df):
    return df.memory_usage(deep=True).sum() / 1e6

print(f'Start: {mem_mb(df):.1f} MB')

for c in ['user_id','age']:
    df[c] = pd.to_numeric(df[c], downcast='integer')
print(f'After int downcast: {mem_mb(df):.1f} MB')

df['revenue'] = pd.to_numeric(df['revenue'], downcast='float')
print(f'After float downcast: {mem_mb(df):.1f} MB')

for c in ['country','tier']:
    df[c] = df[c].astype('category')
print(f'After Categorical: {mem_mb(df):.1f} MB')

अनुकूलित प्रकारों को सहेजना और फिर से लोड करना

यदि आप CSV में सहेजते हैं, तो अनुकूलित डेटा प्रकार खो जाते हैं, क्योंकि सब कुछ फिर से टेक्स्ट में बदल जाता है। डेटा प्रकारों को सुरक्षित रखने के लिए Parquet प्रारूप में df.to_parquet('file.parquet') का उपयोग करके सहेजिए — Parquet, int32, float32 और Categorical प्रकारों को सुरक्षित रखता है। pd.read_parquet से फिर से लोड करने पर DataFrame में वही मेमोरी-कुशल प्रकार रहते हैं और अनुकूलन फ़ंक्शन को दोबारा चलाने की आवश्यकता नहीं होती। बड़ी फ़ाइलों के लिए Parquet, CSV की तुलना में काफ़ी तेज़ी से लोड भी होता है।

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({
    'age': np.random.randint(18, 80, 100000).astype('int8'),   # already optimised
    'score': np.random.randn(100000).astype('float32'),
    'tier': pd.Categorical(np.random.choice(['free','pro'], 100000))
})
print('Dtypes:', df.dtypes.to_dict())

# Save to Parquet (preserves dtypes)
df.to_parquet('/tmp/optimised.parquet', index=False)

# Reload — dtypes preserved!
df_loaded = pd.read_parquet('/tmp/optimised.parquet')
print('\nLoaded dtypes:', df_loaded.dtypes.to_dict())
print(f'Memory: {df_loaded.memory_usage(deep=True).sum()/1e6:.2f} MB')

त्वरित जाँच

इस पाठ में मेमोरी-कुशल डेटा प्रकारों से संबंधित अपनी समझ की जाँच कीजिए।

पाठ का पुनरावलोकन

इस पाठ में आपने सीखा: pd.to_numeric(downcast='integer') पूर्णांक कॉलमों का आकार 8 बाइट से घटाकर 1–4 बाइट कर देता है, pd.to_numeric(downcast='float') फ़्लोट मेमोरी को आधा कर देता है, Categorical dtype कम विशिष्टता वाले स्ट्रिंग कॉलमों का आकार 50 गुना तक घटाने के साथ groupby को भी तेज़ करता है, और Parquet format फ़ाइल सहेजने और लोड करने के दौरान अनुकूलित डेटा प्रकारों को सुरक्षित रखता है। अब हम खंडों में पढ़ने का तरीका सीखेंगे — ऐसी फ़ाइलों को संसाधित करना जो उपलब्ध RAM से बड़ी हों।

शुरुआत निःशुल्क

एआई शिक्षक के साथ Python सीखें — निःशुल्क

अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।

पाठ्यक्रम
30
पाठ
120

अक्सर पूछे जाने वाले प्रश्न

क्या “मेमोरी घटाने के लिए कुशल डेटा प्रकार” पाठ निःशुल्क है?

हाँ—“मेमोरी घटाने के लिए कुशल डेटा प्रकार” का पूरा पाठ यहाँ वेब पर निःशुल्क पढ़ा जा सकता है। इंटरैक्टिव अभ्यास (अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर) करने और Pandas & NumPy Academy पाठ्यक्रम का बाकी हिस्सा अनलॉक करने के लिए CoddyKit PRO लें। Pandas & NumPy Academy पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

“मेमोरी घटाने के लिए कुशल डेटा प्रकार” में मैं क्या सीखूँगा?

संख्यात्मक कॉलमों को int32/float32 में डाउनकास्ट करें और string कॉलमों को Categorical में बदलकर DataFrame की मेमोरी 70% तक घटाएँ। आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ Pandas & NumPy Academy का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।

क्या Pandas & NumPy Academy शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?

पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर Pandas & NumPy Academy शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 4 में से 3वाँ पाठ है।

“मेमोरी घटाने के लिए कुशल डेटा प्रकार” पाठ पूरा करने में कितना समय लगता है?

CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।

क्या मैं इस Pandas & NumPy Academy पाठ में कोड लिख और चला सकता हूँ?

हाँ। हर Pandas & NumPy Academy पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।

इस पाठ्यक्रम के सभी पाठ

  1. timeit और memory_profiler से प्रोफ़ाइल बनाना
  2. iterrows और Python लूप से बचना
  3. मेमोरी घटाने के लिए कुशल डेटा प्रकार
  4. बड़ी फ़ाइलों को खंडों में पढ़ना
← Pandas & NumPy Academy पर वापस जाएँ