⚡ مبانی Dask
Dask یک کتابخانه قدرتمند پایتون برای محاسبات موازی و پردازش دادههای بزرگتر از حافظه (Out-of-Core) است [citation:1][citation:3]. Dask با ارائه APIهای سطح بالا مشابه Pandas، NumPy و Scikit-learn، به شما امکان میدهد کدهای آشنا را روی دادههای بزرگتر و با استفاده از چندین هسته پردازشی یا حتی یک کلاستر اجرا کنید [citation:7][citation:8].
پیشنیاز: آشنایی با Pandas، NumPy و مفاهیم پایه پردازش داده.
🔹 نصب و مفاهیم پایه
# نصب (در محیط واقعی)
# pip install dask[complete]
import dask
import dask.dataframe as dd
import dask.array as da
import dask.bag as db
import pandas as pd
import numpy as np
print(f"Dask version: {dask.__version__}")
print("Dask imported successfully!")
🔹 تفاوت Dask و Pandas
import pandas as pd
import dask.dataframe as dd
# ===== Pandas: بارگذاری کامل در حافظه =====
# df = pd.read_csv('large_file.csv') # همه داده در RAM
# result = df.groupby('column').sum()
# ===== Dask: بارگذاری تکهتکه (lazy) =====
# ddf = dd.read_csv('large_file.csv') # فقط برنامهریزی
# result = ddf.groupby('column').sum().compute() # اجرا با compute()
# ===== تفاوتهای کلیدی =====
print("Pandas:")
print(" - داده را کامل در RAM بارگذاری میکند")
print(" - عملیات به صورت فوری (eager) اجرا میشوند")
print(" - برای دادههای کوچک و متوسط مناسب است")
print("\nDask:")
print(" - داده را به صورت تکهتکه (chunk) پردازش میکند")
print(" - عملیات به صورت تنبل (lazy) و با compute() اجرا میشوند")
print(" - برای دادههای بزرگتر از RAM و محاسبات موازی مناسب است")
🔹 Dask DataFrame
Dask DataFrame یک Pandas DataFrame تکهتکه شده (partitioned) است که هر تکه یک Pandas DataFrame معمولی است [citation:5][citation:7]. عملیات روی Dask DataFrame به صورت تنبل (lazy) انجام میشود و فقط با فراخوانی compute() اجرا میشوند [citation:4][citation:6].
import dask.dataframe as dd
import pandas as pd
import numpy as np
# ===== ایجاد داده نمونه =====
# در عمل از dd.read_csv() برای فایلهای بزرگ استفاده میشود
# ddf = dd.read_csv('large_file.csv', blocksize='100MB')
# ===== ایجاد Dask DataFrame از Pandas =====
pdf = pd.DataFrame({
'id': range(1, 101),
'name': ['User_' + str(i) for i in range(1, 101)],
'value': np.random.randint(0, 100, 100)
})
ddf = dd.from_pandas(pdf, npartitions=4)
print("Dask DataFrame:")
print(ddf)
print(f"Number of partitions: {ddf.npartitions}")
# ===== عملیات روی Dask DataFrame (lazy) =====
filtered = ddf[ddf['value'] > 50]
grouped = filtered.groupby('name')['value'].mean()
print("\nOperations are lazy (no computation yet):")
print(" - filter: lazy")
print(" - groupby: lazy")
# ===== اجرا با compute() =====
result = grouped.compute()
print("\nAfter compute():")
print(result.head())
# ===== استفاده از head() برای مشاهده سریع =====
print("\nFirst 5 rows (head):")
print(ddf.head())
🔹 Dask Array
Dask Array یک NumPy Array تکهتکه شده است که برای کار با آرایههای بزرگتر از حافظه طراحی شده است [citation:3][citation:5]. هر تکه یک NumPy Array است و عملیات به صورت موازی روی تکهها اجرا میشود.
import dask.array as da
import numpy as np
# ===== ایجاد Dask Array =====
# یک آرایه 10000x10000 با تکههای 1000x1000
x = da.random.random((10000, 10000), chunks=(1000, 1000))
print("Dask Array:")
print(x)
print(f"Chunks: {x.chunks}")
# ===== عملیات روی Dask Array (lazy) =====
mean = x.mean()
std = x.std()
sum_all = x.sum()
print("\nOperations are lazy:")
print(f" mean: {mean}")
print(f" std: {std}")
print(f" sum: {sum_all}")
# ===== اجرا با compute() =====
print("\nAfter compute():")
print(f" Mean: {mean.compute():.4f}")
print(f" Std: {std.compute():.4f}")
print(f" Sum: {sum_all.compute():.2f}")
# ===== عملیات ماتریسی =====
y = da.random.random((10000, 10000), chunks=(1000, 1000))
result = da.matmul(x, y)
print(f"\nMatrix multiplication shape: {result.shape}")
🔹 Dask Delayed (محاسبات سفارشی)
dask.delayed برای موازیسازی کدهای سفارشی استفاده میشود و به شما اجازه میدهد هر تابع پایتونی را به صورت موازی اجرا کنید [citation:4][citation:10].
import dask
from dask.delayed import delayed
import time
# ===== توابع نمونه =====
def add_two(x):
time.sleep(0.1) # شبیهسازی کار سنگین
return x + 2
def multiply_four(x):
time.sleep(0.1)
return x * 4
def sum_numbers(numbers):
return sum(numbers)
# ===== استفاده از delayed =====
data = [1, 5, 8, 10]
# ایجاد گرههای تاخیری (lazy)
step1 = [delayed(add_two)(i) for i in data]
step2 = [delayed(multiply_four)(j) for j in step1]
total = delayed(sum_numbers)(step2)
print("Lazy computation graph created:")
# ===== اجرا =====
start = time.time()
result = total.compute()
end = time.time()
print(f"Result: {result}")
print(f"Time: {end - start:.2f} seconds")
# ===== محاسبه موازی با چندین تابع =====
@delayed
def process_file(filename):
# شبیهسازی پردازش فایل
time.sleep(0.2)
return f"Processed {filename}"
files = ['file1.csv', 'file2.csv', 'file3.csv', 'file4.csv']
results = [process_file(f) for f in files]
combined = delayed(sum)(results)
print(f"\nParallel file processing: {combined.compute()}")
🔹 Dask Bag (دادههای نیمهساختاریافته)
Dask Bag برای پردازش دادههای نیمهساختاریافته مانند فایلهای JSON، لاگها و متنها استفاده میشود [citation:7].
import dask.bag as db
import json
# ===== ایجاد داده نمونه =====
data = [
{'id': 1, 'name': 'Saba', 'score': 95},
{'id': 2, 'name': 'Ali', 'score': 88},
{'id': 3, 'name': 'Reza', 'score': 72},
{'id': 4, 'name': 'Mina', 'score': 91},
{'id': 5, 'name': 'Hossein', 'score': 65}
]
# ===== ایجاد Bag =====
bag = db.from_sequence(data)
print("Dask Bag:")
print(bag)
# ===== عملیات روی Bag (مانند map/filter) =====
# فیلتر کردن دانشجویان با نمره بالای 80
high_scorers = bag.filter(lambda x: x['score'] > 80)
# استخراج نامها
names = high_scorers.map(lambda x: x['name'])
# ===== اجرا =====
print("\nStudents with score > 80:")
print(list(names.compute()))
# ===== جمعآوری آمار =====
total_score = bag.map(lambda x: x['score']).sum()
avg_score = bag.map(lambda x: x['score']).mean()
print(f"\nTotal score: {total_score.compute()}")
print(f"Average score: {avg_score.compute():.2f}")
# ===== پردازش فایلهای JSON =====
# در عمل: bag = db.read_text('logs/*.json').map(json.loads)
print("\nBag is ideal for processing JSON logs and semi-structured data.")
🔹 Distributed Client
dask.distributed.Client برای اجرای محاسبات روی چندین هسته یا چندین ماشین استفاده میشود [citation:1][citation:12].
from dask.distributed import Client
import dask.dataframe as dd
import pandas as pd
import numpy as np
# ===== راهاندازی Client محلی =====
# client = Client() # استفاده از همه هستههای CPU
# print(f"Dashboard URL: {client.dashboard_link}")
# ===== تنظیم تعداد Workers =====
# client = Client(n_workers=4, threads_per_worker=2)
# ===== مثال با Client =====
# ایجاد داده بزرگ
pdf = pd.DataFrame({
'id': range(1, 10001),
'value': np.random.randint(0, 100, 10000)
})
ddf = dd.from_pandas(pdf, npartitions=8)
# ===== محاسبه با Client =====
# با Client فعال، compute() به صورت توزیعشده اجرا میشود
result = ddf.groupby('id')['value'].mean().compute()
print("Distributed computation completed!")
print("\nClient features:")
print(" - Dashboard for monitoring")
print(" - Parallel execution across workers")
print(" - Fault tolerance")
print(" - Memory management")
# ===== بستن Client =====
# client.close()
🔹 Dask-ML (یادگیری ماشین با Dask)
dask-ml نسخه مقیاسپذیر Scikit-learn است که برای آموزش مدلهای یادگیری ماشین روی دادههای بزرگ طراحی شده است [citation:1][citation:12].
# pip install dask-ml
import dask.dataframe as dd
from dask_ml.preprocessing import StandardScaler
from dask_ml.model_selection import train_test_split
from dask_ml.linear_model import LogisticRegression
# ===== بارگذاری داده بزرگ =====
# ddf = dd.read_csv('large_dataset.csv')
# ===== پیشپردازش =====
# X = ddf[['feature1', 'feature2', 'feature3']]
# y = ddf['target']
# ===== تقسیم داده =====
# X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# ===== مقیاسسازی =====
# scaler = StandardScaler()
# X_train_scaled = scaler.fit_transform(X_train)
# X_test_scaled = scaler.transform(X_test)
# ===== آموزش مدل =====
# model = LogisticRegression()
# model.fit(X_train_scaled, y_train)
# ===== پیشبینی =====
# predictions = model.predict(X_test_scaled)
print("Dask-ML features:")
print(" - Scikit-learn compatible API")
print(" - Distributed training")
print(" - Scalable preprocessing")
print(" - Out-of-core learning")
print("\nSupported estimators:")
print(" - Linear models")
print(" - Tree-based models")
print(" - Clustering")
print(" - Preprocessing")
🔹 بهترین روشها و نکات
print("=" * 50)
print("WHEN TO USE DASK")
print("=" * 50)
print("\n✅ USE DASK WHEN:")
print(" - Data is larger than RAM (> 10GB)")
print(" - You have multiple CPU cores available")
print(" - You need to process many files in parallel")
print(" - Your computations are embarrassingly parallel")
print(" - You're using pandas but need to scale")
print("\n❌ DO NOT USE DASK WHEN:")
print(" - Data fits comfortably in RAM (< 1GB)")
print(" - You need low-latency queries (use database)")
print(" - Your operations are highly sequential")
print(" - You have many small tasks (overhead)")
print(" - You need interactive EDA on small data")
print("\n💡 BEST PRACTICES:")
print(" - Use blocksize for reading large files")
print(" - Call compute() only when you need results")
print(" - Use persist() for data used multiple times")
print(" - Monitor dashboard for performance")
print(" - Start with local cluster, then scale")
print(" - Use appropriate API (DataFrame/Array/Bag)")
print("\n📊 COMPARISON:")
print(" Pandas: Data fits in RAM, fast for small data")
print(" Dask: Data larger than RAM, multi-core")
print(" Spark: Very large clusters, SQL-heavy")
print(" DuckDB: Fast SQL on files without cluster")
🔹 مثال جامع: تحلیل داده بزرگ
import dask.dataframe as dd
import dask.array as da
import pandas as pd
import numpy as np
import time
class BigDataAnalyzer:
"""کلاس تحلیل داده بزرگ با Dask"""
def __init__(self, n_rows=100000):
self.n_rows = n_rows
self.ddf = None
self.darr = None
self.results = {}
def create_sample_data(self):
"""ایجاد داده نمونه بزرگ"""
print(f"Creating {self.n_rows:,} rows of sample data...")
# داده به صورت تکهتکه
pdf = pd.DataFrame({
'id': range(self.n_rows),
'value': np.random.randn(self.n_rows),
'category': np.random.choice(['A', 'B', 'C', 'D'], self.n_rows),
'group': np.random.choice(['X', 'Y', 'Z'], self.n_rows)
})
self.ddf = dd.from_pandas(pdf, npartitions=8)
self.darr = da.from_array(pdf['value'].values, chunks=(10000,))
return self
def analyze_dataframe(self):
"""تحلیل با Dask DataFrame"""
print("\n📊 DataFrame Analysis:")
# آمار پایه
self.results['mean'] = self.ddf['value'].mean().compute()
self.results['std'] = self.ddf['value'].std().compute()
print(f" Mean: {self.results['mean']:.4f}")
print(f" Std: {self.results['std']:.4f}")
# گروهبندی
grouped = self.ddf.groupby('category')['value'].mean().compute()
print(" Mean by category:")
for cat, val in grouped.items():
print(f" {cat}: {val:.4f}")
return self
def analyze_array(self):
"""تحلیل با Dask Array"""
print("\n🔢 Array Analysis:")
# محاسبات آرایه
arr_mean = self.darr.mean().compute()
arr_std = self.darr.std().compute()
arr_sum = self.darr.sum().compute()
print(f" Mean: {arr_mean:.4f}")
print(f" Std: {arr_std:.4f}")
print(f" Sum: {arr_sum:.2f}")
return self
def process_in_chunks(self):
"""پردازش تکهتکه (Out-of-Core)"""
print("\n📦 Chunk Processing:")
# پردازش تکهتکه با map_partitions
def process_chunk(df):
df['value_squared'] = df['value'] ** 2
return df
processed = self.ddf.map_partitions(process_chunk)
result = processed['value_squared'].mean().compute()
print(f" Mean of squared values: {result:.4f}")
return self
def filter_and_aggregate(self):
"""فیلتر و تجمیع"""
print("\n🔍 Filter and Aggregate:")
# فیلتر و محاسبه
filtered = self.ddf[self.ddf['category'].isin(['A', 'B'])]
result = filtered.groupby('group')['value'].agg(['mean', 'count']).compute()
print(" Group statistics (categories A & B):")
for idx, row in result.iterrows():
print(f" {idx}: mean={row['mean']:.4f}, count={row['count']}")
return self
def show_summary(self):
"""نمایش خلاصه"""
print("\n" + "=" * 50)
print("ANALYSIS SUMMARY")
print("=" * 50)
for key, value in self.results.items():
if isinstance(value, float):
print(f" {key}: {value:.4f}")
else:
print(f" {key}: {value}")
# ===== استفاده =====
if __name__ == "__main__":
start = time.time()
analyzer = BigDataAnalyzer(n_rows=100000)
analyzer.create_sample_data()
analyzer.analyze_dataframe()
analyzer.analyze_array()
analyzer.process_in_chunks()
analyzer.filter_and_aggregate()
analyzer.show_summary()
end = time.time()
print(f"\n⏱️ Total time: {end - start:.2f} seconds")
print("\n🚀 Dask makes big data processing easy and fast!")
print(" With Dask, you can scale from laptops to clusters.")
📌 نکات کلیدی
- ✅ Dask برای پردازش دادههای بزرگتر از RAM و محاسبات موازی طراحی شده است [citation:1][citation:3].
- ✅ Dask DataFrame نسخه مقیاسپذیر Pandas است که داده را به صورت تکهتکه (partitioned) پردازش میکند [citation:5][citation:7].
- ✅ Dask Array نسخه مقیاسپذیر NumPy است که آرایههای بزرگ را با chunking مدیریت میکند [citation:3].
- ✅ Dask Delayed برای موازیسازی کدهای سفارشی استفاده میشود [citation:4][citation:10].
- ✅ عملیات در Dask تنبل (lazy) هستند و با
compute()اجرا میشوند [citation:4][citation:6]. - ✅ Dask Client برای اجرای توزیعشده روی چندین هسته یا کلاستر استفاده میشود [citation:1][citation:12].
- ✅ Dask-ML امکان مقیاسپذیری Scikit-learn را برای دادههای بزرگ فراهم میکند [citation:12].
- ✅ Dask برای دادههای بیش از ۱۰ گیگابایت و عملیات موازی مناسب است [citation:7][citation:9].
- ✅ برای دادههای کوچک، Pandas سریعتر است و Dask سربار (overhead) اضافه میکند [citation:7][citation:9].