Python3
200 subscribers
100 photos
6 videos
26 files
518 links
🎓 آموزش و پروژه‌های Python
آموزش‌های کاربردی و پروژه‌های عملی Python برای همه سطوح. 🚀
Download Telegram
🎓 آموزش الگوریتم مرتب‌سازی رادیکس (پارت ۴)

🔰 تحلیل و بررسی Radix Sort

در این پارت پایانی، به بررسی عملکرد الگوریتم Radix Sort از نظر زمان اجرا، فضای موردنیاز، مزایا، معایب و کاربردهای آن می‌پردازیم. این اطلاعات به شما کمک می‌کند تا بدانید چه زمانی از این الگوریتم استفاده کنید. 📊



🌟 پیچیدگی زمانی Radix Sort

حالت عادی (Average Case):
اگر تعداد عناصر لیست n و بیشترین طول ارقام d باشد:
O(n * d)


یعنی زمان اجرا خطی است، به شرطی که تعداد ارقام d کوچک باشد.

حالت بدترین (Worst Case):
مشابه حالت عادی:
O(n * d)



حالت بهترین (Best Case):
باز هم همان پیچیدگی:
O(n * d)





🌟 پیچیدگی فضایی (Space Complexity):
Radix Sort به دلیل استفاده از آرایه کمکی (مثل آرایه شمارش)، به فضای اضافی نیاز دارد:
O(n + k)


که k تعداد مقدارهای ممکن در هر رقم است (برای اعداد دهدهی، معمولاً 10).



🌟 مزایا و معایب Radix Sort

مزایا:
1. پیچیدگی زمانی خطی: در داده‌هایی با تعداد رقم کم، Radix Sort عملکرد سریعی دارد.
2. مرتب‌سازی پایدار: ترتیب عناصر مشابه حفظ می‌شود، که در مسائل خاص مفید است.
3. عدم نیاز به مقایسه: برخلاف Quick Sort یا Merge Sort، این الگوریتم بر اساس مقایسه عمل نمی‌کند.

معایب:
1. نیاز به فضای اضافی: استفاده از آرایه‌های کمکی باعث مصرف حافظه بیشتری می‌شود.
2. محدودیت داده‌ها: این الگوریتم برای داده‌های با طول زیاد (مثل رشته‌های بسیار بزرگ) کارآمد نیست.
3. وابستگی به تعداد ارقام: اگر تعداد ارقام زیاد باشد، Radix Sort ناکارآمد می‌شود.

🌟 چه زمانی از Radix Sort استفاده کنیم؟
- داده‌های عددی بزرگ با ارقام کم: مانند کدهای پستی، شماره حساب‌ها و ...
- وقتی نیاز به مرتب‌سازی پایدار داریم: چون ترتیب عناصر با مقدار برابر حفظ می‌شود.
- وقتی مقایسه‌ها در مرتب‌سازی گران است: مثل داده‌های خاص که مقایسه‌ی مستقیم دشوار است.



🧩 نتیجه‌گیری
Radix Sort یک الگوریتم قدرتمند و کارآمد برای مرتب‌سازی اعداد است، مخصوصاً در شرایطی که تعداد ارقام محدود باشد. با این حال، اگر به فضای زیادی نیاز نداشته باشید یا داده‌های خاصی دارید، ممکن است الگوریتم‌های دیگر مانند Quick Sort یا Merge Sort انتخاب بهتری باشند.



🔗 بزن رو این تا بیشتر یاد بگیری

#آموزش_پایتون #مرتب_سازی #RadixSort #الگوریتم #پایتون #برنامه_نویسی
شبکه‌های عصبی مصنوعی: مغز ماشینی دنیای مدرن 🧠🤖

مقدمه: چرا شبکه‌های عصبی؟
تصور کنید می‌خواهید ماشینی بسازید که بتواند تصاویر را شناسایی کند، زبان انسان را بفهمد، یا حتی بازی‌هایی مانند شطرنج را بهتر از شما انجام دهد. برای رسیدن به این هدف، الهام‌بخش‌ترین الگو، مغز انسان است. مغز ما از میلیاردها سلول کوچک به نام نورون ساخته شده است که به صورت موازی کار می‌کنند تا اطلاعات را پردازش کنند. شبکه‌های عصبی مصنوعی (ANN) تلاش می‌کنند این فرایند را شبیه‌سازی کنند و این کار را با مدل‌سازی ریاضی و استفاده از سخت‌افزار‌های محاسباتی قدرتمند انجام می‌دهند.



شبکه عصبی چیست؟
یک شبکه عصبی مصنوعی مجموعه‌ای از واحدهای محاسباتی (که به آن‌ها نورون‌های مصنوعی یا گره‌ها گفته می‌شود) است که به صورت لایه‌ای سازمان‌دهی شده‌اند. این واحدها داده‌ها را پردازش کرده و اطلاعات را از یک لایه به لایه دیگر منتقل می‌کنند.

ساختار کلی:
1. لایه ورودی (Input Layer): داده‌های خام (مثل تصویر، صدا، یا عدد) وارد این لایه می‌شوند.
2. لایه‌های پنهان (Hidden Layers): این لایه‌ها همان‌جایی هستند که جادو رخ می‌دهد. در هر گره (یا نورون)، داده‌ها با وزن‌ها ضرب شده، جمع شده و از یک تابع غیرخطی (فعال‌سازی) عبور می‌کنند.
3. لایه خروجی (Output Layer): نتیجه نهایی (مثل پیش‌بینی یک کلاس یا تولید یک مقدار عددی) از این لایه به دست می‌آید.



چگونه یک نورون مصنوعی کار می‌کند؟
بیایید یک نورون ساده را بررسی کنیم:
1. هر نورون ورودی‌هایی از نورون‌های قبلی می‌گیرد (مثل داده خام یا خروجی یک نورون دیگر).
2. این ورودی‌ها با مقادیری به نام وزن‌ها (Weights) ضرب می‌شوند. وزن‌ها نشان می‌دهند که هر ورودی چقدر مهم است.
3. خروجی حاصل از وزن‌ها جمع می‌شود و یک مقدار بایاس (Bias) به آن اضافه می‌شود.
4. نتیجه به یک تابع فعال‌سازی (Activation Function) داده می‌شود تا غیرخطی شود. این مرحله بسیار مهم است، زیرا به مدل امکان می‌دهد مسائل پیچیده را حل کند.

فرمول ریاضی یک نورون:
import numpy as np

# داده‌های ورودی (مثال: ویژگی‌های یک داده)
inputs = np.array([1.2, 2.3, 3.4]) # x1, x2, x3

# وزن‌های هر ورودی (چقدر هر ورودی مهم است)
weights = np.array([0.5, -0.7, 0.9]) # w1, w2, w3

# مقدار بایاس (bias)
bias = 1.0 # مقدار ثابت اضافه‌شده

# محاسبه خروجی نورون
# 1. ضرب هر ورودی در وزن مربوطه
weighted_sum = np.dot(inputs, weights) # مجموع وزن‌دار x1*w1 + x2*w2 + x3*w3

# 2. افزودن بایاس
weighted_sum += bias # مجموع وزن‌دار به‌علاوه بایاس

# 3. اعمال تابع فعال‌سازی (برای غیرخطی‌سازی)
def activation_function(x):
return 1 / (1 + np.exp(-x)) # تابع سیگموید (نمونه‌ای از توابع فعال‌سازی)

output = activation_function(weighted_sum) # نتیجه نهایی نورون

# چاپ خروجی
print(f"Weighted Sum: {weighted_sum}")
print(f"Neuron Output: {output}")

یک مثال ساده:
فرض کنید می‌خواهید دمای یک روز را پیش‌بینی کنید. ورودی‌ها می‌توانند شامل رطوبت، فشار، و سرعت باد باشند. نورون شما این ورودی‌ها را گرفته، با وزن‌های مناسب ترکیب کرده و خروجی را تولید می‌کند.



اتفاقات پشت پرده: محاسبات روی سخت‌افزار
1. سخت‌افزار محاسباتی:
شبکه‌های عصبی نیازمند حجم زیادی از محاسبات موازی هستند. اینجا جایی است که پردازنده‌ها (CPU) و واحدهای پردازش گرافیکی (GPU/TPU) وارد عمل می‌شوند:
- CPU (واحد پردازش مرکزی): وظایف سریالی و عملیات منطقی را اجرا می‌کند. مناسب برای کارهای سبک و کنترل کلی سیستم.
- GPU (واحد پردازش گرافیکی): طراحی‌شده برای پردازش موازی. ایده‌آل برای انجام محاسبات ماتریسی سنگین در شبکه‌های عصبی.
- TPU (واحد پردازش تنسوری): سخت‌افزار خاص گوگل برای شتاب‌دهی به محاسبات یادگیری ماشین. سرعت بسیار بالایی در عملیات ماتریسی دارد.

2. محاسبات ماتریسی:
- هر لایه از شبکه عصبی را می‌توان به شکل یک ضرب ماتریسی بزرگ در نظر گرفت. به همین دلیل GPU‌ها و TPU‌ها در این زمینه کارآمد هستند.
- مثال:
اگر لایه‌ای 1000 ورودی و 500 نورون داشته باشد ضرب ماتریسی میشود.

3. بهینه‌سازی حافظه:
برای اجرای مدل‌های بزرگ، حافظه بهینه استفاده می‌شود. بچ‌پردازش (Batch Processing) به مدل کمک می‌کند تا داده‌ها را به دسته‌های کوچک‌تر تقسیم کرده و پردازش کند.



آموزش شبکه عصبی:
شبکه‌های عصبی باید آموزش داده شوند تا بتوانند وظایف خاصی را به درستی انجام دهند. این فرایند شامل مراحل زیر است:
👍1
1. فاز پیش‌رو (Forward Pass):
- داده از لایه‌های شبکه عبور می‌کند و خروجی تولید می‌شود.
- هر نورون ورودی را پردازش کرده و خروجی را به نورون بعدی ارسال می‌کند.

2. محاسبه خطا (Loss Calculation):
- خطا (Loss) میزان اختلاف بین خروجی مدل و مقدار واقعی (برچسب) را نشان می‌دهد.
- توابعی مثل MSE یا Cross-Entropy برای محاسبه خطا استفاده می‌شوند.

3. فاز پس‌انتشار (Backward Pass):
- با استفاده از الگوریتم پس‌انتشار (Backpropagation)، خطا به عقب شبکه منتقل می‌شود.
- گرادیان نزولی (Gradient Descent) وزن‌ها را به‌گونه‌ای به‌روزرسانی می‌کند که خطا کاهش یابد.



سوال مهم: چرا شبکه‌های عصبی اینقدر قدرتمند هستند؟
1. توانایی یادگیری غیرخطی: به لطف توابع فعال‌سازی، شبکه‌های عصبی می‌توانند روابط پیچیده غیرخطی را یاد بگیرند.
2. مقیاس‌پذیری: شبکه‌های عصبی بزرگ‌تر و عمیق‌تر می‌توانند وظایف پیچیده‌تری را انجام دهند.
3. تنوع کاربرد: از تشخیص تصویر گرفته تا پردازش زبان طبیعی (NLP) و پیش‌بینی سری‌های زمانی.



چالش‌ها و محدودیت‌ها:
1. نیاز به داده‌های زیاد برای آموزش.
2. مصرف منابع محاسباتی بالا.
3. حساسیت به تنظیمات هایپرپارامترها.



مثالی واقعی: شناسایی دست‌نوشته با شبکه عصبی
فرض کنید می‌خواهید اعداد دست‌نوشته را شناسایی کنید:
1. ورودی: تصویر 28x28 پیکسلی از یک عدد.
2. لایه‌های پنهان: نورون‌ها ویژگی‌هایی مثل خطوط و منحنی‌ها را شناسایی می‌کنند.
3. خروجی: یکی از 10 عدد (0 تا 9).



نتیجه‌گیری: آینده شبکه‌های عصبی
شبکه‌های عصبی قلب تپنده هوش مصنوعی مدرن هستند. از شناسایی چهره گرفته تا ترجمه زبان و حتی رانندگی خودکار، این مدل‌ها به زندگی ما شکل جدیدی داده‌اند. با پیشرفت سخت‌افزار و الگوریتم‌ها، شبکه‌های عصبی روزبه‌روز هوشمندتر می‌شوند.
👍1
مثال

import numpy as np

# ======= توابع فعال‌سازی برای هر نورون =======
def sigmoid(x):
return 1 / (1 + np.exp(-x))

def relu(x):
return np.maximum(0, x)

# ======= تعریف نورون‌ها به صورت توابع مستقل =======
def neuron_1(inputs, weights, bias):
return relu(np.dot(inputs, weights) + bias)

def neuron_2(inputs, weights, bias):
return sigmoid(np.dot(inputs, weights) + bias)

def neuron_3(inputs, weights, bias):
return np.tanh(np.dot(inputs, weights) + bias)

def neuron_4(inputs, weights, bias):
return np.exp(-np.abs(np.dot(inputs, weights) + bias))

# ======= تنظیمات شبکه =======
np.random.seed(42)

# تعداد نورون‌های هر لایه
input_neurons = 2
hidden_neurons = [3, 3, 3, 3] # چهار لایه پنهان با مجموع 12 نورون
output_neurons = 2

# ======= وزن‌ها و بایاس‌ها =======
weights = {
"layer_1": np.random.randn(input_neurons, hidden_neurons[0]),
"layer_2": np.random.randn(hidden_neurons[0], hidden_neurons[1]),
"layer_3": np.random.randn(hidden_neurons[1], hidden_neurons[2]),
"layer_4": np.random.randn(hidden_neurons[2], hidden_neurons[3]),
"output": np.random.randn(hidden_neurons[3], output_neurons)
}

biases = {
"layer_1": np.random.randn(hidden_neurons[0]),
"layer_2": np.random.randn(hidden_neurons[1]),
"layer_3": np.random.randn(hidden_neurons[2]),
"layer_4": np.random.randn(hidden_neurons[3]),
"output": np.random.randn(output_neurons)
}

# ======= ورودی اولیه =======
inputs = np.array([0.5, -1.5])

# ======= فاز پیش‌رو (Forward Pass) =======
# لایه 1
layer_1_output = np.array([
neuron_1(inputs, weights["layer_1"][:, 0], biases["layer_1"][0]),
neuron_2(inputs, weights["layer_1"][:, 1], biases["layer_1"][1]),
neuron_3(inputs, weights["layer_1"][:, 2], biases["layer_1"][2])
])

# لایه 2
layer_2_output = np.array([
neuron_2(layer_1_output, weights["layer_2"][:, 0], biases["layer_2"][0]),
neuron_3(layer_1_output, weights["layer_2"][:, 1], biases["layer_2"][1]),
neuron_4(layer_1_output, weights["layer_2"][:, 2], biases["layer_2"][2])
])

# لایه 3
layer_3_output = np.array([
neuron_1(layer_2_output, weights["layer_3"][:, 0], biases["layer_3"][0]),
neuron_3(layer_2_output, weights["layer_3"][:, 1], biases["layer_3"][1]),
neuron_4(layer_2_output, weights["layer_3"][:, 2], biases["layer_3"][2])
])

# لایه 4
layer_4_output = np.array([
neuron_2(layer_3_output, weights["layer_4"][:, 0], biases["layer_4"][0]),
neuron_3(layer_3_output, weights["layer_4"][:, 1], biases["layer_4"][1]),
neuron_4(layer_3_output, weights["layer_4"][:, 2], biases["layer_4"][2])
])

# لایه خروجی
output = np.array([
neuron_1(layer_4_output, weights["output"][:, 0], biases["output"][0]),
neuron_2(layer_4_output, weights["output"][:, 1], biases["output"][1])
])

# ======= نمایش خروجی =======
print("Input:", inputs)
print("Layer 1 Output:", layer_1_output)
print("Layer 2 Output:", layer_2_output)
print("Layer 3 Output:", layer_3_output)
print("Layer 4 Output:", layer_4_output)
print("Final Output:", output)
👍2
پارت ۱: مقدمات پیشرفته حلقه for (قسمت ۱/۴)

در این قسمت، وارد مفاهیم اولیه و ساختارهای پایه حلقه for در پایتون می‌شویم. این موضوع به شما کمک می‌کند پایه‌ای محکم برای مباحث پیشرفته‌تر بسازید.

---

1. مفهوم for در پایتون
برخلاف زبان‌هایی مثل C++ یا Java که از شاخص‌ها استفاده می‌کنند، پایتون از Iterable Objects استفاده می‌کند. یعنی:
- حلقه for مستقیماً با مقادیر مجموعه کار می‌کند، نه صرفاً شاخص‌ها.
- هر چیزی که قابل تکرار (Iterable) باشد، می‌تواند در حلقه for پیمایش شود.

2. ساختار کلی حلقه for
for variable in iterable:
# دستورات

- variable: متغیری که در هر دور حلقه، مقدار جدیدی از iterable دریافت می‌کند.
- iterable: هر مجموعه‌ای مثل لیست، رشته، تاپل، دیکشنری یا حتی یک فایل.

مثال پایه‌ای:
names = ['Alice', 'Bob', 'Charlie']
for name in names:
print(name)

خروجی:
Alice  
Bob
Charlie

---

3. پیمایش روی اعداد با range()
تابع range() ابزاری قدرتمند برای تولید توالی عددی است.

مثال:
for i in range(5):  # تولید اعداد از 0 تا 4
print(i)

خروجی:
0  
1
2
3
4

تخصیص محدوده در range():
تابع range() سه پارامتر دارد:
- شروع (اختیاری): عدد شروع (پیش‌فرض ۰).
- پایان: عدد انتهایی (این عدد شامل نمی‌شود).
- گام (اختیاری): فاصله بین اعداد.

مثال پیشرفته‌تر:
for i in range(2, 10, 2):  # تولید اعداد ۲، ۴، ۶، ۸
print(i)

---

4. حلقه بدون بدنه (حلقه خالی)
در مواقعی که فقط نیاز دارید حلقه‌ای را اجرا کنید بدون اینکه کاری درون آن انجام دهید، از کلمه کلیدی pass استفاده کنید:
for _ in range(5):
pass # حلقه اجرا می‌شود ولی کاری انجام نمی‌دهد

---

ادامه دارد...
در قسمت دوم، با حلقه‌های تو در تو و ابزارهای حرفه‌ای مانند enumerate آشنا خواهیم شد.

برای دیدن پارت های بعدی و آموزش های بیشتر در این چنل عضو شوید
پارت ۱: مقدمات پیشرفته حلقه for (قسمت ۲/۴)

در این قسمت، به موضوعات پیشرفته‌تر مانند حلقه‌های تو در تو (Nested Loops) و استفاده از ابزارهای حرفه‌ای مثل enumerate و zip می‌پردازیم. این موارد به شما کمک می‌کند از حلقه for به شیوه‌ای بهینه‌تر استفاده کنید.

---

1. حلقه‌های تو در تو (Nested Loops)
گاهی اوقات برای پردازش داده‌های چندلایه (مثل لیست‌های تو در تو)، نیاز به حلقه‌های تو در تو دارید.

مثال: پیمایش یک لیست تو در تو
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]

for row in matrix:
for item in row:
print(item, end=" ") # نمایش همه اعداد در یک خط

خروجی:
1 2 3 4 5 6 7 8 9

مثال: محاسبه مجموع عناصر
total = 0
for row in matrix:
for item in row:
total += item
print(f"Total: {total}")

خروجی:
Total: 45

---

2. پیمایش همراه با اندیس (Index) با enumerate
تابع enumerate امکان پیمایش همزمان مقدار و اندیس هر عنصر را می‌دهد.

مثال:
names = ['Alice', 'Bob', 'Charlie']
for index, name in enumerate(names):
print(f"{index}: {name}")

خروجی:
0: Alice  
1: Bob
2: Charlie

کاربرد: پیدا کردن موقعیت یک عنصر خاص
numbers = [10, 20, 30, 40]
for index, num in enumerate(numbers):
if num == 30:
print(f"Found 30 at index {index}")
break

خروجی:
Found 30 at index 2

---

3. پیمایش همزمان چند مجموعه با zip
تابع zip این امکان را فراهم می‌کند که چند لیست یا مجموعه را همزمان پیمایش کنید.

مثال:
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]

for name, age in zip(names, ages):
print(f"{name} is {age} years old.")

خروجی:
Alice is 25 years old.  
Bob is 30 years old.
Charlie is 35 years old.

---

4. ترکیب enumerate و zip برای پیمایش پیشرفته
می‌توانید enumerate و zip را با هم ترکیب کنید تا اندیس‌ها و مقادیر چند مجموعه را همزمان مدیریت کنید.

مثال:
for index, (name, age) in enumerate(zip(names, ages)):
print(f"{index}: {name} - {age}")

خروجی:
0: Alice - 25  
1: Bob - 30
2: Charlie - 35

---

ادامهقسمت سوم
در قسمت سوم، به موضوعات پیشرفته‌تر مانند فیلتر کردن داده‌ها، استفاده از حلقه‌ها در شرط‌ها، و ساختارهای List Comprehension می‌پردازیم.

برای دیدن پارت های بعدی و آموزش های بیشتر در این چنل عضو شوید
پارت ۱: مقدمات پیشرفته حلقه for (قسمت ۳/۴)

در این قسمت، به مباحث پیشرفته‌تری مانند فیلتر کردن داده‌ها و استفاده از حلقه‌ها در ساختارهای شرطی و List Comprehension می‌پردازیم.

۱. فیلتر کردن داده‌ها در حلقه for
در پایتون می‌توانید با استفاده از شرط‌ها درون حلقه for، داده‌های مورد نظر خود را فیلتر کنید.

- مثال: فیلتر کردن اعداد زوج
numbers = [1, 2, 3, 4, 5, 6]  
for num in numbers:
if num % 2 == 0:
print(num)

خروجی:
۲
۴
۶

- مثال: فیلتر کردن رشته‌های طولانی‌تر از ۳ کاراکتر
words = ['cat', 'dog', 'elephant', 'fox']  
for word in words:
if len(word) > 3:
print(word)

خروجی:
elephant

۲. استفاده از حلقه‌ها در شرط‌ها
گاهی اوقات نیاز است که وجود یا عدم وجود یک عنصر خاص را بررسی کنید.

- مثال: بررسی وجود یک عنصر
numbers = [10, 20, 30, 40]  
target = 30

found = False
for num in numbers:
if num == target:
found = True
break

if found:
print("Number found!")
else:
print("Number not found!")

خروجی:
Number found!

۳. معرفی List Comprehension
List Comprehension یکی از روش‌های کوتاه و قدرتمند برای تولید یا فیلتر کردن لیست‌ها است.

- مثال ۱: تولید یک لیست جدید با اعداد زوج
numbers = [1, 2, 3, 4, 5, 6]  
even_numbers = [num for num in numbers if num % 2 == 0]
print(even_numbers)

خروجی:
[2, 4, 6]

- مثال ۲: تولید مقادیر مربع یک لیست
numbers = [1, 2, 3, 4, 5]  
squares = [num**2 for num in numbers]
print(squares)

خروجی:
[1, 4, 9, 16, 25]

۴. Nested List Comprehension (پیشرفته)
می‌توانید لیست‌های تو در تو را با استفاده از List Comprehension پردازش کنید.

- مثال: صاف کردن یک لیست تو در تو
matrix = [  
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]

flattened = [item for row in matrix for item in row]
print(flattened)

خروجی:
[1, 2, 3, 4, 5, 6, 7, 8, 9]

ادامه دارد...
در قسمت چهارم (پایانی)، تکنیک‌های بسیار پیشرفته‌ای مانند استفاده از حلقه for برای ایجاد دیکشنری‌ها و مجموعه‌ها، و همچنین کاربردهای خاص با generatorها را یاد خواهیم گرفت.

برای دیدن پارت های بعدی و آموزش های بیشتر در این چنل عضو شوید
پارت ۱: مقدمات پیشرفته حلقه for (قسمت ۴/۴)

در این قسمت پایانی، به مباحث پیشرفته‌تر مانند استفاده از حلقه for برای ایجاد دیکشنری‌ها، مجموعه‌ها و کاربردهای خاص با generatorها پرداخته‌ایم. این تکنیک‌ها به شما کمک می‌کند از قدرت حلقه‌ها بهره‌برداری بیشتری کنید.

---

۱. ایجاد دیکشنری‌ها با for
حلقه for می‌تواند برای ساخت دیکشنری‌های پیچیده استفاده شود. با استفاده از Dictionary Comprehension می‌توانید دیکشنری‌ها را به صورت سریع و بهینه بسازید.

مثال: ساخت دیکشنری از اعداد و مربعات آنها
numbers = [1, 2, 3, 4, 5]  
squares_dict = {num: num**2 for num in numbers}
print(squares_dict)

خروجی:
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

مثال: تبدیل لیست به دیکشنری با استفاده از zip
keys = ['a', 'b', 'c']  
values = [1, 2, 3]
dictionary = {key: value for key, value in zip(keys, values)}
print(dictionary)

خروجی:
{'a': 1, 'b': 2, 'c': 3}

---

۲. ایجاد مجموعه‌ها (Sets) با for
برای ساخت مجموعه‌ها از Set Comprehension استفاده می‌کنیم که مشابه به List Comprehension است ولی به جای لیست، مجموعه‌ای ایجاد می‌شود.

مثال: ساخت مجموعه‌ای از اعداد زوج
numbers = [1, 2, 3, 4, 5, 6]  
even_set = {num for num in numbers if num % 2 == 0}
print(even_set)

خروجی:
{2, 4, 6}

---

۳. استفاده از for با generatorها
Generatorها ابزاری هستند که برای تولید مقادیر به صورت تدریجی و بهینه طراحی شده‌اند. در پایتون، می‌توانیم از یک حلقه for برای ایجاد یک generator استفاده کنیم.

مثال: ساخت generator برای اعداد زوج
def even_numbers(limit):  
for num in range(0, limit, 2):
yield num

evens = even_numbers(10)
for even in evens:
print(even)

خروجی:
0
2
4
6
8

توجه: به جای تولید همه مقادیر در یک لحظه، generator مقادیر را به تدریج تولید می‌کند و در نتیجه حافظه کمتری مصرف می‌شود.

---

۴. ترکیب for با توابع و شرایط پیچیده
حلقه for را می‌توان با توابع و شرایط پیچیده ترکیب کرد تا کدهایی بهینه و قدرتمند بسازیم.

مثال: ترکیب حلقه با تابع و شرط
def is_prime(num):  
if num < 2:
return False
for i in range(2, num):
if num % i == 0:
return False
return True

numbers = [10, 15, 17, 20, 23, 25]
primes = [num for num in numbers if is_prime(num)]
print(primes)

خروجی:
[17, 23]

---

خلاصه
در این مجموعه آموزش‌ها، شما با تکنیک‌های پیشرفته و کاربردی حلقه for در پایتون آشنا شدید. با استفاده از این روش‌ها می‌توانید کدهای بهینه، خوانا و قدرتمندتری بنویسید که در پردازش داده‌ها و حل مسائل پیچیده کمک زیادی به شما خواهد کرد.

---

پایان پارت ۱

اگر مایلید که به یادگیری بیشتر ادامه دهید، می‌توانید پارت‌های بعدی را مطالعه کرده و به تمرین با کدهای جدید بپردازید!

برای دیدن پارت های بعدی و آموزش های بیشتر در این چنل عضو شوید
👏3
پارت ۲: کاربردهای پیشرفته حلقه for (قسمت ۱/۴)

۱. حلقه‌های تو در تو (Nested Loops):
حلقه‌های تو در تو برای پیمایش در ساختارهای داده‌ای چندبعدی مثل ماتریس یا لیست‌های تودرتو بسیار مفید هستند.
مثال:
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]

for row in matrix:
for elem in row:
print(elem)

خروجی:
1
2
3
4
5
6
7
8
9

۲. استفاده از enumerate() برای دسترسی به ایندکس‌ها:
تابع enumerate() این امکان را می‌دهد که همزمان با پیمایش یک مجموعه، به ایندکس و مقدار آن دسترسی داشته باشید.
مثال:
names = ['Alice', 'Bob', 'Charlie']

for index, name in enumerate(names):
print("Index:", index, "Name:", name)

خروجی:
Index: 0 Name: Alice
Index: 1 Name: Bob
Index: 2 Name: Charlie

۳. استفاده از zip() برای پیمایش همزمان چند مجموعه:
اگر نیاز دارید که دو یا چند مجموعه را به صورت همزمان پیمایش کنید، از تابع zip() استفاده کنید.
مثال:
names = ['Alice', 'Bob', 'Charlie']
scores = [85, 90, 88]

for name, score in zip(names, scores):
print(name, "scored", score)

خروجی:
Alice scored 85
Bob scored 90
Charlie scored 88

۴. فیلتر کردن داده‌ها در حلقه for:
با استفاده از شرط‌های منطقی در حلقه، می‌توانید داده‌های خاصی را فیلتر کنید.
مثال:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
odd_numbers = [num for num in numbers if num % 2 != 0]
print(odd_numbers)

خروجی:
[1, 3, 5, 7, 9]

۵. حلقه خالی با pass:
گاهی نیاز دارید یک حلقه را تعریف کنید ولی هنوز کاری در آن انجام ندهید. در این موارد از pass استفاده کنید.
مثال:
for _ in range(5):
pass # حلقه بدون هیچ عملیات

---

در قسمت بعدی، به کاربردهای پیچیده‌تر و حرفه‌ای‌تر حلقه for خواهیم پرداخت. منتظر باشید!

برای دیدن قسمت های بعدی آموزش اینجا کلیک کن
👍1
پارت ۲: کاربردهای پیشرفته حلقه for (قسمت ۲/۴)

---

۱. استفاده از else در حلقه for:
برخلاف تصور رایج، حلقه for می‌تواند دارای بلوک else باشد. این بلوک تنها زمانی اجرا می‌شود که حلقه به طور کامل اجرا شده باشد (و نه با break متوقف شود).
مثال:
for num in [1, 2, 3, 4]:
if num == 5:
break
else:
print("Loop completed without break.")

خروجی:
Loop completed without break.

---

۲. استفاده از break و continue:
- break: حلقه را بلافاصله متوقف می‌کند.
- continue: اجرای آن دور حلقه را رد کرده و به دور بعدی می‌رود.
مثال:
for i in range(5):
if i == 2:
continue
if i == 4:
break
print(i)

خروجی:
0  
1
3

---

۳. پیمایش معکوس با reversed():
با استفاده از تابع reversed() می‌توانید یک مجموعه را به صورت معکوس پیمایش کنید.
مثال:
numbers = [1, 2, 3, 4, 5]
for num in reversed(numbers):
print(num)

خروجی:
5  
4
3
2
1

---

۴. حلقه‌های تو در تو با ترکیب enumerate():
می‌توانید از enumerate() در حلقه‌های تو در تو برای دسترسی به ایندکس‌ها و مقادیر استفاده کنید.
مثال:
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]

for row_index, row in enumerate(matrix):
for col_index, value in enumerate(row):
print(f"Value at ({row_index}, {col_index}) is {value}")

خروجی:
Value at (0, 0) is 1  
Value at (0, 1) is 2
...
Value at (2, 2) is 9

---

۵. ترکیب zip() با enumerate():
با ترکیب zip() و enumerate() می‌توانید به طور همزمان به ایندکس و مقادیر دو یا چند مجموعه دسترسی داشته باشید.
مثال:
names = ['Alice', 'Bob', 'Charlie']
scores = [85, 90, 88]

for index, (name, score) in enumerate(zip(names, scores)):
print(f"{index}: {name} scored {score}")

خروجی:
0: Alice scored 85  
1: Bob scored 90
2: Charlie scored 88

---

در قسمت سوم، به تکنیک‌های پیشرفته‌تر و بهینه‌سازی‌های خاص در حلقه for خواهیم پرداخت. منتظر باشید!

برای دیدن قسمت های بعدی آموزش اینجا کلیک کن
👍2
پارت ۲: کاربردهای پیشرفته حلقه for (قسمت ۳/۴)

---

۱. استفاده از List Comprehensions برای فیلتر داده‌ها:
List Comprehensions می‌تواند با شرط‌های اضافی ترکیب شود تا داده‌ها را فیلتر کند.
مثال:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
odd_numbers = [num for num in numbers if num % 2 != 0]
print(odd_numbers)


خروجی:
[1, 3, 5, 7, 9]



---

۲. ساخت مجموعه (Set Comprehensions) با حلقه for:
مشابه لیست‌ها، می‌توانید مجموعه‌هایی ایجاد کنید که مقادیر تکراری را حذف می‌کنند.
مثال:
numbers = [1, 2, 2, 3, 4, 4, 5]
unique_squares = {x ** 2 for x in numbers}
print(unique_squares)


خروجی:
{1, 4, 9, 16, 25}



---

۳. استفاده از Dictionary Comprehensions:
با حلقه for می‌توانید دیکشنری‌های جدید بسازید.
مثال:
keys = ['a', 'b', 'c']
values = [1, 2, 3]
dictionary = {key: value for key, value in zip(keys, values)}
print(dictionary)


خروجی:
{'a': 1, 'b': 2, 'c': 3}



---

۴. پیمایش با حلقه for و پردازش شرطی داده‌ها:
می‌توانید از حلقه for همراه با شرط برای انتخاب داده‌ها استفاده کنید.
مثال:
words = ["apple", "banana", "cherry", "date"]
short_words = [word for word in words if len(word) <= 5]
print(short_words)


خروجی:
['apple', 'date']



---

۵. ترکیب چندین حلقه در List Comprehensions:
می‌توانید از چند حلقه for در یک List Comprehension استفاده کنید.
مثال:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened)


خروجی:
[1, 2, 3, 4, 5, 6, 7, 8, 9]



---

۶. استفاده از تابع any() و all() در حلقه‌های for:
این توابع برای بررسی شرط‌هایی روی داده‌ها در حلقه for کاربرد دارند.
مثال:
numbers = [2, 4, 6, 8]
all_even = all(num % 2 == 0 for num in numbers)
print(all_even)


خروجی:
True



---

در قسمت بعدی، به تکنیک‌های بهینه‌سازی و مفاهیم پیشرفته‌تر خواهیم پرداخت. منتظر باشید!

برای دیدن قسمت های بعدی آموزش اینجا کلیک کن
👍1
پارت ۲: کاربردهای پیشرفته حلقه for (قسمت ۴/۴)


۱. حلقه for با itertools:
ماژول itertools مجموعه‌ای از ابزارهای قدرتمند برای کار با حلقه‌ها ارائه می‌دهد.
مثال: استفاده از itertools.cycle برای تکرار بی‌نهایت:
import itertools

colors = ['red', 'green', 'blue']
for color in itertools.cycle(colors):
print(color)
break # برای جلوگیری از حلقه بی‌پایان


خروجی:
red  
green
blue



---

۲. حلقه‌های موازی با itertools.product:
برای ایجاد ترکیب تمام مقادیر دو مجموعه، از itertools.product استفاده کنید.
مثال:
import itertools

letters = ['A', 'B']
numbers = [1, 2]
combinations = itertools.product(letters, numbers)

for combo in combinations:
print(combo)


خروجی:
('A', 1)  
('A', 2)
('B', 1)
('B', 2)



---

۳. کار با enumerate در شرایط خاص:
enumerate می‌تواند شروع ایندکس را سفارشی کند.
مثال:
fruits = ['apple', 'banana', 'cherry']
for index, fruit in enumerate(fruits, start=1):
print(f"{index}: {fruit}")


خروجی:
1: apple  
2: banana
3: cherry



---

۴. ایجاد حلقه‌های بی‌پایان با while و for ترکیبی:
می‌توانید از یک حلقه for به همراه حلقه while برای پردازش بی‌پایان استفاده کنید.
مثال:
counter = 0
for char in 'ABC':
while counter < 3:
print(f"{char}-{counter}")
counter += 1


خروجی:
A-0  
A-1
A-2



---

۵. فیلتر داده‌ها با حلقه و شرط‌های چندگانه:
می‌توانید از شرط‌های ترکیبی برای فیلتر دقیق‌تر داده‌ها استفاده کنید.
مثال:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
filtered_numbers = [num for num in numbers if num > 4 and num % 2 == 0]
print(filtered_numbers)


خروجی:
[6, 8]



---

۶. استفاده از توابع lambda در حلقه‌های for:
ترکیب توابع lambda با حلقه‌ها امکان پردازش‌های پیچیده را فراهم می‌کند.
مثال:
numbers = [1, 2, 3, 4]
squared = list(map(lambda x: x ** 2, numbers))
print(squared)


خروجی:
[1, 4, 9, 16]



---

پایان پارت ۲: کاربردهای پیشرفته حلقه for

در این پارت، تکنیک‌های متنوعی از جمله استفاده از ماژول itertools، کار با enumerate و ترکیب شرط‌های مختلف را بررسی کردیم. این مفاهیم، شما را برای نوشتن کدهای پیشرفته‌تر و حرفه‌ای‌تر آماده می‌کند.

در پارت ۳، به سراغ بهینه‌سازی حلقه‌ها و نکات پیشرفته‌تر می‌رویم. منتظر باشید!

برای دیدن قسمت های بعدی آموزش اینجا کلیک کن
👍4
پارت ۳: بهینه‌سازی حلقه‌های for در پایتون (قسمت ۱/۴)



مقدمه
بهینه‌سازی حلقه‌ها یکی از مهم‌ترین مراحل بهبود کارایی کدهای پایتون است. در این قسمت، با اصول اولیه بهینه‌سازی آشنا می‌شویم و سعی می‌کنیم با استفاده از تکنیک‌های ساده و کاربردی، حلقه‌های سریع‌تر و کارآمدتری بنویسیم.



۱. استفاده از List Comprehension به‌جای حلقه‌های معمولی

توضیح:
اگر هدف شما ساخت یک لیست جدید از عناصر یک مجموعه دیگر باشد، List Comprehension از نظر خوانایی و سرعت بسیار بهتر از روش سنتی حلقه‌ها عمل می‌کند.

مثال: ساخت لیستی از اعداد مربع‌شده
روش سنتی:
numbers = [1, 2, 3, 4]
squared_numbers = []
for num in numbers:
squared_numbers.append(num ** 2)
print(squared_numbers)

با استفاده از List Comprehension:
numbers = [1, 2, 3, 4]
squared_numbers = [num ** 2 for num in numbers]
print(squared_numbers)

مزایا:
- کاهش خطوط کد
- افزایش سرعت در اجرای کد
- افزایش خوانایی

مقایسه سرعت:
در پروژه‌های بزرگ، List Comprehension معمولاً سریع‌تر عمل می‌کند.



۲. استفاده از Generator Expression برای صرفه‌جویی در حافظه

توضیح:
زمانی که نیازی به ذخیره همه مقادیر در حافظه ندارید (مثل زمانی که مقادیر فقط یک‌بار استفاده می‌شوند)، Generator Expression گزینه مناسبی است.

مثال:
با لیست:
numbers = [1, 2, 3, 4]
squared_numbers = [num ** 2 for num in numbers]
for sq in squared_numbers:
print(sq)

با Generator Expression:
numbers = [1, 2, 3, 4]
squared_numbers = (num ** 2 for num in numbers)
for sq in squared_numbers:
print(sq)

تفاوت اصلی:
- لیست: تمام مقادیر در حافظه ذخیره می‌شوند.
- جنراتور: مقادیر به‌صورت لحظه‌ای تولید می‌شوند و در حافظه ذخیره نمی‌شوند.

نکته: جنراتورها در پردازش داده‌های بسیار بزرگ مؤثرتر هستند.



۳. استفاده از شرط در List Comprehension

توضیح:
شما می‌توانید به‌راحتی شرایط را داخل یک List Comprehension قرار دهید تا تنها مقادیر مورد نظر به لیست اضافه شوند.

مثال: فیلتر کردن اعداد فرد
روش سنتی:
numbers = [1, 2, 3, 4, 5, 6]
odd_numbers = []
for num in numbers:
if num % 2 != 0:
odd_numbers.append(num)
print(odd_numbers)

با استفاده از شرط داخل List Comprehension:
numbers = [1, 2, 3, 4, 5, 6]
odd_numbers = [num for num in numbers if num % 2 != 0]
print(odd_numbers)

مزایا:
- کد کوتاه‌تر و خواناتر می‌شود.
- پردازش داده‌ها بهینه‌تر می‌شود.

تمرین: لیستی از اعداد بین ۱ تا ۲۰ تولید کنید که مضرب ۳ هستند.



۴. استفاده از توابع آماده مثل sum() و max()

توضیح:
در بسیاری از موارد، به‌جای نوشتن حلقه‌های دستی برای جمع‌زدن یا یافتن بیشترین مقدار، بهتر است از توابع آماده استفاده کنید.


روش دستی:
numbers = [1, 2, 3, 4, 5]
total = 0
for num in numbers:
total += num
print(total)

استفاده از تابع آماده:
numbers = [1, 2, 3, 4, 5]
total = sum(numbers)
print(total)

مزایا:
- سرعت بیشتر (این توابع در سطح پایین پایتون بهینه شده‌اند).
- کد خواناتر.



۵. تمرین:
یک جنراتور بنویسید که مقادیر بین ۱ تا ۱۰۰ را تولید کند که هم زوج باشند و هم مضرب ۵. سپس این مقادیر را در کنسول چاپ کنید.



در قسمت دوم این پارت، به بررسی ابزارها و تکنیک‌های پیشرفته‌تر، از جمله پردازش موازی و بهینه‌سازی حافظه می‌پردازیم.

https://t.iss.one/hamidpython123
👍1
پارت ۳: بهینه‌سازی حلقه‌های for در پایتون (قسمت ۲/۴)



مقدمه
در این قسمت، به ابزارها و تکنیک‌های پیشرفته‌تر برای بهینه‌سازی حلقه‌های for می‌پردازیم. این روش‌ها به شما کمک می‌کنند تا کدهای سریع‌تر و کارآمدتری بنویسید، مخصوصاً زمانی که با داده‌های بزرگ کار می‌کنید.



۱. استفاده از تابع map() برای تبدیل داده‌ها

توضیح:
تابع map() برای اعمال یک تابع روی تمام عناصر یک مجموعه استفاده می‌شود. این روش سریع‌تر و ساده‌تر از استفاده از یک حلقه معمولی است.

مثال: تبدیل لیستی از اعداد به مربع‌هایشان
روش سنتی:
numbers = [1, 2, 3, 4]
squared_numbers = []
for num in numbers:
squared_numbers.append(num ** 2)
print(squared_numbers)

با استفاده از map():
numbers = [1, 2, 3, 4]
squared_numbers = list(map(lambda x: x ** 2, numbers))
print(squared_numbers)

مزایا:
- کد کوتاه‌تر.
- عملکرد بهینه‌تر در برخی موارد.



۲. استفاده از پردازش هم‌زمان با ThreadPoolExecutor

توضیح:
در مواردی که نیاز به انجام محاسبات سنگین دارید، می‌توانید از پردازش موازی برای افزایش سرعت استفاده کنید.

مثال: محاسبه توان‌های بزرگ با ThreadPoolExecutor
from concurrent.futures import ThreadPoolExecutor

def calculate_power(num):
return num ** 2

numbers = [1, 2, 3, 4, 5]
with ThreadPoolExecutor() as executor:
results = list(executor.map(calculate_power, numbers))
print(results)

مزایا:
- افزایش سرعت در پردازش داده‌های بزرگ.
- استفاده هم‌زمان از چندین هسته CPU.



۳. استفاده از itertools برای حلقه‌های پیچیده

توضیح:
ماژول itertools مجموعه‌ای از توابع کمکی است که به شما اجازه می‌دهد حلقه‌های پیشرفته‌تری ایجاد کنید.

مثال: ایجاد ترکیب‌های ممکن از دو لیست
from itertools import product

list1 = [1, 2]
list2 = ['A', 'B']
for combination in product(list1, list2):
print(combination)

خروجی:
(1, 'A')  
(1, 'B')
(2, 'A')
(2, 'B')

کاربردها:
- ایجاد ترکیب‌ها و جایگشت‌ها.
- پردازش داده‌های چندبعدی.



۴. استفاده از collections.Counter برای شمارش مقادیر

توضیح:
اگر نیاز به شمارش تعداد تکرار عناصر یک مجموعه دارید، استفاده از حلقه معمولی ممکن است زمان‌بر باشد. به‌جای آن، می‌توانید از collections.Counter استفاده کنید.

مثال: شمارش تکرار اعداد
from collections import Counter

numbers = [1, 2, 2, 3, 3, 3, 4]
count = Counter(numbers)
print(count)

خروجی:
Counter({3: 3, 2: 2, 1: 1, 4: 1})



۵. استفاده از timeit برای اندازه‌گیری زمان اجرای حلقه‌ها

توضیح:
گاهی اوقات، نیاز دارید بدانید کدام روش سریع‌تر است. ماژول timeit می‌تواند زمان اجرای کد شما را اندازه‌گیری کند.

مثال: مقایسه سرعت حلقه for و map()
import timeit

numbers = list(range(1, 1000))
print("Using for loop:", timeit.timeit('''
squared_numbers = []
for num in numbers:
squared_numbers.append(num ** 2)
''', globals=globals(), number=100))

print("Using map():", timeit.timeit('''
squared_numbers = list(map(lambda x: x ** 2, numbers))
''', globals=globals(), number=100))



در قسمت سوم این پارت، به تکنیک‌های پیشرفته‌تر مثل استفاده از NumPy برای بهینه‌سازی حلقه‌ها و پردازش داده‌ها خواهیم پرداخت. منتظر باشید!

https://t.iss.one/hamidpython123
پارت ۳: بهینه‌سازی حلقه‌های for در پایتون (قسمت ۳/۴)



مقدمه
در این قسمت، با تکنیک‌های حرفه‌ای‌تر آشنا خواهید شد که به شما کمک می‌کنند حلقه‌های خود را در پروژه‌های پیچیده و داده‌محور بهینه‌سازی کنید.



۱. جایگزینی حلقه‌های for با NumPy

توضیح:
در مواردی که با داده‌های عددی بزرگ کار می‌کنید، استفاده از کتابخانه NumPy به‌جای حلقه‌های for می‌تواند عملکرد را به شدت بهبود بخشد.

مثال: محاسبه مربع اعداد
روش سنتی:
numbers = list(range(1, 10001))
squared_numbers = [num ** 2 for num in numbers]

با NumPy:
import numpy as np

numbers = np.arange(1, 10001)
squared_numbers = numbers ** 2

مزایا:
- سرعت بیشتر.
- استفاده بهینه از حافظه.



۲. فیلتر کردن داده‌ها با List Comprehension

توضیح:
List Comprehension می‌تواند جایگزینی سریع و مختصر برای فیلتر کردن داده‌ها در حلقه‌های for باشد.

مثال: استخراج اعداد زوج
روش سنتی:
numbers = range(1, 11)
even_numbers = []
for num in numbers:
if num % 2 == 0:
even_numbers.append(num)

با List Comprehension:
numbers = range(1, 11)
even_numbers = [num for num in numbers if num % 2 == 0]

مزایا:
- کد کوتاه‌تر و خواناتر.
- عملکرد بهینه‌تر.



۳. ترکیب شرط‌ها با حلقه for

توضیح:
می‌توانید از چندین شرط در یک حلقه for استفاده کنید تا داده‌ها را فیلتر کنید یا تغییر دهید.

مثال: فیلتر اعداد بین ۱۰ تا ۵۰ و محاسبه مربع آن‌ها
numbers = range(1, 101)
filtered_squares = [num ** 2 for num in numbers if 10 <= num <= 50]
print(filtered_squares)

کاربرد:
- پردازش داده‌های پیچیده در یک خط کد.



۴. پردازش همزمان با multiprocessing

توضیح:
برای پردازش موازی داده‌ها، کتابخانه multiprocessing می‌تواند سرعت پردازش را افزایش دهد.

مثال: محاسبه توان‌های بزرگ
from multiprocessing import Pool

def calculate_power(num):
return num ** 2

numbers = range(1, 10001)
with Pool() as pool:
results = pool.map(calculate_power, numbers)

مزایا:
- افزایش سرعت برای داده‌های بزرگ.
- توزیع کار بین چندین پردازنده.



۵. ذخیره داده‌ها با Generator ها

توضیح:
Generator ها حافظه کمتری مصرف می‌کنند و برای پردازش داده‌های بزرگ مناسب‌اند.

مثال: ایجاد توالی اعداد بدون ذخیره تمام مقادیر
def generate_numbers(limit):
for i in range(limit):
yield i ** 2

for num in generate_numbers(10):
print(num)

مزایا:
- مدیریت بهینه حافظه.
- مناسب برای داده‌های جریانی.



۶. بررسی کد با ابزار cProfile

توضیح:
برای بهینه‌سازی حلقه‌های for، ابتدا باید بخش‌های کند کد را شناسایی کنید. ماژول cProfile می‌تواند در این کار کمک کند.

مثال: پروفایل‌کردن یک حلقه
import cProfile

def process_numbers():
numbers = range(1, 10000)
squares = [num ** 2 for num in numbers]

cProfile.run('process_numbers()')

کاربرد:
- شناسایی گلوگاه‌های عملکردی.
- بهبود عملکرد بخش‌های کند.



در قسمت چهارم، به تکنیک‌های نهایی و ترکیب روش‌ها برای بهینه‌سازی حداکثری حلقه‌های for خواهیم پرداخت. منتظر بمانید!

https://t.iss.one/hamidpython123
👍1
پارت ۳: بهینه‌سازی حلقه‌های for در پایتون (قسمت ۴/۴)



مقدمه
در این قسمت پایانی، به‌صورت تئوری و عملی روی تکنیک‌های نهایی تمرکز خواهیم کرد. این تکنیک‌ها شامل بهینه‌سازی حافظه، بازنویسی حلقه‌ها، و اصولی است که نه‌تنها عملکرد حلقه‌ها را بهبود می‌دهد، بلکه کدی تمیزتر و قابل‌نگهداری‌تر تولید می‌کند.



۱. اجتناب از تکرار بیهوده عملیات در حلقه

توضیح:
یکی از رایج‌ترین اشتباهات در حلقه‌ها، اجرای مجدد عملیاتی است که نیازی به محاسبه مکرر ندارند. با استخراج عملیات ثابت از حلقه، می‌توانید عملکرد را بهبود دهید.

مثال: جمع اعداد چندین بار در حلقه
روش غیربهینه:
numbers = [1, 2, 3, 4, 5]
for num in numbers:
result = sum(numbers) + num
print(result)

روش بهینه:
numbers = [1, 2, 3, 4, 5]
total = sum(numbers) # محاسبه فقط یک بار انجام می‌شود
for num in numbers:
result = total + num
print(result)

توضیح:
در روش دوم، تابع sum() تنها یک بار اجرا می‌شود و حلقه سریع‌تر اجرا می‌شود.



۲. استفاده از Generator ها برای پردازش داده‌های بزرگ

توضیح:
Generator ها به‌جای ذخیره کل مجموعه داده‌ها در حافظه، مقادیر را به‌صورت بازگشتی تولید می‌کنند. این امر مخصوصاً برای داده‌های حجیم مفید است.

مثال: پردازش فایل‌های بزرگ
روش معمول:
lines = open('large_file.txt').readlines()
for line in lines:
print(line)

روش بهینه با Generator:
with open('large_file.txt') as file:
for line in file:
print(line)

توضیح:
در روش دوم، فایل خط‌به‌خط پردازش می‌شود و حافظه کمتری مصرف می‌شود.



۳. تغییر ساختار حلقه با توابع داخلی

توضیح:
پایتون توابع داخلی مانند map(), filter(), و reduce() را فراهم می‌کند که می‌توانند حلقه‌های for را ساده‌تر و سریع‌تر کنند.

مثال: اعمال یک تابع روی لیست
با حلقه for:
numbers = [1, 2, 3, 4, 5]
squared = []
for num in numbers:
squared.append(num ** 2)

با `map():
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))

توضیح:
تابع map() به‌طور داخلی بهینه است و عملکرد حلقه را سریع‌تر می‌کند.



‌۴. استفاده از ابزار itertools برای بهینه‌سازی پیشرفته

توضیح:
کتابخانه itertools مجموعه‌ای از ابزارهای قدرتمند برای کار با حلقه‌ها ارائه می‌دهد.

مثال: ایجاد یک ترکیب‌سازی از دو لیست
روش معمول:

list1 = [1, 2, 3]
list2 = ['a', 'b', 'c']
combinations = []
for i in list1:
for j in list2:
combinations.append((i, j))
print(combinations)

با `itertools.product:

from itertools import product

list1 = [1, 2, 3]
list2 = ['a', 'b', 'c']
combinations = list(product(list1, list2))
print(combinations)

توضیح:
تابع product به‌طور داخلی بهینه است و کد را مختصرتر و سریع‌تر می‌کند.



۵. بررسی زمانی اجرای حلقه‌ها

توضیح:
برای مقایسه عملکرد حلقه‌ها یا تکنیک‌های مختلف، می‌توانید از ماژول time یا timeit استفاده کنید.

مثال: مقایسه دو روش جمع اعداد


import time

# روش اول
start = time.time()
numbers = range(1, 1000000)
total = sum(numbers)
end = time.time()
print(f"Method 1 took: {end - start} seconds")

# روش دوم
start = time.time()
total = 0
for num in range(1, 1000000):
total += num
end = time.time()
print(f"Method 2 took: {end - start} seconds")

توضیح:
با استفاده از این تکنیک، می‌توانید زمان اجرای هر روش را اندازه‌گیری کرده و بهترین گزینه را انتخاب کنید.



۶. ترکیب ابزارها برای بهینه‌سازی نهایی

توضیح:
در مسائل پیچیده، ترکیب ابزارهای مختلف مانند Generator ها، itertools، و توابع داخلی می‌تواند هم کد را بهینه کند و هم خوانایی آن را افزایش دهد.

مثال: فیلتر و پردازش یک لیست بزرگ


from itertools import islice

numbers = (x for x in range(1, 1000000) if x % 2 == 0)
result = islice(numbers, 10) # فقط ۱۰ مقدار اول را انتخاب می‌کند
for num in result:
print(num)

توضیح:
در این روش:
- از Generator برای مدیریت حافظه استفاده شده است.
- از islice برای محدودکردن خروجی بهره گرفته شده است.
👍2
جمع‌بندی
در این پارت، یاد گرفتید که چگونه:
- عملیات ثابت را از حلقه‌ها استخراج کنید.
- با Generator ها و ابزارهای داخلی، حافظه را بهینه کنید.
- با ابزارهای پیشرفته‌ای مثل itertools، حلقه‌های خود را ساده و قدرتمند کنید.

در پروژه‌های واقعی، این تکنیک‌ها می‌توانند به شما کمک کنند تا کدهایی سریع‌تر، تمیزتر و حرفه‌ای‌تر بنویسید.

https://t.iss.one/hamidpython123
👍2
جنریتور ها در پایتون

جنریتور‌ها در پایتون ابزارهای قدرتمندی هستند که به شما امکان می‌دهند مقادیر را به صورت تدریجی تولید کنید. این ویژگی برای مدیریت حافظه و پردازش داده‌های بزرگ بسیار مفید است.

۱. ساخت جنریتور با کلمه کلیدی yield:
با استفاده از yield می‌توانید مقادیر را یکی‌یکی بازگردانید.

def simple_generator():
yield 1
yield 2
yield 3

gen = simple_generator()
print(next(gen)) # خروجی: 1
print(next(gen)) # خروجی: 2
print(next(gen)) # خروجی: 3

۲. استفاده از حلقه‌ها در جنریتور:
حلقه‌ها به شما این امکان را می‌دهند که تعداد زیادی مقدار تولید کنید.

def range_generator(n):
for i in range(n):
yield i

gen = range_generator(5)
for value in gen:
print(value)

۳. جنریتور‌های بی‌نهایت:
می‌توانید جنریتور‌هایی ایجاد کنید که تا بی‌نهایت مقادیر تولید کنند.

def infinite_counter():
num = 0
while True:
yield num
num += 1

counter = infinite_counter()
print(next(counter)) # خروجی: 0
print(next(counter)) # خروجی: 1
print(next(counter)) # خروجی: 2

۴. جنریتور‌های فشرده (Generator Expressions):
با سینتکس کوتاه می‌توانید جنریتور‌ها را سریعاً تعریف کنید.

gen = (x * x for x in range(5))
print(next(gen)) # خروجی: 0
print(next(gen)) # خروجی: 1
print(next(gen)) # خروجی: 4

۵. ارسال داده به جنریتور با send():
جنریتور‌ها نه تنها می‌توانند مقادیر تولید کنند، بلکه می‌توانند داده از بیرون دریافت کنند.

def multiplier():
factor = 1
while True:
number = yield
print(number * factor)

gen = multiplier()
next(gen) # آماده‌سازی جنریتور
gen.send(10) # خروجی: 10
gen.send(20) # خروجی: 20

۶. مدیریت پایان جنریتور:
هنگامی که جنریتور به انتها می‌رسد، خطای StopIteration ایجاد می‌شود.

def controlled_generator():
for i in range(5):
yield i
return "Done"

gen = controlled_generator()
try:
while True:
print(next(gen))
except StopIteration as e:
print(e)

۷. استفاده از جنریتور برای پردازش داده‌های بزرگ:
مثالی از خواندن فایل‌های بزرگ به صورت خط به خط:

def read_large_file(file_path):
with open(file_path, 'r') as file:
for line in file:
yield line.strip()

for line in read_large_file('large_file.txt'):
print(line)



جنریتور‌ها ابزاری قدرتمند برای مدیریت کارآمد داده‌ها هستند و در بسیاری از برنامه‌های پایتون کاربرد دارند. با تسلط بر این ابزار می‌توانید کدهایی بهینه‌تر و حرفه‌ای‌تر بنویسید.

برای دیدن آموزش های مخطلف پایتون اینجا کلیک کن
👍2
💡 TPU چیست و چرا مهم است؟

TPU یا Tensor Processing Unit یک پردازنده خاص است که توسط گوگل ساخته شده تا عملیات یادگیری ماشین، به‌ویژه مدل‌های شبکه عصبی و یادگیری عمیق، سریع‌تر و کارآمدتر انجام شود. این پردازنده به طور ویژه برای این نوع محاسبات طراحی شده و عملکرد آن بسیار بهینه‌تر از CPU و GPU است.

🔍 چرا TPU طراحی شد؟
در گذشته برای اجرای مدل‌های یادگیری ماشین از CPU و GPU استفاده می‌شد. اما این پردازنده‌ها عمومی بودند و برای محاسبات پیچیده یادگیری عمیق بهینه نبودند. گوگل TPU را ساخت تا این محدودیت‌ها را رفع کند و بتواند مدل‌های یادگیری عمیق را سریع‌تر و با مصرف انرژی کمتر اجرا کند.

⚙️ TPU چه کار می‌کند؟
1️⃣ عملیات‌های پیچیده ریاضی مانند ضرب ماتریس‌ها را با سرعت بالا انجام می‌دهد.
2️⃣ برای اجرای مدل‌های یادگیری عمیق بزرگ مانند GPT طراحی شده است.
3️⃣ در مقایسه با GPU انرژی کمتری مصرف می‌کند و برای مراکز داده بزرگ ایده‌آل است.

🤔 تفاوت TPU با CPU و GPU چیست؟
🔹 CPU: برای وظایف عمومی طراحی شده، سرعت پایین‌تری دارد و انرژی زیادی مصرف می‌کند.
🔹 GPU: در پردازش موازی و گرافیکی خوب است اما مصرف انرژی آن بالاست.
🔹 TPU: فقط برای یادگیری عمیق ساخته شده، سرعت فوق‌العاده‌ای دارد و بسیار کم‌مصرف است.

🚀 چرا TPU برای یادگیری عمیق مناسب است؟
طراحی ویژه برای عملیات ماتریسی.
سرعت بسیار بالا در محاسبات شبکه عصبی.
مصرف انرژی بسیار کمتر نسبت به GPU.

📌 نتیجه‌گیری:
TPU یک ابزار پیشرفته و بهینه برای یادگیری عمیق است. این فناوری نه‌تنها سرعت اجرای مدل‌ها را افزایش می‌دهد بلکه با کاهش مصرف انرژی، کمک بزرگی به پردازش در مقیاس‌های بزرگ می‌کند. در بخش‌های بعدی، جزئیات بیشتری درباره عملکرد و کاربردهای TPU بررسی خواهیم کرد.
💡 TPU چگونه کار می‌کند؟

برای درک عملکرد TPU باید بدانیم که این پردازنده دقیقاً چه چیزی را متفاوت انجام می‌دهد و چگونه برای یادگیری عمیق بهینه شده است.

⚙️ طراحی ویژه TPU
TPU برخلاف CPU و GPU که برای کارهای عمومی ساخته شده‌اند، به طور خاص برای محاسبات ماتریسی و برداری که در مدل‌های یادگیری عمیق بسیار رایج هستند، طراحی شده است. این طراحی باعث می‌شود که عملیات‌هایی مانند ضرب ماتریس‌ها و محاسبات گرادیان با سرعت بسیار بالا انجام شود.

🔗 بخش‌های اصلی TPU:
1️⃣ Matrix Multiply Unit (MXU):
این واحد مسئول اجرای عملیات ماتریسی است که در شبکه‌های عصبی به‌وفور استفاده می‌شود. MXU می‌تواند صدها محاسبه را به‌صورت موازی انجام دهد.

2️⃣ حافظه پرسرعت (High Bandwidth Memory):
TPU از حافظه سریع برای ذخیره و بازیابی وزن‌ها و داده‌های مدل استفاده می‌کند. این حافظه با پهنای باند بالا به کاهش تأخیر در پردازش کمک می‌کند.

3️⃣ Pipeline Processing:
داده‌ها به‌صورت خطی و مرحله‌به‌مرحله پردازش می‌شوند. این روش بهینه، استفاده حداکثری از منابع TPU را تضمین می‌کند.

🔍 چرا TPU سریع‌تر است؟
پردازش عملیات ماتریسی با سخت‌افزار اختصاصی (MXU).
کاهش زمان انتظار برای بارگذاری داده‌ها از طریق حافظه سریع.
پردازش موازی تعداد زیادی از داده‌ها در یک زمان.

🌟 کاربردهای TPU
TPU در موارد زیر استفاده می‌شود:
🔹 آموزش مدل‌های پیچیده یادگیری عمیق.
🔹 استنتاج (Inference) در زمان اجرا برای اپلیکیشن‌هایی مانند ترجمه زبان، تشخیص تصویر و تحلیل صدا.
🔹 اجرای مدل‌های مقیاس‌پذیر در پلتفرم‌هایی مانند Google Cloud.

📌 نتیجه‌گیری:
TPU با طراحی ویژه و واحدهای سخت‌افزاری پیشرفته، عملیات‌های پیچیده ریاضی را بسیار سریع و کارآمد انجام می‌دهد. این قابلیت‌ها باعث شده که TPU ابزاری ایده‌آل برای یادگیری عمیق باشد. در بخش بعدی به تفاوت‌های نسل‌های مختلف TPU و پیشرفت‌های آن خواهیم پرداخت.
💡 نسل‌های مختلف TPU و پیشرفت‌های آن

TPU‌ها در طول زمان پیشرفت‌های چشمگیری داشته‌اند و هر نسل جدید قابلیت‌های بیشتری برای بهینه‌سازی پردازش مدل‌های یادگیری عمیق ارائه داده است.

⚙️ نسل‌های مختلف TPU:
1️⃣ TPU v1 (2015):
🔹 اولین نسل TPU که برای استنتاج (Inference) مدل‌های یادگیری عمیق طراحی شد.
🔹 استفاده اختصاصی برای پردازش وظایف گوگل مانند ترجمه ماشینی، جستجو و تشخیص تصویر.
🔹 توانایی پردازش 92 ترافلاپ (TFLOPS).

2️⃣ TPU v2 (2017):
🔹 اضافه شدن قابلیت آموزش (Training) مدل‌ها.
🔹 مجهز به حافظه پرسرعت HBM (High Bandwidth Memory) با ظرفیت 8 گیگابایت.
🔹 پشتیبانی از عملیات محاسباتی با دقت‌های متنوع، مانند float16.
🔹 توانایی پردازش 180 ترافلاپ.

3️⃣ TPU v3 (2018):
🔹 افزایش ظرفیت حافظه HBM به 16 گیگابایت.
🔹 خنک‌کننده مایع برای جلوگیری از داغی بیش از حد در بارهای کاری سنگین.
🔹 توانایی پردازش 420 ترافلاپ که باعث می‌شود آموزش مدل‌های بسیار بزرگ‌تر سریع‌تر انجام شود.

4️⃣ TPU v4 (2021):
🔹 تمرکز بر افزایش سرعت و کارایی برای مدل‌های بزرگ مانند GPT و BERT.
🔹 بهبود معماری حافظه برای انتقال سریع‌تر داده‌ها.
🔹 توانایی پردازش 1000 ترافلاپ در هر TPU Pod.

🔗 پیشرفت‌های کلیدی در هر نسل:
افزایش قدرت پردازش برای مدیریت مدل‌های پیچیده‌تر.
بهبود حافظه برای کاهش تأخیر در بارگذاری داده‌ها.
خنک‌کننده‌های پیشرفته برای پایداری عملکرد در شرایط سنگین.

🌟 نسل‌های جدید چه قابلیت‌هایی دارند؟
🔹 پشتیبانی از مدل‌های بزرگ زبانی و گرافیکی.
🔹 کاهش مصرف انرژی با حفظ سرعت و عملکرد بالا.
🔹 طراحی بهینه‌تر برای استفاده در سیستم‌های مقیاس‌پذیر مانند Google Cloud.

📌 نتیجه‌گیری:
هر نسل از TPU نه‌تنها قدرت پردازش بالاتری ارائه می‌دهد، بلکه قابلیت‌های بیشتری برای آموزش و استنتاج مدل‌های یادگیری عمیق فراهم می‌کند. این پیشرفت‌ها TPU را به یک انتخاب ایده‌آل برای پروژه‌های پیشرفته در حوزه هوش مصنوعی تبدیل کرده است. در بخش بعدی به مقایسه TPU با سایر پردازنده‌ها مانند GPU و CPU خواهیم پرداخت.