چطور میتونیم کدهای Pandas رو سریعتر و بهینهتر بنویسیم؟
یکی از نکات خیلی مهم موقع کار با کتابخونهی pandas اینه که بدونیم چطوری از عملیاتهای برداری (vectorized operations) استفاده کنیم تا هم کدهامون سریعتر اجرا بشن، هم خواناتر و بهینهتر باشن. خیلی وقتا پیش میاد که ناخواسته از روشهایی استفاده میکنیم که کندتر هستن، در حالی که pandas ابزارهای خیلی قویای برای سریعتر انجام دادن محاسبات در اختیارمون گذاشته.
برای اینکه بهتر متوجه بشیم، بیاین با یه مثال ساده شروع کنیم. فرض کنیم یه DataFrame داریم با ستونی به اسم "India" و میخوایم مقادیر این ستون رو تقسیم بر ۱۰۰ کنیم و نتیجه رو تو یه ستون جدید ذخیره کنیم.
اول از همه، از روش برداری مستقیم استفاده میکنیم:
خروجی:
همونطور که میبینید، این روش خیلی سریع و بهینهست؛ بهطور میانگین فقط حدود ۶۵ میکروثانیه زمان نیاز داره.
تو مرحله بعد، همین عملیات رو با استفاده از تابع
خروجی:
اینجا باید به یه نکته مهم توجه کنیم:
📌 زمانی که عملیاتی که میخوایم انجام بدیم به صورت آماده (built-in) تو pandas یا NumPy وجود نداره، استفاده از
ولی باید بدونیم که
در نهایت، بیاین نگاهی بندازیم به حالتی که همین کار رو با پیمایش ردیف به ردیف (با استفاده از
خروجی:
میبینید که این روش حدود ۵ برابر کندتر از روش برداریه. دلیلش هم اینه که تو این روش، pandas نمیتونه از بهینهسازیهای داخلی خودش استفاده کنه و مجبور میشه هر ردیف رو جداگونه پردازش کنه.
جمعبندی:
🔹 اگه قراره یه عملیات روی کل یه ستون انجام بشه، استفاده از عملیات برداری سریعترین و بهینهترین روشه.
🔹 اگه عملیات پیچیدهتره و توابع آماده براش وجود نداره،
🔹 استفاده از روشهایی مثل
💞
یکی از نکات خیلی مهم موقع کار با کتابخونهی pandas اینه که بدونیم چطوری از عملیاتهای برداری (vectorized operations) استفاده کنیم تا هم کدهامون سریعتر اجرا بشن، هم خواناتر و بهینهتر باشن. خیلی وقتا پیش میاد که ناخواسته از روشهایی استفاده میکنیم که کندتر هستن، در حالی که pandas ابزارهای خیلی قویای برای سریعتر انجام دادن محاسبات در اختیارمون گذاشته.
برای اینکه بهتر متوجه بشیم، بیاین با یه مثال ساده شروع کنیم. فرض کنیم یه DataFrame داریم با ستونی به اسم "India" و میخوایم مقادیر این ستون رو تقسیم بر ۱۰۰ کنیم و نتیجه رو تو یه ستون جدید ذخیره کنیم.
اول از همه، از روش برداری مستقیم استفاده میکنیم:
import pandas as pd
df = pd.DataFrame({
"India": [100, 200, 300, 400, 500]
})
# vectorized operation
%timeit df["India_fraction"] = df["India"] / 100
خروجی:
65.7 µs ± 1.01 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)همونطور که میبینید، این روش خیلی سریع و بهینهست؛ بهطور میانگین فقط حدود ۶۵ میکروثانیه زمان نیاز داره.
تو مرحله بعد، همین عملیات رو با استفاده از تابع
apply و یه تابع lambda انجام میدیم:# apply
%timeit df["India_fraction"] = df["India"].apply(lambda x: x / 100)
خروجی:
87.7 µs ± 302 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)اینجا باید به یه نکته مهم توجه کنیم:
📌 زمانی که عملیاتی که میخوایم انجام بدیم به صورت آماده (built-in) تو pandas یا NumPy وجود نداره، استفاده از
apply میتونه گزینهی خوبی باشه. باهاش میشه هر تابع دلخواهی رو روی یه ستون اجرا کرد.ولی باید بدونیم که
apply نسبت به روش برداری مستقیم یه مقدار سربار (overhead) داره و طبیعتاً یهکم کندتره.در نهایت، بیاین نگاهی بندازیم به حالتی که همین کار رو با پیمایش ردیف به ردیف (با استفاده از
iterrows) انجام میدیم:# iterrows
%timeit df["India_fraction"] = [row["India"] / 100 for index, row in df.iterrows()]
خروجی:
348 µs ± 4.14 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)میبینید که این روش حدود ۵ برابر کندتر از روش برداریه. دلیلش هم اینه که تو این روش، pandas نمیتونه از بهینهسازیهای داخلی خودش استفاده کنه و مجبور میشه هر ردیف رو جداگونه پردازش کنه.
جمعبندی:
🔹 اگه قراره یه عملیات روی کل یه ستون انجام بشه، استفاده از عملیات برداری سریعترین و بهینهترین روشه.
🔹 اگه عملیات پیچیدهتره و توابع آماده براش وجود نداره،
apply انتخاب خوبیه؛ ولی باید بدونیم یهکم زمان بیشتری میبره.🔹 استفاده از روشهایی مثل
iterrows فقط تو شرایط خاص پیشنهاد میشه، چون هم زمانبرن و هم منابع بیشتری مصرف میکنن.💞
⭕ تفاوت باگ Bug و دیباگ Debug در چیست؟!
▪️باگ Bug :
باگ یا خطا (Bug) به هر نوع ایراد یا خطای پیشآمده در برنامههای کامپیوتری گفته میشود. این خطاها میتوانند از اشتباهات کد نوشتهشده تا مشکلات در محیط اجرایی نرمافزار ناشی شوند. باگها ممکن است منجر به عملکرد نادرست یا غیرمنتظره برنامه شوند و معمولا نیاز به دیباگ دارند.
▪️دیباگ Debug :
دیباگ (Debug) فرآیند شناسایی و رفع باگها یا خطاهای موجود در یک نرمافزار است. این فرآیند شامل استفاده از ابزارها و تکنیکهای مختلف برای پیدا کردن و برطرف کردن باگها میشود. دیباگ معمولا توسط برنامهنویس یا تیمهای توسعه انجام میشود تا اطمینان حاصل شود که نرمافزار به صورت صحیح کار میکند.
🔹تفاوت اصلی بین باگ و دیباگ :
تفاوت اصلی بین این دو مفهوم در این است که "باگ" یک مشکل یا خطای امکانپذیر در نرمافزار است که نیاز به تصحیح دارد، در حالی که "دیباگ" فرآیند شناسایی و رفع این مشکلات است.
🐞
▪️باگ Bug :
باگ یا خطا (Bug) به هر نوع ایراد یا خطای پیشآمده در برنامههای کامپیوتری گفته میشود. این خطاها میتوانند از اشتباهات کد نوشتهشده تا مشکلات در محیط اجرایی نرمافزار ناشی شوند. باگها ممکن است منجر به عملکرد نادرست یا غیرمنتظره برنامه شوند و معمولا نیاز به دیباگ دارند.
▪️دیباگ Debug :
دیباگ (Debug) فرآیند شناسایی و رفع باگها یا خطاهای موجود در یک نرمافزار است. این فرآیند شامل استفاده از ابزارها و تکنیکهای مختلف برای پیدا کردن و برطرف کردن باگها میشود. دیباگ معمولا توسط برنامهنویس یا تیمهای توسعه انجام میشود تا اطمینان حاصل شود که نرمافزار به صورت صحیح کار میکند.
🔹تفاوت اصلی بین باگ و دیباگ :
تفاوت اصلی بین این دو مفهوم در این است که "باگ" یک مشکل یا خطای امکانپذیر در نرمافزار است که نیاز به تصحیح دارد، در حالی که "دیباگ" فرآیند شناسایی و رفع این مشکلات است.
🐞
Code Like a Pro in Rust - DevTwitter.pdf
10.7 MB
#Rust
Code Like a Pro in Rust
Explore the latest features of Rust 2018 for building fast and
secure apps
- By Brenden Matthews
- 265 Pages
@DevTwitter
Code Like a Pro in Rust
Explore the latest features of Rust 2018 for building fast and
secure apps
- By Brenden Matthews
- 265 Pages
@DevTwitter
به اون کاری که امروز کردی نگو "ریفکتور" (Refactor). اگه تست نداره، اون فقط یه "گندکاریِ تمیزه".
این فقط یه جملهی قشنگ نیست؛ این یه زخمه که من هنوز یادمه.
اوایل کارم، میخواستم قهرمان باشم. ️ تو یه پروژهی لگسی، یه "God Function" هزار خطی پیدا کردم و گفتم: "من اینو تمیز میکنم!"
نشستم و تیکهتیکهاش کردم. ۵۰ تا تابع کوچولوی تر و تمیز. اصل DRY رو پیاده کردم. ظاهر کد عالی شد. "تمیز" و "حرفهای". احساس غرور میکردم.
مشکل چی بود؟ اون کد اصلی لعنتی، یه دونه هم تست خودکار نداشت.
اونجا بود که فاجعه اتفاق افتاد. کاری که من انجام دادم، "ریفکتور" نبود؛ "تغییر دادنِ کورکورانه" بود.
اون کد "تمیز" من، چند تا باگ جدید و پنهان داشت. چرا؟ چون اون "کد اسپاگتی" زشت، پر از منطقهای تجاری پنهان و وابستگیهای زمانی بود که فقط تو همون حالت کار میکرد.
من "بدهی فنی" رو پرداخت نکردم؛ من یه بدهی کمبهره (مثل تکرار کد که فهمیدنش ساده بود) رو برداشتم و با یه بدهی پربهره (مثل یه "انتزاع اشتباه" که حالا دیباگ کردنش غیرممکنه) عوض کردم.
این "تلهی کد تمیز"ئه. مهمترین تعریفی که تو این صنعت باید بلد باشیم مال مایکل فدرز (Michael Feathers) ئه: "کد لگسی، کدیه که تست نداره." همین.
تو یه سیستم لگسی، قانون اول "تمیز کن" نیست. قانون اول اینه: "اول امنش کن." برو "تستهای مشخصهیابی" (Characterization Tests) بنویس تا رفتار فعلیِ سیستم (با همهی باگهاش) رو قفل کنی. وقتی اون تور ایمنی رو ساختی، اونوقت حق داری که شروع به تمیزکاری کنی.
🦓
این فقط یه جملهی قشنگ نیست؛ این یه زخمه که من هنوز یادمه.
اوایل کارم، میخواستم قهرمان باشم. ️ تو یه پروژهی لگسی، یه "God Function" هزار خطی پیدا کردم و گفتم: "من اینو تمیز میکنم!"
نشستم و تیکهتیکهاش کردم. ۵۰ تا تابع کوچولوی تر و تمیز. اصل DRY رو پیاده کردم. ظاهر کد عالی شد. "تمیز" و "حرفهای". احساس غرور میکردم.
مشکل چی بود؟ اون کد اصلی لعنتی، یه دونه هم تست خودکار نداشت.
اونجا بود که فاجعه اتفاق افتاد. کاری که من انجام دادم، "ریفکتور" نبود؛ "تغییر دادنِ کورکورانه" بود.
اون کد "تمیز" من، چند تا باگ جدید و پنهان داشت. چرا؟ چون اون "کد اسپاگتی" زشت، پر از منطقهای تجاری پنهان و وابستگیهای زمانی بود که فقط تو همون حالت کار میکرد.
من "بدهی فنی" رو پرداخت نکردم؛ من یه بدهی کمبهره (مثل تکرار کد که فهمیدنش ساده بود) رو برداشتم و با یه بدهی پربهره (مثل یه "انتزاع اشتباه" که حالا دیباگ کردنش غیرممکنه) عوض کردم.
این "تلهی کد تمیز"ئه. مهمترین تعریفی که تو این صنعت باید بلد باشیم مال مایکل فدرز (Michael Feathers) ئه: "کد لگسی، کدیه که تست نداره." همین.
تو یه سیستم لگسی، قانون اول "تمیز کن" نیست. قانون اول اینه: "اول امنش کن." برو "تستهای مشخصهیابی" (Characterization Tests) بنویس تا رفتار فعلیِ سیستم (با همهی باگهاش) رو قفل کنی. وقتی اون تور ایمنی رو ساختی، اونوقت حق داری که شروع به تمیزکاری کنی.
🦓