# کار با داده‌ها: آماده‌سازی داده‌ها |![طرح دستی توسط [(@sketchthedocs)](https://sketchthedocs.dev)](../../sketchnotes/08-DataPreparation.png)| |:---:| |آماده‌سازی داده‌ها - _طرح دستی توسط [@nitya](https://twitter.com/nitya)_ | ## [پیش‌آزمون](https://purple-hill-04aebfb03.1.azurestaticapps.net/quiz/14) بسته به منبع داده، داده‌های خام ممکن است شامل ناسازگاری‌هایی باشند که در تحلیل و مدل‌سازی چالش ایجاد می‌کنند. به عبارت دیگر، این داده‌ها می‌توانند به عنوان داده‌های "کثیف" دسته‌بندی شوند و نیاز به پاک‌سازی دارند. این درس بر روی تکنیک‌های پاک‌سازی و تبدیل داده‌ها برای مدیریت چالش‌های مربوط به داده‌های ناقص، نادرست یا ناکامل تمرکز دارد. موضوعات پوشش داده‌شده در این درس از پایتون و کتابخانه Pandas استفاده می‌کنند و در [دفترچه یادداشت](notebook.ipynb) موجود در این پوشه نمایش داده می‌شوند. ## اهمیت پاک‌سازی داده‌ها - **سهولت استفاده و استفاده مجدد**: وقتی داده‌ها به درستی سازماندهی و نرمال‌سازی شوند، جستجو، استفاده و به اشتراک‌گذاری آن‌ها با دیگران آسان‌تر می‌شود. - **سازگاری**: علم داده اغلب نیاز به کار با بیش از یک مجموعه داده دارد، جایی که مجموعه داده‌ها از منابع مختلف باید با هم ترکیب شوند. اطمینان از اینکه هر مجموعه داده به صورت جداگانه استانداردسازی شده است، تضمین می‌کند که داده‌ها هنگام ادغام در یک مجموعه داده همچنان مفید باقی می‌مانند. - **دقت مدل**: داده‌هایی که پاک‌سازی شده‌اند، دقت مدل‌هایی که به آن‌ها وابسته هستند را بهبود می‌بخشند. ## اهداف و استراتژی‌های رایج در پاک‌سازی - **کاوش در یک مجموعه داده**: کاوش داده‌ها، که در [درس بعدی](https://github.com/microsoft/Data-Science-For-Beginners/tree/main/4-Data-Science-Lifecycle/15-analyzing) پوشش داده می‌شود، می‌تواند به شما کمک کند داده‌هایی که نیاز به پاک‌سازی دارند را شناسایی کنید. مشاهده بصری مقادیر در یک مجموعه داده می‌تواند انتظاراتی از ظاهر بقیه داده‌ها ایجاد کند یا ایده‌ای از مشکلاتی که می‌توان حل کرد ارائه دهد. کاوش می‌تواند شامل پرس‌وجوهای ساده، مصورسازی‌ها و نمونه‌گیری باشد. - **فرمت‌بندی**: بسته به منبع، داده‌ها ممکن است ناسازگاری‌هایی در نحوه ارائه داشته باشند. این می‌تواند مشکلاتی در جستجو و نمایش مقادیر ایجاد کند، جایی که داده‌ها در مجموعه دیده می‌شوند اما به درستی در مصورسازی‌ها یا نتایج پرس‌وجو نمایش داده نمی‌شوند. مشکلات رایج فرمت‌بندی شامل حذف فاصله‌های اضافی، تاریخ‌ها و انواع داده‌ها است. حل مشکلات فرمت‌بندی معمولاً به عهده افرادی است که از داده‌ها استفاده می‌کنند. به عنوان مثال، استانداردهای نحوه نمایش تاریخ‌ها و اعداد ممکن است در کشورهای مختلف متفاوت باشد. - **تکرارها**: داده‌هایی که بیش از یک بار ظاهر می‌شوند می‌توانند نتایج نادرستی تولید کنند و معمولاً باید حذف شوند. این می‌تواند هنگام ترکیب دو یا چند مجموعه داده با هم رایج باشد. با این حال، مواردی وجود دارد که تکرار در مجموعه داده‌های ترکیبی شامل اطلاعات اضافی است که ممکن است نیاز به حفظ داشته باشد. - **داده‌های گمشده**: داده‌های گمشده می‌توانند باعث نادرستی و همچنین نتایج ضعیف یا متعصبانه شوند. گاهی اوقات این مشکلات می‌توانند با "بارگذاری مجدد" داده‌ها، پر کردن مقادیر گمشده با محاسبات و کدهایی مانند پایتون، یا به سادگی حذف مقدار و داده‌های مربوطه حل شوند. دلایل متعددی برای گم شدن داده‌ها وجود دارد و اقداماتی که برای حل این مقادیر گمشده انجام می‌شود می‌تواند به چگونگی و چرایی گم شدن آن‌ها بستگی داشته باشد. ## کاوش اطلاعات DataFrame > **هدف یادگیری:** تا پایان این بخش، باید بتوانید اطلاعات کلی درباره داده‌های ذخیره‌شده در DataFrameهای pandas پیدا کنید. وقتی داده‌های خود را در pandas بارگذاری می‌کنید، احتمالاً در یک DataFrame قرار می‌گیرند (برای مرور دقیق‌تر به [درس قبلی](https://github.com/microsoft/Data-Science-For-Beginners/tree/main/2-Working-With-Data/07-python#dataframe) مراجعه کنید). با این حال، اگر مجموعه داده شما در DataFrame شامل ۶۰,۰۰۰ سطر و ۴۰۰ ستون باشد، چگونه می‌توانید حتی شروع به درک آنچه با آن کار می‌کنید کنید؟ خوشبختانه، [pandas](https://pandas.pydata.org/) ابزارهای مناسبی برای مشاهده سریع اطلاعات کلی درباره یک DataFrame و همچنین چند سطر اول و آخر آن ارائه می‌دهد. برای کاوش این قابلیت‌ها، ما کتابخانه scikit-learn پایتون را وارد کرده و از یک مجموعه داده معروف استفاده خواهیم کرد: **مجموعه داده Iris**. ```python import pandas as pd from sklearn.datasets import load_iris iris = load_iris() iris_df = pd.DataFrame(data=iris['data'], columns=iris['feature_names']) ``` | |طول کاسبرگ (سانتی‌متر)|عرض کاسبرگ (سانتی‌متر)|طول گلبرگ (سانتی‌متر)|عرض گلبرگ (سانتی‌متر)| |----------------------------------------|-----------------------|-----------------------|-----------------------|-----------------------| |0 |5.1 |3.5 |1.4 |0.2 | |1 |4.9 |3.0 |1.4 |0.2 | |2 |4.7 |3.2 |1.3 |0.2 | |3 |4.6 |3.1 |1.5 |0.2 | |4 |5.0 |3.6 |1.4 |0.2 | - **DataFrame.info**: برای شروع، از متد `info()` برای چاپ خلاصه‌ای از محتوای موجود در یک `DataFrame` استفاده می‌شود. بیایید نگاهی به این مجموعه داده بیندازیم تا ببینیم چه چیزی داریم: ```python iris_df.info() ``` ``` RangeIndex: 150 entries, 0 to 149 Data columns (total 4 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 sepal length (cm) 150 non-null float64 1 sepal width (cm) 150 non-null float64 2 petal length (cm) 150 non-null float64 3 petal width (cm) 150 non-null float64 dtypes: float64(4) memory usage: 4.8 KB ``` از اینجا می‌دانیم که مجموعه داده *Iris* شامل ۱۵۰ ورودی در چهار ستون است و هیچ ورودی خالی ندارد. تمام داده‌ها به صورت اعداد اعشاری ۶۴ بیتی ذخیره شده‌اند. - **DataFrame.head()**: سپس، برای بررسی محتوای واقعی `DataFrame`، از متد `head()` استفاده می‌کنیم. بیایید ببینیم چند سطر اول `iris_df` ما چگونه به نظر می‌رسند: ```python iris_df.head() ``` ``` sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) 0 5.1 3.5 1.4 0.2 1 4.9 3.0 1.4 0.2 2 4.7 3.2 1.3 0.2 3 4.6 3.1 1.5 0.2 4 5.0 3.6 1.4 0.2 ``` - **DataFrame.tail()**: به طور مشابه، برای بررسی چند سطر آخر `DataFrame`، از متد `tail()` استفاده می‌کنیم: ```python iris_df.tail() ``` ``` sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) 145 6.7 3.0 5.2 2.3 146 6.3 2.5 5.0 1.9 147 6.5 3.0 5.2 2.0 148 6.2 3.4 5.4 2.3 149 5.9 3.0 5.1 1.8 ``` > **نتیجه‌گیری:** حتی با نگاه کردن به متادیتای اطلاعات موجود در یک DataFrame یا چند مقدار اول و آخر آن، می‌توانید بلافاصله ایده‌ای از اندازه، شکل و محتوای داده‌هایی که با آن‌ها کار می‌کنید به دست آورید. ## مدیریت داده‌های گمشده > **هدف یادگیری:** تا پایان این بخش، باید بدانید چگونه مقادیر خالی را در DataFrameها جایگزین یا حذف کنید. اغلب مجموعه داده‌هایی که می‌خواهید استفاده کنید (یا مجبور به استفاده از آن‌ها هستید) شامل مقادیر گمشده هستند. نحوه مدیریت داده‌های گمشده دارای ملاحظات ظریفی است که می‌تواند بر تحلیل نهایی و نتایج دنیای واقعی تأثیر بگذارد. Pandas داده‌های گمشده را به دو روش مدیریت می‌کند. اولین مورد که قبلاً در بخش‌های قبلی دیده‌اید: `NaN` یا Not a Number. این در واقع یک مقدار خاص است که بخشی از مشخصات IEEE برای اعداد اعشاری است و فقط برای نشان دادن مقادیر گمشده اعشاری استفاده می‌شود. برای مقادیر گمشده غیر از اعداد اعشاری، pandas از شیء `None` پایتون استفاده می‌کند. در حالی که ممکن است گیج‌کننده به نظر برسد که با دو نوع مقدار مختلف مواجه شوید که اساساً یک چیز را می‌گویند، دلایل برنامه‌نویسی معتبری برای این انتخاب طراحی وجود دارد و در عمل، این رویکرد به pandas اجازه می‌دهد تا برای اکثر موارد یک سازش خوب ارائه دهد. با این حال، هم `None` و هم `NaN` محدودیت‌هایی دارند که باید در مورد نحوه استفاده از آن‌ها به آن‌ها توجه کنید. اطلاعات بیشتری درباره `NaN` و `None` را از [دفترچه یادداشت](https://github.com/microsoft/Data-Science-For-Beginners/blob/main/4-Data-Science-Lifecycle/15-analyzing/notebook.ipynb) بررسی کنید! - **تشخیص مقادیر خالی**: در `pandas`، متدهای `isnull()` و `notnull()` ابزارهای اصلی شما برای تشخیص داده‌های خالی هستند. هر دو ماسک‌های بولی روی داده‌های شما بازمی‌گردانند. ما از `numpy` برای مقادیر `NaN` استفاده خواهیم کرد: ```python import numpy as np example1 = pd.Series([0, np.nan, '', None]) example1.isnull() ``` ``` 0 False 1 True 2 False 3 True dtype: bool ``` به خروجی دقت کنید. آیا چیزی شما را شگفت‌زده می‌کند؟ در حالی که `0` یک مقدار عددی خالی است، با این حال یک عدد صحیح معتبر است و pandas آن را به این صورت در نظر می‌گیرد. `''` کمی ظریف‌تر است. در حالی که ما از آن در بخش ۱ برای نشان دادن یک مقدار رشته‌ای خالی استفاده کردیم، با این حال یک شیء رشته‌ای است و به عنوان یک مقدار خالی از نظر pandas در نظر گرفته نمی‌شود. حالا، بیایید این موضوع را برعکس کنیم و از این متدها به روشی استفاده کنیم که بیشتر در عمل استفاده خواهید کرد. شما می‌توانید از ماسک‌های بولی مستقیماً به عنوان یک ``Series`` یا ``DataFrame`` استفاده کنید، که می‌تواند هنگام کار با مقادیر خالی (یا موجود) مفید باشد. > **نتیجه‌گیری:** هم متدهای `isnull()` و هم `notnull()` نتایج مشابهی را هنگام استفاده در `DataFrame`ها تولید می‌کنند: آن‌ها نتایج و شاخص آن نتایج را نشان می‌دهند، که به شما کمک زیادی می‌کند زیرا با داده‌های خود کار می‌کنید. - **حذف مقادیر خالی**: علاوه بر شناسایی مقادیر گمشده، pandas یک روش مناسب برای حذف مقادیر خالی از `Series` و `DataFrame`ها ارائه می‌دهد. (به خصوص در مجموعه داده‌های بزرگ، اغلب توصیه می‌شود که به سادگی مقادیر گمشده [NA] را از تحلیل خود حذف کنید تا اینکه به روش‌های دیگر با آن‌ها برخورد کنید.) برای مشاهده این موضوع در عمل، بیایید به `example1` بازگردیم: ```python example1 = example1.dropna() example1 ``` ``` 0 0 2 dtype: object ``` توجه داشته باشید که این باید شبیه خروجی شما از `example3[example3.notnull()]` باشد. تفاوت در اینجا این است که به جای فقط ایندکس کردن مقادیر ماسک‌شده، `dropna` آن مقادیر گمشده را از `Series` `example1` حذف کرده است. از آنجا که `DataFrame`ها دو بعدی هستند، گزینه‌های بیشتری برای حذف داده‌ها ارائه می‌دهند. ```python example2 = pd.DataFrame([[1, np.nan, 7], [2, 5, 8], [np.nan, 6, 9]]) example2 ``` | | 0 | 1 | 2 | |------|---|---|---| |0 |1.0|NaN|7 | |1 |2.0|5.0|8 | |2 |NaN|6.0|9 | (آیا متوجه شدید که pandas دو ستون را به اعداد اعشاری تبدیل کرد تا با `NaN`ها سازگار شود؟) شما نمی‌توانید یک مقدار واحد را از یک `DataFrame` حذف کنید، بنابراین باید سطرها یا ستون‌های کامل را حذف کنید. بسته به کاری که انجام می‌دهید، ممکن است بخواهید یکی یا دیگری را انجام دهید، و بنابراین pandas گزینه‌هایی برای هر دو به شما می‌دهد. زیرا در علم داده، ستون‌ها معمولاً متغیرها و سطرها مشاهدات را نشان می‌دهند، احتمالاً بیشتر سطرهای داده را حذف خواهید کرد؛ تنظیم پیش‌فرض برای `dropna()` این است که تمام سطرهایی که شامل هر مقدار خالی هستند را حذف کند: ```python example2.dropna() ``` ``` 0 1 2 1 2.0 5.0 8 ``` در صورت لزوم، می‌توانید مقادیر NA را از ستون‌ها حذف کنید. از `axis=1` برای این کار استفاده کنید: ```python example2.dropna(axis='columns') ``` ``` 2 0 7 1 8 2 9 ``` توجه داشته باشید که این می‌تواند مقدار زیادی از داده‌هایی را که ممکن است بخواهید نگه دارید حذف کند، به خصوص در مجموعه داده‌های کوچکتر. اگر فقط بخواهید سطرها یا ستون‌هایی را حذف کنید که شامل چندین مقدار خالی یا حتی تمام مقادیر خالی هستند چه؟ شما می‌توانید این تنظیمات را در `dropna` با پارامترهای `how` و `thresh` مشخص کنید. به طور پیش‌فرض، `how='any'` است (اگر می‌خواهید خودتان بررسی کنید یا ببینید چه پارامترهای دیگری این متد دارد، `example4.dropna?` را در یک سلول کد اجرا کنید). شما می‌توانید به جای آن `how='all'` را مشخص کنید تا فقط سطرها یا ستون‌هایی که شامل تمام مقادیر خالی هستند حذف شوند. بیایید مثال `DataFrame` خود را گسترش دهیم تا این موضوع را در عمل ببینیم. ```python example2[3] = np.nan example2 ``` | |0 |1 |2 |3 | |------|---|---|---|---| |0 |1.0|NaN|7 |NaN| |1 |2.0|5.0|8 |NaN| |2 |NaN|6.0|9 |NaN| پارامتر `thresh` کنترل دقیق‌تری به شما می‌دهد: شما تعداد مقادیر *غیر خالی* را که یک سطر یا ستون باید داشته باشد تا نگه داشته شود تنظیم می‌کنید: ```python example2.dropna(axis='rows', thresh=3) ``` ``` 0 1 2 3 1 2.0 5.0 8 NaN ``` در اینجا، سطر اول و آخر حذف شده‌اند، زیرا آن‌ها فقط شامل دو مقدار غیر خالی هستند. - **پر کردن مقادیر خالی**: بسته به مجموعه داده شما، گاهی اوقات پر کردن مقادیر خالی با مقادیر معتبر به جای حذف آن‌ها منطقی‌تر است. شما می‌توانید از `isnull` برای این کار به صورت درجا استفاده کنید، اما این می‌تواند زمان‌بر باشد، به خصوص اگر مقادیر زیادی برای پر کردن داشته باشید. زیرا این یک کار رایج در علم داده است، pandas متد `fillna` را ارائه می‌دهد که یک کپی از `Series` یا `DataFrame` را با مقادیر گمشده جایگزین‌شده با یکی از انتخاب شما بازمی‌گرداند. بیایید یک مثال دیگر از `Series` ایجاد کنیم تا ببینیم این در عمل چگونه کار می‌کند. ```python example3 = pd.Series([1, np.nan, 2, None, 3], index=list('abcde')) example3 ``` ``` a 1.0 b NaN c 2.0 d NaN e 3.0 dtype: float64 ``` شما می‌توانید تمام ورودی‌های خالی را با یک مقدار واحد، مانند `0` پر کنید: ```python example3.fillna(0) ``` ``` a 1.0 b 0.0 c 2.0 d 0.0 e 3.0 dtype: float64 ``` شما می‌توانید مقادیر خالی را به صورت **پر کردن به جلو** پر کنید، یعنی از آخرین مقدار معتبر برای پر کردن یک مقدار خالی استفاده کنید: ```python example3.fillna(method='ffill') ``` ``` a 1.0 b 1.0 c 2.0 d 2.0 e 3.0 dtype: float64 ``` شما همچنین می‌توانید به صورت **پر کردن به عقب** مقدار معتبر بعدی را به عقب منتقل کنید تا یک مقدار خالی را پر کنید: ```python example3.fillna(method='bfill') ``` ``` a 1.0 b 2.0 c 2.0 d 3.0 e 3.0 dtype: float64 ``` همان‌طور که ممکن است حدس بزنید، این با `DataFrame`ها نیز به همین صورت کار می‌کند، اما شما می‌توانید یک `axis` را مشخص کنید که در طول آن مقادیر خالی پر شوند. با استفاده مجدد از `example2` که قبلاً استفاده شد: ```python example2.fillna(method='ffill', axis=1) ``` ``` 0 1 2 3 0 1.0 1.0 7.0 7.0 1 2.0 5.0 8.0 8.0 2 NaN 6.0 9.0 9.0 ``` توجه داشته باشید که وقتی مقدار قبلی برای پر کردن به جلو در دسترس نیست، مقدار خالی باقی می‌ماند. > **نکته مهم:** روش‌های مختلفی برای مدیریت مقادیر گمشده در مجموعه داده‌های شما وجود دارد. استراتژی خاصی که استفاده می‌کنید (حذف کردن، جایگزین کردن، یا حتی نحوه جایگزین کردن) باید بر اساس ویژگی‌های خاص آن داده‌ها تعیین شود. هرچه بیشتر با مجموعه داده‌ها کار کنید و تعامل داشته باشید، درک بهتری از نحوه مدیریت مقادیر گمشده پیدا خواهید کرد. ## حذف داده‌های تکراری > **هدف یادگیری:** تا پایان این بخش، باید بتوانید مقادیر تکراری را در DataFrame‌ها شناسایی و حذف کنید. علاوه بر داده‌های گمشده، اغلب در مجموعه داده‌های واقعی با داده‌های تکراری مواجه خواهید شد. خوشبختانه، `pandas` روشی ساده برای شناسایی و حذف ورودی‌های تکراری ارائه می‌دهد. - **شناسایی داده‌های تکراری: `duplicated`**: شما می‌توانید به راحتی مقادیر تکراری را با استفاده از متد `duplicated` در pandas شناسایی کنید. این متد یک ماسک بولی برمی‌گرداند که نشان می‌دهد آیا یک ورودی در `DataFrame` تکراری از ورودی قبلی است یا خیر. بیایید یک مثال دیگر از `DataFrame` ایجاد کنیم تا این موضوع را در عمل ببینیم. ```python example4 = pd.DataFrame({'letters': ['A','B'] * 2 + ['B'], 'numbers': [1, 2, 1, 3, 3]}) example4 ``` | |letters|numbers| |------|-------|-------| |0 |A |1 | |1 |B |2 | |2 |A |1 | |3 |B |3 | |4 |B |3 | ```python example4.duplicated() ``` ``` 0 False 1 False 2 True 3 False 4 True dtype: bool ``` - **حذف داده‌های تکراری: `drop_duplicates`:** به سادگی یک نسخه از داده‌ها را برمی‌گرداند که در آن تمام مقادیر `duplicated` برابر با `False` هستند: ```python example4.drop_duplicates() ``` ``` letters numbers 0 A 1 1 B 2 3 B 3 ``` هم `duplicated` و هم `drop_duplicates` به طور پیش‌فرض تمام ستون‌ها را در نظر می‌گیرند، اما شما می‌توانید مشخص کنید که فقط یک زیرمجموعه از ستون‌ها در `DataFrame` بررسی شوند: ```python example4.drop_duplicates(['letters']) ``` ``` letters numbers 0 A 1 1 B 2 ``` > **نکته مهم:** حذف داده‌های تکراری بخش ضروری تقریباً هر پروژه علم داده است. داده‌های تکراری می‌توانند نتایج تحلیل‌های شما را تغییر دهند و نتایج نادرستی به شما بدهند! ## 🚀 چالش تمام مطالب مطرح شده به صورت یک [دفترچه Jupyter](https://github.com/microsoft/Data-Science-For-Beginners/blob/main/2-Working-With-Data/08-data-preparation/notebook.ipynb) ارائه شده‌اند. علاوه بر این، تمرین‌هایی پس از هر بخش وجود دارند، آن‌ها را امتحان کنید! ## [آزمون پس از درس](https://ff-quizzes.netlify.app/en/ds/) ## مرور و مطالعه شخصی روش‌های زیادی برای کشف و آماده‌سازی داده‌های شما برای تحلیل و مدل‌سازی وجود دارد و پاکسازی داده‌ها یک مرحله مهم و عملی است. این چالش‌ها را از Kaggle امتحان کنید تا تکنیک‌هایی را که در این درس پوشش داده نشده‌اند، کشف کنید. - [چالش پاکسازی داده‌ها: تجزیه تاریخ‌ها](https://www.kaggle.com/rtatman/data-cleaning-challenge-parsing-dates/) - [چالش پاکسازی داده‌ها: مقیاس‌بندی و نرمال‌سازی داده‌ها](https://www.kaggle.com/rtatman/data-cleaning-challenge-scale-and-normalize-data) ## تکلیف [ارزیابی داده‌ها از یک فرم](assignment.md) --- **سلب مسئولیت**: این سند با استفاده از سرویس ترجمه هوش مصنوعی [Co-op Translator](https://github.com/Azure/co-op-translator) ترجمه شده است. در حالی که ما برای دقت تلاش می‌کنیم، لطفاً توجه داشته باشید که ترجمه‌های خودکار ممکن است شامل خطاها یا نادرستی‌هایی باشند. سند اصلی به زبان اصلی آن باید به عنوان منبع معتبر در نظر گرفته شود. برای اطلاعات حساس، ترجمه حرفه‌ای انسانی توصیه می‌شود. ما هیچ مسئولیتی در قبال سوءتفاهم‌ها یا تفسیرهای نادرست ناشی از استفاده از این ترجمه نداریم.