# العمل مع البيانات: إعداد البيانات |![ رسم توضيحي بواسطة [(@sketchthedocs)](https://sketchthedocs.dev) ](../../sketchnotes/08-DataPreparation.png)| |:---:| |إعداد البيانات - _رسم توضيحي بواسطة [@nitya](https://twitter.com/nitya)_ | ## [اختبار ما قبل المحاضرة](https://purple-hill-04aebfb03.1.azurestaticapps.net/quiz/14) اعتمادًا على مصدرها، قد تحتوي البيانات الخام على بعض التناقضات التي تسبب تحديات في التحليل والنمذجة. بمعنى آخر، يمكن تصنيف هذه البيانات على أنها "غير نظيفة" وستحتاج إلى تنظيفها. تركز هذه الدرس على تقنيات تنظيف وتحويل البيانات للتعامل مع تحديات البيانات المفقودة أو غير الدقيقة أو غير المكتملة. المواضيع التي يتم تناولها في هذا الدرس ستستخدم مكتبة Python وPandas وسيتم [عرضها في الدفتر](notebook.ipynb) داخل هذا الدليل. ## أهمية تنظيف البيانات - **سهولة الاستخدام وإعادة الاستخدام**: عندما تكون البيانات منظمة ومُطَبَّعة بشكل صحيح، يصبح من السهل البحث عنها واستخدامها ومشاركتها مع الآخرين. - **الاتساق**: غالبًا ما يتطلب علم البيانات العمل مع أكثر من مجموعة بيانات، حيث يجب دمج مجموعات البيانات من مصادر مختلفة معًا. ضمان أن كل مجموعة بيانات فردية لديها توحيد مشترك سيضمن أن البيانات تظل مفيدة عند دمجها في مجموعة بيانات واحدة. - **دقة النماذج**: تحسين دقة النماذج التي تعتمد على البيانات النظيفة. ## أهداف واستراتيجيات التنظيف الشائعة - **استكشاف مجموعة البيانات**: يمكن أن يساعد استكشاف البيانات، الذي يتم تغطيته في [درس لاحق](https://github.com/microsoft/Data-Science-For-Beginners/tree/main/4-Data-Science-Lifecycle/15-analyzing)، في اكتشاف البيانات التي تحتاج إلى تنظيف. يمكن أن يوفر الملاحظة البصرية للقيم داخل مجموعة البيانات توقعات لما ستبدو عليه بقية البيانات أو فكرة عن المشكلات التي يمكن حلها. يشمل الاستكشاف الاستعلامات الأساسية، التصورات، وأخذ العينات. - **التنسيق**: اعتمادًا على المصدر، قد تحتوي البيانات على تناقضات في كيفية تقديمها. يمكن أن يسبب ذلك مشاكل في البحث عن القيم وتمثيلها، حيث يتم رؤيتها داخل مجموعة البيانات ولكن لا يتم تمثيلها بشكل صحيح في التصورات أو نتائج الاستعلام. تشمل مشاكل التنسيق الشائعة معالجة المسافات البيضاء، التواريخ، وأنواع البيانات. عادةً ما يكون حل مشاكل التنسيق مسؤولية الأشخاص الذين يستخدمون البيانات. على سبيل المثال، تختلف المعايير حول كيفية تقديم التواريخ والأرقام حسب البلد. - **التكرار**: يمكن أن تؤدي البيانات التي تحتوي على أكثر من تكرار إلى نتائج غير دقيقة وعادةً ما يجب إزالتها. يمكن أن يحدث هذا بشكل شائع عند دمج مجموعتين أو أكثر من البيانات معًا. ومع ذلك، هناك حالات يكون فيها التكرار في مجموعات البيانات المدمجة يحتوي على أجزاء يمكن أن توفر معلومات إضافية وقد تحتاج إلى الاحتفاظ بها. - **البيانات المفقودة**: يمكن أن تسبب البيانات المفقودة نتائج غير دقيقة بالإضافة إلى نتائج ضعيفة أو منحازة. يمكن أحيانًا حل هذه المشكلة عن طريق "إعادة تحميل" البيانات، أو ملء القيم المفقودة بالحسابات والرموز مثل Python، أو ببساطة إزالة القيمة والبيانات المقابلة. هناك أسباب عديدة لفقدان البيانات، والإجراءات المتخذة لحل هذه القيم المفقودة تعتمد على كيفية ولماذا فقدت في المقام الأول. ## استكشاف معلومات DataFrame > **هدف التعلم:** بنهاية هذا القسم، يجب أن تكون مرتاحًا في العثور على معلومات عامة حول البيانات المخزنة في DataFrames في pandas. بمجرد تحميل البيانات في pandas، من المرجح أن تكون في DataFrame (راجع [الدرس السابق](https://github.com/microsoft/Data-Science-For-Beginners/tree/main/2-Working-With-Data/07-python#dataframe) للحصول على نظرة عامة مفصلة). ومع ذلك، إذا كانت مجموعة البيانات في DataFrame تحتوي على 60,000 صف و400 عمود، كيف يمكنك البدء في فهم ما تعمل معه؟ لحسن الحظ، توفر [pandas](https://pandas.pydata.org/) أدوات ملائمة للنظر بسرعة في المعلومات العامة حول DataFrame بالإضافة إلى الصفوف الأولى والأخيرة. لاستكشاف هذه الوظيفة، سنقوم باستيراد مكتبة Python 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* تحتوي على 150 إدخالًا في أربعة أعمدة بدون أي إدخالات فارغة. يتم تخزين جميع البيانات كأرقام عائمة 64 بت. - **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 أو القيم الأولى والأخيرة، يمكنك الحصول على فكرة فورية عن الحجم والشكل والمحتوى للبيانات التي تتعامل معها. ## التعامل مع البيانات المفقودة > **هدف التعلم:** بنهاية هذا القسم، يجب أن تعرف كيفية استبدال أو إزالة القيم الفارغة من DataFrames. غالبًا ما تحتوي مجموعات البيانات التي ترغب في استخدامها (أو يجب استخدامها) على قيم مفقودة. الطريقة التي يتم بها التعامل مع البيانات المفقودة تحمل معها توازنات دقيقة يمكن أن تؤثر على التحليل النهائي والنتائج الواقعية. يتعامل pandas مع القيم المفقودة بطريقتين. الأولى التي رأيتها من قبل في الأقسام السابقة: `NaN`، أو ليس رقمًا. هذه في الواقع قيمة خاصة وهي جزء من مواصفات IEEE للأرقام العائمة وتستخدم فقط للإشارة إلى القيم العائمة المفقودة. بالنسبة للقيم المفقودة بخلاف الأرقام العائمة، يستخدم pandas كائن Python `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 على هذا النحو. `''` أكثر دقة قليلاً. بينما استخدمناه في القسم 1 لتمثيل قيمة سلسلة فارغة، إلا أنه مع ذلك كائن سلسلة وليس تمثيلًا للفارغ كما يعتبره pandas. الآن، دعنا نعكس هذا ونستخدم هذه الطرق بطريقة أكثر تشابهًا مع الطريقة التي ستستخدمها في الممارسة. يمكنك استخدام الأقنعة المنطقية مباشرة كمؤشر ``Series`` أو ``DataFrame``، وهو أمر مفيد عند محاولة العمل مع القيم الفارغة (أو الموجودة) المعزولة. > **الخلاصة**: تنتج الطرق `isnull()` و`notnull()` نتائج مشابهة عند استخدامها في `DataFrame`s: فهي تعرض النتائج ومؤشر تلك النتائج، مما سيساعدك بشكل كبير أثناء التعامل مع بياناتك. - **إزالة القيم الفارغة**: بالإضافة إلى تحديد القيم المفقودة، يوفر pandas وسيلة ملائمة لإزالة القيم الفارغة من `Series` و`DataFrame`s. (خصوصًا في مجموعات البيانات الكبيرة، غالبًا ما يكون من الأفضل ببساطة إزالة القيم المفقودة [NA] من تحليلك بدلاً من التعامل معها بطرق أخرى.) لرؤية هذا عمليًا، دعنا نعود إلى `example1`: ```python example1 = example1.dropna() example1 ``` ``` 0 0 2 dtype: object ``` لاحظ أن هذا يجب أن يبدو مثل الإخراج الخاص بك من `example3[example3.notnull()]`. الفرق هنا هو أنه، بدلاً من مجرد الفهرسة على القيم المقنعة، قامت `dropna` بإزالة تلك القيم المفقودة من `Series` `example1`. نظرًا لأن `DataFrame`s لها بعدان، فإنها توفر المزيد من الخيارات لإسقاط البيانات. ```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`s؟) لا يمكنك إسقاط قيمة واحدة من `DataFrame`، لذا عليك إسقاط صفوف أو أعمدة كاملة. اعتمادًا على ما تقوم به، قد ترغب في القيام بأحدهما أو الآخر، لذا يوفر pandas خيارات لكليهما. نظرًا لأن الأعمدة تمثل عادةً المتغيرات والصفوف تمثل الملاحظات في علم البيانات، فمن المرجح أن تقوم بإسقاط صفوف البيانات؛ الإعداد الافتراضي لـ `dropna()` هو إسقاط جميع الصفوف التي تحتوي على أي قيم فارغة: ```python example2.dropna() ``` ``` 0 1 2 1 2.0 5.0 8 ``` إذا لزم الأمر، يمكنك إسقاط القيم الفارغة من الأعمدة. استخدم `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`s، ولكن يمكنك أيضًا تحديد `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 ``` لاحظ أنه عندما لا تكون هناك قيمة سابقة متاحة للملء للأمام، تبقى القيمة الفارغة. > **المغزى:** هناك طرق متعددة للتعامل مع القيم المفقودة في مجموعات البيانات الخاصة بك. يجب أن تكون الاستراتيجية التي تستخدمها (إزالتها، استبدالها، أو حتى كيفية استبدالها) مستندة إلى خصائص تلك البيانات. ستكتسب فهمًا أفضل لكيفية التعامل مع القيم المفقودة كلما تعاملت وتفاعلت مع مجموعات البيانات. ## إزالة البيانات المكررة > **هدف التعلم:** بنهاية هذا القسم الفرعي، يجب أن تكون قادرًا على تحديد وإزالة القيم المكررة من DataFrames بسهولة. بالإضافة إلى البيانات المفقودة، ستواجه غالبًا بيانات مكررة في مجموعات البيانات الواقعية. لحسن الحظ، يوفر `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`:** ببساطة تُرجع نسخة من البيانات التي تكون فيها جميع القيم المكررة `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 Notebook](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). بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو معلومات غير دقيقة. يجب اعتبار المستند الأصلي بلغته الأصلية هو المصدر الموثوق. للحصول على معلومات حساسة أو هامة، يُوصى بالاستعانة بترجمة بشرية احترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة تنشأ عن استخدام هذه الترجمة.