മെമ്മറി ഉപയോഗവും പ്രകടനവും ഒപ്റ്റിമൈസ് ചെയ്യുന്നതിനായി പാണ്ടസ് ഡാറ്റാഫ്രെയിമുകളെക്കുറിച്ചുള്ള ഒരു സമഗ്രമായ ഗൈഡ്. ഡാറ്റാ ടൈപ്പുകൾ, ഇൻഡെക്സിംഗ്, നൂതന സാങ്കേതിക വിദ്യകൾ എന്നിവ ഇതിൽ ഉൾപ്പെടുന്നു.
പാണ്ടസ് ഡാറ്റാഫ്രെയിം ഒപ്റ്റിമൈസേഷൻ: മെമ്മറി ഉപയോഗവും പ്രകടനവും മെച്ചപ്പെടുത്തൽ
ഡാറ്റാ കൈകാര്യം ചെയ്യുന്നതിനും വിശകലനം ചെയ്യുന്നതിനുമുള്ള ശക്തമായ ഒരു പൈത്തൺ ലൈബ്രറിയാണ് പാണ്ടസ്. എന്നിരുന്നാലും, വലിയ ഡാറ്റാസെറ്റുകളിൽ പ്രവർത്തിക്കുമ്പോൾ, പാണ്ടസ് ഡാറ്റാഫ്രെയിമുകൾക്ക് കാര്യമായ മെമ്മറി ഉപയോഗിക്കാനും വേഗത കുറഞ്ഞ പ്രകടനം കാഴ്ചവെക്കാനും കഴിയും. ഈ ലേഖനം പാണ്ടസ് ഡാറ്റാഫ്രെയിമുകളുടെ മെമ്മറി ഉപയോഗവും പ്രകടനവും ഒപ്റ്റിമൈസ് ചെയ്യുന്നതിനുള്ള ഒരു സമഗ്രമായ വഴികാട്ടി നൽകുന്നു, ഇത് വലിയ ഡാറ്റാസെറ്റുകൾ കൂടുതൽ കാര്യക്ഷമമായി പ്രോസസ്സ് ചെയ്യാൻ നിങ്ങളെ സഹായിക്കുന്നു.
പാണ്ടസ് ഡാറ്റാഫ്രെയിമുകളിലെ മെമ്മറി ഉപയോഗം മനസ്സിലാക്കൽ
ഒപ്റ്റിമൈസേഷൻ ടെക്നിക്കുകളിലേക്ക് കടക്കുന്നതിനുമുമ്പ്, പാണ്ടസ് ഡാറ്റാഫ്രെയിമുകൾ എങ്ങനെയാണ് മെമ്മറിയിൽ ഡാറ്റ സംഭരിക്കുന്നതെന്ന് മനസ്സിലാക്കേണ്ടത് അത്യാവശ്യമാണ്. ഒരു ഡാറ്റാഫ്രെയിമിലെ ഓരോ കോളത്തിനും ഒരു പ്രത്യേക ഡാറ്റാ ടൈപ്പ് ഉണ്ട്, അത് അതിന്റെ മൂല്യങ്ങൾ സംഭരിക്കുന്നതിന് ആവശ്യമായ മെമ്മറിയുടെ അളവ് നിർണ്ണയിക്കുന്നു. സാധാരണ ഡാറ്റാ ടൈപ്പുകളിൽ ഇവ ഉൾപ്പെടുന്നു:
- int64: 64-ബിറ്റ് പൂർണ്ണസംഖ്യകൾ (പൂർണ്ണസംഖ്യകൾക്കുള്ള ഡിഫോൾട്ട്)
- float64: 64-ബിറ്റ് ഫ്ലോട്ടിംഗ്-പോയിന്റ് സംഖ്യകൾ (ഫ്ലോട്ടിംഗ്-പോയിന്റ് സംഖ്യകൾക്കുള്ള ഡിഫോൾട്ട്)
- object: പൈത്തൺ ഒബ്ജക്റ്റുകൾ (സ്ട്രിംഗുകൾക്കും മിക്സഡ് ഡാറ്റാ ടൈപ്പുകൾക്കും ഉപയോഗിക്കുന്നു)
- category: കാറ്റഗറിക്കൽ ഡാറ്റ (ആവർത്തന മൂല്യങ്ങൾക്ക് കാര്യക്ഷമമാണ്)
- bool: ബൂളിയൻ മൂല്യങ്ങൾ (True/False)
- datetime64: ഡേറ്റ്ടൈം മൂല്യങ്ങൾ
object ഡാറ്റാ ടൈപ്പ് പലപ്പോഴും ഏറ്റവും കൂടുതൽ മെമ്മറി ഉപയോഗിക്കുന്ന ഒന്നാണ്, കാരണം ഇത് പൈത്തൺ ഒബ്ജക്റ്റുകളിലേക്കുള്ള പോയിന്ററുകൾ സംഭരിക്കുന്നു, ഇത് പൂർണ്ണസംഖ്യകളോ ഫ്ലോട്ടുകളോ പോലുള്ള പ്രിമിറ്റീവ് ഡാറ്റാ ടൈപ്പുകളേക്കാൾ വളരെ വലുതായിരിക്കും. ചെറിയ സ്ട്രിംഗുകൾ പോലും object ആയി സംഭരിക്കുമ്പോൾ, ആവശ്യമായതിലും കൂടുതൽ മെമ്മറി ഉപയോഗിക്കുന്നു. അതുപോലെ, int32 മതിയാകുന്നിടത്ത് int64 ഉപയോഗിക്കുന്നത് മെമ്മറി പാഴാക്കുന്നു.
ഉദാഹരണം: ഡാറ്റാഫ്രെയിം മെമ്മറി ഉപയോഗം പരിശോധിക്കുന്നു
ഒരു ഡാറ്റാഫ്രെയിമിന്റെ മെമ്മറി ഉപയോഗം പരിശോധിക്കാൻ നിങ്ങൾക്ക് memory_usage() മെത്തേഡ് ഉപയോഗിക്കാം:
import pandas as pd
import numpy as np
data = {
'col1': np.random.randint(0, 1000, 100000),
'col2': np.random.rand(100000),
'col3': ['A', 'B', 'C'] * (100000 // 3 + 1)[:100000],
'col4': ['This is a long string'] * 100000
}
df = pd.DataFrame(data)
memory_usage = df.memory_usage(deep=True)
print(memory_usage)
print(df.dtypes)
deep=True എന്ന ആർഗ്യുമെന്റ്, ഒബ്ജക്റ്റുകളുടെ (സ്ട്രിംഗുകൾ പോലുള്ളവ) മെമ്മറി ഉപയോഗം കൃത്യമായി കണക്കാക്കുന്നുവെന്ന് ഉറപ്പാക്കുന്നു. deep=True ഇല്ലാതെ, ഇത് പോയിന്ററുകൾക്കുള്ള മെമ്മറി മാത്രമേ കണക്കാക്കൂ, യഥാർത്ഥ ഡാറ്റയുടേതല്ല.
ഡാറ്റാ ടൈപ്പുകൾ ഒപ്റ്റിമൈസ് ചെയ്യൽ
മെമ്മറി ഉപയോഗം കുറയ്ക്കുന്നതിനുള്ള ഏറ്റവും ഫലപ്രദമായ മാർഗ്ഗങ്ങളിലൊന്ന് നിങ്ങളുടെ ഡാറ്റാഫ്രെയിം കോളങ്ങൾക്ക് ഏറ്റവും അനുയോജ്യമായ ഡാറ്റാ ടൈപ്പുകൾ തിരഞ്ഞെടുക്കുക എന്നതാണ്. സാധാരണയായി ഉപയോഗിക്കുന്ന ചില ടെക്നിക്കുകൾ താഴെ നൽകുന്നു:
1. ന്യൂമെറിക്കൽ ഡാറ്റാ ടൈപ്പുകൾ ഡൗൺകാസ്റ്റ് ചെയ്യുക
നിങ്ങളുടെ പൂർണ്ണസംഖ്യ അല്ലെങ്കിൽ ഫ്ലോട്ടിംഗ്-പോയിന്റ് കോളങ്ങൾക്ക് 64-ബിറ്റ് പ്രിസിഷന്റെ പൂർണ്ണ ശ്രേണി ആവശ്യമില്ലെങ്കിൽ, നിങ്ങൾക്ക് അവയെ int32, int16, float32, അല്ലെങ്കിൽ float16 പോലുള്ള ചെറിയ ഡാറ്റാ ടൈപ്പുകളിലേക്ക് ഡൗൺകാസ്റ്റ് ചെയ്യാൻ കഴിയും. ഇത്, പ്രത്യേകിച്ച് വലിയ ഡാറ്റാസെറ്റുകളിൽ, മെമ്മറി ഉപയോഗം ഗണ്യമായി കുറയ്ക്കാൻ സഹായിക്കും.
ഉദാഹരണം: പ്രായത്തെ പ്രതിനിധീകരിക്കുന്ന ഒരു കോളം പരിഗണിക്കുക, അത് 120-ൽ കവിയാൻ സാധ്യതയില്ല. ഇത് int64 ആയി സംഭരിക്കുന്നത് പാഴാണ്; int8 (ശ്രേണി -128 മുതൽ 127 വരെ) കൂടുതൽ ഉചിതമായിരിക്കും.
def downcast_numeric(df):
"""Downcasts numeric columns to the smallest possible data type."""
for col in df.columns:
if pd.api.types.is_integer_dtype(df[col]):
df[col] = pd.to_numeric(df[col], downcast='integer')
elif pd.api.types.is_float_dtype(df[col]):
df[col] = pd.to_numeric(df[col], downcast='float')
return df
df = downcast_numeric(df.copy())
print(df.memory_usage(deep=True))
print(df.dtypes)
downcast ആർഗ്യുമെന്റോടുകൂടിയ pd.to_numeric() ഫംഗ്ഷൻ, ഒരു കോളത്തിലെ മൂല്യങ്ങളെ പ്രതിനിധീകരിക്കാൻ കഴിയുന്ന ഏറ്റവും ചെറിയ ഡാറ്റാ ടൈപ്പ് സ്വയമേവ തിരഞ്ഞെടുക്കാൻ ഉപയോഗിക്കുന്നു. copy() ഉപയോഗിക്കുന്നത് യഥാർത്ഥ ഡാറ്റാഫ്രെയിമിൽ മാറ്റങ്ങൾ വരുത്തുന്നത് ഒഴിവാക്കുന്നു. വിവരങ്ങൾ നഷ്ടപ്പെടുന്നില്ലെന്ന് ഉറപ്പാക്കാൻ ഡൗൺകാസ്റ്റ് ചെയ്യുന്നതിന് മുമ്പ് നിങ്ങളുടെ ഡാറ്റയിലെ മൂല്യങ്ങളുടെ ശ്രേണി എപ്പോഴും പരിശോധിക്കുക.
2. കാറ്റഗറിക്കൽ ഡാറ്റാ ടൈപ്പുകൾ ഉപയോഗിക്കൽ
ഒരു കോളത്തിൽ പരിമിതമായ എണ്ണം തനതായ മൂല്യങ്ങൾ അടങ്ങിയിട്ടുണ്ടെങ്കിൽ, നിങ്ങൾക്ക് അതിനെ ഒരു category ഡാറ്റാ ടൈപ്പിലേക്ക് മാറ്റാൻ കഴിയും. കാറ്റഗറിക്കൽ ഡാറ്റാ ടൈപ്പുകൾ ഓരോ തനതായ മൂല്യവും ഒരു തവണ മാത്രം സംഭരിക്കുകയും, തുടർന്ന് കോളത്തിലെ മൂല്യങ്ങളെ പ്രതിനിധീകരിക്കാൻ പൂർണ്ണസംഖ്യാ കോഡുകൾ ഉപയോഗിക്കുകയും ചെയ്യുന്നു. ഇത്, പ്രത്യേകിച്ച് ആവർത്തിച്ചുള്ള മൂല്യങ്ങൾ കൂടുതലുള്ള കോളങ്ങളിൽ, മെമ്മറി ഉപയോഗം ഗണ്യമായി കുറയ്ക്കാൻ സഹായിക്കും.
ഉദാഹരണം: രാജ്യങ്ങളുടെ കോഡുകളെ പ്രതിനിധീകരിക്കുന്ന ഒരു കോളം പരിഗണിക്കുക. നിങ്ങൾ പരിമിതമായ രാജ്യങ്ങളുമായി (ഉദാഹരണത്തിന്, യൂറോപ്യൻ യൂണിയനിലെ രാജ്യങ്ങൾ മാത്രം) പ്രവർത്തിക്കുകയാണെങ്കിൽ, ഇത് ഒരു കാറ്റഗറിയായി സംഭരിക്കുന്നത് സ്ട്രിംഗുകളായി സംഭരിക്കുന്നതിനേക്കാൾ വളരെ കാര്യക്ഷമമായിരിക്കും.
def optimize_categories(df):
"""Converts object columns with low cardinality to categorical type."""
for col in df.columns:
if df[col].dtype == 'object':
num_unique_values = len(df[col].unique())
num_total_values = len(df[col])
if num_unique_values / num_total_values < 0.5:
df[col] = df[col].astype('category')
return df
df = optimize_categories(df.copy())
print(df.memory_usage(deep=True))
print(df.dtypes)
ഈ കോഡ് ഒരു ഒബ്ജക്റ്റ് കോളത്തിലെ തനതായ മൂല്യങ്ങളുടെ എണ്ണം മൊത്തം മൂല്യങ്ങളുടെ 50%-ൽ കുറവാണോ എന്ന് പരിശോധിക്കുന്നു. അങ്ങനെയെങ്കിൽ, അത് കോളത്തെ ഒരു കാറ്റഗറിക്കൽ ഡാറ്റാ ടൈപ്പിലേക്ക് മാറ്റുന്നു. 50% എന്ന പരിധി ഒരു ഏകദേശ കണക്കാണ്, നിങ്ങളുടെ ഡാറ്റയുടെ പ്രത്യേകതകൾക്കനുസരിച്ച് ഇത് ക്രമീകരിക്കാവുന്നതാണ്. കോളത്തിൽ ധാരാളം ആവർത്തിച്ചുള്ള മൂല്യങ്ങൾ അടങ്ങിയിരിക്കുമ്പോൾ ഈ സമീപനം ഏറ്റവും പ്രയോജനകരമാണ്.
3. സ്ട്രിംഗുകൾക്കായി ഒബ്ജക്റ്റ് ഡാറ്റാ ടൈപ്പുകൾ ഒഴിവാക്കൽ
മുമ്പ് സൂചിപ്പിച്ചതുപോലെ, object ഡാറ്റാ ടൈപ്പ് പലപ്പോഴും ഏറ്റവും കൂടുതൽ മെമ്മറി ഉപയോഗിക്കുന്ന ഒന്നാണ്, പ്രത്യേകിച്ച് സ്ട്രിംഗുകൾ സംഭരിക്കാൻ ഉപയോഗിക്കുമ്പോൾ. സാധ്യമെങ്കിൽ, സ്ട്രിംഗ് കോളങ്ങൾക്കായി object ഡാറ്റാ ടൈപ്പുകൾ ഉപയോഗിക്കുന്നത് ഒഴിവാക്കാൻ ശ്രമിക്കുക. കുറഞ്ഞ കാർഡിനാലിറ്റിയുള്ള സ്ട്രിംഗുകൾക്ക് കാറ്റഗറിക്കൽ ടൈപ്പുകളാണ് അഭികാമ്യം. കാർഡിനാലിറ്റി ഉയർന്നതാണെങ്കിൽ, സ്ട്രിംഗുകളെ ന്യൂമെറിക്കൽ കോഡുകൾ ഉപയോഗിച്ച് പ്രതിനിധീകരിക്കാൻ കഴിയുമോയെന്നോ അല്ലെങ്കിൽ സ്ട്രിംഗ് ഡാറ്റ പൂർണ്ണമായും ഒഴിവാക്കാൻ കഴിയുമോയെന്നോ പരിഗണിക്കുക.
നിങ്ങൾക്ക് കോളത്തിൽ സ്ട്രിംഗ് ഓപ്പറേഷനുകൾ നടത്തണമെങ്കിൽ, അത് ഒരു ഒബ്ജക്റ്റ് ടൈപ്പായി നിലനിർത്തേണ്ടി വന്നേക്കാം, എന്നാൽ ഈ പ്രവർത്തനങ്ങൾ മുൻകൂട്ടി നടത്തി, തുടർന്ന് കൂടുതൽ കാര്യക്ഷമമായ ഒരു ടൈപ്പിലേക്ക് മാറ്റാൻ കഴിയുമോ എന്ന് പരിഗണിക്കുക.
4. തീയതിയും സമയവും സംബന്ധിച്ച ഡാറ്റ
തീയതിയും സമയവും സംബന്ധിച്ച വിവരങ്ങൾക്കായി datetime64 ഡാറ്റാ ടൈപ്പ് ഉപയോഗിക്കുക. റെസല്യൂഷൻ അനുയോജ്യമാണെന്ന് ഉറപ്പാക്കുക (നാനോസെക്കൻഡ് റെസല്യൂഷൻ അനാവശ്യമായിരിക്കാം). പാണ്ടസ് ടൈം സീരീസ് ഡാറ്റ വളരെ കാര്യക്ഷമമായി കൈകാര്യം ചെയ്യുന്നു.
ഡാറ്റാഫ്രെയിം പ്രവർത്തനങ്ങൾ ഒപ്റ്റിമൈസ് ചെയ്യൽ
ഡാറ്റാ ടൈപ്പുകൾ ഒപ്റ്റിമൈസ് ചെയ്യുന്നതിനു പുറമേ, നിങ്ങൾ ഡാറ്റാഫ്രെയിമുകളിൽ നടത്തുന്ന പ്രവർത്തനങ്ങൾ ഒപ്റ്റിമൈസ് ചെയ്യുന്നതിലൂടെയും പാണ്ടസ് ഡാറ്റാഫ്രെയിമുകളുടെ പ്രകടനം മെച്ചപ്പെടുത്താൻ കഴിയും. സാധാരണയായി ഉപയോഗിക്കുന്ന ചില ടെക്നിക്കുകൾ താഴെ നൽകുന്നു:
1. വെക്ടറൈസേഷൻ
ഓരോരോ ഘടകങ്ങളിലൂടെയും ആവർത്തിക്കുന്നതിന് പകരം, മുഴുവൻ അറേകളിലോ കോളങ്ങളിലോ ഒരേസമയം പ്രവർത്തനങ്ങൾ നടത്തുന്ന പ്രക്രിയയാണ് വെക്ടറൈസേഷൻ. പാണ്ടസ് വെക്ടറൈസ്ഡ് ഓപ്പറേഷനുകൾക്കായി വളരെയധികം ഒപ്റ്റിമൈസ് ചെയ്തിട്ടുണ്ട്, അതിനാൽ അവ ഉപയോഗിക്കുന്നത് പ്രകടനം ഗണ്യമായി മെച്ചപ്പെടുത്തും. സാധ്യമാകുമ്പോഴെല്ലാം നേരിട്ടുള്ള ലൂപ്പുകൾ ഒഴിവാക്കുക. പാണ്ടസിന്റെ ബിൽറ്റ്-ഇൻ ഫംഗ്ഷനുകൾ സാധാരണയായി തത്തുല്യമായ പൈത്തൺ ലൂപ്പുകളേക്കാൾ വളരെ വേഗതയേറിയതാണ്.
ഉദാഹരണം: ഓരോ മൂല്യത്തിന്റെയും വർഗ്ഗം കണക്കാക്കാൻ ഒരു കോളത്തിലൂടെ ലൂപ്പ് ചെയ്യുന്നതിനു പകരം, pow() ഫംഗ്ഷൻ ഉപയോഗിക്കുക:
# Inefficient (using a loop)
import time
start_time = time.time()
results = []
for value in df['col2']:
results.append(value ** 2)
df['col2_squared_loop'] = results
end_time = time.time()
print(f"Loop time: {end_time - start_time:.4f} seconds")
# Efficient (using vectorization)
start_time = time.time()
df['col2_squared_vectorized'] = df['col2'] ** 2
end_time = time.time()
print(f"Vectorized time: {end_time - start_time:.4f} seconds")
വെക്ടറൈസ്ഡ് സമീപനം സാധാരണയായി ലൂപ്പ് അടിസ്ഥാനമാക്കിയുള്ള സമീപനത്തേക്കാൾ പല മടങ്ങ് വേഗതയേറിയതാണ്.
2. `apply()` ശ്രദ്ധയോടെ ഉപയോഗിക്കുക
apply() മെത്തേഡ് ഒരു ഡാറ്റാഫ്രെയിമിന്റെ ഓരോ വരിയിലോ കോളത്തിലോ ഒരു ഫംഗ്ഷൻ പ്രയോഗിക്കാൻ നിങ്ങളെ അനുവദിക്കുന്നു. എന്നിരുന്നാലും, ഇത് സാധാരണയായി വെക്ടറൈസ്ഡ് ഓപ്പറേഷനുകളേക്കാൾ വേഗത കുറഞ്ഞതാണ്, കാരണം ഓരോ ഘടകത്തിനും ഒരു പൈത്തൺ ഫംഗ്ഷൻ വിളിക്കുന്നത് ഇതിൽ ഉൾപ്പെടുന്നു. വെക്ടറൈസ്ഡ് ഓപ്പറേഷനുകൾ സാധ്യമല്ലാത്തപ്പോൾ മാത്രം apply() ഉപയോഗിക്കുക.
നിങ്ങൾ apply() ഉപയോഗിക്കുകയാണെങ്കിൽ, നിങ്ങൾ പ്രയോഗിക്കുന്ന ഫംഗ്ഷൻ പരമാവധി വെക്ടറൈസ് ചെയ്യാൻ ശ്രമിക്കുക. കാര്യമായ പ്രകടന മെച്ചപ്പെടുത്തലുകൾക്കായി ഫംഗ്ഷൻ മെഷീൻ കോഡിലേക്ക് കംപൈൽ ചെയ്യാൻ നമ്പയുടെ (Numba) jit ഡെക്കറേറ്റർ ഉപയോഗിക്കുന്നത് പരിഗണിക്കുക.
from numba import jit
@jit(nopython=True)
def my_function(x):
return x * 2 # Example function
df['col2_applied'] = df['col2'].apply(my_function)
3. കോളങ്ങൾ കാര്യക്ഷമമായി തിരഞ്ഞെടുക്കൽ
ഒരു ഡാറ്റാഫ്രെയിമിൽ നിന്ന് കോളങ്ങളുടെ ഒരു ഉപവിഭാഗം തിരഞ്ഞെടുക്കുമ്പോൾ, മികച്ച പ്രകടനത്തിനായി ഇനിപ്പറയുന്ന രീതികൾ ഉപയോഗിക്കുക:
- നേരിട്ടുള്ള കോളം തിരഞ്ഞെടുക്കൽ:
df[['col1', 'col2']](കുറച്ച് കോളങ്ങൾ തിരഞ്ഞെടുക്കുന്നതിനുള്ള ഏറ്റവും വേഗതയേറിയ മാർഗ്ഗം) - ബൂളിയൻ ഇൻഡെക്സിംഗ്:
df.loc[:, [True if col.startswith('col') else False for col in df.columns]](ഒരു വ്യവസ്ഥയെ അടിസ്ഥാനമാക്കി കോളങ്ങൾ തിരഞ്ഞെടുക്കുന്നതിന് ഉപയോഗപ്രദമാണ്)
കോളങ്ങൾ തിരഞ്ഞെടുക്കുന്നതിന് റെഗുലർ എക്സ്പ്രഷനുകളോടൊപ്പം df.filter() ഉപയോഗിക്കുന്നത് ഒഴിവാക്കുക, കാരണം ഇത് മറ്റ് രീതികളേക്കാൾ വേഗത കുറഞ്ഞതായിരിക്കും.
4. ജോയിനുകളും മെർജുകളും ഒപ്റ്റിമൈസ് ചെയ്യൽ
ഡാറ്റാഫ്രെയിമുകൾ ജോയിൻ ചെയ്യുന്നതും മെർജ് ചെയ്യുന്നതും കമ്പ്യൂട്ടേഷണൽ രീതിയിൽ ചെലവേറിയതാണ്, പ്രത്യേകിച്ച് വലിയ ഡാറ്റാസെറ്റുകളിൽ. ജോയിനുകളും മെർജുകളും ഒപ്റ്റിമൈസ് ചെയ്യുന്നതിനുള്ള ചില നുറുങ്ങുകൾ ഇതാ:
- അനുയോജ്യമായ ജോയിൻ കീ-കൾ ഉപയോഗിക്കുക: ജോയിൻ കീ-കൾക്ക് ഒരേ ഡാറ്റാ ടൈപ്പ് ഉണ്ടെന്നും അവ ഇൻഡെക്സ് ചെയ്തിട്ടുണ്ടെന്നും ഉറപ്പാക്കുക.
- ജോയിൻ തരം വ്യക്തമാക്കുക: നിങ്ങളുടെ ആവശ്യകതകളെ അടിസ്ഥാനമാക്കി ഉചിതമായ ജോയിൻ തരം (ഉദാഹരണത്തിന്,
inner,left,right,outer) ഉപയോഗിക്കുക. ഒരു ഇന്നർ ജോയിൻ സാധാരണയായി ഒരു ഔട്ടർ ജോയിനേക്കാൾ വേഗതയേറിയതാണ്. - `join()`-ന് പകരം `merge()` ഉപയോഗിക്കുക:
merge()ഫംഗ്ഷൻ കൂടുതൽ വൈവിധ്യമാർന്നതും പലപ്പോഴുംjoin()മെത്തേഡിനേക്കാൾ വേഗതയേറിയതുമാണ്.
ഉദാഹരണം:
df1 = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'value1': [1, 2, 3, 4]})
df2 = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'value2': [5, 6, 7, 8]})
# Efficient inner join
df_merged = pd.merge(df1, df2, on='key', how='inner')
print(df_merged)
5. അനാവശ്യമായി ഡാറ്റാഫ്രെയിമുകൾ കോപ്പി ചെയ്യുന്നത് ഒഴിവാക്കുക
പല പാണ്ടസ് പ്രവർത്തനങ്ങളും ഡാറ്റാഫ്രെയിമുകളുടെ പകർപ്പുകൾ സൃഷ്ടിക്കുന്നു, ഇത് മെമ്മറി-ഇന്റൻസീവും സമയം എടുക്കുന്നതുമാണ്. അനാവശ്യമായ കോപ്പിയെടുക്കൽ ഒഴിവാക്കാൻ, ലഭ്യമാകുമ്പോൾ inplace=True ആർഗ്യുമെന്റ് ഉപയോഗിക്കുക, അല്ലെങ്കിൽ ഒരു ഓപ്പറേഷന്റെ ഫലം യഥാർത്ഥ ഡാറ്റാഫ്രെയിമിലേക്ക് തിരികെ നൽകുക. inplace=True ഉപയോഗിക്കുമ്പോൾ വളരെ ശ്രദ്ധിക്കുക, കാരണം ഇത് പിശകുകൾ മറച്ചുവെക്കാനും ഡീബഗ്ഗിംഗ് ബുദ്ധിമുട്ടാക്കാനും ഇടയുണ്ട്. അല്പം പ്രകടനം കുറവാണെങ്കിലും, റീ-അസൈൻ ചെയ്യുന്നത് പലപ്പോഴും സുരക്ഷിതമാണ്.
ഉദാഹരണം:
# Inefficient (creates a copy)
df_filtered = df[df['col1'] > 500]
# Efficient (modifies the original DataFrame in place - CAUTION)
df.drop(df[df['col1'] <= 500].index, inplace=True)
#SAFER - reassigns, avoids inplace
df = df[df['col1'] > 500]
6. ചങ്കിംഗും ഇറ്ററേറ്റിംഗും
മെമ്മറിയിൽ ഒതുങ്ങാത്ത വളരെ വലിയ ഡാറ്റാസെറ്റുകൾക്കായി, ഡാറ്റയെ ഭാഗങ്ങളായി (chunks) പ്രോസസ്സ് ചെയ്യുന്നത് പരിഗണിക്കുക. ഫയലുകളിൽ നിന്ന് ഡാറ്റ വായിക്കുമ്പോൾ chunksize പാരാമീറ്റർ ഉപയോഗിക്കുക. ഭാഗങ്ങളിലൂടെ ആവർത്തിച്ച് ഓരോ ഭാഗത്തും നിങ്ങളുടെ വിശകലനം വെവ്വേറെ നടത്തുക. ചില പ്രവർത്തനങ്ങൾക്ക് മുഴുവൻ ഡാറ്റാസെറ്റും ഒരേസമയം പ്രോസസ്സ് ചെയ്യേണ്ടതിനാൽ, വിശകലനം ശരിയായി തുടരുന്നുവെന്ന് ഉറപ്പാക്കാൻ ഇതിന് ശ്രദ്ധാപൂർവ്വമായ ആസൂത്രണം ആവശ്യമാണ്.
# Read CSV in chunks
for chunk in pd.read_csv('large_data.csv', chunksize=100000):
# Process each chunk
print(chunk.shape)
7. പാരലൽ പ്രോസസ്സിംഗിനായി ഡാസ്ക് (Dask) ഉപയോഗിക്കൽ
പാണ്ടസുമായി പരിധികളില്ലാതെ സംയോജിപ്പിക്കുന്ന ഒരു പാരലൽ കമ്പ്യൂട്ടിംഗ് ലൈബ്രറിയാണ് ഡാസ്ക്. വലിയ ഡാറ്റാഫ്രെയിമുകൾ സമാന്തരമായി പ്രോസസ്സ് ചെയ്യാൻ ഇത് നിങ്ങളെ അനുവദിക്കുന്നു, ഇത് പ്രകടനം ഗണ്യമായി മെച്ചപ്പെടുത്തും. ഡാസ്ക് ഡാറ്റാഫ്രെയിമിനെ ചെറിയ പാർട്ടീഷനുകളായി വിഭജിച്ച് ഒന്നിലധികം കോറുകളിലേക്കോ മെഷീനുകളിലേക്കോ വിതരണം ചെയ്യുന്നു.
import dask.dataframe as dd
# Create a Dask DataFrame
ddf = dd.read_csv('large_data.csv')
# Perform operations on the Dask DataFrame
ddf_filtered = ddf[ddf['col1'] > 500]
# Compute the result (this triggers the parallel computation)
result = ddf_filtered.compute()
print(result.head())
വേഗതയേറിയ ലുക്കപ്പുകൾക്കായി ഇൻഡെക്സിംഗ്
ഒരു കോളത്തിൽ ഒരു ഇൻഡെക്സ് സൃഷ്ടിക്കുന്നത് ലുക്കപ്പുകളും ഫിൽട്ടറിംഗ് പ്രവർത്തനങ്ങളും ഗണ്യമായി വേഗത്തിലാക്കാൻ കഴിയും. ഒരു പ്രത്യേക മൂല്യവുമായി പൊരുത്തപ്പെടുന്ന വരികൾ വേഗത്തിൽ കണ്ടെത്താൻ പാണ്ടസ് ഇൻഡെക്സുകൾ ഉപയോഗിക്കുന്നു.
ഉദാഹരണം:
# Set 'col3' as the index
df = df.set_index('col3')
# Faster lookup
value = df.loc['A']
print(value)
# Reset the index
df = df.reset_index()
എന്നിരുന്നാലും, വളരെയധികം ഇൻഡെക്സുകൾ സൃഷ്ടിക്കുന്നത് മെമ്മറി ഉപയോഗം വർദ്ധിപ്പിക്കുകയും റൈറ്റ് പ്രവർത്തനങ്ങളെ മന്ദഗതിയിലാക്കുകയും ചെയ്യും. ലുക്കപ്പുകൾക്കോ ഫിൽട്ടറിംഗിനോ പതിവായി ഉപയോഗിക്കുന്ന കോളങ്ങളിൽ മാത്രം ഇൻഡെക്സുകൾ സൃഷ്ടിക്കുക.
മറ്റ് പരിഗണനകൾ
- ഹാർഡ്വെയർ: നിങ്ങൾ സ്ഥിരമായി വലിയ ഡാറ്റാസെറ്റുകളിൽ പ്രവർത്തിക്കുന്നുണ്ടെങ്കിൽ നിങ്ങളുടെ ഹാർഡ്വെയർ (CPU, RAM, SSD) അപ്ഗ്രേഡ് ചെയ്യുന്നത് പരിഗണിക്കുക.
- സോഫ്റ്റ്വെയർ: നിങ്ങൾ പാണ്ടസിന്റെ ഏറ്റവും പുതിയ പതിപ്പാണ് ഉപയോഗിക്കുന്നതെന്ന് ഉറപ്പാക്കുക, കാരണം പുതിയ പതിപ്പുകളിൽ പലപ്പോഴും പ്രകടന മെച്ചപ്പെടുത്തലുകൾ ഉൾപ്പെടുന്നു.
- പ്രൊഫൈലിംഗ്: നിങ്ങളുടെ കോഡിലെ പ്രകടനത്തിലെ തടസ്സങ്ങൾ തിരിച്ചറിയാൻ പ്രൊഫൈലിംഗ് ടൂളുകൾ (ഉദാഹരണത്തിന്,
cProfile,line_profiler) ഉപയോഗിക്കുക. - ഡാറ്റാ സ്റ്റോറേജ് ഫോർമാറ്റ്: CSV-ക്ക് പകരം Parquet അല്ലെങ്കിൽ Feather പോലുള്ള കൂടുതൽ കാര്യക്ഷമമായ ഡാറ്റാ സ്റ്റോറേജ് ഫോർമാറ്റുകൾ ഉപയോഗിക്കുന്നത് പരിഗണിക്കുക. ഈ ഫോർമാറ്റുകൾ കോളമ്നാർ ആയതും പലപ്പോഴും കംപ്രസ് ചെയ്തതുമാണ്, ഇത് ചെറിയ ഫയൽ വലുപ്പത്തിലേക്കും വേഗതയേറിയ റീഡ്/റൈറ്റ് സമയങ്ങളിലേക്കും നയിക്കുന്നു.
ഉപസംഹാരം
വലിയ ഡാറ്റാസെറ്റുകളിൽ കാര്യക്ഷമമായി പ്രവർത്തിക്കുന്നതിന് പാണ്ടസ് ഡാറ്റാഫ്രെയിമുകൾ മെമ്മറി ഉപയോഗത്തിനും പ്രകടനത്തിനുമായി ഒപ്റ്റിമൈസ് ചെയ്യേണ്ടത് അത്യാവശ്യമാണ്. അനുയോജ്യമായ ഡാറ്റാ ടൈപ്പുകൾ തിരഞ്ഞെടുക്കുന്നതിലൂടെയും വെക്ടറൈസ്ഡ് ഓപ്പറേഷനുകൾ ഉപയോഗിക്കുന്നതിലൂടെയും നിങ്ങളുടെ ഡാറ്റയെ ഫലപ്രദമായി ഇൻഡെക്സ് ചെയ്യുന്നതിലൂടെയും നിങ്ങൾക്ക് മെമ്മറി ഉപഭോഗം ഗണ്യമായി കുറയ്ക്കാനും പ്രകടനം മെച്ചപ്പെടുത്താനും കഴിയും. പ്രകടനത്തിലെ തടസ്സങ്ങൾ തിരിച്ചറിയാൻ നിങ്ങളുടെ കോഡ് പ്രൊഫൈൽ ചെയ്യാൻ ഓർമ്മിക്കുക, വളരെ വലിയ ഡാറ്റാസെറ്റുകൾക്കായി ചങ്കിംഗ് അല്ലെങ്കിൽ ഡാസ്ക് ഉപയോഗിക്കുന്നത് പരിഗണിക്കുക. ഈ ടെക്നിക്കുകൾ നടപ്പിലാക്കുന്നതിലൂടെ, ഡാറ്റാ വിശകലനത്തിനും കൈകാര്യം ചെയ്യലിനും പാണ്ടസിന്റെ മുഴുവൻ കഴിവുകളും നിങ്ങൾക്ക് പ്രയോജനപ്പെടുത്താൻ കഴിയും.