From 462a17f4b47edd0b5052d8d5b06647f7c9bcf3a7 Mon Sep 17 00:00:00 2001 From: leestott Date: Fri, 3 Oct 2025 21:27:28 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=90=20Update=20translations=20via=20Co?= =?UTF-8?q?-op=20Translator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../08-data-preparation/notebook.ipynb | 742 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 716 +++++++++++++-- .../08-data-preparation/notebook.ipynb | 742 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 719 +++++++++++++-- .../08-data-preparation/notebook.ipynb | 727 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 687 ++++++++++++-- .../08-data-preparation/notebook.ipynb | 719 +++++++++++++-- .../08-data-preparation/notebook.ipynb | 692 ++++++++++++-- .../08-data-preparation/notebook.ipynb | 700 ++++++++++++-- .../08-data-preparation/notebook.ipynb | 685 ++++++++++++-- .../08-data-preparation/notebook.ipynb | 756 +++++++++++++--- .../08-data-preparation/notebook.ipynb | 726 +++++++++++++-- .../08-data-preparation/notebook.ipynb | 680 ++++++++++++-- .../08-data-preparation/notebook.ipynb | 713 +++++++++++++-- .../08-data-preparation/notebook.ipynb | 796 +++++++++++++--- .../08-data-preparation/notebook.ipynb | 744 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 724 +++++++++++++-- .../08-data-preparation/notebook.ipynb | 759 +++++++++++++--- .../08-data-preparation/notebook.ipynb | 690 ++++++++++++-- .../08-data-preparation/notebook.ipynb | 734 +++++++++++++-- .../08-data-preparation/notebook.ipynb | 730 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 752 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 728 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 797 +++++++++++++--- .../08-data-preparation/notebook.ipynb | 810 ++++++++++++++--- .../08-data-preparation/notebook.ipynb | 732 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 854 ++++++++++++++---- .../08-data-preparation/notebook.ipynb | 826 ++++++++++++++--- .../08-data-preparation/notebook.ipynb | 697 ++++++++++++-- .../08-data-preparation/notebook.ipynb | 766 +++++++++++++--- .../08-data-preparation/notebook.ipynb | 820 ++++++++++++++--- .../08-data-preparation/notebook.ipynb | 715 +++++++++++++-- .../08-data-preparation/notebook.ipynb | 738 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 746 +++++++++++++-- .../08-data-preparation/notebook.ipynb | 752 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 747 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 727 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 748 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 690 ++++++++++++-- .../08-data-preparation/notebook.ipynb | 798 +++++++++++++--- .../08-data-preparation/notebook.ipynb | 817 ++++++++++++++--- .../08-data-preparation/notebook.ipynb | 759 +++++++++++++--- .../08-data-preparation/notebook.ipynb | 738 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 770 +++++++++++++--- .../08-data-preparation/notebook.ipynb | 754 +++++++++++++--- .../08-data-preparation/notebook.ipynb | 742 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 753 ++++++++++++--- .../08-data-preparation/notebook.ipynb | 729 ++++++++++++--- 48 files changed, 30634 insertions(+), 5052 deletions(-) diff --git a/translations/ar/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/ar/2-Working-With-Data/08-data-preparation/notebook.ipynb index 2f32685f..c5f62f02 100644 --- a/translations/ar/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/ar/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# إعداد البيانات\n", "\n", - "[المصدر الأصلي للمفكرة من *علم البيانات: مقدمة إلى تعلم الآلة لعلم البيانات باستخدام Python وMachine Learning Studio بواسطة Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[المصدر الأصلي للمفكرة من *علم البيانات: مقدمة في تعلم الآلة لعلم البيانات باستخدام Python وMachine Learning Studio بواسطة Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## استكشاف معلومات `DataFrame`\n", "\n", - "> **الهدف التعليمي:** بنهاية هذا القسم الفرعي، يجب أن تكون مرتاحًا في العثور على معلومات عامة حول البيانات المخزنة في DataFrames الخاصة بـ pandas.\n", + "> **هدف التعلم:** بنهاية هذا القسم الفرعي، يجب أن تكون مرتاحًا في العثور على معلومات عامة حول البيانات المخزنة في DataFrames الخاصة بـ pandas.\n", "\n", - "بمجرد تحميل بياناتك في pandas، من المرجح أن تكون في شكل `DataFrame`. ولكن إذا كان مجموعة البيانات في `DataFrame` تحتوي على 60,000 صف و400 عمود، كيف يمكنك حتى البدء في فهم ما تعمل معه؟ لحسن الحظ، توفر pandas أدوات مريحة لعرض معلومات عامة عن `DataFrame` بسرعة بالإضافة إلى عرض أول بضعة صفوف وآخر بضعة صفوف.\n", + "بمجرد تحميل بياناتك في pandas، من المرجح أن تكون في شكل `DataFrame`. ومع ذلك، إذا كان مجموعة البيانات في `DataFrame` تحتوي على 60,000 صف و400 عمود، كيف يمكنك حتى البدء في فهم ما تعمل معه؟ لحسن الحظ، توفر pandas أدوات مريحة لعرض معلومات عامة عن `DataFrame` بسرعة بالإضافة إلى الصفوف الأولى والأخيرة.\n", "\n", - "لاستكشاف هذه الوظيفة، سنقوم باستيراد مكتبة scikit-learn الخاصة بـ Python واستخدام مجموعة بيانات أيقونية يعرفها كل عالم بيانات تقريبًا: مجموعة بيانات *Iris* لعالم الأحياء البريطاني رونالد فيشر، التي استخدمها في ورقته البحثية عام 1936 بعنوان \"استخدام القياسات المتعددة في المشكلات التصنيفية\":\n" + "لاستكشاف هذه الوظيفة، سنقوم باستيراد مكتبة scikit-learn الخاصة بـ Python واستخدام مجموعة بيانات شهيرة يعرفها كل عالم بيانات مئات المرات: مجموعة بيانات *Iris* لعالم الأحياء البريطاني رونالد فيشر، التي استخدمها في ورقته البحثية عام 1936 بعنوان \"استخدام القياسات المتعددة في المشاكل التصنيفية\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "قمنا بتحميل مجموعة بيانات Iris في المتغير `iris_df`. قبل التعمق في البيانات، سيكون من المفيد معرفة عدد نقاط البيانات التي لدينا والحجم الإجمالي لمجموعة البيانات. من المفيد إلقاء نظرة على حجم البيانات التي نتعامل معها.\n" + "لقد قمنا بتحميل مجموعة بيانات Iris في المتغير `iris_df`. قبل التعمق في البيانات، سيكون من المفيد معرفة عدد نقاط البيانات التي لدينا وحجم مجموعة البيانات بشكل عام. من المفيد النظر إلى حجم البيانات التي نتعامل معها.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "لذلك، نحن نتعامل مع 150 صفًا و4 أعمدة من البيانات. يمثل كل صف نقطة بيانات واحدة، وكل عمود يمثل ميزة واحدة مرتبطة بإطار البيانات. بمعنى آخر، هناك 150 نقطة بيانات تحتوي كل منها على 4 ميزات.\n", + "إذن، نحن نتعامل مع 150 صفًا و4 أعمدة من البيانات. كل صف يمثل نقطة بيانات واحدة وكل عمود يمثل ميزة واحدة مرتبطة بإطار البيانات. لذا، بشكل أساسي، هناك 150 نقطة بيانات تحتوي كل منها على 4 ميزات.\n", "\n", - "`shape` هنا هو خاصية لإطار البيانات وليس دالة، ولهذا السبب لا ينتهي بقوسين.\n" + "`shape` هنا هو خاصية لإطار البيانات وليس وظيفة، ولهذا السبب لا ينتهي بقوسين.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "دعونا الآن ننتقل إلى الأعمدة الأربعة للبيانات. ماذا يمثل كل منها بالضبط؟ سيوفر لنا السمة `columns` أسماء الأعمدة في إطار البيانات.\n" + "دعونا الآن ننتقل إلى الأعمدة الأربعة للبيانات. ماذا يمثل كل منها بالضبط؟ ستوفر لنا خاصية `columns` أسماء الأعمدة في إطار البيانات.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "كمية البيانات (المعطاة بواسطة الخاصية `shape`) وأسماء الميزات أو الأعمدة (المعطاة بواسطة الخاصية `columns`) تخبرنا شيئًا عن مجموعة البيانات. الآن، نرغب في التعمق أكثر في مجموعة البيانات. وظيفة `DataFrame.info()` مفيدة جدًا لهذا الغرض.\n" + "كمية البيانات (المعطاة بواسطة الخاصية `shape`) وأسماء الميزات أو الأعمدة (المعطاة بواسطة الخاصية `columns`) تخبرنا شيئًا عن مجموعة البيانات. الآن، قد نرغب في التعمق أكثر في مجموعة البيانات. وظيفة `DataFrame.info()` مفيدة جدًا لهذا الغرض.\n" ] }, { @@ -180,9 +180,8 @@ "id": "1XgVMpvigRru" }, "source": [ - "من هنا، يمكننا أن نستنتج بعض الملاحظات:\n", - "\n", - "1. نوع البيانات لكل عمود: في هذا الملف، يتم تخزين جميع البيانات كأرقام ذات فاصلة عائمة بدقة 64 بت.\n", + "من هنا، يمكننا ملاحظة بعض النقاط:\n", + "1. نوع البيانات لكل عمود: في هذه المجموعة من البيانات، يتم تخزين جميع البيانات كأرقام ذات فاصلة عائمة 64-بت.\n", "2. عدد القيم غير الفارغة: التعامل مع القيم الفارغة هو خطوة مهمة في إعداد البيانات. سيتم التعامل معها لاحقًا في الدفتر.\n" ] }, @@ -193,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "لنفترض أن لدينا الكثير من البيانات الرقمية في مجموعة البيانات الخاصة بنا. يمكن إجراء الحسابات الإحصائية الأحادية المتغير مثل المتوسط، الوسيط، الأرباع، وما إلى ذلك على كل عمود بشكل فردي. وظيفة `DataFrame.describe()` تقدم لنا ملخصًا إحصائيًا للأعمدة الرقمية في مجموعة البيانات.\n" + "لنفترض أن لدينا الكثير من البيانات الرقمية في مجموعة البيانات الخاصة بنا. يمكن إجراء حسابات إحصائية أحادية المتغير مثل المتوسط، الوسيط، الأرباع وغيرها على كل عمود بشكل فردي. توفر لنا وظيفة `DataFrame.describe()` ملخصًا إحصائيًا للأعمدة الرقمية في مجموعة البيانات.\n" ] }, { @@ -323,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "يُظهر الناتج أعلاه العدد الإجمالي لنقاط البيانات، المتوسط، الانحراف المعياري، الحد الأدنى، الربع الأدنى (25%)، الوسيط (50%)، الربع الأعلى (75%) والقيمة القصوى لكل عمود.\n" + "يعرض الإخراج أعلاه العدد الإجمالي لنقاط البيانات، المتوسط، الانحراف المعياري، الحد الأدنى، الربع الأدنى (25%)، الوسيط (50%)، الربع الأعلى (75%) والقيمة القصوى لكل عمود.\n" ] }, { @@ -333,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "مع كل الوظائف والخصائص المذكورة أعلاه، حصلنا على نظرة عامة على مستوى عالٍ للمجموعة البيانية. نعرف عدد النقاط البيانية الموجودة، وعدد الميزات، ونوع البيانات لكل ميزة، وعدد القيم غير الفارغة لكل ميزة.\n", + "مع كل الوظائف والخصائص المذكورة أعلاه، حصلنا على نظرة عامة على مستوى عالٍ للمجموعة البيانات. نعرف الآن عدد النقاط البيانات الموجودة، وعدد الميزات، ونوع البيانات لكل ميزة، وعدد القيم غير الفارغة لكل ميزة.\n", "\n", - "الآن حان الوقت للنظر في البيانات نفسها. دعونا نرى كيف تبدو الصفوف الأولى (النقاط البيانية الأولى) من الـ `DataFrame`:\n" + "حان الوقت الآن لإلقاء نظرة على البيانات نفسها. دعونا نرى كيف تبدو الصفوف القليلة الأولى (النقاط البيانات الأولى) من الـ `DataFrame`:\n" ] }, { @@ -442,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "كما نرى هنا في المخرجات، هناك خمس (5) إدخالات من مجموعة البيانات. إذا نظرنا إلى الفهرس على اليسار، نجد أن هذه هي الصفوف الخمسة الأولى.\n" + "كما نرى في الناتج هنا، توجد خمس (5) إدخالات من مجموعة البيانات. إذا نظرنا إلى الفهرس على اليسار، نجد أن هذه هي أول خمس صفوف.\n" ] }, { @@ -476,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "طريقة أخرى لعرض البيانات يمكن أن تكون من النهاية (بدلاً من البداية). الجانب الآخر من `DataFrame.head` هو `DataFrame.tail`، الذي يعيد آخر خمس صفوف من `DataFrame`:\n" + "طريقة أخرى لعرض البيانات يمكن أن تكون من النهاية (بدلاً من البداية). الجانب الآخر لـ `DataFrame.head` هو `DataFrame.tail`، والذي يعرض آخر خمس صفوف من الـ `DataFrame`:\n" ] }, { @@ -583,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "في الممارسة العملية، من المفيد أن تكون قادرًا على فحص الصفوف الأولى أو الصفوف الأخيرة من `DataFrame` بسهولة، خاصة عندما تبحث عن القيم الشاذة في مجموعات البيانات المرتبة.\n", + "في الممارسة العملية، من المفيد أن تتمكن بسهولة من فحص الصفوف الأولى أو الصفوف الأخيرة من `DataFrame`، خاصةً عندما تبحث عن القيم الشاذة في مجموعات البيانات المرتبة.\n", "\n", - "جميع الوظائف والخصائص الموضحة أعلاه بمساعدة أمثلة الكود، تساعدنا في الحصول على نظرة عامة وشعور بالبيانات.\n", + "جميع الوظائف والخصائص التي تم عرضها أعلاه بمساعدة أمثلة الكود تساعدنا في الحصول على نظرة عامة وشعور بالبيانات.\n", "\n", - "> **الخلاصة:** حتى بمجرد النظر إلى البيانات الوصفية حول المعلومات في `DataFrame` أو القيم الأولى والأخيرة فيه، يمكنك الحصول على فكرة فورية عن حجم وشكل ومحتوى البيانات التي تتعامل معها.\n" + "> **الخلاصة:** حتى بمجرد النظر إلى البيانات الوصفية حول المعلومات في `DataFrame` أو القيم الأولى والأخيرة فيها، يمكنك الحصول على فكرة فورية عن حجم وشكل ومحتوى البيانات التي تتعامل معها.\n" ] }, { @@ -599,15 +598,15 @@ "### البيانات المفقودة\n", "دعونا نتعمق في موضوع البيانات المفقودة. تحدث البيانات المفقودة عندما لا يتم تخزين أي قيمة في بعض الأعمدة.\n", "\n", - "لنأخذ مثالاً: لنفترض أن شخصًا ما يهتم بوزنه ولم يقم بملء خانة الوزن في استبيان. في هذه الحالة، ستكون قيمة الوزن لهذا الشخص مفقودة.\n", + "لنأخذ مثالاً: لنفترض أن شخصًا ما يهتم بوزنه ولا يملأ خانة الوزن في استبيان. في هذه الحالة، ستكون قيمة الوزن لهذا الشخص مفقودة.\n", "\n", "في معظم الأحيان، تظهر القيم المفقودة في مجموعات البيانات الواقعية.\n", "\n", "**كيف يتعامل Pandas مع البيانات المفقودة**\n", "\n", - "يتعامل Pandas مع القيم المفقودة بطريقتين. الطريقة الأولى التي رأيتها سابقًا في الأقسام السابقة هي `NaN`، أو \"ليس رقمًا\". هذه في الواقع قيمة خاصة وهي جزء من مواصفات النقطة العائمة IEEE وتُستخدم فقط للإشارة إلى القيم المفقودة من النوع العائم.\n", + "يتعامل Pandas مع القيم المفقودة بطريقتين. الأولى التي رأيتها سابقًا في الأقسام السابقة هي: `NaN`، أو \"ليس رقمًا\". هذه في الواقع قيمة خاصة وهي جزء من مواصفات النقطة العائمة IEEE وتُستخدم فقط للإشارة إلى القيم المفقودة من النوع العائم.\n", "\n", - "بالنسبة للقيم المفقودة التي ليست من النوع العائم، يستخدم Pandas كائن Python `None`. قد يبدو الأمر مربكًا أنك ستواجه نوعين مختلفين من القيم التي تعبر عن نفس الشيء تقريبًا، ولكن هناك أسباب برمجية منطقية لهذا الاختيار التصميمي. عمليًا، هذا النهج يمكّن Pandas من تقديم حل وسط جيد في معظم الحالات. ومع ذلك، فإن كلا من `None` و `NaN` يحملان قيودًا يجب أن تكون على دراية بها فيما يتعلق بكيفية استخدامهما.\n" + "بالنسبة للقيم المفقودة التي ليست من النوع العائم، يستخدم Pandas كائن Python `None`. قد يبدو الأمر مربكًا أنك ستواجه نوعين مختلفين من القيم يشيران إلى نفس المعنى تقريبًا، ولكن هناك أسباب برمجية منطقية لهذا الاختيار التصميمي، وفي الواقع، هذا النهج يمكّن Pandas من تقديم حل وسط جيد في الغالبية العظمى من الحالات. ومع ذلك، فإن كلا من `None` و `NaN` يحملان قيودًا يجب أن تكون على دراية بها فيما يتعلق بكيفية استخدامهما.\n" ] }, { @@ -617,9 +616,9 @@ }, "source": [ "### `None`: البيانات المفقودة غير العائمة\n", - "بما أن `None` تأتي من Python، فلا يمكن استخدامها في مصفوفات NumPy وpandas التي ليست من نوع البيانات `'object'`. تذكر أن مصفوفات NumPy (وهياكل البيانات في pandas) يمكن أن تحتوي على نوع واحد فقط من البيانات. هذا ما يمنحها قوتها الهائلة للعمل مع البيانات واسعة النطاق والعمليات الحسابية، ولكنه أيضًا يحد من مرونتها. يجب على هذه المصفوفات أن تتحول إلى \"القاسم المشترك الأدنى\"، وهو نوع البيانات الذي يمكن أن يشمل كل شيء في المصفوفة. عندما تكون `None` في المصفوفة، فهذا يعني أنك تعمل مع كائنات Python.\n", + "نظرًا لأن `None` تأتي من Python، فلا يمكن استخدامها في مصفوفات NumPy وpandas التي ليست من نوع البيانات `'object'`. تذكر أن مصفوفات NumPy (والهياكل البيانية في pandas) يمكن أن تحتوي فقط على نوع واحد من البيانات. هذه الخاصية تمنحها قوة هائلة للعمل مع البيانات واسعة النطاق والعمليات الحسابية، لكنها أيضًا تحد من مرونتها. مثل هذه المصفوفات يجب أن تُرفع إلى \"القاسم المشترك الأدنى\"، وهو نوع البيانات الذي يشمل كل شيء في المصفوفة. عندما تكون `None` موجودة في المصفوفة، فهذا يعني أنك تعمل مع كائنات Python.\n", "\n", - "لرؤية ذلك عمليًا، انظر المثال التالي للمصفوفة (لاحظ `dtype` الخاص بها):\n" + "لرؤية ذلك عمليًا، انظر إلى المثال التالي للمصفوفة (لاحظ نوع البيانات `dtype` الخاص بها):\n" ] }, { @@ -658,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "واقع تحويل أنواع البيانات إلى أنواع أعلى يحمل معه تأثيرين جانبيين. أولاً، يتم تنفيذ العمليات على مستوى كود Python المفسر بدلاً من كود NumPy المُجمّع. بشكل أساسي، هذا يعني أن أي عمليات تتضمن `Series` أو `DataFrames` تحتوي على `None` ستكون أبطأ. على الرغم من أنك ربما لن تلاحظ هذا التأثير على الأداء، إلا أنه قد يصبح مشكلة مع مجموعات البيانات الكبيرة.\n", + "واقع تحويل أنواع البيانات إلى أنواع أعلى يحمل معه تأثيرين جانبيين. أولاً، يتم تنفيذ العمليات على مستوى كود Python المفسر بدلاً من كود NumPy المُجمع. بمعنى آخر، هذا يعني أن أي عمليات تتضمن `Series` أو `DataFrames` تحتوي على `None` ستكون أبطأ. وعلى الرغم من أنك قد لا تلاحظ هذا التأثير على الأداء، إلا أنه قد يصبح مشكلة مع مجموعات البيانات الكبيرة.\n", "\n", - "التأثير الجانبي الثاني ينبع من الأول. لأن `None` يعيد `Series` أو `DataFrame`s إلى عالم Python العادي، فإن استخدام التجميعات في NumPy/pandas مثل `sum()` أو `min()` على المصفوفات التي تحتوي على قيمة ``None`` سيؤدي عادةً إلى ظهور خطأ:\n" + "التأثير الجانبي الثاني ينبع من الأول. نظرًا لأن `None` يعيد `Series` أو `DataFrame`s إلى عالم Python العادي، فإن استخدام التجميعات مثل `sum()` أو `min()` في NumPy/pandas على المصفوفات التي تحتوي على قيمة ``None`` سيؤدي عادةً إلى ظهور خطأ:\n" ] }, { @@ -699,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**الفكرة الرئيسية**: الجمع (وغيره من العمليات) بين الأعداد الصحيحة وقيم `None` غير معرف، مما قد يحد من ما يمكنك القيام به مع مجموعات البيانات التي تحتوي عليها.\n" + "**المعلومة الرئيسية**: الجمع (وغيره من العمليات) بين الأعداد الصحيحة وقيم `None` غير معرف، مما قد يحد من ما يمكنك القيام به مع مجموعات البيانات التي تحتوي عليها.\n" ] }, { @@ -710,7 +709,7 @@ "source": [ "### `NaN`: القيم العائمة المفقودة\n", "\n", - "على عكس `None`، يدعم NumPy (وبالتالي pandas) استخدام `NaN` لعملياته السريعة والمتجهة والوظائف العامة. الخبر السيئ هو أن أي عملية حسابية تُجرى على `NaN` دائمًا ما تُنتج `NaN`. على سبيل المثال:\n" + "على عكس `None`, يدعم NumPy (وبالتالي pandas) استخدام `NaN` لعملياته السريعة والمتجهة ووظائف ufuncs. الخبر السيئ هو أن أي عملية حسابية تُجرى على `NaN` دائمًا ما تؤدي إلى `NaN`. على سبيل المثال:\n" ] }, { @@ -773,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "الخبر الجيد: التجميعات التي تعمل على المصفوفات التي تحتوي على `NaN` لا تُظهر أخطاء. الخبر السيئ: النتائج ليست مفيدة بشكل موحد:\n" + "الخبر الجيد: التجميعات التي تعمل على المصفوفات التي تحتوي على `NaN` لا تظهر أخطاء. الخبر السيئ: النتائج ليست مفيدة بشكل موحد:\n" ] }, { @@ -810,7 +809,7 @@ "id": "nhlnNJT7gRr_" }, "source": [ - "### تمرين:\n" + "### التمرين:\n" ] }, { @@ -832,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "تذكر: `NaN` هو فقط للقيم العائمة المفقودة؛ لا يوجد مكافئ لـ `NaN` للأعداد الصحيحة أو النصوص أو القيم المنطقية.\n" + "تذكر: `NaN` مخصص فقط للقيم العائمة المفقودة؛ لا يوجد مكافئ لـ `NaN` للأعداد الصحيحة أو النصوص أو القيم المنطقية.\n" ] }, { @@ -843,7 +842,7 @@ "source": [ "### `NaN` و `None`: القيم الفارغة في pandas\n", "\n", - "على الرغم من أن `NaN` و `None` يمكن أن يتصرفا بشكل مختلف إلى حد ما، إلا أن pandas مصمم للتعامل معهما بشكل متبادل. لفهم ما نعنيه، انظر إلى سلسلة `Series` من الأعداد الصحيحة:\n" + "على الرغم من أن `NaN` و `None` يمكن أن يتصرفا بشكل مختلف إلى حد ما، إلا أن pandas مصمم للتعامل معهما بشكل متبادل. لفهم ما نعنيه، انظر إلى سلسلة (`Series`) من الأعداد الصحيحة:\n" ] }, { @@ -883,7 +882,7 @@ "id": "WklCzqb8gRsB" }, "source": [ - "### تمرين:\n" + "### التمرين:\n" ] }, { @@ -907,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "في عملية ترقية أنواع البيانات لتحقيق التجانس في البيانات داخل `Series` و `DataFrame`s، يقوم pandas بسهولة بتبديل القيم المفقودة بين `None` و `NaN`. بسبب هذه الميزة التصميمية، يمكن أن يكون من المفيد التفكير في `None` و `NaN` كنوعين مختلفين من \"القيم الفارغة\" في pandas. في الواقع، بعض الطرق الأساسية التي ستستخدمها للتعامل مع القيم المفقودة في pandas تعكس هذه الفكرة في أسمائها:\n", + "أثناء عملية تحويل أنواع البيانات إلى أنواع أعلى لتحقيق تجانس البيانات في `Series` و `DataFrame`s، يقوم pandas بتبديل القيم المفقودة بين `None` و `NaN` بسهولة. بسبب هذه الخاصية التصميمية، يمكن أن يكون من المفيد التفكير في `None` و `NaN` كنوعين مختلفين من \"القيم الفارغة\" في pandas. في الواقع، بعض الطرق الأساسية التي ستستخدمها للتعامل مع القيم المفقودة في pandas تعكس هذه الفكرة في أسمائها:\n", "\n", "- `isnull()`: تُنتج قناعًا منطقيًا يشير إلى القيم المفقودة\n", "- `notnull()`: عكس `isnull()`\n", "- `dropna()`: تُرجع نسخة مفلترة من البيانات\n", - "- `fillna()`: تُرجع نسخة من البيانات مع تعبئة أو تقدير القيم المفقودة\n", + "- `fillna()`: تُرجع نسخة من البيانات مع القيم المفقودة مملوءة أو مُقدّرة\n", "\n", - "هذه طرق مهمة يجب إتقانها والشعور بالراحة عند استخدامها، لذا دعونا نستعرض كل واحدة منها بعمق.\n" + "هذه طرق مهمة يجب إتقانها والشعور بالراحة في استخدامها، لذا دعونا نستعرض كل واحدة منها بعمق.\n" ] }, { @@ -926,7 +925,7 @@ "### الكشف عن القيم الفارغة\n", "\n", "الآن بعد أن فهمنا أهمية القيم المفقودة، نحتاج إلى الكشف عنها في مجموعة البيانات الخاصة بنا قبل التعامل معها. \n", - "تُعد كل من `isnull()` و `notnull()` الطرق الأساسية للكشف عن البيانات الفارغة. كلاهما يعيد أقنعة منطقية (Boolean masks) على بياناتك.\n" + "تُعتبر كل من `isnull()` و `notnull()` الطرق الأساسية للكشف عن البيانات الفارغة. كلاهما يُرجع أقنعة بوليانية على بياناتك.\n" ] }, { @@ -979,9 +978,9 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "انظر عن كثب إلى النتائج. هل أي منها يفاجئك؟ بينما `0` هو قيمة فارغة حسابياً، إلا أنه مع ذلك عدد صحيح صالح تماماً و pandas يتعامل معه على هذا الأساس. أما `''` فهو أكثر دقة قليلاً. على الرغم من أننا استخدمناه في القسم الأول لتمثيل قيمة سلسلة فارغة، إلا أنه مع ذلك كائن سلسلة وليس تمثيلاً للقيمة الفارغة كما يراها pandas.\n", + "انظر عن كثب إلى النتيجة. هل هناك شيء يفاجئك؟ على الرغم من أن `0` يُعتبر قيمة فارغة حسابيًا، إلا أنه لا يزال عددًا صحيحًا جيدًا تمامًا، و pandas يتعامل معه على هذا الأساس. أما `''` فهو أكثر دقة قليلاً. على الرغم من أننا استخدمناه في القسم الأول لتمثيل قيمة سلسلة فارغة، إلا أنه لا يزال كائن سلسلة وليس تمثيلًا للقيمة الفارغة بالنسبة لـ pandas.\n", "\n", - "الآن، دعونا نعكس هذا ونستخدم هذه الطرق بطريقة أكثر شبهاً بكيفية استخدامها عملياً. يمكنك استخدام الأقنعة المنطقية مباشرة كمؤشر لـ ``Series`` أو ``DataFrame``، وهو أمر مفيد عند محاولة العمل مع القيم المفقودة (أو الموجودة) المعزولة.\n", + "الآن، دعونا نعكس هذا ونستخدم هذه الطرق بطريقة أكثر قربًا لما ستستخدمه في الممارسة العملية. يمكنك استخدام الأقنعة المنطقية مباشرة كمؤشر لـ ``Series`` أو ``DataFrame``، وهذا يمكن أن يكون مفيدًا عند محاولة العمل مع القيم المفقودة (أو الموجودة) المعزولة.\n", "\n", "إذا أردنا العدد الإجمالي للقيم المفقودة، يمكننا ببساطة إجراء عملية جمع على القناع الناتج عن طريقة `isnull()`.\n" ] @@ -1018,7 +1017,7 @@ "id": "PlBqEo3mgRsC" }, "source": [ - "### تمرين:\n" + "### التمرين:\n" ] }, { @@ -1041,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**الخلاصة الرئيسية**: كل من الطريقتين `isnull()` و `notnull()` تنتجان نتائج مشابهة عند استخدامهما في إطارات البيانات: تعرضان النتائج وفهرس تلك النتائج، مما سيساعدك بشكل كبير أثناء التعامل مع بياناتك.\n" + "**الخلاصة الرئيسية**: كل من الطريقتين `isnull()` و `notnull()` تنتجان نتائج مشابهة عند استخدامهما في إطارات البيانات: تظهر النتائج وفهرس تلك النتائج، مما سيساعدك بشكل كبير أثناء التعامل مع بياناتك.\n" ] }, { @@ -1052,18 +1051,18 @@ "source": [ "### التعامل مع البيانات المفقودة\n", "\n", - "> **الهدف التعليمي:** بنهاية هذا القسم، يجب أن تكون قادرًا على معرفة كيفية ومتى يتم استبدال أو إزالة القيم الفارغة من DataFrames.\n", + "> **هدف التعلم:** بنهاية هذا القسم، يجب أن تكون قادرًا على معرفة كيفية ومتى يتم استبدال أو إزالة القيم الفارغة من DataFrames.\n", "\n", - "لا يمكن لنماذج التعلم الآلي التعامل مع البيانات المفقودة بنفسها. لذلك، قبل تمرير البيانات إلى النموذج، نحتاج إلى معالجة هذه القيم المفقودة.\n", + "نماذج التعلم الآلي لا تستطيع التعامل مع البيانات المفقودة بنفسها. لذا، قبل تمرير البيانات إلى النموذج، يجب أن نتعامل مع هذه القيم المفقودة.\n", "\n", - "طريقة التعامل مع البيانات المفقودة تحمل معها توازنات دقيقة، ويمكن أن تؤثر على تحليلك النهائي ونتائجك في العالم الحقيقي.\n", + "كيفية التعامل مع البيانات المفقودة تحمل معها توازنات دقيقة، ويمكن أن تؤثر على تحليلك النهائي ونتائجك في العالم الحقيقي.\n", "\n", "هناك طريقتان رئيسيتان للتعامل مع البيانات المفقودة:\n", "\n", "1. حذف الصف الذي يحتوي على القيمة المفقودة \n", "2. استبدال القيمة المفقودة بقيمة أخرى \n", "\n", - "سنناقش كلتا الطريقتين ومزاياهما وعيوبهما بالتفصيل.\n" + "سنناقش كلا الطريقتين ومزاياهما وعيوبهما بالتفصيل.\n" ] }, { @@ -1076,9 +1075,9 @@ "\n", "كمية البيانات التي نقدمها لنموذجنا تؤثر بشكل مباشر على أدائه. إسقاط القيم الفارغة يعني أننا نقلل عدد نقاط البيانات، وبالتالي نقلل حجم مجموعة البيانات. لذلك، يُنصح بإسقاط الصفوف التي تحتوي على قيم فارغة عندما تكون مجموعة البيانات كبيرة جدًا.\n", "\n", - "حالة أخرى قد تكون أن صفًا معينًا أو عمودًا يحتوي على الكثير من القيم المفقودة. في هذه الحالة، يمكن إسقاطها لأنها لن تضيف قيمة كبيرة لتحليلنا حيث أن معظم البيانات مفقودة لهذا الصف/العمود.\n", + "قد يكون هناك حالة أخرى حيث يحتوي صف معين أو عمود معين على الكثير من القيم المفقودة. في هذه الحالة، يمكن إسقاطها لأنها لن تضيف قيمة كبيرة لتحليلنا حيث أن معظم البيانات مفقودة لهذا الصف/العمود.\n", "\n", - "إلى جانب تحديد القيم المفقودة، توفر مكتبة pandas وسيلة مريحة لإزالة القيم الفارغة من `Series` و`DataFrame`s. لرؤية ذلك عمليًا، دعونا نعود إلى `example3`. وظيفة `DataFrame.dropna()` تساعد في إسقاط الصفوف التي تحتوي على قيم فارغة.\n" + "إلى جانب تحديد القيم المفقودة، توفر مكتبة pandas وسيلة مريحة لإزالة القيم الفارغة من `Series` و `DataFrame`s. لرؤية ذلك عمليًا، دعونا نعود إلى `example3`. وظيفة `DataFrame.dropna()` تساعد في إسقاط الصفوف التي تحتوي على قيم فارغة.\n" ] }, { @@ -1117,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "لاحظ أن هذا يجب أن يبدو مثل ناتج `example3[example3.notnull()]`. الفرق هنا هو أنه بدلاً من الفهرسة فقط على القيم المفلترة، قامت `dropna` بإزالة تلك القيم المفقودة من الـ `Series` `example3`.\n", + "لاحظ أن هذا يجب أن يبدو مثل الناتج من `example3[example3.notnull()]`. الفرق هنا هو أنه بدلاً من الفهرسة فقط على القيم المموهة، فإن `dropna` قد أزال تلك القيم المفقودة من الـ `Series` `example3`.\n", "\n", - "نظرًا لأن DataFrames لها بُعدين، فإنها توفر المزيد من الخيارات لحذف البيانات.\n" + "نظرًا لأن الـ DataFrames لها بعدان، فإنها توفر خيارات أكثر لإزالة البيانات.\n" ] }, { @@ -1209,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "هل لاحظت أن pandas قامت بترقية نوعين من الأعمدة إلى أرقام عشرية لتستوعب القيم `NaN`؟\n", + "(هل لاحظت أن pandas قام بتحويل نوعين من الأعمدة إلى أرقام عشرية لتناسب القيم `NaN`؟)\n", "\n", - "لا يمكنك حذف قيمة واحدة فقط من `DataFrame`، لذا عليك حذف صفوف أو أعمدة كاملة. بناءً على ما تقوم به، قد ترغب في اختيار أحد الخيارين، ولهذا السبب توفر pandas خيارات لكليهما. نظرًا لأن الأعمدة في علم البيانات تمثل عادةً المتغيرات والصفوف تمثل الملاحظات، فمن المرجح أن تقوم بحذف صفوف البيانات؛ الإعداد الافتراضي لـ `dropna()` هو حذف جميع الصفوف التي تحتوي على أي قيم فارغة:\n" + "لا يمكنك حذف قيمة واحدة فقط من `DataFrame`، لذا عليك حذف صفوف أو أعمدة كاملة. بناءً على ما تقوم به، قد ترغب في اختيار أحد الخيارين، ولهذا يوفر pandas خيارات لكلاهما. نظرًا لأن الأعمدة في علم البيانات تمثل عادةً المتغيرات والصفوف تمثل الملاحظات، فمن المرجح أن تقوم بحذف صفوف البيانات؛ الإعداد الافتراضي لـ `dropna()` هو حذف جميع الصفوف التي تحتوي على أي قيم فارغة:\n" ] }, { @@ -1284,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "إذا لزم الأمر، يمكنك إزالة القيم NA من الأعمدة. استخدم `axis=1` للقيام بذلك:\n" + "إذا لزم الأمر، يمكنك حذف القيم NA من الأعمدة. استخدم `axis=1` للقيام بذلك:\n" ] }, { @@ -1363,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "لاحظ أن هذا قد يؤدي إلى فقدان الكثير من البيانات التي قد ترغب في الاحتفاظ بها، خاصة في مجموعات البيانات الصغيرة. ماذا لو كنت تريد فقط حذف الصفوف أو الأعمدة التي تحتوي على عدة قيم فارغة أو حتى جميعها؟ يمكنك تحديد هذه الإعدادات في `dropna` باستخدام المعاملين `how` و `thresh`.\n", + "لاحظ أن هذا يمكن أن يؤدي إلى فقدان الكثير من البيانات التي قد ترغب في الاحتفاظ بها، خاصة في مجموعات البيانات الصغيرة. ماذا لو كنت تريد فقط حذف الصفوف أو الأعمدة التي تحتوي على عدد كبير أو حتى جميع القيم الفارغة؟ يمكنك تحديد هذه الإعدادات في `dropna` باستخدام المعاملين `how` و `thresh`.\n", "\n", - "بشكل افتراضي، يكون `how='any'` (إذا كنت ترغب في التحقق بنفسك أو رؤية المعاملات الأخرى التي تحتوي عليها الطريقة، قم بتشغيل `example4.dropna?` في خلية كود). يمكنك بدلاً من ذلك تحديد `how='all'` لحذف الصفوف أو الأعمدة التي تحتوي فقط على قيم فارغة بالكامل. دعنا نوسع مثالنا على `DataFrame` لرؤية ذلك عمليًا في التمرين التالي.\n" + "بشكل افتراضي، `how='any'` (إذا كنت ترغب في التحقق بنفسك أو رؤية المعاملات الأخرى التي تحتوي عليها الطريقة، قم بتشغيل `example4.dropna?` في خلية كود). يمكنك بدلاً من ذلك تحديد `how='all'` لحذف الصفوف أو الأعمدة التي تحتوي فقط على جميع القيم الفارغة. دعنا نوسع مثالنا `DataFrame` لنرى ذلك عمليًا في التمرين التالي.\n" ] }, { @@ -1458,10 +1457,10 @@ }, "source": [ "> النقاط الرئيسية:\n", - "1. حذف القيم الفارغة فكرة جيدة فقط إذا كانت مجموعة البيانات كبيرة بما يكفي.\n", + "1. حذف القيم الفارغة فكرة جيدة فقط إذا كان حجم مجموعة البيانات كبيرًا بما يكفي.\n", "2. يمكن حذف الصفوف أو الأعمدة بالكامل إذا كانت معظم بياناتها مفقودة.\n", "3. تساعد طريقة `DataFrame.dropna(axis=)` في حذف القيم الفارغة. يشير الوسيط `axis` إلى ما إذا كان سيتم حذف الصفوف أو الأعمدة.\n", - "4. يمكن استخدام الوسيط `how` أيضًا. يتم ضبطه افتراضيًا على `any`. لذلك، يتم حذف الصفوف/الأعمدة التي تحتوي على أي قيم فارغة فقط. يمكن ضبطه على `all` لتحديد أننا سنحذف فقط الصفوف/الأعمدة التي تكون جميع قيمها فارغة.\n" + "4. يمكن أيضًا استخدام الوسيط `how`. يتم تعيينه افتراضيًا إلى `any`. وبالتالي، يتم حذف الصفوف/الأعمدة التي تحتوي على أي قيم فارغة فقط. يمكن تعيينه إلى `all` لتحديد أننا سنحذف فقط الصفوف/الأعمدة التي تكون جميع قيمها فارغة.\n" ] }, { @@ -1470,7 +1469,7 @@ "id": "oXXSfQFHgRsF" }, "source": [ - "### تمرين:\n" + "### التمرين:\n" ] }, { @@ -1568,7 +1567,7 @@ "id": "fmSFnzZegRsG" }, "source": [ - "هنا، تم حذف الصف الأول والأخير، لأنه يحتوي فقط على قيمتين غير فارغتين.\n" + "هنا، تم حذف الصف الأول والأخير، لأنهما يحتويان فقط على قيمتين غير فارغتين.\n" ] }, { @@ -1581,7 +1580,7 @@ "\n", "في بعض الأحيان يكون من المنطقي ملء القيم المفقودة بأخرى قد تكون صالحة. هناك بعض التقنيات لملء القيم الفارغة. الأولى هي استخدام المعرفة بالمجال (المعرفة بالموضوع الذي يعتمد عليه مجموعة البيانات) لتقدير القيم المفقودة بطريقة ما.\n", "\n", - "يمكنك استخدام `isnull` للقيام بذلك مباشرة، ولكن قد يكون ذلك مرهقًا، خاصة إذا كان لديك الكثير من القيم لملئها. نظرًا لأن هذه مهمة شائعة جدًا في علم البيانات، يوفر pandas الدالة `fillna`، التي تعيد نسخة من `Series` أو `DataFrame` مع استبدال القيم المفقودة بالقيم التي تختارها. لنقم بإنشاء مثال آخر لـ `Series` لنرى كيف يعمل هذا عمليًا.\n" + "يمكنك استخدام `isnull` للقيام بذلك مباشرة، ولكن قد يكون ذلك مرهقًا، خاصة إذا كان لديك الكثير من القيم التي تحتاج إلى ملء. نظرًا لأن هذه مهمة شائعة جدًا في علم البيانات، يوفر pandas الدالة `fillna`، التي تُرجع نسخة من `Series` أو `DataFrame` مع استبدال القيم المفقودة بالقيمة التي تختارها. دعونا ننشئ مثالًا آخر لـ `Series` لنرى كيف يعمل هذا عمليًا.\n" ] }, { @@ -1591,9 +1590,9 @@ }, "source": [ "### البيانات الفئوية (غير الرقمية)\n", - "لنبدأ أولاً بالنظر إلى البيانات غير الرقمية. في مجموعات البيانات، لدينا أعمدة تحتوي على بيانات فئوية. على سبيل المثال: الجنس، صحيح أو خطأ، وما إلى ذلك.\n", + "أولاً، دعونا نأخذ بعين الاعتبار البيانات غير الرقمية. في مجموعات البيانات، لدينا أعمدة تحتوي على بيانات فئوية. على سبيل المثال: الجنس، صحيح أو خطأ، إلخ.\n", "\n", - "في معظم هذه الحالات، نستبدل القيم المفقودة بـ `الوضع` (mode) الخاص بالعمود. لنفترض أن لدينا 100 نقطة بيانات، 90 منها أشارت إلى \"صحيح\"، و8 أشارت إلى \"خطأ\"، و2 لم يتم تعبئتها. في هذه الحالة، يمكننا ملء القيمتين المفقودتين بـ \"صحيح\"، مع الأخذ بعين الاعتبار العمود بأكمله.\n", + "في معظم هذه الحالات، نستبدل القيم المفقودة بـ `الوضع` (mode) الخاص بالعمود. على سبيل المثال، إذا كان لدينا 100 نقطة بيانات، و90 منها قالت صحيح، و8 قالت خطأ، و2 لم تُملأ. في هذه الحالة، يمكننا ملء القيمتين المفقودتين بـ \"صحيح\"، مع الأخذ في الاعتبار العمود بأكمله.\n", "\n", "مرة أخرى، يمكننا استخدام المعرفة بالمجال هنا. دعونا نأخذ مثالاً على ملء القيم باستخدام الوضع.\n" ] @@ -1700,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "الآن، دعونا أولاً نجد المنوال قبل ملء القيمة `None` بالمنوال.\n" + ] }, { "cell_type": "code", @@ -1735,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "لذلك، سنستبدل None بـ True\n" + ] }, { "cell_type": "code", @@ -1854,17 +1857,17 @@ "id": "heYe1I0dOmQ_" }, "source": [ - "### البيانات الرقمية \n", - "الآن، ننتقل إلى البيانات الرقمية. هنا لدينا طريقتان شائعتان لاستبدال القيم المفقودة: \n", + "### البيانات الرقمية\n", + "الآن، ننتقل إلى البيانات الرقمية. هنا لدينا طريقتان شائعتان لاستبدال القيم المفقودة:\n", "\n", - "1. الاستبدال بوسيط الصف \n", - "2. الاستبدال بمتوسط الصف \n", + "1. الاستبدال بالوسيط الخاص بالصف\n", + "2. الاستبدال بالمتوسط الخاص بالصف\n", "\n", - "نستبدل بالوسيط في حالة البيانات المنحرفة التي تحتوي على قيم شاذة. السبب هو أن الوسيط مقاوم للقيم الشاذة. \n", + "نقوم بالاستبدال بالوسيط في حالة البيانات المنحرفة التي تحتوي على قيم شاذة. وذلك لأن الوسيط مقاوم للقيم الشاذة.\n", "\n", - "عندما تكون البيانات مُطَبَّعة، يمكننا استخدام المتوسط، لأنه في هذه الحالة، سيكون المتوسط والوسيط قريبين جدًا من بعضهما البعض. \n", + "أما عندما تكون البيانات مُطَبَّعة (normalized)، يمكننا استخدام المتوسط، حيث في هذه الحالة يكون المتوسط والوسيط قريبين جدًا من بعضهما البعض.\n", "\n", - "أولاً، دعونا نأخذ عمودًا موزعًا بشكل طبيعي ونملأ القيمة المفقودة بمتوسط العمود. \n" + "أولاً، دعونا نأخذ عمودًا موزعًا بشكل طبيعي ونملأ القيم المفقودة بمتوسط العمود.\n" ] }, { @@ -2004,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "التعبئة بالمتوسط\n" + ] }, { "cell_type": "code", @@ -2113,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "الآن دعونا نجرب إطار بيانات آخر، وهذه المرة سنستبدل القيم None بالوسيط الخاص بالعمود.\n" + "الآن دعونا نجرب إطار بيانات آخر، وهذه المرة سنستبدل القيم None بمتوسط العمود.\n" ] }, { @@ -2355,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "كما نرى، تم استبدال قيمة NaN بالوسيط الخاص بالعمود\n" + "كما نرى، تم استبدال قيمة NaN بالوسيط الخاص بالعمود.\n" ] }, { @@ -2439,10 +2444,10 @@ }, "source": [ "> النقاط الرئيسية:\n", - "1. يجب تعبئة القيم المفقودة عندما يكون هناك بيانات قليلة أو عندما تكون هناك استراتيجية لتعبئة البيانات المفقودة.\n", - "2. يمكن استخدام المعرفة بالمجال لتعبئة القيم المفقودة عن طريق تقديرها.\n", + "1. يجب ملء القيم المفقودة عندما يكون هناك بيانات قليلة أو عندما تكون هناك استراتيجية لملء البيانات المفقودة.\n", + "2. يمكن استخدام المعرفة بالمجال لتقدير القيم المفقودة وملئها.\n", "3. بالنسبة للبيانات الفئوية، غالبًا ما يتم استبدال القيم المفقودة بالنمط الخاص بالعمود.\n", - "4. بالنسبة للبيانات الرقمية، عادةً ما يتم تعبئة القيم المفقودة بالمتوسط (للمجموعات البيانات المُطَبَّعة) أو الوسيط الخاص بالأعمدة.\n" + "4. بالنسبة للبيانات الرقمية، عادةً ما يتم ملء القيم المفقودة بمتوسط العمود (للمجموعات المعيارية) أو الوسيط.\n" ] }, { @@ -2451,7 +2456,7 @@ "id": "FI9MmqFJgRsH" }, "source": [ - "### تمرين:\n" + "### التمرين:\n" ] }, { @@ -2473,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "يمكنك **ملء القيم الفارغة** باستخدام آخر قيمة صالحة لملء القيمة الفارغة:\n" + "يمكنك **ملء القيم الفارغة بالتقدم**، وهو استخدام آخر قيمة صالحة لملء القيمة الفارغة:\n" ] }, { @@ -2514,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "يمكنك أيضًا **الملء العكسي** لنشر القيمة الصالحة التالية للخلف لملء قيمة فارغة:\n" + "يمكنك أيضًا **الملء الخلفي** لنشر القيمة الصالحة التالية إلى الخلف لملء قيمة فارغة:\n" ] }, { @@ -2556,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "كما قد تخمن، يعمل هذا بنفس الطريقة مع DataFrames، ولكن يمكنك أيضًا تحديد `axis` لملء القيم الفارغة على طوله:\n" + "كما قد تخمن، يعمل هذا بنفس الطريقة مع إطارات البيانات، ولكن يمكنك أيضًا تحديد `axis` الذي يتم على أساسه ملء القيم الفارغة:\n" ] }, { @@ -2729,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "لاحظ أنه عندما لا تكون هناك قيمة سابقة متاحة للتعبئة الأمامية، تظل القيمة الفارغة كما هي.\n" + "لاحظ أنه عندما لا تكون هناك قيمة سابقة متاحة للتعبئة الأمامية، تبقى القيمة الفارغة.\n" ] }, { @@ -2738,7 +2743,7 @@ "id": "eeAoOU0RgRsJ" }, "source": [ - "### تمرين:\n" + "### التمرين:\n" ] }, { @@ -2762,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "يمكنك أن تكون مبدعًا في كيفية استخدام `fillna`. على سبيل المثال، دعنا نلقي نظرة على `example4` مرة أخرى، ولكن هذه المرة دعنا نملأ القيم المفقودة بمتوسط جميع القيم في الـ `DataFrame`:\n" + "يمكنك أن تكون مبدعًا في كيفية استخدام `fillna`. على سبيل المثال، دعنا ننظر إلى `example4` مرة أخرى، ولكن هذه المرة دعنا نملأ القيم المفقودة بمتوسط جميع القيم في `DataFrame`:\n" ] }, { @@ -2866,9 +2871,9 @@ "source": [ "### ترميز البيانات الفئوية\n", "\n", - "نماذج التعلم الآلي تتعامل فقط مع الأرقام وأي شكل من أشكال البيانات الرقمية. فهي لن تكون قادرة على التمييز بين \"نعم\" و\"لا\"، لكنها ستتمكن من التمييز بين 0 و1. لذلك، بعد ملء القيم المفقودة، نحتاج إلى ترميز البيانات الفئوية إلى شكل رقمي لكي يتمكن النموذج من فهمها.\n", + "نماذج التعلم الآلي تتعامل فقط مع الأرقام وأي شكل من أشكال البيانات الرقمية. فهي لن تكون قادرة على التمييز بين \"نعم\" و \"لا\"، لكنها ستتمكن من التمييز بين 0 و 1. لذلك، بعد ملء القيم المفقودة، نحتاج إلى ترميز البيانات الفئوية إلى شكل رقمي لكي يتمكن النموذج من فهمها.\n", "\n", - "يمكن إجراء الترميز بطريقتين. سنناقشهما في القسم التالي.\n" + "يمكن إجراء الترميز بطريقتين. سنناقشهما لاحقًا.\n" ] }, { @@ -2879,7 +2884,7 @@ "source": [ "**ترميز التصنيفات**\n", "\n", - "ترميز التصنيفات يعني بشكل أساسي تحويل كل فئة إلى رقم. على سبيل المثال، لنفترض أن لدينا مجموعة بيانات لركاب الطيران وهناك عمود يحتوي على فئاتهم من بين ['درجة رجال الأعمال', 'الدرجة الاقتصادية', 'الدرجة الأولى']. إذا تم تطبيق ترميز التصنيفات على هذا العمود، فسيتم تحويله إلى [0,1,2]. دعونا نرى مثالاً عبر الكود. بما أننا سنتعلم استخدام `scikit-learn` في الدفاتر القادمة، فلن نستخدمه هنا.\n" + "ترميز التصنيفات يعني بشكل أساسي تحويل كل فئة إلى رقم. على سبيل المثال، لنفترض أن لدينا مجموعة بيانات لركاب الطيران وهناك عمود يحتوي على فئاتهم من بين ['درجة رجال الأعمال', 'الدرجة الاقتصادية', 'الدرجة الأولى']. إذا تم تطبيق ترميز التصنيفات على هذا، فسيتم تحويله إلى [0,1,2]. دعونا نرى مثالاً عبر الكود. بما أننا سنتعلم استخدام `scikit-learn` في الدفاتر القادمة، فلن نستخدمه هنا.\n" ] }, { @@ -2987,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "لإجراء ترميز التصنيفات على العمود الأول، يجب أولاً وصف خريطة من كل فئة إلى رقم، قبل الاستبدال\n" + "لإجراء ترميز التصنيفات على العمود الأول، يجب أولاً وصف عملية الربط بين كل فئة ورقم، قبل الاستبدال.\n" ] }, { @@ -3089,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "كما نرى، النتيجة تطابق ما توقعنا حدوثه. إذن، متى نستخدم ترميز التصنيفات؟ يتم استخدام ترميز التصنيفات في إحدى أو كلتا الحالتين التاليتين:\n", - "1. عندما يكون عدد الفئات كبيرًا\n", - "2. عندما تكون الفئات مرتبة.\n" + "كما نرى، النتيجة تتطابق مع ما توقعنا حدوثه. إذن، متى نستخدم ترميز التصنيفات؟ يُستخدم ترميز التصنيفات في إحدى الحالتين أو كلتيهما: \n", + "1. عندما يكون عدد الفئات كبيرًا \n", + "2. عندما تكون الفئات مرتبة. \n" ] }, { @@ -3100,11 +3105,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**الترميز الأحادي (One Hot Encoding)**\n", + "**الترميز الواحد (One Hot Encoding)**\n", "\n", - "نوع آخر من الترميز هو الترميز الأحادي. في هذا النوع من الترميز، يتم إضافة كل فئة من العمود كعمود منفصل، وكل نقطة بيانات تحصل على 0 أو 1 بناءً على ما إذا كانت تحتوي على تلك الفئة أم لا. لذلك، إذا كان هناك n فئة مختلفة، سيتم إضافة n عمود إلى إطار البيانات.\n", + "نوع آخر من الترميز هو الترميز الواحد. في هذا النوع من الترميز، يتم إضافة كل فئة من العمود كعمود منفصل، ويحصل كل نقطة بيانات على 0 أو 1 بناءً على ما إذا كانت تحتوي على تلك الفئة أم لا. لذلك، إذا كانت هناك n فئات مختلفة، سيتم إضافة n أعمدة إلى إطار البيانات.\n", "\n", - "على سبيل المثال، لنأخذ نفس مثال فئات الطائرة. كانت الفئات: ['درجة رجال الأعمال', 'الدرجة الاقتصادية', 'الدرجة الأولى']. لذا، إذا قمنا بتنفيذ الترميز الأحادي، سيتم إضافة الأعمدة الثلاثة التالية إلى مجموعة البيانات: ['class_business class', 'class_economy class', 'class_first class'].\n" + "على سبيل المثال، دعونا نأخذ نفس مثال فئات الطائرة. كانت الفئات: ['درجة رجال الأعمال', 'الدرجة الاقتصادية', 'الدرجة الأولى']. لذا، إذا قمنا بتطبيق الترميز الواحد، سيتم إضافة الأعمدة الثلاثة التالية إلى مجموعة البيانات: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3212,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "دعنا نقوم بترميز العمود الأول بطريقة التشفير الواحد\n" + "دعنا نقوم بترميز العمود الأول باستخدام الترميز الأحادي\n" ] }, { @@ -3337,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "كل عمود مشفر بطريقة التشفير الواحد يحتوي على 0 أو 1، مما يحدد ما إذا كانت تلك الفئة موجودة لذلك النقطة البيانية.\n" + "كل عمود مشفر بطريقة \"واحد ساخن\" يحتوي على 0 أو 1، مما يحدد ما إذا كانت تلك الفئة موجودة لذلك النقطة البيانية.\n" ] }, { @@ -3346,11 +3351,10 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "متى نستخدم الترميز الواحد (One Hot Encoding)؟ \n", - "يُستخدم الترميز الواحد في إحدى أو كلتا الحالتين التاليتين:\n", + "متى نستخدم الترميز الواحد؟ يُستخدم الترميز الواحد في إحدى الحالتين أو كلتيهما:\n", "\n", - "1. عندما يكون عدد الفئات وحجم مجموعة البيانات صغيرًا. \n", - "2. عندما لا تتبع الفئات ترتيبًا معينًا. \n" + "1. عندما يكون عدد الفئات وحجم مجموعة البيانات صغيرًا.\n", + "2. عندما لا تتبع الفئات أي ترتيب معين.\n" ] }, { @@ -3359,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> النقاط الرئيسية: \n", - "1. يتم استخدام الترميز لتحويل البيانات غير الرقمية إلى بيانات رقمية. \n", - "2. هناك نوعان من الترميز: الترميز بالملصقات والترميز بالواحد الساخن، وكلاهما يمكن تنفيذه بناءً على متطلبات مجموعة البيانات. \n" + "> النقاط الرئيسية:\n", + "1. يتم استخدام الترميز لتحويل البيانات غير الرقمية إلى بيانات رقمية.\n", + "2. هناك نوعان من الترميز: الترميز بالملصقات والترميز بالواحد الساخن، وكلاهما يمكن تنفيذه بناءً على متطلبات مجموعة البيانات.\n" ] }, { @@ -3372,7 +3376,7 @@ "source": [ "## إزالة البيانات المكررة\n", "\n", - "> **هدف التعلم:** بنهاية هذا القسم الفرعي، يجب أن تكون قادرًا على التعرف على القيم المكررة وإزالتها من DataFrames.\n", + "> **هدف التعلم:** بنهاية هذا القسم الفرعي، يجب أن تكون قادرًا على التعرف على القيم المكررة وإزالتها من DataFrames بسهولة.\n", "\n", "بالإضافة إلى البيانات المفقودة، ستواجه غالبًا بيانات مكررة في مجموعات البيانات الواقعية. لحسن الحظ، توفر pandas وسيلة سهلة لاكتشاف وإزالة الإدخالات المكررة.\n" ] @@ -3385,7 +3389,7 @@ "source": [ "### التعرف على القيم المكررة: `duplicated`\n", "\n", - "يمكنك بسهولة تحديد القيم المكررة باستخدام طريقة `duplicated` في pandas، والتي تُرجع قناعًا منطقيًا يشير إلى ما إذا كان إدخال في `DataFrame` مكررًا لإدخال سابق. دعنا ننشئ مثالًا آخر لـ `DataFrame` لنرى ذلك عمليًا.\n" + "يمكنك بسهولة تحديد القيم المكررة باستخدام طريقة `duplicated` في pandas، والتي تُرجع قناعًا منطقيًا يشير إلى ما إذا كانت إحدى الإدخالات في `DataFrame` مكررة لإدخال سابق. لنقم بإنشاء مثال آخر لـ `DataFrame` لنرى ذلك عمليًا.\n" ] }, { @@ -3515,7 +3519,7 @@ }, "source": [ "### إزالة التكرارات: `drop_duplicates`\n", - "`drop_duplicates` يعيد ببساطة نسخة من البيانات حيث تكون جميع القيم التي تم تحديدها كـ `duplicated` هي `False`:\n" + "`drop_duplicates` ببساطة يعيد نسخة من البيانات حيث تكون جميع القيم التي تم تحديدها كـ `duplicated` هي `False`:\n" ] }, { @@ -3675,14 +3679,530 @@ "id": "GvX4og1EgRsL" }, "source": [ - "> **الخلاصة:** إزالة البيانات المكررة جزء أساسي من كل مشروع علم بيانات تقريبًا. يمكن أن تؤدي البيانات المكررة إلى تغيير نتائج تحليلاتك وتقديم نتائج غير دقيقة!\n" + "> **الخلاصة:** إزالة البيانات المكررة جزء أساسي من كل مشروع علم بيانات تقريبًا. يمكن أن تؤثر البيانات المكررة على نتائج تحليلاتك وتمنحك نتائج غير دقيقة!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## فحوصات جودة البيانات في العالم الحقيقي\n", + "\n", + "> **هدف التعلم:** بنهاية هذا القسم، يجب أن تكون قادرًا على اكتشاف وتصحيح مشكلات جودة البيانات الشائعة في العالم الحقيقي، بما في ذلك القيم الفئوية غير المتسقة، القيم الرقمية غير الطبيعية (الشواذ)، والكيانات المكررة مع اختلافات.\n", + "\n", + "بينما تُعتبر القيم المفقودة والنسخ المكررة الدقيقة مشكلات شائعة، تحتوي مجموعات البيانات في العالم الحقيقي غالبًا على مشكلات أكثر دقة:\n", + "\n", + "1. **القيم الفئوية غير المتسقة**: نفس الفئة مكتوبة بطرق مختلفة (مثل \"USA\"، \"U.S.A\"، \"United States\").\n", + "2. **القيم الرقمية غير الطبيعية**: شواذ متطرفة تشير إلى أخطاء في إدخال البيانات (مثل العمر = 999).\n", + "3. **الصفوف شبه المكررة**: سجلات تمثل نفس الكيان مع اختلافات طفيفة.\n", + "\n", + "دعونا نستكشف تقنيات لاكتشاف هذه المشكلات ومعالجتها.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### إنشاء مجموعة بيانات \"غير نظيفة\" كمثال\n", + "\n", + "أولاً، دعونا ننشئ مجموعة بيانات تحتوي على أنواع المشكلات التي نواجهها عادةً في البيانات الواقعية:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. اكتشاف القيم الفئوية غير المتسقة\n", + "\n", + "لاحظ أن عمود `country` يحتوي على تمثيلات متعددة لنفس البلدان. دعونا نحدد هذه التناقضات:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### توحيد القيم الفئوية\n", + "\n", + "يمكننا إنشاء خريطة لتوحيد هذه القيم. نهج بسيط هو تحويل النصوص إلى أحرف صغيرة وإنشاء قاموس خريطة:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**بديل: استخدام المطابقة الغامضة**\n", + "\n", + "في الحالات الأكثر تعقيدًا، يمكننا استخدام مطابقة النصوص الغامضة مع مكتبة `rapidfuzz` لاكتشاف النصوص المتشابهة تلقائيًا:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. الكشف عن القيم الرقمية غير الطبيعية (الشواذ)\n", + "\n", + "بالنظر إلى عمود `age`، لدينا بعض القيم المشبوهة مثل 199 و -5. دعونا نستخدم الطرق الإحصائية للكشف عن هذه القيم الشاذة.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### استخدام طريقة IQR (النطاق الربعي)\n", + "\n", + "طريقة IQR هي تقنية إحصائية قوية للكشف عن القيم الشاذة، وهي أقل حساسية للقيم المتطرفة:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### استخدام طريقة Z-Score\n", + "\n", + "تحدد طريقة Z-Score القيم الشاذة بناءً على الانحرافات المعيارية عن المتوسط:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### التعامل مع القيم الشاذة\n", + "\n", + "بمجرد اكتشافها، يمكن التعامل مع القيم الشاذة بعدة طرق:\n", + "1. **الإزالة**: حذف الصفوف التي تحتوي على قيم شاذة (إذا كانت أخطاء)\n", + "2. **التحديد**: استبدالها بالقيم الحدودية\n", + "3. **الاستبدال بـ NaN**: اعتبارها بيانات مفقودة واستخدام تقنيات التعويض\n", + "4. **الإبقاء عليها**: إذا كانت قيم متطرفة مشروعة\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. اكتشاف الصفوف المتشابهة جدًا\n", + "\n", + "لاحظ أن مجموعة البيانات لدينا تحتوي على عدة إدخالات لـ \"John Smith\" مع قيم مختلفة قليلاً. دعونا نحدد التكرارات المحتملة بناءً على تشابه الأسماء.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### العثور على النسخ المتشابهة باستخدام المطابقة الغامضة\n", + "\n", + "للكشف عن النسخ المتشابهة بشكل أكثر تطورًا، يمكننا استخدام المطابقة الغامضة للعثور على أسماء متشابهة:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### التعامل مع التكرارات\n", + "\n", + "بمجرد تحديدها، تحتاج إلى اتخاذ قرار بشأن كيفية التعامل مع التكرارات:\n", + "1. **الاحتفاظ بالظهور الأول**: استخدم `drop_duplicates(keep='first')`\n", + "2. **الاحتفاظ بالظهور الأخير**: استخدم `drop_duplicates(keep='last')`\n", + "3. **تجميع المعلومات**: دمج المعلومات من الصفوف المكررة\n", + "4. **المراجعة اليدوية**: وضع علامة للمراجعة البشرية\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### الملخص: إنشاء خط أنابيب شامل لتنظيف البيانات\n", + "\n", + "لنقم بتجميع كل شيء في خط أنابيب شامل لتنظيف البيانات:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 تمرين التحدي\n", + "\n", + "الآن دورك! أدناه يوجد صف جديد من البيانات يحتوي على عدة مشاكل في الجودة. هل يمكنك:\n", + "\n", + "1. تحديد جميع المشاكل في هذا الصف\n", + "2. كتابة الكود لتنظيف كل مشكلة\n", + "3. إضافة الصف المنظف إلى مجموعة البيانات\n", + "\n", + "إليك البيانات التي تحتوي على المشاكل:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### النقاط الرئيسية\n", + "\n", + "1. **الفئات غير المتسقة** شائعة في البيانات الواقعية. تحقق دائمًا من القيم الفريدة وقم بتوحيدها باستخدام الخرائط أو المطابقة الغامضة.\n", + "\n", + "2. **القيم الشاذة** يمكن أن تؤثر بشكل كبير على تحليلك. استخدم المعرفة بالمجال مع الطرق الإحصائية (IQR، Z-score) لاكتشافها.\n", + "\n", + "3. **القيم شبه المكررة** أصعب في الكشف من القيم المكررة تمامًا. فكر في استخدام المطابقة الغامضة وتطبيع البيانات (تحويلها إلى أحرف صغيرة، إزالة المسافات الزائدة) لتحديدها.\n", + "\n", + "4. **تنظيف البيانات عملية تكرارية**. قد تحتاج إلى تطبيق تقنيات متعددة ومراجعة النتائج قبل الانتهاء من مجموعة البيانات النظيفة.\n", + "\n", + "5. **وثّق قراراتك**. احتفظ بسجل للخطوات التي طبقتها أثناء التنظيف وأسبابها، حيث إن ذلك مهم لإعادة الإنتاج والشفافية.\n", + "\n", + "> **أفضل ممارسة:** احتفظ دائمًا بنسخة من بياناتك \"الخام\" الأصلية. لا تقم أبدًا بالكتابة فوق ملفات بيانات المصدر - أنشئ نسخًا نظيفة بأسماء واضحة مثل `data_cleaned.csv`.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**إخلاء المسؤولية**: \nتم ترجمة هذا المستند باستخدام خدمة الترجمة بالذكاء الاصطناعي [Co-op Translator](https://github.com/Azure/co-op-translator). بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو معلومات غير دقيقة. يجب اعتبار المستند الأصلي بلغته الأصلية المصدر الموثوق. للحصول على معلومات حاسمة، يُوصى بالاستعانة بترجمة بشرية احترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة ناتجة عن استخدام هذه الترجمة.\n" + "\n---\n\n**إخلاء المسؤولية**: \nتم ترجمة هذا المستند باستخدام خدمة الترجمة بالذكاء الاصطناعي [Co-op Translator](https://github.com/Azure/co-op-translator). بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو عدم دقة. يجب اعتبار المستند الأصلي بلغته الأصلية المصدر الرسمي. للحصول على معلومات حاسمة، يُوصى بالترجمة البشرية الاحترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة ناتجة عن استخدام هذه الترجمة.\n" ] } ], @@ -3710,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:15:36+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:05:43+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "ar" } diff --git a/translations/bg/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/bg/2-Working-With-Data/08-data-preparation/notebook.ipynb index 813fb8e7..612e6f13 100644 --- a/translations/bg/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/bg/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# Подготовка на данни\n", "\n", - "[Оригинален източник на тетрадката от *Data Science: Въведение в машинното обучение за наука за данни Python и Machine Learning Studio от Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Оригинален източник на ноутбука от *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## Изследване на информацията в `DataFrame`\n", "\n", - "> **Цел на обучението:** До края на тази подсекция трябва да се чувствате уверени в намирането на обща информация за данните, съхранявани в pandas DataFrames.\n", + "> **Цел на обучението:** До края на този подраздел трябва да сте уверени в намирането на обща информация за данните, съхранявани в pandas DataFrames.\n", "\n", - "След като заредите данните си в pandas, най-вероятно те ще бъдат в `DataFrame`. Но ако наборът от данни във вашия `DataFrame` съдържа 60,000 реда и 400 колони, как изобщо да започнете да разбирате с какво работите? За щастие, pandas предоставя удобни инструменти, които позволяват бърз преглед на общата информация за `DataFrame`, както и на първите и последните няколко реда.\n", + "След като заредите данните си в pandas, най-вероятно те ще бъдат в `DataFrame`. Но ако наборът от данни във вашия `DataFrame` има 60,000 реда и 400 колони, как изобщо да започнете да разбирате с какво работите? За щастие, pandas предоставя удобни инструменти за бързо разглеждане на общата информация за `DataFrame`, както и за първите и последните няколко реда.\n", "\n", - "За да изследваме тази функционалност, ще импортираме библиотеката scikit-learn за Python и ще използваме емблематичен набор от данни, който всеки специалист по данни е виждал стотици пъти: набора от данни *Iris* на британския биолог Роналд Фишър, използван в неговата статия от 1936 г. \"Използването на множество измервания в таксономични проблеми\":\n" + "За да изследваме тази функционалност, ще импортираме библиотеката Python scikit-learn и ще използваме емблематичен набор от данни, който всеки специалист по данни е виждал стотици пъти: набора от данни *Iris* на британския биолог Роналд Фишър, използван в неговата статия от 1936 г. \"Използването на множество измервания в таксономични проблеми\":\n" ] }, { @@ -78,7 +78,7 @@ "id": "smE7AGzOhxk2" }, "source": [ - "И така, имаме 150 реда и 4 колони с данни. Всеки ред представлява една точка от данни, а всяка колона представлява една характеристика, свързана с рамката на данните. Така че, на практика, има 150 точки от данни, всяка съдържаща 4 характеристики.\n", + "И така, имаме 150 реда и 4 колони данни. Всеки ред представлява една точка от данни, а всяка колона представлява една характеристика, свързана с рамката на данните. Така че, основно, има 150 точки от данни, всяка съдържаща 4 характеристики.\n", "\n", "`shape` тук е атрибут на рамката на данните, а не функция, поради което не завършва с чифт скоби.\n" ] @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Нека сега разгледаме 4-те колони от данни. Какво точно представлява всяка от тях? Атрибутът `columns` ще ни даде имената на колоните в dataframe.\n" + "Нека сега разгледаме четирите колони с данни. Какво точно представлява всяка от тях? Атрибутът `columns` ще ни даде имената на колоните в dataframe.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Както виждаме, има четири (4) колони. Атрибутът `columns` ни казва имената на колоните и основно нищо друго. Този атрибут придобива значение, когато искаме да идентифицираме характеристиките, които един набор от данни съдържа.\n" + "Както виждаме, има четири (4) колони. Атрибутът `columns` ни казва имената на колоните и основно нищо друго. Този атрибут придобива значение, когато искаме да идентифицираме характеристиките, които съдържа даден набор от данни.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Количеството данни (определено от атрибута `shape`) и имената на характеристиките или колоните (определени от атрибута `columns`) ни дават известна информация за набора от данни. Сега бихме искали да се задълбочим повече в набора от данни. Функцията `DataFrame.info()` е доста полезна за това.\n" + "Количеството данни (посочено от атрибута `shape`) и имената на характеристиките или колоните (посочени от атрибута `columns`) ни дават известна информация за набора от данни. Сега бихме искали да се задълбочим в анализа на набора от данни. Функцията `DataFrame.info()` е доста полезна за тази цел.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Оттук можем да направим няколко наблюдения: \n", - "1. Типът данни на всяка колона: В този набор от данни, цялата информация е съхранена като 64-битови числа с плаваща запетая. \n", - "2. Брой на ненулевите стойности: Работата с нулеви стойности е важна стъпка в подготовката на данните. Това ще бъде разгледано по-късно в тетрадката. \n" + "Оттук можем да направим няколко наблюдения:\n", + "1. Типът данни на всяка колона: В този набор от данни всички стойности са съхранени като 64-битови числа с плаваща запетая.\n", + "2. Брой ненулеви стойности: Работата с нулеви стойности е важна стъпка в подготовката на данните. Това ще бъде разгледано по-късно в тетрадката.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Да предположим, че имаме много числови данни в нашия набор от данни. Едновариантни статистически изчисления като средна стойност, медиана, квартилни стойности и т.н. могат да се извършват за всяка от колоните поотделно. Функцията `DataFrame.describe()` ни предоставя статистическо обобщение на числовите колони в набора от данни.\n" + "Да предположим, че имаме много числови данни в нашия набор от данни. Едновариантни статистически изчисления като средна стойност, медиана, квартили и т.н. могат да бъдат направени за всяка от колоните поотделно. Функцията `DataFrame.describe()` ни предоставя статистическо обобщение на числовите колони в набора от данни.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "Изходът по-горе показва общия брой точки данни, средната стойност, стандартното отклонение, минималната стойност, долния квартил (25%), медианата (50%), горния квартил (75%) и максималната стойност на всяка колона.\n" + "Горният изход показва общия брой точки данни, средната стойност, стандартното отклонение, минималната стойност, долния квартил (25%), медианата (50%), горния квартил (75%) и максималната стойност на всяка колона.\n" ] }, { @@ -334,7 +334,7 @@ "### `DataFrame.head`\n", "С всички гореспоменати функции и атрибути, вече имаме обща представа за набора от данни. Знаем колко точки данни има, колко характеристики има, типа данни на всяка характеристика и броя на ненулевите стойности за всяка характеристика.\n", "\n", - "Сега е време да разгледаме самите данни. Нека видим как изглеждат първите няколко реда (първите няколко точки данни) на нашия `DataFrame`:\n" + "Сега е време да разгледаме самите данни. Нека видим как изглеждат първите няколко реда (първите няколко точки данни) от нашия `DataFrame`:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Като изход тук можем да видим пет (5) записа от набора данни. Ако погледнем индекса отляво, откриваме, че това са първите пет реда.\n" + "Както е показано тук, можем да видим пет (5) записа от набора от данни. Ако погледнем индекса отляво, откриваме, че това са първите пет реда.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Упражнение:\n", "\n", - "От дадения пример по-горе е ясно, че по подразбиране `DataFrame.head` връща първите пет реда на `DataFrame`. В кода по-долу, можете ли да намерите начин да покажете повече от пет реда?\n" + "От дадения пример по-горе е ясно, че по подразбиране `DataFrame.head` връща първите пет реда на `DataFrame`. В клетката с код по-долу, можете ли да намерите начин да покажете повече от пет реда?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Друг начин за разглеждане на данните е от края (вместо от началото). Обратното на `DataFrame.head` е `DataFrame.tail`, който връща последните пет реда на `DataFrame`:\n" + "Друг начин за разглеждане на данните е от края (вместо от началото). Обратното на `DataFrame.head` е `DataFrame.tail`, който връща последните пет реда от `DataFrame`:\n" ] }, { @@ -584,9 +584,9 @@ "source": [ "На практика е полезно да можете лесно да разгледате първите няколко реда или последните няколко реда на `DataFrame`, особено когато търсите отклонения в подредени набори от данни.\n", "\n", - "Всички функции и атрибути, показани по-горе с помощта на примери с код, ни помагат да получим представа за данните.\n", + "Всички функции и атрибути, показани по-горе с помощта на примери с код, ни помагат да добием представа за данните.\n", "\n", - "> **Основен извод:** Дори само като разгледате метаданните за информацията в един DataFrame или първите и последните няколко стойности в него, можете веднага да получите представа за размера, формата и съдържанието на данните, с които работите.\n" + "> **Основен извод:** Дори само като разгледате метаданните за информацията в един DataFrame или първите и последните няколко стойности в него, можете веднага да добиете представа за размера, формата и съдържанието на данните, с които работите.\n" ] }, { @@ -598,15 +598,15 @@ "### Липсващи данни\n", "Нека разгледаме липсващите данни. Липсващи данни се появяват, когато няма стойност, записана в някои от колоните.\n", "\n", - "Нека вземем пример: да кажем, че някой е загрижен за теглото си и не попълва полето за тегло в анкета. Тогава стойността за тегло за този човек ще липсва.\n", + "Нека вземем пример: да кажем, че някой е чувствителен относно теглото си и не попълва полето за тегло в анкета. Тогава стойността за тегло на този човек ще липсва.\n", "\n", - "В повечето случаи, в реалните набори от данни, се срещат липсващи стойности.\n", + "В повечето случаи, в реални набори от данни, се срещат липсващи стойности.\n", "\n", "**Как Pandas обработва липсващи данни**\n", "\n", - "Pandas обработва липсващите стойности по два начина. Първият, който вече сте виждали в предишни секции, е `NaN`, или Not a Number. Това всъщност е специална стойност, която е част от IEEE спецификацията за числа с плаваща запетая и се използва само за обозначаване на липсващи стойности от тип плаваща запетая.\n", + "Pandas обработва липсващите стойности по два начина. Първият, който сте виждали в предишни раздели, е `NaN`, или Not a Number. Това всъщност е специална стойност, която е част от спецификацията на IEEE за плаваща запетая и се използва само за обозначаване на липсващи стойности от тип плаваща запетая.\n", "\n", - "За липсващи стойности, различни от числа с плаваща запетая, pandas използва Python обекта `None`. Въпреки че може да изглежда объркващо, че ще срещнете два различни типа стойности, които по същество означават едно и също, има основателни програмни причини за този избор на дизайн и, на практика, този подход позволява на pandas да предложи добро решение за по-голямата част от случаите. Независимо от това, както `None`, така и `NaN` имат ограничения, за които трябва да сте наясно по отношение на начина, по който могат да бъдат използвани.\n" + "За липсващи стойности, различни от числа с плаваща запетая, pandas използва Python обекта `None`. Макар че може да изглежда объркващо, че ще срещнете два различни типа стойности, които по същество означават едно и също, има основателни програмни причини за този избор на дизайн и, на практика, този подход позволява на pandas да предложи добро решение за огромното мнозинство от случаи. Въпреки това, както `None`, така и `NaN` имат ограничения, които трябва да имате предвид относно начина, по който могат да бъдат използвани.\n" ] }, { @@ -615,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: липсващи данни, които не са числа с плаваща запетая\n", - "Тъй като `None` идва от Python, той не може да се използва в масиви на NumPy и pandas, които не са от тип данни `'object'`. Запомнете, масивите на NumPy (и структурите от данни в pandas) могат да съдържат само един тип данни. Това е причината за тяхната огромна мощност при работа с големи обеми данни и изчисления, но също така ограничава тяхната гъвкавост. Такива масиви трябва да се преобразуват към „най-ниския общ знаменател“, типа данни, който може да обхване всичко в масива. Когато `None` е в масива, това означава, че работите с Python обекти.\n", + "### `None`: липсващи данни, които не са от тип float\n", + "Тъй като `None` идва от Python, той не може да се използва в масиви на NumPy и pandas, които не са от тип данни `'object'`. Запомнете, че масивите на NumPy (и структурите от данни в pandas) могат да съдържат само един тип данни. Това им дава огромна мощност за работа с големи обеми данни и изчисления, но също така ограничава тяхната гъвкавост. Такива масиви трябва да се преобразуват към „най-ниския общ знаменател“, типа данни, който може да обхване всичко в масива. Когато `None` е в масива, това означава, че работите с Python обекти.\n", "\n", - "За да видите това в действие, разгледайте следния пример за масив (обърнете внимание на `dtype` за него):\n" + "За да видите това на практика, разгледайте следния примерен масив (обърнете внимание на `dtype` за него):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Реалността на повишените типове данни носи със себе си два странични ефекта. Първо, операциите ще се изпълняват на нивото на интерпретиран Python код, а не на компилиран NumPy код. По същество това означава, че всякакви операции, включващи `Series` или `DataFrames` с `None` в тях, ще бъдат по-бавни. Макар че вероятно няма да забележите този спад в производителността, при големи набори от данни това може да се превърне в проблем.\n", + "Реалността на повишените типове данни носи със себе си два странични ефекта. Първо, операциите ще се изпълняват на нивото на интерпретиран Python код, а не на компилиран NumPy код. По същество това означава, че всякакви операции, включващи `Series` или `DataFrames`, които съдържат `None`, ще бъдат по-бавни. Макар че вероятно няма да забележите този спад в производителността, при големи набори от данни това може да се превърне в проблем.\n", "\n", - "Вторият страничен ефект произтича от първия. Тъй като `None` по същество връща `Series` или `DataFrame`s обратно в света на обикновения Python, използването на NumPy/pandas агрегиращи функции като `sum()` или `min()` върху масиви, които съдържат стойност ``None``, обикновено ще доведе до грешка:\n" + "Вторият страничен ефект произтича от първия. Тъй като `None` на практика връща `Series` или `DataFrame` обратно в света на стандартния Python, използването на агрегации от NumPy/pandas като `sum()` или `min()` върху масиви, които съдържат стойност ``None``, обикновено ще доведе до грешка:\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Добрата новина: агрегациите, изпълнявани върху масиви с `NaN`, не предизвикват грешки. Лошата новина: резултатите не са еднакво полезни:\n" + "Добрата новина: агрегатите, изпълнявани върху масиви с `NaN` в тях, не предизвикват грешки. Лошата новина: резултатите не са еднакво полезни:\n" ] }, { @@ -842,7 +842,7 @@ "source": [ "### `NaN` и `None`: нулеви стойности в pandas\n", "\n", - "Въпреки че `NaN` и `None` могат да се държат по малко различен начин, pandas е създаден така, че да ги обработва взаимозаменяемо. За да разберете какво имаме предвид, разгледайте един `Series` от цели числа:\n" + "Въпреки че `NaN` и `None` могат да се държат малко различно, pandas е създаден така, че да ги обработва взаимозаменяемо. За да разберете какво имаме предвид, разгледайте един `Series` от цели числа:\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "В процеса на преобразуване на типовете данни за установяване на хомогенност на данните в `Series` и `DataFrame`, pandas лесно превключва липсващите стойности между `None` и `NaN`. Поради тази особеност на дизайна, може да бъде полезно да мислите за `None` и `NaN` като два различни вида \"null\" в pandas. Всъщност, някои от основните методи, които ще използвате за работа с липсващи стойности в pandas, отразяват тази идея в техните имена:\n", + "В процеса на преобразуване на типове данни с цел установяване на хомогенност на данните в `Series` и `DataFrame`, pandas лесно превключва липсващите стойности между `None` и `NaN`. Поради тази особеност на дизайна, може да бъде полезно да мислим за `None` и `NaN` като два различни вида \"null\" в pandas. Всъщност, някои от основните методи, които ще използвате за работа с липсващи стойности в pandas, отразяват тази идея в своите имена:\n", "\n", "- `isnull()`: Генерира булева маска, която показва липсващите стойности\n", "- `notnull()`: Обратното на `isnull()`\n", "- `dropna()`: Връща филтрирана версия на данните\n", - "- `fillna()`: Връща копие на данните с попълнени или изчислени липсващи стойности\n", + "- `fillna()`: Връща копие на данните с попълнени или импутирани липсващи стойности\n", "\n", - "Това са важни методи, които трябва да овладеете и с които да се чувствате уверени, затова нека разгледаме всеки от тях по-подробно.\n" + "Това са важни методи, които трябва да овладеете и да се чувствате комфортно с тях, затова нека ги разгледаме по-подробно.\n" ] }, { @@ -924,8 +924,8 @@ "source": [ "### Откриване на null стойности\n", "\n", - "След като разбрахме значението на липсващите стойности, трябва да ги открием в нашия набор от данни, преди да се справим с тях. \n", - "И `isnull()`, и `notnull()` са основните ви методи за откриване на null данни. И двата връщат булеви маски върху вашите данни.\n" + "След като разбрахме значението на липсващите стойности, трябва да ги открием в нашия набор от данни, преди да се справим с тях. \n", + "И двете функции `isnull()` и `notnull()` са основните методи за откриване на null данни. И двете връщат булеви маски върху вашите данни.\n" ] }, { @@ -978,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Погледнете внимателно резултата. Нещо от него изненадва ли ви? Докато `0` е аритметична нула, той все пак е напълно валидно цяло число и pandas го третира като такова. `''` е малко по-деликатен случай. Докато го използвахме в Раздел 1, за да представим празна стойност на низ, той все пак е обект от тип низ и не е представяне на null според pandas.\n", + "Вгледайте се внимателно в резултата. Има ли нещо, което ви изненадва? Макар че `0` е аритметичен нулев елемент, той все пак е напълно валидно цяло число и pandas го третира като такова. `''` е малко по-деликатен случай. Докато го използвахме в Раздел 1, за да представим стойност на празен низ, той все пак е обект от тип низ и не е представяне на null според pandas.\n", "\n", - "Сега, нека обърнем това и използваме тези методи по начин, който е по-близък до реалната практика. Можете да използвате булеви маски директно като индекс на ``Series`` или ``DataFrame``, което може да бъде полезно, когато се опитвате да работите с изолирани липсващи (или налични) стойности.\n", + "Сега, нека обърнем ситуацията и използваме тези методи по начин, който е по-близък до практическата им употреба. Можете да използвате булеви маски директно като индекс на ``Series`` или ``DataFrame``, което може да бъде полезно, когато се опитвате да работите с изолирани липсващи (или налични) стойности.\n", "\n", - "Ако искаме общия брой на липсващите стойности, можем просто да направим сума върху маската, произведена от метода `isnull()`.\n" + "Ако искаме общия брой липсващи стойности, можем просто да направим сума върху маската, произведена от метода `isnull()`.\n" ] }, { @@ -1040,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Основен извод**: И двата метода `isnull()` и `notnull()` дават сходни резултати, когато ги използвате в DataFrames: те показват резултатите и индекса на тези резултати, което ще ви помогне значително, докато работите с вашите данни.\n" + "**Основен извод**: И двата метода `isnull()` и `notnull()` дават подобни резултати, когато ги използвате в DataFrames: те показват резултатите и индекса на тези резултати, което ще ви помогне значително, докато работите с вашите данни.\n" ] }, { @@ -1051,16 +1051,16 @@ "source": [ "### Работа с липсващи данни\n", "\n", - "> **Цел на обучението:** До края на този подраздел трябва да знаете как и кога да заменяте или премахвате липсващи стойности от DataFrames.\n", + "> **Цел на обучението:** До края на този подраздел трябва да знаете как и кога да заменяте или премахвате null стойности от DataFrames.\n", "\n", - "Моделите за машинно обучение не могат сами да се справят с липсващи данни. Затова, преди да подадем данните в модела, трябва да се справим с тези липсващи стойности.\n", + "Моделите за машинно обучение не могат сами да се справят с липсващи данни. Затова, преди да подадем данните към модела, трябва да се справим с тези липсващи стойности.\n", "\n", - "Начинът, по който се обработват липсващите данни, носи със себе си фини компромиси и може да повлияе на вашия краен анализ и реалните резултати.\n", + "Начинът, по който се обработват липсващите данни, носи със себе си фини компромиси и може да повлияе на крайния анализ и реалните резултати.\n", "\n", - "Основно има два начина за справяне с липсващи данни:\n", + "Има основно два начина за справяне с липсващи данни:\n", "\n", - "1. Премахване на реда, съдържащ липсващата стойност \n", - "2. Замяна на липсващата стойност с някаква друга стойност \n", + "1. Премахване на реда, съдържащ липсващата стойност\n", + "2. Замяна на липсващата стойност с друга стойност\n", "\n", "Ще обсъдим и двата метода, както и техните предимства и недостатъци в детайли.\n" ] @@ -1071,13 +1071,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### Премахване на липсващи стойности\n", + "### Премахване на празни стойности\n", "\n", - "Количеството данни, които подаваме към нашия модел, има пряко влияние върху неговата производителност. Премахването на липсващи стойности означава, че намаляваме броя на данните, а следователно и размера на набора от данни. Затова е препоръчително да се премахват редове с липсващи стойности, когато наборът от данни е доста голям.\n", + "Количеството данни, които предоставяме на нашия модел, има пряко влияние върху неговата производителност. Премахването на празни стойности означава, че намаляваме броя на точките с данни и съответно намаляваме размера на набора от данни. Затова е препоръчително да се премахват редове с празни стойности, когато наборът от данни е доста голям.\n", "\n", - "Друг случай може да бъде, когато определен ред или колона съдържа много липсващи стойности. Тогава те могат да бъдат премахнати, защото няма да добавят особена стойност към нашия анализ, тъй като по-голямата част от данните за този ред/колона липсват.\n", + "Друг случай може да бъде, когато определен ред или колона има много липсващи стойности. Тогава те могат да бъдат премахнати, защото няма да добавят голяма стойност към нашия анализ, тъй като повечето данни за този ред/колона липсват.\n", "\n", - "Освен идентифицирането на липсващи стойности, pandas предоставя удобен начин за премахване на липсващи стойности от `Series` и `DataFrame`. За да видим това в действие, нека се върнем към `example3`. Функцията `DataFrame.dropna()` помага за премахването на редовете с липсващи стойности.\n" + "Освен идентифицирането на липсващи стойности, pandas предоставя удобен начин за премахване на празни стойности от `Series` и `DataFrame`. За да видим това в действие, нека се върнем към `example3`. Функцията `DataFrame.dropna()` помага за премахването на редовете с празни стойности.\n" ] }, { @@ -1116,7 +1116,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "Имайте предвид, че това трябва да изглежда като вашия изход от `example3[example3.notnull()]`. Разликата тук е, че вместо просто да индексира маскираните стойности, `dropna` е премахнал тези липсващи стойности от `Series` `example3`.\n", + "Обърнете внимание, че това трябва да изглежда като вашия изход от `example3[example3.notnull()]`. Разликата тук е, че вместо просто да индексира маскираните стойности, `dropna` е премахнал тези липсващи стойности от `Series` `example3`.\n", "\n", "Тъй като DataFrames имат две измерения, те предоставят повече опции за премахване на данни.\n" ] @@ -1210,7 +1210,7 @@ "source": [ "(Забелязахте ли, че pandas преобразува две от колоните в числа с плаваща запетая, за да се справи с `NaN`?)\n", "\n", - "Не можете да премахнете единична стойност от `DataFrame`, затова трябва да премахнете цели редове или колони. В зависимост от това, което правите, може да искате да изберете едното или другото, и затова pandas ви предоставя опции за двете. Тъй като в науката за данни колоните обикновено представляват променливи, а редовете представляват наблюдения, по-вероятно е да премахнете редове от данни; стандартната настройка за `dropna()` е да премахне всички редове, които съдържат някакви празни стойности:\n" + "Не можете да премахнете единична стойност от `DataFrame`, така че трябва да премахнете цели редове или колони. В зависимост от това какво правите, може да искате да изберете едното или другото, и затова pandas ви предоставя опции за двете. Тъй като в науката за данни колоните обикновено представляват променливи, а редовете представляват наблюдения, по-вероятно е да премахнете редове от данни; стандартната настройка за `dropna()` е да премахне всички редове, които съдържат някакви празни стойности:\n" ] }, { @@ -1362,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Имайте предвид, че това може да премахне много данни, които може да искате да запазите, особено в по-малки набори от данни. Ами ако искате просто да премахнете редове или колони, които съдържат няколко или дори всички null стойности? Можете да зададете тези настройки в `dropna` с параметрите `how` и `thresh`.\n", + "Обърнете внимание, че това може да премахне много данни, които може да искате да запазите, особено при по-малки набори от данни. Ами ако искате да премахнете само редове или колони, които съдържат няколко или дори всички null стойности? Можете да зададете тези настройки в `dropna` с параметрите `how` и `thresh`.\n", "\n", - "По подразбиране, `how='any'` (ако искате да проверите сами или да видите какви други параметри има методът, изпълнете `example4.dropna?` в кодова клетка). Можете алтернативно да зададете `how='all'`, за да премахнете само редове или колони, които съдържат всички null стойности. Нека разширим нашия примерен `DataFrame`, за да видим това в действие в следващото упражнение.\n" + "По подразбиране, `how='any'` (ако искате да проверите сами или да видите какви други параметри има методът, изпълнете `example4.dropna?` в кодова клетка). Можете също така да зададете `how='all'`, за да премахнете само редове или колони, които съдържат всички null стойности. Нека разширим нашия примерен `DataFrame`, за да видим това в действие в следващото упражнение.\n" ] }, { @@ -1456,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> Основни изводи: \n", - "1. Премахването на null стойности е добра идея само ако наборът от данни е достатъчно голям. \n", - "2. Цели редове или колони могат да бъдат премахнати, ако по-голямата част от данните в тях липсват. \n", - "3. Методът `DataFrame.dropna(axis=)` помага за премахването на null стойности. Аргументът `axis` указва дали да се премахват редове или колони. \n", - "4. Аргументът `how` също може да се използва. По подразбиране е зададен на `any`. Така се премахват само тези редове/колони, които съдържат поне една null стойност. Може да се зададе на `all`, за да се уточни, че ще премахваме само тези редове/колони, където всички стойности са null. \n" + "> Основни моменти:\n", + "1. Премахването на празни стойности е добра идея само ако наборът от данни е достатъчно голям.\n", + "2. Цели редове или колони могат да бъдат премахнати, ако повечето от данните в тях липсват.\n", + "3. Методът `DataFrame.dropna(axis=)` помага за премахването на празни стойности. Аргументът `axis` указва дали да се премахват редове или колони.\n", + "4. Аргументът `how` също може да се използва. По подразбиране е зададен на `any`. Така се премахват само тези редове/колони, които съдържат някакви празни стойности. Може да бъде зададен на `all`, за да се уточни, че ще премахваме само тези редове/колони, където всички стойности са празни.\n" ] }, { @@ -1578,9 +1578,9 @@ "source": [ "### Попълване на липсващи стойности\n", "\n", - "Понякога има смисъл да се попълнят липсващите стойности с такива, които биха могли да бъдат валидни. Съществуват няколко техники за попълване на липсващи стойности. Първата е използването на Домейн Знания (познания за темата, върху която е базиран набора от данни), за да се направи някаква приблизителна оценка на липсващите стойности.\n", + "Понякога има смисъл да се попълнят липсващите стойности с такива, които биха могли да бъдат валидни. Съществуват няколко техники за попълване на null стойности. Първата е използването на Домейн Знания (знания за темата, върху която е базиран набора от данни), за да се направи приблизителна оценка на липсващите стойности.\n", "\n", - "Можете да използвате `isnull`, за да направите това директно, но това може да бъде трудоемко, особено ако имате много стойности за попълване. Тъй като това е толкова често срещана задача в науката за данни, pandas предоставя `fillna`, който връща копие на `Series` или `DataFrame` с липсващите стойности, заменени с избрани от вас. Нека създадем друг пример за `Series`, за да видим как това работи на практика.\n" + "Можете да използвате `isnull`, за да направите това директно, но това може да бъде трудоемко, особено ако имате много стойности за попълване. Тъй като това е толкова често срещана задача в анализа на данни, pandas предоставя `fillna`, който връща копие на `Series` или `DataFrame` с липсващите стойности, заменени с избрани от вас. Нека създадем друг пример за `Series`, за да видим как това работи на практика.\n" ] }, { @@ -1589,12 +1589,12 @@ "id": "CE8S7louLezV" }, "source": [ - "### Категориални данни (Ненумерични)\n", - "Първо нека разгледаме ненумерични данни. В наборите от данни имаме колони с категориални данни. Например, Пол, Вярно или Невярно и т.н.\n", + "### Категорични данни (Ненумерични)\n", + "Първо нека разгледаме ненумерични данни. В наборите от данни имаме колони с категорични данни, например Пол, Вярно или Невярно и т.н.\n", "\n", - "В повечето от тези случаи заместваме липсващите стойности с `модата` на колоната. Да кажем, че имаме 100 точки с данни, като 90 са посочили Вярно, 8 са посочили Невярно, а 2 не са попълнени. Тогава можем да попълним тези 2 с Вярно, като разгледаме цялата колона.\n", + "В повечето от тези случаи заменяме липсващите стойности с `мода` на колоната. Да кажем, че имаме 100 точки данни, като 90 са посочили Вярно, 8 са посочили Невярно, а 2 не са попълнени. Тогава можем да попълним тези 2 с Вярно, като разгледаме цялата колона.\n", "\n", - "Отново, тук можем да използваме и познания за домейна. Нека разгледаме пример за попълване с модата.\n" + "Отново, тук можем да използваме знания за конкретната област. Нека разгледаме пример за попълване с модата.\n" ] }, { @@ -1699,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Сега, нека първо намерим модата, преди да запълним стойността `None` с модата.\n" + ] }, { "cell_type": "code", @@ -1734,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "И така, ще заменим None с True\n" + ] }, { "cell_type": "code", @@ -1844,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Както виждаме, нулевата стойност беше заменена. Разбира се, можехме да напишем каквото и да е вместо `'True'` и то щеше да бъде заместено.\n" + "Както виждаме, нулевата стойност е заменена. Без съмнение, можехме да напишем каквото и да е вместо `'True'` и то щеше да бъде заместено.\n" ] }, { @@ -1854,16 +1858,16 @@ }, "source": [ "### Числови данни\n", - "Сега, нека преминем към числовите данни. Тук имаме два често използвани начина за заместване на липсващи стойности:\n", + "Сега, нека разгледаме числовите данни. Тук имаме два често срещани начина за заместване на липсващи стойности:\n", "\n", "1. Замяна с медианата на реда\n", "2. Замяна със средната стойност на реда\n", "\n", - "Замяната с медиана се използва в случай на изкривени данни с отклонения. Това е така, защото медианата е устойчива на отклонения.\n", + "Заместваме с медианата, когато данните са изкривени и съдържат отклонения. Това е така, защото медианата е устойчива на отклонения.\n", "\n", "Когато данните са нормализирани, можем да използваме средната стойност, тъй като в този случай средната стойност и медианата ще бъдат доста близки.\n", "\n", - "Нека първо вземем колона, която е нормално разпределена, и да запълним липсващите стойности със средната стойност на колоната.\n" + "Първо, нека вземем колона, която е нормално разпределена, и да запълним липсващите стойности със средната стойност на колоната.\n" ] }, { @@ -2003,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Попълване със средна стойност\n" + ] }, { "cell_type": "code", @@ -2252,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Запълване с медиана\n" + ] }, { "cell_type": "code", @@ -2394,7 +2402,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "Можете да попълните всички празни записи с една стойност, като например `0`:\n" + "Можете да попълните всички празни записи с една стойност, например `0`:\n" ] }, { @@ -2435,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Основни изводи: \n", - "1. Попълването на липсващи стойности трябва да се извършва, когато има малко данни или когато има стратегия за попълване на липсващите данни. \n", - "2. Домейн знанията могат да се използват за попълване на липсващи стойности чрез тяхното приблизително изчисляване. \n", - "3. За категорийни данни липсващите стойности най-често се заместват с модата на колоната. \n", - "4. За числови данни липсващите стойности обикновено се попълват със средната стойност (за нормализирани набори от данни) или с медианата на колоните. \n" + "> Основни изводи:\n", + "1. Попълването на липсващи стойности трябва да се извършва, когато има малко данни или когато има стратегия за попълване на липсващите данни.\n", + "2. Домейн знанията могат да се използват за попълване на липсващи стойности чрез тяхното приблизително изчисляване.\n", + "3. При категорийни данни липсващите стойности най-често се заменят с модата на колоната.\n", + "4. При числови данни липсващите стойности обикновено се попълват със средната стойност (за нормализирани набори от данни) или с медианата на колоните.\n" ] }, { @@ -2470,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "Можете **да попълните напред** null стойности, като използвате последната валидна стойност, за да попълните null:\n" + "Можете да **запълните напред** null стойностите, като използвате последната валидна стойност за запълване на null:\n" ] }, { @@ -2511,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Можете също така **да попълните обратно**, за да разпространите следващата валидна стойност назад и да запълните null:\n" + "Можете също така **да попълните назад**, за да разпространите следващата валидна стойност назад и да запълните null:\n" ] }, { @@ -2553,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "Както може би се досещате, това работи по същия начин с DataFrames, но можете също да зададете `axis`, по който да запълните null стойностите:\n" + "Както може би се досещате, това работи по същия начин с DataFrames, но можете също така да зададете `axis`, по който да запълвате null стойности:\n" ] }, { @@ -2850,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Имайте предвид, че колона 3 все още няма стойности: по подразбиране стойностите се попълват ред по ред.\n", + "Забележете, че колонка 3 все още е без стойности: стандартната посока е да се попълват стойности по редове.\n", "\n", - "> **Основна идея:** Има множество начини за справяне с липсващи стойности в наборите от данни. Конкретната стратегия, която ще използвате (премахване, заместване или дори как точно ще ги замените), трябва да бъде продиктувана от спецификата на данните. Ще развиете по-добро усещане за това как да се справяте с липсващи стойности, колкото повече работите и взаимодействате с набори от данни.\n" + "> **Основен извод:** Има множество начини за справяне с липсващи стойности в вашите набори от данни. Конкретната стратегия, която използвате (премахване, заместване или дори как точно да ги замените), трябва да бъде продиктувана от спецификата на тези данни. Ще развиете по-добро усещане за справяне с липсващи стойности, колкото повече работите и взаимодействате с набори от данни.\n" ] }, { @@ -2863,7 +2871,7 @@ "source": [ "### Кодиране на категорийни данни\n", "\n", - "Моделите за машинно обучение работят само с числа и всякакъв вид числови данни. Те не могат да различат \"Да\" от \"Не\", но могат да разграничат 0 от 1. Затова, след като попълним липсващите стойности, трябва да кодираме категорийни данни в някаква числова форма, за да може моделът да ги разбере.\n", + "Моделите за машинно обучение работят само с числа и всякакъв вид числови данни. Те не могат да различат \"Да\" от \"Не\", но могат да разграничат 0 от 1. Затова, след като попълним липсващите стойности, трябва да кодираме категорийните данни в някаква числова форма, за да може моделът да ги разбере.\n", "\n", "Кодирането може да се извърши по два начина. Ще ги разгледаме по-нататък.\n" ] @@ -2876,7 +2884,7 @@ "source": [ "**КОДИРАНЕ НА ЕТИКЕТИ**\n", "\n", - "Кодирането на етикети представлява преобразуване на всяка категория в число. Например, да кажем, че имаме набор от данни за пътници на авиолинии и има колона, съдържаща техния клас сред следните ['бизнес клас', 'икономичен клас', 'първа класа']. Ако се извърши кодиране на етикети, това ще бъде преобразувано в [0,1,2]. Нека видим пример чрез код. Тъй като ще изучаваме `scikit-learn` в следващите тетрадки, няма да го използваме тук.\n" + "Кодирането на етикети представлява преобразуване на всяка категория в число. Например, да предположим, че имаме набор от данни за пътници на авиолинии и има колона, съдържаща техния клас сред следните ['бизнес клас', 'икономичен клас', 'първа класа']. Ако се извърши кодиране на етикети, това ще бъде преобразувано в [0,1,2]. Нека видим пример чрез код. Тъй като ще изучаваме `scikit-learn` в следващите тетрадки, няма да го използваме тук.\n" ] }, { @@ -2984,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "За да извършим кодиране на етикети на първата колона, трябва първо да опишем съответствие от всеки клас към число, преди да заменим\n" + "За да извършим кодиране на етикети на първата колона, първо трябва да опишем съответствие от всеки клас към число, преди да заменим.\n" ] }, { @@ -3086,7 +3094,7 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Както виждаме, резултатът съвпада с това, което очаквахме. И така, кога използваме кодиране на етикети? Кодирането на етикети се използва в един или и в двата от следните случаи:\n", + "Както виждаме, резултатът съответства на това, което очаквахме. И така, кога използваме кодиране на етикети? Кодирането на етикети се използва в един или и двата от следните случаи:\n", "1. Когато броят на категориите е голям\n", "2. Когато категориите са подредени.\n" ] @@ -3099,7 +3107,7 @@ "source": [ "**ONE HOT ENCODING**\n", "\n", - "Друг вид кодиране е One Hot Encoding. При този вид кодиране всяка категория от колоната се добавя като отделна колона, а всяка точка от данните получава стойност 0 или 1 в зависимост от това дали съдържа тази категория. Така че, ако има n различни категории, към датафрейма ще бъдат добавени n колони.\n", + "Друг вид кодиране е One Hot Encoding. При този тип кодиране всяка категория от колоната се добавя като отделна колона, а всяка точка от данните получава стойност 0 или 1 в зависимост от това дали съдържа съответната категория. Така че, ако има n различни категории, към таблицата ще бъдат добавени n колони.\n", "\n", "Например, нека вземем същия пример с класовете на самолетите. Категориите бяха: ['business class', 'economy class', 'first class']. Ако извършим One Hot Encoding, към набора от данни ще бъдат добавени следните три колони: ['class_business class', 'class_economy class', 'class_first class'].\n" ] @@ -3334,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Всяка едно hot encoded колона съдържа 0 или 1, което указва дали тази категория съществува за дадената точка от данни.\n" + "Всеки еднократно кодиращ колон съдържа 0 или 1, което указва дали тази категория съществува за дадената точка от данни.\n" ] }, { @@ -3368,7 +3376,7 @@ "source": [ "## Премахване на дублирани данни\n", "\n", - "> **Цел на обучението:** До края на този подраздел трябва да се чувствате уверени в идентифицирането и премахването на дублирани стойности от DataFrames.\n", + "> **Цел на обучението:** До края на този подраздел трябва да сте уверени в идентифицирането и премахването на дублирани стойности от DataFrames.\n", "\n", "Освен липсващи данни, често ще срещате дублирани данни в реални набори от данни. За щастие, pandas предоставя лесен начин за откриване и премахване на дублирани записи.\n" ] @@ -3381,7 +3389,7 @@ "source": [ "### Идентифициране на дубликати: `duplicated`\n", "\n", - "Можете лесно да откриете дублирани стойности, като използвате метода `duplicated` в pandas, който връща булева маска, указваща дали даден запис в `DataFrame` е дубликат на по-ранен. Нека създадем още един примерен `DataFrame`, за да видим това в действие.\n" + "Можете лесно да откриете дублирани стойности, използвайки метода `duplicated` в pandas, който връща булева маска, указваща дали даден запис в `DataFrame` е дубликат на по-ранен. Нека създадем още един примерен `DataFrame`, за да видим това в действие.\n" ] }, { @@ -3511,7 +3519,7 @@ }, "source": [ "### Премахване на дубликати: `drop_duplicates`\n", - "`drop_duplicates` просто връща копие на данните, за които всички стойности на `duplicated` са `False`:\n" + "`drop_duplicates` просто връща копие на данните, за които всички стойности, маркирани като `duplicated`, са `False`:\n" ] }, { @@ -3594,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "И двете `duplicated` и `drop_duplicates` по подразбиране разглеждат всички колони, но можете да уточните да проверяват само подмножество от колони във вашия `DataFrame`:\n" + "И `duplicated`, и `drop_duplicates` по подразбиране разглеждат всички колони, но можете да посочите да проверяват само подмножество от колони във вашия `DataFrame`:\n" ] }, { @@ -3678,7 +3686,523 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Отказ от отговорност**: \nТози документ е преведен с помощта на AI услуга за превод [Co-op Translator](https://github.com/Azure/co-op-translator). Въпреки че се стремим към точност, моля, имайте предвид, че автоматизираните преводи може да съдържат грешки или неточности. Оригиналният документ на неговия роден език трябва да се счита за авторитетен източник. За критична информация се препоръчва професионален човешки превод. Не носим отговорност за недоразумения или погрешни интерпретации, произтичащи от използването на този превод.\n" + "## Проверки за качество на данни в реалния свят\n", + "\n", + "> **Цел на обучението:** До края на този раздел трябва да сте уверени в откриването и коригирането на често срещани проблеми с качеството на данни в реалния свят, включително несъответстващи категорийни стойности, необичайни числови стойности (отклонения) и дублирани записи с вариации.\n", + "\n", + "Докато липсващите стойности и точните дубликати са често срещани проблеми, наборите от данни в реалния свят често съдържат по-фини проблеми:\n", + "\n", + "1. **Несъответстващи категорийни стойности**: Една и съща категория, изписана по различен начин (напр. \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Необичайни числови стойности**: Екстремни отклонения, които показват грешки при въвеждане на данни (напр. възраст = 999)\n", + "3. **Близки дубликати**: Записи, които представляват едно и също лице или обект с леки вариации\n", + "\n", + "Нека разгледаме техники за откриване и справяне с тези проблеми.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Създаване на примерен \"замърсен\" набор от данни\n", + "\n", + "Първо, нека създадем примерен набор от данни, който съдържа типовете проблеми, с които често се сблъскваме в реални данни:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Откриване на несъответстващи категорийни стойности\n", + "\n", + "Забележете, че колоната `country` има множество представяния за едни и същи държави. Нека идентифицираме тези несъответствия:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Стандартизиране на категорийни стойности\n", + "\n", + "Можем да създадем карта за стандартизиране на тези стойности. Един прост подход е да ги преобразуваме в малки букви и да създадем речник за картографиране:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Алтернатива: Използване на размито съвпадение**\n", + "\n", + "За по-сложни случаи можем да използваме размито съвпадение на низове с библиотеката `rapidfuzz`, за да откриваме автоматично подобни низове:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Откриване на необичайни числови стойности (отклонения)\n", + "\n", + "Разглеждайки колоната `age`, имаме някои подозрителни стойности като 199 и -5. Нека използваме статистически методи, за да открием тези отклонения.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Използване на метода IQR (Интерквартилен обхват)\n", + "\n", + "Методът IQR е надежден статистически подход за откриване на отклонения, който е по-малко чувствителен към екстремни стойности:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Използване на метода Z-Score\n", + "\n", + "Методът Z-Score идентифицира отклонения въз основа на стандартни отклонения от средната стойност:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Работа с отклонения\n", + "\n", + "След като бъдат открити, отклоненията могат да бъдат обработени по няколко начина:\n", + "1. **Премахване**: Изтриване на редове с отклонения (ако са грешки)\n", + "2. **Ограничаване**: Замяна с гранични стойности\n", + "3. **Замяна с NaN**: Третиране като липсващи данни и използване на техники за импутация\n", + "4. **Запазване**: Ако са легитимни екстремни стойности\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Откриване на почти идентични редове\n", + "\n", + "Забележете, че нашият набор от данни има множество записи за \"John Smith\" с леко различни стойности. Нека идентифицираме потенциални дубликати въз основа на сходство на имената.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Откриване на близки дубликати с размито съвпадение\n", + "\n", + "За по-усъвършенствано откриване на дубликати можем да използваме размито съвпадение, за да намерим подобни имена:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Работа с дубликати\n", + "\n", + "След като бъдат идентифицирани, трябва да решите как да се справите с дубликатите:\n", + "1. **Запазване на първото срещане**: Използвайте `drop_duplicates(keep='first')`\n", + "2. **Запазване на последното срещане**: Използвайте `drop_duplicates(keep='last')`\n", + "3. **Агрегиране на информация**: Комбинирайте информацията от дублиращите се редове\n", + "4. **Ръчен преглед**: Отбележете за преглед от човек\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Резюме: Пълна система за почистване на данни\n", + "\n", + "Нека съберем всичко в една цялостна система за почистване на данни:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Упражнение за предизвикателство\n", + "\n", + "Сега е ваш ред! По-долу има нов ред данни с множество проблеми с качеството. Можете ли:\n", + "\n", + "1. Да идентифицирате всички проблеми в този ред\n", + "2. Да напишете код за коригиране на всеки проблем\n", + "3. Да добавите почистения ред към набора от данни\n", + "\n", + "Ето проблемните данни:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Основни изводи\n", + "\n", + "1. **Несъответстващи категории** са често срещани в реалните данни. Винаги проверявайте уникалните стойности и ги стандартизирайте чрез съответствия или размито съвпадение.\n", + "\n", + "2. **Аномалии** могат значително да повлияят на анализа ви. Използвайте знания за конкретната област, комбинирани със статистически методи (IQR, Z-score), за да ги откриете.\n", + "\n", + "3. **Близки дубликати** са по-трудни за откриване от точните дубликати. Помислете за използване на размито съвпадение и нормализиране на данните (преобразуване в малки букви, премахване на празни пространства), за да ги идентифицирате.\n", + "\n", + "4. **Почистването на данни е итеративен процес**. Може да се наложи да приложите множество техники и да прегледате резултатите, преди да финализирате почистения набор от данни.\n", + "\n", + "5. **Документирайте решенията си**. Проследявайте какви стъпки за почистване сте приложили и защо, тъй като това е важно за възпроизводимостта и прозрачността.\n", + "\n", + "> **Най-добра практика:** Винаги запазвайте копие на оригиналните \"замърсени\" данни. Никога не презаписвайте изходните файлове с данни - създавайте почистени версии с ясни конвенции за именуване, като `data_cleaned.csv`.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n---\n\n**Отказ от отговорност**: \nТози документ е преведен с помощта на AI услуга за превод [Co-op Translator](https://github.com/Azure/co-op-translator). Въпреки че се стремим към точност, моля, имайте предвид, че автоматизираните преводи може да съдържат грешки или неточности. Оригиналният документ на неговия роден език трябва да се счита за авторитетен източник. За критична информация се препоръчва професионален човешки превод. Ние не носим отговорност за недоразумения или погрешни интерпретации, произтичащи от използването на този превод.\n" ] } ], @@ -3706,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:21:44+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T21:06:02+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "bg" } diff --git a/translations/bn/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/bn/2-Working-With-Data/08-data-preparation/notebook.ipynb index de48aec8..516e4b2d 100644 --- a/translations/bn/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/bn/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# ডেটা প্রস্তুতি\n", "\n", - "[মূল নোটবুক উৎস *ডেটা সায়েন্স: পাইথন এবং মেশিন লার্নিং স্টুডিওর জন্য মেশিন লার্নিং পরিচিতি - লি স্টট*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[মূল নোটবুক উৎস *ডেটা সায়েন্স: ডেটা সায়েন্সের জন্য মেশিন লার্নিং পরিচিতি, পাইথন এবং মেশিন লার্নিং স্টুডিও - লি স্টট*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## `DataFrame` তথ্য অনুসন্ধান\n", "\n", - "> **শিক্ষার লক্ষ্য:** এই উপ-অধ্যায়ের শেষে, আপনি pandas DataFrame-এ সংরক্ষিত ডেটা সম্পর্কে সাধারণ তথ্য খুঁজে পেতে স্বাচ্ছন্দ্যবোধ করবেন।\n", + "> **শিক্ষার লক্ষ্য:** এই উপ-অধ্যায়ের শেষে, আপনি pandas DataFrame-এ সংরক্ষিত ডেটার সাধারণ তথ্য খুঁজে বের করতে স্বাচ্ছন্দ্যবোধ করবেন।\n", "\n", - "যখন আপনি pandas-এ আপনার ডেটা লোড করবেন, এটি সম্ভবত একটি `DataFrame` আকারে থাকবে। তবে, যদি আপনার `DataFrame`-এ থাকা ডেটাসেটে ৬০,০০০ সারি এবং ৪০০ কলাম থাকে, তাহলে আপনি কীভাবে কাজ শুরু করবেন? সৌভাগ্যবশত, pandas কিছু সুবিধাজনক টুল সরবরাহ করে যা একটি `DataFrame`-এর সামগ্রিক তথ্য এবং প্রথম কয়েকটি ও শেষ কয়েকটি সারি দ্রুত দেখার সুযোগ দেয়।\n", + "যখন আপনি pandas-এ আপনার ডেটা লোড করবেন, এটি সম্ভবত `DataFrame` আকারে থাকবে। তবে, যদি আপনার `DataFrame`-এ থাকা ডেটাসেটে ৬০,০০০ সারি এবং ৪০০ কলাম থাকে, তাহলে আপনি কীভাবে কাজ শুরু করবেন? সৌভাগ্যক্রমে, pandas কিছু সুবিধাজনক টুল সরবরাহ করে যা `DataFrame`-এর সামগ্রিক তথ্য এবং প্রথম কয়েকটি ও শেষ কয়েকটি সারি দ্রুত দেখার সুযোগ দেয়।\n", "\n", - "এই কার্যকারিতা অনুসন্ধান করার জন্য, আমরা Python-এর scikit-learn লাইব্রেরি ইম্পোর্ট করব এবং একটি আইকনিক ডেটাসেট ব্যবহার করব যা প্রতিটি ডেটা সায়েন্টিস্ট শত শত বার দেখেছেন: ব্রিটিশ জীববিজ্ঞানী রোনাল্ড ফিশারের *আইরিস* ডেটাসেট, যা তিনি ১৯৩৬ সালে তার \"The use of multiple measurements in taxonomic problems\" শীর্ষক গবেষণাপত্রে ব্যবহার করেছিলেন:\n" + "এই কার্যকারিতা অনুসন্ধানের জন্য, আমরা Python-এর scikit-learn লাইব্রেরি আমদানি করব এবং একটি আইকনিক ডেটাসেট ব্যবহার করব যা প্রতিটি ডেটা বিজ্ঞানী শত শত বার দেখেছেন: ব্রিটিশ জীববিজ্ঞানী রোনাল্ড ফিশারের *আইরিস* ডেটাসেট, যা তিনি ১৯৩৬ সালে তার \"ট্যাক্সোনমিক সমস্যায় একাধিক পরিমাপের ব্যবহার\" শীর্ষক গবেষণাপত্রে ব্যবহার করেছিলেন:\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "আমরা `iris_df` ভেরিয়েবলে Iris Dataset লোড করেছি। ডেটাতে গভীরভাবে যাওয়ার আগে, আমাদের কাছে কতগুলো ডেটাপয়েন্ট আছে এবং ডেটাসেটের সামগ্রিক আকার জানা গুরুত্বপূর্ণ। আমরা যে ডেটার পরিমাণ নিয়ে কাজ করছি তা বোঝার জন্য এটি উপকারী।\n" + "আমরা `iris_df` ভেরিয়েবলে আইরিস ডেটাসেট লোড করেছি। ডেটাতে গভীরভাবে যাওয়ার আগে, আমাদের কাছে কতগুলো ডেটাপয়েন্ট আছে এবং ডেটাসেটের সামগ্রিক আকার জানা গুরুত্বপূর্ণ। আমরা যে ডেটার পরিমাণ নিয়ে কাজ করছি তা বোঝার জন্য এটি উপকারী।\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "আমরা এখানে ১৫০ সারি এবং ৪টি কলামের ডেটা নিয়ে কাজ করছি। প্রতিটি সারি একটি ডেটাপয়েন্টকে উপস্থাপন করে এবং প্রতিটি কলাম ডেটা ফ্রেমের সাথে সম্পর্কিত একটি বৈশিষ্ট্যকে উপস্থাপন করে। সুতরাং, মূলত ১৫০টি ডেটাপয়েন্ট রয়েছে, যার প্রতিটিতে ৪টি বৈশিষ্ট্য রয়েছে।\n", + "আমরা এখানে ১৫০টি সারি এবং ৪টি কলামের ডেটা নিয়ে কাজ করছি। প্রতিটি সারি একটি ডেটাপয়েন্টকে উপস্থাপন করে এবং প্রতিটি কলাম ডেটা ফ্রেমের সাথে সম্পর্কিত একটি বৈশিষ্ট্যকে উপস্থাপন করে। অর্থাৎ, এখানে মোট ১৫০টি ডেটাপয়েন্ট রয়েছে, প্রতিটি ডেটাপয়েন্টে ৪টি বৈশিষ্ট্য রয়েছে।\n", "\n", - "`shape` এখানে ডেটা ফ্রেমের একটি অ্যাট্রিবিউট এবং এটি একটি ফাংশন নয়, যার কারণে এটি বন্ধনী দিয়ে শেষ হয় না।\n" + "`shape` এখানে ডেটা ফ্রেমের একটি অ্যাট্রিবিউট এবং এটি কোনো ফাংশন নয়, এজন্য এটি একটি জোড়া বন্ধনী দিয়ে শেষ হয় না।\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "এবার আমরা ডেটার ৪টি কলামে প্রবেশ করি। প্রতিটি কলাম আসলে কী বোঝায়? `columns` অ্যাট্রিবিউটটি আমাদের ডেটাফ্রেমের কলামগুলোর নাম জানাবে।\n" + "এখন আমরা ডেটার ৪টি কলামে প্রবেশ করব। প্রতিটি কলাম ঠিক কী উপস্থাপন করে? `columns` অ্যাট্রিবিউট আমাদের ডেটাফ্রেমের কলামের নামগুলি প্রদান করবে।\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "যেমন আমরা দেখতে পাচ্ছি, এখানে চার(৪)টি কলাম রয়েছে। `columns` অ্যাট্রিবিউট আমাদের কলামের নাম জানায় এবং মূলত আর কিছুই নয়। এই অ্যাট্রিবিউটটি গুরুত্বপূর্ণ হয়ে ওঠে যখন আমরা একটি ডেটাসেটে থাকা বৈশিষ্ট্যগুলি চিহ্নিত করতে চাই।\n" + "যেমন আমরা দেখতে পাচ্ছি, এখানে চার(৪)টি কলাম রয়েছে। `columns` অ্যাট্রিবিউট আমাদের কলামগুলোর নাম জানায় এবং মূলত আর কিছুই নয়। এই অ্যাট্রিবিউট গুরুত্বপূর্ণ হয়ে ওঠে যখন আমরা কোনো ডেটাসেটে থাকা বৈশিষ্ট্যগুলো চিহ্নিত করতে চাই।\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "ডেটার পরিমাণ (`shape` অ্যাট্রিবিউট দ্বারা প্রদত্ত) এবং ফিচার বা কলামের নামসমূহ (`columns` অ্যাট্রিবিউট দ্বারা প্রদত্ত) আমাদের ডেটাসেট সম্পর্কে কিছু ধারণা দেয়। এখন, আমরা ডেটাসেটটি আরও গভীরভাবে বিশ্লেষণ করতে চাই। এ ক্ষেত্রে, `DataFrame.info()` ফাংশনটি বেশ উপকারী।\n" + "ডেটার পরিমাণ (`shape` attribute দ্বারা প্রদত্ত) এবং বৈশিষ্ট্য বা কলামের নাম (`columns` attribute দ্বারা প্রদত্ত) আমাদের ডেটাসেট সম্পর্কে কিছু তথ্য দেয়। এখন, আমরা ডেটাসেটটি আরও গভীরভাবে বিশ্লেষণ করতে চাই। `DataFrame.info()` ফাংশন এই ক্ষেত্রে বেশ কার্যকর।\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "এখান থেকে আমরা কিছু পর্যবেক্ষণ করতে পারি: \n", - "1. প্রতিটি কলামের DataType: এই ডেটাসেটে, সমস্ত ডেটা ৬৪-বিট ফ্লোটিং-পয়েন্ট সংখ্যার আকারে সংরক্ষিত। \n", - "2. Non-Null মানের সংখ্যা: ডেটা প্রস্তুতির ক্ষেত্রে null মানগুলোর সাথে কাজ করা একটি গুরুত্বপূর্ণ ধাপ। এটি নোটবুকে পরে আলোচনা করা হবে। \n" + "এখান থেকে আমরা কয়েকটি পর্যবেক্ষণ করতে পারি:\n", + "1. প্রতিটি কলামের DataType: এই ডেটাসেটে, সমস্ত ডেটা 64-বিট ফ্লোটিং-পয়েন্ট সংখ্যার আকারে সংরক্ষিত।\n", + "2. Non-Null মানের সংখ্যা: null মানগুলোর সাথে কাজ করা ডেটা প্রস্তুতির একটি গুরুত্বপূর্ণ ধাপ। এটি পরে নোটবুকে আলোচনা করা হবে।\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "ধরুন আমাদের ডেটাসেটে অনেক সংখ্যাগত ডেটা রয়েছে। একক পরিবর্তনশীল পরিসংখ্যানগত হিসাব যেমন গড়, মধ্যমা, চতুর্থাংশ ইত্যাদি প্রতিটি কলামের উপর আলাদাভাবে করা যেতে পারে। `DataFrame.describe()` ফাংশন আমাদের ডেটাসেটের সংখ্যাগত কলামগুলোর একটি পরিসংখ্যানগত সারাংশ প্রদান করে।\n" + "ধরুন আমাদের ডেটাসেটে অনেক সংখ্যাগত ডেটা রয়েছে। একক পরিবর্তনশীল পরিসংখ্যানগত হিসাব যেমন গড়, মধ্যমা, চতুর্থাংশ ইত্যাদি প্রতিটি কলামের উপর আলাদাভাবে করা যেতে পারে। `DataFrame.describe()` ফাংশন আমাদের ডেটাসেটের সংখ্যাগত কলামগুলোর একটি পরিসংখ্যানগত সারসংক্ষেপ প্রদান করে।\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "উপরে প্রদর্শিত আউটপুট প্রতিটি কলামের মোট ডেটা পয়েন্টের সংখ্যা, গড়, মানক বিচ্যুতি, সর্বনিম্ন, নিম্ন চতুর্থাংশ (২৫%), মধ্যম (৫০%), উপরের চতুর্থাংশ (৭৫%) এবং সর্বোচ্চ মান দেখায়।\n" + "উপরে প্রদর্শিত আউটপুটটি প্রতিটি কলামের মোট ডেটা পয়েন্টের সংখ্যা, গড়, মানদণ্ড বিচ্যুতি, সর্বনিম্ন, নিম্ন চতুর্থাংশ (২৫%), মধ্যম (৫০%), উপরের চতুর্থাংশ (৭৫%) এবং সর্বোচ্চ মান দেখায়।\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "উপরের সমস্ত ফাংশন এবং অ্যাট্রিবিউটগুলোর মাধ্যমে, আমরা ডেটাসেটের একটি শীর্ষ স্তরের ধারণা পেয়েছি। আমরা জানি ডেটাসেটে কতগুলো ডেটা পয়েন্ট আছে, কতগুলো বৈশিষ্ট্য আছে, প্রতিটি বৈশিষ্ট্যের ডেটা টাইপ কী এবং প্রতিটি বৈশিষ্ট্যের জন্য কতগুলো নন-নাল মান রয়েছে।\n", + "উপরের সমস্ত ফাংশন এবং অ্যাট্রিবিউট ব্যবহার করে আমরা ডেটাসেটের একটি শীর্ষ স্তরের ধারণা পেয়েছি। আমরা জানি এখানে কতগুলো ডেটা পয়েন্ট আছে, কতগুলো বৈশিষ্ট্য আছে, প্রতিটি বৈশিষ্ট্যের ডেটা টাইপ কী এবং প্রতিটি বৈশিষ্ট্যের জন্য কতগুলো নন-নাল মান রয়েছে।\n", "\n", - "এখন সময় এসেছে ডেটা নিজেই দেখার। চলুন দেখি আমাদের `DataFrame`-এর প্রথম কয়েকটি সারি (প্রথম কয়েকটি ডেটা পয়েন্ট) কেমন দেখায়:\n" + "এখন সময় এসেছে ডেটা নিজেই দেখার। চলুন দেখি আমাদের `DataFrame`-এর প্রথম কয়েকটি সারি (প্রথম কয়েকটি ডেটা পয়েন্ট) দেখতে কেমন:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "ডেটাসেটের আউটপুটে আমরা পাঁচ(৫)টি এন্ট্রি দেখতে পাচ্ছি। যদি আমরা বাম দিকে সূচকটি দেখি, তাহলে বুঝতে পারি যে এগুলো প্রথম পাঁচটি সারি।\n" + "আউটপুটে, আমরা দেখতে পাচ্ছি যে ডেটাসেটের পাঁচ(৫)টি এন্ট্রি রয়েছে। যদি আমরা বাম দিকে থাকা সূচকের দিকে তাকাই, তাহলে দেখতে পাই যে এগুলো প্রথম পাঁচটি সারি।\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### অনুশীলন:\n", "\n", - "উপরের উদাহরণ থেকে এটি স্পষ্ট যে, ডিফল্টভাবে `DataFrame.head` একটি `DataFrame`-এর প্রথম পাঁচটি সারি ফেরত দেয়। নিচের কোড সেলে, আপনি কি পাঁচটির বেশি সারি প্রদর্শনের কোনো উপায় বের করতে পারেন?\n" + "উপরের উদাহরণ থেকে এটি স্পষ্ট যে, ডিফল্টভাবে `DataFrame.head` একটি `DataFrame`-এর প্রথম পাঁচটি সারি ফেরত দেয়। নিচের কোড সেলে, আপনি কি এমন একটি উপায় বের করতে পারেন যাতে পাঁচটির বেশি সারি প্রদর্শন করা যায়?\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "ডেটাফ্রেম (`DataFrame`) এর প্রথম কয়েকটি সারি বা শেষ কয়েকটি সারি সহজেই পরীক্ষা করতে পারা খুবই উপকারী, বিশেষত যখন আপনি ক্রমানুসারে সাজানো ডেটাসেটে অস্বাভাবিক মান খুঁজছেন। \n", + "প্রকৃতপক্ষে, একটি `DataFrame`-এর প্রথম কয়েকটি সারি বা শেষ কয়েকটি সারি সহজে পরীক্ষা করা খুবই উপকারী, বিশেষত যখন আপনি ক্রমানুসারে সাজানো ডেটাসেটে অস্বাভাবিক মান খুঁজছেন।\n", "\n", - "উপরের কোড উদাহরণগুলোর মাধ্যমে প্রদর্শিত সমস্ত ফাংশন এবং অ্যাট্রিবিউট আমাদের ডেটার একটি সামগ্রিক ধারণা পেতে সাহায্য করে। \n", + "উপরে প্রদর্শিত কোড উদাহরণগুলোর সাহায্যে দেখানো সমস্ত ফাংশন এবং অ্যাট্রিবিউট আমাদের ডেটার একটি সামগ্রিক ধারণা পেতে সাহায্য করে।\n", "\n", - "> **মূল কথা:** শুধুমাত্র ডেটাফ্রেমের তথ্য সম্পর্কিত মেটাডেটা বা এর প্রথম এবং শেষ কয়েকটি মান দেখেই আপনি ডেটার আকার, গঠন এবং বিষয়বস্তু সম্পর্কে তাৎক্ষণিক ধারণা পেতে পারেন।\n" + "> **মূল কথা:** শুধুমাত্র একটি DataFrame-এর তথ্য সম্পর্কিত মেটাডেটা বা এর প্রথম এবং শেষ কয়েকটি মান দেখেই আপনি ডেটার আকার, আকৃতি এবং বিষয়বস্তু সম্পর্কে তাত্ক্ষণিক ধারণা পেতে পারেন।\n" ] }, { @@ -606,7 +606,7 @@ "\n", "Pandas দুটি উপায়ে অনুপস্থিত মান পরিচালনা করে। প্রথমটি আপনি আগের অংশগুলোতে দেখেছেন: `NaN`, বা Not a Number। এটি আসলে IEEE floating-point স্পেসিফিকেশনের একটি বিশেষ মান এবং এটি শুধুমাত্র অনুপস্থিত floating-point মান নির্দেশ করার জন্য ব্যবহৃত হয়।\n", "\n", - "Floating-point ছাড়া অন্যান্য অনুপস্থিত মানের জন্য, pandas Python এর `None` অবজেক্ট ব্যবহার করে। যদিও এটি বিভ্রান্তিকর মনে হতে পারে যে আপনি দুটি ভিন্ন ধরনের মান দেখতে পাবেন যা মূলত একই জিনিস নির্দেশ করে, তবে এই ডিজাইন পছন্দের পেছনে যথাযথ প্রোগ্রাম্যাটিক কারণ রয়েছে। বাস্তবে, এই পদ্ধতি pandas-কে বেশিরভাগ ক্ষেত্রে একটি ভালো সমাধান প্রদান করতে সক্ষম করে। তবে, `None` এবং `NaN` উভয়েরই কিছু সীমাবদ্ধতা রয়েছে, যা তাদের ব্যবহারের ক্ষেত্রে আপনাকে সচেতন থাকতে হবে।\n" + "ফ্লোট ছাড়া অন্যান্য অনুপস্থিত মানের জন্য, pandas Python এর `None` অবজেক্ট ব্যবহার করে। যদিও এটি বিভ্রান্তিকর মনে হতে পারে যে আপনি দুটি ভিন্ন ধরনের মানের সম্মুখীন হবেন যা মূলত একই জিনিস নির্দেশ করে, তবে এই ডিজাইন পছন্দের পেছনে যথাযথ প্রোগ্রাম্যাটিক কারণ রয়েছে এবং বাস্তবে, এই পদ্ধতি pandas-কে বেশিরভাগ ক্ষেত্রে একটি ভালো সমঝোতা প্রদান করতে সক্ষম করে। তবুও, `None` এবং `NaN` উভয়েরই কিছু সীমাবদ্ধতা রয়েছে যা তাদের ব্যবহারের ক্ষেত্রে আপনাকে সচেতন থাকতে হবে।\n" ] }, { @@ -615,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: নন-ফ্লোট অনুপস্থিত ডেটা\n", - "যেহেতু `None` পাইথন থেকে আসে, এটি এমন NumPy এবং pandas অ্যারেতে ব্যবহার করা যায় না যেগুলোর ডেটা টাইপ `'object'` নয়। মনে রাখবেন, NumPy অ্যারে (এবং pandas-এর ডেটা স্ট্রাকচারগুলো) শুধুমাত্র এক ধরনের ডেটা ধারণ করতে পারে। এটি তাদের বৃহৎ পরিসরের ডেটা এবং গণনামূলক কাজের জন্য অসাধারণ ক্ষমতা প্রদান করে, তবে এটি তাদের নমনীয়তাকে সীমিত করে। এমন অ্যারেগুলোকে \"সর্বনিম্ন সাধারণ গুণ\" অর্থাৎ এমন ডেটা টাইপে আপকাস্ট করতে হয় যা অ্যারেতে থাকা সবকিছুকে অন্তর্ভুক্ত করতে পারে। যখন `None` অ্যারেতে থাকে, এর অর্থ আপনি পাইথন অবজেক্ট নিয়ে কাজ করছেন।\n", + "### `None`: অ-ফ্লোট অনুপস্থিত ডেটা\n", + "যেহেতু `None` পাইথন থেকে আসে, এটি NumPy এবং pandas এর সেই অ্যারে-তে ব্যবহার করা যায় না যেগুলোর ডেটা টাইপ `'object'` নয়। মনে রাখবেন, NumPy অ্যারে (এবং pandas এর ডেটা স্ট্রাকচারগুলো) শুধুমাত্র এক ধরনের ডেটা ধারণ করতে পারে। এটি তাদের বৃহৎ পরিসরের ডেটা এবং গণনামূলক কাজের জন্য অসাধারণ ক্ষমতা প্রদান করে, তবে এটি তাদের নমনীয়তাকে সীমিত করে। এমন অ্যারেগুলোকে \"সর্বনিম্ন সাধারণ গুণ\" অর্থাৎ এমন ডেটা টাইপে রূপান্তর করতে হয় যা অ্যারেতে থাকা সবকিছুকে অন্তর্ভুক্ত করতে পারে। যখন `None` অ্যারেতে থাকে, এর অর্থ আপনি পাইথন অবজেক্ট নিয়ে কাজ করছেন।\n", "\n", - "এটি বাস্তবে দেখতে, নিচের উদাহরণ অ্যারেটি বিবেচনা করুন (এর `dtype` লক্ষ্য করুন):\n" + "এটি বাস্তবে দেখতে, নিচের উদাহরণ অ্যারে বিবেচনা করুন (এর `dtype` লক্ষ্য করুন):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "আপকাস্ট ডেটা টাইপের বাস্তবতা দুটি পার্শ্বপ্রতিক্রিয়া নিয়ে আসে। প্রথমত, অপারেশনগুলো সংকলিত NumPy কোডের পরিবর্তে ব্যাখ্যামূলক Python কোডের স্তরে সম্পন্ন হবে। মূলত, এর অর্থ হলো `Series` বা `DataFrames`-এ যদি `None` থাকে, তাহলে সংশ্লিষ্ট অপারেশনগুলো ধীরগতির হবে। যদিও আপনি সম্ভবত এই পারফরম্যান্সের প্রভাব লক্ষ্য করবেন না, বড় ডেটাসেটের ক্ষেত্রে এটি একটি সমস্যা হয়ে উঠতে পারে।\n", + "আপকাস্ট ডেটা টাইপের বাস্তবতা দুটি পার্শ্বপ্রতিক্রিয়া নিয়ে আসে। প্রথমত, অপারেশনগুলি সংকলিত NumPy কোডের পরিবর্তে ব্যাখ্যা করা Python কোডের স্তরে সম্পন্ন হবে। মূলত, এর অর্থ হলো `Series` বা `DataFrame`-এ যদি `None` থাকে, তাহলে সংশ্লিষ্ট অপারেশনগুলি ধীরগতির হবে। যদিও আপনি সম্ভবত এই পারফরম্যান্সের প্রভাব লক্ষ্য করবেন না, বড় ডেটাসেটের ক্ষেত্রে এটি একটি সমস্যা হয়ে উঠতে পারে।\n", "\n", - "দ্বিতীয় পার্শ্বপ্রতিক্রিয়া প্রথমটির থেকে উদ্ভূত। কারণ `None` মূলত `Series` বা `DataFrame`-কে সাধারণ Python-এর জগতে ফিরিয়ে নিয়ে যায়, তাই যদি কোনো অ্যারে-তে `None` মান থাকে, NumPy/pandas-এর মতো অ্যাগ্রিগেশন ফাংশন যেমন `sum()` বা `min()` ব্যবহার করলে সাধারণত একটি ত্রুটি তৈরি হবে:\n" + "দ্বিতীয় পার্শ্বপ্রতিক্রিয়া প্রথমটির সাথে সম্পর্কিত। কারণ `None` মূলত `Series` বা `DataFrame`-কে সাধারণ Python-এর জগতে ফিরিয়ে নিয়ে যায়, তাই NumPy/pandas-এর মতো অ্যাগ্রিগেশন ফাংশন যেমন `sum()` বা `min()` ব্যবহার করে যদি অ্যারে-তে ``None`` থাকে, সাধারণত একটি ত্রুটি তৈরি হবে:\n" ] }, { @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**মূল কথা**: পূর্ণসংখ্যা এবং `None` মানের মধ্যে যোগ (এবং অন্যান্য ক্রিয়াকলাপ) অনির্ধারিত, যা এমন ডেটাসেটের সাথে কাজ করার সীমাবদ্ধতা তৈরি করতে পারে যেখানে এগুলি অন্তর্ভুক্ত থাকে।\n" + "**মূল কথা**: পূর্ণসংখ্যা এবং `None` মানের মধ্যে যোগ (এবং অন্যান্য অপারেশন) অনির্ধারিত, যা এমন ডেটাসেটের সাথে কাজ করার সীমাবদ্ধতা তৈরি করতে পারে যেখানে এগুলো উপস্থিত।\n" ] }, { @@ -709,7 +709,7 @@ "source": [ "### `NaN`: অনুপস্থিত ফ্লোট মান\n", "\n", - "`None` এর বিপরীতে, NumPy (এবং সেইসাথে pandas) তার দ্রুত, ভেক্টরাইজড অপারেশন এবং ufuncs এর জন্য `NaN` সমর্থন করে। খারাপ খবর হলো, `NaN` এর উপর যেকোনো গাণিতিক ক্রিয়া সবসময় `NaN` ফলাফল দেয়। উদাহরণস্বরূপ:\n" + "`None` এর বিপরীতে, NumPy (এবং সেইসাথে pandas) তার দ্রুত, ভেক্টরাইজড অপারেশন এবং ufuncs এর জন্য `NaN` সমর্থন করে। খারাপ খবর হলো, `NaN` এর উপর যেকোনো গাণিতিক অপারেশন করলে ফলাফল সবসময় `NaN` হয়। উদাহরণস্বরূপ:\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "ভালো খবর: `NaN` থাকা অ্যারেগুলিতে অ্যাগ্রিগেশন চালালে কোনো ত্রুটি প্রদর্শিত হয় না। খারাপ খবর: ফলাফলগুলি সর্বদা উপযোগী নয়:\n" + "ভালো খবর: `NaN` থাকা অ্যারেগুলিতে অ্যাগ্রিগেশন চালালে কোনো ত্রুটি দেখায় না। খারাপ খবর: ফলাফলগুলি সর্বদা উপযোগী হয় না:\n" ] }, { @@ -831,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "মনে রাখবেন: `NaN` শুধুমাত্র অনুপস্থিত ফ্লোটিং-পয়েন্ট মানগুলির জন্য; পূর্ণসংখ্যা, স্ট্রিং বা বুলিয়ানের জন্য কোনও `NaN` সমতুল্য নেই।\n" + "মনে রাখুন: `NaN` শুধুমাত্র অনুপস্থিত ফ্লোটিং-পয়েন্ট মানগুলির জন্য; পূর্ণসংখ্যা, স্ট্রিং বা বুলিয়ানের জন্য কোনও `NaN` সমতুল্য নেই।\n" ] }, { @@ -842,7 +842,7 @@ "source": [ "### `NaN` এবং `None`: pandas-এ null মান\n", "\n", - "যদিও `NaN` এবং `None` কিছুটা ভিন্নভাবে আচরণ করতে পারে, pandas তবুও এগুলোকে একে অপরের পরিবর্তে ব্যবহার করার জন্য তৈরি করা হয়েছে। আমরা কী বোঝাতে চাই তা দেখতে, একটি পূর্ণসংখ্যার `Series` বিবেচনা করুন:\n" + "যদিও `NaN` এবং `None` কিছুটা ভিন্নভাবে আচরণ করতে পারে, pandas এগুলোকে একে অপরের পরিবর্তে ব্যবহার করার জন্য তৈরি করা হয়েছে। আমরা কী বোঝাতে চাই তা দেখতে, একটি পূর্ণসংখ্যার `Series` বিবেচনা করুন:\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "ডেটা টাইপগুলিকে একরূপতা নিশ্চিত করার জন্য `Series` এবং `DataFrame`-এ আপকাস্ট করার প্রক্রিয়ায়, pandas সহজেই অনুপস্থিত মানগুলিকে `None` এবং `NaN` এর মধ্যে পরিবর্তন করতে পারে। এই ডিজাইন বৈশিষ্ট্যের কারণে, pandas-এ `None` এবং `NaN`-কে \"null\" এর দুটি ভিন্ন রূপ হিসেবে ভাবা সহায়ক হতে পারে। প্রকৃতপক্ষে, pandas-এ অনুপস্থিত মানগুলির সাথে কাজ করার জন্য ব্যবহৃত কিছু প্রধান মেথডের নামেও এই ধারণাটি প্রতিফলিত হয়:\n", + "`Series` এবং `DataFrame`-এ ডেটার সামঞ্জস্যতা নিশ্চিত করার জন্য ডেটা টাইপ আপকাস্ট করার প্রক্রিয়ায়, pandas সহজেই `None` এবং `NaN` এর মধ্যে অনুপস্থিত মানগুলি পরিবর্তন করতে পারে। এই ডিজাইন বৈশিষ্ট্যের কারণে, pandas-এ `None` এবং `NaN` কে \"null\" এর দুটি ভিন্ন রূপ হিসেবে ভাবা সুবিধাজনক হতে পারে। প্রকৃতপক্ষে, pandas-এ অনুপস্থিত মানগুলি পরিচালনা করার জন্য আপনি যে মূল পদ্ধতিগুলি ব্যবহার করবেন, সেগুলোর নামেও এই ধারণাটি প্রতিফলিত হয়:\n", "\n", - "- `isnull()`: অনুপস্থিত মান নির্দেশ করার জন্য একটি বুলিয়ান মাস্ক তৈরি করে\n", + "- `isnull()`: অনুপস্থিত মানগুলি নির্দেশ করার জন্য একটি বুলিয়ান মাস্ক তৈরি করে\n", "- `notnull()`: `isnull()`-এর বিপরীত\n", "- `dropna()`: ডেটার একটি ফিল্টার করা সংস্করণ প্রদান করে\n", - "- `fillna()`: অনুপস্থিত মান পূরণ বা ইম্পুট করে ডেটার একটি কপি প্রদান করে\n", + "- `fillna()`: অনুপস্থিত মানগুলি পূরণ বা অনুমান করে ডেটার একটি কপি প্রদান করে\n", "\n", - "এই মেথডগুলো আয়ত্ত করা এবং সেগুলোর সাথে স্বাচ্ছন্দ্য বোধ করা অত্যন্ত গুরুত্বপূর্ণ, তাই চলুন প্রতিটি মেথড নিয়ে একটু গভীরভাবে আলোচনা করি।\n" + "এই পদ্ধতিগুলি আয়ত্ত করা এবং সেগুলোর সাথে স্বাচ্ছন্দ্য বোধ করা অত্যন্ত গুরুত্বপূর্ণ। তাই চলুন, প্রতিটি পদ্ধতি বিস্তারিতভাবে আলোচনা করি।\n" ] }, { @@ -924,7 +924,7 @@ "source": [ "### নাল মান সনাক্ত করা\n", "\n", - "এখন যেহেতু আমরা অনুপস্থিত মানগুলোর গুরুত্ব বুঝেছি, আমাদের ডেটাসেটে সেগুলো সনাক্ত করতে হবে, তারপরে সেগুলো নিয়ে কাজ করতে হবে। \n", + "এখন যেহেতু আমরা অনুপস্থিত মানগুলোর গুরুত্ব বুঝেছি, আমাদের ডেটাসেটে সেগুলো মোকাবিলা করার আগে সনাক্ত করতে হবে। \n", "`isnull()` এবং `notnull()` উভয়ই নাল ডেটা সনাক্ত করার জন্য আপনার প্রধান পদ্ধতি। উভয়ই আপনার ডেটার উপর বুলিয়ান মাস্ক প্রদান করে।\n" ] }, @@ -978,9 +978,9 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "আউটপুটটি ভালোভাবে দেখুন। এর মধ্যে কি কিছু আপনাকে অবাক করছে? যদিও `0` একটি গাণিতিক শূন্য, এটি তবুও একটি সম্পূর্ণ সংখ্যার ভালো উদাহরণ এবং pandas এটিকে সেইভাবেই বিবেচনা করে। `''` একটু বেশি সূক্ষ্ম। আমরা এটি অধ্যায় ১-এ একটি খালি স্ট্রিং মান হিসেবে ব্যবহার করেছিলাম, তবে এটি একটি স্ট্রিং অবজেক্ট এবং pandas-এর দৃষ্টিতে এটি শূন্যের প্রতিনিধিত্ব করে না।\n", + "আউটপুটটি ভালোভাবে দেখুন। এর মধ্যে কি কিছু আপনাকে অবাক করছে? যদিও `0` একটি গাণিতিক শূন্য, এটি তবুও একটি সম্পূর্ণ ভালো পূর্ণসংখ্যা এবং pandas এটিকে সেইভাবেই বিবেচনা করে। `''` একটু বেশি সূক্ষ্ম। আমরা এটি অধ্যায় ১-এ একটি খালি স্ট্রিং মান হিসেবে ব্যবহার করেছিলাম, তবে এটি একটি স্ট্রিং অবজেক্ট এবং pandas-এর দৃষ্টিতে এটি শূন্যের প্রতিনিধিত্ব করে না।\n", "\n", - "এখন, চলুন এটি উল্টে দেখি এবং এই পদ্ধতিগুলোকে এমনভাবে ব্যবহার করি যেভাবে আপনি বাস্তবে ব্যবহার করবেন। আপনি Boolean মাস্কগুলো সরাসরি ``Series`` বা ``DataFrame`` ইনডেক্স হিসেবে ব্যবহার করতে পারেন, যা বিচ্ছিন্ন অনুপস্থিত (বা উপস্থিত) মান নিয়ে কাজ করার সময় কার্যকর হতে পারে।\n", + "এখন, চলুন এই বিষয়টি উল্টে দেখি এবং এই পদ্ধতিগুলো এমনভাবে ব্যবহার করি যেভাবে আপনি বাস্তবে এগুলো ব্যবহার করবেন। আপনি Boolean মাস্কগুলো সরাসরি ``Series`` বা ``DataFrame`` ইনডেক্স হিসেবে ব্যবহার করতে পারেন, যা বিচ্ছিন্নভাবে অনুপস্থিত (বা উপস্থিত) মান নিয়ে কাজ করার সময় কার্যকর হতে পারে।\n", "\n", "যদি আমরা অনুপস্থিত মানগুলোর মোট সংখ্যা জানতে চাই, তাহলে আমরা `isnull()` পদ্ধতির মাধ্যমে তৈরি হওয়া মাস্কের উপর একটি যোগফল করতে পারি।\n" ] @@ -1040,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**মূল কথা**: উভয় `isnull()` এবং `notnull()` পদ্ধতি DataFrame-এ ব্যবহার করলে একই ধরনের ফলাফল প্রদান করে: এগুলো ফলাফল এবং সেই ফলাফলের সূচক প্রদর্শন করে, যা আপনার ডেটা নিয়ে কাজ করার সময় আপনাকে অত্যন্ত সাহায্য করবে।\n" + "**মূল কথা**: উভয় `isnull()` এবং `notnull()` পদ্ধতি DataFrame-এ ব্যবহার করলে একই ধরনের ফলাফল প্রদান করে: এগুলো ফলাফল এবং সেই ফলাফলের সূচক দেখায়, যা আপনার ডেটা নিয়ে কাজ করার সময় আপনাকে অত্যন্ত সাহায্য করবে।\n" ] }, { @@ -1049,20 +1049,20 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### অনুপস্থিত ডেটা সামলানো\n", + "### অনুপস্থিত ডেটা মোকাবিলা করা\n", "\n", - "> **শিক্ষার লক্ষ্য:** এই উপ-অধ্যায়ের শেষে, আপনি জানতে পারবেন কীভাবে এবং কখন DataFrames থেকে শূন্য মান প্রতিস্থাপন বা সরিয়ে ফেলা যায়।\n", + "> **শিক্ষার লক্ষ্য:** এই উপ-অধ্যায়ের শেষে, আপনি জানতে পারবেন কীভাবে এবং কখন DataFrames থেকে null মান প্রতিস্থাপন বা সরানো যায়।\n", "\n", - "মেশিন লার্নিং মডেলগুলো নিজেরাই অনুপস্থিত ডেটা সামলাতে পারে না। তাই, মডেলে ডেটা পাঠানোর আগে আমাদের এই অনুপস্থিত মানগুলো সামলাতে হবে।\n", + "মেশিন লার্নিং মডেলগুলো নিজেরাই অনুপস্থিত ডেটা পরিচালনা করতে পারে না। তাই, মডেলে ডেটা পাঠানোর আগে আমাদের এই অনুপস্থিত মানগুলো মোকাবিলা করতে হবে।\n", "\n", - "অনুপস্থিত ডেটা কীভাবে সামলানো হয়, তার সঙ্গে সূক্ষ্ম সমঝোতা জড়িত থাকে, যা আপনার চূড়ান্ত বিশ্লেষণ এবং বাস্তব জীবনের ফলাফলে প্রভাব ফেলতে পারে।\n", + "অনুপস্থিত ডেটা কীভাবে পরিচালনা করা হয় তা সূক্ষ্ম ভারসাম্য বহন করে, যা আপনার চূড়ান্ত বিশ্লেষণ এবং বাস্তব জীবনের ফলাফলে প্রভাব ফেলতে পারে।\n", "\n", - "মূলত অনুপস্থিত ডেটা সামলানোর দুটি প্রধান পদ্ধতি রয়েছে:\n", + "অনুপস্থিত ডেটা মোকাবিলা করার প্রধানত দুটি উপায় রয়েছে:\n", "\n", - "1. অনুপস্থিত মান থাকা সারিটি বাদ দেওয়া\n", - "2. অনুপস্থিত মানটি অন্য কোনো মান দিয়ে প্রতিস্থাপন করা\n", + "1. অনুপস্থিত মান থাকা সারি বাদ দেওয়া\n", + "2. অনুপস্থিত মানকে অন্য কোনো মান দিয়ে প্রতিস্থাপন করা\n", "\n", - "আমরা এই দুটি পদ্ধতি এবং তাদের সুবিধা ও অসুবিধাগুলো বিস্তারিতভাবে আলোচনা করব।\n" + "আমরা এই দুটি পদ্ধতি এবং তাদের সুবিধা ও অসুবিধা বিস্তারিতভাবে আলোচনা করব।\n" ] }, { @@ -1073,11 +1073,11 @@ "source": [ "### নাল মান বাদ দেওয়া\n", "\n", - "আমাদের মডেলে যে পরিমাণ ডেটা আমরা সরবরাহ করি, তা তার কার্যক্ষমতার উপর সরাসরি প্রভাব ফেলে। নাল মান বাদ দেওয়ার অর্থ হলো আমরা ডেটাপয়েন্টের সংখ্যা কমাচ্ছি, এবং সেইসঙ্গে ডেটাসেটের আকারও কমাচ্ছি। তাই, যখন ডেটাসেট বেশ বড় হয়, তখন নাল মানযুক্ত সারি বাদ দেওয়া পরামর্শযোগ্য।\n", + "আমাদের মডেলে যে পরিমাণ ডেটা আমরা সরবরাহ করি, তা তার কার্যকারিতার উপর সরাসরি প্রভাব ফেলে। নাল মান বাদ দেওয়া মানে আমরা ডেটাপয়েন্টের সংখ্যা কমাচ্ছি, এবং সেইসঙ্গে ডেটাসেটের আকারও কমাচ্ছি। তাই, যখন ডেটাসেট বেশ বড় হয়, তখন নাল মানযুক্ত সারি বাদ দেওয়া পরামর্শযোগ্য।\n", "\n", "আরেকটি উদাহরণ হতে পারে যে কোনো নির্দিষ্ট সারি বা কলামে অনেক বেশি অনুপস্থিত মান রয়েছে। সেক্ষেত্রে, সেগুলো বাদ দেওয়া যেতে পারে কারণ সেগুলো আমাদের বিশ্লেষণে খুব বেশি মূল্য যোগ করবে না যেহেতু সেই সারি/কলামের বেশিরভাগ ডেটা অনুপস্থিত।\n", "\n", - "অনুপস্থিত মান সনাক্ত করার বাইরে, pandas `Series` এবং `DataFrame` থেকে নাল মান সরানোর একটি সুবিধাজনক উপায় প্রদান করে। এটি বাস্তবে দেখতে, চলুন `example3`-এ ফিরে যাই। `DataFrame.dropna()` ফাংশন নাল মানযুক্ত সারি বাদ দিতে সাহায্য করে।\n" + "নাল মান সনাক্ত করার বাইরে, pandas `Series` এবং `DataFrame` থেকে নাল মান সরানোর একটি সুবিধাজনক উপায় প্রদান করে। এটি বাস্তবে দেখতে, চলুন `example3`-এ ফিরে যাই। `DataFrame.dropna()` ফাংশন নাল মানযুক্ত সারি বাদ দিতে সাহায্য করে।\n" ] }, { @@ -1116,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "দ্রষ্টব্য যে এটি আপনার `example3[example3.notnull()]` এর আউটপুটের মতো দেখাবে। এখানে পার্থক্য হলো, কেবলমাত্র মাস্ক করা মানগুলোর উপর ইনডেক্সিং করার পরিবর্তে, `dropna` সেই অনুপস্থিত মানগুলোকে `Series` `example3` থেকে সরিয়ে দিয়েছে।\n", + "লক্ষ্য করুন যে এটি `example3[example3.notnull()]` এর আউটপুটের মতো দেখাবে। এখানে পার্থক্য হলো, শুধু মাস্ক করা মানগুলোর উপর ইনডেক্সিং করার পরিবর্তে, `dropna` `Series` `example3` থেকে সেই অনুপস্থিত মানগুলো সরিয়ে দিয়েছে।\n", "\n", - "যেহেতু DataFrame-গুলোর দুটি মাত্রা রয়েছে, তাই ডেটা বাদ দেওয়ার জন্য এগুলো আরও বেশি বিকল্প প্রদান করে।\n" + "কারণ DataFrames-এর দুটি মাত্রা থাকে, এটি ডেটা বাদ দেওয়ার জন্য আরও বিকল্প প্রদান করে।\n" ] }, { @@ -1208,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(আপনি কি লক্ষ্য করেছেন যে pandas দুটি কলামকে `NaN` এর কারণে ফ্লোটে আপকাস্ট করেছে?)\n", + "(আপনি কি লক্ষ্য করেছেন যে pandas দুটি কলামকে `NaN` মানগুলোর জন্য ফ্লোটে আপকাস্ট করেছে?)\n", "\n", - "আপনি একটি `DataFrame` থেকে একটি একক মান বাদ দিতে পারবেন না, তাই আপনাকে সম্পূর্ণ সারি বা কলাম বাদ দিতে হবে। আপনি কী করছেন তার উপর নির্ভর করে, আপনি একটির পরিবর্তে অন্যটি করতে চাইতে পারেন, এবং তাই pandas আপনাকে উভয়ের জন্য বিকল্প দেয়। কারণ ডেটা সায়েন্সে, কলাম সাধারণত ভেরিয়েবল এবং সারি পর্যবেক্ষণকে উপস্থাপন করে, আপনি সম্ভবত ডেটার সারি বাদ দিতে চাইবেন; `dropna()` এর ডিফল্ট সেটিং হল সমস্ত সারি বাদ দেওয়া যা কোনো null মান ধারণ করে:\n" + "আপনি `DataFrame` থেকে একটি একক মান বাদ দিতে পারবেন না, তাই আপনাকে সম্পূর্ণ সারি বা কলাম বাদ দিতে হবে। আপনি কী করছেন তার উপর নির্ভর করে, আপনি একটির পরিবর্তে অন্যটি করতে চাইতে পারেন, এবং তাই pandas আপনাকে উভয়ের জন্য বিকল্প দেয়। কারণ ডেটা সায়েন্সে, কলাম সাধারণত ভেরিয়েবল এবং সারি পর্যবেক্ষণকে উপস্থাপন করে, আপনি সম্ভবত ডেটার সারি বাদ দিতে চাইবেন; `dropna()`-এর ডিফল্ট সেটিং হল যেকোনো null মান থাকা সমস্ত সারি বাদ দেওয়া:\n" ] }, { @@ -1362,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "লক্ষ্য করুন যে এটি অনেক ডেটা বাদ দিতে পারে যা আপনি হয়তো রাখতে চাইবেন, বিশেষত ছোট ডেটাসেটে। যদি আপনি কেবল এমন সারি বা কলাম বাদ দিতে চান যেগুলিতে কয়েকটি বা এমনকি সব null মান রয়েছে? আপনি `dropna`-তে `how` এবং `thresh` প্যারামিটার দিয়ে এই সেটিং নির্ধারণ করতে পারেন।\n", + "লক্ষ্য করুন যে এটি অনেক ডেটা বাদ দিতে পারে যা আপনি রাখতে চাইতে পারেন, বিশেষত ছোট ডেটাসেটে। যদি আপনি শুধুমাত্র সেই সারি বা কলাম বাদ দিতে চান যেখানে বেশ কয়েকটি বা এমনকি সব null মান রয়েছে? আপনি `dropna`-তে `how` এবং `thresh` প্যারামিটার ব্যবহার করে এই সেটিং নির্ধারণ করতে পারেন।\n", "\n", - "ডিফল্টভাবে, `how='any'` (যদি আপনি নিজে পরীক্ষা করতে চান বা দেখতে চান যে এই মেথডের অন্য কী প্যারামিটার রয়েছে, তাহলে একটি কোড সেলে `example4.dropna?` চালান)। আপনি বিকল্পভাবে `how='all'` নির্ধারণ করতে পারেন, যাতে কেবল সেই সারি বা কলাম বাদ দেওয়া হয় যেগুলিতে সব null মান রয়েছে। চলুন আমাদের উদাহরণ `DataFrame` প্রসারিত করি এবং এটি পরবর্তী অনুশীলনে কার্যকরভাবে দেখি।\n" + "ডিফল্টভাবে, `how='any'` (যদি আপনি নিজে পরীক্ষা করতে চান বা দেখতে চান এই মেথডের অন্য কোন প্যারামিটার রয়েছে, তাহলে একটি কোড সেলে `example4.dropna?` চালান)। আপনি বিকল্পভাবে `how='all'` নির্ধারণ করতে পারেন যাতে শুধুমাত্র সেই সারি বা কলাম বাদ দেওয়া হয় যেখানে সব null মান রয়েছে। চলুন আমাদের উদাহরণ `DataFrame` প্রসারিত করি এবং পরবর্তী অনুশীলনে এটি কার্যকরভাবে দেখি।\n" ] }, { @@ -1456,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> মূল বিষয়গুলো:\n", - "1. শুধুমাত্র তখনই null মান বাদ দেওয়া উচিত যদি ডেটাসেট যথেষ্ট বড় হয়।\n", - "2. পুরো সারি বা কলাম বাদ দেওয়া যেতে পারে যদি তাদের বেশিরভাগ ডেটা অনুপস্থিত থাকে।\n", - "3. `DataFrame.dropna(axis=)` মেথডটি null মান বাদ দিতে সাহায্য করে। এখানে `axis` আর্গুমেন্টটি নির্দেশ করে যে সারি বাদ দেওয়া হবে নাকি কলাম।\n", - "4. `how` আর্গুমেন্টটিও ব্যবহার করা যেতে পারে। ডিফল্টভাবে এটি `any` তে সেট করা থাকে। তাই এটি শুধুমাত্র সেই সারি/কলাম বাদ দেয় যেখানে কোনো null মান থাকে। এটি `all` এ সেট করা যেতে পারে, যা নির্দেশ করে যে শুধুমাত্র সেই সারি/কলাম বাদ দেওয়া হবে যেখানে সব মান null।\n" + "> মূল বিষয়সমূহ:\n", + "1. ডেটাসেট যথেষ্ট বড় হলে তবেই null মান বাদ দেওয়া ভালো।\n", + "2. সম্পূর্ণ সারি বা কলাম বাদ দেওয়া যেতে পারে যদি তাদের বেশিরভাগ ডেটা অনুপস্থিত থাকে।\n", + "3. `DataFrame.dropna(axis=)` মেথড null মান বাদ দিতে সাহায্য করে। `axis` আর্গুমেন্ট নির্দেশ করে সারি বাদ দেওয়া হবে নাকি কলাম।\n", + "4. `how` আর্গুমেন্টও ব্যবহার করা যেতে পারে। ডিফল্টভাবে এটি `any` সেট করা থাকে। তাই এটি শুধুমাত্র সেই সারি/কলাম বাদ দেয় যেখানে কোনো null মান থাকে। এটি `all` এ সেট করা যেতে পারে, যা নির্দেশ করে যে আমরা শুধুমাত্র সেই সারি/কলাম বাদ দেব যেখানে সব মান null।\n" ] }, { @@ -1492,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "`thresh` প্যারামিটার আপনাকে আরও সূক্ষ্ম নিয়ন্ত্রণ দেয়: আপনি সেট করেন একটি সারি বা কলামে *অ-শূন্য* মানের সংখ্যা যা ধরে রাখার জন্য প্রয়োজন।\n" + "`thresh` প্যারামিটার আপনাকে সূক্ষ্ম-স্তরের নিয়ন্ত্রণ দেয়: আপনি সেট করেন একটি সারি বা কলামে *অ-শূন্য* মানের সংখ্যা যা থাকা প্রয়োজন যাতে তা সংরক্ষিত হয়:\n" ] }, { @@ -1578,9 +1578,9 @@ "source": [ "### নাল মান পূরণ করা\n", "\n", - "কখনও কখনও অনুপস্থিত মানগুলো এমন মান দিয়ে পূরণ করা যৌক্তিক হতে পারে যা বৈধ হতে পারে। নাল মান পূরণের জন্য কিছু কৌশল রয়েছে। প্রথমটি হলো ডোমেইন জ্ঞান (ডেটাসেট যে বিষয়ের উপর ভিত্তি করে তৈরি, সেই বিষয়ের জ্ঞান) ব্যবহার করে কোনোভাবে অনুপস্থিত মানগুলো অনুমান করা। \n", + "কখনও কখনও অনুপস্থিত মানগুলি এমন মান দিয়ে পূরণ করা যুক্তিসঙ্গত হতে পারে যা বৈধ হতে পারে। নাল মান পূরণের জন্য কয়েকটি কৌশল রয়েছে। প্রথমটি হল ডোমেইন জ্ঞান (ডেটাসেটের ভিত্তি যে বিষয়টি নিয়ে তা সম্পর্কে জ্ঞান) ব্যবহার করে অনুপস্থিত মানগুলি আনুমানিকভাবে পূরণ করা। \n", "\n", - "আপনি `isnull` ব্যবহার করে এটি সরাসরি করতে পারেন, তবে এটি সময়সাপেক্ষ হতে পারে, বিশেষত যদি অনেক মান পূরণ করতে হয়। যেহেতু এটি ডেটা সায়েন্সে একটি সাধারণ কাজ, pandas `fillna` প্রদান করে, যা একটি `Series` বা `DataFrame`-এর কপি ফেরত দেয় যেখানে অনুপস্থিত মানগুলো আপনার পছন্দমতো মান দিয়ে প্রতিস্থাপিত হয়। চলুন আরেকটি উদাহরণ `Series` তৈরি করি এবং দেখি এটি বাস্তবে কীভাবে কাজ করে।\n" + "আপনি `isnull` ব্যবহার করে এটি সরাসরি করতে পারেন, তবে এটি শ্রমসাধ্য হতে পারে, বিশেষত যদি আপনার অনেক মান পূরণ করতে হয়। যেহেতু এটি ডেটা সায়েন্সে একটি সাধারণ কাজ, pandas `fillna` প্রদান করে, যা একটি `Series` বা `DataFrame`-এর কপি প্রদান করে যেখানে অনুপস্থিত মানগুলি আপনার পছন্দমতো মান দিয়ে প্রতিস্থাপিত হয়। চলুন আরেকটি উদাহরণ `Series` তৈরি করি এবং দেখি এটি বাস্তবে কীভাবে কাজ করে।\n" ] }, { @@ -1589,12 +1589,12 @@ "id": "CE8S7louLezV" }, "source": [ - "### শ্রেণীবদ্ধ ডেটা (অ-সংখ্যাসূচক)\n", - "প্রথমে আমরা অ-সংখ্যাসূচক ডেটা নিয়ে আলোচনা করি। ডেটাসেটে, আমাদের কাছে শ্রেণীবদ্ধ ডেটা সহ কলাম থাকে। যেমন: লিঙ্গ, সত্য বা মিথ্যা ইত্যাদি।\n", + "### শ্রেণীবদ্ধ ডেটা (অসংখ্যিক)\n", + "প্রথমে আসুন অসংখ্যিক ডেটা নিয়ে আলোচনা করি। ডেটাসেটে, আমাদের কাছে এমন কলাম থাকে যেখানে শ্রেণীবদ্ধ ডেটা থাকে। যেমন, লিঙ্গ, সত্য বা মিথ্যা ইত্যাদি।\n", "\n", - "এই ধরনের ক্ষেত্রে, আমরা সাধারণত কলামের `mode` দিয়ে অনুপস্থিত মানগুলো পূরণ করি। ধরুন, আমাদের কাছে ১০০টি ডেটা পয়েন্ট আছে, যার মধ্যে ৯০টি \"সত্য\" বলেছে, ৮টি \"মিথ্যা\" বলেছে এবং ২টি পূরণ করা হয়নি। তাহলে, আমরা পুরো কলাম বিবেচনা করে সেই ২টি \"সত্য\" দিয়ে পূরণ করতে পারি।\n", + "এই ধরনের ক্ষেত্রে, আমরা সাধারণত অনুপস্থিত মানগুলো কলামের `mode` দিয়ে পূরণ করি। ধরুন, আমাদের কাছে ১০০টি ডেটা পয়েন্ট আছে, যার মধ্যে ৯০টি \"True\" বলেছে, ৮টি \"False\" বলেছে এবং ২টি পূরণ করা হয়নি। তাহলে, আমরা পুরো কলামটি বিবেচনা করে সেই ২টি \"True\" দিয়ে পূরণ করতে পারি।\n", "\n", - "আবার, এখানে আমরা ডোমেইন জ্ঞান ব্যবহার করতে পারি। চলুন একটি উদাহরণ দেখি যেখানে `mode` দিয়ে পূরণ করা হয়েছে।\n" + "এখানে আবার আমরা ডোমেইন জ্ঞান ব্যবহার করতে পারি। আসুন, mode দিয়ে পূরণের একটি উদাহরণ বিবেচনা করি।\n" ] }, { @@ -1699,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "এখন, প্রথমে মোডটি খুঁজে বের করি তারপরে `None` মানটি মোড দিয়ে পূরণ করি।\n" + ] }, { "cell_type": "code", @@ -1734,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "তাহলে, আমরা None এর পরিবর্তে True ব্যবহার করব।\n" + ] }, { "cell_type": "code", @@ -1854,16 +1858,16 @@ }, "source": [ "### সংখ্যাগত ডেটা\n", - "এখন, সংখ্যাগত ডেটার দিকে আসা যাক। এখানে, অনুপস্থিত মান প্রতিস্থাপনের দুটি সাধারণ পদ্ধতি রয়েছে:\n", + "এখন, সংখ্যাগত ডেটার ক্ষেত্রে আসা যাক। এখানে, অনুপস্থিত মান প্রতিস্থাপনের দুটি সাধারণ পদ্ধতি রয়েছে:\n", "\n", "1. সারির মধ্যম (Median) দিয়ে প্রতিস্থাপন\n", "2. সারির গড় (Mean) দিয়ে প্রতিস্থাপন\n", "\n", - "যখন ডেটা আউটলাইয়ারসহ তির্যক (skewed) হয়, তখন আমরা মধ্যম দিয়ে প্রতিস্থাপন করি। কারণ মধ্যম আউটলাইয়ারের প্রতি সংবেদনশীল নয়।\n", + "যখন ডেটা আউটলাইয়ারসহ বক্ররেখা (skewed) হয়, তখন আমরা মধ্যম দিয়ে প্রতিস্থাপন করি। কারণ মধ্যম আউটলাইয়ারগুলোর প্রতি সংবেদনশীল নয়।\n", "\n", "যখন ডেটা স্বাভাবিকীকৃত হয়, তখন আমরা গড় ব্যবহার করতে পারি, কারণ সেই ক্ষেত্রে গড় এবং মধ্যম প্রায় কাছাকাছি থাকে।\n", "\n", - "প্রথমে, চলুন একটি কলাম নিই যা স্বাভাবিকভাবে বিতরণ করা হয়েছে এবং কলামের গড় দিয়ে অনুপস্থিত মান পূরণ করি।\n" + "প্রথমে, আমরা একটি কলাম নেব যা স্বাভাবিকভাবে বিতরণ করা হয়েছে এবং সেই কলামের অনুপস্থিত মান গড় দিয়ে পূরণ করব।\n" ] }, { @@ -1969,7 +1973,7 @@ "id": "ka7-wNfzSxbx" }, "source": [ - "কলামের গড় হল\n" + "কলামের গড় হলো\n" ] }, { @@ -2003,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "মধ্যমান দিয়ে পূরণ করা\n" + ] }, { "cell_type": "code", @@ -2103,7 +2109,7 @@ "id": "CwpVFCrPTC5z" }, "source": [ - "যেমন আমরা দেখতে পাচ্ছি, অনুপস্থিত মানটি তার গড় দিয়ে প্রতিস্থাপিত হয়েছে।\n" + "যেমনটি আমরা দেখতে পাচ্ছি, অনুপস্থিত মানটি তার গড় দিয়ে প্রতিস্থাপিত হয়েছে।\n" ] }, { @@ -2112,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "এবার আসুন আমরা আরেকটি ডেটাফ্রেম চেষ্টা করি, এবং এইবার আমরা None মানগুলোকে কলামের মধ্যম মান দিয়ে প্রতিস্থাপন করব।\n" + "এবার চলুন আমরা আরেকটি ডেটাফ্রেম চেষ্টা করি, এবং এইবার আমরা None মানগুলো কলামের মধ্যম মান দিয়ে প্রতিস্থাপন করব।\n" ] }, { @@ -2218,7 +2224,7 @@ "id": "mM1GpXYmjHnc" }, "source": [ - "দ্বিতীয় কলামের মধ্যমা হল\n" + "দ্বিতীয় কলামের মধ্যম মান হল\n" ] }, { @@ -2354,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "যেমনটি আমরা দেখতে পাচ্ছি, NaN মানটি কলামের মধ্যম দ্বারা প্রতিস্থাপিত হয়েছে\n" + "যেমন আমরা দেখতে পাচ্ছি, NaN মানটি কলামের মধ্যমান দ্বারা প্রতিস্থাপিত হয়েছে।\n" ] }, { @@ -2438,8 +2444,8 @@ }, "source": [ "> মূল বিষয়সমূহ:\n", - "1. অনুপস্থিত মান পূরণ করা উচিত যখন ডেটা কম থাকে বা অনুপস্থিত ডেটা পূরণের জন্য একটি কৌশল থাকে।\n", - "2. ডোমেইন জ্ঞান ব্যবহার করে অনুপস্থিত মান আনুমানিকভাবে পূরণ করা যেতে পারে।\n", + "1. অনুপস্থিত মান পূরণ করা উচিত যখন ডেটা কম থাকে বা অনুপস্থিত ডেটা পূরণের জন্য কোনো কৌশল থাকে।\n", + "2. ডোমেইন জ্ঞান ব্যবহার করে আনুমানিকভাবে অনুপস্থিত মান পূরণ করা যেতে পারে।\n", "3. শ্রেণীবদ্ধ ডেটার ক্ষেত্রে, সাধারণত অনুপস্থিত মান কলামের মোড দিয়ে প্রতিস্থাপন করা হয়।\n", "4. সংখ্যাসূচক ডেটার ক্ষেত্রে, অনুপস্থিত মান সাধারণত কলামের গড় (স্বাভাবিককৃত ডেটাসেটের জন্য) বা মধ্যমা দিয়ে পূরণ করা হয়।\n" ] @@ -2472,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "আপনি **forward-fill** পদ্ধতিতে null মান পূরণ করতে পারেন, যা হল শেষ বৈধ মানটি ব্যবহার করে null পূরণ করা:\n" + "আপনি **ফরওয়ার্ড-ফিল** null মানগুলি করতে পারেন, যা হল শেষ বৈধ মানটি ব্যবহার করে null পূরণ করা:\n" ] }, { @@ -2513,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "আপনি এছাড়াও **ব্যাক-ফিল** ব্যবহার করে একটি শূন্যস্থান পূরণের জন্য পরবর্তী বৈধ মানটি পিছনের দিকে প্রচার করতে পারেন:\n" + "আপনি **ব্যাক-ফিল** ব্যবহার করে null পূরণের জন্য পরবর্তী বৈধ মানকে পিছনের দিকে প্রসারিত করতে পারেন:\n" ] }, { @@ -2555,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "যেমন আপনি অনুমান করতে পারেন, এটি DataFrames এর সাথে একইভাবে কাজ করে, তবে আপনি null মান পূরণ করার জন্য একটি `axis` নির্দিষ্ট করতে পারেন:\n" + "আপনি যেমন অনুমান করতে পারেন, এটি DataFrames-এর ক্ষেত্রেও একইভাবে কাজ করে, তবে আপনি null মান পূরণ করার জন্য একটি `axis` নির্দিষ্ট করতে পারেন:\n" ] }, { @@ -2728,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "যখন একটি পূর্ববর্তী মান ফরোয়ার্ড-ফিলিংয়ের জন্য উপলব্ধ নয়, তখন শূন্য মানটি রয়ে যায়।\n" + "যখন পূর্ববর্তী মান ফরওয়ার্ড-ফিলিংয়ের জন্য উপলব্ধ নয়, লক্ষ্য করুন যে শূন্য মানটি অপরিবর্তিত থাকে।\n" ] }, { @@ -2761,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "আপনি `fillna` ব্যবহার করার ক্ষেত্রে সৃজনশীল হতে পারেন। উদাহরণস্বরূপ, আসুন আবার `example4` এর দিকে তাকাই, তবে এবার চলুন অনুপস্থিত মানগুলোকে `DataFrame`-এর সমস্ত মানের গড় দিয়ে পূরণ করি:\n" + "আপনি `fillna` ব্যবহার করার ক্ষেত্রে সৃজনশীল হতে পারেন। উদাহরণস্বরূপ, চলুন আবার `example4` এর দিকে তাকাই, তবে এবার চলুন `DataFrame`-এর সমস্ত মানের গড় দিয়ে অনুপস্থিত মানগুলি পূরণ করি:\n" ] }, { @@ -2852,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "লক্ষ্য করুন যে তৃতীয় কলাম এখনও শূন্য: ডিফল্ট দিক হলো সারি অনুযায়ী মান পূরণ করা।\n", + "লক্ষ্য করুন যে কলাম ৩ এখনও খালি রয়েছে: ডিফল্ট নির্দেশনা হল সারি অনুযায়ী মান পূরণ করা।\n", "\n", - "> **মূল কথা:** আপনার ডেটাসেটে অনুপস্থিত মানগুলোর সাথে মোকাবিলা করার বিভিন্ন উপায় রয়েছে। আপনি যে নির্দিষ্ট কৌশল ব্যবহার করবেন (তাদের সরিয়ে ফেলা, প্রতিস্থাপন করা, বা কীভাবে প্রতিস্থাপন করবেন) তা সেই ডেটার বিশেষত্ব দ্বারা নির্ধারিত হওয়া উচিত। আপনি যত বেশি ডেটাসেট পরিচালনা করবেন এবং তাদের সাথে কাজ করবেন, অনুপস্থিত মানগুলোর সাথে কীভাবে মোকাবিলা করতে হবে তা সম্পর্কে আরও ভালো ধারণা তৈরি করবেন।\n" + "> **মূল কথা:** আপনার ডেটাসেটে অনুপস্থিত মানগুলি মোকাবিলা করার বিভিন্ন উপায় রয়েছে। আপনি যে নির্দিষ্ট কৌশলটি ব্যবহার করবেন (সেগুলি সরানো, প্রতিস্থাপন করা, বা কীভাবে প্রতিস্থাপন করবেন) তা সেই ডেটার নির্দিষ্ট বৈশিষ্ট্যের উপর নির্ভর করবে। আপনি যত বেশি ডেটাসেট পরিচালনা করবেন এবং এর সাথে কাজ করবেন, অনুপস্থিত মানগুলি মোকাবিলা করার ক্ষেত্রে তত বেশি দক্ষতা অর্জন করবেন।\n" ] }, { @@ -2878,7 +2884,7 @@ "source": [ "**লেবেল এনকোডিং**\n", "\n", - "লেবেল এনকোডিং মূলত প্রতিটি ক্যাটাগরিকে একটি সংখ্যা হিসেবে রূপান্তরিত করা। উদাহরণস্বরূপ, ধরুন আমাদের কাছে একটি এয়ারলাইন যাত্রীদের ডেটাসেট রয়েছে এবং সেখানে একটি কলাম আছে যা তাদের ক্লাস নির্দেশ করে ['বিজনেস ক্লাস', 'ইকোনমি ক্লাস', 'ফার্স্ট ক্লাস'] এর মধ্যে। যদি লেবেল এনকোডিং করা হয়, এটি [0,1,2] এ রূপান্তরিত হবে। চলুন কোডের মাধ্যমে একটি উদাহরণ দেখি। যেহেতু আমরা পরবর্তী নোটবুকে `scikit-learn` শিখব, তাই এখানে এটি ব্যবহার করব না।\n" + "লেবেল এনকোডিং মূলত প্রতিটি ক্যাটাগরিকে একটি সংখ্যা হিসেবে রূপান্তরিত করা। উদাহরণস্বরূপ, ধরুন আমাদের কাছে একটি এয়ারলাইন যাত্রীদের ডেটাসেট রয়েছে এবং সেখানে একটি কলাম আছে যা তাদের ক্লাস নির্দেশ করে ['বিজনেস ক্লাস', 'ইকোনমি ক্লাস', 'ফার্স্ট ক্লাস'] এর মধ্যে। যদি লেবেল এনকোডিং করা হয়, তাহলে এটি [0,1,2] এ রূপান্তরিত হবে। চলুন কোডের মাধ্যমে একটি উদাহরণ দেখি। যেহেতু আমরা পরবর্তী নোটবুকে `scikit-learn` শিখব, তাই এখানে এটি ব্যবহার করব না।\n" ] }, { @@ -3089,8 +3095,8 @@ }, "source": [ "যেমন আমরা দেখতে পাচ্ছি, আউটপুটটি আমাদের প্রত্যাশার সাথে মিলে গেছে। তাহলে, লেবেল এনকোডিং কখন ব্যবহার করা হয়? লেবেল এনকোডিং নিম্নলিখিত যেকোনো একটি বা উভয় ক্ষেত্রে ব্যবহার করা হয়:\n", - "1. যখন ক্যাটেগরির সংখ্যা অনেক বেশি হয়\n", - "2. যখন ক্যাটেগরিগুলি একটি নির্দিষ্ট ক্রমে থাকে।\n" + "1. যখন ক্যাটাগরির সংখ্যা বেশি হয়\n", + "2. যখন ক্যাটাগরিগুলি ক্রমানুসারে থাকে।\n" ] }, { @@ -3101,9 +3107,9 @@ "source": [ "**ওয়ান হট এনকোডিং**\n", "\n", - "আরেক ধরনের এনকোডিং হলো ওয়ান হট এনকোডিং। এই ধরনের এনকোডিংয়ে, একটি কলামের প্রতিটি ক্যাটেগরি আলাদা কলাম হিসেবে যুক্ত হয় এবং প্রতিটি ডেটাপয়েন্ট ০ বা ১ পায় এই ভিত্তিতে যে সেটি সেই ক্যাটেগরিটি ধারণ করে কিনা। সুতরাং, যদি n সংখ্যক ভিন্ন ক্যাটেগরি থাকে, তাহলে n সংখ্যক কলাম ডেটাফ্রেমে যোগ হবে।\n", + "ওয়ান হট এনকোডিং একটি ভিন্ন ধরনের এনকোডিং। এই পদ্ধতিতে, কলামের প্রতিটি ক্যাটাগরি আলাদা একটি কলাম হিসেবে যুক্ত হয় এবং প্রতিটি ডেটাপয়েন্ট 0 বা 1 পায় এই ভিত্তিতে যে সেটি সেই ক্যাটাগরি ধারণ করে কিনা। সুতরাং, যদি nটি ভিন্ন ক্যাটাগরি থাকে, তাহলে nটি কলাম ডেটাফ্রেমে যোগ করা হবে।\n", "\n", - "উদাহরণস্বরূপ, চলুন আগের বিমান শ্রেণির উদাহরণটি দেখি। ক্যাটেগরিগুলো ছিল: ['business class', 'economy class', 'first class']। সুতরাং, যদি আমরা ওয়ান হট এনকোডিং করি, তাহলে ডেটাসেটে নিম্নলিখিত তিনটি কলাম যুক্ত হবে: ['class_business class', 'class_economy class', 'class_first class']।\n" + "উদাহরণস্বরূপ, চলুন আমরা আগের বিমান শ্রেণির উদাহরণটি দেখি। ক্যাটাগরিগুলো ছিল: ['business class', 'economy class', 'first class']। সুতরাং, যদি আমরা ওয়ান হট এনকোডিং করি, তাহলে ডেটাসেটে নিম্নলিখিত তিনটি কলাম যুক্ত হবে: ['class_business class', 'class_economy class', 'class_first class']।\n" ] }, { @@ -3211,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "চলুন প্রথম কলামে এক হট এনকোডিং সম্পাদন করি\n" + "চলুন প্রথম কলামে এক হট এনকোডিং সম্পন্ন করি।\n" ] }, { @@ -3336,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "প্রতিটি হট এনকোডেড কলামে 0 বা 1 থাকে, যা নির্ধারণ করে যে সেই বিভাগটি সেই ডেটাপয়েন্টের জন্য বিদ্যমান কিনা।\n" + "প্রতিটি হট এনকোডেড কলামে 0 বা 1 থাকে, যা নির্ধারণ করে যে সেই ক্যাটাগরি সেই ডেটাপয়েন্টের জন্য বিদ্যমান কিনা।\n" ] }, { @@ -3345,10 +3351,10 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "এক হট এনকোডিং কখন ব্যবহার করা হয়? এক হট এনকোডিং নিম্নলিখিত যেকোনো একটি বা উভয় ক্ষেত্রে ব্যবহার করা হয়:\n", + "কখন আমরা ওয়ান হট এনকোডিং ব্যবহার করি? ওয়ান হট এনকোডিং নিম্নলিখিত যেকোনো একটি বা উভয় ক্ষেত্রে ব্যবহার করা হয়:\n", "\n", - "1. যখন ক্যাটেগরির সংখ্যা এবং ডেটাসেটের আকার ছোট হয়।\n", - "2. যখন ক্যাটেগরিগুলোর মধ্যে কোনো নির্দিষ্ট ক্রম থাকে না।\n" + "1. যখন ক্যাটাগরির সংখ্যা এবং ডেটাসেটের আকার ছোট হয়।\n", + "2. যখন ক্যাটাগরিগুলোর মধ্যে কোনো নির্দিষ্ট ক্রম থাকে না।\n" ] }, { @@ -3358,8 +3364,8 @@ }, "source": [ "> মূল বিষয়সমূহ:\n", - "1. এনকোডিং ব্যবহার করা হয় অ-সংখ্যাসূচক ডেটাকে সংখ্যাসূচক ডেটায় রূপান্তর করার জন্য।\n", - "2. এনকোডিংয়ের দুই ধরনের পদ্ধতি রয়েছে: লেবেল এনকোডিং এবং ওয়ান হট এনকোডিং, যা ডেটাসেটের প্রয়োজন অনুযায়ী প্রয়োগ করা যেতে পারে।\n" + "1. এনকোডিং ব্যবহার করা হয় অ-সংখ্যাগত ডেটাকে সংখ্যাগত ডেটায় রূপান্তর করার জন্য।\n", + "2. এনকোডিংয়ের দুটি ধরন রয়েছে: লেবেল এনকোডিং এবং ওয়ান হট এনকোডিং, যা ডেটাসেটের প্রয়োজন অনুযায়ী সম্পন্ন করা যেতে পারে।\n" ] }, { @@ -3368,11 +3374,11 @@ "id": "K8UXOJYRgRsJ" }, "source": [ - "## ডুপ্লিকেট ডেটা সরানো\n", + "## ডুপ্লিকেট ডেটা অপসারণ\n", "\n", - "> **শিক্ষার লক্ষ্য:** এই উপ-অধ্যায়ের শেষে, আপনি DataFrames থেকে ডুপ্লিকেট মান সনাক্ত এবং সরাতে স্বাচ্ছন্দ্যবোধ করবেন।\n", + "> **শিক্ষার লক্ষ্য:** এই উপ-অংশের শেষে, আপনি DataFrames থেকে ডুপ্লিকেট মান সনাক্ত এবং অপসারণ করতে স্বাচ্ছন্দ্যবোধ করবেন।\n", "\n", - "অনুপস্থিত ডেটার পাশাপাশি, বাস্তব জীবনের ডেটাসেটে প্রায়ই ডুপ্লিকেট ডেটার সম্মুখীন হতে হয়। সৌভাগ্যবশত, pandas ডুপ্লিকেট এন্ট্রি সনাক্ত এবং সরানোর একটি সহজ উপায় প্রদান করে।\n" + "অনুপস্থিত ডেটার পাশাপাশি, বাস্তব জীবনের ডেটাসেটে আপনি প্রায়ই ডুপ্লিকেট ডেটার সম্মুখীন হবেন। সৌভাগ্যক্রমে, pandas ডুপ্লিকেট এন্ট্রি সনাক্ত এবং অপসারণের একটি সহজ উপায় প্রদান করে।\n" ] }, { @@ -3381,9 +3387,9 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### ডুপ্লিকেট সনাক্ত করা: `duplicated`\n", + "### ডুপ্লিকেট শনাক্ত করা: `duplicated`\n", "\n", - "আপনি সহজেই ডুপ্লিকেট মানগুলো সনাক্ত করতে পারেন pandas-এর `duplicated` মেথড ব্যবহার করে, যা একটি বুলিয়ান মাস্ক প্রদান করে যা নির্দেশ করে যে একটি `DataFrame`-এর কোনো এন্ট্রি আগের একটি এন্ট্রির ডুপ্লিকেট কিনা। চলুন এটি কার্যকরভাবে দেখার জন্য আরেকটি উদাহরণ `DataFrame` তৈরি করি।\n" + "আপনি সহজেই ডুপ্লিকেট মানগুলো শনাক্ত করতে পারেন pandas-এর `duplicated` মেথড ব্যবহার করে, যা একটি বুলিয়ান মাস্ক প্রদান করে যা নির্দেশ করে যে একটি `DataFrame`-এর কোনো এন্ট্রি আগের একটি এন্ট্রির ডুপ্লিকেট কিনা। চলুন এটি কার্যকরভাবে দেখার জন্য আরেকটি উদাহরণ `DataFrame` তৈরি করি।\n" ] }, { @@ -3513,7 +3519,7 @@ }, "source": [ "### ডুপ্লিকেট সরানো: `drop_duplicates`\n", - "`drop_duplicates` কেবল সেই ডেটার একটি কপি প্রদান করে যার জন্য সমস্ত `duplicated` মান `False`:\n" + "`drop_duplicates` সহজভাবে সেই ডেটার একটি কপি প্রদান করে যেখানে সমস্ত `duplicated` মান `False`:\n" ] }, { @@ -3680,7 +3686,523 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**অস্বীকৃতি**: \nএই নথিটি AI অনুবাদ পরিষেবা [Co-op Translator](https://github.com/Azure/co-op-translator) ব্যবহার করে অনুবাদ করা হয়েছে। আমরা যথাসাধ্য সঠিক অনুবাদের চেষ্টা করি, তবে দয়া করে মনে রাখবেন যে স্বয়ংক্রিয় অনুবাদে ত্রুটি বা অসঙ্গতি থাকতে পারে। নথিটির মূল ভাষায় থাকা সংস্করণটিকেই প্রামাণিক উৎস হিসেবে বিবেচনা করা উচিত। গুরুত্বপূর্ণ তথ্যের জন্য, পেশাদার মানব অনুবাদ সুপারিশ করা হয়। এই অনুবাদ ব্যবহারের ফলে সৃষ্ট কোনো ভুল বোঝাবুঝি বা ভুল ব্যাখ্যার জন্য আমরা দায়ী নই।\n" + "## বাস্তব-জগতের ডেটা গুণগত মান যাচাই\n", + "\n", + "> **শিক্ষার লক্ষ্য:** এই অংশের শেষে, আপনি বাস্তব-জগতের ডেটার সাধারণ গুণগত মানের সমস্যাগুলি সনাক্ত এবং সংশোধন করতে স্বাচ্ছন্দ্যবোধ করবেন, যার মধ্যে রয়েছে অসঙ্গতিপূর্ণ শ্রেণীবিভাগ মান, অস্বাভাবিক সংখ্যাসূচক মান (আউটলায়ার), এবং সামান্য পরিবর্তন সহ ডুপ্লিকেট সত্তা।\n", + "\n", + "যদিও অনুপস্থিত মান এবং সঠিক ডুপ্লিকেট সাধারণ সমস্যা, বাস্তব-জগতের ডেটাসেটে প্রায়ই আরও সূক্ষ্ম সমস্যাগুলি থাকে:\n", + "\n", + "1. **অসঙ্গতিপূর্ণ শ্রেণীবিভাগ মান**: একই শ্রেণী বিভিন্নভাবে লেখা (যেমন, \"USA\", \"U.S.A\", \"United States\")\n", + "2. **অস্বাভাবিক সংখ্যাসূচক মান**: চরম আউটলায়ার যা ডেটা এন্ট্রি ত্রুটি নির্দেশ করে (যেমন, বয়স = 999)\n", + "3. **প্রায়-ডুপ্লিকেট সারি**: রেকর্ড যা সামান্য পরিবর্তনের সাথে একই সত্তাকে উপস্থাপন করে\n", + "\n", + "এসব সমস্যাগুলি সনাক্ত এবং পরিচালনা করার কৌশলগুলি আমরা এখন অন্বেষণ করব।\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### একটি নমুনা \"অগোছালো\" ডেটাসেট তৈরি করা\n", + "\n", + "প্রথমে, চলুন একটি নমুনা ডেটাসেট তৈরি করি যা বাস্তব জীবনের ডেটাতে আমরা সাধারণত যে ধরণের সমস্যাগুলোর সম্মুখীন হই তা ধারণ করে:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ১. অসঙ্গত শ্রেণীবদ্ধ মান সনাক্ত করা\n", + "\n", + "লক্ষ করুন যে `country` কলামে একই দেশের জন্য একাধিক উপস্থাপনা রয়েছে। চলুন এই অসঙ্গতিগুলো সনাক্ত করি:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### শ্রেণীবদ্ধ মানগুলিকে মানসম্মত করা\n", + "\n", + "আমরা একটি ম্যাপিং তৈরি করে এই মানগুলোকে মানসম্মত করতে পারি। একটি সহজ পদ্ধতি হলো ছোট হাতের অক্ষরে রূপান্তর করা এবং একটি ম্যাপিং ডিকশনারি তৈরি করা:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**বিকল্প: ফাজি ম্যাচিং ব্যবহার করা**\n", + "\n", + "আরও জটিল ক্ষেত্রে, আমরা `rapidfuzz` লাইব্রেরি ব্যবহার করে ফাজি স্ট্রিং ম্যাচিং করতে পারি, যা স্বয়ংক্রিয়ভাবে অনুরূপ স্ট্রিং সনাক্ত করতে সাহায্য করে:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. অস্বাভাবিক সংখ্যাগত মান (আউটলায়ার) সনাক্ত করা\n", + "\n", + "`age` কলামটি দেখলে, আমরা কিছু সন্দেহজনক মান যেমন ১৯৯ এবং -৫ দেখতে পাই। চলুন এই আউটলায়ারগুলো সনাক্ত করতে পরিসংখ্যানগত পদ্ধতি ব্যবহার করি।\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### IQR (ইন্টারকোয়ার্টাইল রেঞ্জ) পদ্ধতি ব্যবহার করা\n", + "\n", + "IQR পদ্ধতি একটি শক্তিশালী পরিসংখ্যানগত কৌশল যা চরম মানগুলোর প্রতি কম সংবেদনশীল এবং বহিরাগত মান সনাক্ত করতে ব্যবহৃত হয়:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Z-স্কোর পদ্ধতি ব্যবহার করা\n", + "\n", + "Z-স্কোর পদ্ধতি গড় থেকে মানের মানক বিচ্যুতির উপর ভিত্তি করে অস্বাভাবিক মান নির্ধারণ করে:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### আউটলায়ার পরিচালনা\n", + "\n", + "আউটলায়ার সনাক্ত করার পর, এগুলো বিভিন্নভাবে পরিচালনা করা যেতে পারে:\n", + "1. **অপসারণ**: আউটলায়ার থাকা সারি বাদ দিন (যদি এগুলো ত্রুটি হয়)\n", + "2. **সীমাবদ্ধ করা**: সীমার মান দিয়ে প্রতিস্থাপন করুন\n", + "3. **NaN দিয়ে প্রতিস্থাপন**: অনুপস্থিত ডেটা হিসেবে বিবেচনা করুন এবং ইম্পুটেশন কৌশল ব্যবহার করুন\n", + "4. **রাখা**: যদি এগুলো বৈধ চরম মান হয়\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ৩. কাছাকাছি সদৃশ সারি শনাক্ত করা\n", + "\n", + "লক্ষ্য করুন যে আমাদের ডেটাসেটে \"John Smith\"-এর জন্য একাধিক এন্ট্রি রয়েছে, যেগুলোর মান সামান্য ভিন্ন। চলুন নামের সাদৃশ্যের ভিত্তিতে সম্ভাব্য সদৃশগুলো শনাক্ত করি।\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### ফাজি ম্যাচিং ব্যবহার করে কাছাকাছি ডুপ্লিকেট খুঁজে বের করা\n", + "\n", + "আরও উন্নত ডুপ্লিকেট শনাক্তকরণের জন্য, আমরা ফাজি ম্যাচিং ব্যবহার করে মিলের কাছাকাছি নামগুলি খুঁজে বের করতে পারি:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### ডুপ্লিকেট পরিচালনা করা\n", + "\n", + "একবার ডুপ্লিকেট শনাক্ত করার পর, আপনাকে সিদ্ধান্ত নিতে হবে কীভাবে এগুলো পরিচালনা করবেন:\n", + "1. **প্রথম occurrence রাখুন**: `drop_duplicates(keep='first')` ব্যবহার করুন\n", + "2. **শেষ occurrence রাখুন**: `drop_duplicates(keep='last')` ব্যবহার করুন\n", + "3. **তথ্য একত্রিত করুন**: ডুপ্লিকেট সারি থেকে তথ্য একত্রিত করুন\n", + "4. **ম্যানুয়াল পর্যালোচনা**: মানুষের পর্যালোচনার জন্য চিহ্নিত করুন\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### সারসংক্ষেপ: সম্পূর্ণ ডেটা ক্লিনিং পাইপলাইন\n", + "\n", + "চলুন সবকিছু একত্রিত করে একটি পূর্ণাঙ্গ ক্লিনিং পাইপলাইন তৈরি করি:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 চ্যালেঞ্জ অনুশীলন\n", + "\n", + "এখন আপনার পালা! নিচে একটি নতুন ডেটার সারি দেওয়া হয়েছে যেখানে একাধিক গুণগত সমস্যা রয়েছে। আপনি কি পারবেন:\n", + "\n", + "1. এই সারির সমস্ত সমস্যাগুলি চিহ্নিত করতে\n", + "2. প্রতিটি সমস্যার সমাধানের জন্য কোড লিখতে\n", + "3. পরিষ্কার করা সারিটি ডেটাসেটে যোগ করতে\n", + "\n", + "এখানে সমস্যাযুক্ত ডেটা:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### মূল বিষয়গুলো\n", + "\n", + "1. **অসংগতিপূর্ণ বিভাগ** বাস্তব জীবনের ডেটায় সাধারণ। সবসময় ইউনিক মানগুলো পরীক্ষা করুন এবং ম্যাপিং বা ফাজি ম্যাচিং ব্যবহার করে সেগুলো মানক করুন।\n", + "\n", + "2. **আউটলায়ার** আপনার বিশ্লেষণে উল্লেখযোগ্য প্রভাব ফেলতে পারে। ডোমেইন জ্ঞান এবং পরিসংখ্যান পদ্ধতি (IQR, Z-score) একত্রে ব্যবহার করে সেগুলো সনাক্ত করুন।\n", + "\n", + "3. **প্রায়-ডুপ্লিকেট** সনাক্ত করা সঠিক ডুপ্লিকেটের তুলনায় কঠিন। ফাজি ম্যাচিং এবং ডেটা স্বাভাবিকীকরণ (লোয়ারকেসিং, হোয়াইটস্পেস সরানো) ব্যবহার করে সেগুলো চিহ্নিত করার চেষ্টা করুন।\n", + "\n", + "4. **ডেটা পরিষ্কারকরণ একটি পুনরাবৃত্তিমূলক প্রক্রিয়া**। চূড়ান্ত পরিষ্কার ডেটাসেট তৈরি করার আগে একাধিক কৌশল প্রয়োগ করতে হতে পারে এবং ফলাফল পর্যালোচনা করতে হতে পারে।\n", + "\n", + "5. **আপনার সিদ্ধান্তগুলো নথিভুক্ত করুন**। কোন পরিষ্কারকরণ ধাপগুলো প্রয়োগ করেছেন এবং কেন, তা লিপিবদ্ধ করুন, কারণ এটি পুনরুত্পাদনযোগ্যতা এবং স্বচ্ছতার জন্য গুরুত্বপূর্ণ।\n", + "\n", + "> **সেরা পদ্ধতি:** সবসময় আপনার মূল \"ডার্টি\" ডেটার একটি কপি রাখুন। কখনোই আপনার সোর্স ডেটা ফাইলগুলো ওভাররাইট করবেন না - পরিষ্কার সংস্করণ তৈরি করুন এবং স্পষ্ট নামকরণের নিয়ম অনুসরণ করুন, যেমন `data_cleaned.csv`।\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n---\n\n**অস্বীকৃতি**: \nএই নথিটি AI অনুবাদ পরিষেবা [Co-op Translator](https://github.com/Azure/co-op-translator) ব্যবহার করে অনুবাদ করা হয়েছে। আমরা যথাসাধ্য সঠিকতার জন্য চেষ্টা করি, তবে অনুগ্রহ করে মনে রাখবেন যে স্বয়ংক্রিয় অনুবাদে ত্রুটি বা অসঙ্গতি থাকতে পারে। মূল ভাষায় থাকা নথিটিকে প্রামাণিক উৎস হিসেবে বিবেচনা করা উচিত। গুরুত্বপূর্ণ তথ্যের জন্য, পেশাদার মানব অনুবাদ সুপারিশ করা হয়। এই অনুবাদ ব্যবহারের ফলে কোনো ভুল বোঝাবুঝি বা ভুল ব্যাখ্যা হলে আমরা দায়বদ্ধ থাকব না।\n" ] } ], @@ -3708,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:18:36+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:39:02+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "bn" } diff --git a/translations/br/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/br/2-Working-With-Data/08-data-preparation/notebook.ipynb index d14770e4..a150a43a 100644 --- a/translations/br/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/br/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# Preparação de Dados\n", "\n", - "[Notebook original de *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Fonte original do Notebook de *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio por Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## Explorando informações do `DataFrame`\n", "\n", - "> **Objetivo de aprendizado:** Ao final desta subseção, você deve se sentir confortável em encontrar informações gerais sobre os dados armazenados em DataFrames do pandas.\n", + "> **Objetivo de aprendizado:** Ao final desta subseção, você deve estar confortável em encontrar informações gerais sobre os dados armazenados em DataFrames do pandas.\n", "\n", - "Depois de carregar seus dados no pandas, é muito provável que eles estejam em um `DataFrame`. No entanto, se o conjunto de dados no seu `DataFrame` tiver 60.000 linhas e 400 colunas, como você começa a ter uma noção do que está lidando? Felizmente, o pandas oferece algumas ferramentas convenientes para rapidamente obter informações gerais sobre um `DataFrame`, além de visualizar as primeiras e últimas linhas.\n", + "Depois de carregar seus dados no pandas, é muito provável que eles estejam em um `DataFrame`. No entanto, se o conjunto de dados no seu `DataFrame` tiver 60.000 linhas e 400 colunas, como você começa a ter uma ideia do que está lidando? Felizmente, o pandas oferece algumas ferramentas convenientes para visualizar rapidamente informações gerais sobre um `DataFrame`, além das primeiras e últimas linhas.\n", "\n", - "Para explorar essa funcionalidade, vamos importar a biblioteca scikit-learn do Python e usar um conjunto de dados icônico que todo cientista de dados já viu centenas de vezes: o conjunto de dados *Iris* do biólogo britânico Ronald Fisher, usado em seu artigo de 1936 \"The use of multiple measurements in taxonomic problems\":\n" + "Para explorar essa funcionalidade, vamos importar a biblioteca Python scikit-learn e usar um conjunto de dados icônico que todo cientista de dados já viu centenas de vezes: o conjunto de dados *Iris* do biólogo britânico Ronald Fisher, utilizado em seu artigo de 1936 \"The use of multiple measurements in taxonomic problems\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Carregamos o Conjunto de Dados Iris na variável `iris_df`. Antes de explorar os dados, seria interessante saber o número de pontos de dados que temos e o tamanho geral do conjunto de dados. É útil observar o volume de dados com o qual estamos lidando.\n" + "Carregamos o Conjunto de Dados Iris na variável `iris_df`. Antes de mergulharmos nos dados, seria interessante saber o número de pontos de dados que temos e o tamanho geral do conjunto de dados. É útil observar o volume de dados com o qual estamos lidando.\n" ] }, { @@ -78,7 +78,7 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Portanto, estamos lidando com 150 linhas e 4 colunas de dados. Cada linha representa um ponto de dados e cada coluna representa uma única característica associada ao dataframe. Basicamente, existem 150 pontos de dados contendo 4 características cada.\n", + "Então, estamos lidando com 150 linhas e 4 colunas de dados. Cada linha representa um ponto de dados e cada coluna representa uma única característica associada ao dataframe. Basicamente, há 150 pontos de dados contendo 4 características cada.\n", "\n", "`shape` aqui é um atributo do dataframe e não uma função, por isso não termina com um par de parênteses.\n" ] @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Agora vamos explorar as 4 colunas de dados. O que exatamente cada uma delas representa? O atributo `columns` nos fornecerá os nomes das colunas no dataframe.\n" + "Agora vamos analisar as 4 colunas de dados. O que exatamente cada uma delas representa? O atributo `columns` nos fornecerá os nomes das colunas no dataframe.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "A quantidade de dados (fornecida pelo atributo `shape`) e o nome das características ou colunas (fornecido pelo atributo `columns`) nos dizem algo sobre o conjunto de dados. Agora, queremos explorar o conjunto de dados mais a fundo. A função `DataFrame.info()` é bastante útil para isso.\n" + "A quantidade de dados (indicada pelo atributo `shape`) e o nome das características ou colunas (indicados pelo atributo `columns`) nos dizem algo sobre o conjunto de dados. Agora, queremos explorar o conjunto de dados mais a fundo. A função `DataFrame.info()` é bastante útil para isso.\n" ] }, { @@ -181,7 +181,7 @@ }, "source": [ "A partir daqui, podemos fazer algumas observações: \n", - "1. O tipo de dado de cada coluna: Neste conjunto de dados, todas as informações estão armazenadas como números de ponto flutuante de 64 bits. \n", + "1. O tipo de dado de cada coluna: Neste conjunto de dados, todos os dados estão armazenados como números de ponto flutuante de 64 bits. \n", "2. Número de valores não nulos: Lidar com valores nulos é uma etapa importante na preparação de dados. Isso será tratado mais adiante no notebook. \n" ] }, @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Digamos que temos muitos dados numéricos em nosso conjunto de dados. Cálculos estatísticos univariados, como média, mediana, quartis, etc., podem ser realizados individualmente em cada uma das colunas. A função `DataFrame.describe()` nos fornece um resumo estatístico das colunas numéricas de um conjunto de dados.\n" + "Suponha que temos muitos dados numéricos em nosso conjunto de dados. Cálculos estatísticos univariados, como média, mediana, quartis, etc., podem ser realizados individualmente em cada uma das colunas. A função `DataFrame.describe()` nos fornece um resumo estatístico das colunas numéricas de um conjunto de dados.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Exercício:\n", "\n", - "Pelo exemplo dado acima, fica claro que, por padrão, `DataFrame.head` retorna as primeiras cinco linhas de um `DataFrame`. Na célula de código abaixo, você consegue descobrir uma maneira de exibir mais de cinco linhas?\n" + "Pelo exemplo dado acima, fica claro que, por padrão, `DataFrame.head` retorna as primeiras cinco linhas de um `DataFrame`. No bloco de código abaixo, você consegue descobrir uma maneira de exibir mais de cinco linhas?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Outra maneira de visualizar os dados pode ser a partir do final (em vez do início). O oposto de `DataFrame.head` é `DataFrame.tail`, que retorna as últimas cinco linhas de um `DataFrame`:\n" + "Outra forma de visualizar os dados pode ser a partir do final (em vez do início). O oposto de `DataFrame.head` é `DataFrame.tail`, que retorna as últimas cinco linhas de um `DataFrame`:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "Na prática, é útil poder examinar facilmente as primeiras ou as últimas linhas de um `DataFrame`, especialmente quando você está procurando por valores atípicos em conjuntos de dados ordenados.\n", + "Na prática, é útil poder examinar facilmente as primeiras ou últimas linhas de um `DataFrame`, especialmente quando você está procurando por valores atípicos em conjuntos de dados ordenados.\n", "\n", - "Todas as funções e atributos mostrados acima com a ajuda de exemplos de código nos ajudam a ter uma visão geral e uma sensação dos dados.\n", + "Todas as funções e atributos mostrados acima com a ajuda de exemplos de código nos ajudam a ter uma visão geral dos dados.\n", "\n", - "> **Conclusão:** Apenas ao observar os metadados sobre as informações em um DataFrame ou os primeiros e últimos valores em um, você pode obter uma ideia imediata sobre o tamanho, a forma e o conteúdo dos dados com os quais está lidando.\n" + "> **Conclusão:** Apenas ao observar os metadados sobre as informações em um DataFrame ou os primeiros e últimos valores nele, você pode ter uma ideia imediata sobre o tamanho, formato e conteúdo dos dados com os quais está lidando.\n" ] }, { @@ -596,9 +596,9 @@ }, "source": [ "### Dados Ausentes\n", - "Vamos explorar os dados ausentes. Dados ausentes ocorrem quando nenhum valor é armazenado em algumas das colunas.\n", + "Vamos explorar o tema de dados ausentes. Dados ausentes ocorrem quando nenhum valor é armazenado em algumas colunas.\n", "\n", - "Vamos usar um exemplo: imagine que alguém está preocupado com seu peso e não preenche o campo de peso em uma pesquisa. Nesse caso, o valor do peso para essa pessoa estará ausente.\n", + "Vamos usar um exemplo: imagine que alguém é muito preocupado com seu peso e decide não preencher o campo de peso em uma pesquisa. Nesse caso, o valor do peso para essa pessoa estará ausente.\n", "\n", "Na maioria das vezes, em conjuntos de dados do mundo real, valores ausentes são comuns.\n", "\n", @@ -606,7 +606,7 @@ "\n", "O Pandas lida com valores ausentes de duas maneiras. A primeira, que você já viu em seções anteriores, é o `NaN`, ou Not a Number. Este é, na verdade, um valor especial que faz parte da especificação de ponto flutuante IEEE e é usado apenas para indicar valores ausentes de ponto flutuante.\n", "\n", - "Para valores ausentes que não sejam de ponto flutuante, o Pandas utiliza o objeto `None` do Python. Embora possa parecer confuso encontrar dois tipos diferentes de valores que essencialmente indicam a mesma coisa, há razões programáticas sólidas para essa escolha de design e, na prática, essa abordagem permite que o Pandas ofereça um bom equilíbrio para a grande maioria dos casos. Apesar disso, tanto `None` quanto `NaN` possuem restrições que você precisa ter em mente em relação à forma como podem ser utilizados.\n" + "Para valores ausentes que não sejam de ponto flutuante, o Pandas utiliza o objeto `None` do Python. Embora possa parecer confuso encontrar dois tipos diferentes de valores que essencialmente indicam a mesma coisa, há razões programáticas sólidas para essa escolha de design e, na prática, essa abordagem permite que o Pandas ofereça um bom equilíbrio para a grande maioria dos casos. Apesar disso, tanto `None` quanto `NaN` possuem restrições que você deve ter em mente em relação ao modo como podem ser utilizados.\n" ] }, { @@ -616,9 +616,9 @@ }, "source": [ "### `None`: dados ausentes não numéricos\n", - "Como `None` vem do Python, ele não pode ser usado em arrays do NumPy e pandas que não sejam do tipo de dado `'object'`. Lembre-se, arrays do NumPy (e as estruturas de dados no pandas) podem conter apenas um tipo de dado. Isso é o que lhes dá um enorme poder para trabalho com dados e computação em larga escala, mas também limita sua flexibilidade. Esses arrays precisam ser convertidos para o \"menor denominador comum\", ou seja, o tipo de dado que abrange tudo no array. Quando `None` está no array, significa que você está lidando com objetos do Python.\n", + "Como `None` vem do Python, ele não pode ser usado em arrays do NumPy e pandas que não sejam do tipo de dado `'object'`. Lembre-se de que os arrays do NumPy (e as estruturas de dados no pandas) podem conter apenas um tipo de dado. Isso é o que lhes dá um enorme poder para trabalhar com dados e computação em larga escala, mas também limita sua flexibilidade. Esses arrays precisam ser convertidos para o \"denominador comum mais baixo\", ou seja, o tipo de dado que abrange tudo no array. Quando `None` está no array, significa que você está lidando com objetos do Python.\n", "\n", - "Para ver isso em ação, considere o seguinte exemplo de array (observe o `dtype` dele):\n" + "Para ver isso em prática, considere o seguinte exemplo de array (observe o `dtype` dele):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "A realidade dos tipos de dados promovidos traz consigo dois efeitos colaterais. Primeiro, as operações serão realizadas no nível do código interpretado do Python, em vez do código compilado do NumPy. Essencialmente, isso significa que quaisquer operações envolvendo `Series` ou `DataFrames` com `None` serão mais lentas. Embora você provavelmente não perceba essa queda de desempenho, para conjuntos de dados grandes isso pode se tornar um problema.\n", + "A realidade dos tipos de dados promovidos traz consigo dois efeitos colaterais. Primeiro, as operações serão realizadas no nível do código interpretado do Python, em vez do código compilado do NumPy. Basicamente, isso significa que quaisquer operações envolvendo `Series` ou `DataFrames` com `None` serão mais lentas. Embora você provavelmente não perceba essa queda de desempenho, para conjuntos de dados grandes isso pode se tornar um problema.\n", "\n", - "O segundo efeito colateral decorre do primeiro. Como `None` essencialmente faz com que `Series` ou `DataFrames` retornem ao mundo do Python puro, usar agregações do NumPy/pandas como `sum()` ou `min()` em arrays que contêm um valor ``None`` geralmente resultará em um erro:\n" + "O segundo efeito colateral decorre do primeiro. Como o `None` essencialmente faz com que `Series` ou `DataFrames` retornem ao mundo do Python puro, usar agregações do NumPy/pandas como `sum()` ou `min()` em arrays que contêm um valor ``None`` geralmente resultará em um erro:\n" ] }, { @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**Conclusão principal**: A adição (e outras operações) entre inteiros e valores `None` é indefinida, o que pode limitar o que você pode fazer com conjuntos de dados que os contêm.\n" + ] }, { "cell_type": "markdown", @@ -707,7 +709,7 @@ "source": [ "### `NaN`: valores float ausentes\n", "\n", - "Ao contrário de `None`, o NumPy (e, consequentemente, o pandas) suporta `NaN` para suas operações rápidas, vetorizadas e ufuncs. A má notícia é que qualquer operação aritmética realizada com `NaN` sempre resulta em `NaN`. Por exemplo:\n" + "Ao contrário de `None`, o NumPy (e, consequentemente, o pandas) oferece suporte ao `NaN` para suas operações vetorizadas rápidas e ufuncs. A má notícia é que qualquer operação aritmética realizada com `NaN` sempre resulta em `NaN`. Por exemplo:\n" ] }, { @@ -806,7 +808,9 @@ "metadata": { "id": "nhlnNJT7gRr_" }, - "source": [] + "source": [ + "### Exercício:\n" + ] }, { "cell_type": "code", @@ -826,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "Lembre-se: `NaN` é apenas para valores de ponto flutuante ausentes; não existe um equivalente `NaN` para inteiros, strings ou valores Booleanos.\n" + ] }, { "cell_type": "markdown", @@ -836,7 +842,7 @@ "source": [ "### `NaN` e `None`: valores nulos no pandas\n", "\n", - "Embora `NaN` e `None` possam se comportar de maneira um pouco diferente, o pandas foi projetado para lidar com eles de forma intercambiável. Para entender o que isso significa, considere uma `Series` de inteiros:\n" + "Embora `NaN` e `None` possam se comportar de maneira um pouco diferente, o pandas foi projetado para lidar com eles de forma intercambiável. Para entender melhor, considere uma `Series` de números inteiros:\n" ] }, { @@ -875,7 +881,9 @@ "metadata": { "id": "WklCzqb8gRsB" }, - "source": [] + "source": [ + "### Exercício:\n" + ] }, { "cell_type": "code", @@ -898,7 +906,7 @@ "id": "WjMQwltNgRsB" }, "source": [ - "No processo de conversão de tipos de dados para estabelecer homogeneidade em `Series` e `DataFrame`s, o pandas irá, sem problemas, alternar valores ausentes entre `None` e `NaN`. Por causa dessa característica de design, pode ser útil pensar em `None` e `NaN` como dois tipos diferentes de \"nulo\" no pandas. De fato, alguns dos métodos principais que você usará para lidar com valores ausentes no pandas refletem essa ideia em seus nomes:\n", + "No processo de promoção de tipos de dados para estabelecer homogeneidade de dados em `Series` e `DataFrame`s, o pandas troca facilmente valores ausentes entre `None` e `NaN`. Por causa dessa característica de design, pode ser útil pensar em `None` e `NaN` como dois tipos diferentes de \"nulo\" no pandas. De fato, alguns dos métodos principais que você usará para lidar com valores ausentes no pandas refletem essa ideia em seus nomes:\n", "\n", "- `isnull()`: Gera uma máscara booleana indicando valores ausentes\n", "- `notnull()`: O oposto de `isnull()`\n", @@ -916,8 +924,7 @@ "source": [ "### Detectando valores nulos\n", "\n", - "Agora que entendemos a importância dos valores ausentes, precisamos detectá-los em nosso conjunto de dados antes de lidar com eles. \n", - "Tanto `isnull()` quanto `notnull()` são seus métodos principais para detectar dados nulos. Ambos retornam máscaras booleanas sobre seus dados.\n" + "Agora que entendemos a importância dos valores ausentes, precisamos detectá-los em nosso conjunto de dados antes de lidar com eles. Tanto `isnull()` quanto `notnull()` são seus métodos principais para detectar dados nulos. Ambos retornam máscaras booleanas sobre seus dados.\n" ] }, { @@ -970,9 +977,9 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Observe atentamente o resultado. Alguma coisa te surpreende? Embora `0` seja um nulo aritmético, ele ainda é um número inteiro perfeitamente válido, e o pandas o trata dessa forma. `''` é um pouco mais sutil. Embora o tenhamos usado na Seção 1 para representar um valor de string vazio, ele ainda é um objeto de string e não uma representação de nulo no que diz respeito ao pandas.\n", + "Observe atentamente o resultado. Alguma coisa te surpreende? Embora `0` seja um nulo aritmético, ele ainda é um número inteiro perfeitamente válido, e o pandas o trata como tal. `''` é um pouco mais sutil. Embora o tenhamos usado na Seção 1 para representar um valor de string vazia, ele ainda é um objeto do tipo string e não uma representação de nulo no que diz respeito ao pandas.\n", "\n", - "Agora, vamos inverter isso e usar esses métodos de uma forma mais parecida com a prática. Você pode usar máscaras Booleanas diretamente como um índice de ``Series`` ou ``DataFrame``, o que pode ser útil ao tentar trabalhar com valores ausentes (ou presentes) isolados.\n", + "Agora, vamos inverter a situação e usar esses métodos de uma maneira mais próxima de como você os usará na prática. Você pode usar máscaras Booleanas diretamente como um índice de ``Series`` ou ``DataFrame``, o que pode ser útil ao tentar trabalhar com valores ausentes (ou presentes) isolados.\n", "\n", "Se quisermos o número total de valores ausentes, podemos simplesmente fazer uma soma sobre a máscara produzida pelo método `isnull()`.\n" ] @@ -1008,7 +1015,9 @@ "metadata": { "id": "PlBqEo3mgRsC" }, - "source": [] + "source": [ + "### Exercício:\n" + ] }, { "cell_type": "code", @@ -1030,7 +1039,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Conclusão principal**: Tanto os métodos `isnull()` quanto `notnull()` produzem resultados semelhantes quando usados em DataFrames: eles mostram os resultados e o índice desses resultados, o que será de grande ajuda enquanto você lida com seus dados.\n" + "**Conclusão principal**: Tanto o método `isnull()` quanto o método `notnull()` produzem resultados semelhantes quando usados em DataFrames: eles mostram os resultados e o índice desses resultados, o que será de grande ajuda enquanto você trabalha com seus dados.\n" ] }, { @@ -1047,10 +1056,10 @@ "\n", "A forma como os dados ausentes são tratados envolve sutis compensações, podendo impactar sua análise final e os resultados no mundo real.\n", "\n", - "Existem basicamente duas maneiras de lidar com dados ausentes:\n", + "Existem principalmente duas maneiras de lidar com dados ausentes:\n", "\n", - "1. Remover a linha que contém o valor ausente \n", - "2. Substituir o valor ausente por algum outro valor \n", + "1. Remover a linha que contém o valor ausente\n", + "2. Substituir o valor ausente por algum outro valor\n", "\n", "Discutiremos ambos os métodos e seus prós e contras em detalhes.\n" ] @@ -1061,13 +1070,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### Eliminando valores nulos\n", + "### Removendo valores nulos\n", "\n", - "A quantidade de dados que passamos para o nosso modelo tem um efeito direto em seu desempenho. Eliminar valores nulos significa que estamos reduzindo o número de pontos de dados e, consequentemente, o tamanho do conjunto de dados. Portanto, é recomendável eliminar linhas com valores nulos quando o conjunto de dados for bastante grande.\n", + "A quantidade de dados que passamos para o nosso modelo tem um efeito direto em seu desempenho. Remover valores nulos significa que estamos reduzindo o número de pontos de dados e, consequentemente, diminuindo o tamanho do conjunto de dados. Portanto, é recomendável eliminar linhas com valores nulos quando o conjunto de dados é bastante grande.\n", "\n", - "Outro caso pode ser quando uma determinada linha ou coluna possui muitos valores ausentes. Nesse caso, elas podem ser eliminadas porque não adicionariam muito valor à nossa análise, já que a maior parte dos dados está ausente para essa linha/coluna.\n", + "Outro caso pode ser quando uma determinada linha ou coluna possui muitos valores ausentes. Nesse caso, elas podem ser removidas porque não adicionariam muito valor à nossa análise, já que a maior parte dos dados está ausente para essa linha/coluna.\n", "\n", - "Além de identificar valores ausentes, pandas oferece um meio prático para remover valores nulos de `Series` e `DataFrame`s. Para ver isso em ação, vamos voltar ao `example3`. A função `DataFrame.dropna()` ajuda a eliminar as linhas com valores nulos.\n" + "Além de identificar valores ausentes, o pandas oferece uma maneira prática de remover valores nulos de `Series` e `DataFrame`s. Para ver isso em ação, vamos voltar ao `example3`. A função `DataFrame.dropna()` ajuda a eliminar as linhas com valores nulos.\n" ] }, { @@ -1106,9 +1115,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "Note que isso deve se parecer com o resultado de `example3[example3.notnull()]`. A diferença aqui é que, em vez de apenas indexar os valores mascarados, `dropna` removeu esses valores ausentes da `Series` `example3`.\n", + "Observe que isso deve se parecer com o resultado de `example3[example3.notnull()]`. A diferença aqui é que, em vez de apenas indexar os valores mascarados, `dropna` removeu esses valores ausentes da `Series` `example3`.\n", "\n", - "Como os DataFrames possuem duas dimensões, eles oferecem mais opções para remover dados.\n" + "Como os DataFrames têm duas dimensões, eles oferecem mais opções para remover dados.\n" ] }, { @@ -1200,7 +1209,7 @@ "source": [ "(Você percebeu que o pandas converteu duas das colunas para floats para acomodar os `NaN`s?)\n", "\n", - "Você não pode remover um único valor de um `DataFrame`, então é necessário remover linhas ou colunas inteiras. Dependendo do que você está fazendo, pode ser mais adequado optar por uma ou outra opção, e o pandas oferece alternativas para ambas. Como na ciência de dados as colunas geralmente representam variáveis e as linhas representam observações, é mais comum remover linhas de dados; a configuração padrão para `dropna()` é remover todas as linhas que contêm qualquer valor nulo:\n" + "Você não pode remover um único valor de um `DataFrame`, então é necessário remover linhas ou colunas inteiras. Dependendo do que você está fazendo, pode ser mais adequado optar por uma ou outra abordagem, e o pandas oferece opções para ambas. Como na ciência de dados as colunas geralmente representam variáveis e as linhas representam observações, é mais comum remover linhas de dados; a configuração padrão de `dropna()` é remover todas as linhas que contêm qualquer valor nulo:\n" ] }, { @@ -1352,9 +1361,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Observe que isso pode descartar muitos dados que você pode querer manter, especialmente em conjuntos de dados menores. E se você quiser apenas remover linhas ou colunas que contenham vários ou até mesmo todos os valores nulos? Você pode especificar essas configurações em `dropna` com os parâmetros `how` e `thresh`.\n", + "Observe que isso pode eliminar muitos dados que você talvez queira manter, especialmente em conjuntos de dados menores. E se você quiser apenas remover linhas ou colunas que contenham vários ou até mesmo todos os valores nulos? Você pode especificar essas configurações em `dropna` usando os parâmetros `how` e `thresh`.\n", "\n", - "Por padrão, `how='any'` (se você quiser verificar por conta própria ou ver quais outros parâmetros o método possui, execute `example4.dropna?` em uma célula de código). Alternativamente, você pode especificar `how='all'` para remover apenas linhas ou colunas que contenham todos os valores nulos. Vamos expandir nosso exemplo de `DataFrame` para ver isso em ação no próximo exercício.\n" + "Por padrão, `how='any'` (se você quiser verificar por conta própria ou ver quais outros parâmetros o método possui, execute `example4.dropna?` em uma célula de código). Você também pode especificar `how='all'` para remover apenas linhas ou colunas que contenham todos os valores nulos. Vamos expandir nosso exemplo de `DataFrame` para ver isso em ação no próximo exercício.\n" ] }, { @@ -1448,9 +1457,9 @@ "source": [ "> Principais pontos: \n", "1. Remover valores nulos é uma boa ideia apenas se o conjunto de dados for grande o suficiente. \n", - "2. Linhas ou colunas inteiras podem ser removidas se a maior parte de seus dados estiver ausente. \n", - "3. O método `DataFrame.dropna(axis=)` ajuda a remover valores nulos. O argumento `axis` indica se as linhas ou colunas devem ser removidas. \n", - "4. O argumento `how` também pode ser utilizado. Por padrão, ele é definido como `any`. Assim, ele remove apenas as linhas/colunas que contêm qualquer valor nulo. Pode ser configurado como `all` para especificar que removeremos apenas as linhas/colunas onde todos os valores são nulos. \n" + "2. Linhas ou colunas inteiras podem ser removidas se a maior parte dos dados estiver ausente. \n", + "3. O método `DataFrame.dropna(axis=)` ajuda a eliminar valores nulos. O argumento `axis` indica se as linhas ou colunas devem ser removidas. \n", + "4. O argumento `how` também pode ser utilizado. Por padrão, ele está definido como `any`. Assim, ele remove apenas as linhas/colunas que contêm qualquer valor nulo. Pode ser configurado como `all` para especificar que removeremos apenas as linhas/colunas onde todos os valores são nulos. \n" ] }, { @@ -1458,7 +1467,9 @@ "metadata": { "id": "oXXSfQFHgRsF" }, - "source": [] + "source": [ + "### Exercício:\n" + ] }, { "cell_type": "code", @@ -1568,7 +1579,7 @@ "\n", "Às vezes, faz sentido preencher valores ausentes com aqueles que poderiam ser válidos. Existem algumas técnicas para preencher valores nulos. A primeira é usar o Conhecimento de Domínio (conhecimento sobre o assunto no qual o conjunto de dados se baseia) para, de alguma forma, aproximar os valores ausentes.\n", "\n", - "Você poderia usar `isnull` para fazer isso diretamente, mas isso pode ser trabalhoso, especialmente se você tiver muitos valores para preencher. Como essa é uma tarefa tão comum em ciência de dados, pandas fornece `fillna`, que retorna uma cópia do `Series` ou `DataFrame` com os valores ausentes substituídos por um de sua escolha. Vamos criar outro exemplo de `Series` para ver como isso funciona na prática.\n" + "Você poderia usar `isnull` para fazer isso diretamente, mas isso pode ser trabalhoso, especialmente se você tiver muitos valores para preencher. Como essa é uma tarefa tão comum em ciência de dados, pandas oferece o método `fillna`, que retorna uma cópia do `Series` ou `DataFrame` com os valores ausentes substituídos por um de sua escolha. Vamos criar outro exemplo de `Series` para ver como isso funciona na prática.\n" ] }, { @@ -1577,10 +1588,10 @@ "id": "CE8S7louLezV" }, "source": [ - "### Dados Categóricos (Não Numéricos)\n", + "### Dados Categóricos (Não numéricos)\n", "Primeiro, vamos considerar dados não numéricos. Em conjuntos de dados, temos colunas com dados categóricos. Por exemplo, Gênero, Verdadeiro ou Falso, etc.\n", "\n", - "Na maioria desses casos, substituímos os valores ausentes pelo `moda` da coluna. Suponha que temos 100 pontos de dados, 90 disseram Verdadeiro, 8 disseram Falso e 2 não preencheram. Então, podemos preencher os 2 com Verdadeiro, considerando a coluna inteira.\n", + "Na maioria desses casos, substituímos os valores ausentes pelo `moda` da coluna. Por exemplo, temos 100 pontos de dados, 90 indicaram Verdadeiro, 8 indicaram Falso e 2 não preencheram. Então, podemos preencher os 2 com Verdadeiro, considerando a coluna inteira.\n", "\n", "Novamente, aqui podemos usar conhecimento de domínio. Vamos considerar um exemplo de preenchimento com a moda.\n" ] @@ -1687,7 +1698,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Agora, vamos primeiro encontrar a moda antes de preencher o valor `None` com a moda.\n" + ] }, { "cell_type": "code", @@ -1722,7 +1735,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Então, vamos substituir None por True\n" + ] }, { "cell_type": "code", @@ -1842,12 +1857,12 @@ }, "source": [ "### Dados Numéricos\n", - "Agora, falando sobre dados numéricos. Aqui, temos duas maneiras comuns de substituir valores ausentes:\n", + "Agora, falando sobre dados numéricos. Aqui, temos duas formas comuns de substituir valores ausentes:\n", "\n", - "1. Substituir pela mediana da linha\n", - "2. Substituir pela média da linha\n", + "1. Substituir pela mediana da linha \n", + "2. Substituir pela média da linha \n", "\n", - "Substituímos pela mediana no caso de dados distorcidos com outliers. Isso ocorre porque a mediana é robusta contra outliers.\n", + "Substituímos pela mediana no caso de dados assimétricos com outliers. Isso ocorre porque a mediana é resistente a outliers.\n", "\n", "Quando os dados estão normalizados, podemos usar a média, já que, nesse caso, a média e a mediana seriam bastante próximas.\n", "\n", @@ -1991,7 +2006,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Preenchendo com a média\n" + ] }, { "cell_type": "code", @@ -2100,7 +2117,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Agora, vamos tentar outro dataframe, e desta vez substituiremos os valores None pela mediana da coluna.\n" + "Agora vamos tentar outro dataframe, e desta vez substituiremos os valores None pela mediana da coluna.\n" ] }, { @@ -2240,7 +2257,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Preenchendo com mediana\n" + ] }, { "cell_type": "code", @@ -2435,7 +2454,9 @@ "metadata": { "id": "FI9MmqFJgRsH" }, - "source": [] + "source": [ + "### Exercício:\n" + ] }, { "cell_type": "code", @@ -2455,7 +2476,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "Você pode **preencher para frente** valores nulos, que é usar o último valor válido para preencher um nulo:\n" + ] }, { "cell_type": "code", @@ -2495,7 +2518,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Você também pode **preencher para trás** para propagar o próximo valor válido para trás e preencher um nulo:\n" + "Você também pode **preencher retroativamente** para propagar o próximo valor válido para trás e preencher um nulo:\n" ] }, { @@ -2718,7 +2741,9 @@ "metadata": { "id": "eeAoOU0RgRsJ" }, - "source": [] + "source": [ + "### Exercício:\n" + ] }, { "cell_type": "code", @@ -2741,7 +2766,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Você pode ser criativo sobre como usar `fillna`. Por exemplo, vamos olhar para o `example4` novamente, mas desta vez vamos preencher os valores ausentes com a média de todos os valores no `DataFrame`:\n" + "Você pode ser criativo sobre como usar `fillna`. Por exemplo, vamos olhar para `example4` novamente, mas desta vez vamos preencher os valores ausentes com a média de todos os valores no `DataFrame`:\n" ] }, { @@ -2832,9 +2857,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Observe que a coluna 3 ainda está sem valor: a direção padrão é preencher os valores linha por linha.\n", + "Observe que a coluna 3 ainda está sem valores: a direção padrão é preencher os valores linha por linha.\n", "\n", - "> **Conclusão:** Existem várias maneiras de lidar com valores ausentes em seus conjuntos de dados. A estratégia específica que você utiliza (removê-los, substituí-los ou até mesmo como substituí-los) deve ser ditada pelas particularidades desses dados. Você desenvolverá uma melhor noção de como lidar com valores ausentes à medida que manipular e interagir mais com conjuntos de dados.\n" + "> **Conclusão:** Existem várias maneiras de lidar com valores ausentes em seus conjuntos de dados. A estratégia específica que você utiliza (removê-los, substituí-los ou até mesmo como substituí-los) deve ser determinada pelas particularidades desses dados. Você desenvolverá uma melhor percepção de como lidar com valores ausentes à medida que trabalhar e interagir mais com conjuntos de dados.\n" ] }, { @@ -2845,7 +2870,7 @@ "source": [ "### Codificação de Dados Categóricos\n", "\n", - "Modelos de aprendizado de máquina lidam apenas com números e qualquer tipo de dado numérico. Eles não conseguem diferenciar entre um \"Sim\" e um \"Não\", mas conseguem distinguir entre 0 e 1. Portanto, após preencher os valores ausentes, precisamos codificar os dados categóricos em alguma forma numérica para que o modelo possa entendê-los.\n", + "Modelos de aprendizado de máquina lidam apenas com números e qualquer tipo de dado numérico. Eles não conseguem diferenciar entre um \"Sim\" e um \"Não\", mas conseguem distinguir entre 0 e 1. Portanto, após preencher os valores ausentes, é necessário codificar os dados categóricos em uma forma numérica para que o modelo possa compreendê-los.\n", "\n", "A codificação pode ser feita de duas maneiras. Vamos discutir essas formas a seguir.\n" ] @@ -2858,7 +2883,7 @@ "source": [ "**CODIFICAÇÃO DE RÓTULOS**\n", "\n", - "A codificação de rótulos basicamente consiste em converter cada categoria em um número. Por exemplo, suponha que temos um conjunto de dados de passageiros de uma companhia aérea e há uma coluna contendo suas classes entre as seguintes ['classe executiva', 'classe econômica', 'primeira classe']. Se a codificação de rótulos for aplicada, isso seria transformado em [0,1,2]. Vamos ver um exemplo por meio de código. Como aprenderemos `scikit-learn` nos próximos notebooks, não o utilizaremos aqui.\n" + "A codificação de rótulos basicamente consiste em converter cada categoria em um número. Por exemplo, suponha que temos um conjunto de dados de passageiros de avião e há uma coluna contendo a classe deles entre as seguintes ['classe executiva', 'classe econômica', 'primeira classe']. Se aplicarmos a codificação de rótulos, isso seria transformado em [0,1,2]. Vamos ver um exemplo com código. Como aprenderemos `scikit-learn` nos próximos notebooks, não o utilizaremos aqui.\n" ] }, { @@ -2966,7 +2991,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Para realizar a codificação de rótulos na 1ª coluna, primeiro precisamos descrever um mapeamento de cada classe para um número, antes de substituir\n" + "Para realizar a codificação de rótulos na primeira coluna, primeiro precisamos descrever um mapeamento de cada classe para um número, antes de substituir.\n" ] }, { @@ -3068,9 +3093,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Como podemos ver, o resultado corresponde ao que esperávamos. Então, quando usamos a codificação de rótulos? A codificação de rótulos é usada em um ou ambos os seguintes casos: \n", - "1. Quando o número de categorias é grande \n", - "2. Quando as categorias estão em ordem. \n" + "Como podemos ver, o resultado corresponde ao que esperávamos. Então, quando usamos a codificação de rótulos? A codificação de rótulos é usada em um ou ambos os seguintes casos:\n", + "1. Quando o número de categorias é grande\n", + "2. Quando as categorias estão em ordem.\n" ] }, { @@ -3081,9 +3106,9 @@ "source": [ "**ONE HOT ENCODING**\n", "\n", - "Outro tipo de codificação é o One Hot Encoding. Nesse tipo de codificação, cada categoria da coluna é adicionada como uma coluna separada, e cada ponto de dado recebe um 0 ou 1, dependendo se contém ou não aquela categoria. Assim, se houver n categorias diferentes, n colunas serão adicionadas ao dataframe.\n", + "Outro tipo de codificação é o One Hot Encoding. Nesse tipo de codificação, cada categoria da coluna é adicionada como uma coluna separada, e cada ponto de dados recebe um 0 ou 1 dependendo se contém ou não aquela categoria. Assim, se houver n categorias diferentes, n colunas serão adicionadas ao dataframe.\n", "\n", - "Por exemplo, vamos usar o mesmo exemplo da classe de avião. As categorias eram: ['business class', 'economy class', 'first class']. Então, se realizarmos o One Hot Encoding, as seguintes três colunas serão adicionadas ao conjunto de dados: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Por exemplo, vamos usar o mesmo exemplo de classe de avião. As categorias eram: ['business class', 'economy class', 'first class']. Então, se realizarmos o One Hot Encoding, as seguintes três colunas serão adicionadas ao conjunto de dados: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3350,9 +3375,9 @@ "source": [ "## Removendo dados duplicados\n", "\n", - "> **Objetivo de aprendizado:** Ao final desta subseção, você deverá se sentir à vontade para identificar e remover valores duplicados de DataFrames.\n", + "> **Objetivo de aprendizado:** Ao final desta subseção, você deve estar confortável em identificar e remover valores duplicados de DataFrames.\n", "\n", - "Além de dados ausentes, você frequentemente encontrará dados duplicados em conjuntos de dados do mundo real. Felizmente, o pandas oferece um meio fácil de detectar e remover entradas duplicadas.\n" + "Além de dados ausentes, você frequentemente encontrará dados duplicados em conjuntos de dados do mundo real. Felizmente, o pandas oferece uma maneira fácil de detectar e remover entradas duplicadas.\n" ] }, { @@ -3361,9 +3386,9 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### Identificando duplicatas: `duplicated`\n", + "### Identificando duplicados: `duplicated`\n", "\n", - "Você pode identificar valores duplicados facilmente usando o método `duplicated` do pandas, que retorna uma máscara booleana indicando se uma entrada em um `DataFrame` é uma duplicata de uma anterior. Vamos criar outro exemplo de `DataFrame` para ver isso em ação.\n" + "Você pode identificar valores duplicados facilmente usando o método `duplicated` no pandas, que retorna uma máscara booleana indicando se uma entrada em um `DataFrame` é duplicada de uma anterior. Vamos criar outro exemplo de `DataFrame` para ver isso em ação.\n" ] }, { @@ -3492,7 +3517,7 @@ "id": "0eDRJD4SgRsK" }, "source": [ - "### Removendo duplicados: `drop_duplicates`\n", + "### Removendo duplicatas: `drop_duplicates`\n", "`drop_duplicates` simplesmente retorna uma cópia dos dados em que todos os valores `duplicated` são `False`:\n" ] }, @@ -3576,7 +3601,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Tanto `duplicated` quanto `drop_duplicates` consideram todas as colunas por padrão, mas você pode especificar que eles examinem apenas um subconjunto de colunas no seu `DataFrame`:\n" + "Tanto `duplicated` quanto `drop_duplicates` consideram por padrão todas as colunas, mas você pode especificar que eles examinem apenas um subconjunto de colunas no seu `DataFrame`:\n" ] }, { @@ -3652,13 +3677,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Conclusão:** Remover dados duplicados é uma parte essencial de quase todos os projetos de ciência de dados. Dados duplicados podem alterar os resultados de suas análises e fornecer resultados imprecisos!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Verificação de Qualidade de Dados do Mundo Real\n", + "\n", + "> **Objetivo de aprendizado:** Ao final desta seção, você deve estar confortável em detectar e corrigir problemas comuns de qualidade de dados do mundo real, incluindo valores categóricos inconsistentes, valores numéricos anormais (outliers) e entidades duplicadas com variações.\n", + "\n", + "Embora valores ausentes e duplicatas exatas sejam problemas comuns, conjuntos de dados do mundo real frequentemente apresentam problemas mais sutis:\n", + "\n", + "1. **Valores categóricos inconsistentes**: A mesma categoria escrita de forma diferente (ex.: \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Valores numéricos anormais**: Outliers extremos que indicam erros de entrada de dados (ex.: idade = 999)\n", + "3. **Linhas quase duplicadas**: Registros que representam a mesma entidade com pequenas variações\n", + "\n", + "Vamos explorar técnicas para detectar e lidar com esses problemas.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Criando um Conjunto de Dados \"Sujo\" de Exemplo\n", + "\n", + "Primeiro, vamos criar um conjunto de dados de exemplo que contém os tipos de problemas que encontramos com frequência em dados do mundo real:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Detectando Valores Categóricos Inconsistentes\n", + "\n", + "Observe que a coluna `country` possui várias representações para os mesmos países. Vamos identificar essas inconsistências:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Padronizando Valores Categóricos\n", + "\n", + "Podemos criar um mapeamento para padronizar esses valores. Uma abordagem simples é converter para letras minúsculas e criar um dicionário de mapeamento:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternativa: Usando Correspondência Fuzzy**\n", + "\n", + "Para casos mais complexos, podemos usar a correspondência de strings fuzzy com a biblioteca `rapidfuzz` para detectar automaticamente strings semelhantes:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Detectando Valores Numéricos Anormais (Outliers)\n", + "\n", + "Analisando a coluna `age`, temos alguns valores suspeitos como 199 e -5. Vamos usar métodos estatísticos para detectar esses outliers.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Usando o Método IQR (Intervalo Interquartil)\n", + "\n", + "O método IQR é uma técnica estatística robusta para detecção de valores atípicos, sendo menos sensível a valores extremos:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Usando o Método Z-Score\n", + "\n", + "O método Z-score identifica outliers com base em desvios padrão em relação à média:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Lidando com Outliers\n", + "\n", + "Uma vez detectados, os outliers podem ser tratados de várias maneiras:\n", + "1. **Remover**: Excluir linhas com outliers (se forem erros)\n", + "2. **Limitar**: Substituir pelos valores limite\n", + "3. **Substituir por NaN**: Tratar como dados ausentes e usar técnicas de imputação\n", + "4. **Manter**: Se forem valores extremos legítimos\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Detectando Linhas Quase Duplicadas\n", + "\n", + "Observe que nosso conjunto de dados possui várias entradas para \"John Smith\" com valores ligeiramente diferentes. Vamos identificar possíveis duplicatas com base na similaridade dos nomes.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Encontrando Quase-Duplicados com Correspondência Fuzzy\n", + "\n", + "Para uma detecção de duplicados mais avançada, podemos usar correspondência fuzzy para encontrar nomes semelhantes:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Lidando com Duplicatas\n", + "\n", + "Uma vez identificadas, você precisa decidir como lidar com as duplicatas:\n", + "1. **Manter a primeira ocorrência**: Use `drop_duplicates(keep='first')`\n", + "2. **Manter a última ocorrência**: Use `drop_duplicates(keep='last')`\n", + "3. **Agregação de informações**: Combine informações das linhas duplicadas\n", + "4. **Revisão manual**: Marque para revisão humana\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Resumo: Pipeline Completo de Limpeza de Dados\n", + "\n", + "Vamos reunir tudo em um pipeline abrangente de limpeza:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Exercício de Desafio\n", + "\n", + "Agora é sua vez! Abaixo está uma nova linha de dados com vários problemas de qualidade. Você consegue:\n", + "\n", + "1. Identificar todos os problemas nesta linha\n", + "2. Escrever o código para corrigir cada problema\n", + "3. Adicionar a linha corrigida ao conjunto de dados\n", + "\n", + "Aqui estão os dados problemáticos:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Principais Pontos\n", + "\n", + "1. **Categorias inconsistentes** são comuns em dados do mundo real. Sempre verifique os valores únicos e padronize-os usando mapeamentos ou correspondência aproximada.\n", + "\n", + "2. **Outliers** podem afetar significativamente sua análise. Use conhecimento do domínio combinado com métodos estatísticos (IQR, Z-score) para detectá-los.\n", + "\n", + "3. **Quase duplicados** são mais difíceis de detectar do que duplicados exatos. Considere usar correspondência aproximada e normalizar os dados (letras minúsculas, remoção de espaços) para identificá-los.\n", + "\n", + "4. **A limpeza de dados é iterativa**. Pode ser necessário aplicar várias técnicas e revisar os resultados antes de finalizar seu conjunto de dados limpo.\n", + "\n", + "5. **Documente suas decisões**. Registre quais etapas de limpeza você aplicou e por que, pois isso é importante para a reprodutibilidade e transparência.\n", + "\n", + "> **Melhor Prática:** Sempre mantenha uma cópia dos seus dados originais \"sujos\". Nunca sobrescreva seus arquivos de dados fonte - crie versões limpas com convenções de nomenclatura claras, como `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional feita por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n" + "\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n" ] } ], @@ -3686,8 +4229,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:24:10+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:56:22+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "br" } diff --git a/translations/cs/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/cs/2-Working-With-Data/08-data-preparation/notebook.ipynb index 2dcc83f1..7004f117 100644 --- a/translations/cs/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/cs/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# Příprava dat\n", "\n", - "[Originální zdroj notebooku z *Data Science: Úvod do strojového učení pro datovou vědu Python a Machine Learning Studio od Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Originální zdroj notebooku z *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio od Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## Zkoumání informací o `DataFrame`\n", "\n", "> **Cíl učení:** Na konci této podsekce byste měli být schopni pohodlně najít obecné informace o datech uložených v pandas DataFrames.\n", "\n", - "Jakmile načtete svá data do pandas, je velmi pravděpodobné, že budou uložena v `DataFrame`. Ale pokud má datová sada ve vašem `DataFrame` 60 000 řádků a 400 sloupců, jak vůbec začít získávat přehled o tom, s čím pracujete? Naštěstí pandas poskytuje několik praktických nástrojů, které umožňují rychle získat celkový přehled o `DataFrame`, kromě zobrazení prvních a posledních několika řádků.\n", + "Jakmile načtete svá data do pandas, je velmi pravděpodobné, že budou ve formátu `DataFrame`. Ale pokud má datová sada ve vašem `DataFrame` 60 000 řádků a 400 sloupců, jak vůbec začít získávat představu o tom, s čím pracujete? Naštěstí pandas poskytuje několik praktických nástrojů, které vám umožní rychle získat celkový přehled o `DataFrame`, kromě prvních a posledních několika řádků.\n", "\n", - "Abychom prozkoumali tuto funkcionalitu, importujeme knihovnu Python scikit-learn a použijeme ikonickou datovou sadu, kterou každý datový vědec viděl už stokrát: datovou sadu *Iris* britského biologa Ronalda Fishera, použitou v jeho článku z roku 1936 \"Použití více měření v taxonomických problémech\":\n" + "Abychom prozkoumali tuto funkcionalitu, importujeme knihovnu Python scikit-learn a použijeme ikonickou datovou sadu, kterou každý datový vědec viděl už stokrát: *Iris* dataset britského biologa Ronalda Fishera, použitý v jeho článku z roku 1936 \"Použití více měření v taxonomických problémech\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Načetli jsme dataset Iris do proměnné `iris_df`. Než se pustíme do analýzy dat, bylo by užitečné zjistit počet datových bodů, které máme, a celkovou velikost datasetu. Je dobré mít přehled o objemu dat, se kterými pracujeme.\n" + "Načetli jsme dataset Iris do proměnné `iris_df`. Než se pustíme do analýzy dat, bylo by užitečné zjistit počet datových bodů, které máme, a celkovou velikost datasetu. Je dobré podívat se na objem dat, se kterými pracujeme.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Takže máme 150 řádků a 4 sloupce dat. Každý řádek představuje jeden datový bod a každý sloupec představuje jednu vlastnost spojenou s datovým rámcem. V podstatě tedy máme 150 datových bodů, z nichž každý obsahuje 4 vlastnosti.\n", + "Takže máme 150 řádků a 4 sloupce dat. Každý řádek představuje jeden datový bod a každý sloupec představuje jednu vlastnost spojenou s datovým rámcem. V podstatě tedy existuje 150 datových bodů, z nichž každý obsahuje 4 vlastnosti.\n", "\n", - "`shape` je zde atributem datového rámce, nikoliv funkcí, což je důvod, proč nekončí párem závorek.\n" + "`shape` je zde atribut datového rámce, nikoli funkce, což je důvod, proč nekončí dvojicí závorek.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Jak vidíme, jsou zde čtyři (4) sloupce. Atribut `columns` nám říká názvy sloupců a v podstatě nic jiného. Tento atribut nabývá na důležitosti, když chceme identifikovat vlastnosti, které datová sada obsahuje.\n" + "Jak můžeme vidět, jsou zde čtyři (4) sloupce. Atribut `columns` nám říká názvy sloupců a v podstatě nic jiného. Tento atribut nabývá na důležitosti, když chceme identifikovat vlastnosti, které dataset obsahuje.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Množství dat (určené atributem `shape`) a názvy vlastností nebo sloupců (určené atributem `columns`) nám poskytují určité informace o datové sadě. Nyní bychom chtěli jít hlouběji do datové sady. Funkce `DataFrame.info()` je pro tento účel velmi užitečná.\n" + "Množství dat (dané atributem `shape`) a názvy vlastností nebo sloupců (dané atributem `columns`) nám poskytují určité informace o datové sadě. Nyní bychom chtěli prozkoumat datovou sadu podrobněji. Funkce `DataFrame.info()` je pro tento účel velmi užitečná.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Zde můžeme udělat několik pozorování:\n", - "1. Datový typ každého sloupce: V tomto datasetu jsou všechna data uložena jako 64bitová čísla s plovoucí desetinnou čárkou.\n", - "2. Počet nenulových hodnot: Práce s nulovými hodnotami je důležitým krokem při přípravě dat. Tím se budeme zabývat později v notebooku.\n" + "Odtud můžeme učinit několik pozorování: \n", + "1. Datový typ každého sloupce: V tomto datasetu jsou všechna data uložena jako 64bitová čísla s plovoucí desetinnou čárkou. \n", + "2. Počet nenulových hodnot: Práce s nulovými hodnotami je důležitým krokem při přípravě dat. Tím se budeme zabývat později v notebooku. \n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Řekněme, že máme v našem datasetu hodně číselných dat. Jednovariabilní statistické výpočty, jako je průměr, medián, kvartily atd., lze provádět na jednotlivých sloupcích. Funkce `DataFrame.describe()` nám poskytuje statistický přehled číselných sloupců datasetu.\n" + "Řekněme, že máme v našem datovém souboru hodně číselných dat. Jednovariátní statistické výpočty, jako je průměr, medián, kvartily atd., lze provádět na jednotlivých sloupcích samostatně. Funkce `DataFrame.describe()` nám poskytuje statistický přehled číselných sloupců datového souboru.\n" ] }, { @@ -332,7 +332,7 @@ }, "source": [ "### `DataFrame.head`\n", - "S využitím všech výše uvedených funkcí a atributů jsme získali přehled na nejvyšší úrovni o datové sadě. Víme, kolik datových bodů je k dispozici, kolik je vlastností, jaký je datový typ každé vlastnosti a kolik hodnot není nulových pro každou vlastnost.\n", + "S pomocí všech výše uvedených funkcí a atributů jsme získali přehled na vysoké úrovni o datasetu. Víme, kolik datových bodů obsahuje, kolik má vlastností, jaký je datový typ každé vlastnosti a kolik má každá vlastnost nenulových hodnot.\n", "\n", "Teď je čas podívat se na samotná data. Podívejme se, jak vypadají první řádky (první datové body) našeho `DataFrame`:\n" ] @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Jak vidíme v tomto výstupu, máme pět (5) záznamů datové sady. Pokud se podíváme na index vlevo, zjistíme, že se jedná o prvních pět řádků.\n" + "Jak vidíme na výstupu, máme zde pět (5) záznamů datové sady. Pokud se podíváme na index vlevo, zjistíme, že se jedná o prvních pět řádků.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Cvičení:\n", "\n", - "Z výše uvedeného příkladu je zřejmé, že `DataFrame.head` ve výchozím nastavení vrací prvních pět řádků `DataFrame`. V níže uvedené buňce kódu, dokážete najít způsob, jak zobrazit více než pět řádků?\n" + "Z výše uvedeného příkladu je zřejmé, že `DataFrame.head` ve výchozím nastavení vrací prvních pět řádků `DataFrame`. Dokážete v níže uvedené buňce kódu najít způsob, jak zobrazit více než pět řádků?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Další způsob, jak se podívat na data, může být od konce (namísto od začátku). Opakem `DataFrame.head` je `DataFrame.tail`, který vrací posledních pět řádků `DataFrame`:\n" + "Další způsob, jak se podívat na data, může být od konce (namísto od začátku). Opačnou funkcí k `DataFrame.head` je `DataFrame.tail`, která vrací posledních pět řádků `DataFrame`:\n" ] }, { @@ -584,9 +584,9 @@ "source": [ "V praxi je užitečné mít možnost snadno prohlédnout prvních několik řádků nebo posledních několik řádků `DataFrame`, zejména když hledáte odlehlé hodnoty v uspořádaných datových sadách.\n", "\n", - "Všechny funkce a atributy uvedené výše pomocí příkladů kódu nám pomáhají získat přehled o datech.\n", + "Všechny funkce a atributy uvedené výše s pomocí příkladů kódu nám umožňují získat přehled o datech.\n", "\n", - "> **Shrnutí:** Už jen pohledem na metadata o informacích v `DataFrame` nebo na prvních a posledních několik hodnot v něm můžete okamžitě získat představu o velikosti, tvaru a obsahu dat, se kterými pracujete.\n" + "> **Shrnutí:** Už jen pohledem na metadata o informacích v DataFrame nebo na prvních a posledních několik hodnot v něm můžete okamžitě získat představu o velikosti, tvaru a obsahu dat, se kterými pracujete.\n" ] }, { @@ -596,17 +596,17 @@ }, "source": [ "### Chybějící data\n", - "Pojďme se podívat na chybějící data. Chybějící data nastávají, když v některých sloupcích nejsou uloženy žádné hodnoty.\n", + "Pojďme se podívat na chybějící data. Chybějící data nastávají, když v některých sloupcích není uložena žádná hodnota.\n", "\n", "Uveďme si příklad: řekněme, že někdo je citlivý na svou váhu a nevyplní pole s váhou v dotazníku. Potom bude hodnota váhy pro tuto osobu chybět.\n", "\n", - "Ve většině případů se v reálných datových sadách chybějící hodnoty vyskytují.\n", + "Ve většině případů se v reálných datových sadách vyskytují chybějící hodnoty.\n", "\n", - "**Jak Pandas zpracovává chybějící data**\n", + "**Jak Pandas pracuje s chybějícími daty**\n", "\n", - "Pandas zpracovává chybějící hodnoty dvěma způsoby. První způsob jste již viděli v předchozích sekcích: `NaN`, neboli Not a Number. Toto je ve skutečnosti speciální hodnota, která je součástí specifikace IEEE pro čísla s plovoucí desetinnou čárkou, a používá se pouze k označení chybějících hodnot typu float.\n", + "Pandas pracuje s chybějícími hodnotami dvěma způsoby. První způsob jste již viděli v předchozích sekcích: `NaN`, neboli Not a Number. Jedná se o speciální hodnotu, která je součástí specifikace IEEE pro čísla s plovoucí desetinnou čárkou a používá se pouze k označení chybějících hodnot typu float.\n", "\n", - "Pro chybějící hodnoty jiného typu než float používá pandas objekt `None` z Pythonu. I když se může zdát matoucí, že se setkáte se dvěma různými typy hodnot, které v podstatě znamenají totéž, existují logické programátorské důvody pro toto rozhodnutí. V praxi tento přístup umožňuje pandas nabídnout dobrý kompromis pro drtivou většinu případů. Přesto však jak `None`, tak `NaN` mají určitá omezení, na která je třeba dávat pozor, pokud jde o jejich použití.\n" + "Pro chybějící hodnoty, které nejsou typu float, používá pandas objekt `None` z Pythonu. I když se může zdát matoucí, že se setkáte se dvěma různými typy hodnot, které v podstatě říkají totéž, existují dobré programátorské důvody pro toto designové rozhodnutí. V praxi tento přístup umožňuje pandas nabídnout dobrý kompromis pro drtivou většinu případů. Přesto však jak `None`, tak `NaN` mají omezení, na která je třeba dávat pozor, pokud jde o jejich použití.\n" ] }, { @@ -615,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: nečíselná chybějící data\n", - "Protože `None` pochází z Pythonu, nemůže být použito v polích NumPy a pandas, která nemají datový typ `'object'`. Pamatujte, že NumPy pole (a datové struktury v pandas) mohou obsahovat pouze jeden typ dat. To jim dává obrovskou sílu pro práci s velkými objemy dat a výpočty, ale zároveň omezuje jejich flexibilitu. Taková pole musí být převedena na „nejnižší společný jmenovatel“, tedy datový typ, který zahrne vše v poli. Když je v poli `None`, znamená to, že pracujete s Python objekty.\n", + "### `None`: ne-float chybějící data\n", + "Protože `None` pochází z Pythonu, nelze jej použít v polích NumPy a pandas, která nemají datový typ `'object'`. Pamatujte, že NumPy pole (a datové struktury v pandas) mohou obsahovat pouze jeden typ dat. To je to, co jim dává jejich obrovskou sílu pro práci s velkými daty a výpočty, ale zároveň to omezuje jejich flexibilitu. Taková pole musí být převedena na „nejnižší společný jmenovatel“, tedy datový typ, který zahrne vše v poli. Když je v poli `None`, znamená to, že pracujete s Python objekty.\n", "\n", - "Pro ukázku, jak to funguje, zvažte následující příklad pole (všimněte si jeho `dtype`):\n" + "Pro názornou ukázku zvažte následující příklad pole (všimněte si jeho `dtype`):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Realita upcast datových typů s sebou nese dva vedlejší efekty. Za prvé, operace budou prováděny na úrovni interpretovaného Python kódu namísto zkompilovaného NumPy kódu. To v podstatě znamená, že jakékoli operace zahrnující `Series` nebo `DataFrames` s hodnotou `None` budou pomalejší. I když si tohoto zpomalení pravděpodobně nevšimnete, u velkých datových sad by to mohlo představovat problém.\n", + "Realita upcastovaných datových typů přináší dva vedlejší účinky. Za prvé, operace budou prováděny na úrovni interpretovaného Python kódu, nikoli na úrovni kompilovaného kódu NumPy. To v podstatě znamená, že jakékoli operace zahrnující `Series` nebo `DataFrames`, které obsahují `None`, budou pomalejší. I když si tohoto výkonového poklesu pravděpodobně nevšimnete, u velkých datových sad by to mohlo představovat problém.\n", "\n", - "Druhý vedlejší efekt vyplývá z prvního. Protože `None` v podstatě vrací `Series` nebo `DataFrame` zpět do světa základního Pythonu, použití agregací NumPy/pandas, jako je `sum()` nebo `min()`, na polích obsahujících hodnotu ``None`` obvykle vyvolá chybu:\n" + "Druhý vedlejší účinek vyplývá z prvního. Protože `None` v podstatě vrací `Series` nebo `DataFrame` zpět do světa běžného Pythonu, použití agregací NumPy/pandas, jako je `sum()` nebo `min()`, na polích obsahujících hodnotu ``None`` obvykle způsobí chybu:\n" ] }, { @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Klíčová myšlenka**: Sčítání (a jiné operace) mezi celými čísly a hodnotami `None` není definováno, což může omezit možnosti práce s datovými sadami, které je obsahují.\n" + "**Klíčový poznatek**: Sčítání (a jiné operace) mezi celými čísly a hodnotami `None` není definováno, což může omezit možnosti práce s datovými sadami, které je obsahují.\n" ] }, { @@ -709,7 +709,7 @@ "source": [ "### `NaN`: chybějící hodnoty typu float\n", "\n", - "Na rozdíl od `None` podporuje NumPy (a tím pádem i pandas) `NaN` pro své rychlé, vektorové operace a ufuncs. Špatnou zprávou je, že jakákoli aritmetická operace provedená na `NaN` vždy vrátí `NaN`. Například:\n" + "Na rozdíl od `None` podporuje NumPy (a tedy i pandas) `NaN` pro své rychlé, vektorové operace a ufuncs. Špatnou zprávou je, že jakákoli aritmetická operace provedená na `NaN` vždy vrátí `NaN`. Například:\n" ] }, { @@ -831,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "Pamatujte: `NaN` je pouze pro chybějící hodnoty s plovoucí desetinnou čárkou; neexistuje žádný ekvivalent `NaN` pro celá čísla, řetězce nebo Booleovské hodnoty.\n" + "Pamatujte: `NaN` je pouze pro chybějící hodnoty s plovoucí desetinnou čárkou; neexistuje žádný ekvivalent `NaN` pro celá čísla, řetězce nebo Booleany.\n" ] }, { @@ -842,7 +842,7 @@ "source": [ "### `NaN` a `None`: nulové hodnoty v pandas\n", "\n", - "I když se `NaN` a `None` mohou chovat poněkud odlišně, pandas je navrženo tak, aby s nimi zacházelo zaměnitelně. Pro lepší pochopení si vezměme `Series` celých čísel:\n" + "I když se `NaN` a `None` mohou chovat trochu odlišně, pandas je přesto navržen tak, aby s nimi pracoval zaměnitelně. Abyste pochopili, co tím myslíme, podívejte se na `Series` celých čísel:\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Při procesu převodu datových typů za účelem dosažení homogenity dat v `Series` a `DataFrame`, pandas ochotně přepíná chybějící hodnoty mezi `None` a `NaN`. Díky této vlastnosti návrhu může být užitečné považovat `None` a `NaN` za dvě různé podoby \"null\" v pandas. Ve skutečnosti některé základní metody, které budete používat k práci s chybějícími hodnotami v pandas, tuto myšlenku odrážejí ve svých názvech:\n", + "Při procesu převodu datových typů na vyšší úroveň za účelem zajištění homogenity dat v `Series` a `DataFrame`, pandas ochotně přepíná chybějící hodnoty mezi `None` a `NaN`. Kvůli této vlastnosti návrhu může být užitečné považovat `None` a `NaN` za dvě různé podoby \"null\" v pandas. Ve skutečnosti některé základní metody, které budete používat k práci s chybějícími hodnotami v pandas, tuto myšlenku odrážejí ve svých názvech:\n", "\n", - "- `isnull()`: Vytváří Booleovskou masku označující chybějící hodnoty\n", + "- `isnull()`: Vytváří booleovskou masku označující chybějící hodnoty\n", "- `notnull()`: Opak metody `isnull()`\n", "- `dropna()`: Vrací filtrovanou verzi dat\n", "- `fillna()`: Vrací kopii dat s vyplněnými nebo imputovanými chybějícími hodnotami\n", "\n", - "Tyto metody jsou důležité zvládnout a osvojit si, takže si je podrobněji projdeme jednu po druhé.\n" + "Tyto metody jsou důležité zvládnout a osvojit si jejich používání, takže si je podrobněji projdeme.\n" ] }, { @@ -924,8 +924,7 @@ "source": [ "### Detekce nulových hodnot\n", "\n", - "Nyní, když jsme pochopili důležitost chybějících hodnot, musíme je v našem datovém souboru nejprve detekovat, než s nimi začneme pracovat. \n", - "Metody `isnull()` a `notnull()` jsou vaše hlavní nástroje pro detekci nulových dat. Obě vracejí Booleovské masky nad vašimi daty.\n" + "Nyní, když jsme pochopili důležitost chybějících hodnot, musíme je v našem datovém souboru nejprve detekovat, než s nimi začneme pracovat. Metody `isnull()` a `notnull()` jsou vaše hlavní nástroje pro detekci nulových dat. Obě vracejí Booleovské masky nad vašimi daty.\n" ] }, { @@ -978,11 +977,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Podívejte se pozorně na výstup. Překvapuje vás něco? Zatímco `0` je aritmetická nula, je to přesto zcela platné celé číslo a pandas ho takto i považuje. `''` je o něco jemnější. Zatímco jsme ho v sekci 1 použili k reprezentaci prázdné hodnoty řetězce, je to přesto objekt typu řetězec a nikoli reprezentace nulové hodnoty, pokud jde o pandas.\n", + "Pozorně se podívejte na výstup. Překvapilo vás něco? I když `0` je aritmetická nula, stále je to zcela platné celé číslo a pandas s ním tak zachází. `''` je trochu jemnější záležitost. Zatímco jsme jej v sekci 1 použili k reprezentaci prázdné hodnoty řetězce, stále se jedná o objekt typu řetězec, nikoli o reprezentaci nulové hodnoty z pohledu pandas.\n", "\n", - "Teď to otočíme a použijeme tyto metody způsobem, jakým je pravděpodobně budete používat v praxi. Boolean masky můžete použít přímo jako index ``Series`` nebo ``DataFrame``, což může být užitečné při práci s izolovanými chybějícími (nebo přítomnými) hodnotami.\n", + "Teď to otočíme a použijeme tyto metody způsobem, který je blíže tomu, jak je budete používat v praxi. Boolean masky můžete použít přímo jako index ``Series`` nebo ``DataFrame``, což může být užitečné při práci s izolovanými chybějícími (nebo přítomnými) hodnotami.\n", "\n", - "Pokud chceme celkový počet chybějících hodnot, stačí provést součet přes masku vytvořenou metodou `isnull()`.\n" + "Pokud chceme celkový počet chybějících hodnot, stačí provést součet nad maskou vytvořenou metodou `isnull()`.\n" ] }, { @@ -1040,7 +1039,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Klíčové poznatky**: Metody `isnull()` a `notnull()` produkují podobné výsledky, když je použijete v DataFramech: zobrazují výsledky a index těchto výsledků, což vám může nesmírně pomoci při práci s vašimi daty.\n" + "**Klíčový poznatek**: Metody `isnull()` a `notnull()` produkují podobné výsledky, když je použijete v DataFramech: zobrazují výsledky a index těchto výsledků, což vám enormně pomůže při práci s vašimi daty.\n" ] }, { @@ -1051,18 +1050,18 @@ "source": [ "### Práce s chybějícími daty\n", "\n", - "> **Cíl učení:** Na konci této podkapitoly byste měli vědět, jak a kdy nahradit nebo odstranit nulové hodnoty z DataFrames.\n", + "> **Cíl učení:** Na konci této podsekce byste měli vědět, jak a kdy nahradit nebo odstranit nulové hodnoty z DataFrame.\n", "\n", - "Modely strojového učení si samy nedokážou poradit s chybějícími daty. Proto je potřeba tyto chybějící hodnoty zpracovat ještě předtím, než data předáme modelu.\n", + "Modely strojového učení si samy s chybějícími daty neporadí. Proto je potřeba před předáním dat modelu tyto chybějící hodnoty vyřešit.\n", "\n", - "Způsob, jakým se chybějící data zpracovávají, s sebou nese jemné kompromisy a může ovlivnit vaši finální analýzu i reálné výsledky.\n", + "Způsob, jakým se chybějící data řeší, s sebou nese jemné kompromisy, které mohou ovlivnit vaše konečné analýzy i výsledky v reálném světě.\n", "\n", - "Existují především dva způsoby, jak se vypořádat s chybějícími daty:\n", + "Existují především dva způsoby, jak pracovat s chybějícími daty:\n", "\n", - "1. Odstranit řádek obsahující chybějící hodnotu \n", - "2. Nahradit chybějící hodnotu jinou hodnotou \n", + "1. Odstranit řádek obsahující chybějící hodnotu\n", + "2. Nahradit chybějící hodnotu jinou hodnotou\n", "\n", - "Oba tyto přístupy a jejich výhody a nevýhody si podrobně rozebereme.\n" + "Obě tyto metody a jejich výhody i nevýhody si podrobně rozebereme.\n" ] }, { @@ -1075,9 +1074,9 @@ "\n", "Množství dat, které předáváme našemu modelu, má přímý vliv na jeho výkon. Odstranění nulových hodnot znamená, že snižujeme počet datových bodů, a tím i velikost datové sady. Proto je vhodné odstranit řádky s nulovými hodnotami, pokud je datová sada poměrně velká.\n", "\n", - "Dalším případem může být situace, kdy určitý řádek nebo sloupec obsahuje mnoho chybějících hodnot. V takovém případě je možné je odstranit, protože by nepřidaly příliš hodnotu naší analýze, jelikož většina dat pro daný řádek/sloupec chybí.\n", + "Dalším případem může být situace, kdy určitý řádek nebo sloupec obsahuje mnoho chybějících hodnot. V takovém případě je možné je odstranit, protože by nepřidaly přílišnou hodnotu naší analýze, jelikož většina dat pro daný řádek/sloupec chybí.\n", "\n", - "Kromě identifikace chybějících hodnot poskytuje pandas pohodlný způsob, jak odstranit nulové hodnoty z `Series` a `DataFrame`. Abychom si to ukázali v praxi, vraťme se k `example3`. Funkce `DataFrame.dropna()` pomáhá odstranit řádky s nulovými hodnotami.\n" + "Kromě identifikace chybějících hodnot poskytuje pandas pohodlný způsob, jak odstranit nulové hodnoty z `Series` a `DataFrame`. Abychom si to ukázali v praxi, vraťme se k `example3`. Funkce `DataFrame.dropna()` pomáhá při odstraňování řádků s nulovými hodnotami.\n" ] }, { @@ -1116,7 +1115,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "Všimněte si, že by to mělo vypadat jako váš výstup z `example3[example3.notnull()]`. Rozdíl zde spočívá v tom, že místo pouhého indexování na základě maskovaných hodnot metoda `dropna` odstranila tyto chybějící hodnoty ze `Series` `example3`.\n", + "Všimněte si, že by to mělo vypadat jako váš výstup z `example3[example3.notnull()]`. Rozdíl je zde v tom, že místo pouhého indexování na maskované hodnoty `dropna` odstranil tyto chybějící hodnoty ze `Series` `example3`.\n", "\n", "Protože DataFrames mají dvě dimenze, nabízejí více možností pro odstranění dat.\n" ] @@ -1208,9 +1207,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Všimli jste si, že pandas převedl dva sloupce na typ float, aby mohl pracovat s hodnotami `NaN`?)\n", + "(Všimli jste si, že pandas převedl dva sloupce na typ float, aby mohl zpracovat hodnoty `NaN`?)\n", "\n", - "Nemůžete odstranit jednotlivou hodnotu z `DataFrame`, takže musíte odstranit celé řádky nebo sloupce. V závislosti na tom, co děláte, můžete chtít provést jedno nebo druhé, a proto vám pandas nabízí možnosti pro obě varianty. Protože ve vědě o datech sloupce obvykle představují proměnné a řádky představují pozorování, je pravděpodobnější, že budete odstraňovat řádky dat; výchozí nastavení pro `dropna()` je odstranit všechny řádky, které obsahují jakékoli nulové hodnoty:\n" + "Z `DataFrame` nelze odstranit jednotlivou hodnotu, takže je nutné odstranit celé řádky nebo sloupce. V závislosti na tom, co děláte, můžete chtít provést jedno nebo druhé, a proto vám pandas nabízí možnosti pro obě varianty. Protože ve vědě o datech sloupce obvykle představují proměnné a řádky představují pozorování, je pravděpodobnější, že budete odstraňovat řádky dat; výchozí nastavení pro `dropna()` je odstranit všechny řádky, které obsahují jakékoli nulové hodnoty:\n" ] }, { @@ -1362,9 +1361,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Všimněte si, že to může odstranit mnoho dat, která byste mohli chtít zachovat, zejména u menších datových sad. Co když chcete odstranit pouze řádky nebo sloupce, které obsahují několik nebo dokonce všechny nulové hodnoty? Tyto nastavení určíte v `dropna` pomocí parametrů `how` a `thresh`.\n", + "Všimněte si, že tímto způsobem můžete ztratit mnoho dat, která byste si možná chtěli ponechat, zejména u menších datových sad. Co když chcete odstranit pouze řádky nebo sloupce, které obsahují několik nebo dokonce všechny nulové hodnoty? Tyto možnosti nastavíte v `dropna` pomocí parametrů `how` a `thresh`.\n", "\n", - "Ve výchozím nastavení je `how='any'` (pokud si to chcete ověřit sami nebo zjistit, jaké další parametry metoda má, spusťte `example4.dropna?` v buňce kódu). Alternativně můžete specifikovat `how='all`, abyste odstranili pouze řádky nebo sloupce, které obsahují všechny nulové hodnoty. Rozšíříme náš příklad `DataFrame`, abychom to viděli v praxi v následujícím cvičení.\n" + "Ve výchozím nastavení je `how='any'` (pokud si to chcete ověřit sami nebo zjistit, jaké další parametry metoda má, spusťte `example4.dropna?` v buňce kódu). Alternativně můžete nastavit `how='all`, aby se odstranily pouze řádky nebo sloupce, které obsahují všechny nulové hodnoty. Rozšíříme náš příklad `DataFrame`, abychom si to ukázali v praxi v následujícím cvičení.\n" ] }, { @@ -1456,10 +1455,10 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> Klíčové poznatky: \n", + "> Klíčové body: \n", "1. Odstranění nulových hodnot je dobrý nápad pouze tehdy, pokud je datová sada dostatečně velká. \n", "2. Celé řádky nebo sloupce lze odstranit, pokud jim chybí většina dat. \n", - "3. Metoda `DataFrame.dropna(axis=)` pomáhá při odstraňování nulových hodnot. Argument `axis` určuje, zda mají být odstraněny řádky nebo sloupce. \n", + "3. Metoda `DataFrame.dropna(axis=)` pomáhá při odstraňování nulových hodnot. Argument `axis` určuje, zda se mají odstranit řádky nebo sloupce. \n", "4. Lze použít také argument `how`. Ve výchozím nastavení je nastaven na `any`. To znamená, že odstraní pouze ty řádky/sloupce, které obsahují jakékoli nulové hodnoty. Může být nastaven na `all`, což specifikuje, že odstraníme pouze ty řádky/sloupce, kde jsou všechny hodnoty nulové. \n" ] }, @@ -1492,7 +1491,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "Parametr `thresh` vám poskytuje jemnější kontrolu: nastavíte počet *ne-null* hodnot, které řádek nebo sloupec musí mít, aby byl zachován:\n" + "Parametr `thresh` vám poskytuje jemnější kontrolu: nastavíte počet *neprázdných* hodnot, které musí řádek nebo sloupec mít, aby byl zachován:\n" ] }, { @@ -1576,11 +1575,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### Vyplňování nulových hodnot\n", + "### Vyplňování chybějících hodnot\n", "\n", - "Někdy má smysl doplnit chybějící hodnoty takovými, které by mohly být platné. Existuje několik technik, jak vyplnit nulové hodnoty. První z nich je použití znalostí domény (znalostí o tématu, na kterém je datová sada založena) k přibližnému odhadu chybějících hodnot.\n", + "Někdy má smysl doplnit chybějící hodnoty takovými, které by mohly být platné. Existuje několik technik, jak vyplnit chybějící hodnoty. První z nich je použití znalostí z dané oblasti (znalostí tématu, na kterém je datová sada založena) k přibližnému odhadu chybějících hodnot.\n", "\n", - "Můžete použít `isnull` k provedení této operace přímo, ale to může být zdlouhavé, zejména pokud máte mnoho hodnot k vyplnění. Protože se jedná o tak běžný úkol v datové vědě, pandas poskytuje funkci `fillna`, která vrací kopii `Series` nebo `DataFrame` s chybějícími hodnotami nahrazenými hodnotami podle vašeho výběru. Pojďme vytvořit další příklad `Series`, abychom viděli, jak to funguje v praxi.\n" + "Můžete použít `isnull` k provedení této operace přímo, ale to může být zdlouhavé, zvláště pokud máte hodně hodnot k vyplnění. Protože se jedná o tak běžný úkol v datové vědě, pandas poskytuje funkci `fillna`, která vrací kopii `Series` nebo `DataFrame` s chybějícími hodnotami nahrazenými hodnotami podle vašeho výběru. Vytvořme další příklad `Series`, abychom viděli, jak to funguje v praxi.\n" ] }, { @@ -1589,12 +1588,12 @@ "id": "CE8S7louLezV" }, "source": [ - "### Kategorická data (Nenumerická)\n", - "Nejprve se podívejme na nenumerická data. V datových sadách máme sloupce s kategorickými daty. Například pohlaví, Pravda nebo Nepravda atd.\n", + "### Kategorická data (nečíselná)\n", + "Nejprve se podívejme na nečíselná data. V datových sadách máme sloupce s kategorickými daty, například pohlaví, Pravda nebo Nepravda atd.\n", "\n", "Ve většině těchto případů nahrazujeme chybějící hodnoty `modem` sloupce. Řekněme, že máme 100 datových bodů, z nichž 90 uvedlo Pravda, 8 uvedlo Nepravda a 2 nevyplnili. Poté můžeme tyto 2 nahradit hodnotou Pravda, pokud zohledníme celý sloupec.\n", "\n", - "I zde můžeme využít znalosti z dané oblasti. Podívejme se na příklad vyplnění pomocí modu.\n" + "Opět zde můžeme využít znalosti z dané oblasti. Podívejme se na příklad vyplnění pomocí modu.\n" ] }, { @@ -1699,7 +1698,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Nyní nejprve najdeme modus, než vyplníme hodnotu `None` pomocí modusu.\n" + ] }, { "cell_type": "code", @@ -1734,7 +1735,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Takže nahradíme None za True\n" + ] }, { "cell_type": "code", @@ -1856,12 +1859,12 @@ "### Číselná data\n", "Nyní se podíváme na číselná data. Zde máme dva běžné způsoby nahrazování chybějících hodnot:\n", "\n", - "1. Nahrazení mediánem řádku\n", - "2. Nahrazení průměrem řádku\n", + "1. Nahrazení mediánem řádku \n", + "2. Nahrazení průměrem řádku \n", "\n", - "Medián používáme v případě, že data jsou zkreslená a obsahují odlehlé hodnoty. Je to proto, že medián je vůči odlehlým hodnotám odolný.\n", + "Medián používáme v případě zkreslených dat s odlehlými hodnotami. Je to proto, že medián je vůči odlehlým hodnotám odolný.\n", "\n", - "Když jsou data normalizovaná, můžeme použít průměr, protože v takovém případě jsou průměr a medián velmi blízko.\n", + "Když jsou data normalizovaná, můžeme použít průměr, protože v takovém případě budou průměr a medián velmi blízko.\n", "\n", "Nejprve si vezměme sloupec, který má normální rozdělení, a vyplňme chybějící hodnoty průměrem sloupce.\n" ] @@ -2003,7 +2006,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Vyplnění průměrem\n" + ] }, { "cell_type": "code", @@ -2112,7 +2117,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Nyní zkusme další dataframe a tentokrát nahradíme hodnoty None mediánem sloupce.\n" + "Nyní zkusme jiný dataframe a tentokrát nahradíme hodnoty None mediánem sloupce.\n" ] }, { @@ -2252,7 +2257,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Vyplnění mediánem\n" + ] }, { "cell_type": "code", @@ -2352,7 +2359,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Jak vidíme, hodnota NaN byla nahrazena mediánem sloupce\n" + "Jak vidíme, hodnota NaN byla nahrazena mediánem sloupce.\n" ] }, { @@ -2435,11 +2442,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Klíčové poznatky: \n", - "1. Vyplňování chybějících hodnot by mělo být prováděno buď tehdy, když je méně dat, nebo když existuje strategie pro doplnění chybějících dat. \n", - "2. K doplnění chybějících hodnot lze využít znalosti z dané oblasti tím, že se hodnoty přibližně odhadnou. \n", - "3. U kategoriálních dat se chybějící hodnoty většinou nahrazují módem sloupce. \n", - "4. U číselných dat se chybějící hodnoty obvykle doplňují průměrem (pro normalizované datové sady) nebo mediánem sloupců. \n" + "> Klíčové poznatky:\n", + "1. Doplnění chybějících hodnot by mělo být provedeno, pokud je k dispozici méně dat nebo existuje strategie, jak chybějící data doplnit.\n", + "2. K doplnění chybějících hodnot lze využít znalosti z dané oblasti a hodnoty přibližně odhadnout.\n", + "3. U kategorických dat se chybějící hodnoty většinou nahrazují módem sloupce.\n", + "4. U číselných dat se chybějící hodnoty obvykle doplňují průměrem (u normalizovaných dat) nebo mediánem sloupců.\n" ] }, { @@ -2470,7 +2477,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "Můžete **doplnit** nulové hodnoty, což znamená použít poslední platnou hodnotu k vyplnění nulové hodnoty:\n" + "Můžete **doplnit dopředu** nulové hodnoty, což znamená použít poslední platnou hodnotu k vyplnění nulové hodnoty:\n" ] }, { @@ -2511,7 +2518,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Můžete také **zpětně vyplnit**, abyste zpětně propagovali další platnou hodnotu a vyplnili null:\n" + "Můžete také **zpětně vyplnit**, abyste propagovali další platnou hodnotu zpět a vyplnili null:\n" ] }, { @@ -2553,7 +2560,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "Jak můžete tušit, toto funguje stejně s DataFrames, ale můžete také specifikovat `axis`, podél kterého chcete vyplnit nulové hodnoty:\n" + "Jak můžete tušit, toto funguje stejně i s DataFrames, ale můžete také specifikovat `axis`, podél kterého chcete vyplnit nulové hodnoty:\n" ] }, { @@ -2850,9 +2857,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Všimněte si, že sloupec 3 je stále bez hodnoty: výchozí směr je vyplňovat hodnoty po řádcích.\n", + "Všimněte si, že sloupec 3 je stále bez hodnot: výchozí směr je vyplňování hodnot po řádcích.\n", "\n", - "> **Shrnutí:** Existuje několik způsobů, jak se vypořádat s chybějícími hodnotami ve vašich datových sadách. Konkrétní strategie, kterou použijete (odstranění, nahrazení nebo způsob, jakým je nahradíte), by měla být určena specifiky těchto dat. Čím více budete s datovými sadami pracovat a interagovat, tím lepší smysl pro řešení chybějících hodnot si vyvinete.\n" + "> **Poučení:** Existuje několik způsobů, jak se vypořádat s chybějícími hodnotami ve vašich datových sadách. Konkrétní strategie, kterou použijete (odstranění, nahrazení nebo způsob nahrazení), by měla být určena specifiky těchto dat. Čím více budete pracovat s datovými sadami, tím lépe si osvojíte způsoby, jak řešit chybějící hodnoty.\n" ] }, { @@ -2863,7 +2870,7 @@ "source": [ "### Kódování kategorických dat\n", "\n", - "Modely strojového učení pracují pouze s čísly a jakoukoli formou číselných dat. Nejsou schopny rozlišit mezi Ano a Ne, ale dokážou rozlišit mezi 0 a 1. Proto je po doplnění chybějících hodnot potřeba zakódovat kategorická data do číselné podoby, aby jim model porozuměl.\n", + "Modely strojového učení pracují pouze s čísly a jakoukoli formou číselných dat. Nebudou schopny rozlišit mezi Ano a Ne, ale dokážou rozlišit mezi 0 a 1. Proto je po doplnění chybějících hodnot potřeba zakódovat kategorická data do nějaké číselné podoby, aby je model pochopil.\n", "\n", "Kódování lze provést dvěma způsoby. Ty si nyní rozebereme.\n" ] @@ -2876,7 +2883,7 @@ "source": [ "**KÓDOVÁNÍ ŠTÍTKŮ**\n", "\n", - "Kódování štítků spočívá v převodu každé kategorie na číslo. Například, řekněme, že máme dataset cestujících letecké společnosti a je zde sloupec obsahující jejich třídu mezi následujícími ['business class', 'economy class', 'first class']. Pokud by bylo provedeno kódování štítků, bylo by to převedeno na [0,1,2]. Podívejme se na příklad pomocí kódu. Protože se budeme učit `scikit-learn` v nadcházejících poznámkových blocích, zde ho nepoužijeme.\n" + "Kódování štítků spočívá v převodu každé kategorie na číslo. Například, řekněme, že máme dataset cestujících letecké společnosti a je zde sloupec obsahující jejich třídu z následujících možností ['business class', 'economy class', 'first class']. Pokud by bylo provedeno kódování štítků, bylo by to převedeno na [0,1,2]. Podívejme se na příklad pomocí kódu. Jelikož se budeme učit `scikit-learn` v nadcházejících poznámkách, zde ho nepoužijeme.\n" ] }, { @@ -2984,7 +2991,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Pro provedení kódování štítků na prvním sloupci musíme nejprve popsat mapování každé třídy na číslo, než provedeme nahrazení\n" + "Pro provedení kódování štítků na 1. sloupci musíme nejprve popsat mapování každé třídy na číslo, než provedeme nahrazení.\n" ] }, { @@ -3086,9 +3093,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Jak vidíme, výsledek odpovídá tomu, co jsme očekávali. Kdy tedy použít label encoding? Label encoding se používá v jednom nebo obou z následujících případů:\n", + "Jak vidíme, výstup odpovídá tomu, co jsme očekávali. Kdy tedy použít kódování štítků? Kódování štítků se používá v jednom nebo obou z následujících případů:\n", "1. Když je počet kategorií velký\n", - "2. Když jsou kategorie v pořadí.\n" + "2. Když jsou kategorie seřazeny.\n" ] }, { @@ -3097,11 +3104,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**JEDNOHOTOVÉ KÓDOVÁNÍ**\n", + "**ONE HOT ENCODING**\n", "\n", - "Dalším typem kódování je Jednohotové kódování (One Hot Encoding). Při tomto typu kódování se každá kategorie ve sloupci přidá jako samostatný sloupec a každý datový bod dostane hodnotu 0 nebo 1 podle toho, zda obsahuje danou kategorii. Pokud tedy existuje n různých kategorií, do datového rámce bude přidáno n sloupců.\n", + "Dalším typem kódování je One Hot Encoding. Při tomto typu kódování se každá kategorie sloupce přidá jako samostatný sloupec a každému datovému bodu se přiřadí 0 nebo 1 podle toho, zda obsahuje danou kategorii. Pokud tedy existuje n různých kategorií, do datového rámce se přidá n sloupců.\n", "\n", - "Například vezměme stejný příklad s třídami v letadle. Kategorie byly: ['business class', 'economy class', 'first class']. Pokud tedy provedeme jednohotové kódování, do datové sady budou přidány následující tři sloupce: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Například vezměme stejný příklad tříd v letadle. Kategorie byly: ['business class', 'economy class', 'first class']. Pokud provedeme One Hot Encoding, do datasetu budou přidány následující tři sloupce: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3209,7 +3216,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "Proveďme one hot encoding na 1. sloupci\n" + "Proveďme one hot encoding na prvním sloupci\n" ] }, { @@ -3343,7 +3350,7 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "Kdy používáme one hot encoding? One hot encoding se používá v jednom nebo obou z následujících případů:\n", + "Kdy používáme one hot encoding? One hot encoding se používá v jednom nebo obou následujících případech:\n", "\n", "1. Když je počet kategorií a velikost datového souboru menší.\n", "2. Když kategorie nemají žádné konkrétní pořadí.\n" @@ -3370,7 +3377,7 @@ "\n", "> **Cíl učení:** Na konci této podsekce byste měli být schopni identifikovat a odstranit duplicitní hodnoty z DataFrames.\n", "\n", - "Kromě chybějících dat se v reálných datových sadách často setkáte s duplicitními daty. Naštěstí pandas nabízí jednoduchý způsob, jak detekovat a odstranit duplicitní záznamy.\n" + "Kromě chybějících dat se v reálných datových sadách často setkáte s duplicitními daty. Naštěstí pandas nabízí snadný způsob, jak detekovat a odstranit duplicitní záznamy.\n" ] }, { @@ -3381,7 +3388,7 @@ "source": [ "### Identifikace duplicit: `duplicated`\n", "\n", - "Duplicitní hodnoty můžete snadno identifikovat pomocí metody `duplicated` v pandas, která vrací Booleovskou masku označující, zda je záznam v `DataFrame` duplicitou dřívějšího záznamu. Vytvořme další příklad `DataFrame`, abychom si to ukázali v praxi.\n" + "Duplicitní hodnoty můžete snadno zjistit pomocí metody `duplicated` v pandas, která vrací Booleovskou masku označující, zda je záznam v `DataFrame` duplicitou dřívějšího záznamu. Vytvořme si další příklad `DataFrame`, abychom to viděli v praxi.\n" ] }, { @@ -3594,7 +3601,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Oba `duplicated` a `drop_duplicates` standardně zvažují všechny sloupce, ale můžete specifikovat, že mají zkoumat pouze podmnožinu sloupců ve vašem `DataFrame`:\n" + "Jak `duplicated`, tak `drop_duplicates` ve výchozím nastavení zohledňují všechny sloupce, ale můžete specifikovat, že mají zkoumat pouze podmnožinu sloupců ve vašem `DataFrame`:\n" ] }, { @@ -3670,13 +3677,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Závěr:** Odstranění duplicitních dat je nezbytnou součástí téměř každého projektu v oblasti datové vědy. Duplicitní data mohou změnit výsledky vašich analýz a poskytnout vám nepřesné výsledky!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Kontroly kvality dat v reálném světě\n", + "\n", + "> **Cíl učení:** Na konci této sekce byste měli být schopni rozpoznat a opravit běžné problémy s kvalitou dat v reálném světě, včetně nekonzistentních hodnot kategorií, abnormálních číselných hodnot (odlehlých bodů) a duplicitních entit s variacemi.\n", + "\n", + "Zatímco chybějící hodnoty a přesné duplicity jsou běžné problémy, datové sady z reálného světa často obsahují jemnější problémy:\n", + "\n", + "1. **Nekonzistentní hodnoty kategorií**: Stejná kategorie napsaná různými způsoby (např. \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Abnormální číselné hodnoty**: Extrémní odlehlé body, které naznačují chyby při zadávání dat (např. věk = 999)\n", + "3. **Téměř duplicitní řádky**: Záznamy, které představují stejnou entitu s drobnými variacemi\n", + "\n", + "Pojďme prozkoumat techniky, jak tyto problémy odhalit a řešit.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Vytvoření ukázkového „špinavého“ datasetu\n", + "\n", + "Nejprve vytvoříme ukázkový dataset, který obsahuje typy problémů, se kterými se běžně setkáváme u reálných dat:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Detekce nekonzistentních hodnot v kategoriích\n", + "\n", + "Všimněte si, že sloupec `country` obsahuje více reprezentací pro stejné země. Pojďme identifikovat tyto nekonzistence:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Standardizace kategoriálních hodnot\n", + "\n", + "Můžeme vytvořit mapování pro standardizaci těchto hodnot. Jednoduchý přístup je převést hodnoty na malá písmena a vytvořit slovník mapování:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternativa: Použití rozmazaného porovnávání**\n", + "\n", + "Pro složitější případy můžeme použít rozmazané porovnávání řetězců s knihovnou `rapidfuzz` k automatické detekci podobných řetězců:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Detekce abnormálních číselných hodnot (odlehlých hodnot)\n", + "\n", + "Při pohledu na sloupec `age` máme některé podezřelé hodnoty, jako například 199 a -5. Použijme statistické metody k detekci těchto odlehlých hodnot.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Použití metody IQR (Interkvartilové rozpětí)\n", + "\n", + "Metoda IQR je robustní statistická technika pro detekci odlehlých hodnot, která je méně citlivá na extrémní hodnoty:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Použití metody Z-skóre\n", + "\n", + "Metoda Z-skóre identifikuje odlehlé hodnoty na základě standardních odchylek od průměru:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Zpracování odlehlých hodnot\n", + "\n", + "Jakmile jsou odlehlé hodnoty detekovány, lze je zpracovat několika způsoby:\n", + "1. **Odstranit**: Smazat řádky s odlehlými hodnotami (pokud se jedná o chyby)\n", + "2. **Omezit**: Nahradit hraničními hodnotami\n", + "3. **Nahradit NaN**: Považovat za chybějící data a použít metody imputace\n", + "4. **Ponechat**: Pokud se jedná o legitimní extrémní hodnoty\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Detekce téměř duplicitních řádků\n", + "\n", + "Všimněte si, že náš dataset obsahuje více záznamů pro „John Smith“ s mírně odlišnými hodnotami. Pojďme identifikovat potenciální duplicity na základě podobnosti jmen.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Hledání téměř duplicit pomocí fuzzy porovnávání\n", + "\n", + "Pro pokročilejší detekci duplicit můžeme použít fuzzy porovnávání k nalezení podobných jmen:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Řešení duplicit\n", + "\n", + "Jakmile jsou duplicity identifikovány, je třeba rozhodnout, jak s nimi naložit:\n", + "1. **Ponechat první výskyt**: Použijte `drop_duplicates(keep='first')`\n", + "2. **Ponechat poslední výskyt**: Použijte `drop_duplicates(keep='last')`\n", + "3. **Agregovat informace**: Sloučit informace z duplicitních řádků\n", + "4. **Ruční kontrola**: Označit k manuálnímu přezkoumání\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Shrnutí: Kompletní proces čištění dat\n", + "\n", + "Spojme vše dohromady do uceleného procesu čištění dat:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Cvičné cvičení\n", + "\n", + "Teď je řada na vás! Níže je nový řádek dat s několika problémy s kvalitou. Dokážete:\n", + "\n", + "1. Identifikovat všechny problémy v tomto řádku\n", + "2. Napsat kód pro opravu každého problému\n", + "3. Přidat opravený řádek do datové sady\n", + "\n", + "Zde jsou problematická data:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Klíčové poznatky\n", + "\n", + "1. **Nekonzistentní kategorie** jsou běžné v reálných datech. Vždy zkontrolujte unikátní hodnoty a standardizujte je pomocí mapování nebo fuzzy porovnávání.\n", + "\n", + "2. **Odlehlé hodnoty** mohou výrazně ovlivnit vaši analýzu. Použijte kombinaci znalostí z oboru a statistických metod (IQR, Z-skóre) k jejich detekci.\n", + "\n", + "3. **Téměř duplicitní hodnoty** je těžší odhalit než přesné duplicity. Zvažte použití fuzzy porovnávání a normalizace dat (převod na malá písmena, odstranění mezer) k jejich identifikaci.\n", + "\n", + "4. **Čištění dat je iterativní proces**. Může být nutné použít více technik a zkontrolovat výsledky před dokončením čištěného datasetu.\n", + "\n", + "5. **Dokumentujte svá rozhodnutí**. Sledujte, jaké kroky čištění jste aplikovali a proč, protože to je důležité pro reprodukovatelnost a transparentnost.\n", + "\n", + "> **Doporučený postup:** Vždy si ponechte kopii původních \"špinavých\" dat. Nikdy nepřepisujte své zdrojové datové soubory – vytvořte vyčištěné verze s jasnými názvy, například `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Prohlášení**: \nTento dokument byl přeložen pomocí služby pro automatický překlad [Co-op Translator](https://github.com/Azure/co-op-translator). I když se snažíme o přesnost, mějte prosím na paměti, že automatické překlady mohou obsahovat chyby nebo nepřesnosti. Původní dokument v jeho původním jazyce by měl být považován za autoritativní zdroj. Pro důležité informace se doporučuje profesionální lidský překlad. Neodpovídáme za žádné nedorozumění nebo nesprávné interpretace vyplývající z použití tohoto překladu.\n" + "\n---\n\n**Prohlášení**: \nTento dokument byl přeložen pomocí služby AI pro překlady [Co-op Translator](https://github.com/Azure/co-op-translator). I když se snažíme o přesnost, mějte prosím na paměti, že automatizované překlady mohou obsahovat chyby nebo nepřesnosti. Původní dokument v jeho původním jazyce by měl být považován za autoritativní zdroj. Pro důležité informace doporučujeme profesionální lidský překlad. Neodpovídáme za žádná nedorozumění nebo nesprávné interpretace vyplývající z použití tohoto překladu.\n" ] } ], @@ -3704,8 +4229,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:26:59+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:56:02+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "cs" } diff --git a/translations/da/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/da/2-Working-With-Data/08-data-preparation/notebook.ipynb index 0f8e50de..66729873 100644 --- a/translations/da/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/da/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# Dataklargøring\n", "\n", - "[Original Notebook-kilde fra *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Original Notebook-kilde fra *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio af Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## Udforskning af `DataFrame`-information\n", "\n", - "> **Læringsmål:** Ved slutningen af dette afsnit bør du være komfortabel med at finde generel information om data, der er gemt i pandas DataFrames.\n", + "> **Læringsmål:** Ved slutningen af denne undersektion bør du være komfortabel med at finde generel information om data, der er gemt i pandas DataFrames.\n", "\n", "Når du har indlæst dine data i pandas, vil de sandsynligvis være i en `DataFrame`. Men hvis datasættet i din `DataFrame` har 60.000 rækker og 400 kolonner, hvordan begynder du så overhovedet at få en fornemmelse af, hvad du arbejder med? Heldigvis tilbyder pandas nogle praktiske værktøjer til hurtigt at få et overblik over en `DataFrame` samt de første og sidste par rækker.\n", "\n", - "For at udforske denne funktionalitet vil vi importere Python-biblioteket scikit-learn og bruge et ikonisk datasæt, som enhver dataforsker har set hundredevis af gange: Den britiske biolog Ronald Fishers *Iris*-datasæt, der blev brugt i hans artikel fra 1936 \"The use of multiple measurements in taxonomic problems\":\n" + "For at udforske denne funktionalitet vil vi importere Python scikit-learn-biblioteket og bruge et ikonisk datasæt, som enhver dataforsker har set hundredevis af gange: Den britiske biolog Ronald Fishers *Iris*-datasæt, der blev brugt i hans artikel fra 1936 \"The use of multiple measurements in taxonomic problems\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Vi har indlæst Iris-datasættet i variablen `iris_df`. Før vi dykker ned i dataene, vil det være nyttigt at kende antallet af datapunkter, vi har, samt den samlede størrelse af datasættet. Det er værdifuldt at få et overblik over mængden af data, vi arbejder med.\n" + "Vi har indlæst Iris-datasættet i variablen `iris_df`. Før vi dykker ned i dataene, vil det være værdifuldt at kende antallet af datapunkter, vi har, og den samlede størrelse af datasættet. Det er nyttigt at få et overblik over mængden af data, vi arbejder med.\n" ] }, { @@ -78,7 +78,7 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Så vi har at gøre med 150 rækker og 4 kolonner af data. Hver række repræsenterer ét datapunkt, og hver kolonne repræsenterer en enkelt egenskab forbundet med dataframen. Så grundlæggende er der 150 datapunkter, der hver indeholder 4 egenskaber.\n", + "Så vi har med 150 rækker og 4 kolonner af data at gøre. Hver række repræsenterer et datapunkt, og hver kolonne repræsenterer en enkelt egenskab, der er knyttet til dataframen. Så grundlæggende er der 150 datapunkter, der hver indeholder 4 egenskaber.\n", "\n", "`shape` her er en attribut for dataframen og ikke en funktion, hvilket er grunden til, at den ikke slutter med et par parenteser.\n" ] @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Lad os nu se på de 4 kolonner af data. Hvad repræsenterer hver af dem præcist? Attributten `columns` vil give os navnene på kolonnerne i dataframen.\n" + "Lad os nu gå videre til de 4 kolonner af data. Hvad repræsenterer hver af dem præcist? Attributten `columns` vil give os navnene på kolonnerne i dataframen.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Som vi kan se, er der fire(4) kolonner. Attributten `columns` fortæller os navnene på kolonnerne og stort set ikke andet. Denne attribut bliver vigtig, når vi ønsker at identificere de funktioner, et datasæt indeholder.\n" + "Som vi kan se, er der fire(4) kolonner. `columns` attributten fortæller os navnene på kolonnerne og grundlæggende intet andet. Denne attribut bliver vigtig, når vi ønsker at identificere de funktioner, et datasæt indeholder.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Fra dette punkt kan vi gøre nogle få observationer:\n", + "Herfra kan vi gøre nogle få observationer:\n", "1. Datatypen for hver kolonne: I dette datasæt er alle data gemt som 64-bit flydende tal.\n", - "2. Antal ikke-null værdier: Håndtering af null-værdier er et vigtigt skridt i databehandling. Dette vil blive behandlet senere i notebooken.\n" + "2. Antallet af ikke-null værdier: Håndtering af null-værdier er et vigtigt skridt i dataklargøring. Dette vil blive behandlet senere i notebooken.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Lad os sige, at vi har en masse numeriske data i vores datasæt. Univariate statistiske beregninger såsom gennemsnit, median, kvartiler osv. kan udføres på hver af kolonnerne individuelt. Funktionen `DataFrame.describe()` giver os et statistisk overblik over de numeriske kolonner i et datasæt.\n" + "Lad os sige, at vi har en masse numeriske data i vores datasæt. Univariate statistiske beregninger som gennemsnit, median, kvartiler osv. kan udføres på hver af kolonnerne individuelt. Funktionen `DataFrame.describe()` giver os en statistisk oversigt over de numeriske kolonner i et datasæt.\n" ] }, { @@ -332,7 +332,7 @@ }, "source": [ "### `DataFrame.head`\n", - "Med alle de ovenstående funktioner og attributter har vi fået et overordnet overblik over datasættet. Vi ved, hvor mange datapunkter der er, hvor mange funktioner der er, datatypen for hver funktion og antallet af ikke-null værdier for hver funktion.\n", + "Med alle de ovenstående funktioner og attributter har vi fået et overordnet billede af datasættet. Vi ved, hvor mange datapunkter der er, hvor mange funktioner der er, datatypen for hver funktion og antallet af ikke-null værdier for hver funktion.\n", "\n", "Nu er det tid til at se på selve dataene. Lad os se, hvordan de første par rækker (de første par datapunkter) i vores `DataFrame` ser ud:\n" ] @@ -452,7 +452,7 @@ "source": [ "### Øvelse:\n", "\n", - "Fra eksemplet ovenfor er det tydeligt, at `DataFrame.head` som standard returnerer de første fem rækker af en `DataFrame`. Kan du i kodecellen nedenfor finde en måde at vise mere end fem rækker?\n" + "Ud fra eksemplet ovenfor er det tydeligt, at `DataFrame.head` som standard returnerer de første fem rækker af en `DataFrame`. Kan du i kodecellen nedenfor finde en måde at vise mere end fem rækker på?\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "I praksis er det nyttigt at kunne nemt undersøge de første par rækker eller de sidste par rækker af en `DataFrame`, især når du leder efter afvigelser i ordnede datasæt.\n", + "I praksis er det nyttigt nemt at kunne undersøge de første par rækker eller de sidste par rækker af en `DataFrame`, især når du leder efter outliers i ordnede datasæt.\n", "\n", "Alle de funktioner og attributter, der er vist ovenfor med hjælp fra kodeeksempler, hjælper os med at få et indtryk af dataene.\n", "\n", - "> **Konklusion:** Bare ved at kigge på metadata om informationen i en DataFrame eller de første og sidste par værdier i en, kan du få en øjeblikkelig idé om størrelsen, formen og indholdet af de data, du arbejder med.\n" + "> **Vigtig pointe:** Bare ved at kigge på metadata om informationen i en DataFrame eller de første og sidste værdier i en, kan du hurtigt få en idé om størrelsen, formen og indholdet af de data, du arbejder med.\n" ] }, { @@ -598,13 +598,13 @@ "### Manglende Data\n", "Lad os dykke ned i manglende data. Manglende data opstår, når der ikke er gemt nogen værdi i nogle af kolonnerne.\n", "\n", - "Lad os tage et eksempel: forestil dig, at en person er bevidst om sin vægt og undlader at udfylde vægtfeltet i en undersøgelse. Så vil vægtværdien for denne person være manglende.\n", + "Lad os tage et eksempel: forestil dig, at en person er meget bevidst om sin vægt og derfor ikke udfylder vægtfeltet i en undersøgelse. Så vil vægtværdien for denne person mangle.\n", "\n", "I de fleste tilfælde opstår manglende værdier i datasæt fra den virkelige verden.\n", "\n", "**Hvordan Pandas håndterer manglende data**\n", "\n", - "Pandas håndterer manglende værdier på to måder. Den første har du set før i tidligere afsnit: `NaN`, eller Not a Number. Dette er faktisk en speciel værdi, der er en del af IEEE's flydende-punkt specifikation, og den bruges kun til at indikere manglende værdier af typen flydende tal.\n", + "Pandas håndterer manglende værdier på to måder. Den første har du allerede set i tidligere afsnit: `NaN`, eller Not a Number. Dette er faktisk en speciel værdi, der er en del af IEEE's flydende-punkt specifikation, og den bruges kun til at indikere manglende værdier for flydende tal.\n", "\n", "For manglende værdier, der ikke er flydende tal, bruger pandas Python-objektet `None`. Selvom det kan virke forvirrende, at du støder på to forskellige typer værdier, der grundlæggende betyder det samme, er der gode programmatiske grunde til dette designvalg. I praksis gør denne tilgang det muligt for pandas at levere et godt kompromis i langt de fleste tilfælde. Ikke desto mindre har både `None` og `NaN` begrænsninger, som du skal være opmærksom på i forhold til, hvordan de kan bruges.\n" ] @@ -616,9 +616,9 @@ }, "source": [ "### `None`: ikke-flydende manglende data\n", - "Fordi `None` stammer fra Python, kan det ikke bruges i NumPy- og pandas-arrays, der ikke har datatypen `'object'`. Husk, at NumPy-arrays (og datastrukturerne i pandas) kun kan indeholde én type data. Dette er det, der giver dem deres enorme styrke til storskala data- og beregningsarbejde, men det begrænser også deres fleksibilitet. Sådanne arrays skal opgradere til den \"laveste fællesnævner,\" den datatype, der kan rumme alt i arrayet. Når `None` er i arrayet, betyder det, at du arbejder med Python-objekter.\n", + "Da `None` stammer fra Python, kan det ikke bruges i NumPy- og pandas-arrays, der ikke har datatypen `'object'`. Husk, at NumPy-arrays (og datastrukturerne i pandas) kun kan indeholde én type data. Det er netop dette, der giver dem deres enorme styrke til storskala data- og beregningsarbejde, men det begrænser også deres fleksibilitet. Sådanne arrays skal opgradere til den \"laveste fællesnævner,\" altså den datatype, der kan rumme alt i arrayet. Når `None` er i arrayet, betyder det, at du arbejder med Python-objekter.\n", "\n", - "For at se dette i praksis, overvej følgende eksempel-array (bemærk `dtype` for det):\n" + "For at se dette i praksis, overvej følgende eksempel på et array (bemærk dets `dtype`):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Virkeligheden ved opgraderede datatyper medfører to bivirkninger. For det første vil operationer blive udført på niveauet af fortolket Python-kode i stedet for kompileret NumPy-kode. Grundlæggende betyder det, at enhver operation, der involverer `Series` eller `DataFrames` med `None` i dem, vil være langsommere. Selvom du sandsynligvis ikke vil bemærke denne præstationsnedgang, kan det blive et problem for store datasæt.\n", + "Virkeligheden ved opcasting af datatyper medfører to bivirkninger. For det første vil operationer blive udført på niveauet af fortolket Python-kode i stedet for kompileret NumPy-kode. Grundlæggende betyder det, at enhver operation, der involverer `Series` eller `DataFrames` med `None` i dem, vil være langsommere. Selvom du sandsynligvis ikke vil bemærke denne præstationsnedgang, kan det blive et problem for store datasæt.\n", "\n", - "Den anden bivirkning stammer fra den første. Fordi `None` i bund og grund trækker `Series` eller `DataFrame`s tilbage til den almindelige Python-verden, vil brugen af NumPy/pandas-aggregationer som `sum()` eller `min()` på arrays, der indeholder en ``None``-værdi, generelt resultere i en fejl:\n" + "Den anden bivirkning udspringer af den første. Fordi `None` i bund og grund trækker `Series` eller `DataFrame`s tilbage til den almindelige Python-verden, vil brugen af NumPy/pandas-aggregationer som `sum()` eller `min()` på arrays, der indeholder en ``None``-værdi, generelt resultere i en fejl:\n" ] }, { @@ -709,7 +709,7 @@ "source": [ "### `NaN`: manglende float-værdier\n", "\n", - "I modsætning til `None` understøtter NumPy (og dermed pandas) `NaN` for sine hurtige, vektoriserede operationer og ufuncs. Den dårlige nyhed er, at enhver aritmetisk operation udført på `NaN` altid resulterer i `NaN`. For eksempel:\n" + "I modsætning til `None` understøtter NumPy (og dermed pandas) `NaN` for sine hurtige, vektoriserede operationer og ufuncs. Den dårlige nyhed er, at enhver aritmetik udført på `NaN` altid resulterer i `NaN`. For eksempel:\n" ] }, { @@ -831,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "Husk: `NaN` er kun for manglende flydende punktværdier; der findes ingen `NaN`-ækvivalent for heltal, strenge eller boolske værdier.\n" + "Husk: `NaN` er kun for manglende flydende punktværdier; der findes ikke en `NaN`-ækvivalent for heltal, strenge eller boolske værdier.\n" ] }, { @@ -842,7 +842,7 @@ "source": [ "### `NaN` og `None`: null-værdier i pandas\n", "\n", - "Selvom `NaN` og `None` kan opføre sig en smule forskelligt, er pandas stadig designet til at håndtere dem som udskiftelige. For at illustrere dette, lad os se på en `Series` af heltal:\n" + "Selvom `NaN` og `None` kan opføre sig lidt forskelligt, er pandas alligevel designet til at håndtere dem som udskiftelige. For at forstå dette, kan vi se på en `Series` af heltal:\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "I processen med at opgradere datatyper for at etablere datakonsistens i `Series` og `DataFrame`s, vil pandas villigt skifte manglende værdier mellem `None` og `NaN`. På grund af denne designfunktion kan det være nyttigt at tænke på `None` og `NaN` som to forskellige varianter af \"null\" i pandas. Faktisk afspejler nogle af de centrale metoder, du vil bruge til at håndtere manglende værdier i pandas, denne idé i deres navne:\n", + "I processen med at opgradere datatyper for at etablere datahomogenitet i `Series` og `DataFrame`s, vil pandas villigt skifte manglende værdier mellem `None` og `NaN`. På grund af denne designfunktion kan det være nyttigt at tænke på `None` og `NaN` som to forskellige typer af \"null\" i pandas. Faktisk afspejler nogle af de centrale metoder, du vil bruge til at håndtere manglende værdier i pandas, denne idé i deres navne:\n", "\n", "- `isnull()`: Genererer en Boolean-maske, der angiver manglende værdier\n", - "- `notnull()`: Modsatte af `isnull()`\n", + "- `notnull()`: Modsat af `isnull()`\n", "- `dropna()`: Returnerer en filtreret version af dataene\n", "- `fillna()`: Returnerer en kopi af dataene med manglende værdier udfyldt eller estimeret\n", "\n", - "Disse metoder er vigtige at mestre og blive fortrolig med, så lad os gennemgå dem hver især i lidt dybde.\n" + "Disse metoder er vigtige at mestre og blive fortrolig med, så lad os gennemgå dem hver især i detaljer.\n" ] }, { @@ -924,8 +924,7 @@ "source": [ "### Registrering af null-værdier\n", "\n", - "Nu hvor vi har forstået vigtigheden af manglende værdier, skal vi registrere dem i vores datasæt, før vi håndterer dem. \n", - "Både `isnull()` og `notnull()` er dine primære metoder til at registrere null-data. Begge returnerer Boolean-masker over dine data.\n" + "Nu hvor vi har forstået vigtigheden af manglende værdier, skal vi registrere dem i vores datasæt, før vi håndterer dem. Både `isnull()` og `notnull()` er dine primære metoder til at registrere null-data. Begge returnerer Boolean-masker over dine data.\n" ] }, { @@ -978,11 +977,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Se nøje på outputtet. Er der noget af det, der overrasker dig? Selvom `0` er en aritmetisk nul, er det ikke desto mindre et fuldt gyldigt heltal, og pandas behandler det som sådan. `''` er lidt mere subtil. Selvom vi brugte det i Afsnit 1 til at repræsentere en tom strengværdi, er det ikke desto mindre et strengobjekt og ikke en repræsentation af null, når det kommer til pandas.\n", + "Se nøje på outputtet. Er der noget, der overrasker dig? Selvom `0` er en aritmetisk null, er det stadig en fuldt gyldig integer, og pandas behandler det som sådan. `''` er lidt mere subtilt. Selvom vi brugte det i afsnit 1 til at repræsentere en tom strengværdi, er det stadig et strengobjekt og ikke en repræsentation af null, når det kommer til pandas.\n", "\n", "Lad os nu vende det om og bruge disse metoder på en måde, der minder mere om, hvordan du vil bruge dem i praksis. Du kan bruge Boolean-masker direkte som en ``Series``- eller ``DataFrame``-indeks, hvilket kan være nyttigt, når du forsøger at arbejde med isolerede manglende (eller tilstedeværende) værdier.\n", "\n", - "Hvis vi ønsker det samlede antal manglende værdier, kan vi blot lave en sum over masken, der produceres af `isnull()`-metoden.\n" + "Hvis vi vil have det samlede antal manglende værdier, kan vi blot lave en sum over masken, der er produceret af metoden `isnull()`.\n" ] }, { @@ -1053,16 +1052,16 @@ "\n", "> **Læringsmål:** Ved slutningen af dette afsnit bør du vide, hvordan og hvornår du skal erstatte eller fjerne null-værdier fra DataFrames.\n", "\n", - "Maskinlæringsmodeller kan ikke selv håndtere manglende data. Derfor skal vi tage os af disse manglende værdier, inden vi sender dataene ind i modellen.\n", + "Maskinlæringsmodeller kan ikke selv håndtere manglende data. Derfor skal vi tage os af disse manglende værdier, før vi sender dataene ind i modellen.\n", "\n", - "Måden, hvorpå manglende data håndteres, indebærer subtile afvejninger og kan påvirke din endelige analyse og resultater i den virkelige verden.\n", + "Hvordan manglende data håndteres, indebærer subtile afvejninger, som kan påvirke din endelige analyse og resultater i den virkelige verden.\n", "\n", "Der er primært to måder at håndtere manglende data på:\n", "\n", - "1. Slet rækken, der indeholder den manglende værdi \n", - "2. Erstat den manglende værdi med en anden værdi \n", + "1. Slette rækken, der indeholder den manglende værdi\n", + "2. Erstatte den manglende værdi med en anden værdi\n", "\n", - "Vi vil diskutere begge disse metoder samt deres fordele og ulemper i detaljer.\n" + "Vi vil diskutere begge metoder og deres fordele og ulemper i detaljer.\n" ] }, { @@ -1073,11 +1072,11 @@ "source": [ "### Fjernelse af null-værdier\n", "\n", - "Mængden af data, vi giver til vores model, har en direkte indflydelse på dens ydeevne. At fjerne null-værdier betyder, at vi reducerer antallet af datapunkter og dermed størrelsen af datasættet. Derfor anbefales det at fjerne rækker med null-værdier, når datasættet er ret stort.\n", + "Mængden af data, vi giver til vores model, har en direkte indflydelse på dens ydeevne. At fjerne null-værdier betyder, at vi reducerer antallet af datapunkter og dermed størrelsen på datasættet. Derfor anbefales det at fjerne rækker med null-værdier, når datasættet er ret stort.\n", "\n", - "En anden situation kan være, at en bestemt række eller kolonne har mange manglende værdier. I så fald kan de fjernes, da de ikke vil bidrage væsentligt til vores analyse, fordi størstedelen af dataene mangler for den række/kolonne.\n", + "En anden situation kan være, at en bestemt række eller kolonne har mange manglende værdier. I så fald kan de fjernes, da de ikke vil bidrage meget til vores analyse, fordi størstedelen af dataene mangler for den række/kolonne.\n", "\n", - "Udover at identificere manglende værdier tilbyder pandas en praktisk metode til at fjerne null-værdier fra `Series` og `DataFrame`s. For at se dette i praksis, lad os vende tilbage til `example3`. Funktionen `DataFrame.dropna()` hjælper med at fjerne rækker med null-værdier.\n" + "Ud over at identificere manglende værdier tilbyder pandas en praktisk metode til at fjerne null-værdier fra `Series` og `DataFrame`s. For at se dette i praksis, lad os vende tilbage til `example3`. Funktionen `DataFrame.dropna()` hjælper med at fjerne rækker med null-værdier.\n" ] }, { @@ -1116,7 +1115,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "Bemærk, at dette skal ligne dit output fra `example3[example3.notnull()]`. Forskellen her er, at i stedet for blot at indeksere på de maskerede værdier, har `dropna` fjernet de manglende værdier fra `Series` `example3`.\n", + "Bemærk, at dette bør ligne dit output fra `example3[example3.notnull()]`. Forskellen her er, at i stedet for blot at indeksere de maskerede værdier, har `dropna` fjernet de manglende værdier fra `Series` `example3`.\n", "\n", "Da DataFrames har to dimensioner, giver de flere muligheder for at fjerne data.\n" ] @@ -1208,9 +1207,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Lagde du mærke til, at pandas opgraderede to af kolonnerne til floats for at håndtere `NaN`-værdierne?)\n", + "(Bemærkede du, at pandas opgraderede to af kolonnerne til floats for at håndtere `NaN`-værdierne?)\n", "\n", - "Du kan ikke fjerne en enkelt værdi fra en `DataFrame`, så du er nødt til at fjerne hele rækker eller kolonner. Afhængigt af hvad du arbejder med, kan det være, at du vil gøre det ene eller det andet, og derfor giver pandas dig muligheder for begge dele. Fordi kolonner generelt repræsenterer variabler og rækker repræsenterer observationer inden for data science, er det mere sandsynligt, at du vil fjerne rækker af data; standardindstillingen for `dropna()` er at fjerne alle rækker, der indeholder nogen null-værdier:\n" + "Du kan ikke fjerne en enkelt værdi fra en `DataFrame`, så du er nødt til at fjerne hele rækker eller kolonner. Afhængigt af hvad du arbejder med, kan det være nødvendigt at gøre det ene eller det andet, og derfor giver pandas dig muligheder for begge dele. Fordi kolonner generelt repræsenterer variabler og rækker repræsenterer observationer inden for datavidenskab, er det mere almindeligt at fjerne rækker af data; standardindstillingen for `dropna()` er at fjerne alle rækker, der indeholder nogen null-værdier:\n" ] }, { @@ -1283,7 +1282,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "Hvis nødvendigt, kan du fjerne NA-værdier fra kolonner. Brug `axis=1` til at gøre det:\n" + "Hvis nødvendigt, kan du fjerne NA-værdier fra kolonner. Brug `axis=1` til dette:\n" ] }, { @@ -1362,9 +1361,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Bemærk, at dette kan fjerne en del data, som du måske ønsker at beholde, især i mindre datasæt. Hvad hvis du kun vil fjerne rækker eller kolonner, der indeholder flere eller endda alle null-værdier? Du angiver disse indstillinger i `dropna` med parametrene `how` og `thresh`.\n", + "Bemærk, at dette kan fjerne en masse data, som du måske gerne vil beholde, især i mindre datasæt. Hvad nu, hvis du kun vil fjerne rækker eller kolonner, der indeholder flere eller endda alle null-værdier? Du kan angive disse indstillinger i `dropna` med parametrene `how` og `thresh`.\n", "\n", - "Som standard er `how='any'` (hvis du gerne vil kontrollere det selv eller se, hvilke andre parametre metoden har, kan du køre `example4.dropna?` i en kodecelle). Alternativt kan du angive `how='all'` for kun at fjerne rækker eller kolonner, der indeholder alle null-værdier. Lad os udvide vores eksempel `DataFrame` for at se dette i praksis i den næste øvelse.\n" + "Som standard er `how='any'` (hvis du gerne vil tjekke det selv eller se, hvilke andre parametre metoden har, kan du køre `example4.dropna?` i en kodecelle). Alternativt kan du angive `how='all'` for kun at fjerne rækker eller kolonner, der indeholder alle null-værdier. Lad os udvide vores eksempel `DataFrame` for at se dette i praksis i den næste øvelse.\n" ] }, { @@ -1580,7 +1579,7 @@ "\n", "Det giver nogle gange mening at udfylde manglende værdier med nogle, der kunne være gyldige. Der er flere teknikker til at udfylde null-værdier. Den første er at bruge domæneviden (viden om det emne, som datasættet er baseret på) til på en eller anden måde at estimere de manglende værdier.\n", "\n", - "Du kunne bruge `isnull` til at gøre dette direkte, men det kan være tidskrævende, især hvis du har mange værdier, der skal udfyldes. Fordi dette er en så almindelig opgave inden for data science, tilbyder pandas `fillna`, som returnerer en kopi af `Series` eller `DataFrame` med de manglende værdier erstattet med en værdi, du vælger. Lad os oprette et andet eksempel på en `Series` for at se, hvordan dette fungerer i praksis.\n" + "Du kunne bruge `isnull` til at gøre dette direkte, men det kan være tidskrævende, især hvis du har mange værdier, der skal udfyldes. Fordi dette er en så almindelig opgave inden for data science, tilbyder pandas `fillna`, som returnerer en kopi af `Series` eller `DataFrame` med de manglende værdier erstattet med en, du vælger. Lad os oprette et andet eksempel på en `Series` for at se, hvordan dette fungerer i praksis.\n" ] }, { @@ -1589,7 +1588,7 @@ "id": "CE8S7louLezV" }, "source": [ - "### Kategoriske Data (Ikke-numerisk)\n", + "### Kategoriske data (ikke-numeriske)\n", "Lad os først se på ikke-numeriske data. I datasæt har vi kolonner med kategoriske data, f.eks. Køn, Sandt eller Falsk osv.\n", "\n", "I de fleste af disse tilfælde erstatter vi manglende værdier med `mode` for kolonnen. Lad os sige, at vi har 100 datapunkter, hvor 90 har angivet Sandt, 8 har angivet Falsk, og 2 ikke har udfyldt. Så kan vi udfylde de 2 med Sandt, baseret på hele kolonnen.\n", @@ -1699,7 +1698,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Nu, lad os først finde typetallet, før vi udfylder `None`-værdien med typetallet.\n" + ] }, { "cell_type": "code", @@ -1734,7 +1735,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Så vi vil erstatte None med True\n" + ] }, { "cell_type": "code", @@ -1844,7 +1847,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Som vi kan se, er null-værdien blevet erstattet. Det er unødvendigt at sige, at vi kunne have skrevet hvad som helst i stedet for `'True'`, og det ville være blevet erstattet.\n" + "Som vi kan se, er null-værdien blevet erstattet. Det er unødvendigt at sige, at vi kunne have skrevet hvad som helst i stedet for `'True'`, og det ville være blevet substitueret.\n" ] }, { @@ -1854,16 +1857,16 @@ }, "source": [ "### Numeriske Data\n", - "Nu, lad os se på numeriske data. Her har vi to almindelige måder at erstatte manglende værdier på:\n", + "Nu kommer vi til numeriske data. Her har vi to almindelige måder at erstatte manglende værdier på:\n", "\n", - "1. Erstat med medianen af rækken\n", - "2. Erstat med gennemsnittet af rækken\n", + "1. Erstat med medianen for rækken\n", + "2. Erstat med gennemsnittet for rækken\n", "\n", "Vi erstatter med medianen i tilfælde af skæve data med outliers. Dette skyldes, at medianen er robust over for outliers.\n", "\n", "Når dataene er normaliserede, kan vi bruge gennemsnittet, da gennemsnit og median i så fald vil være ret tæt på hinanden.\n", "\n", - "Lad os først tage en kolonne, der er normalfordelt, og udfylde den manglende værdi med gennemsnittet af kolonnen.\n" + "Lad os først tage en kolonne, der er normalt fordelt, og udfylde den manglende værdi med gennemsnittet for kolonnen.\n" ] }, { @@ -2003,7 +2006,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Fyldning med gennemsnit\n" + ] }, { "cell_type": "code", @@ -2112,7 +2117,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Nu lad os prøve en anden dataframe, og denne gang vil vi erstatte None-værdierne med medianen af kolonnen.\n" + "Lad os nu prøve en anden dataframe, og denne gang vil vi erstatte None-værdierne med medianen af kolonnen.\n" ] }, { @@ -2252,7 +2257,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Fyldning med median\n" + ] }, { "cell_type": "code", @@ -2352,7 +2359,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Som vi kan se, er NaN-værdien blevet erstattet af medianen for kolonnen\n" + "Som vi kan se, er NaN-værdien blevet erstattet med medianen af kolonnen\n" ] }, { @@ -2435,11 +2442,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Vigtige pointer: \n", - "1. Udfyldning af manglende værdier bør kun ske, når der enten er få data, eller der findes en strategi til at udfylde de manglende data. \n", - "2. Domæneviden kan bruges til at udfylde manglende værdier ved at estimere dem. \n", - "3. For kategoriske data bliver manglende værdier oftest erstattet med modus for kolonnen. \n", - "4. For numeriske data bliver manglende værdier normalt udfyldt med gennemsnittet (for normaliserede datasæt) eller medianen for kolonnerne. \n" + "> Vigtige pointer:\n", + "1. Udfyldning af manglende værdier bør kun ske, når der enten er begrænset data, eller der findes en strategi til at udfylde de manglende data.\n", + "2. Faglig viden kan bruges til at estimere og udfylde manglende værdier.\n", + "3. For kategoriske data bliver manglende værdier ofte erstattet med kolonnens typetal.\n", + "4. For numeriske data bliver manglende værdier typisk udfyldt med gennemsnittet (for normaliserede datasæt) eller medianen af kolonnerne.\n" ] }, { @@ -2726,7 +2733,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Bemærk, at når en tidligere værdi ikke er tilgængelig for fremadfyldning, forbliver null-værdien.\n" + "Bemærk, at når en tidligere værdi ikke er tilgængelig til fremadfyldning, forbliver null-værdien.\n" ] }, { @@ -2850,9 +2857,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Bemærk, at kolonne 3 stadig mangler værdier: standardretningen er at udfylde værdier rækkevis.\n", + "Bemærk, at kolonne 3 stadig er uden værdi: standardretningen er at udfylde værdier rækkevis.\n", "\n", - "> **Hovedpointe:** Der er flere måder at håndtere manglende værdier i dine datasæt på. Den specifikke strategi, du vælger (at fjerne dem, erstatte dem eller endda hvordan du erstatter dem), bør afhænge af de specifikke forhold i dataene. Jo mere du arbejder med og interagerer med datasæt, desto bedre bliver du til at håndtere manglende værdier.\n" + "> **Konklusion:** Der er flere måder at håndtere manglende værdier i dine datasæt. Den specifikke strategi, du vælger (at fjerne dem, erstatte dem eller endda hvordan du erstatter dem), bør afhænge af de specifikke forhold i dataene. Du vil få en bedre fornemmelse af, hvordan du håndterer manglende værdier, jo mere du arbejder med og interagerer med datasæt.\n" ] }, { @@ -2861,11 +2868,11 @@ "id": "bauDnESIl9FH" }, "source": [ - "### Kodning af Kategoriske Data\n", + "### Kodning af kategoriske data\n", "\n", - "Maskinlæringsmodeller arbejder kun med tal og enhver form for numeriske data. De kan ikke skelne mellem et Ja og et Nej, men de kan skelne mellem 0 og 1. Så efter at have udfyldt de manglende værdier, skal vi kode de kategoriske data til en numerisk form, som modellen kan forstå.\n", + "Maskinlæringsmodeller arbejder kun med tal og enhver form for numeriske data. De kan ikke skelne mellem et Ja og et Nej, men de kan skelne mellem 0 og 1. Så efter at have udfyldt de manglende værdier, skal vi kode de kategoriske data til en eller anden numerisk form, så modellen kan forstå dem.\n", "\n", - "Kodning kan udføres på to måder. Vi vil diskutere dem i det følgende.\n" + "Kodning kan udføres på to måder. Vi vil diskutere dem næste.\n" ] }, { @@ -2876,7 +2883,7 @@ "source": [ "**LABEL ENCODERING**\n", "\n", - "Label-encodering handler grundlæggende om at konvertere hver kategori til et tal. For eksempel, lad os sige, at vi har et datasæt med flypassagerer, og der er en kolonne, der indeholder deres klasse blandt følgende ['business class', 'economy class', 'first class']. Hvis der udføres label-encodering på dette, vil det blive transformeret til [0,1,2]. Lad os se et eksempel via kode. Da vi kommer til at lære `scikit-learn` i de kommende notesbøger, vil vi ikke bruge det her.\n" + "Label-encodering handler grundlæggende om at konvertere hver kategori til et tal. For eksempel, lad os sige, at vi har et datasæt med flypassagerer, og der er en kolonne, der indeholder deres klasse blandt følgende ['business class', 'economy class', 'first class']. Hvis der udføres label-encodering på dette, vil det blive transformeret til [0,1,2]. Lad os se et eksempel via kode. Da vi vil lære `scikit-learn` i de kommende notebooks, vil vi ikke bruge det her.\n" ] }, { @@ -2984,7 +2991,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "For at udføre label encoding på den første kolonne, skal vi først beskrive en mapping fra hver klasse til et nummer, før vi erstatter\n" + "For at udføre label encoding på den første kolonne, skal vi først beskrive en mapping fra hver klasse til et tal, før vi erstatter\n" ] }, { @@ -3086,7 +3093,7 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Som vi kan se, stemmer resultatet overens med, hvad vi forventede. Så hvornår bruger vi label encoding? Label encoding bruges i en eller begge af følgende tilfælde:\n", + "Som vi kan se, stemmer outputtet overens med, hvad vi forventede ville ske. Så hvornår bruger vi label encoding? Label encoding bruges i en eller begge af følgende tilfælde:\n", "1. Når antallet af kategorier er stort\n", "2. Når kategorierne er i rækkefølge.\n" ] @@ -3099,9 +3106,9 @@ "source": [ "**ONE HOT ENCODING**\n", "\n", - "En anden type kodning er One Hot Encoding. Ved denne type kodning bliver hver kategori i kolonnen tilføjet som en separat kolonne, og hver datapunkt får enten en 0 eller en 1, afhængigt af om det indeholder den pågældende kategori. Så hvis der er n forskellige kategorier, vil n kolonner blive tilføjet til dataframen.\n", + "En anden type kodning er One Hot Encoding. Ved denne type kodning bliver hver kategori i kolonnen tilføjet som en separat kolonne, og hver datapunkt får enten en 0 eller en 1 afhængigt af, om det indeholder den pågældende kategori. Så hvis der er n forskellige kategorier, vil n kolonner blive tilføjet til dataframen.\n", "\n", - "For eksempel, lad os tage det samme eksempel med flyklasser. Kategorierne var: ['business class', 'economy class', 'first class']. Hvis vi udfører one hot encoding, vil de følgende tre kolonner blive tilføjet til datasættet: ['class_business class', 'class_economy class', 'class_first class'].\n" + "For eksempel, lad os tage det samme eksempel med flyklasser. Kategorierne var: ['business class', 'economy class', 'first class']. Hvis vi udfører One Hot Encoding, vil følgende tre kolonner blive tilføjet til datasættet: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3334,7 +3341,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Hver one-hot-kodet kolonne indeholder 0 eller 1, hvilket angiver, om den kategori findes for det datapunkt.\n" + "Hver one-hot kodet kolonne indeholder 0 eller 1, hvilket angiver, om den kategori eksisterer for det datapunkt.\n" ] }, { @@ -3381,7 +3388,7 @@ "source": [ "### Identificering af dubletter: `duplicated`\n", "\n", - "Du kan nemt finde dubletter ved hjælp af metoden `duplicated` i pandas, som returnerer en Boolean-maske, der angiver, om en post i en `DataFrame` er en dublet af en tidligere. Lad os oprette et andet eksempel på en `DataFrame` for at se dette i praksis.\n" + "Du kan nemt finde dublerede værdier ved hjælp af metoden `duplicated` i pandas, som returnerer en Boolean-maske, der angiver, om en post i en `DataFrame` er en dublet af en tidligere. Lad os oprette et andet eksempel på en `DataFrame` for at se dette i praksis.\n" ] }, { @@ -3511,7 +3518,7 @@ }, "source": [ "### Fjernelse af dubletter: `drop_duplicates`\n", - "`drop_duplicates` returnerer blot en kopi af dataene, hvor alle værdier, der er `duplicated`, er `False`:\n" + "`drop_duplicates` returnerer simpelthen en kopi af dataene, hvor alle værdier, der er `duplicated`, er `False`:\n" ] }, { @@ -3594,7 +3601,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Både `duplicated` og `drop_duplicates` tager som standard hensyn til alle kolonner, men du kan angive, at de kun skal undersøge et delmængde af kolonnerne i din `DataFrame`:\n" + "Både `duplicated` og `drop_duplicates` har som standard at tage alle kolonner i betragtning, men du kan angive, at de kun skal undersøge en delmængde af kolonnerne i din `DataFrame`:\n" ] }, { @@ -3670,13 +3677,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Takeaway:** Fjernelse af duplikerede data er en essentiel del af næsten hvert datavidenskabsprojekt. Duplikerede data kan ændre resultaterne af dine analyser og give dig unøjagtige resultater!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Kvalitetskontrol af data fra den virkelige verden\n", + "\n", + "> **Læringsmål:** Ved afslutningen af dette afsnit bør du være komfortabel med at opdage og rette almindelige kvalitetsproblemer i data fra den virkelige verden, herunder inkonsistente kategoriværdier, unormale numeriske værdier (outliers) og duplikerede enheder med variationer.\n", + "\n", + "Selvom manglende værdier og præcise duplikater er almindelige problemer, indeholder datasæt fra den virkelige verden ofte mere subtile udfordringer:\n", + "\n", + "1. **Inkonsistente kategoriværdier**: Den samme kategori stavet forskelligt (f.eks. \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Unormale numeriske værdier**: Ekstreme outliers, der indikerer fejl i dataindtastning (f.eks. alder = 999)\n", + "3. **Næsten-duplikerede rækker**: Poster, der repræsenterer den samme enhed med små variationer\n", + "\n", + "Lad os undersøge teknikker til at opdage og håndtere disse problemer.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Oprettelse af et eksempel på et \"beskidt\" datasæt\n", + "\n", + "Lad os først oprette et eksempel på et datasæt, der indeholder de typer problemer, vi ofte støder på i virkelige data:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Registrering af inkonsekvente kategoriske værdier\n", + "\n", + "Bemærk, at kolonnen `country` har flere repræsentationer for de samme lande. Lad os identificere disse uoverensstemmelser:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Standardisering af kategoriske værdier\n", + "\n", + "Vi kan oprette en mapping for at standardisere disse værdier. En simpel tilgang er at konvertere til små bogstaver og oprette en mapping-dictionary:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternativ: Brug af Fuzzy Matching**\n", + "\n", + "Til mere komplekse tilfælde kan vi bruge fuzzy string matching med `rapidfuzz`-biblioteket til automatisk at finde lignende strenge:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Detektering af unormale numeriske værdier (Outliers)\n", + "\n", + "Når vi ser på kolonnen `age`, har vi nogle mistænkelige værdier som 199 og -5. Lad os bruge statistiske metoder til at finde disse outliers.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Brug af IQR (Interkvartilafstand) Metoden\n", + "\n", + "IQR-metoden er en robust statistisk teknik til at opdage afvigere, som er mindre følsom over for ekstreme værdier:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Brug af Z-score-metoden\n", + "\n", + "Z-score-metoden identificerer outliers baseret på standardafvigelser fra gennemsnittet:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Håndtering af outliers\n", + "\n", + "Når outliers er identificeret, kan de håndteres på flere måder:\n", + "1. **Fjern**: Slet rækker med outliers (hvis de er fejl)\n", + "2. **Begræns**: Erstat med grænseværdier\n", + "3. **Erstat med NaN**: Behandl som manglende data og brug imputeringsteknikker\n", + "4. **Behold**: Hvis de er legitime ekstreme værdier\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Registrering af næsten-ens rækker\n", + "\n", + "Bemærk, at vores datasæt har flere poster for \"John Smith\" med lidt forskellige værdier. Lad os identificere potentielle dubletter baseret på navnelighed.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Find nær-duplicater med fuzzy matching\n", + "\n", + "For mere avanceret detektion af dubletter kan vi bruge fuzzy matching til at finde lignende navne:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Håndtering af dubletter\n", + "\n", + "Når de er identificeret, skal du beslutte, hvordan du vil håndtere dubletter:\n", + "1. **Behold den første forekomst**: Brug `drop_duplicates(keep='first')`\n", + "2. **Behold den sidste forekomst**: Brug `drop_duplicates(keep='last')`\n", + "3. **Aggreger information**: Kombiner information fra dublerede rækker\n", + "4. **Manuel gennemgang**: Marker til menneskelig gennemgang\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Resumé: Komplet datarensningspipeline\n", + "\n", + "Lad os samle det hele i en omfattende rengøringspipeline:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Udfordringsøvelse\n", + "\n", + "Nu er det din tur! Nedenfor er en ny række data med flere kvalitetsproblemer. Kan du:\n", + "\n", + "1. Identificere alle problemer i denne række\n", + "2. Skrive kode for at rette hvert problem\n", + "3. Tilføje den rensede række til datasættet\n", + "\n", + "Her er de problematiske data:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Vigtige pointer\n", + "\n", + "1. **Uensartede kategorier** er almindelige i virkelige data. Tjek altid unikke værdier og standardiser dem ved hjælp af mappings eller fuzzy matching.\n", + "\n", + "2. **Outliers** kan have stor indflydelse på din analyse. Brug domæneviden kombineret med statistiske metoder (IQR, Z-score) til at opdage dem.\n", + "\n", + "3. **Næsten-duplikater** er sværere at opdage end eksakte duplikater. Overvej at bruge fuzzy matching og normalisere data (gøre små bogstaver, fjerne mellemrum) for at identificere dem.\n", + "\n", + "4. **Datavask er iterativ**. Du kan være nødt til at anvende flere teknikker og gennemgå resultaterne, før du færdiggør dit rensede datasæt.\n", + "\n", + "5. **Dokumentér dine beslutninger**. Hold styr på, hvilke rengøringsskridt du har anvendt og hvorfor, da dette er vigtigt for reproducerbarhed og gennemsigtighed.\n", + "\n", + "> **Bedste praksis:** Behold altid en kopi af dine originale \"beskidte\" data. Overskriv aldrig dine kilde-datafiler – opret rensede versioner med klare navngivningskonventioner som `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Ansvarsfraskrivelse**: \nDette dokument er blevet oversat ved hjælp af AI-oversættelsestjenesten [Co-op Translator](https://github.com/Azure/co-op-translator). Selvom vi bestræber os på nøjagtighed, skal du være opmærksom på, at automatiserede oversættelser kan indeholde fejl eller unøjagtigheder. Det originale dokument på dets oprindelige sprog bør betragtes som den autoritative kilde. For kritisk information anbefales professionel menneskelig oversættelse. Vi er ikke ansvarlige for eventuelle misforståelser eller fejltolkninger, der måtte opstå som følge af brugen af denne oversættelse.\n" + "\n---\n\n**Ansvarsfraskrivelse**: \nDette dokument er blevet oversat ved hjælp af AI-oversættelsestjenesten [Co-op Translator](https://github.com/Azure/co-op-translator). Selvom vi bestræber os på nøjagtighed, skal det bemærkes, at automatiserede oversættelser kan indeholde fejl eller unøjagtigheder. Det originale dokument på dets oprindelige sprog bør betragtes som den autoritative kilde. For kritisk information anbefales professionel menneskelig oversættelse. Vi påtager os ikke ansvar for misforståelser eller fejltolkninger, der måtte opstå som følge af brugen af denne oversættelse.\n" ] } ], @@ -3704,8 +4229,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:29:46+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:19:56+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "da" } diff --git a/translations/de/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/de/2-Working-With-Data/08-data-preparation/notebook.ipynb index 7c514e0f..ae1236df 100644 --- a/translations/de/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/de/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# Datenvorbereitung\n", "\n", - "[Originales Notebook aus *Data Science: Einführung in Machine Learning für Data Science Python und Machine Learning Studio von Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Originales Notebook aus *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio von Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## Untersuchung von `DataFrame`-Informationen\n", "\n", "> **Lernziel:** Am Ende dieses Abschnitts sollten Sie in der Lage sein, allgemeine Informationen über die in pandas DataFrames gespeicherten Daten zu finden.\n", "\n", - "Sobald Sie Ihre Daten in pandas geladen haben, werden sie höchstwahrscheinlich in einem `DataFrame` vorliegen. Aber wenn der Datensatz in Ihrem `DataFrame` 60.000 Zeilen und 400 Spalten hat, wie fangen Sie überhaupt an, sich einen Überblick darüber zu verschaffen, womit Sie arbeiten? Glücklicherweise bietet pandas einige praktische Werkzeuge, um schnell allgemeine Informationen über ein `DataFrame` sowie die ersten und letzten Zeilen zu erhalten.\n", + "Sobald Sie Ihre Daten in pandas geladen haben, befinden sie sich höchstwahrscheinlich in einem `DataFrame`. Aber wenn der Datensatz in Ihrem `DataFrame` 60.000 Zeilen und 400 Spalten hat, wie fangen Sie überhaupt an, sich einen Überblick darüber zu verschaffen, womit Sie arbeiten? Glücklicherweise bietet pandas einige praktische Werkzeuge, um schnell allgemeine Informationen über ein `DataFrame` sowie die ersten und letzten Zeilen zu erhalten.\n", "\n", - "Um diese Funktionalität zu erkunden, werden wir die Python-Bibliothek scikit-learn importieren und einen ikonischen Datensatz verwenden, den jeder Data Scientist schon hunderte Male gesehen hat: Der britische Biologe Ronald Fisher's *Iris*-Datensatz, der in seinem Papier von 1936 \"Die Verwendung von mehreren Messungen in taxonomischen Problemen\" verwendet wurde:\n" + "Um diese Funktionalität zu erkunden, werden wir die Python-Bibliothek scikit-learn importieren und einen ikonischen Datensatz verwenden, den jeder Data Scientist schon hunderte Male gesehen hat: den *Iris*-Datensatz des britischen Biologen Ronald Fisher, der in seinem Papier von 1936 \"The use of multiple measurements in taxonomic problems\" verwendet wurde:\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Wir haben den Iris-Datensatz in der Variable `iris_df` geladen. Bevor wir uns tiefer mit den Daten beschäftigen, wäre es hilfreich zu wissen, wie viele Datenpunkte wir haben und wie groß der Datensatz insgesamt ist. Es ist nützlich, das Volumen der Daten, mit denen wir arbeiten, zu betrachten.\n" + "Wir haben den Iris-Datensatz in der Variable `iris_df` geladen. Bevor wir uns mit den Daten beschäftigen, wäre es hilfreich zu wissen, wie viele Datenpunkte wir haben und wie groß der Datensatz insgesamt ist. Es ist nützlich, das Volumen der Daten, mit denen wir arbeiten, zu betrachten.\n" ] }, { @@ -78,7 +78,7 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Wir haben es hier mit 150 Zeilen und 4 Spalten von Daten zu tun. Jede Zeile repräsentiert einen Datenpunkt, und jede Spalte steht für ein einzelnes Merkmal, das mit dem Dataframe verknüpft ist. Im Grunde gibt es also 150 Datenpunkte, die jeweils 4 Merkmale enthalten.\n", + "Wir haben es also mit 150 Zeilen und 4 Spalten von Daten zu tun. Jede Zeile repräsentiert einen Datenpunkt, und jede Spalte steht für ein einzelnes Merkmal, das mit dem Dataframe verbunden ist. Im Grunde gibt es also 150 Datenpunkte, die jeweils 4 Merkmale enthalten.\n", "\n", "`shape` ist hier ein Attribut des Dataframes und keine Funktion, weshalb es nicht mit einem Paar Klammern endet.\n" ] @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Lassen Sie uns nun die 4 Spalten der Daten betrachten. Was genau repräsentiert jede von ihnen? Das Attribut `columns` gibt uns die Namen der Spalten im DataFrame.\n" + "Lassen Sie uns nun die 4 Spalten der Daten genauer betrachten. Was genau repräsentiert jede von ihnen? Das Attribut `columns` gibt uns die Namen der Spalten im DataFrame.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Wie wir sehen können, gibt es vier (4) Spalten. Das Attribut `columns` gibt uns die Namen der Spalten und im Grunde nichts anderes. Dieses Attribut wird wichtig, wenn wir die Merkmale eines Datensatzes identifizieren möchten.\n" + "Wie wir sehen können, gibt es vier (4) Spalten. Das `columns`-Attribut gibt uns die Namen der Spalten und im Grunde nichts anderes. Dieses Attribut wird wichtig, wenn wir die Merkmale eines Datensatzes identifizieren möchten.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Die Menge der Daten (angegeben durch das Attribut `shape`) und die Namen der Merkmale oder Spalten (angegeben durch das Attribut `columns`) geben uns einige Informationen über den Datensatz. Nun möchten wir tiefer in den Datensatz eintauchen. Die Funktion `DataFrame.info()` ist dafür sehr nützlich.\n" + "Die Menge der Daten (angegeben durch das `shape`-Attribut) und die Namen der Merkmale oder Spalten (angegeben durch das `columns`-Attribut) geben uns einige Informationen über den Datensatz. Nun möchten wir tiefer in den Datensatz eintauchen. Die Funktion `DataFrame.info()` ist dafür sehr nützlich.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Von hier aus können wir einige Beobachtungen machen: \n", - "1. Der Datentyp jeder Spalte: In diesem Datensatz werden alle Daten als 64-Bit-Gleitkommazahlen gespeichert. \n", - "2. Anzahl der Nicht-Null-Werte: Der Umgang mit Nullwerten ist ein wichtiger Schritt in der Datenvorbereitung. Dies wird später im Notebook behandelt. \n" + "Von hier aus können wir einige Beobachtungen machen:\n", + "1. Der Datentyp jeder Spalte: In diesem Datensatz werden alle Daten als 64-Bit-Gleitkommazahlen gespeichert.\n", + "2. Anzahl der Nicht-Null-Werte: Der Umgang mit Nullwerten ist ein wichtiger Schritt in der Datenvorbereitung. Dies wird später im Notebook behandelt.\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "Mit all den oben genannten Funktionen und Attributen haben wir einen Überblick über das Dataset erhalten. Wir wissen, wie viele Datenpunkte vorhanden sind, wie viele Merkmale es gibt, den Datentyp jedes Merkmals und die Anzahl der nicht-null Werte für jedes Merkmal.\n", + "Mit all den oben genannten Funktionen und Attributen haben wir einen Überblick über den Datensatz erhalten. Wir wissen, wie viele Datenpunkte vorhanden sind, wie viele Merkmale es gibt, den Datentyp jedes Merkmals und die Anzahl der nicht-null Werte für jedes Merkmal.\n", "\n", - "Jetzt ist es an der Zeit, die Daten selbst anzuschauen. Sehen wir uns an, wie die ersten paar Zeilen (die ersten paar Datenpunkte) unseres `DataFrame` aussehen:\n" + "Jetzt ist es an der Zeit, die Daten selbst anzusehen. Schauen wir uns an, wie die ersten paar Zeilen (die ersten paar Datenpunkte) unseres `DataFrame` aussehen:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Als Ausgabe sehen wir hier fünf(5) Einträge des Datensatzes. Wenn wir uns den Index auf der linken Seite ansehen, stellen wir fest, dass dies die ersten fünf Zeilen sind.\n" + "Wie wir hier sehen können, gibt es fünf (5) Einträge im Datensatz. Wenn wir uns den Index auf der linken Seite ansehen, stellen wir fest, dass dies die ersten fünf Zeilen sind.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Übung:\n", "\n", - "Aus dem obigen Beispiel wird deutlich, dass `DataFrame.head` standardmäßig die ersten fünf Zeilen eines `DataFrame` zurückgibt. In der untenstehenden Code-Zelle, kannst du eine Möglichkeit finden, mehr als fünf Zeilen anzuzeigen?\n" + "Aus dem obigen Beispiel wird deutlich, dass `DataFrame.head` standardmäßig die ersten fünf Zeilen eines `DataFrame` zurückgibt. Kannst du im folgenden Codeblock herausfinden, wie man mehr als fünf Zeilen anzeigen kann?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Eine andere Möglichkeit, die Daten anzusehen, ist vom Ende her (anstatt vom Anfang). Das Gegenstück zu `DataFrame.head` ist `DataFrame.tail`, das die letzten fünf Zeilen eines `DataFrame` zurückgibt:\n" + "Eine andere Möglichkeit, die Daten anzusehen, ist vom Ende aus (anstatt vom Anfang). Das Gegenstück zu `DataFrame.head` ist `DataFrame.tail`, das die letzten fünf Zeilen eines `DataFrame` zurückgibt:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "In der Praxis ist es nützlich, die ersten oder letzten Zeilen eines `DataFrame` leicht untersuchen zu können, insbesondere wenn man nach Ausreißern in geordneten Datensätzen sucht.\n", + "In der Praxis ist es hilfreich, die ersten oder letzten Zeilen eines `DataFrame` leicht untersuchen zu können, insbesondere wenn man nach Ausreißern in geordneten Datensätzen sucht.\n", "\n", - "Alle oben gezeigten Funktionen und Attribute, die mit Hilfe von Codebeispielen erläutert wurden, helfen uns, einen Eindruck von den Daten zu bekommen.\n", + "Alle oben gezeigten Funktionen und Attribute, unterstützt durch Code-Beispiele, helfen uns, einen Eindruck von den Daten zu bekommen.\n", "\n", - "> **Fazit:** Schon allein durch das Betrachten der Metadaten über die Informationen in einem DataFrame oder der ersten und letzten Werte darin, kann man sich sofort ein Bild von der Größe, der Struktur und dem Inhalt der Daten machen, mit denen man arbeitet.\n" + "> **Wichtig:** Schon allein durch das Betrachten der Metadaten eines DataFrame oder der ersten und letzten Werte darin kann man sofort eine Vorstellung von der Größe, Form und dem Inhalt der Daten gewinnen, mit denen man arbeitet.\n" ] }, { @@ -598,15 +598,15 @@ "### Fehlende Daten\n", "Lassen Sie uns in das Thema fehlende Daten eintauchen. Fehlende Daten treten auf, wenn in einigen Spalten keine Werte gespeichert sind.\n", "\n", - "Nehmen wir ein Beispiel: Angenommen, jemand ist sehr auf sein/ihr Gewicht bedacht und füllt das Feld für das Gewicht in einer Umfrage nicht aus. Dann wird der Gewichtswert für diese Person fehlen.\n", + "Nehmen wir ein Beispiel: Angenommen, jemand ist sehr auf sein/ihr Gewicht bedacht und füllt das Gewichtsfeld in einer Umfrage nicht aus. Dann wird der Gewichtswert für diese Person fehlen.\n", "\n", - "In den meisten Fällen treten fehlende Werte in realen Datensätzen auf.\n", + "In den meisten Fällen treten in realen Datensätzen fehlende Werte auf.\n", "\n", "**Wie Pandas mit fehlenden Daten umgeht**\n", "\n", - "Pandas geht auf zwei Arten mit fehlenden Werten um. Die erste haben Sie bereits in vorherigen Abschnitten gesehen: `NaN`, oder Not a Number. Dies ist tatsächlich ein spezieller Wert, der Teil der IEEE-Gleitkomma-Spezifikation ist und ausschließlich verwendet wird, um fehlende Gleitkommawerte anzuzeigen.\n", + "Pandas geht auf zwei Arten mit fehlenden Werten um. Die erste Methode haben Sie bereits in den vorherigen Abschnitten gesehen: `NaN`, oder Not a Number. Dies ist tatsächlich ein spezieller Wert, der Teil der IEEE-Gleitkomma-Spezifikation ist und ausschließlich verwendet wird, um fehlende Gleitkommawerte anzuzeigen.\n", "\n", - "Für fehlende Werte, die keine Gleitkommazahlen sind, verwendet Pandas das Python-Objekt `None`. Auch wenn es verwirrend erscheinen mag, dass Sie zwei verschiedene Arten von Werten antreffen, die im Wesentlichen dasselbe aussagen, gibt es gute programmatische Gründe für diese Designentscheidung. In der Praxis ermöglicht dieser Ansatz Pandas, in den meisten Fällen einen guten Kompromiss zu bieten. Nichtsdestotrotz bringen sowohl `None` als auch `NaN` Einschränkungen mit sich, die Sie im Hinblick darauf, wie sie verwendet werden können, beachten müssen.\n" + "Für fehlende Werte, die keine Gleitkommazahlen sind, verwendet Pandas das Python-Objekt `None`. Auch wenn es zunächst verwirrend erscheinen mag, dass Sie zwei verschiedene Arten von Werten begegnen, die im Wesentlichen dasselbe aussagen, gibt es gute programmatische Gründe für diese Designentscheidung. In der Praxis ermöglicht dieser Ansatz Pandas, für die überwiegende Mehrheit der Fälle einen guten Kompromiss zu bieten. Dennoch bringen sowohl `None` als auch `NaN` Einschränkungen mit sich, die Sie im Hinblick darauf, wie sie verwendet werden können, beachten müssen.\n" ] }, { @@ -615,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: nicht-float fehlende Daten\n", + "### `None`: nicht-fließende fehlende Daten\n", "Da `None` aus Python stammt, kann es nicht in NumPy- und pandas-Arrays verwendet werden, die keinen Datentyp `'object'` haben. Denken Sie daran, dass NumPy-Arrays (und die Datenstrukturen in pandas) nur einen Datentyp enthalten können. Dies verleiht ihnen ihre enorme Leistungsfähigkeit für groß angelegte Daten- und Rechenarbeiten, schränkt jedoch auch ihre Flexibilität ein. Solche Arrays müssen auf den „kleinsten gemeinsamen Nenner“ hochgestuft werden, den Datentyp, der alles im Array umfassen kann. Wenn `None` im Array enthalten ist, bedeutet dies, dass Sie mit Python-Objekten arbeiten.\n", "\n", - "Um dies in Aktion zu sehen, betrachten Sie das folgende Beispiel-Array (beachten Sie den `dtype` dafür):\n" + "Um dies in Aktion zu sehen, betrachten Sie das folgende Beispielarray (beachten Sie den `dtype` dafür):\n" ] }, { @@ -659,7 +659,7 @@ "source": [ "Die Realität von hochgestuften Datentypen bringt zwei Nebenwirkungen mit sich. Erstens werden Operationen auf der Ebene des interpretierten Python-Codes statt des kompilierten NumPy-Codes ausgeführt. Im Wesentlichen bedeutet dies, dass alle Operationen, die `Series` oder `DataFrames` mit `None` enthalten, langsamer sein werden. Obwohl Sie diesen Leistungseinbruch wahrscheinlich nicht bemerken würden, könnte er bei großen Datensätzen zu einem Problem werden.\n", "\n", - "Die zweite Nebenwirkung ergibt sich aus der ersten. Da `None` `Series` oder `DataFrames` im Grunde zurück in die Welt des reinen Python zieht, führen NumPy/pandas-Aggregationen wie `sum()` oder `min()` auf Arrays, die einen `None`-Wert enthalten, im Allgemeinen zu einem Fehler:\n" + "Die zweite Nebenwirkung ergibt sich aus der ersten. Da `None` `Series` oder `DataFrames` im Grunde zurück in die Welt des reinen Python zieht, führen NumPy/pandas-Aggregationen wie `sum()` oder `min()` auf Arrays, die einen ``None``-Wert enthalten, im Allgemeinen zu einem Fehler:\n" ] }, { @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Wichtigste Erkenntnis**: Die Addition (und andere Operationen) zwischen Ganzzahlen und `None`-Werten ist undefiniert, was einschränken kann, was Sie mit Datensätzen, die sie enthalten, tun können.\n" + "**Wichtigste Erkenntnis**: Die Addition (und andere Operationen) zwischen Ganzzahlen und `None`-Werten ist undefiniert, was die Möglichkeiten im Umgang mit Datensätzen, die solche Werte enthalten, einschränken kann.\n" ] }, { @@ -707,9 +707,9 @@ "id": "pWvVHvETgRr9" }, "source": [ - "### `NaN`: Fehlende Gleitkommawerte\n", + "### `NaN`: fehlende Float-Werte\n", "\n", - "Im Gegensatz zu `None` unterstützt NumPy (und damit auch pandas) `NaN` für seine schnellen, vektorisierten Operationen und ufuncs. Die schlechte Nachricht ist, dass jede arithmetische Operation mit `NaN` immer zu `NaN` führt. Zum Beispiel:\n" + "Im Gegensatz zu `None` unterstützt NumPy (und damit auch pandas) `NaN` für seine schnellen, vektorisierten Operationen und ufuncs. Der Nachteil ist, dass jede arithmetische Operation mit `NaN` immer zu `NaN` führt. Zum Beispiel:\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Die gute Nachricht: Aggregationen, die auf Arrays mit `NaN` ausgeführt werden, verursachen keine Fehler. Die schlechte Nachricht: Die Ergebnisse sind nicht einheitlich nützlich:\n" + "Die gute Nachricht: Aggregationen, die auf Arrays mit `NaN` ausgeführt werden, verursachen keine Fehler. Die schlechte Nachricht: Die Ergebnisse sind nicht durchgehend nützlich:\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Beim Hochstufen von Datentypen, um Datenhomogenität in `Series` und `DataFrame`s zu gewährleisten, wechselt pandas bereitwillig fehlende Werte zwischen `None` und `NaN`. Aufgrund dieser Design-Eigenschaft kann es hilfreich sein, `None` und `NaN` als zwei verschiedene Varianten von \"null\" in pandas zu betrachten. Tatsächlich spiegeln einige der Kernmethoden, die Sie verwenden werden, um mit fehlenden Werten in pandas umzugehen, diese Idee in ihren Namen wider:\n", + "Im Prozess des Hochstufens von Datentypen, um Datenhomogenität in `Series` und `DataFrame`s zu gewährleisten, wechselt pandas bereitwillig fehlende Werte zwischen `None` und `NaN`. Aufgrund dieser Designentscheidung kann es hilfreich sein, `None` und `NaN` als zwei verschiedene Varianten von \"null\" in pandas zu betrachten. Tatsächlich spiegeln einige der zentralen Methoden, die Sie zur Behandlung fehlender Werte in pandas verwenden, diese Idee in ihren Namen wider:\n", "\n", "- `isnull()`: Erstellt eine Boolesche Maske, die fehlende Werte anzeigt\n", "- `notnull()`: Gegenteil von `isnull()`\n", "- `dropna()`: Gibt eine gefilterte Version der Daten zurück\n", - "- `fillna()`: Gibt eine Kopie der Daten zurück, bei der fehlende Werte gefüllt oder ersetzt wurden\n", + "- `fillna()`: Gibt eine Kopie der Daten zurück, bei der fehlende Werte aufgefüllt oder ersetzt wurden\n", "\n", - "Diese Methoden sind wichtig zu beherrschen und sich mit ihnen vertraut zu machen. Lassen Sie uns sie daher im Detail durchgehen.\n" + "Diese Methoden sind wichtig, um sie zu beherrschen und sich mit ihnen vertraut zu machen. Lassen Sie uns sie daher im Detail durchgehen.\n" ] }, { @@ -922,10 +922,9 @@ "id": "Yh5ifd9FgRsB" }, "source": [ - "### Erkennen von Nullwerten\n", + "### Erkennung von Nullwerten\n", "\n", - "Nachdem wir die Bedeutung fehlender Werte verstanden haben, müssen wir sie in unserem Datensatz erkennen, bevor wir sie behandeln. \n", - "Sowohl `isnull()` als auch `notnull()` sind Ihre primären Methoden, um Nullwerte zu erkennen. Beide geben boolesche Masken für Ihre Daten zurück.\n" + "Nachdem wir die Bedeutung fehlender Werte verstanden haben, müssen wir sie in unserem Datensatz erkennen, bevor wir sie bearbeiten. Sowohl `isnull()` als auch `notnull()` sind Ihre primären Methoden zur Erkennung von Nullwerten. Beide geben boolesche Masken über Ihre Daten zurück.\n" ] }, { @@ -978,11 +977,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Schauen Sie sich die Ausgabe genau an. Überrascht Sie etwas davon? Während `0` ein arithmetisches Null ist, ist es dennoch eine vollkommen gültige Ganzzahl, und pandas behandelt es auch so. `''` ist etwas subtiler. Obwohl wir es in Abschnitt 1 verwendet haben, um einen leeren Zeichenkettenwert darzustellen, ist es dennoch ein Zeichenkettenobjekt und keine Darstellung von Null, zumindest aus der Sicht von pandas.\n", + "Schauen Sie sich das Ergebnis genau an. Überrascht Sie etwas davon? Während `0` ein arithmetisches Null ist, ist es dennoch eine vollkommen gültige Ganzzahl, und pandas behandelt es auch so. `''` ist etwas subtiler. Obwohl wir es in Abschnitt 1 verwendet haben, um einen leeren Zeichenkettenwert darzustellen, ist es dennoch ein Zeichenkettenobjekt und keine Darstellung von Null, zumindest aus Sicht von pandas.\n", "\n", - "Wenden wir uns nun der Praxis zu und nutzen diese Methoden auf eine Weise, wie Sie sie tatsächlich verwenden würden. Sie können Boolesche Masken direkt als ``Series``- oder ``DataFrame``-Index verwenden, was nützlich sein kann, wenn Sie mit isolierten fehlenden (oder vorhandenen) Werten arbeiten möchten.\n", + "Wenden wir uns nun der praktischen Anwendung dieser Methoden zu, so wie Sie sie im Alltag nutzen werden. Sie können Boolesche Masken direkt als Index für eine ``Series`` oder ein ``DataFrame`` verwenden, was nützlich sein kann, wenn Sie mit isolierten fehlenden (oder vorhandenen) Werten arbeiten möchten.\n", "\n", - "Wenn wir die Gesamtanzahl der fehlenden Werte ermitteln möchten, können wir einfach eine Summe über die Maske durchführen, die durch die Methode `isnull()` erzeugt wird.\n" + "Wenn wir die Gesamtanzahl der fehlenden Werte ermitteln möchten, können wir einfach die Maske, die durch die Methode `isnull()` erzeugt wird, summieren.\n" ] }, { @@ -1040,7 +1039,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Wichtige Erkenntnis**: Sowohl die Methoden `isnull()` als auch `notnull()` liefern ähnliche Ergebnisse, wenn Sie sie in DataFrames verwenden: Sie zeigen die Ergebnisse und den Index dieser Ergebnisse, was Ihnen enorm helfen wird, wenn Sie mit Ihren Daten arbeiten.\n" + "**Wichtigste Erkenntnis**: Sowohl die Methoden `isnull()` als auch `notnull()` liefern ähnliche Ergebnisse, wenn Sie sie in DataFrames verwenden: Sie zeigen die Ergebnisse und den Index dieser Ergebnisse, was Ihnen enorm helfen wird, wenn Sie mit Ihren Daten arbeiten.\n" ] }, { @@ -1051,18 +1050,18 @@ "source": [ "### Umgang mit fehlenden Daten\n", "\n", - "> **Lernziel:** Am Ende dieses Abschnitts solltest du wissen, wie und wann du Nullwerte in DataFrames ersetzen oder entfernen kannst.\n", + "> **Lernziel:** Am Ende dieses Abschnitts sollten Sie wissen, wie und wann Sie Nullwerte in DataFrames ersetzen oder entfernen können.\n", "\n", - "Machine-Learning-Modelle können nicht eigenständig mit fehlenden Daten umgehen. Daher müssen wir diese fehlenden Werte behandeln, bevor wir die Daten in das Modell einspeisen.\n", + "Maschinelle Lernmodelle können nicht selbst mit fehlenden Daten umgehen. Daher müssen wir diese fehlenden Werte bearbeiten, bevor wir die Daten in das Modell einspeisen.\n", "\n", - "Die Art und Weise, wie fehlende Daten behandelt werden, bringt subtile Kompromisse mit sich und kann deine abschließende Analyse sowie die Ergebnisse in der realen Welt beeinflussen.\n", + "Die Art und Weise, wie fehlende Daten behandelt werden, bringt subtile Kompromisse mit sich und kann Ihre endgültige Analyse sowie die Ergebnisse in der realen Welt beeinflussen.\n", "\n", - "Es gibt hauptsächlich zwei Ansätze, um mit fehlenden Daten umzugehen:\n", + "Es gibt hauptsächlich zwei Methoden, um mit fehlenden Daten umzugehen:\n", "\n", "1. Die Zeile mit dem fehlenden Wert entfernen\n", "2. Den fehlenden Wert durch einen anderen Wert ersetzen\n", "\n", - "Wir werden beide Methoden sowie ihre Vor- und Nachteile im Detail besprechen.\n" + "Wir werden beide Methoden sowie ihre Vor- und Nachteile ausführlich besprechen.\n" ] }, { @@ -1071,13 +1070,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### Nullwerte entfernen\n", + "### Entfernen von Nullwerten\n", "\n", - "Die Menge an Daten, die wir unserem Modell übergeben, hat einen direkten Einfluss auf dessen Leistung. Nullwerte zu entfernen bedeutet, dass wir die Anzahl der Datenpunkte reduzieren und somit die Größe des Datensatzes verringern. Daher ist es ratsam, Zeilen mit Nullwerten zu entfernen, wenn der Datensatz ziemlich groß ist.\n", + "Die Menge an Daten, die wir unserem Modell übergeben, hat einen direkten Einfluss auf dessen Leistung. Das Entfernen von Nullwerten bedeutet, dass wir die Anzahl der Datenpunkte reduzieren und somit die Größe des Datensatzes verringern. Daher ist es ratsam, Zeilen mit Nullwerten zu entfernen, wenn der Datensatz ziemlich groß ist.\n", "\n", "Ein weiterer Fall könnte sein, dass eine bestimmte Zeile oder Spalte viele fehlende Werte enthält. In diesem Fall können sie entfernt werden, da sie nicht viel Wert für unsere Analyse hinzufügen würden, da die meisten Daten für diese Zeile/Spalte fehlen.\n", "\n", - "Neben der Identifizierung fehlender Werte bietet pandas eine praktische Möglichkeit, Nullwerte aus `Series` und `DataFrame`s zu entfernen. Um dies in Aktion zu sehen, kehren wir zu `example3` zurück. Die Funktion `DataFrame.dropna()` hilft dabei, die Zeilen mit Nullwerten zu entfernen.\n" + "Über das Identifizieren von fehlenden Werten hinaus bietet pandas eine praktische Möglichkeit, Nullwerte aus `Series` und `DataFrame`s zu entfernen. Um dies in Aktion zu sehen, kehren wir zu `example3` zurück. Die Funktion `DataFrame.dropna()` hilft dabei, die Zeilen mit Nullwerten zu entfernen.\n" ] }, { @@ -1116,7 +1115,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "Beachten Sie, dass dies wie Ihre Ausgabe von `example3[example3.notnull()]` aussehen sollte. Der Unterschied hier besteht darin, dass `dropna` anstelle des Indexierens auf die maskierten Werte diese fehlenden Werte aus der `Series` `example3` entfernt hat.\n", + "Beachten Sie, dass dies wie Ihre Ausgabe von `example3[example3.notnull()]` aussehen sollte. Der Unterschied hier ist, dass `dropna` die fehlenden Werte aus der `Series` `example3` entfernt hat, anstatt nur die maskierten Werte zu indexieren.\n", "\n", "Da DataFrames zwei Dimensionen haben, bieten sie mehr Möglichkeiten zum Entfernen von Daten.\n" ] @@ -1208,9 +1207,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Haben Sie bemerkt, dass pandas zwei der Spalten zu Floats hochgestuft hat, um die `NaN`s zu berücksichtigen?)\n", + "(Haben Sie bemerkt, dass pandas zwei der Spalten in Floats umgewandelt hat, um die `NaN`s zu berücksichtigen?)\n", "\n", - "Sie können keinen einzelnen Wert aus einem `DataFrame` entfernen, daher müssen Sie ganze Zeilen oder Spalten löschen. Je nachdem, was Sie tun möchten, könnten Sie sich für das eine oder das andere entscheiden, und pandas bietet Ihnen Optionen für beides. Da in der Datenwissenschaft Spalten im Allgemeinen Variablen und Zeilen Beobachtungen darstellen, ist es wahrscheinlicher, dass Sie Zeilen von Daten löschen; die Standardeinstellung für `dropna()` ist, alle Zeilen zu entfernen, die irgendeinen Nullwert enthalten:\n" + "Sie können keinen einzelnen Wert aus einem `DataFrame` entfernen, sondern müssen ganze Zeilen oder Spalten löschen. Je nachdem, was Sie tun möchten, könnten Sie sich für das eine oder das andere entscheiden, und pandas bietet Ihnen Optionen für beides. Da in der Datenwissenschaft Spalten im Allgemeinen Variablen und Zeilen Beobachtungen darstellen, ist es wahrscheinlicher, dass Sie Zeilen mit Daten löschen; die Standardeinstellung für `dropna()` ist, alle Zeilen zu entfernen, die irgendeinen Nullwert enthalten:\n" ] }, { @@ -1283,7 +1282,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "Wenn nötig, können Sie NA-Werte aus Spalten entfernen. Verwenden Sie `axis=1`, um dies zu tun:\n" + "Falls erforderlich, können Sie NA-Werte aus Spalten entfernen. Verwenden Sie `axis=1`, um dies zu tun:\n" ] }, { @@ -1362,9 +1361,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Beachten Sie, dass dies viele Daten entfernen kann, die Sie möglicherweise behalten möchten, insbesondere in kleineren Datensätzen. Was ist, wenn Sie nur Zeilen oder Spalten entfernen möchten, die mehrere oder sogar alle Nullwerte enthalten? Sie können diese Einstellungen in `dropna` mit den Parametern `how` und `thresh` festlegen.\n", + "Beachten Sie, dass dadurch viele Daten verloren gehen können, die Sie möglicherweise behalten möchten, insbesondere bei kleineren Datensätzen. Was ist, wenn Sie nur Zeilen oder Spalten entfernen möchten, die mehrere oder sogar alle Nullwerte enthalten? Diese Einstellungen können Sie in `dropna` mit den Parametern `how` und `thresh` festlegen.\n", "\n", - "Standardmäßig ist `how='any'` (wenn Sie dies selbst überprüfen oder sehen möchten, welche anderen Parameter die Methode hat, führen Sie `example4.dropna?` in einer Codezelle aus). Alternativ könnten Sie `how='all'` angeben, um nur Zeilen oder Spalten zu entfernen, die ausschließlich Nullwerte enthalten. Lassen Sie uns unser Beispiel-`DataFrame` erweitern, um dies im nächsten Übungsbeispiel in Aktion zu sehen.\n" + "Standardmäßig ist `how='any'` (wenn Sie dies selbst überprüfen oder sehen möchten, welche anderen Parameter die Methode hat, führen Sie `example4.dropna?` in einer Codezelle aus). Alternativ könnten Sie `how='all'` angeben, um nur Zeilen oder Spalten zu entfernen, die ausschließlich Nullwerte enthalten. Lassen Sie uns unser Beispiel-`DataFrame` erweitern, um dies im nächsten Übungsbeispiel zu sehen.\n" ] }, { @@ -1492,7 +1491,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "Der Parameter `thresh` gibt Ihnen eine feinere Kontrolle: Sie legen die Anzahl der *nicht-null* Werte fest, die eine Zeile oder Spalte haben muss, um beibehalten zu werden:\n" + "Der `thresh`-Parameter bietet Ihnen eine feinere Kontrolle: Sie legen die Anzahl der *nicht-null* Werte fest, die eine Zeile oder Spalte haben muss, um beibehalten zu werden:\n" ] }, { @@ -1578,9 +1577,9 @@ "source": [ "### Auffüllen von Nullwerten\n", "\n", - "Manchmal ist es sinnvoll, fehlende Werte mit solchen zu ersetzen, die plausibel sein könnten. Es gibt einige Techniken, um Nullwerte aufzufüllen. Die erste besteht darin, Domänenwissen (Kenntnisse über das Thema, auf dem der Datensatz basiert) zu nutzen, um die fehlenden Werte irgendwie abzuschätzen.\n", + "Es kann manchmal sinnvoll sein, fehlende Werte durch solche zu ersetzen, die gültig sein könnten. Es gibt einige Techniken, um Nullwerte zu füllen. Die erste besteht darin, Domänenwissen (Kenntnisse über das Thema, auf dem der Datensatz basiert) zu nutzen, um die fehlenden Werte irgendwie zu approximieren.\n", "\n", - "Du könntest `isnull` verwenden, um dies direkt zu tun, aber das kann mühsam sein, besonders wenn du viele Werte auffüllen musst. Da dies eine so häufige Aufgabe in der Datenwissenschaft ist, stellt pandas die Funktion `fillna` bereit. Diese gibt eine Kopie der `Series` oder des `DataFrame` zurück, bei der die fehlenden Werte durch einen von dir gewählten Wert ersetzt werden. Lass uns ein weiteres Beispiel für eine `Series` erstellen, um zu sehen, wie das in der Praxis funktioniert.\n" + "Man könnte `isnull` verwenden, um dies direkt zu tun, aber das kann mühsam sein, insbesondere wenn viele Werte gefüllt werden müssen. Da dies eine so häufige Aufgabe in der Datenwissenschaft ist, bietet pandas `fillna`, das eine Kopie der `Series` oder des `DataFrame` zurückgibt, bei der die fehlenden Werte durch einen von Ihnen gewählten Wert ersetzt werden. Lassen Sie uns ein weiteres Beispiel für eine `Series` erstellen, um zu sehen, wie dies in der Praxis funktioniert.\n" ] }, { @@ -1592,7 +1591,7 @@ "### Kategorische Daten (Nicht-numerisch)\n", "Betrachten wir zunächst nicht-numerische Daten. In Datensätzen gibt es Spalten mit kategorischen Daten, z. B. Geschlecht, Wahr oder Falsch usw.\n", "\n", - "In den meisten dieser Fälle ersetzen wir fehlende Werte durch den `Modus` der Spalte. Angenommen, wir haben 100 Datenpunkte, von denen 90 \"Wahr\" angegeben haben, 8 \"Falsch\" und 2 keine Angabe gemacht haben. Dann können wir die 2 fehlenden Werte mit \"Wahr\" auffüllen, indem wir die gesamte Spalte betrachten.\n", + "In den meisten Fällen ersetzen wir fehlende Werte durch den `Modus` der Spalte. Angenommen, wir haben 100 Datenpunkte, von denen 90 \"Wahr\" angegeben haben, 8 \"Falsch\" und 2 keine Angabe gemacht haben. Dann können wir die 2 fehlenden Werte mit \"Wahr\" auffüllen, indem wir die gesamte Spalte betrachten.\n", "\n", "Auch hier können wir Fachwissen nutzen. Betrachten wir ein Beispiel, bei dem mit dem Modus aufgefüllt wird.\n" ] @@ -1699,7 +1698,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Lassen Sie uns zuerst die Modalwert finden, bevor wir den `None`-Wert mit dem Modalwert ausfüllen.\n" + ] }, { "cell_type": "code", @@ -1734,7 +1735,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Also, wir werden None durch True ersetzen\n" + ] }, { "cell_type": "code", @@ -1844,7 +1847,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Wie wir sehen können, wurde der Nullwert ersetzt. Es versteht sich von selbst, dass wir anstelle von `'True'` alles hätten schreiben können, und es wäre ersetzt worden.\n" + "Wie wir sehen können, wurde der Nullwert ersetzt. Es versteht sich von selbst, dass wir anstelle von `'True'` alles hätten schreiben können und es wäre ersetzt worden.\n" ] }, { @@ -1856,14 +1859,14 @@ "### Numerische Daten\n", "Kommen wir nun zu numerischen Daten. Hier gibt es zwei gängige Methoden, um fehlende Werte zu ersetzen:\n", "\n", - "1. Ersetzen mit dem Median der Zeile \n", - "2. Ersetzen mit dem Mittelwert der Zeile \n", + "1. Ersetzen durch den Median der Zeile\n", + "2. Ersetzen durch den Mittelwert der Zeile\n", "\n", - "Wir ersetzen mit dem Median, wenn die Daten schief verteilt sind und Ausreißer enthalten. Das liegt daran, dass der Median unempfindlich gegenüber Ausreißern ist.\n", + "Wir verwenden den Median, wenn die Daten verzerrt sind und Ausreißer enthalten. Der Grund dafür ist, dass der Median gegenüber Ausreißern robust ist.\n", "\n", "Wenn die Daten normalisiert sind, können wir den Mittelwert verwenden, da in diesem Fall Mittelwert und Median ziemlich nah beieinander liegen.\n", "\n", - "Nehmen wir zunächst eine Spalte, die normal verteilt ist, und füllen die fehlenden Werte mit dem Mittelwert der Spalte auf.\n" + "Nehmen wir zunächst eine Spalte, die normalverteilt ist, und füllen die fehlenden Werte mit dem Mittelwert der Spalte.\n" ] }, { @@ -2003,7 +2006,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Füllen mit dem Mittelwert\n" + ] }, { "cell_type": "code", @@ -2112,7 +2117,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Lassen Sie uns nun ein weiteres DataFrame ausprobieren, und dieses Mal werden wir die None-Werte durch den Median der Spalte ersetzen.\n" + "Lassen Sie uns nun einen anderen DataFrame ausprobieren, und dieses Mal werden wir die None-Werte durch den Median der Spalte ersetzen.\n" ] }, { @@ -2252,7 +2257,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Füllen mit Median\n" + ] }, { "cell_type": "code", @@ -2435,11 +2442,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Wichtige Erkenntnisse: \n", - "1. Fehlende Werte sollten ausgefüllt werden, wenn entweder nur wenige Daten fehlen oder eine Strategie zum Auffüllen der fehlenden Daten vorhanden ist. \n", - "2. Fachwissen kann genutzt werden, um fehlende Werte durch Schätzungen zu ersetzen. \n", - "3. Bei kategorialen Daten werden fehlende Werte meist durch den Modus der Spalte ersetzt. \n", - "4. Bei numerischen Daten werden fehlende Werte in der Regel mit dem Mittelwert (bei normalisierten Datensätzen) oder dem Median der Spalten aufgefüllt. \n" + "> Wichtige Erkenntnisse:\n", + "1. Fehlende Werte sollten nur dann ausgefüllt werden, wenn entweder wenig Daten vorhanden sind oder eine Strategie zum Auffüllen der fehlenden Daten existiert.\n", + "2. Fachwissen kann genutzt werden, um fehlende Werte durch Schätzungen zu ersetzen.\n", + "3. Bei kategorischen Daten werden fehlende Werte meist durch den Modus der Spalte ersetzt.\n", + "4. Bei numerischen Daten werden fehlende Werte in der Regel mit dem Mittelwert (für normalisierte Datensätze) oder dem Median der Spalten ausgefüllt.\n" ] }, { @@ -2470,7 +2477,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "Sie können **forward-fill** Nullwerte, indem Sie den letzten gültigen Wert verwenden, um einen Nullwert zu füllen:\n" + "Sie können **Forward-Fill**-Nullwerte verwenden, wobei der letzte gültige Wert verwendet wird, um eine Null zu füllen:\n" ] }, { @@ -2511,7 +2518,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Sie können auch **Back-Fill** verwenden, um den nächsten gültigen Wert rückwärts zu propagieren und eine Null zu füllen:\n" + "Sie können auch **Rückfüllung** verwenden, um den nächsten gültigen Wert rückwärts zu propagieren, um eine Null zu füllen:\n" ] }, { @@ -2553,7 +2560,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "Wie Sie sich vielleicht denken können, funktioniert dies genauso mit DataFrames, aber Sie können auch eine `axis` angeben, entlang der Nullwerte ausgefüllt werden sollen:\n" + "Wie Sie sich denken können, funktioniert dies genauso mit DataFrames, aber Sie können auch eine `axis` angeben, entlang der Nullwerte ausgefüllt werden sollen:\n" ] }, { @@ -2759,7 +2766,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Du kannst kreativ sein, wie du `fillna` verwendest. Zum Beispiel, schauen wir uns `example4` noch einmal an, aber dieses Mal füllen wir die fehlenden Werte mit dem Durchschnitt aller Werte im `DataFrame`:\n" + "Sie können kreativ sein, wie Sie `fillna` verwenden. Zum Beispiel schauen wir uns erneut `example4` an, aber dieses Mal füllen wir die fehlenden Werte mit dem Durchschnitt aller Werte im `DataFrame`:\n" ] }, { @@ -2850,9 +2857,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Beachten Sie, dass Spalte 3 immer noch keinen Wert hat: Die Standardrichtung ist, die Werte zeilenweise zu füllen.\n", + "Beachten Sie, dass Spalte 3 immer noch keinen Wert hat: Die Standardrichtung ist, Werte zeilenweise zu füllen.\n", "\n", - "> **Fazit:** Es gibt mehrere Möglichkeiten, mit fehlenden Werten in Ihren Datensätzen umzugehen. Die spezifische Strategie, die Sie anwenden (sie entfernen, ersetzen oder wie Sie sie ersetzen), sollte von den Besonderheiten der Daten abhängen. Je mehr Sie mit Datensätzen arbeiten und interagieren, desto besser werden Sie ein Gespür dafür entwickeln, wie Sie mit fehlenden Werten umgehen können.\n" + "> **Fazit:** Es gibt verschiedene Möglichkeiten, mit fehlenden Werten in Ihren Datensätzen umzugehen. Die spezifische Strategie, die Sie anwenden (Entfernen, Ersetzen oder sogar die Art und Weise, wie Sie sie ersetzen), sollte von den Besonderheiten der Daten abhängen. Je mehr Sie mit Datensätzen arbeiten und interagieren, desto besser werden Sie ein Gefühl dafür entwickeln, wie Sie mit fehlenden Werten umgehen können.\n" ] }, { @@ -2863,9 +2870,9 @@ "source": [ "### Kodierung kategorischer Daten\n", "\n", - "Maschinenlernmodelle arbeiten ausschließlich mit Zahlen und jeglicher Art von numerischen Daten. Sie können nicht zwischen einem \"Ja\" und einem \"Nein\" unterscheiden, aber sie können zwischen 0 und 1 unterscheiden. Daher müssen wir, nachdem die fehlenden Werte ausgefüllt wurden, die kategorischen Daten in eine numerische Form kodieren, damit das Modell sie verstehen kann.\n", + "Maschinenlernmodelle arbeiten ausschließlich mit Zahlen und jeglicher Art von numerischen Daten. Sie können nicht zwischen \"Ja\" und \"Nein\" unterscheiden, wohl aber zwischen 0 und 1. Daher müssen wir, nachdem die fehlenden Werte ergänzt wurden, die kategorischen Daten in eine numerische Form umwandeln, damit das Modell sie verstehen kann.\n", "\n", - "Die Kodierung kann auf zwei Arten erfolgen. Wir werden diese im Folgenden besprechen.\n" + "Die Kodierung kann auf zwei Arten erfolgen. Diese werden wir im Folgenden besprechen.\n" ] }, { @@ -2876,7 +2883,7 @@ "source": [ "**LABEL-ENCODIERUNG**\n", "\n", - "Die Label-Encodierung wandelt im Grunde jede Kategorie in eine Zahl um. Nehmen wir zum Beispiel an, wir haben einen Datensatz von Flugpassagieren, und es gibt eine Spalte, die ihre Klasse aus den folgenden Optionen enthält: ['Business Class', 'Economy Class', 'First Class']. Wenn eine Label-Encodierung darauf angewendet wird, würde dies in [0,1,2] umgewandelt werden. Schauen wir uns ein Beispiel anhand von Code an. Da wir `scikit-learn` in den kommenden Notebooks lernen werden, verwenden wir es hier nicht.\n" + "Die Label-Encodierung bedeutet im Wesentlichen, dass jede Kategorie in eine Zahl umgewandelt wird. Nehmen wir zum Beispiel an, wir haben einen Datensatz von Flugpassagieren, und es gibt eine Spalte, die ihre Klasse aus den folgenden Optionen enthält: ['Business Class', 'Economy Class', 'First Class']. Wenn eine Label-Encodierung darauf angewendet wird, würde dies in [0,1,2] umgewandelt werden. Lassen Sie uns dies anhand eines Codebeispiels betrachten. Da wir in den kommenden Notebooks `scikit-learn` lernen werden, verwenden wir es hier nicht.\n" ] }, { @@ -2984,7 +2991,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Um die Label-Codierung auf der ersten Spalte durchzuführen, müssen wir zunächst eine Zuordnung von jeder Klasse zu einer Zahl beschreiben, bevor wir ersetzen.\n" + "Um eine Label-Codierung in der ersten Spalte durchzuführen, müssen wir zunächst eine Zuordnung von jeder Klasse zu einer Zahl beschreiben, bevor wir sie ersetzen.\n" ] }, { @@ -3099,9 +3106,9 @@ "source": [ "**ONE HOT ENCODING**\n", "\n", - "Eine weitere Art der Kodierung ist das One Hot Encoding. Bei dieser Kodierung wird jede Kategorie der Spalte als separate Spalte hinzugefügt, und jeder Datenpunkt erhält eine 0 oder eine 1, je nachdem, ob er diese Kategorie enthält. Wenn es also n verschiedene Kategorien gibt, werden n Spalten zum Dataframe hinzugefügt.\n", + "Eine weitere Art der Kodierung ist das One Hot Encoding. Bei dieser Kodierung wird jede Kategorie der Spalte als separate Spalte hinzugefügt, und jeder Datenpunkt erhält eine 0 oder eine 1, je nachdem, ob er diese Kategorie enthält. Wenn es also n verschiedene Kategorien gibt, werden n Spalten zum DataFrame hinzugefügt.\n", "\n", - "Zum Beispiel nehmen wir das gleiche Beispiel mit den Flugzeugklassen. Die Kategorien waren: ['business class', 'economy class', 'first class']. Wenn wir also One Hot Encoding durchführen, werden die folgenden drei Spalten zum Datensatz hinzugefügt: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Zum Beispiel nehmen wir wieder das Beispiel der Flugzeugklassen. Die Kategorien waren: ['business class', 'economy class', 'first class']. Wenn wir One Hot Encoding anwenden, werden die folgenden drei Spalten zum Datensatz hinzugefügt: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3209,7 +3216,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "Lassen Sie uns eine One-Hot-Encoding auf der ersten Spalte durchführen\n" + "Lassen Sie uns One-Hot-Encoding auf die erste Spalte durchführen.\n" ] }, { @@ -3334,7 +3341,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Jede One-Hot-Encoded-Spalte enthält 0 oder 1, was angibt, ob diese Kategorie für diesen Datenpunkt existiert.\n" + "Jede One-Hot-encodierte Spalte enthält 0 oder 1, was angibt, ob diese Kategorie für diesen Datenpunkt existiert.\n" ] }, { @@ -3357,7 +3364,7 @@ "source": [ "> Wichtige Erkenntnisse:\n", "1. Kodierung wird durchgeführt, um nicht-numerische Daten in numerische Daten umzuwandeln.\n", - "2. Es gibt zwei Arten der Kodierung: Label-Kodierung und One-Hot-Kodierung, die je nach Anforderungen des Datensatzes durchgeführt werden können.\n" + "2. Es gibt zwei Arten der Kodierung: Label-Kodierung und One-Hot-Kodierung, die je nach Anforderungen des Datensatzes angewendet werden können.\n" ] }, { @@ -3368,9 +3375,9 @@ "source": [ "## Entfernen von doppelten Daten\n", "\n", - "> **Lernziel:** Am Ende dieses Abschnitts solltest du in der Lage sein, doppelte Werte in DataFrames zu erkennen und zu entfernen.\n", + "> **Lernziel:** Am Ende dieses Abschnitts sollten Sie in der Lage sein, doppelte Werte in DataFrames zu identifizieren und zu entfernen.\n", "\n", - "Neben fehlenden Daten wirst du in realen Datensätzen häufig auf doppelte Daten stoßen. Glücklicherweise bietet pandas eine einfache Möglichkeit, doppelte Einträge zu erkennen und zu entfernen.\n" + "Neben fehlenden Daten stoßen Sie in realen Datensätzen häufig auf doppelte Daten. Glücklicherweise bietet pandas eine einfache Möglichkeit, doppelte Einträge zu erkennen und zu entfernen.\n" ] }, { @@ -3381,7 +3388,7 @@ "source": [ "### Duplikate identifizieren: `duplicated`\n", "\n", - "Mit der Methode `duplicated` in pandas können Sie Duplikate ganz einfach erkennen. Sie gibt eine Boolesche Maske zurück, die anzeigt, ob ein Eintrag in einem `DataFrame` ein Duplikat eines früheren Eintrags ist. Lassen Sie uns ein weiteres Beispiel-`DataFrame` erstellen, um dies in Aktion zu sehen.\n" + "Mit der `duplicated`-Methode in pandas können Sie ganz einfach doppelte Werte erkennen. Diese Methode gibt eine Boolesche Maske zurück, die anzeigt, ob ein Eintrag in einem `DataFrame` ein Duplikat eines früheren Eintrags ist. Lassen Sie uns ein weiteres Beispiel-`DataFrame` erstellen, um dies in Aktion zu sehen.\n" ] }, { @@ -3510,8 +3517,8 @@ "id": "0eDRJD4SgRsK" }, "source": [ - "### Duplikate entfernen: `drop_duplicates`\n", - "`drop_duplicates` gibt einfach eine Kopie der Daten zurück, bei der alle `duplicated` Werte `False` sind:\n" + "### Entfernen von Duplikaten: `drop_duplicates`\n", + "`drop_duplicates` gibt einfach eine Kopie der Daten zurück, bei der alle `duplicated`-Werte `False` sind:\n" ] }, { @@ -3594,7 +3601,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Sowohl `duplicated` als auch `drop_duplicates` berücksichtigen standardmäßig alle Spalten, aber Sie können angeben, dass sie nur einen Teil der Spalten in Ihrem `DataFrame` untersuchen:\n" + "Sowohl `duplicated` als auch `drop_duplicates` berücksichtigen standardmäßig alle Spalten, aber Sie können angeben, dass sie nur eine Teilmenge der Spalten in Ihrem `DataFrame` untersuchen:\n" ] }, { @@ -3670,7 +3677,525 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Wichtig:** Das Entfernen von doppelten Daten ist ein wesentlicher Bestandteil fast jedes Data-Science-Projekts. Doppelte Daten können die Ergebnisse Ihrer Analysen verändern und Ihnen ungenaue Ergebnisse liefern!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Qualitätsprüfungen für reale Daten\n", + "\n", + "> **Lernziel:** Am Ende dieses Abschnitts sollten Sie in der Lage sein, häufige Qualitätsprobleme in realen Datensätzen zu erkennen und zu beheben, einschließlich inkonsistenter kategorischer Werte, ungewöhnlicher numerischer Werte (Ausreißer) und doppelter Einträge mit Variationen.\n", + "\n", + "Neben fehlenden Werten und exakten Duplikaten enthalten reale Datensätze oft subtilere Probleme:\n", + "\n", + "1. **Inkonsistente kategorische Werte**: Dieselbe Kategorie wird unterschiedlich geschrieben (z. B. \"USA\", \"U.S.A\", \"United States\").\n", + "2. **Ungewöhnliche numerische Werte**: Extreme Ausreißer, die auf Eingabefehler hinweisen (z. B. Alter = 999).\n", + "3. **Fast identische Zeilen**: Datensätze, die dieselbe Entität mit leichten Abweichungen darstellen.\n", + "\n", + "Lassen Sie uns Techniken erkunden, um diese Probleme zu erkennen und zu beheben.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Erstellen eines Beispiel-Datensatzes mit \"schmutzigen\" Daten\n", + "\n", + "Zunächst erstellen wir einen Beispiel-Datensatz, der die Arten von Problemen enthält, die wir häufig in realen Daten antreffen:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Erkennung inkonsistenter kategorischer Werte\n", + "\n", + "Beachten Sie, dass die Spalte `country` mehrere Darstellungen für dieselben Länder enthält. Lassen Sie uns diese Inkonsistenzen identifizieren:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Standardisierung von kategorischen Werten\n", + "\n", + "Wir können eine Zuordnung erstellen, um diese Werte zu standardisieren. Ein einfacher Ansatz ist, die Werte in Kleinbuchstaben umzuwandeln und ein Zuordnungswörterbuch zu erstellen:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternative: Verwendung von Fuzzy Matching**\n", + "\n", + "Für komplexere Fälle können wir Fuzzy-String-Matching mit der `rapidfuzz`-Bibliothek verwenden, um ähnliche Zeichenfolgen automatisch zu erkennen:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Erkennung von ungewöhnlichen numerischen Werten (Ausreißer)\n", + "\n", + "Betrachten wir die Spalte `age`, so finden sich einige verdächtige Werte wie 199 und -5. Lassen Sie uns statistische Methoden verwenden, um diese Ausreißer zu erkennen.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Verwendung der IQR-Methode (Interquartilsabstand)\n", + "\n", + "Die IQR-Methode ist eine robuste statistische Technik zur Erkennung von Ausreißern, die weniger empfindlich gegenüber Extremwerten ist:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Verwendung der Z-Score-Methode\n", + "\n", + "Die Z-Score-Methode identifiziert Ausreißer basierend auf Standardabweichungen vom Mittelwert:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Umgang mit Ausreißern\n", + "\n", + "Sobald Ausreißer erkannt wurden, können sie auf verschiedene Weise behandelt werden:\n", + "1. **Entfernen**: Zeilen mit Ausreißern löschen (falls es sich um Fehler handelt)\n", + "2. **Begrenzen**: Mit Grenzwerten ersetzen\n", + "3. **Mit NaN ersetzen**: Als fehlende Daten behandeln und Imputationstechniken anwenden\n", + "4. **Behalten**: Wenn es sich um legitime Extremwerte handelt\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Erkennen von nahezu identischen Zeilen\n", + "\n", + "Beachten Sie, dass unser Datensatz mehrere Einträge für \"John Smith\" mit leicht unterschiedlichen Werten enthält. Lassen Sie uns potenzielle Duplikate basierend auf Namensähnlichkeit identifizieren.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Finden von nahezu Duplikaten mit unscharfer Übereinstimmung\n", + "\n", + "Für eine fortgeschrittene Duplikaterkennung können wir unscharfe Übereinstimmung verwenden, um ähnliche Namen zu finden:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Umgang mit Duplikaten\n", + "\n", + "Sobald Duplikate identifiziert wurden, musst du entscheiden, wie du sie behandeln möchtest:\n", + "1. **Erste Vorkommen behalten**: Verwende `drop_duplicates(keep='first')`\n", + "2. **Letzte Vorkommen behalten**: Verwende `drop_duplicates(keep='last')`\n", + "3. **Informationen zusammenfassen**: Kombiniere Informationen aus den duplizierten Zeilen\n", + "4. **Manuelle Überprüfung**: Markiere sie für eine Überprüfung durch Menschen\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Zusammenfassung: Vollständige Datenbereinigungs-Pipeline\n", + "\n", + "Lassen Sie uns alles zu einer umfassenden Bereinigungs-Pipeline zusammenfügen:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Herausforderungsübung\n", + "\n", + "Jetzt bist du dran! Unten findest du eine neue Datenzeile mit mehreren Qualitätsproblemen. Kannst du:\n", + "\n", + "1. Alle Probleme in dieser Zeile identifizieren\n", + "2. Code schreiben, um jedes Problem zu beheben\n", + "3. Die bereinigte Zeile dem Datensatz hinzufügen\n", + "\n", + "Hier sind die fehlerhaften Daten:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Wichtige Erkenntnisse\n", + "\n", + "1. **Inkonsistente Kategorien** sind in realen Daten häufig. Überprüfen Sie immer die eindeutigen Werte und standardisieren Sie sie mithilfe von Zuordnungen oder unscharfem Abgleich.\n", + "\n", + "2. **Ausreißer** können Ihre Analyse erheblich beeinflussen. Verwenden Sie Fachwissen in Kombination mit statistischen Methoden (IQR, Z-Score), um sie zu erkennen.\n", + "\n", + "3. **Nahezu-Duplikate** sind schwieriger zu erkennen als exakte Duplikate. Ziehen Sie unscharfen Abgleich und die Normalisierung von Daten (Kleinschreibung, Entfernen von Leerzeichen) in Betracht, um sie zu identifizieren.\n", + "\n", + "4. **Datenbereinigung ist iterativ**. Es kann erforderlich sein, mehrere Techniken anzuwenden und die Ergebnisse zu überprüfen, bevor Sie Ihr bereinigtes Dataset finalisieren.\n", + "\n", + "5. **Dokumentieren Sie Ihre Entscheidungen**. Halten Sie fest, welche Bereinigungsschritte Sie angewendet haben und warum, da dies für Reproduzierbarkeit und Transparenz wichtig ist.\n", + "\n", + "> **Best Practice:** Bewahren Sie immer eine Kopie Ihrer ursprünglichen \"rohen\" Daten auf. Überschreiben Sie niemals Ihre Quelldateien – erstellen Sie bereinigte Versionen mit klaren Namenskonventionen wie `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", @@ -3704,8 +4229,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:32:26+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T18:59:17+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "de" } diff --git a/translations/el/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/el/2-Working-With-Data/08-data-preparation/notebook.ipynb index 4adc5491..7d41950d 100644 --- a/translations/el/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/el/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# Προετοιμασία Δεδομένων\n", "\n", - "[Πρωτότυπη πηγή Notebook από *Data Science: Εισαγωγή στη Μηχανική Μάθηση για Data Science Python και Machine Learning Studio από τον Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Αρχική πηγή Notebook από *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## Εξερεύνηση πληροφοριών του `DataFrame`\n", "\n", "> **Στόχος μάθησης:** Μέχρι το τέλος αυτής της υποενότητας, θα πρέπει να είστε άνετοι με την εύρεση γενικών πληροφοριών για τα δεδομένα που είναι αποθηκευμένα σε pandas DataFrames.\n", "\n", - "Αφού φορτώσετε τα δεδομένα σας στο pandas, είναι πολύ πιθανό να βρίσκονται σε ένα `DataFrame`. Ωστόσο, αν το σύνολο δεδομένων στο `DataFrame` σας έχει 60.000 γραμμές και 400 στήλες, πώς μπορείτε καν να αρχίσετε να κατανοείτε με τι δουλεύετε; Ευτυχώς, το pandas παρέχει μερικά βολικά εργαλεία για να δείτε γρήγορα συνολικές πληροφορίες για ένα `DataFrame`, καθώς και τις πρώτες και τελευταίες γραμμές.\n", + "Μόλις φορτώσετε τα δεδομένα σας στο pandas, είναι πολύ πιθανό να βρίσκονται σε ένα `DataFrame`. Ωστόσο, αν το σύνολο δεδομένων στο `DataFrame` σας έχει 60.000 γραμμές και 400 στήλες, πώς μπορείτε καν να αρχίσετε να κατανοείτε με τι δουλεύετε; Ευτυχώς, το pandas παρέχει μερικά βολικά εργαλεία για να δείτε γρήγορα συνολικές πληροφορίες για ένα `DataFrame`, καθώς και τις πρώτες και τελευταίες γραμμές.\n", "\n", - "Για να εξερευνήσουμε αυτή τη λειτουργικότητα, θα εισάγουμε τη βιβλιοθήκη scikit-learn της Python και θα χρησιμοποιήσουμε ένα εμβληματικό σύνολο δεδομένων που κάθε επιστήμονας δεδομένων έχει δει εκατοντάδες φορές: το σύνολο δεδομένων *Iris* του Βρετανού βιολόγου Ronald Fisher, που χρησιμοποιήθηκε στο άρθρο του το 1936 \"Η χρήση πολλαπλών μετρήσεων σε ταξινομικά προβλήματα\":\n" + "Για να εξερευνήσουμε αυτή τη λειτουργικότητα, θα εισάγουμε τη βιβλιοθήκη Python scikit-learn και θα χρησιμοποιήσουμε ένα εμβληματικό σύνολο δεδομένων που κάθε επιστήμονας δεδομένων έχει δει εκατοντάδες φορές: το σύνολο δεδομένων *Iris* του Βρετανού βιολόγου Ronald Fisher, που χρησιμοποιήθηκε στο άρθρο του το 1936 \"Η χρήση πολλαπλών μετρήσεων σε ταξινομικά προβλήματα\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Έχουμε φορτώσει το σύνολο δεδομένων Iris στη μεταβλητή `iris_df`. Πριν εμβαθύνουμε στα δεδομένα, θα ήταν χρήσιμο να γνωρίζουμε τον αριθμό των σημείων δεδομένων που έχουμε και το συνολικό μέγεθος του συνόλου δεδομένων. Είναι χρήσιμο να εξετάσουμε τον όγκο των δεδομένων με τα οποία ασχολούμαστε.\n" + "Έχουμε φορτώσει το Iris Dataset στη μεταβλητή `iris_df`. Πριν εξετάσουμε τα δεδομένα, θα ήταν χρήσιμο να γνωρίζουμε τον αριθμό των σημείων δεδομένων που έχουμε και το συνολικό μέγεθος του συνόλου δεδομένων. Είναι χρήσιμο να δούμε τον όγκο των δεδομένων που επεξεργαζόμαστε.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Έχουμε να κάνουμε με 150 γραμμές και 4 στήλες δεδομένων. Κάθε γραμμή αντιπροσωπεύει ένα σημείο δεδομένων και κάθε στήλη αντιπροσωπεύει ένα χαρακτηριστικό που σχετίζεται με το πλαίσιο δεδομένων. Ουσιαστικά, υπάρχουν 150 σημεία δεδομένων που περιέχουν από 4 χαρακτηριστικά το καθένα.\n", + "Λοιπόν, έχουμε να κάνουμε με 150 γραμμές και 4 στήλες δεδομένων. Κάθε γραμμή αντιπροσωπεύει ένα σημείο δεδομένων και κάθε στήλη αντιπροσωπεύει ένα χαρακτηριστικό που σχετίζεται με το πλαίσιο δεδομένων. Ουσιαστικά, υπάρχουν 150 σημεία δεδομένων που περιέχουν από 4 χαρακτηριστικά το καθένα.\n", "\n", - "Το `shape` εδώ είναι μια ιδιότητα του πλαισίου δεδομένων και όχι μια συνάρτηση, γι' αυτό δεν τελειώνει με ένα ζευγάρι παρενθέσεων.\n" + "Το `shape` εδώ είναι ένα χαρακτηριστικό του πλαισίου δεδομένων και όχι μια συνάρτηση, γι' αυτό δεν τελειώνει με ένα ζευγάρι παρενθέσεων.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Ας προχωρήσουμε τώρα στις 4 στήλες δεδομένων. Τι ακριβώς αντιπροσωπεύει η κάθε μία; Η ιδιότητα `columns` θα μας δώσει τα ονόματα των στηλών στο dataframe.\n" + "Ας εξετάσουμε τώρα τις 4 στήλες δεδομένων. Τι ακριβώς αντιπροσωπεύει η κάθε μία; Η ιδιότητα `columns` θα μας δώσει τα ονόματα των στηλών στο dataframe.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Από εδώ, μπορούμε να κάνουμε μερικές παρατηρήσεις: \n", - "1. Ο τύπος δεδομένων (DataType) κάθε στήλης: Σε αυτό το σύνολο δεδομένων, όλα τα δεδομένα αποθηκεύονται ως αριθμοί κινητής υποδιαστολής 64-bit. \n", - "2. Ο αριθμός των μη μηδενικών τιμών (Non-Null values): Η διαχείριση των μηδενικών τιμών είναι ένα σημαντικό βήμα στην προετοιμασία δεδομένων. Αυτό θα αντιμετωπιστεί αργότερα στο notebook. \n" + "Από εδώ, μπορούμε να κάνουμε μερικές παρατηρήσεις:\n", + "1. Ο τύπος δεδομένων κάθε στήλης: Σε αυτό το σύνολο δεδομένων, όλα τα δεδομένα αποθηκεύονται ως αριθμοί κινητής υποδιαστολής 64-bit.\n", + "2. Αριθμός μη μηδενικών τιμών: Η διαχείριση των μηδενικών τιμών είναι ένα σημαντικό βήμα στην προετοιμασία δεδομένων. Θα αντιμετωπιστεί αργότερα στο σημειωματάριο.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "Η έξοδος παραπάνω δείχνει τον συνολικό αριθμό σημείων δεδομένων, τη μέση τιμή, την τυπική απόκλιση, την ελάχιστη τιμή, το κατώτερο τεταρτημόριο (25%), τη διάμεσο (50%), το ανώτερο τεταρτημόριο (75%) και τη μέγιστη τιμή κάθε στήλης.\n" + "Η παραπάνω έξοδος δείχνει τον συνολικό αριθμό σημείων δεδομένων, τη μέση τιμή, την τυπική απόκλιση, την ελάχιστη τιμή, το κατώτερο τεταρτημόριο (25%), τη διάμεσο (50%), το ανώτερο τεταρτημόριο (75%) και τη μέγιστη τιμή κάθε στήλης.\n" ] }, { @@ -334,7 +334,7 @@ "### `DataFrame.head`\n", "Με όλες τις παραπάνω συναρτήσεις και ιδιότητες, έχουμε αποκτήσει μια συνολική εικόνα του συνόλου δεδομένων. Γνωρίζουμε πόσα σημεία δεδομένων υπάρχουν, πόσα χαρακτηριστικά υπάρχουν, τον τύπο δεδομένων κάθε χαρακτηριστικού και τον αριθμό των μη μηδενικών τιμών για κάθε χαρακτηριστικό.\n", "\n", - "Τώρα είναι η στιγμή να δούμε τα ίδια τα δεδομένα. Ας δούμε πώς φαίνονται οι πρώτες γραμμές (τα πρώτα σημεία δεδομένων) του `DataFrame` μας:\n" + "Τώρα είναι η ώρα να δούμε τα ίδια τα δεδομένα. Ας δούμε πώς φαίνονται οι πρώτες γραμμές (τα πρώτα σημεία δεδομένων) του `DataFrame` μας:\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Άσκηση:\n", "\n", - "Από το παραπάνω παράδειγμα, είναι ξεκάθαρο ότι, από προεπιλογή, το `DataFrame.head` επιστρέφει τις πρώτες πέντε γραμμές ενός `DataFrame`. Στο παρακάτω κελί κώδικα, μπορείς να βρεις έναν τρόπο να εμφανίσεις περισσότερες από πέντε γραμμές;\n" + "Από το παραπάνω παράδειγμα, είναι ξεκάθαρο ότι, από προεπιλογή, η μέθοδος `DataFrame.head` επιστρέφει τις πρώτες πέντε γραμμές ενός `DataFrame`. Στο παρακάτω κελί κώδικα, μπορείτε να βρείτε έναν τρόπο να εμφανίσετε περισσότερες από πέντε γραμμές;\n" ] }, { @@ -586,7 +586,7 @@ "\n", "Όλες οι συναρτήσεις και οι ιδιότητες που παρουσιάστηκαν παραπάνω με τη βοήθεια παραδειγμάτων κώδικα, μας βοηθούν να αποκτήσουμε μια εικόνα και αίσθηση των δεδομένων.\n", "\n", - "> **Συμπέρασμα:** Ακόμη και μόνο κοιτάζοντας τα μεταδεδομένα σχετικά με τις πληροφορίες σε ένα DataFrame ή τις πρώτες και τελευταίες τιμές του, μπορείτε να αποκτήσετε άμεσα μια ιδέα για το μέγεθος, τη μορφή και το περιεχόμενο των δεδομένων που επεξεργάζεστε.\n" + "> **Συμπέρασμα:** Ακόμα και μόνο κοιτάζοντας τα μεταδεδομένα σχετικά με τις πληροφορίες σε ένα DataFrame ή τις πρώτες και τελευταίες τιμές του, μπορείτε να αποκτήσετε άμεσα μια ιδέα για το μέγεθος, τη μορφή και το περιεχόμενο των δεδομένων που επεξεργάζεστε.\n" ] }, { @@ -598,15 +598,15 @@ "### Ελλιπή Δεδομένα\n", "Ας εξετάσουμε τα ελλιπή δεδομένα. Ελλιπή δεδομένα εμφανίζονται όταν δεν έχει αποθηκευτεί κάποια τιμή σε ορισμένες στήλες.\n", "\n", - "Ας πάρουμε ένα παράδειγμα: ας πούμε ότι κάποιος είναι ευαίσθητος σχετικά με το βάρος του και δεν συμπληρώνει το πεδίο βάρους σε μια έρευνα. Τότε, η τιμή του βάρους για αυτό το άτομο θα είναι ελλιπής.\n", + "Ας πάρουμε ένα παράδειγμα: ας πούμε ότι κάποιος είναι ευαίσθητος σχετικά με το βάρος του και δεν συμπληρώνει το πεδίο του βάρους σε μια έρευνα. Τότε, η τιμή του βάρους για αυτό το άτομο θα λείπει.\n", "\n", - "Στις περισσότερες περιπτώσεις, σε σύνολα δεδομένων του πραγματικού κόσμου, εμφανίζονται ελλιπείς τιμές.\n", + "Τις περισσότερες φορές, σε σύνολα δεδομένων του πραγματικού κόσμου, εμφανίζονται ελλιπείς τιμές.\n", "\n", - "**Πώς τα Pandas διαχειρίζονται τα ελλιπή δεδομένα**\n", + "**Πώς το Pandas διαχειρίζεται τα ελλιπή δεδομένα**\n", "\n", - "Τα Pandas διαχειρίζονται τις ελλιπείς τιμές με δύο τρόπους. Ο πρώτος τρόπος, τον οποίο έχετε δει σε προηγούμενες ενότητες, είναι το `NaN`, ή Not a Number. Αυτό είναι στην πραγματικότητα μια ειδική τιμή που αποτελεί μέρος της προδιαγραφής IEEE για αριθμούς κινητής υποδιαστολής και χρησιμοποιείται μόνο για να υποδείξει ελλιπείς τιμές κινητής υποδιαστολής.\n", + "Το Pandas διαχειρίζεται τις ελλιπείς τιμές με δύο τρόπους. Ο πρώτος τρόπος, τον οποίο έχετε δει σε προηγούμενες ενότητες, είναι το `NaN`, ή Not a Number. Αυτό είναι στην πραγματικότητα μια ειδική τιμή που αποτελεί μέρος της προδιαγραφής IEEE floating-point και χρησιμοποιείται μόνο για να υποδείξει ελλιπείς τιμές κινητής υποδιαστολής.\n", "\n", - "Για ελλιπείς τιμές εκτός από αριθμούς κινητής υποδιαστολής, τα Pandas χρησιμοποιούν το αντικείμενο `None` της Python. Ενώ μπορεί να φαίνεται μπερδεμένο ότι θα συναντήσετε δύο διαφορετικά είδη τιμών που ουσιαστικά λένε το ίδιο πράγμα, υπάρχουν βάσιμοι προγραμματιστικοί λόγοι για αυτήν την επιλογή σχεδίασης και, στην πράξη, αυτή η προσέγγιση επιτρέπει στα Pandas να προσφέρουν έναν καλό συμβιβασμό για τη συντριπτική πλειονότητα των περιπτώσεων. Παρ' όλα αυτά, τόσο το `None` όσο και το `NaN` έχουν περιορισμούς που πρέπει να έχετε υπόψη σας σχετικά με το πώς μπορούν να χρησιμοποιηθούν.\n" + "Για ελλιπείς τιμές εκτός από αριθμούς κινητής υποδιαστολής, το Pandas χρησιμοποιεί το αντικείμενο `None` της Python. Παρόλο που μπορεί να φαίνεται μπερδεμένο ότι θα συναντήσετε δύο διαφορετικά είδη τιμών που ουσιαστικά λένε το ίδιο πράγμα, υπάρχουν βάσιμοι προγραμματιστικοί λόγοι για αυτήν την επιλογή σχεδίασης και, στην πράξη, αυτή η προσέγγιση επιτρέπει στο Pandas να προσφέρει έναν καλό συμβιβασμό για τη συντριπτική πλειονότητα των περιπτώσεων. Παρ' όλα αυτά, τόσο το `None` όσο και το `NaN` έχουν περιορισμούς που πρέπει να έχετε υπόψη σας σχετικά με το πώς μπορούν να χρησιμοποιηθούν.\n" ] }, { @@ -616,9 +616,9 @@ }, "source": [ "### `None`: μη αριθμητικά δεδομένα που λείπουν\n", - "Επειδή το `None` προέρχεται από την Python, δεν μπορεί να χρησιμοποιηθεί σε πίνακες NumPy και pandas που δεν έχουν τύπο δεδομένων `'object'`. Θυμηθείτε, οι πίνακες NumPy (και οι δομές δεδομένων στις pandas) μπορούν να περιέχουν μόνο έναν τύπο δεδομένων. Αυτό είναι που τους δίνει τη μεγάλη τους δύναμη για επεξεργασία δεδομένων και υπολογιστική σε μεγάλη κλίμακα, αλλά περιορίζει επίσης την ευελιξία τους. Τέτοιοι πίνακες πρέπει να μετατρέπονται στον \"χαμηλότερο κοινό παρονομαστή\", δηλαδή τον τύπο δεδομένων που μπορεί να περιλάβει τα πάντα στον πίνακα. Όταν το `None` βρίσκεται στον πίνακα, σημαίνει ότι εργάζεστε με αντικείμενα της Python.\n", + "Επειδή το `None` προέρχεται από την Python, δεν μπορεί να χρησιμοποιηθεί σε πίνακες NumPy και pandas που δεν έχουν τύπο δεδομένων `'object'`. Θυμηθείτε, οι πίνακες NumPy (και οι δομές δεδομένων στις pandas) μπορούν να περιέχουν μόνο έναν τύπο δεδομένων. Αυτό είναι που τους δίνει τη μεγάλη τους δύναμη για επεξεργασία δεδομένων μεγάλης κλίμακας και υπολογιστική εργασία, αλλά περιορίζει επίσης την ευελιξία τους. Τέτοιοι πίνακες πρέπει να μετατρέπονται στον \"χαμηλότερο κοινό παρονομαστή\", δηλαδή τον τύπο δεδομένων που θα περιλαμβάνει όλα τα στοιχεία του πίνακα. Όταν το `None` βρίσκεται στον πίνακα, σημαίνει ότι εργάζεστε με αντικείμενα της Python.\n", "\n", - "Για να το δείτε στην πράξη, εξετάστε τον παρακάτω πίνακα παραδείγματος (σημειώστε το `dtype` του):\n" + "Για να το δείτε στην πράξη, εξετάστε τον παρακάτω παράδειγμα πίνακα (προσέξτε το `dtype` του):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Η πραγματικότητα των αναβαθμισμένων τύπων δεδομένων συνοδεύεται από δύο παρενέργειες. Πρώτον, οι λειτουργίες θα εκτελούνται στο επίπεδο του ερμηνευμένου κώδικα Python αντί για τον μεταγλωττισμένο κώδικα NumPy. Ουσιαστικά, αυτό σημαίνει ότι οποιεσδήποτε λειτουργίες που περιλαμβάνουν `Series` ή `DataFrames` με `None` θα είναι πιο αργές. Αν και πιθανότατα δεν θα παρατηρήσετε αυτήν την πτώση απόδοσης, για μεγάλα σύνολα δεδομένων μπορεί να γίνει πρόβλημα.\n", + "Η πραγματικότητα των ανυψωμένων τύπων δεδομένων συνοδεύεται από δύο παρενέργειες. Πρώτον, οι λειτουργίες θα εκτελούνται στο επίπεδο του ερμηνευμένου κώδικα Python αντί για τον μεταγλωττισμένο κώδικα NumPy. Ουσιαστικά, αυτό σημαίνει ότι οποιεσδήποτε λειτουργίες που περιλαμβάνουν `Series` ή `DataFrames` με `None` θα είναι πιο αργές. Αν και πιθανότατα δεν θα παρατηρήσετε αυτήν την πτώση απόδοσης, για μεγάλα σύνολα δεδομένων μπορεί να γίνει πρόβλημα.\n", "\n", - "Η δεύτερη παρενέργεια προκύπτει από την πρώτη. Επειδή το `None` ουσιαστικά \"τραβάει\" τα `Series` ή τα `DataFrame`s πίσω στον κόσμο της απλής Python, η χρήση συναρτήσεων συσσωμάτωσης του NumPy/pandas όπως `sum()` ή `min()` σε πίνακες που περιέχουν μια τιμή ``None`` θα παράγει γενικά σφάλμα:\n" + "Η δεύτερη παρενέργεια προκύπτει από την πρώτη. Επειδή το `None` ουσιαστικά \"τραβάει\" τα `Series` ή τα `DataFrame` πίσω στον κόσμο της απλής Python, η χρήση συναθροίσεων NumPy/pandas όπως `sum()` ή `min()` σε πίνακες που περιέχουν μια τιμή ``None`` θα παράγει γενικά ένα σφάλμα:\n" ] }, { @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Βασικό συμπέρασμα**: Η πρόσθεση (και άλλες πράξεις) μεταξύ ακέραιων αριθμών και τιμών `None` είναι απροσδιόριστη, κάτι που μπορεί να περιορίσει τι μπορείτε να κάνετε με σύνολα δεδομένων που τις περιέχουν.\n" + "**Κύριο συμπέρασμα**: Η πρόσθεση (και άλλες πράξεις) μεταξύ ακέραιων αριθμών και τιμών `None` είναι απροσδιόριστη, κάτι που μπορεί να περιορίσει τις δυνατότητες επεξεργασίας συνόλων δεδομένων που τις περιέχουν.\n" ] }, { @@ -707,9 +707,9 @@ "id": "pWvVHvETgRr9" }, "source": [ - "### `NaN`: τιμές κινητής υποδιαστολής που λείπουν\n", + "### `NaN`: έλλειψη τιμών float\n", "\n", - "Σε αντίθεση με το `None`, η NumPy (και συνεπώς το pandas) υποστηρίζει το `NaN` για τις γρήγορες, διανυσματικές λειτουργίες και τις ufuncs. Τα κακά νέα είναι ότι οποιαδήποτε αριθμητική πράξη εκτελείται στο `NaN` έχει πάντα ως αποτέλεσμα το `NaN`. Για παράδειγμα:\n" + "Σε αντίθεση με το `None`, το NumPy (και κατά συνέπεια το pandas) υποστηρίζει το `NaN` για τις γρήγορες, διανυσματικές λειτουργίες και ufuncs. Το αρνητικό είναι ότι οποιαδήποτε αριθμητική πράξη που εκτελείται με `NaN` πάντα καταλήγει σε `NaN`. Για παράδειγμα:\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Τα καλά νέα: οι συναθροίσεις που εκτελούνται σε πίνακες με `NaN` δεν εμφανίζουν σφάλματα. Τα κακά νέα: τα αποτελέσματα δεν είναι ομοιόμορφα χρήσιμα:\n" + "Τα καλά νέα: οι συναθροίσεις που εκτελούνται σε πίνακες με `NaN` μέσα τους δεν εμφανίζουν σφάλματα. Τα κακά νέα: τα αποτελέσματα δεν είναι ομοιόμορφα χρήσιμα:\n" ] }, { @@ -831,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "Θυμηθείτε: `NaN` είναι μόνο για ελλείποντα δεκαδικά σημεία; δεν υπάρχει αντίστοιχο `NaN` για ακέραιους, συμβολοσειρές ή Boolean.\n" + "Θυμήσου: `NaN` είναι μόνο για ελλείποντα δεκαδικά (floating-point) δεδομένα· δεν υπάρχει αντίστοιχο `NaN` για ακέραιους, συμβολοσειρές ή λογικές τιμές.\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Κατά τη διαδικασία αναβάθμισης τύπων δεδομένων για την επίτευξη ομοιογένειας δεδομένων σε `Series` και `DataFrame`s, το pandas είναι πρόθυμο να μετατρέψει τις ελλείπουσες τιμές μεταξύ `None` και `NaN`. Λόγω αυτού του χαρακτηριστικού σχεδιασμού, μπορεί να είναι χρήσιμο να σκεφτείτε το `None` και το `NaN` ως δύο διαφορετικές εκδοχές του \"null\" στο pandas. Πράγματι, ορισμένες από τις βασικές μεθόδους που θα χρησιμοποιήσετε για να διαχειριστείτε ελλείπουσες τιμές στο pandas αντικατοπτρίζουν αυτήν την ιδέα στα ονόματά τους:\n", + "Κατά τη διαδικασία αναβάθμισης τύπων δεδομένων για την καθιέρωση ομοιογένειας δεδομένων σε `Series` και `DataFrame`s, το pandas μπορεί να αλλάξει πρόθυμα τις ελλείπουσες τιμές μεταξύ `None` και `NaN`. Λόγω αυτής της σχεδιαστικής λειτουργίας, είναι χρήσιμο να σκεφτόμαστε το `None` και το `NaN` ως δύο διαφορετικές μορφές \"κενών\" στο pandas. Πράγματι, ορισμένες από τις βασικές μεθόδους που θα χρησιμοποιήσετε για να διαχειριστείτε ελλείπουσες τιμές στο pandas αντικατοπτρίζουν αυτήν την ιδέα στα ονόματά τους:\n", "\n", - "- `isnull()`: Δημιουργεί μια Boolean μάσκα που υποδεικνύει ελλείπουσες τιμές\n", + "- `isnull()`: Δημιουργεί μια μάσκα Boolean που υποδεικνύει τις ελλείπουσες τιμές\n", "- `notnull()`: Αντίθετο του `isnull()`\n", "- `dropna()`: Επιστρέφει μια φιλτραρισμένη έκδοση των δεδομένων\n", "- `fillna()`: Επιστρέφει ένα αντίγραφο των δεδομένων με τις ελλείπουσες τιμές συμπληρωμένες ή υπολογισμένες\n", "\n", - "Αυτές είναι σημαντικές μέθοδοι που πρέπει να κατανοήσετε και να εξοικειωθείτε, οπότε ας τις εξετάσουμε καθεμία με περισσότερη λεπτομέρεια.\n" + "Αυτές είναι σημαντικές μέθοδοι που πρέπει να μάθετε και να εξοικειωθείτε, οπότε ας τις εξετάσουμε καθεμία πιο αναλυτικά.\n" ] }, { @@ -924,7 +924,7 @@ "source": [ "### Εντοπισμός κενών τιμών\n", "\n", - "Τώρα που κατανοήσαμε τη σημασία των ελλιπών τιμών, πρέπει να τις εντοπίσουμε στο σύνολο δεδομένων μας, πριν τις διαχειριστούμε. \n", + "Τώρα που έχουμε κατανοήσει τη σημασία των ελλειπόντων τιμών, πρέπει να τις εντοπίσουμε στο σύνολο δεδομένων μας, πριν τις διαχειριστούμε. \n", "Οι μέθοδοι `isnull()` και `notnull()` είναι οι κύριες μέθοδοι σας για τον εντοπισμό κενών δεδομένων. Και οι δύο επιστρέφουν μάσκες Boolean πάνω στα δεδομένα σας.\n" ] }, @@ -978,9 +978,9 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Κοιτάξτε προσεκτικά το αποτέλεσμα. Σας εκπλήσσει κάτι από αυτό; Παρόλο που το `0` είναι μια αριθμητική μηδενική τιμή, είναι παρ' όλα αυτά ένας απολύτως έγκυρος ακέραιος αριθμός και το pandas τον αντιμετωπίζει ως τέτοιο. Το `''` είναι λίγο πιο λεπτό ζήτημα. Ενώ το χρησιμοποιήσαμε στην Ενότητα 1 για να αντιπροσωπεύσουμε μια κενή συμβολοσειρά, είναι παρ' όλα αυτά ένα αντικείμενο συμβολοσειράς και όχι μια αναπαράσταση του null σύμφωνα με το pandas.\n", + "Κοιτάξτε προσεκτικά το αποτέλεσμα. Σας εκπλήσσει κάτι από αυτό; Παρόλο που το `0` είναι μια αριθμητική τιμή null, παραμένει ένας απολύτως καλός ακέραιος αριθμός και το pandas το αντιμετωπίζει ως τέτοιο. Το `''` είναι λίγο πιο λεπτό. Ενώ το χρησιμοποιήσαμε στην Ενότητα 1 για να εκπροσωπήσουμε μια κενή συμβολοσειρά, παραμένει ένα αντικείμενο συμβολοσειράς και όχι μια αναπαράσταση του null σύμφωνα με το pandas.\n", "\n", - "Τώρα, ας το αντιστρέψουμε και ας χρησιμοποιήσουμε αυτές τις μεθόδους με έναν τρόπο πιο κοντά σε αυτόν που θα τις χρησιμοποιείτε στην πράξη. Μπορείτε να χρησιμοποιήσετε Boolean μάσκες απευθείας ως δείκτη ``Series`` ή ``DataFrame``, κάτι που μπορεί να είναι χρήσιμο όταν προσπαθείτε να εργαστείτε με απομονωμένες τιμές που λείπουν (ή που υπάρχουν).\n", + "Τώρα, ας το δούμε από την αντίθετη πλευρά και ας χρησιμοποιήσουμε αυτές τις μεθόδους με τρόπο που μοιάζει περισσότερο με τον τρόπο που θα τις χρησιμοποιείτε στην πράξη. Μπορείτε να χρησιμοποιήσετε Boolean μάσκες απευθείας ως δείκτη ``Series`` ή ``DataFrame``, κάτι που μπορεί να είναι χρήσιμο όταν προσπαθείτε να εργαστείτε με απομονωμένες τιμές που λείπουν (ή που υπάρχουν).\n", "\n", "Αν θέλουμε τον συνολικό αριθμό των τιμών που λείπουν, μπορούμε απλώς να κάνουμε ένα άθροισμα πάνω στη μάσκα που παράγεται από τη μέθοδο `isnull()`.\n" ] @@ -1053,16 +1053,16 @@ "\n", "> **Στόχος μάθησης:** Μέχρι το τέλος αυτής της υποενότητας, θα πρέπει να γνωρίζετε πώς και πότε να αντικαθιστάτε ή να αφαιρείτε κενές τιμές από DataFrames.\n", "\n", - "Τα μοντέλα Μηχανικής Μάθησης δεν μπορούν να διαχειριστούν από μόνα τους τα ελλιπή δεδομένα. Επομένως, πριν περάσουμε τα δεδομένα στο μοντέλο, πρέπει να αντιμετωπίσουμε αυτές τις ελλείψεις.\n", + "Τα μοντέλα Μηχανικής Μάθησης δεν μπορούν να επεξεργαστούν μόνα τους ελλιπή δεδομένα. Επομένως, πριν περάσουμε τα δεδομένα στο μοντέλο, πρέπει να αντιμετωπίσουμε αυτές τις ελλείψεις.\n", "\n", - "Ο τρόπος με τον οποίο διαχειριζόμαστε τα ελλιπή δεδομένα περιλαμβάνει λεπτές ισορροπίες, μπορεί να επηρεάσει την τελική ανάλυση και τα αποτελέσματα στον πραγματικό κόσμο.\n", + "Ο τρόπος με τον οποίο χειριζόμαστε τα ελλιπή δεδομένα περιλαμβάνει λεπτές συμβιβαστικές αποφάσεις, που μπορούν να επηρεάσουν την τελική ανάλυση και τα αποτελέσματα στον πραγματικό κόσμο.\n", "\n", - "Υπάρχουν κυρίως δύο τρόποι για να αντιμετωπίσουμε τα ελλιπή δεδομένα:\n", + "Υπάρχουν κυρίως δύο τρόποι αντιμετώπισης ελλιπών δεδομένων:\n", "\n", "1. Διαγραφή της γραμμής που περιέχει την ελλιπή τιμή\n", "2. Αντικατάσταση της ελλιπούς τιμής με κάποια άλλη τιμή\n", "\n", - "Θα συζητήσουμε και τις δύο αυτές μεθόδους, καθώς και τα πλεονεκτήματα και τα μειονεκτήματά τους, με λεπτομέρεια.\n" + "Θα συζητήσουμε και τις δύο αυτές μεθόδους καθώς και τα πλεονεκτήματα και μειονεκτήματά τους λεπτομερώς.\n" ] }, { @@ -1075,9 +1075,9 @@ "\n", "Η ποσότητα των δεδομένων που περνάμε στο μοντέλο μας έχει άμεση επίδραση στην απόδοσή του. Η αφαίρεση κενών τιμών σημαίνει ότι μειώνουμε τον αριθμό των σημείων δεδομένων και, κατά συνέπεια, το μέγεθος του συνόλου δεδομένων. Επομένως, είναι προτιμότερο να αφαιρούμε γραμμές με κενές τιμές όταν το σύνολο δεδομένων είναι αρκετά μεγάλο.\n", "\n", - "Μια άλλη περίπτωση μπορεί να είναι ότι μια συγκεκριμένη γραμμή ή στήλη έχει πολλές ελλείπουσες τιμές. Τότε, αυτές μπορεί να αφαιρεθούν επειδή δεν θα προσθέσουν ιδιαίτερη αξία στην ανάλυσή μας, καθώς τα περισσότερα δεδομένα λείπουν για αυτή τη γραμμή/στήλη.\n", + "Μια άλλη περίπτωση μπορεί να είναι ότι μια συγκεκριμένη γραμμή ή στήλη έχει πολλές ελλείπουσες τιμές. Σε αυτή την περίπτωση, μπορεί να αφαιρεθούν, καθώς δεν θα προσθέσουν ιδιαίτερη αξία στην ανάλυσή μας, αφού τα περισσότερα δεδομένα λείπουν για αυτή τη γραμμή/στήλη.\n", "\n", - "Πέρα από την αναγνώριση ελλειπουσών τιμών, το pandas παρέχει έναν εύχρηστο τρόπο για την αφαίρεση κενών τιμών από `Series` και `DataFrame`s. Για να δούμε αυτό στην πράξη, ας επιστρέψουμε στο `example3`. Η συνάρτηση `DataFrame.dropna()` βοηθά στην αφαίρεση των γραμμών με κενές τιμές.\n" + "Πέρα από την αναγνώριση ελλειπουσών τιμών, το pandas παρέχει έναν εύχρηστο τρόπο για την αφαίρεση κενών τιμών από `Series` και `DataFrame`s. Για να το δούμε στην πράξη, ας επιστρέψουμε στο `example3`. Η συνάρτηση `DataFrame.dropna()` βοηθά στην αφαίρεση των γραμμών με κενές τιμές.\n" ] }, { @@ -1116,7 +1116,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "Σημειώστε ότι αυτό θα μοιάζει με την έξοδο από το `example3[example3.notnull()]`. Η διαφορά εδώ είναι ότι, αντί να γίνεται απλώς ευρετηρίαση στις τιμές που δεν είναι κενές, η `dropna` έχει αφαιρέσει αυτές τις ελλιπείς τιμές από τη `Series` `example3`.\n", + "Σημειώστε ότι αυτό θα πρέπει να μοιάζει με το αποτέλεσμα από `example3[example3.notnull()]`. Η διαφορά εδώ είναι ότι, αντί απλώς να γίνεται ευρετηρίαση στις τιμές που έχουν μάσκα, το `dropna` έχει αφαιρέσει αυτές τις ελλείπουσες τιμές από το `Series` `example3`.\n", "\n", "Επειδή τα DataFrames έχουν δύο διαστάσεις, προσφέρουν περισσότερες επιλογές για την αφαίρεση δεδομένων.\n" ] @@ -1208,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Παρατηρήσατε ότι το pandas μετέτρεψε δύο από τις στήλες σε δεκαδικούς αριθμούς για να προσαρμόσει τα `NaN`;)\n", + "(Παρατηρήσατε ότι το pandas ανέβασε δύο από τις στήλες σε τύπο float για να φιλοξενήσει τα `NaN`;)\n", "\n", - "Δεν μπορείτε να διαγράψετε μία μόνο τιμή από ένα `DataFrame`, οπότε πρέπει να διαγράψετε ολόκληρες γραμμές ή στήλες. Ανάλογα με το τι κάνετε, μπορεί να θέλετε να επιλέξετε τη μία ή την άλλη επιλογή, και έτσι το pandas σας δίνει δυνατότητες και για τις δύο. Επειδή στην επιστήμη δεδομένων οι στήλες γενικά αντιπροσωπεύουν μεταβλητές και οι γραμμές αντιπροσωπεύουν παρατηρήσεις, είναι πιο πιθανό να διαγράψετε γραμμές δεδομένων. Η προεπιλεγμένη ρύθμιση για το `dropna()` είναι να διαγράφει όλες τις γραμμές που περιέχουν οποιεσδήποτε κενές τιμές:\n" + "Δεν μπορείτε να αφαιρέσετε μία μόνο τιμή από ένα `DataFrame`, οπότε πρέπει να αφαιρέσετε ολόκληρες γραμμές ή στήλες. Ανάλογα με το τι κάνετε, μπορεί να θέλετε να κάνετε το ένα ή το άλλο, και έτσι το pandas σας δίνει επιλογές και για τα δύο. Επειδή στην επιστήμη δεδομένων οι στήλες γενικά αντιπροσωπεύουν μεταβλητές και οι γραμμές αντιπροσωπεύουν παρατηρήσεις, είναι πιο πιθανό να αφαιρέσετε γραμμές δεδομένων. Η προεπιλεγμένη ρύθμιση για το `dropna()` είναι να αφαιρεί όλες τις γραμμές που περιέχουν οποιεσδήποτε κενές τιμές:\n" ] }, { @@ -1362,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Λάβετε υπόψη ότι αυτό μπορεί να αφαιρέσει πολλά δεδομένα που ίσως θέλετε να διατηρήσετε, ιδιαίτερα σε μικρότερα σύνολα δεδομένων. Τι γίνεται αν θέλετε απλώς να αφαιρέσετε γραμμές ή στήλες που περιέχουν αρκετές ή ακόμα και όλες τις τιμές null; Μπορείτε να ορίσετε αυτές τις ρυθμίσεις στο `dropna` με τις παραμέτρους `how` και `thresh`.\n", + "Σημειώστε ότι αυτό μπορεί να αφαιρέσει πολλά δεδομένα που ίσως θέλετε να διατηρήσετε, ιδιαίτερα σε μικρότερα σύνολα δεδομένων. Τι γίνεται αν θέλετε απλώς να αφαιρέσετε γραμμές ή στήλες που περιέχουν αρκετές ή ακόμα και όλες τις τιμές null; Μπορείτε να ορίσετε αυτές τις ρυθμίσεις στο `dropna` με τις παραμέτρους `how` και `thresh`.\n", "\n", - "Από προεπιλογή, `how='any'` (αν θέλετε να το ελέγξετε μόνοι σας ή να δείτε ποιες άλλες παραμέτρους έχει η μέθοδος, εκτελέστε `example4.dropna?` σε ένα κελί κώδικα). Εναλλακτικά, μπορείτε να ορίσετε `how='all'` ώστε να αφαιρέσετε μόνο γραμμές ή στήλες που περιέχουν όλες τις τιμές null. Ας επεκτείνουμε το παράδειγμα `DataFrame` για να δούμε αυτό σε δράση στην επόμενη άσκηση.\n" + "Από προεπιλογή, `how='any'` (αν θέλετε να το ελέγξετε μόνοι σας ή να δείτε ποιες άλλες παραμέτρους έχει η μέθοδος, εκτελέστε `example4.dropna?` σε ένα κελί κώδικα). Εναλλακτικά, μπορείτε να ορίσετε `how='all'` ώστε να αφαιρέσετε μόνο γραμμές ή στήλες που περιέχουν όλες τις τιμές null. Ας επεκτείνουμε το παράδειγμα `DataFrame` για να δούμε αυτό στην πράξη στην επόμενη άσκηση.\n" ] }, { @@ -1456,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> Βασικά σημεία: \n", - "1. Η αφαίρεση των κενών τιμών είναι καλή ιδέα μόνο αν το σύνολο δεδομένων είναι αρκετά μεγάλο. \n", - "2. Πλήρεις γραμμές ή στήλες μπορούν να αφαιρεθούν αν λείπουν τα περισσότερα δεδομένα τους. \n", - "3. Η μέθοδος `DataFrame.dropna(axis=)` βοηθά στην αφαίρεση των κενών τιμών. Το όρισμα `axis` υποδεικνύει αν θα αφαιρεθούν γραμμές ή στήλες. \n", - "4. Το όρισμα `how` μπορεί επίσης να χρησιμοποιηθεί. Από προεπιλογή είναι ρυθμισμένο στο `any`. Έτσι, αφαιρεί μόνο εκείνες τις γραμμές/στήλες που περιέχουν οποιαδήποτε κενή τιμή. Μπορεί να ρυθμιστεί στο `all` για να καθορίσει ότι θα αφαιρέσουμε μόνο εκείνες τις γραμμές/στήλες όπου όλες οι τιμές είναι κενές. \n" + "> Βασικά σημεία:\n", + "1. Η αφαίρεση κενών τιμών είναι καλή ιδέα μόνο αν το σύνολο δεδομένων είναι αρκετά μεγάλο.\n", + "2. Πλήρεις γραμμές ή στήλες μπορούν να αφαιρεθούν αν λείπουν τα περισσότερα δεδομένα τους.\n", + "3. Η μέθοδος `DataFrame.dropna(axis=)` βοηθά στην αφαίρεση κενών τιμών. Το όρισμα `axis` υποδεικνύει αν θα αφαιρεθούν γραμμές ή στήλες.\n", + "4. Μπορεί επίσης να χρησιμοποιηθεί το όρισμα `how`. Από προεπιλογή είναι ρυθμισμένο στο `any`. Έτσι, αφαιρεί μόνο εκείνες τις γραμμές/στήλες που περιέχουν οποιαδήποτε κενή τιμή. Μπορεί να ρυθμιστεί στο `all` για να καθορίσει ότι θα αφαιρέσουμε μόνο εκείνες τις γραμμές/στήλες όπου όλες οι τιμές είναι κενές.\n" ] }, { @@ -1580,7 +1580,7 @@ "\n", "Μερικές φορές έχει νόημα να συμπληρώσουμε τις ελλείπουσες τιμές με τιμές που θα μπορούσαν να είναι έγκυρες. Υπάρχουν μερικές τεχνικές για τη συμπλήρωση κενών τιμών. Η πρώτη είναι η χρήση Γνώσης του Τομέα (γνώση του αντικειμένου στο οποίο βασίζεται το σύνολο δεδομένων) για να προσεγγίσουμε με κάποιο τρόπο τις ελλείπουσες τιμές.\n", "\n", - "Μπορείτε να χρησιμοποιήσετε το `isnull` για να το κάνετε αυτό απευθείας, αλλά αυτό μπορεί να είναι κουραστικό, ιδιαίτερα αν έχετε πολλές τιμές να συμπληρώσετε. Επειδή αυτή είναι μια τόσο συνηθισμένη εργασία στην επιστήμη δεδομένων, η pandas παρέχει τη μέθοδο `fillna`, η οποία επιστρέφει ένα αντίγραφο του `Series` ή του `DataFrame` με τις ελλείπουσες τιμές να αντικαθίστανται από μια τιμή της επιλογής σας. Ας δημιουργήσουμε ένα άλλο παράδειγμα `Series` για να δούμε πώς λειτουργεί αυτό στην πράξη.\n" + "Μπορείτε να χρησιμοποιήσετε το `isnull` για να το κάνετε αυτό απευθείας, αλλά αυτό μπορεί να είναι κουραστικό, ειδικά αν έχετε πολλές τιμές να συμπληρώσετε. Επειδή αυτή είναι μια τόσο συνηθισμένη εργασία στην επιστήμη δεδομένων, το pandas παρέχει τη μέθοδο `fillna`, η οποία επιστρέφει ένα αντίγραφο του `Series` ή του `DataFrame` με τις ελλείπουσες τιμές αντικαταστημένες με μία της επιλογής σας. Ας δημιουργήσουμε ένα άλλο παράδειγμα `Series` για να δούμε πώς λειτουργεί αυτό στην πράξη.\n" ] }, { @@ -1589,12 +1589,12 @@ "id": "CE8S7louLezV" }, "source": [ - "### Κατηγορικά Δεδομένα (Μη Αριθμητικά)\n", - "Ας εξετάσουμε πρώτα τα μη αριθμητικά δεδομένα. Στα σύνολα δεδομένων, έχουμε στήλες με κατηγορικά δεδομένα. Π.χ. Φύλο, Αληθές ή Ψευδές κ.λπ.\n", + "### Κατηγορικά Δεδομένα (Μη αριθμητικά)\n", + "Ας εξετάσουμε πρώτα τα μη αριθμητικά δεδομένα. Στα σύνολα δεδομένων, υπάρχουν στήλες με κατηγορικά δεδομένα, π.χ. Φύλο, Αληθές ή Ψευδές κ.λπ.\n", "\n", - "Στις περισσότερες από αυτές τις περιπτώσεις, αντικαθιστούμε τις ελλείπουσες τιμές με τη `συχνότερη τιμή` (mode) της στήλης. Για παράδειγμα, αν έχουμε 100 σημεία δεδομένων και τα 90 έχουν δηλώσει Αληθές, τα 8 έχουν δηλώσει Ψευδές και τα 2 δεν έχουν συμπληρωθεί, τότε μπορούμε να συμπληρώσουμε τα 2 με Αληθές, λαμβάνοντας υπόψη ολόκληρη τη στήλη.\n", + "Στις περισσότερες από αυτές τις περιπτώσεις, αντικαθιστούμε τις ελλείπουσες τιμές με τη `mode` της στήλης. Για παράδειγμα, αν έχουμε 100 σημεία δεδομένων και 90 έχουν δηλώσει Αληθές, 8 έχουν δηλώσει Ψευδές και 2 δεν έχουν συμπληρώσει, τότε μπορούμε να συμπληρώσουμε τα 2 με Αληθές, λαμβάνοντας υπόψη ολόκληρη τη στήλη.\n", "\n", - "Εδώ, μπορούμε επίσης να χρησιμοποιήσουμε τη γνώση του πεδίου. Ας εξετάσουμε ένα παράδειγμα συμπλήρωσης με τη συχνότερη τιμή.\n" + "Εδώ μπορούμε επίσης να χρησιμοποιήσουμε τη γνώση του πεδίου. Ας εξετάσουμε ένα παράδειγμα συμπλήρωσης με τη mode.\n" ] }, { @@ -1699,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Τώρα, ας βρούμε πρώτα τη διάμεσο πριν συμπληρώσουμε την τιμή `None` με τη διάμεσο.\n" + ] }, { "cell_type": "code", @@ -1734,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Λοιπόν, θα αντικαταστήσουμε το None με True\n" + ] }, { "cell_type": "code", @@ -1844,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Όπως μπορούμε να δούμε, η τιμή null έχει αντικατασταθεί. Περιττό να πούμε ότι θα μπορούσαμε να είχαμε γράψει οτιδήποτε στη θέση του ή `'True'` και θα είχε αντικατασταθεί.\n" + "Όπως μπορούμε να δούμε, η τιμή null έχει αντικατασταθεί. Περιττό να πούμε ότι θα μπορούσαμε να είχαμε γράψει οτιδήποτε στη θέση του `'True'` και θα είχε αντικατασταθεί.\n" ] }, { @@ -1854,12 +1858,12 @@ }, "source": [ "### Αριθμητικά Δεδομένα\n", - "Τώρα, ας μιλήσουμε για αριθμητικά δεδομένα. Εδώ, έχουμε δύο κοινές μεθόδους αντικατάστασης των ελλειπόντων τιμών:\n", + "Τώρα, ας μιλήσουμε για τα αριθμητικά δεδομένα. Εδώ, έχουμε δύο κοινές μεθόδους για την αντικατάσταση των ελλειπόντων τιμών:\n", "\n", "1. Αντικατάσταση με τη Διάμεσο της γραμμής\n", "2. Αντικατάσταση με τον Μέσο Όρο της γραμμής\n", "\n", - "Αντικαθιστούμε με τη Διάμεσο, σε περίπτωση δεδομένων με ασυμμετρία και ακραίες τιμές. Αυτό συμβαίνει επειδή η διάμεσος είναι ανθεκτική στις ακραίες τιμές.\n", + "Αντικαθιστούμε με τη Διάμεσο σε περίπτωση δεδομένων με ασυμμετρία και ακραίες τιμές. Αυτό συμβαίνει επειδή η διάμεσος είναι ανθεκτική στις ακραίες τιμές.\n", "\n", "Όταν τα δεδομένα είναι κανονικοποιημένα, μπορούμε να χρησιμοποιήσουμε τον μέσο όρο, καθώς σε αυτή την περίπτωση, ο μέσος όρος και η διάμεσος θα είναι αρκετά κοντά.\n", "\n", @@ -2003,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Συμπλήρωση με μέσο όρο\n" + ] }, { "cell_type": "code", @@ -2252,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Συμπλήρωση με διάμεσο\n" + ] }, { "cell_type": "code", @@ -2437,9 +2445,9 @@ "source": [ "> Βασικά σημεία:\n", "1. Η συμπλήρωση των ελλειπόντων τιμών πρέπει να γίνεται είτε όταν υπάρχουν λίγα δεδομένα είτε όταν υπάρχει στρατηγική για τη συμπλήρωση των ελλειπόντων δεδομένων.\n", - "2. Η γνώση του πεδίου μπορεί να χρησιμοποιηθεί για τη συμπλήρωση των ελλειπόντων τιμών μέσω προσέγγισης.\n", - "3. Για κατηγορικά δεδομένα, συνήθως οι ελλείπουσες τιμές αντικαθίστανται με τη συχνότερη τιμή της στήλης.\n", - "4. Για αριθμητικά δεδομένα, οι ελλείπουσες τιμές συνήθως συμπληρώνονται με τον μέσο όρο (για κανονικοποιημένα σύνολα δεδομένων) ή τη διάμεσο των στηλών.\n" + "2. Η γνώση του πεδίου μπορεί να χρησιμοποιηθεί για τη συμπλήρωση ελλειπόντων τιμών μέσω προσέγγισης.\n", + "3. Για κατηγορικά δεδομένα, συνήθως οι ελλείπουσες τιμές αντικαθίστανται με τη συχνότερη τιμή της στήλης (mode).\n", + "4. Για αριθμητικά δεδομένα, οι ελλείπουσες τιμές συνήθως συμπληρώνονται με τον μέσο όρο (για κανονικοποιημένα σύνολα δεδομένων) ή τη διάμεσο της στήλης.\n" ] }, { @@ -2470,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "Μπορείτε να **προωθήσετε την πλήρωση** κενών τιμών, δηλαδή να χρησιμοποιήσετε την τελευταία έγκυρη τιμή για να γεμίσετε ένα κενό:\n" + "Μπορείτε να **συμπληρώσετε προς τα εμπρός** τις κενές τιμές, δηλαδή να χρησιμοποιήσετε την τελευταία έγκυρη τιμή για να συμπληρώσετε μια κενή:\n" ] }, { @@ -2726,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Λάβετε υπόψη ότι όταν μια προηγούμενη τιμή δεν είναι διαθέσιμη για συμπλήρωση προς τα εμπρός, η μηδενική τιμή παραμένει.\n" + "Παρατηρήστε ότι όταν δεν υπάρχει προηγούμενη τιμή για συμπλήρωση προς τα εμπρός, η τιμή null παραμένει.\n" ] }, { @@ -2850,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Σημειώστε ότι η στήλη 3 παραμένει ακόμα χωρίς τιμές: η προεπιλεγμένη κατεύθυνση είναι να γεμίζονται οι τιμές κατά σειρά γραμμών.\n", + "Παρατηρήστε ότι η στήλη 3 εξακολουθεί να είναι χωρίς τιμές: η προεπιλεγμένη κατεύθυνση είναι να γεμίζονται οι τιμές κατά γραμμές.\n", "\n", - "> **Συμπέρασμα:** Υπάρχουν πολλοί τρόποι για να αντιμετωπίσετε τις ελλιπείς τιμές στα σύνολα δεδομένων σας. Η συγκεκριμένη στρατηγική που θα χρησιμοποιήσετε (να τις αφαιρέσετε, να τις αντικαταστήσετε ή ακόμα και πώς θα τις αντικαταστήσετε) θα πρέπει να καθορίζεται από τις ιδιαιτερότητες αυτών των δεδομένων. Θα αναπτύξετε καλύτερη αίσθηση για το πώς να διαχειρίζεστε τις ελλιπείς τιμές όσο περισσότερο ασχολείστε και αλληλεπιδράτε με σύνολα δεδομένων.\n" + "> **Συμπέρασμα:** Υπάρχουν πολλοί τρόποι για να αντιμετωπίσετε τις ελλείπουσες τιμές στα σύνολα δεδομένων σας. Η συγκεκριμένη στρατηγική που θα χρησιμοποιήσετε (αφαίρεση, αντικατάσταση ή ακόμα και ο τρόπος αντικατάστασης) θα πρέπει να καθορίζεται από τις ιδιαιτερότητες αυτών των δεδομένων. Θα αναπτύξετε καλύτερη αίσθηση για το πώς να χειρίζεστε τις ελλείπουσες τιμές όσο περισσότερο ασχολείστε και αλληλεπιδράτε με σύνολα δεδομένων.\n" ] }, { @@ -2876,7 +2884,7 @@ "source": [ "**ΚΩΔΙΚΟΠΟΙΗΣΗ ΕΤΙΚΕΤΩΝ**\n", "\n", - "Η κωδικοποίηση ετικετών ουσιαστικά μετατρέπει κάθε κατηγορία σε έναν αριθμό. Για παράδειγμα, ας υποθέσουμε ότι έχουμε ένα σύνολο δεδομένων με επιβάτες αεροπορικών εταιρειών και υπάρχει μια στήλη που περιέχει την κατηγορία θέσης τους ανάμεσα στις εξής ['business class', 'economy class', 'first class']. Εάν εφαρμοστεί κωδικοποίηση ετικετών σε αυτό, θα μετατραπεί σε [0,1,2]. Ας δούμε ένα παράδειγμα μέσω κώδικα. Καθώς θα μάθουμε το `scikit-learn` στα επόμενα σημειωματάρια, δεν θα το χρησιμοποιήσουμε εδώ.\n" + "Η κωδικοποίηση ετικετών είναι ουσιαστικά η μετατροπή κάθε κατηγορίας σε έναν αριθμό. Για παράδειγμα, ας πούμε ότι έχουμε ένα σύνολο δεδομένων με επιβάτες αεροπορικών εταιρειών και υπάρχει μια στήλη που περιέχει την κατηγορία τους ανάμεσα στις εξής ['business class', 'economy class', 'first class']. Εάν γίνει κωδικοποίηση ετικετών σε αυτό, θα μετατραπεί σε [0,1,2]. Ας δούμε ένα παράδειγμα μέσω κώδικα. Καθώς θα μάθουμε το `scikit-learn` στα επόμενα σημειωματάρια, δεν θα το χρησιμοποιήσουμε εδώ.\n" ] }, { @@ -2984,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Για να εκτελέσουμε την κωδικοποίηση ετικετών στην 1η στήλη, πρέπει πρώτα να περιγράψουμε έναν αντιστοιχισμό από κάθε κατηγορία σε έναν αριθμό, πριν την αντικατάσταση\n" + "Για να εκτελέσουμε κωδικοποίηση ετικετών στην 1η στήλη, πρέπει πρώτα να περιγράψουμε μια αντιστοίχιση από κάθε κατηγορία σε έναν αριθμό, πριν την αντικατάσταση\n" ] }, { @@ -3099,9 +3107,9 @@ "source": [ "**ΚΩΔΙΚΟΠΟΙΗΣΗ ONE HOT**\n", "\n", - "Ένας άλλος τύπος κωδικοποίησης είναι η Κωδικοποίηση One Hot. Σε αυτόν τον τύπο κωδικοποίησης, κάθε κατηγορία της στήλης προστίθεται ως ξεχωριστή στήλη και κάθε δεδομένο λαμβάνει 0 ή 1 ανάλογα με το αν περιέχει αυτήν την κατηγορία. Έτσι, αν υπάρχουν n διαφορετικές κατηγορίες, n στήλες θα προστεθούν στο dataframe.\n", + "Ένας άλλος τύπος κωδικοποίησης είναι η Κωδικοποίηση One Hot. Σε αυτόν τον τύπο κωδικοποίησης, κάθε κατηγορία της στήλης προστίθεται ως ξεχωριστή στήλη και κάθε δεδομένο λαμβάνει τιμή 0 ή 1 ανάλογα με το αν περιέχει αυτήν την κατηγορία. Έτσι, αν υπάρχουν n διαφορετικές κατηγορίες, n στήλες θα προστεθούν στο dataframe.\n", "\n", - "Για παράδειγμα, ας πάρουμε το ίδιο παράδειγμα με τις κατηγορίες θέσεων αεροπλάνου. Οι κατηγορίες ήταν: ['business class', 'economy class', 'first class']. Επομένως, αν εφαρμόσουμε κωδικοποίηση one hot, οι εξής τρεις στήλες θα προστεθούν στο σύνολο δεδομένων: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Για παράδειγμα, ας πάρουμε το ίδιο παράδειγμα με τις κατηγορίες αεροπλάνου. Οι κατηγορίες ήταν: ['business class', 'economy class', 'first class']. Επομένως, αν εφαρμόσουμε την κωδικοποίηση one hot, οι εξής τρεις στήλες θα προστεθούν στο dataset: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3345,7 +3353,7 @@ "source": [ "Πότε χρησιμοποιούμε το one hot encoding; Το one hot encoding χρησιμοποιείται σε μία ή και στις δύο από τις παρακάτω περιπτώσεις:\n", "\n", - "1. Όταν ο αριθμός των κατηγοριών και το μέγεθος του dataset είναι μικρότερα.\n", + "1. Όταν ο αριθμός των κατηγοριών και το μέγεθος του συνόλου δεδομένων είναι μικρότερο.\n", "2. Όταν οι κατηγορίες δεν ακολουθούν κάποια συγκεκριμένη σειρά.\n" ] }, @@ -3366,11 +3374,11 @@ "id": "K8UXOJYRgRsJ" }, "source": [ - "## Αφαίρεση διπλότυπων δεδομένων\n", + "## Αφαίρεση διπλών δεδομένων\n", "\n", - "> **Στόχος μάθησης:** Μέχρι το τέλος αυτής της υποενότητας, θα πρέπει να αισθάνεστε άνετα να εντοπίζετε και να αφαιρείτε διπλότυπες τιμές από DataFrames.\n", + "> **Στόχος μάθησης:** Μέχρι το τέλος αυτής της υποενότητας, θα πρέπει να είστε εξοικειωμένοι με την αναγνώριση και την αφαίρεση διπλών τιμών από DataFrames.\n", "\n", - "Εκτός από τα ελλιπή δεδομένα, συχνά θα συναντήσετε διπλότυπα δεδομένα σε σύνολα δεδομένων του πραγματικού κόσμου. Ευτυχώς, η βιβλιοθήκη pandas παρέχει έναν εύκολο τρόπο για την ανίχνευση και την αφαίρεση διπλότυπων εγγραφών.\n" + "Εκτός από τα ελλιπή δεδομένα, συχνά θα συναντήσετε διπλά δεδομένα σε σύνολα δεδομένων πραγματικού κόσμου. Ευτυχώς, το pandas παρέχει έναν εύκολο τρόπο για την ανίχνευση και την αφαίρεση διπλών εγγραφών.\n" ] }, { @@ -3381,7 +3389,7 @@ "source": [ "### Εντοπισμός διπλότυπων: `duplicated`\n", "\n", - "Μπορείτε εύκολα να εντοπίσετε διπλότυπες τιμές χρησιμοποιώντας τη μέθοδο `duplicated` στο pandas, η οποία επιστρέφει μια μάσκα Boolean που δείχνει αν μια εγγραφή σε ένα `DataFrame` είναι διπλότυπη με κάποια προηγούμενη. Ας δημιουργήσουμε ένα άλλο παράδειγμα `DataFrame` για να δούμε πώς λειτουργεί αυτό στην πράξη.\n" + "Μπορείτε εύκολα να εντοπίσετε διπλότυπες τιμές χρησιμοποιώντας τη μέθοδο `duplicated` στο pandas, η οποία επιστρέφει μια μάσκα Boolean που δείχνει αν μια εγγραφή σε ένα `DataFrame` είναι διπλότυπη με κάποια προηγούμενη. Ας δημιουργήσουμε ένα άλλο παράδειγμα `DataFrame` για να το δούμε αυτό στην πράξη.\n" ] }, { @@ -3594,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Τόσο η `duplicated` όσο και η `drop_duplicates` από προεπιλογή εξετάζουν όλες τις στήλες, αλλά μπορείτε να καθορίσετε ότι εξετάζουν μόνο ένα υποσύνολο στηλών στο `DataFrame` σας:\n" + "Τόσο οι `duplicated` όσο και οι `drop_duplicates` από προεπιλογή λαμβάνουν υπόψη όλες τις στήλες, αλλά μπορείτε να καθορίσετε ότι εξετάζουν μόνο ένα υποσύνολο στηλών στο `DataFrame` σας:\n" ] }, { @@ -3670,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Συμπέρασμα:** Η αφαίρεση διπλότυπων δεδομένων είναι ένα απαραίτητο μέρος σχεδόν κάθε έργου επιστήμης δεδομένων. Τα διπλότυπα δεδομένα μπορούν να αλλάξουν τα αποτελέσματα των αναλύσεών σας και να σας δώσουν ανακριβή αποτελέσματα!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Έλεγχοι Ποιότητας Δεδομένων στον Πραγματικό Κόσμο\n", + "\n", + "> **Στόχος μάθησης:** Μέχρι το τέλος αυτής της ενότητας, θα πρέπει να είστε εξοικειωμένοι με την ανίχνευση και διόρθωση κοινών προβλημάτων ποιότητας δεδομένων στον πραγματικό κόσμο, όπως ασυνεπείς κατηγοριακές τιμές, μη φυσιολογικές αριθμητικές τιμές (ακραίες τιμές) και διπλότυπες οντότητες με παραλλαγές.\n", + "\n", + "Ενώ οι ελλείπουσες τιμές και τα ακριβή διπλότυπα είναι συνηθισμένα προβλήματα, τα σύνολα δεδομένων στον πραγματικό κόσμο συχνά περιέχουν πιο λεπτές δυσκολίες:\n", + "\n", + "1. **Ασυνεπείς κατηγοριακές τιμές**: Η ίδια κατηγορία γραμμένη διαφορετικά (π.χ., \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Μη φυσιολογικές αριθμητικές τιμές**: Ακραίες τιμές που υποδεικνύουν σφάλματα καταχώρησης δεδομένων (π.χ., ηλικία = 999)\n", + "3. **Σχεδόν διπλότυπες γραμμές**: Εγγραφές που αντιπροσωπεύουν την ίδια οντότητα με μικρές παραλλαγές\n", + "\n", + "Ας εξερευνήσουμε τεχνικές για την ανίχνευση και αντιμετώπιση αυτών των προβλημάτων.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Δημιουργία ενός Δείγματος \"Μη Καθαρού\" Συνόλου Δεδομένων\n", + "\n", + "Αρχικά, ας δημιουργήσουμε ένα δείγμα συνόλου δεδομένων που περιέχει τους τύπους προβλημάτων που συναντάμε συχνά σε δεδομένα πραγματικού κόσμου:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Εντοπισμός Ασυνεπών Τιμών Κατηγορίας\n", + "\n", + "Παρατηρήστε ότι η στήλη `country` έχει πολλαπλές αναπαραστάσεις για τις ίδιες χώρες. Ας εντοπίσουμε αυτές τις ασυνέπειες:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Τυποποίηση Κατηγορικών Τιμών\n", + "\n", + "Μπορούμε να δημιουργήσουμε έναν χάρτη για να τυποποιήσουμε αυτές τις τιμές. Μια απλή προσέγγιση είναι να μετατρέψουμε σε πεζά και να δημιουργήσουμε ένα λεξικό αντιστοίχισης:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Εναλλακτική: Χρήση Ασαφούς Αντιστοίχισης**\n", + "\n", + "Για πιο σύνθετες περιπτώσεις, μπορούμε να χρησιμοποιήσουμε την ασαφή αντιστοίχιση συμβολοσειρών με τη βιβλιοθήκη `rapidfuzz` για να εντοπίσουμε αυτόματα παρόμοιες συμβολοσειρές:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Εντοπισμός Αφύσικων Αριθμητικών Τιμών (Ακραίες Τιμές)\n", + "\n", + "Κοιτάζοντας τη στήλη `age`, παρατηρούμε κάποιες ύποπτες τιμές όπως 199 και -5. Ας χρησιμοποιήσουμε στατιστικές μεθόδους για να εντοπίσουμε αυτές τις ακραίες τιμές.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Χρήση της Μεθόδου IQR (Ενδοτεταρτημοριακό Εύρος)\n", + "\n", + "Η μέθοδος IQR είναι μια αξιόπιστη στατιστική τεχνική για την ανίχνευση ακραίων τιμών, η οποία είναι λιγότερο ευαίσθητη σε ακραίες τιμές:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Χρήση της Μεθόδου Z-Score\n", + "\n", + "Η μέθοδος Z-score εντοπίζει τις ακραίες τιμές με βάση τις τυπικές αποκλίσεις από τον μέσο όρο:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Διαχείριση Ακραίων Τιμών\n", + "\n", + "Μόλις εντοπιστούν, οι ακραίες τιμές μπορούν να διαχειριστούν με διάφορους τρόπους:\n", + "1. **Αφαίρεση**: Διαγραφή γραμμών με ακραίες τιμές (αν πρόκειται για σφάλματα)\n", + "2. **Περιορισμός**: Αντικατάσταση με οριακές τιμές\n", + "3. **Αντικατάσταση με NaN**: Θεώρηση ως ελλιπή δεδομένα και χρήση τεχνικών συμπλήρωσης\n", + "4. **Διατήρηση**: Αν είναι νόμιμες ακραίες τιμές\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Εντοπισμός Σχεδόν Διπλότυπων Γραμμών\n", + "\n", + "Παρατηρήστε ότι το σύνολο δεδομένων μας έχει πολλαπλές εγγραφές για τον \"John Smith\" με ελαφρώς διαφορετικές τιμές. Ας εντοπίσουμε πιθανά διπλότυπα με βάση την ομοιότητα των ονομάτων.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Εύρεση Σχεδόν Διπλότυπων με Ασαφή Αντιστοίχιση\n", + "\n", + "Για πιο εξελιγμένη ανίχνευση διπλότυπων, μπορούμε να χρησιμοποιήσουμε την ασαφή αντιστοίχιση για να βρούμε παρόμοια ονόματα:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Διαχείριση Διπλότυπων\n", + "\n", + "Αφού εντοπιστούν, πρέπει να αποφασίσετε πώς να διαχειριστείτε τα διπλότυπα:\n", + "1. **Διατήρηση της πρώτης εμφάνισης**: Χρησιμοποιήστε `drop_duplicates(keep='first')`\n", + "2. **Διατήρηση της τελευταίας εμφάνισης**: Χρησιμοποιήστε `drop_duplicates(keep='last')`\n", + "3. **Συγκέντρωση πληροφοριών**: Συνδυάστε πληροφορίες από διπλότυπες γραμμές\n", + "4. **Χειροκίνητη ανασκόπηση**: Σημειώστε για ανθρώπινη ανασκόπηση\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Περίληψη: Ολοκληρωμένη Διαδικασία Καθαρισμού Δεδομένων\n", + "\n", + "Ας τα συνδυάσουμε όλα σε μια ολοκληρωμένη διαδικασία καθαρισμού:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Άσκηση Πρόκλησης\n", + "\n", + "Τώρα είναι η σειρά σου! Παρακάτω υπάρχει μια νέα γραμμή δεδομένων με πολλαπλά προβλήματα ποιότητας. Μπορείς:\n", + "\n", + "1. Να εντοπίσεις όλα τα προβλήματα σε αυτή τη γραμμή\n", + "2. Να γράψεις κώδικα για να διορθώσεις κάθε πρόβλημα\n", + "3. Να προσθέσεις τη διορθωμένη γραμμή στο σύνολο δεδομένων\n", + "\n", + "Εδώ είναι τα προβληματικά δεδομένα:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Βασικά Σημεία\n", + "\n", + "1. **Ασυνεπείς κατηγορίες** είναι συχνές σε δεδομένα του πραγματικού κόσμου. Ελέγξτε πάντα τις μοναδικές τιμές και τυποποιήστε τις χρησιμοποιώντας αντιστοιχίσεις ή μεθόδους ασαφούς αντιστοίχισης.\n", + "\n", + "2. **Ακραίες τιμές** μπορούν να επηρεάσουν σημαντικά την ανάλυσή σας. Χρησιμοποιήστε γνώση του πεδίου σε συνδυασμό με στατιστικές μεθόδους (IQR, Z-score) για να τις εντοπίσετε.\n", + "\n", + "3. **Σχεδόν διπλότυπα** είναι πιο δύσκολο να εντοπιστούν από τα ακριβή διπλότυπα. Σκεφτείτε να χρησιμοποιήσετε ασαφή αντιστοίχιση και να κανονικοποιήσετε τα δεδομένα (μετατροπή σε πεζά, αφαίρεση κενών) για να τα αναγνωρίσετε.\n", + "\n", + "4. **Ο καθαρισμός δεδομένων είναι επαναληπτικός**. Ίσως χρειαστεί να εφαρμόσετε πολλαπλές τεχνικές και να αναθεωρήσετε τα αποτελέσματα πριν ολοκληρώσετε το καθαρισμένο σύνολο δεδομένων.\n", + "\n", + "5. **Καταγράψτε τις αποφάσεις σας**. Κρατήστε σημειώσεις για τα βήματα καθαρισμού που εφαρμόσατε και τους λόγους, καθώς αυτό είναι σημαντικό για την αναπαραγωγιμότητα και τη διαφάνεια.\n", + "\n", + "> **Καλύτερη Πρακτική:** Πάντα να κρατάτε ένα αντίγραφο των αρχικών \"ακαθάριστων\" δεδομένων σας. Μην αντικαθιστάτε ποτέ τα αρχεία πηγής σας - δημιουργήστε καθαρισμένες εκδόσεις με σαφείς ονομασίες, όπως `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Αποποίηση ευθύνης**: \nΑυτό το έγγραφο έχει μεταφραστεί χρησιμοποιώντας την υπηρεσία αυτόματης μετάφρασης [Co-op Translator](https://github.com/Azure/co-op-translator). Παρόλο που καταβάλλουμε προσπάθειες για ακρίβεια, παρακαλούμε να έχετε υπόψη ότι οι αυτοματοποιημένες μεταφράσεις ενδέχεται να περιέχουν λάθη ή ανακρίβειες. Το πρωτότυπο έγγραφο στη μητρική του γλώσσα θα πρέπει να θεωρείται η αυθεντική πηγή. Για κρίσιμες πληροφορίες, συνιστάται επαγγελματική ανθρώπινη μετάφραση. Δεν φέρουμε ευθύνη για τυχόν παρεξηγήσεις ή εσφαλμένες ερμηνείες που προκύπτουν από τη χρήση αυτής της μετάφρασης.\n" + "\n---\n\n**Αποποίηση ευθύνης**: \nΑυτό το έγγραφο έχει μεταφραστεί χρησιμοποιώντας την υπηρεσία αυτόματης μετάφρασης [Co-op Translator](https://github.com/Azure/co-op-translator). Παρόλο που καταβάλλουμε προσπάθειες για ακρίβεια, παρακαλούμε να έχετε υπόψη ότι οι αυτόματες μεταφράσεις ενδέχεται να περιέχουν λάθη ή ανακρίβειες. Το πρωτότυπο έγγραφο στη μητρική του γλώσσα θα πρέπει να θεωρείται η αυθεντική πηγή. Για κρίσιμες πληροφορίες, συνιστάται επαγγελματική ανθρώπινη μετάφραση. Δεν φέρουμε ευθύνη για τυχόν παρεξηγήσεις ή εσφαλμένες ερμηνείες που προκύπτουν από τη χρήση αυτής της μετάφρασης.\n" ] } ], @@ -3704,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:35:28+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:10:10+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "el" } diff --git a/translations/en/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/en/2-Working-With-Data/08-data-preparation/notebook.ipynb index a2e90449..a04e1659 100644 --- a/translations/en/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/en/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -12,9 +12,9 @@ "\n", "## Exploring `DataFrame` information\n", "\n", - "> **Learning goal:** By the end of this subsection, you should feel confident in finding general information about the data stored in pandas DataFrames.\n", + "> **Learning goal:** By the end of this subsection, you should be comfortable finding general information about the data stored in pandas DataFrames.\n", "\n", - "Once your data is loaded into pandas, it will most likely be in a `DataFrame`. But if your `DataFrame` contains 60,000 rows and 400 columns, where do you even start to understand what you're working with? Luckily, pandas offers some handy tools to quickly get an overview of a `DataFrame` as well as a glimpse of its first and last few rows.\n", + "Once you have loaded your data into pandas, it will most likely be in a `DataFrame`. But if the dataset in your `DataFrame` contains 60,000 rows and 400 columns, how do you even start to understand what you're working with? Fortunately, pandas offers some handy tools to quickly get an overview of a `DataFrame`, as well as to examine the first few and last few rows.\n", "\n", "To explore this functionality, we will import the Python scikit-learn library and use a classic dataset that every data scientist has encountered countless times: British biologist Ronald Fisher's *Iris* dataset, featured in his 1936 paper \"The use of multiple measurements in taxonomic problems\":\n" ] @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "We have loaded the Iris Dataset into the variable `iris_df`. Before exploring the data, it’s helpful to know how many data points we have and the overall dimensions of the dataset. Understanding the size of the data can provide valuable context for analysis.\n" + "We have loaded the Iris Dataset into the variable `iris_df`. Before analyzing the data, it is helpful to know the number of data points and the overall size of the dataset. Understanding the volume of data we are working with is important.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "So, we are working with 150 rows and 4 columns of data. Each row corresponds to one data point, and each column represents a specific feature related to the data frame. Essentially, there are 150 data points, each with 4 features.\n", + "So, we are working with 150 rows and 4 columns of data. Each row corresponds to one data point, and each column represents a single feature associated with the data frame. Essentially, there are 150 data points, each containing 4 features.\n", "\n", - "`shape` in this context is an attribute of the dataframe, not a function, which is why it doesn't have parentheses at the end.\n" + "`shape` is an attribute of the dataframe, not a function, which is why it doesn't have parentheses at the end.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Now let's dive into the 4 columns of data. What does each of them actually represent? The `columns` attribute provides the names of the columns in the dataframe.\n" + "Now let's delve into the 4 columns of data. What does each of them specifically represent? The `columns` attribute will provide us with the names of the columns in the dataframe.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "The size of the dataset (provided by the `shape` attribute) and the names of the features or columns (provided by the `columns` attribute) give us some initial insights into the dataset. Next, we might want to explore the dataset in more detail. The `DataFrame.info()` function is very helpful for this purpose.\n" + "The size of the dataset (provided by the `shape` attribute) and the names of the features or columns (provided by the `columns` attribute) give us some initial insights into the dataset. Now, we might want to explore the dataset in more detail. The `DataFrame.info()` function is particularly helpful for this.\n" ] }, { @@ -181,8 +181,8 @@ }, "source": [ "From here, we can make a few observations:\n", - "1. The data type of each column: In this dataset, all the data is stored as 64-bit floating-point numbers.\n", - "2. Number of non-null values: Handling null values is a crucial step in data preparation. This will be addressed later in the notebook.\n" + "1. The DataType of each column: In this dataset, all the data is stored as 64-bit floating-point numbers.\n", + "2. Number of Non-Null values: Handling null values is a crucial step in data preparation. This will be addressed later in the notebook.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Imagine we have a dataset with plenty of numerical data. We can perform univariate statistical calculations like mean, median, quartiles, etc., on each column separately. The `DataFrame.describe()` function gives us a statistical summary of the numerical columns in the dataset.\n" + "Suppose we have a large amount of numerical data in our dataset. Univariate statistical calculations like mean, median, quartiles, etc., can be performed on each column individually. The `DataFrame.describe()` function gives us a statistical summary of the numerical columns in a dataset.\n" ] }, { @@ -332,7 +332,7 @@ }, "source": [ "### `DataFrame.head`\n", - "With all the functions and attributes mentioned earlier, we now have a high-level overview of the dataset. We know the total number of data points, the number of features, the data type of each feature, and the count of non-null values for each feature.\n", + "With all the functions and attributes mentioned above, we now have a high-level overview of the dataset. We know the total number of data points, the number of features, the data type of each feature, and the count of non-null values for each feature.\n", "\n", "Now it's time to examine the data itself. Let's take a look at the first few rows (the initial data points) of our `DataFrame`:\n" ] @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "As the output here, we can see five(5) entries of the dataset. If we look at the index at the left, we find out that these are the first five rows.\n" + "As the output here, we can see five (5) entries of the dataset. If we look at the index on the left, we find out that these are the first five rows.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Exercise:\n", "\n", - "From the example given above, it is clear that, by default, `DataFrame.head` returns the first five rows of a `DataFrame`. In the code cell below, can you figure out a way to display more than five rows?\n" + "From the example above, it's clear that by default, `DataFrame.head` returns the first five rows of a `DataFrame`. In the code cell below, can you find a way to display more than five rows?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Another way to view the data is from the end (instead of the beginning). The counterpart to `DataFrame.head` is `DataFrame.tail`, which retrieves the last five rows of a `DataFrame`:\n" + "Another way to view the data is from the end (instead of the beginning). The counterpart to `DataFrame.head` is `DataFrame.tail`, which returns the last five rows of a `DataFrame`:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "In practice, it is helpful to quickly inspect the first few rows or the last few rows of a `DataFrame`, especially when searching for anomalies in ordered datasets.\n", + "In practice, it is helpful to quickly inspect the first few rows or the last few rows of a `DataFrame`, especially when searching for outliers in ordered datasets.\n", "\n", - "All the functions and attributes demonstrated above through code examples assist in providing an overview of the data.\n", + "All the functions and attributes demonstrated above with code examples assist in providing an overview of the data.\n", "\n", - "> **Takeaway:** Simply examining the metadata of a DataFrame or the first and last few values can give you a quick understanding of the size, structure, and content of the data you are working with.\n" + "> **Takeaway:** Simply examining the metadata of a DataFrame or the first and last few rows can give you an instant understanding of the size, structure, and content of the data you're working with.\n" ] }, { @@ -596,17 +596,17 @@ }, "source": [ "### Missing Data\n", - "Let’s explore the concept of missing data. Missing data occurs when certain columns have no value stored.\n", + "Let's explore the concept of missing data. Missing data occurs when no value is stored in certain columns.\n", "\n", - "For example, imagine someone is very conscious about their weight and chooses not to fill out the weight field in a survey. In this case, the weight value for that individual will be missing.\n", + "For example, imagine someone is self-conscious about their weight and chooses not to fill out the weight field in a survey. In this case, the weight value for that individual will be missing.\n", "\n", "In real-world datasets, missing values are quite common.\n", "\n", "**How Pandas Handles Missing Data**\n", "\n", - "Pandas deals with missing values in two ways. The first method, which you’ve encountered in earlier sections, is `NaN` (Not a Number). This is a special value defined by the IEEE floating-point specification and is specifically used to represent missing floating-point values.\n", + "Pandas manages missing values in two ways. The first method, which you've encountered in earlier sections, is `NaN`, or Not a Number. This is a special value defined by the IEEE floating-point specification, and it is specifically used to represent missing floating-point values.\n", "\n", - "For missing values that are not floats, pandas uses Python’s `None` object. While it might seem confusing to encounter two different types of values that essentially indicate the same thing, there are solid programming reasons behind this design choice. In practice, this approach allows pandas to strike a good balance for most use cases. However, it’s important to note that both `None` and `NaN` come with certain limitations regarding how they can be used.\n" + "For missing values in data types other than floats, pandas uses Python's `None` object. While it might seem confusing to encounter two different types of values that essentially indicate the same thing, there are solid programmatic reasons behind this design choice. In practice, this approach allows pandas to strike a good balance for most use cases. However, it's important to note that both `None` and `NaN` come with certain limitations regarding how they can be utilized.\n" ] }, { @@ -616,7 +616,7 @@ }, "source": [ "### `None`: non-float missing data\n", - "Since `None` originates from Python, it cannot be used in NumPy and pandas arrays unless their data type is `'object'`. Keep in mind that NumPy arrays (and pandas data structures) are designed to hold only one type of data. This characteristic is what makes them incredibly powerful for handling large-scale data and performing computations, but it also restricts their flexibility. These arrays must convert to the \"lowest common denominator,\" which is the data type capable of accommodating all elements in the array. If `None` is present in the array, it indicates that you are working with Python objects.\n", + "Since `None` originates from Python, it cannot be used in NumPy and pandas arrays unless their data type is `'object'`. Keep in mind that NumPy arrays (and pandas data structures) are designed to hold only one type of data. This characteristic is what makes them incredibly powerful for handling large-scale data and performing computational tasks, but it also restricts their flexibility. These arrays must convert to the \"lowest common denominator,\" which is the data type capable of accommodating all elements in the array. When `None` is present in the array, it indicates that you are working with Python objects.\n", "\n", "To illustrate this, take a look at the following example array (pay attention to its `dtype`):\n" ] @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "The reality of upcasting data types comes with two consequences. First, operations will be executed at the level of Python's interpreted code rather than NumPy's compiled code. In practice, this means that any operations involving `Series` or `DataFrames` containing `None` will be slower. While this performance impact might not be noticeable in smaller datasets, it could become problematic for larger ones.\n", + "The reality of upcasting data types comes with two side effects. First, operations will be executed at the level of interpreted Python code rather than compiled NumPy code. In essence, this means that any operations involving `Series` or `DataFrames` containing `None` will be slower. While this performance impact might not be noticeable in most cases, it could become problematic for large datasets.\n", "\n", - "The second consequence is a direct result of the first. Since `None` essentially pulls `Series` or `DataFrames` back into the realm of standard Python, using NumPy/pandas aggregation functions like `sum()` or `min()` on arrays that include a `None` value will typically result in an error:\n" + "The second side effect is a consequence of the first. Since `None` essentially pulls `Series` or `DataFrames` back into the realm of standard Python, using NumPy/pandas aggregation functions like `sum()` or `min()` on arrays containing a `None` value will typically result in an error:\n" ] }, { @@ -709,7 +709,7 @@ "source": [ "### `NaN`: missing float values\n", "\n", - "Unlike `None`, NumPy (and consequently pandas) supports `NaN` for its efficient, vectorized operations and ufuncs. The downside is that any arithmetic operation involving `NaN` will always yield `NaN`. For example:\n" + "Unlike `None`, NumPy (and consequently pandas) supports `NaN` for efficient, vectorized operations and ufuncs. The downside is that any arithmetic operation involving `NaN` will always yield `NaN`. For example:\n" ] }, { @@ -842,7 +842,7 @@ "source": [ "### `NaN` and `None`: null values in pandas\n", "\n", - "Although `NaN` and `None` can act slightly differently, pandas is designed to treat them as equivalent. To understand this better, let's look at a `Series` of integers:\n" + "Even though `NaN` and `None` can behave slightly differently, pandas is designed to handle them interchangeably. To illustrate this, let's look at a `Series` of integers:\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "When converting data types to ensure uniformity in `Series` and `DataFrame`s, pandas will seamlessly interchange missing values between `None` and `NaN`. Due to this design, it can be useful to think of `None` and `NaN` as two distinct types of \"null\" in pandas. In fact, some of the key methods for handling missing values in pandas reflect this concept in their names:\n", + "In the process of converting data types to ensure uniformity in `Series` and `DataFrame`s, pandas allows missing values to interchangeably appear as `None` or `NaN`. Due to this design, it can be useful to think of `None` and `NaN` as two variations of \"null\" in pandas. In fact, some of the key methods for handling missing values in pandas reflect this concept in their names:\n", "\n", "- `isnull()`: Creates a Boolean mask to identify missing values\n", "- `notnull()`: The inverse of `isnull()`\n", "- `dropna()`: Produces a filtered version of the data\n", - "- `fillna()`: Generates a copy of the data with missing values replaced or imputed\n", + "- `fillna()`: Returns a copy of the data with missing values replaced or filled\n", "\n", - "These methods are essential to learn and become proficient with, so let's explore each one in detail.\n" + "These methods are essential to understand and become proficient with, so let's explore each one in detail.\n" ] }, { @@ -924,8 +924,8 @@ "source": [ "### Detecting null values\n", "\n", - "Now that we understand the significance of missing values, we need to identify them in our dataset before addressing them. \n", - "Both `isnull()` and `notnull()` are your main tools for detecting null data. Both methods return Boolean masks for your data.\n" + "Now that we understand the importance of missing values, we need to identify them in our dataset before addressing them. \n", + "Both `isnull()` and `notnull()` are your main methods for detecting null data. Both return Boolean masks for your data.\n" ] }, { @@ -978,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Look closely at the output. Does any of it surprise you? While `0` is an arithmetic null, it's still a perfectly valid integer, and pandas treats it as such. `''` is a bit more nuanced. Although we used it in Section 1 to represent an empty string value, it is still a string object and not considered a null value by pandas.\n", + "Look closely at the output. Does any of it surprise you? While `0` is an arithmetic null, it's still a perfectly valid integer, and pandas treats it as such. `''` is a bit more nuanced. Although we used it in Section 1 to represent an empty string value, it is still a string object and not considered a null representation by pandas.\n", "\n", - "Now, let's approach this differently and use these methods in a way that's closer to how you'll apply them in practice. You can use Boolean masks directly as an index for a ``Series`` or ``DataFrame``, which can be helpful when working with specific missing (or present) values.\n", + "Now, let's approach this differently and use these methods in a way that's closer to how you'll apply them in practice. Boolean masks can be used directly as a ``Series`` or ``DataFrame`` index, which is helpful when working with specific missing (or present) values.\n", "\n", - "If we want the total count of missing values, we can simply sum up the mask generated by the `isnull()` method.\n" + "If we want the total count of missing values, we can simply sum the mask generated by the `isnull()` method.\n" ] }, { @@ -1049,13 +1049,13 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### Dealing with missing data\n", + "### Handling Missing Data\n", "\n", - "> **Learning goal:** By the end of this subsection, you should understand how and when to replace or remove null values from DataFrames.\n", + "> **Learning goal:** By the end of this subsection, you should understand how and when to replace or remove null values in DataFrames.\n", "\n", "Machine Learning models cannot process missing data directly. Therefore, before feeding the data into the model, we need to address these missing values.\n", "\n", - "The way missing data is handled involves subtle tradeoffs and can impact your final analysis as well as real-world outcomes.\n", + "The way missing data is handled involves subtle trade-offs and can influence your final analysis as well as real-world outcomes.\n", "\n", "There are two main approaches to dealing with missing data:\n", "\n", @@ -1075,9 +1075,9 @@ "\n", "The amount of data we provide to our model directly impacts its performance. Dropping null values means reducing the number of data points, which in turn decreases the size of the dataset. Therefore, it is recommended to drop rows with null values when the dataset is sufficiently large.\n", "\n", - "Another scenario could be when a specific row or column contains a significant amount of missing values. In such cases, they can be dropped since they wouldn't contribute much to our analysis due to the lack of sufficient data in that row or column.\n", + "Another scenario could be when a specific row or column contains a significant number of missing values. In such cases, they can be dropped because they wouldn't contribute much to our analysis, as most of the data for that row/column is missing.\n", "\n", - "Beyond detecting missing values, pandas offers a convenient way to remove null values from `Series` and `DataFrame`s. To see this in practice, let's revisit `example3`. The `DataFrame.dropna()` function is useful for removing rows with null values.\n" + "Beyond detecting missing values, pandas offers a convenient way to remove null values from `Series` and `DataFrame`s. To see this in practice, let's revisit `example3`. The `DataFrame.dropna()` function is useful for dropping rows with null values.\n" ] }, { @@ -1116,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "Note that this should look like your output from `example3[example3.notnull()]`. The difference here is that, instead of simply indexing the masked values, `dropna` has eliminated those missing values from the `Series` `example3`.\n", + "Note that this should resemble your output from `example3[example3.notnull()]`. The difference here is that, instead of simply indexing the masked values, `dropna` has eliminated those missing values from the `Series` `example3`.\n", "\n", - "Since DataFrames are two-dimensional, they offer more possibilities for removing data.\n" + "Since DataFrames are two-dimensional, they offer more flexibility for removing data.\n" ] }, { @@ -1210,7 +1210,7 @@ "source": [ "(Did you notice that pandas converted two of the columns to floats to handle the `NaN`s?)\n", "\n", - "You cannot remove a single value from a `DataFrame`; instead, you have to remove entire rows or columns. Depending on your specific task, you might prefer one approach over the other, and pandas provides options for both. Since, in data science, columns typically represent variables and rows represent observations, it's more common to remove rows of data. The default behavior of `dropna()` is to remove all rows that contain any null values:\n" + "You can't remove a single value from a `DataFrame`; instead, you have to remove entire rows or columns. Depending on your specific needs, you might choose one approach over the other, and pandas provides options for both. In data science, columns typically represent variables while rows represent observations, so it's more common to drop rows of data. The default behavior of `dropna()` is to remove all rows that contain any null values:\n" ] }, { @@ -1362,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Notice that this can remove a significant amount of data that you might want to retain, especially in smaller datasets. What if you only want to drop rows or columns that contain several or even all null values? You can configure this behavior in `dropna` using the `how` and `thresh` parameters.\n", + "Notice that this approach can remove a significant amount of data that you might want to retain, especially in smaller datasets. What if you only want to drop rows or columns that contain several null values or even just entirely null values? You can configure this behavior in `dropna` using the `how` and `thresh` parameters.\n", "\n", - "By default, `how='any'` (if you'd like to verify this or explore other parameters of the method, run `example4.dropna?` in a code cell). Alternatively, you can set `how='all'` to drop only rows or columns that contain entirely null values. Let's expand our example `DataFrame` to observe this in action in the next exercise.\n" + "By default, `how='any'` (if you'd like to verify this or explore other parameters of the method, run `example4.dropna?` in a code cell). Alternatively, you can set `how='all'` to drop only rows or columns that are completely filled with null values. Let's expand our example `DataFrame` to observe this in action in the next exercise.\n" ] }, { @@ -1456,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> Key takeaways: \n", - "1. Removing null values is advisable only when the dataset is sufficiently large. \n", - "2. Entire rows or columns can be removed if the majority of their data is missing. \n", - "3. The `DataFrame.dropna(axis=)` method is useful for eliminating null values. The `axis` parameter determines whether rows or columns are removed. \n", - "4. The `how` parameter can also be utilized. By default, it is set to `any`, meaning it removes rows/columns containing any null values. It can be changed to `all` to specify that only rows/columns where all values are null should be removed. \n" + "> Key takeaways: \n", + "1. Dropping null values is advisable only if the dataset is sufficiently large.\n", + "2. Entire rows or columns can be removed if most of their data is missing.\n", + "3. The `DataFrame.dropna(axis=)` method is useful for eliminating null values. The `axis` argument determines whether rows or columns are dropped.\n", + "4. The `how` argument can also be utilized. By default, it is set to `any`, meaning it will drop rows/columns containing any null values. It can be set to `all` to specify that only rows/columns where all values are null will be dropped.\n" ] }, { @@ -1578,7 +1578,7 @@ "source": [ "### Filling null values\n", "\n", - "Sometimes, it makes sense to replace missing values with ones that could be considered valid. There are several techniques to handle null values. The first involves using Domain Knowledge (expertise in the subject area related to the dataset) to estimate the missing values.\n", + "Sometimes, it makes sense to replace missing values with ones that could be valid. There are several techniques to handle null values. The first involves using Domain Knowledge (expertise in the subject matter related to the dataset) to approximate the missing values.\n", "\n", "You could use `isnull` to fill these values directly, but this can be tedious, especially if there are many values to replace. Since this is a common task in data science, pandas offers the `fillna` method, which creates a copy of the `Series` or `DataFrame` with the missing values replaced by a value of your choice. Let's create another example `Series` to see how this works in practice.\n" ] @@ -1592,9 +1592,9 @@ "### Categorical Data (Non-numeric)\n", "First, let's look at non-numeric data. In datasets, there are columns containing categorical data, such as Gender, True or False, etc.\n", "\n", - "In most cases, missing values in these columns are replaced with the `mode` of the column. For example, if we have 100 data points, where 90 indicate True, 8 indicate False, and 2 are missing, we can fill the 2 missing values with True, based on the overall distribution in the column.\n", + "In most cases, missing values in these columns are replaced with the `mode` of the column. For example, if we have 100 data points where 90 indicate True, 8 indicate False, and 2 are missing, we can fill the 2 missing values with True, based on the overall column data.\n", "\n", - "Additionally, domain knowledge can be applied here. Let's consider an example of filling missing values using the mode.\n" + "Once again, domain knowledge can be applied here. Let's consider an example of filling missing values using the mode.\n" ] }, { @@ -1699,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Now, let's first find the mode before filling the `None` value with the mode.\n" + ] }, { "cell_type": "code", @@ -1734,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "So, we will replace None with True\n" + ] }, { "cell_type": "code", @@ -1844,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "As we can see, the null value has been replaced. Needless to say, we could have written anything in place of `'True'` and it would have got substituted.\n" + "As we can see, the null value has been replaced. Needless to say, we could have written anything in place of `'True'` and it would have been substituted.\n" ] }, { @@ -1854,16 +1858,16 @@ }, "source": [ "### Numeric Data\n", - "Now, let's talk about numeric data. Here, there are two common methods for handling missing values:\n", + "Now, let's talk about numeric data. There are two common methods for handling missing values in this case:\n", "\n", - "1. Replace with the median of the row\n", - "2. Replace with the mean of the row\n", + "1. Replace with the median of the column\n", + "2. Replace with the mean of the column\n", "\n", - "We use the median when the data is skewed and contains outliers. This is because the median is less affected by outliers.\n", + "We use the median when the data is skewed or contains outliers. This is because the median is less affected by outliers.\n", "\n", - "When the data is normalized, we can use the mean, as in such cases, the mean and median are usually very close.\n", + "When the data is normalized, the mean can be used, as in such cases, the mean and median are usually quite similar.\n", "\n", - "First, let's take a column that follows a normal distribution and fill the missing values with the mean of the column.\n" + "To start, let's take a column that follows a normal distribution and fill its missing values with the mean of the column.\n" ] }, { @@ -2003,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Filling with mean\n" + ] }, { "cell_type": "code", @@ -2252,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Filling with median\n" + ] }, { "cell_type": "code", @@ -2436,10 +2444,10 @@ }, "source": [ "> Key takeaways:\n", - "1. Missing values should be filled in when there is limited data or a clear strategy for handling the missing information.\n", - "2. Domain expertise can help approximate and fill in missing values effectively.\n", - "3. For categorical data, missing values are often replaced with the most frequent value (mode) of the column.\n", - "4. For numerical data, missing values are typically filled with the mean (for normalized datasets) or the median of the column.\n" + "1. Missing values should be filled in when there is limited data or a clear strategy for handling the missing data.\n", + "2. Domain knowledge can help approximate and fill in missing values.\n", + "3. For categorical data, missing values are often replaced with the mode of the column.\n", + "4. For numeric data, missing values are typically filled with the mean (for normalized datasets) or the median of the column.\n" ] }, { @@ -2850,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Notice that column 3 is still empty: the default approach is to fill values row by row.\n", + "Notice that column 3 still has no values: the default behavior is to fill values row by row.\n", "\n", - "> **Key point:** There are various methods to address missing values in your datasets. The approach you choose (whether to remove them, replace them, or decide how to replace them) should depend on the specific characteristics of the data. The more you work with and analyze datasets, the better you'll become at handling missing values effectively.\n" + "> **Takeaway:** There are various approaches to handle missing values in your datasets. The method you choose (whether to remove them, replace them, or decide how to replace them) should depend on the specific characteristics of the data. As you work with and explore more datasets, you'll gain a better understanding of how to address missing values effectively.\n" ] }, { @@ -2863,9 +2871,9 @@ "source": [ "### Encoding Categorical Data\n", "\n", - "Machine learning models work exclusively with numbers and any type of numeric data. They cannot differentiate between \"Yes\" and \"No,\" but they can distinguish between 0 and 1. Therefore, after addressing missing values, we need to convert categorical data into a numeric format so the model can interpret it.\n", + "Machine learning models can only process numerical data. They cannot differentiate between \"Yes\" and \"No,\" but they can distinguish between 0 and 1. Therefore, after handling missing values, we need to convert categorical data into a numerical format that the model can interpret.\n", "\n", - "There are two methods for encoding. We will discuss them below.\n" + "There are two main methods for encoding, which we will discuss next.\n" ] }, { @@ -2876,7 +2884,7 @@ "source": [ "**LABEL ENCODING**\n", "\n", - "Label encoding involves converting each category into a numerical value. For instance, imagine we have a dataset of airline passengers with a column indicating their class, such as ['business class', 'economy class', 'first class']. After applying label encoding, this would be transformed into [0, 1, 2]. Let's look at an example using code. Since we will be learning `scikit-learn` in the upcoming notebooks, we won't use it here.\n" + "Label encoding essentially involves converting each category into a number. For instance, suppose we have a dataset of airline passengers, and there is a column indicating their class, which could be one of the following: ['business class', 'economy class', 'first class']. If we apply label encoding to this, it would be transformed into [0, 1, 2]. Let's look at an example using code. Since we will be learning `scikit-learn` in the upcoming notebooks, we won't use it here.\n" ] }, { @@ -3086,7 +3094,7 @@ "id": "ftnF-TyapOPt" }, "source": [ - "As we can see, the output aligns with our expectations. So, when should we use label encoding? Label encoding is applied in one or both of the following situations:\n", + "As we can see, the output aligns with our expectations. So, when should we use label encoding? Label encoding is applied in one or both of the following scenarios:\n", "1. When there are a large number of categories\n", "2. When the categories have a specific order.\n" ] @@ -3099,9 +3107,9 @@ "source": [ "**ONE HOT ENCODING**\n", "\n", - "Another type of encoding is One Hot Encoding. In this method, each category in the column is represented as a separate column, and each data point is assigned a 0 or a 1 depending on whether it belongs to that category. This means that if there are n distinct categories, n columns will be added to the dataframe.\n", + "One Hot Encoding is another method of encoding. In this approach, each category in the column is represented as a separate column, and each data point is assigned a 0 or 1 depending on whether it belongs to that category. Thus, if there are n unique categories, n columns will be added to the dataframe.\n", "\n", - "For example, let’s consider the same airplane class example. The categories were: ['business class', 'economy class', 'first class']. If we apply one hot encoding, the following three columns will be added to the dataset: ['class_business class', 'class_economy class', 'class_first class'].\n" + "For instance, consider the same airplane class example. The categories were: ['business class', 'economy class', 'first class']. If we apply one hot encoding, the dataset will have the following three additional columns: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3334,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Each one hot encoded column contains 0 or 1, which specifies whether that category exists for that datapoint.\n" + "Each one-hot encoded column contains 0 or 1, which specifies whether that category exists for that data point.\n" ] }, { @@ -3343,10 +3351,10 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "When is one hot encoding used? One hot encoding is applied in one or both of the following situations:\n", + "When do we use one hot encoding? One hot encoding is used in one or both of the following cases:\n", "\n", - "1. When the number of categories and the dataset size are relatively small.\n", - "2. When the categories do not have any specific order.\n" + "1. When the number of categories and the size of the dataset are small.\n", + "2. When the categories do not follow any specific order.\n" ] }, { @@ -3357,7 +3365,7 @@ "source": [ "> Key Takeaways:\n", "1. Encoding is used to transform non-numeric data into numeric data.\n", - "2. There are two types of encoding: Label encoding and One Hot encoding, and either can be applied depending on the dataset's requirements.\n" + "2. There are two types of encoding: Label encoding and One Hot encoding, which can be applied depending on the requirements of the dataset.\n" ] }, { @@ -3368,9 +3376,9 @@ "source": [ "## Removing duplicate data\n", "\n", - "> **Learning goal:** By the end of this subsection, you should feel confident identifying and removing duplicate values from DataFrames.\n", + "> **Learning goal:** By the end of this subsection, you should be comfortable identifying and removing duplicate values from DataFrames.\n", "\n", - "Along with missing data, duplicated data is a common issue in real-world datasets. Luckily, pandas offers a straightforward way to detect and eliminate duplicate entries.\n" + "In addition to missing data, you will often encounter duplicated data in real-world datasets. Fortunately, pandas provides an easy way to detect and remove duplicate entries.\n" ] }, { @@ -3381,7 +3389,7 @@ "source": [ "### Identifying duplicates: `duplicated`\n", "\n", - "You can quickly identify duplicate values using the `duplicated` method in pandas. This method provides a Boolean mask that shows whether an entry in a `DataFrame` is a duplicate of a previous one. Let's create another example `DataFrame` to demonstrate this.\n" + "You can easily identify duplicate values using the `duplicated` method in pandas, which provides a Boolean mask indicating whether an entry in a `DataFrame` is a duplicate of a previous one. Let's create another example `DataFrame` to demonstrate this.\n" ] }, { @@ -3511,7 +3519,7 @@ }, "source": [ "### Dropping duplicates: `drop_duplicates`\n", - "`drop_duplicates` returns a copy of the data where all `duplicated` values are `False`:\n" + "`drop_duplicates` simply returns a copy of the data where all `duplicated` values are `False`:\n" ] }, { @@ -3594,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Both `duplicated` and `drop_duplicates` default to consider all columns but you can specify that they examine only a subset of columns in your `DataFrame`:\n" + "Both `duplicated` and `drop_duplicates` default to consider all columns, but you can specify that they examine only a subset of columns in your `DataFrame`:\n" ] }, { @@ -3671,7 +3679,523 @@ "id": "GvX4og1EgRsL" }, "source": [ - "**Takeaway:** Removing duplicate data is an essential part of almost every data-science project. Duplicate data can change the results of your analyses and give you inaccurate results!\n" + "> **Takeaway:** Removing duplicate data is an essential part of almost every data-science project. Duplicate data can change the results of your analyses and give you inaccurate results!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Real-World Data Quality Checks\n", + "\n", + "> **Learning goal:** By the end of this section, you should feel confident identifying and addressing common real-world data quality issues, such as inconsistent categorical values, unusual numeric values (outliers), and duplicate entities with slight variations.\n", + "\n", + "While missing values and exact duplicates are frequent problems, real-world datasets often present more nuanced challenges:\n", + "\n", + "1. **Inconsistent categorical values**: The same category written differently (e.g., \"USA\", \"U.S.A\", \"United States\").\n", + "2. **Unusual numeric values**: Extreme outliers that may indicate data entry mistakes (e.g., age = 999).\n", + "3. **Near-duplicate rows**: Entries that represent the same entity but with minor differences.\n", + "\n", + "Let’s dive into methods for detecting and resolving these issues.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Creating a Sample \"Dirty\" Dataset\n", + "\n", + "First, let's create a sample dataset that includes the types of problems we often face in real-world data:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Detecting Inconsistent Categorical Values\n", + "\n", + "Notice that the `country` column contains multiple variations for the same countries. Let's pinpoint these inconsistencies:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Standardizing Categorical Values\n", + "\n", + "We can create a mapping to standardize these values. A straightforward method is to convert them to lowercase and use a mapping dictionary:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternative: Using Fuzzy Matching**\n", + "\n", + "For more complex scenarios, the `rapidfuzz` library can be used to perform fuzzy string matching and automatically identify similar strings:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Detecting Abnormal Numeric Values (Outliers)\n", + "\n", + "Looking at the `age` column, we have some suspicious values such as 199 and -5. Let's apply statistical methods to identify these outliers.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Using IQR (Interquartile Range) Method\n", + "\n", + "The IQR method is a reliable statistical approach for identifying outliers, as it is less affected by extreme values:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Using Z-Score Method\n", + "\n", + "The Z-score method identifies outliers based on standard deviations from the mean:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Handling Outliers\n", + "\n", + "Once detected, outliers can be handled in several ways:\n", + "1. **Remove**: Delete rows containing outliers (if they are errors)\n", + "2. **Cap**: Replace them with boundary values\n", + "3. **Replace with NaN**: Treat them as missing data and apply imputation techniques\n", + "4. **Keep**: If they are valid extreme values\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Identifying Near-Duplicate Rows\n", + "\n", + "Observe that our dataset contains multiple entries for \"John Smith\" with slightly varying details. Let's pinpoint possible duplicates by analyzing name similarity.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Finding Near-Duplicates with Fuzzy Matching\n", + "\n", + "For more advanced duplicate detection, fuzzy matching can be used to identify similar names:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Handling Duplicates\n", + "\n", + "Once identified, you need to decide how to handle duplicates:\n", + "1. **Keep the first occurrence**: Use `drop_duplicates(keep='first')`\n", + "2. **Keep the last occurrence**: Use `drop_duplicates(keep='last')`\n", + "3. **Aggregate information**: Combine information from duplicate rows\n", + "4. **Manual review**: Flag for human review\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Summary: Complete Data Cleaning Pipeline\n", + "\n", + "Let's combine everything into a full-fledged data cleaning pipeline:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Challenge Exercise\n", + "\n", + "Now it's your turn! Below is a new row of data with multiple quality issues. Can you:\n", + "\n", + "1. Identify all the issues in this row\n", + "2. Write code to clean each issue\n", + "3. Add the cleaned row to the dataset\n", + "\n", + "Here's the problematic data:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Key Takeaways\n", + "\n", + "1. **Inconsistent categories** are common in real-world data. Always review unique values and standardize them using mappings or fuzzy matching.\n", + "\n", + "2. **Outliers** can have a significant impact on your analysis. Combine domain knowledge with statistical methods (IQR, Z-score) to identify them.\n", + "\n", + "3. **Near-duplicates** are more challenging to detect than exact duplicates. Use techniques like fuzzy matching and data normalization (lowercasing, removing extra spaces) to spot them.\n", + "\n", + "4. **Data cleaning is an iterative process**. You may need to apply several techniques and evaluate the results before finalizing your cleaned dataset.\n", + "\n", + "5. **Document your decisions**. Record the cleaning steps you applied and the reasoning behind them, as this is crucial for reproducibility and transparency.\n", + "\n", + "> **Best Practice:** Always retain a copy of your original \"dirty\" data. Avoid overwriting your source data files—create cleaned versions with clear naming conventions, such as `data_cleaned.csv`.\n" ] }, { @@ -3706,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-03T20:41:17+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T18:49:44+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "en" } diff --git a/translations/es/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/es/2-Working-With-Data/08-data-preparation/notebook.ipynb index 7a1a1d4d..bf01b7b6 100644 --- a/translations/es/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/es/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,13 +8,13 @@ "source": [ "# Preparación de Datos\n", "\n", - "[Fuente original del Notebook de *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio por Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Fuente original del cuaderno de *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio por Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## Explorando información de `DataFrame`\n", "\n", - "> **Objetivo de aprendizaje:** Al final de esta subsección, deberías sentirte cómodo encontrando información general sobre los datos almacenados en pandas DataFrames.\n", + "> **Objetivo de aprendizaje:** Al final de esta subsección, deberías sentirte cómodo encontrando información general sobre los datos almacenados en DataFrames de pandas.\n", "\n", - "Una vez que hayas cargado tus datos en pandas, lo más probable es que estén en un `DataFrame`. Sin embargo, si el conjunto de datos en tu `DataFrame` tiene 60,000 filas y 400 columnas, ¿cómo puedes empezar a entender con qué estás trabajando? Afortunadamente, pandas proporciona herramientas convenientes para observar rápidamente información general sobre un `DataFrame`, además de las primeras y últimas filas.\n", + "Una vez que hayas cargado tus datos en pandas, lo más probable es que estén en un `DataFrame`. Sin embargo, si el conjunto de datos en tu `DataFrame` tiene 60,000 filas y 400 columnas, ¿cómo puedes siquiera empezar a entender con qué estás trabajando? Afortunadamente, pandas proporciona herramientas convenientes para observar rápidamente información general sobre un `DataFrame`, además de las primeras y últimas filas.\n", "\n", "Para explorar esta funcionalidad, importaremos la biblioteca Python scikit-learn y utilizaremos un conjunto de datos icónico que todo científico de datos ha visto cientos de veces: el conjunto de datos *Iris* del biólogo británico Ronald Fisher, utilizado en su artículo de 1936 \"El uso de mediciones múltiples en problemas taxonómicos\":\n" ] @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Entonces, estamos trabajando con 150 filas y 4 columnas de datos. Cada fila representa un punto de datos y cada columna representa una característica asociada al marco de datos. Básicamente, hay 150 puntos de datos que contienen 4 características cada uno.\n", + "Entonces, estamos trabajando con 150 filas y 4 columnas de datos. Cada fila representa un punto de datos y cada columna representa una característica única asociada con el marco de datos. Básicamente, hay 150 puntos de datos que contienen 4 características cada uno.\n", "\n", - "`shape` aquí es un atributo del marco de datos y no una función, por lo que no termina con un par de paréntesis.\n" + "`shape` aquí es un atributo del marco de datos y no una función, por eso no termina con un par de paréntesis.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Pasemos ahora a las 4 columnas de datos. ¿Qué representa exactamente cada una de ellas? El atributo `columns` nos dará el nombre de las columnas en el dataframe.\n" + "Ahora pasemos a las 4 columnas de datos. ¿Qué representa exactamente cada una de ellas? El atributo `columns` nos dará el nombre de las columnas en el dataframe.\n" ] }, { @@ -181,8 +181,8 @@ }, "source": [ "A partir de aquí, podemos hacer algunas observaciones: \n", - "1. El tipo de dato de cada columna: En este conjunto de datos, toda la información está almacenada como números de punto flotante de 64 bits. \n", - "2. Número de valores no nulos: Manejar valores nulos es un paso importante en la preparación de datos. Esto se abordará más adelante en el cuaderno. \n" + "1. El tipo de dato de cada columna: En este conjunto de datos, todos los datos están almacenados como números de punto flotante de 64 bits. \n", + "2. Número de valores no nulos: Manejar los valores nulos es un paso importante en la preparación de datos. Esto se abordará más adelante en el cuaderno. \n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Supongamos que tenemos muchos datos numéricos en nuestro conjunto de datos. Los cálculos estadísticos univariados, como la media, la mediana, los cuartiles, etc., se pueden realizar en cada una de las columnas de forma individual. La función `DataFrame.describe()` nos proporciona un resumen estadístico de las columnas numéricas de un conjunto de datos.\n" + "Supongamos que tenemos muchos datos numéricos en nuestro conjunto de datos. Los cálculos estadísticos univariados, como la media, la mediana, los cuartiles, etc., se pueden realizar en cada una de las columnas individualmente. La función `DataFrame.describe()` nos proporciona un resumen estadístico de las columnas numéricas de un conjunto de datos.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Ejercicio:\n", "\n", - "A partir del ejemplo dado anteriormente, queda claro que, por defecto, `DataFrame.head` devuelve las primeras cinco filas de un `DataFrame`. En la celda de código a continuación, ¿puedes encontrar una forma de mostrar más de cinco filas?\n" + "Del ejemplo dado anteriormente, queda claro que, por defecto, `DataFrame.head` devuelve las primeras cinco filas de un `DataFrame`. En la celda de código a continuación, ¿puedes encontrar una manera de mostrar más de cinco filas?\n" ] }, { @@ -584,7 +584,7 @@ "source": [ "En la práctica, es útil poder examinar fácilmente las primeras filas o las últimas filas de un `DataFrame`, especialmente cuando estás buscando valores atípicos en conjuntos de datos ordenados.\n", "\n", - "Todas las funciones y atributos mostrados anteriormente con la ayuda de ejemplos de código nos ayudan a obtener una visión general y una sensación del conjunto de datos.\n", + "Todas las funciones y atributos mostrados anteriormente con la ayuda de ejemplos de código nos ayudan a obtener una visión general y una idea del contenido de los datos.\n", "\n", "> **Conclusión:** Incluso solo mirando los metadatos sobre la información en un DataFrame o los primeros y últimos valores en uno, puedes obtener una idea inmediata sobre el tamaño, la forma y el contenido de los datos con los que estás trabajando.\n" ] @@ -595,18 +595,18 @@ "id": "TvurZyLSDxq_" }, "source": [ - "### Datos Faltantes\n", - "Vamos a profundizar en los datos faltantes. Los datos faltantes ocurren cuando no se almacena un valor en algunas de las columnas.\n", + "### Datos faltantes\n", + "Vamos a profundizar en los datos faltantes. Los datos faltantes ocurren cuando no se almacena ningún valor en algunas de las columnas.\n", "\n", - "Tomemos un ejemplo: supongamos que alguien está consciente de su peso y no completa el campo de peso en una encuesta. Entonces, el valor del peso para esa persona estará ausente.\n", + "Tomemos un ejemplo: supongamos que alguien está preocupado por su peso y no completa el campo de peso en una encuesta. Entonces, el valor de peso para esa persona en particular estará ausente.\n", "\n", "La mayoría de las veces, en conjuntos de datos del mundo real, ocurren valores faltantes.\n", "\n", "**Cómo Pandas maneja los datos faltantes**\n", "\n", - "Pandas maneja los valores faltantes de dos maneras. La primera, que ya has visto en secciones anteriores, es `NaN`, o Not a Number (No es un número). Este es en realidad un valor especial que forma parte de la especificación de punto flotante IEEE y se utiliza únicamente para indicar valores de punto flotante faltantes.\n", + "Pandas maneja los valores faltantes de dos maneras. La primera ya la has visto en secciones anteriores: `NaN`, o Not a Number (No es un número). Este es, de hecho, un valor especial que forma parte de la especificación de punto flotante IEEE y se utiliza únicamente para indicar valores faltantes de tipo flotante.\n", "\n", - "Para los valores faltantes que no son de tipo flotante, pandas utiliza el objeto `None` de Python. Aunque pueda parecer confuso encontrarse con dos tipos diferentes de valores que esencialmente indican lo mismo, hay razones programáticas sólidas para esta elección de diseño y, en la práctica, seguir este enfoque permite a pandas ofrecer un buen compromiso en la gran mayoría de los casos. No obstante, tanto `None` como `NaN` tienen restricciones que debes tener en cuenta en relación con cómo pueden ser utilizados.\n" + "Para valores faltantes que no son de tipo flotante, pandas utiliza el objeto `None` de Python. Aunque pueda parecer confuso encontrarse con dos tipos diferentes de valores que esencialmente indican lo mismo, hay razones programáticas sólidas para esta elección de diseño y, en la práctica, seguir este enfoque permite a pandas ofrecer un buen equilibrio para la gran mayoría de los casos. No obstante, tanto `None` como `NaN` tienen restricciones que debes tener en cuenta con respecto a cómo pueden ser utilizados.\n" ] }, { @@ -616,7 +616,7 @@ }, "source": [ "### `None`: datos faltantes no flotantes\n", - "Debido a que `None` proviene de Python, no puede ser utilizado en arrays de NumPy y pandas que no tengan el tipo de dato `'object'`. Recuerda, los arrays de NumPy (y las estructuras de datos en pandas) solo pueden contener un tipo de dato. Esto es lo que les da su enorme poder para trabajar con datos y cálculos a gran escala, pero también limita su flexibilidad. Dichos arrays tienen que convertir los datos al \"denominador común más bajo\", es decir, al tipo de dato que abarque todo en el array. Cuando `None` está en el array, significa que estás trabajando con objetos de Python.\n", + "Dado que `None` proviene de Python, no puede ser utilizado en arrays de NumPy y pandas que no tengan el tipo de dato `'object'`. Recuerda que los arrays de NumPy (y las estructuras de datos en pandas) solo pueden contener un tipo de dato. Esto es lo que les da su enorme potencia para trabajar con datos y cálculos a gran escala, pero también limita su flexibilidad. Dichos arrays tienen que convertir su tipo al \"mínimo común denominador\", es decir, al tipo de dato que abarque todo en el array. Cuando `None` está en el array, significa que estás trabajando con objetos de Python.\n", "\n", "Para ver esto en acción, considera el siguiente ejemplo de array (nota el `dtype` que tiene):\n" ] @@ -657,7 +657,7 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "La realidad de los tipos de datos promovidos conlleva dos efectos secundarios. Primero, las operaciones se realizarán a nivel de código interpretado de Python en lugar de código compilado de NumPy. Básicamente, esto significa que cualquier operación que involucre `Series` o `DataFrames` con `None` será más lenta. Aunque probablemente no notarías esta disminución de rendimiento, en conjuntos de datos grandes podría convertirse en un problema.\n", + "La realidad de los tipos de datos promovidos conlleva dos efectos secundarios. Primero, las operaciones se realizarán a nivel de código interpretado de Python en lugar de código compilado de NumPy. Básicamente, esto significa que cualquier operación que involucre `Series` o `DataFrames` con `None` será más lenta. Aunque probablemente no notarías este impacto en el rendimiento, en conjuntos de datos grandes podría convertirse en un problema.\n", "\n", "El segundo efecto secundario deriva del primero. Debido a que `None` esencialmente arrastra a las `Series` o `DataFrames` de vuelta al mundo de Python estándar, usar agregaciones de NumPy/pandas como `sum()` o `min()` en arreglos que contienen un valor ``None`` generalmente producirá un error:\n" ] @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**Conclusión clave**: La suma (y otras operaciones) entre enteros y valores `None` no está definida, lo que puede limitar lo que puedes hacer con conjuntos de datos que los contienen.\n" + ] }, { "cell_type": "markdown", @@ -828,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "Recuerda: `NaN` es solo para valores de punto flotante faltantes; no hay un equivalente de `NaN` para enteros, cadenas o valores booleanos.\n" + ] }, { "cell_type": "markdown", @@ -902,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "En el proceso de convertir tipos de datos para establecer homogeneidad en los `Series` y `DataFrame`s, pandas cambiará sin problemas los valores faltantes entre `None` y `NaN`. Debido a esta característica de diseño, puede ser útil pensar en `None` y `NaN` como dos variantes diferentes de \"nulo\" en pandas. De hecho, algunos de los métodos principales que usarás para manejar valores faltantes en pandas reflejan esta idea en sus nombres:\n", + "En el proceso de convertir tipos de datos para establecer homogeneidad en los datos de `Series` y `DataFrame`s, pandas cambiará sin problema los valores faltantes entre `None` y `NaN`. Debido a esta característica de diseño, puede ser útil pensar en `None` y `NaN` como dos variantes diferentes de \"nulo\" en pandas. De hecho, algunos de los métodos principales que usarás para manejar valores faltantes en pandas reflejan esta idea en sus nombres:\n", "\n", - "- `isnull()`: Genera una máscara booleana que indica valores faltantes\n", - "- `notnull()`: Opuesto a `isnull()`\n", - "- `dropna()`: Devuelve una versión filtrada de los datos\n", - "- `fillna()`: Devuelve una copia de los datos con los valores faltantes rellenados o imputados\n", + "- `isnull()`: Genera una máscara booleana que indica valores faltantes.\n", + "- `notnull()`: Opuesto a `isnull()`.\n", + "- `dropna()`: Devuelve una versión filtrada de los datos.\n", + "- `fillna()`: Devuelve una copia de los datos con los valores faltantes rellenados o imputados.\n", "\n", - "Estos son métodos importantes que debes dominar y con los que debes familiarizarte, así que repasémoslos en detalle.\n" + "Estos son métodos importantes que debes dominar y con los que debes sentirte cómodo, así que vamos a repasarlos en detalle.\n" ] }, { @@ -920,8 +924,7 @@ "source": [ "### Detectar valores nulos\n", "\n", - "Ahora que hemos entendido la importancia de los valores faltantes, necesitamos detectarlos en nuestro conjunto de datos antes de manejarlos. \n", - "Tanto `isnull()` como `notnull()` son tus métodos principales para detectar datos nulos. Ambos devuelven máscaras booleanas sobre tus datos.\n" + "Ahora que hemos entendido la importancia de los valores faltantes, necesitamos detectarlos en nuestro conjunto de datos antes de manejarlos. Tanto `isnull()` como `notnull()` son tus métodos principales para detectar datos nulos. Ambos devuelven máscaras booleanas sobre tus datos.\n" ] }, { @@ -974,7 +977,7 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Mira detenidamente el contenido. ¿Hay algo que te sorprenda? Aunque `0` es un nulo aritmético, sigue siendo un número entero perfectamente válido, y pandas lo trata como tal. `''` es un poco más sutil. Aunque lo usamos en la Sección 1 para representar un valor de cadena vacío, sigue siendo un objeto de cadena y no una representación de nulo según pandas.\n", + "Observa detenidamente el resultado. ¿Hay algo que te sorprenda? Aunque `0` es un valor nulo en términos aritméticos, sigue siendo un número entero válido y pandas lo trata como tal. `''` es un caso un poco más sutil. Aunque lo usamos en la Sección 1 para representar un valor de cadena vacío, sigue siendo un objeto de tipo cadena y no una representación de un valor nulo según pandas.\n", "\n", "Ahora, vamos a darle la vuelta y usar estos métodos de una manera más parecida a cómo los usarás en la práctica. Puedes usar máscaras booleanas directamente como un índice de ``Series`` o ``DataFrame``, lo cual puede ser útil cuando intentas trabajar con valores faltantes (o presentes) de forma aislada.\n", "\n", @@ -1071,7 +1074,7 @@ "\n", "La cantidad de datos que pasamos a nuestro modelo tiene un efecto directo en su rendimiento. Eliminar valores nulos significa que estamos reduciendo el número de puntos de datos y, por lo tanto, el tamaño del conjunto de datos. Por eso, es recomendable eliminar filas con valores nulos cuando el conjunto de datos es bastante grande.\n", "\n", - "Otro caso podría ser que una fila o columna específica tenga muchos valores faltantes. En ese caso, podrían eliminarse porque no aportarían mucho valor a nuestro análisis, ya que la mayor parte de los datos están ausentes para esa fila/columna.\n", + "Otro caso podría ser que una fila o columna específica tenga muchos valores faltantes. En ese caso, podrían eliminarse porque no aportarían mucho valor a nuestro análisis, ya que la mayoría de los datos están ausentes para esa fila/columna.\n", "\n", "Más allá de identificar valores faltantes, pandas ofrece una forma conveniente de eliminar valores nulos de `Series` y `DataFrame`s. Para ver esto en acción, volvamos a `example3`. La función `DataFrame.dropna()` ayuda a eliminar las filas con valores nulos.\n" ] @@ -1112,9 +1115,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "Ten en cuenta que esto debería verse como tu salida de `example3[example3.notnull()]`. La diferencia aquí es que, en lugar de simplemente indexar los valores enmascarados, `dropna` ha eliminado esos valores faltantes del `Series` `example3`.\n", + "Ten en cuenta que esto debería parecerse a tu salida de `example3[example3.notnull()]`. La diferencia aquí es que, en lugar de simplemente indexar los valores enmascarados, `dropna` ha eliminado esos valores faltantes del `Series` `example3`.\n", "\n", - "Debido a que los DataFrames tienen dos dimensiones, ofrecen más opciones para eliminar datos.\n" + "Dado que los DataFrames tienen dos dimensiones, ofrecen más opciones para eliminar datos.\n" ] }, { @@ -1206,7 +1209,7 @@ "source": [ "(¿Notaste que pandas convirtió dos de las columnas a flotantes para acomodar los `NaN`?)\n", "\n", - "No puedes eliminar un solo valor de un `DataFrame`, por lo que tienes que eliminar filas o columnas completas. Dependiendo de lo que estés haciendo, podrías querer hacer una cosa u otra, y por eso pandas te da opciones para ambas. Dado que en ciencia de datos las columnas generalmente representan variables y las filas representan observaciones, es más probable que elimines filas de datos; la configuración predeterminada de `dropna()` es eliminar todas las filas que contengan cualquier valor nulo:\n" + "No puedes eliminar un único valor de un `DataFrame`, por lo que tienes que eliminar filas o columnas completas. Dependiendo de lo que estés haciendo, podrías querer hacer una u otra cosa, y por eso pandas te da opciones para ambas. Debido a que en ciencia de datos las columnas generalmente representan variables y las filas representan observaciones, es más probable que elimines filas de datos; la configuración predeterminada de `dropna()` es eliminar todas las filas que contienen cualquier valor nulo:\n" ] }, { @@ -1358,9 +1361,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Ten en cuenta que esto puede eliminar una gran cantidad de datos que podrías querer conservar, especialmente en conjuntos de datos más pequeños. ¿Qué pasa si solo quieres eliminar filas o columnas que contienen varios o incluso todos los valores nulos? Puedes especificar esas configuraciones en `dropna` con los parámetros `how` y `thresh`.\n", + "Ten en cuenta que esto puede eliminar muchos datos que podrías querer conservar, especialmente en conjuntos de datos más pequeños. ¿Qué pasa si solo quieres eliminar filas o columnas que contienen varios o incluso todos los valores nulos? Puedes especificar esas configuraciones en `dropna` utilizando los parámetros `how` y `thresh`.\n", "\n", - "Por defecto, `how='any'` (si deseas comprobarlo por ti mismo o ver qué otros parámetros tiene el método, ejecuta `example4.dropna?` en una celda de código). Alternativamente, podrías especificar `how='all'` para eliminar únicamente las filas o columnas que contienen todos los valores nulos. Ampliemos nuestro ejemplo de `DataFrame` para ver esto en acción en el próximo ejercicio.\n" + "Por defecto, `how='any'` (si deseas verificarlo por ti mismo o ver qué otros parámetros tiene el método, ejecuta `example4.dropna?` en una celda de código). Alternativamente, podrías especificar `how='all'` para eliminar únicamente las filas o columnas que contienen todos los valores nulos. Vamos a ampliar nuestro ejemplo de `DataFrame` para ver esto en acción en el próximo ejercicio.\n" ] }, { @@ -1454,9 +1457,9 @@ "source": [ "> Puntos clave: \n", "1. Eliminar valores nulos es una buena idea solo si el conjunto de datos es lo suficientemente grande. \n", - "2. Se pueden eliminar filas o columnas completas si la mayor parte de sus datos están ausentes. \n", + "2. Se pueden eliminar filas o columnas completas si la mayoría de sus datos están ausentes. \n", "3. El método `DataFrame.dropna(axis=)` ayuda a eliminar valores nulos. El argumento `axis` indica si se deben eliminar filas o columnas. \n", - "4. También se puede usar el argumento `how`. Por defecto, está configurado como `any`. Por lo tanto, elimina solo aquellas filas/columnas que contienen algún valor nulo. Se puede configurar como `all` para especificar que eliminaremos solo aquellas filas/columnas donde todos los valores sean nulos. \n" + "4. También se puede usar el argumento `how`. Por defecto está configurado como `any`. Por lo tanto, elimina solo aquellas filas/columnas que contienen algún valor nulo. Se puede configurar como `all` para especificar que eliminaremos solo aquellas filas/columnas donde todos los valores sean nulos. \n" ] }, { @@ -1488,7 +1491,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "El parámetro `thresh` te da un control más detallado: estableces el número de valores *no nulos* que una fila o columna necesita tener para ser conservada:\n" + "El parámetro `thresh` te ofrece un control más detallado: defines la cantidad de valores *no nulos* que una fila o columna necesita tener para ser conservada:\n" ] }, { @@ -1563,7 +1566,7 @@ "id": "fmSFnzZegRsG" }, "source": [ - "Aquí, la primera y última fila se han eliminado, porque contienen solo dos valores no nulos.\n" + "Aquí, se han eliminado la primera y la última fila, porque contienen solo dos valores no nulos.\n" ] }, { @@ -1574,9 +1577,9 @@ "source": [ "### Rellenar valores nulos\n", "\n", - "A veces tiene sentido completar los valores faltantes con otros que podrían ser válidos. Existen varias técnicas para rellenar valores nulos. La primera es usar Conocimiento del Dominio (conocimiento del tema en el que se basa el conjunto de datos) para aproximar de alguna manera los valores faltantes.\n", + "A veces tiene sentido completar los valores faltantes con aquellos que podrían ser válidos. Hay algunas técnicas para rellenar valores nulos. La primera es usar Conocimiento del Dominio (conocimiento del tema en el que se basa el conjunto de datos) para aproximar de alguna manera los valores faltantes.\n", "\n", - "Podrías usar `isnull` para hacer esto directamente, pero puede ser tedioso, especialmente si tienes muchos valores que rellenar. Dado que esta es una tarea tan común en ciencia de datos, pandas proporciona `fillna`, que devuelve una copia del `Series` o `DataFrame` con los valores faltantes reemplazados por uno de tu elección. Vamos a crear otro ejemplo de `Series` para ver cómo funciona esto en la práctica.\n" + "Puedes usar `isnull` para hacer esto directamente, pero puede ser laborioso, especialmente si tienes muchos valores que rellenar. Debido a que esta es una tarea tan común en ciencia de datos, pandas proporciona `fillna`, que devuelve una copia del `Series` o `DataFrame` con los valores faltantes reemplazados por uno de tu elección. Vamos a crear otro ejemplo de `Series` para ver cómo funciona esto en la práctica.\n" ] }, { @@ -1585,12 +1588,12 @@ "id": "CE8S7louLezV" }, "source": [ - "### Datos Categóricos (No numéricos)\n", + "### Datos categóricos (no numéricos)\n", "Primero, consideremos los datos no numéricos. En los conjuntos de datos, tenemos columnas con datos categóricos. Por ejemplo, Género, Verdadero o Falso, etc.\n", "\n", - "En la mayoría de estos casos, reemplazamos los valores faltantes con la `moda` de la columna. Supongamos que tenemos 100 puntos de datos, 90 han respondido Verdadero, 8 han respondido Falso y 2 no han respondido. Entonces, podemos completar los 2 con Verdadero, considerando toda la columna.\n", + "En la mayoría de estos casos, reemplazamos los valores faltantes con la `moda` de la columna. Supongamos que tenemos 100 puntos de datos, de los cuales 90 han indicado Verdadero, 8 han indicado Falso y 2 no han respondido. Entonces, podemos completar los 2 con Verdadero, considerando toda la columna.\n", "\n", - "Nuevamente, aquí podemos usar conocimiento del dominio. Consideremos un ejemplo de cómo completar con la moda.\n" + "Nuevamente, aquí podemos usar conocimiento del dominio. Veamos un ejemplo de cómo completar con la moda.\n" ] }, { @@ -1695,7 +1698,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Ahora, primero encontremos la moda antes de llenar el valor `None` con la moda.\n" + ] }, { "cell_type": "code", @@ -1730,7 +1735,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Entonces, reemplazaremos None con True\n" + ] }, { "cell_type": "code", @@ -1850,14 +1857,14 @@ }, "source": [ "### Datos Numéricos\n", - "Ahora, pasando a los datos numéricos. Aquí, tenemos dos formas comunes de reemplazar valores faltantes:\n", + "Ahora, pasando a los datos numéricos. Aquí tenemos dos formas comunes de reemplazar valores faltantes:\n", "\n", "1. Reemplazar con la mediana de la fila \n", "2. Reemplazar con el promedio de la fila \n", "\n", - "Reemplazamos con la mediana en caso de datos sesgados con valores atípicos. Esto se debe a que la mediana es robusta frente a los valores atípicos.\n", + "Reemplazamos con la mediana en caso de datos sesgados con valores atípicos. Esto se debe a que la mediana es resistente a los valores atípicos.\n", "\n", - "Cuando los datos están normalizados, podemos usar el promedio, ya que en ese caso, el promedio y la mediana estarían bastante cerca.\n", + "Cuando los datos están normalizados, podemos usar el promedio, ya que en ese caso, el promedio y la mediana serían bastante cercanos.\n", "\n", "Primero, tomemos una columna que esté distribuida normalmente y rellenemos el valor faltante con el promedio de la columna.\n" ] @@ -1999,7 +2006,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Rellenar con la media\n" + ] }, { "cell_type": "code", @@ -2108,7 +2117,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Ahora intentemos con otro dataframe, y esta vez reemplazaremos los valores None con la mediana de la columna.\n" + "Ahora intentemos otro dataframe, y esta vez reemplazaremos los valores None con la mediana de la columna.\n" ] }, { @@ -2248,7 +2257,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Rellenar con la mediana\n" + ] }, { "cell_type": "code", @@ -2432,10 +2443,10 @@ }, "source": [ "> Puntos clave:\n", - "1. Completar los valores faltantes debe hacerse cuando hay poca información o cuando existe una estrategia para llenar los datos faltantes.\n", - "2. El conocimiento del dominio puede utilizarse para completar los valores faltantes aproximándolos.\n", - "3. Para datos categóricos, generalmente, los valores faltantes se sustituyen con la moda de la columna.\n", - "4. Para datos numéricos, los valores faltantes suelen completarse con la media (para conjuntos de datos normalizados) o la mediana de las columnas.\n" + "1. Completar los valores faltantes debe hacerse cuando hay poca información o existe una estrategia para llenar los datos faltantes.\n", + "2. El conocimiento del dominio puede utilizarse para aproximar y completar los valores faltantes.\n", + "3. En el caso de datos categóricos, generalmente los valores faltantes se sustituyen por la moda de la columna.\n", + "4. Para datos numéricos, los valores faltantes suelen completarse con la media (en conjuntos de datos normalizados) o la mediana de las columnas.\n" ] }, { @@ -2465,7 +2476,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "Puedes **rellenar hacia adelante** los valores nulos, lo que significa usar el último valor válido para llenar un nulo:\n" + ] }, { "cell_type": "code", @@ -2720,7 +2733,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Ten en cuenta que cuando no se dispone de un valor previo para completar hacia adelante, el valor nulo permanece.\n" + "Nota que cuando no se dispone de un valor previo para completar hacia adelante, el valor nulo permanece.\n" ] }, { @@ -2753,7 +2766,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Puedes ser creativo con cómo usas `fillna`. Por ejemplo, veamos nuevamente `example4`, pero esta vez llenemos los valores faltantes con el promedio de todos los valores en el `DataFrame`:\n" + "Puedes ser creativo con el uso de `fillna`. Por ejemplo, veamos nuevamente `example4`, pero esta vez llenemos los valores faltantes con el promedio de todos los valores en el `DataFrame`:\n" ] }, { @@ -2844,9 +2857,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Ten en cuenta que la columna 3 aún no tiene valores: la dirección predeterminada es completar los valores fila por fila.\n", + "Observa que la columna 3 sigue sin valores: la dirección predeterminada es llenar los valores fila por fila.\n", "\n", - "> **Conclusión:** Hay múltiples maneras de tratar los valores faltantes en tus conjuntos de datos. La estrategia específica que utilices (eliminarlos, reemplazarlos, o incluso cómo los reemplazas) debe estar dictada por las particularidades de esos datos. Desarrollarás un mejor sentido de cómo manejar los valores faltantes cuanto más trabajes e interactúes con conjuntos de datos.\n" + "> **Conclusión:** Hay múltiples formas de tratar los valores faltantes en tus conjuntos de datos. La estrategia específica que utilices (eliminarlos, reemplazarlos, o incluso cómo los reemplazas) debe estar dictada por las particularidades de esos datos. Desarrollarás un mejor sentido de cómo manejar los valores faltantes cuanto más trabajes e interactúes con conjuntos de datos.\n" ] }, { @@ -2870,7 +2883,7 @@ "source": [ "**CODIFICACIÓN DE ETIQUETAS**\n", "\n", - "La codificación de etiquetas consiste básicamente en convertir cada categoría en un número. Por ejemplo, supongamos que tenemos un conjunto de datos de pasajeros de aerolíneas y hay una columna que contiene su clase entre las siguientes ['clase ejecutiva', 'clase económica', 'primera clase']. Si se realiza la codificación de etiquetas en esto, se transformaría en [0,1,2]. Veamos un ejemplo mediante código. Como estaremos aprendiendo `scikit-learn` en los próximos cuadernos, no lo utilizaremos aquí.\n" + "La codificación de etiquetas consiste básicamente en convertir cada categoría en un número. Por ejemplo, supongamos que tenemos un conjunto de datos de pasajeros de aerolíneas y hay una columna que contiene su clase entre las siguientes ['clase ejecutiva', 'clase económica', 'primera clase']. Si se realiza la codificación de etiquetas en esto, se transformaría en [0,1,2]. Veamos un ejemplo con código. Como estaremos aprendiendo `scikit-learn` en los próximos cuadernos, no lo utilizaremos aquí.\n" ] }, { @@ -2978,7 +2991,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Para realizar la codificación de etiquetas en la primera columna, primero debemos describir un mapeo de cada clase a un número, antes de reemplazar\n" + "Para realizar la codificación de etiquetas en la primera columna, primero debemos describir un mapeo de cada clase a un número, antes de reemplazar.\n" ] }, { @@ -3080,8 +3093,8 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Como podemos ver, el resultado coincide con lo que esperábamos. Entonces, ¿cuándo usamos la codificación de etiquetas? La codificación de etiquetas se utiliza en uno o ambos de los siguientes casos:\n", - "1. Cuando el número de categorías es grande\n", + "Como podemos observar, el resultado coincide con lo que esperábamos. Entonces, ¿cuándo usamos la codificación de etiquetas? La codificación de etiquetas se utiliza en uno o ambos de los siguientes casos:\n", + "1. Cuando el número de categorías es grande.\n", "2. Cuando las categorías tienen un orden.\n" ] }, @@ -3091,11 +3104,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**CODIFICACIÓN ONE HOT**\n", + "**ONE HOT ENCODING**\n", "\n", - "Otro tipo de codificación es la Codificación One Hot. En este tipo de codificación, cada categoría de la columna se agrega como una columna separada y cada punto de datos recibirá un 0 o un 1 dependiendo de si contiene esa categoría. Por lo tanto, si hay n categorías diferentes, se añadirán n columnas al dataframe.\n", + "Otro tipo de codificación es One Hot Encoding. En este tipo de codificación, cada categoría de la columna se agrega como una columna separada y cada dato recibirá un 0 o un 1 dependiendo de si contiene esa categoría. Por lo tanto, si hay n categorías diferentes, se añadirán n columnas al dataframe.\n", "\n", - "Por ejemplo, tomemos el mismo ejemplo de clases de avión. Las categorías eran: ['business class', 'economy class', 'first class']. Entonces, si realizamos la codificación one hot, se agregarán las siguientes tres columnas al conjunto de datos: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Por ejemplo, tomemos el mismo ejemplo de clases de avión. Las categorías eran: ['business class', 'economy class', 'first class']. Entonces, si realizamos One Hot Encoding, se agregarán las siguientes tres columnas al conjunto de datos: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3328,7 +3341,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Cada columna codificada en caliente contiene 0 o 1, lo que especifica si esa categoría existe para ese punto de datos.\n" + "Cada columna codificada en formato one-hot contiene 0 o 1, lo que especifica si esa categoría existe para ese punto de datos.\n" ] }, { @@ -3349,9 +3362,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Puntos clave: \n", - "1. La codificación se utiliza para convertir datos no numéricos en datos numéricos. \n", - "2. Existen dos tipos de codificación: Codificación de etiquetas (Label encoding) y Codificación One Hot (One Hot encoding), ambas pueden realizarse según las necesidades del conjunto de datos. \n" + "> Puntos clave:\n", + "1. La codificación se realiza para convertir datos no numéricos en datos numéricos.\n", + "2. Hay dos tipos de codificación: codificación de etiquetas y codificación One Hot, ambas pueden realizarse según las necesidades del conjunto de datos.\n" ] }, { @@ -3362,7 +3375,7 @@ "source": [ "## Eliminando datos duplicados\n", "\n", - "> **Objetivo de aprendizaje:** Al final de esta subsección, deberías sentirte cómodo identificando y eliminando valores duplicados de DataFrames.\n", + "> **Objetivo de aprendizaje:** Al final de esta subsección, deberías sentirte cómodo identificando y eliminando valores duplicados de los DataFrames.\n", "\n", "Además de los datos faltantes, a menudo encontrarás datos duplicados en conjuntos de datos del mundo real. Afortunadamente, pandas ofrece una forma sencilla de detectar y eliminar entradas duplicadas.\n" ] @@ -3375,7 +3388,7 @@ "source": [ "### Identificando duplicados: `duplicated`\n", "\n", - "Puedes identificar fácilmente valores duplicados utilizando el método `duplicated` en pandas, el cual devuelve una máscara booleana que indica si una entrada en un `DataFrame` es un duplicado de una anterior. Vamos a crear otro ejemplo de `DataFrame` para ver esto en acción.\n" + "Puedes identificar fácilmente valores duplicados utilizando el método `duplicated` en pandas, que devuelve una máscara booleana indicando si un registro en un `DataFrame` es un duplicado de uno anterior. Vamos a crear otro ejemplo de `DataFrame` para ver esto en acción.\n" ] }, { @@ -3664,7 +3677,525 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Conclusión:** Eliminar datos duplicados es una parte esencial de casi todos los proyectos de ciencia de datos. Los datos duplicados pueden alterar los resultados de tus análisis y proporcionarte resultados inexactos.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Verificación de calidad de datos en el mundo real\n", + "\n", + "> **Objetivo de aprendizaje:** Al finalizar esta sección, deberías sentirte cómodo detectando y corrigiendo problemas comunes de calidad de datos en el mundo real, incluyendo valores categóricos inconsistentes, valores numéricos anormales (valores atípicos) y entidades duplicadas con variaciones.\n", + "\n", + "Aunque los valores faltantes y los duplicados exactos son problemas comunes, los conjuntos de datos del mundo real suelen contener problemas más sutiles:\n", + "\n", + "1. **Valores categóricos inconsistentes**: La misma categoría escrita de manera diferente (por ejemplo, \"USA\", \"U.S.A\", \"United States\").\n", + "2. **Valores numéricos anormales**: Valores extremos que indican errores de entrada de datos (por ejemplo, edad = 999).\n", + "3. **Filas casi duplicadas**: Registros que representan la misma entidad con ligeras variaciones.\n", + "\n", + "Exploremos técnicas para detectar y manejar estos problemas.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Creando un Conjunto de Datos \"Sucio\" de Ejemplo\n", + "\n", + "Primero, vamos a crear un conjunto de datos de ejemplo que contenga los tipos de problemas que comúnmente encontramos en datos del mundo real:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Detectar valores categóricos inconsistentes\n", + "\n", + "Observa que la columna `country` tiene múltiples representaciones para los mismos países. Vamos a identificar estas inconsistencias:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Estandarización de Valores Categóricos\n", + "\n", + "Podemos crear un mapeo para estandarizar estos valores. Un enfoque sencillo es convertirlos a minúsculas y crear un diccionario de mapeo:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternativa: Usar coincidencia difusa**\n", + "\n", + "Para casos más complejos, podemos usar la coincidencia de cadenas difusa con la biblioteca `rapidfuzz` para detectar automáticamente cadenas similares:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Detectar valores numéricos anormales (Outliers)\n", + "\n", + "Al observar la columna `age`, encontramos algunos valores sospechosos como 199 y -5. Utilicemos métodos estadísticos para detectar estos outliers.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Usando el método IQR (Rango Intercuartílico)\n", + "\n", + "El método IQR es una técnica estadística robusta para la detección de valores atípicos que es menos sensible a valores extremos:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Usando el Método Z-Score\n", + "\n", + "El método Z-score identifica valores atípicos basándose en desviaciones estándar respecto a la media:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Manejo de valores atípicos\n", + "\n", + "Una vez detectados, los valores atípicos pueden manejarse de varias maneras:\n", + "1. **Eliminar**: Eliminar filas con valores atípicos (si son errores)\n", + "2. **Limitar**: Reemplazar con valores límite\n", + "3. **Reemplazar con NaN**: Tratar como datos faltantes y usar técnicas de imputación\n", + "4. **Conservar**: Si son valores extremos legítimos\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Detectando Filas Casi Duplicadas\n", + "\n", + "Observa que nuestro conjunto de datos tiene múltiples entradas para \"John Smith\" con valores ligeramente diferentes. Identifiquemos posibles duplicados basándonos en la similitud de nombres.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Encontrar casi duplicados con coincidencia difusa\n", + "\n", + "Para una detección de duplicados más avanzada, podemos usar coincidencia difusa para encontrar nombres similares:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Manejo de duplicados\n", + "\n", + "Una vez identificados, debes decidir cómo manejar los duplicados:\n", + "1. **Mantener la primera ocurrencia**: Usa `drop_duplicates(keep='first')`\n", + "2. **Mantener la última ocurrencia**: Usa `drop_duplicates(keep='last')`\n", + "3. **Agregar información**: Combina la información de las filas duplicadas\n", + "4. **Revisión manual**: Marca para revisión humana\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Resumen: Pipeline Completo de Limpieza de Datos\n", + "\n", + "Vamos a reunir todo en un pipeline integral de limpieza:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Ejercicio de Desafío\n", + "\n", + "¡Ahora es tu turno! A continuación, tienes una nueva fila de datos con múltiples problemas de calidad. ¿Puedes:\n", + "\n", + "1. Identificar todos los problemas en esta fila\n", + "2. Escribir código para corregir cada problema\n", + "3. Agregar la fila corregida al conjunto de datos\n", + "\n", + "Aquí están los datos problemáticos:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Puntos clave\n", + "\n", + "1. **Categorías inconsistentes** son comunes en datos del mundo real. Siempre revisa los valores únicos y estandarízalos utilizando mapeos o coincidencias difusas.\n", + "\n", + "2. **Valores atípicos** pueden afectar significativamente tu análisis. Usa conocimiento del dominio combinado con métodos estadísticos (IQR, puntuación Z) para detectarlos.\n", + "\n", + "3. **Casi duplicados** son más difíciles de detectar que los duplicados exactos. Considera usar coincidencias difusas y normalizar los datos (convertir a minúsculas, eliminar espacios) para identificarlos.\n", + "\n", + "4. **La limpieza de datos es iterativa**. Es posible que necesites aplicar múltiples técnicas y revisar los resultados antes de finalizar tu conjunto de datos limpio.\n", + "\n", + "5. **Documenta tus decisiones**. Lleva un registro de los pasos de limpieza que aplicaste y por qué, ya que esto es importante para la reproducibilidad y la transparencia.\n", + "\n", + "> **Mejor práctica:** Siempre conserva una copia de tus datos originales \"sucios\". Nunca sobrescribas tus archivos de datos fuente; crea versiones limpias con convenciones de nombres claras como `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", @@ -3698,8 +4229,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:37:59+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T18:56:03+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "es" } diff --git a/translations/fa/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/fa/2-Working-With-Data/08-data-preparation/notebook.ipynb index ddb191c6..e8a5c0d8 100644 --- a/translations/fa/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/fa/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,13 +8,13 @@ "source": [ "# آماده‌سازی داده‌ها\n", "\n", - "[منبع دفترچه اصلی از *علم داده: مقدمه‌ای بر یادگیری ماشین برای علم داده، پایتون و ماشین لرنینگ استودیو توسط لی استات*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[منبع دفترچه اصلی از *علم داده: مقدمه‌ای بر یادگیری ماشین برای علم داده، پایتون و ماشین لرنینگ استودیو نوشته لی استات*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## بررسی اطلاعات `DataFrame`\n", "\n", - "> **هدف یادگیری:** تا پایان این بخش، باید بتوانید اطلاعات کلی درباره داده‌های ذخیره‌شده در `DataFrame`های pandas را پیدا کنید.\n", + "> **هدف یادگیری:** تا پایان این بخش، باید بتوانید اطلاعات کلی درباره داده‌های ذخیره‌شده در DataFrameهای pandas را پیدا کنید.\n", "\n", - "وقتی داده‌های خود را در pandas بارگذاری کردید، احتمالاً داده‌ها در یک `DataFrame` قرار خواهند گرفت. اما اگر مجموعه داده در `DataFrame` شما شامل ۶۰,۰۰۰ سطر و ۴۰۰ ستون باشد، چگونه می‌توانید حتی شروع به درک آنچه با آن کار می‌کنید کنید؟ خوشبختانه، pandas ابزارهای مناسبی برای مشاهده سریع اطلاعات کلی درباره یک `DataFrame`، علاوه بر چند سطر اول و آخر، ارائه می‌دهد.\n", + "وقتی داده‌های خود را در pandas بارگذاری کردید، احتمالاً در قالب یک `DataFrame` خواهند بود. اما اگر مجموعه داده در `DataFrame` شما شامل ۶۰,۰۰۰ سطر و ۴۰۰ ستون باشد، چگونه می‌توانید حتی شروع به درک آنچه با آن کار می‌کنید کنید؟ خوشبختانه، pandas ابزارهای مناسبی برای مشاهده سریع اطلاعات کلی درباره یک `DataFrame` و همچنین چند سطر اول و آخر آن ارائه می‌دهد.\n", "\n", "برای بررسی این قابلیت‌ها، ما کتابخانه scikit-learn پایتون را وارد می‌کنیم و از یک مجموعه داده نمادین استفاده می‌کنیم که هر دانشمند داده‌ای صدها بار آن را دیده است: مجموعه داده *Iris* زیست‌شناس بریتانیایی رونالد فیشر که در مقاله سال ۱۹۳۶ او با عنوان \"استفاده از اندازه‌گیری‌های متعدد در مسائل طبقه‌بندی\" استفاده شده است:\n" ] @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "ما مجموعه داده Iris را در متغیر `iris_df` بارگذاری کرده‌ایم. قبل از اینکه به داده‌ها بپردازیم، ارزشمند است که بدانیم چه تعداد نقاط داده داریم و اندازه کلی مجموعه داده چقدر است. بررسی حجم داده‌هایی که با آن‌ها سروکار داریم مفید است.\n" + "ما مجموعه داده Iris را در متغیر `iris_df` بارگذاری کرده‌ایم. پیش از بررسی داده‌ها، دانستن تعداد نقاط داده‌ای که داریم و اندازه کلی مجموعه داده ارزشمند خواهد بود. نگاه کردن به حجم داده‌هایی که با آن‌ها سروکار داریم مفید است.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "ما با ۱۵۰ ردیف و ۴ ستون داده سروکار داریم. هر ردیف نشان‌دهنده یک نقطه داده است و هر ستون یک ویژگی مرتبط با قاب داده را نشان می‌دهد. بنابراین، اساساً ۱۵۰ نقطه داده وجود دارد که هر کدام شامل ۴ ویژگی هستند.\n", + "بنابراین، ما با ۱۵۰ ردیف و ۴ ستون داده سروکار داریم. هر ردیف نشان‌دهنده یک نقطه داده است و هر ستون یک ویژگی مرتبط با داده‌ها را نشان می‌دهد. به‌طور کلی، ۱۵۰ نقطه داده وجود دارد که هر کدام شامل ۴ ویژگی هستند.\n", "\n", - "`shape` در اینجا یک ویژگی از قاب داده است و نه یک تابع، به همین دلیل با یک جفت پرانتز پایان نمی‌یابد.\n" + "`shape` در اینجا یک ویژگی از دیتافریم است و نه یک تابع، به همین دلیل با یک جفت پرانتز پایان نمی‌یابد.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "حالا بیایید به ۴ ستون داده بپردازیم. هر کدام از این ستون‌ها دقیقاً چه چیزی را نشان می‌دهند؟ ویژگی `columns` نام ستون‌های موجود در دیتافریم را به ما می‌دهد.\n" + "حالا بیایید به ۴ ستون داده بپردازیم. هر کدام از این ستون‌ها دقیقاً چه چیزی را نشان می‌دهند؟ ویژگی `columns` نام ستون‌ها در دیتافریم را به ما می‌دهد.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "همانطور که می‌بینیم، چهار (۴) ستون وجود دارد. ویژگی `columns` نام ستون‌ها را به ما می‌گوید و اساساً چیز دیگری نمی‌گوید. این ویژگی زمانی اهمیت پیدا می‌کند که بخواهیم ویژگی‌های موجود در یک مجموعه داده را شناسایی کنیم.\n" + "همانطور که می‌بینیم، چهار (۴) ستون وجود دارد. ویژگی `columns` نام ستون‌ها را به ما می‌گوید و اساساً چیز دیگری را نشان نمی‌دهد. این ویژگی زمانی اهمیت پیدا می‌کند که بخواهیم ویژگی‌های موجود در یک مجموعه داده را شناسایی کنیم.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "از اینجا می‌توان چند مشاهده انجام داد: \n", - "1. نوع داده هر ستون: در این مجموعه داده، تمام داده‌ها به صورت اعداد اعشاری ۶۴ بیتی ذخیره شده‌اند. \n", - "2. تعداد مقادیر غیر تهی: رسیدگی به مقادیر تهی یک گام مهم در آماده‌سازی داده‌ها است. این موضوع در ادامه در نوت‌بوک بررسی خواهد شد. \n" + "از اینجا می‌توان چند مشاهده انجام داد:\n", + "1. نوع داده هر ستون: در این مجموعه داده، تمام داده‌ها به صورت اعداد اعشاری 64 بیتی ذخیره شده‌اند.\n", + "2. تعداد مقادیر غیر تهی: رسیدگی به مقادیر تهی یک مرحله مهم در آماده‌سازی داده‌ها است. این موضوع در ادامه در نوت‌بوک بررسی خواهد شد.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "فرض کنید داده‌های عددی زیادی در مجموعه داده خود داریم. محاسبات آماری تک‌متغیره مانند میانگین، میانه، چارک‌ها و غیره می‌توانند به صورت جداگانه بر روی هر ستون انجام شوند. تابع `DataFrame.describe()` خلاصه‌ای آماری از ستون‌های عددی یک مجموعه داده را در اختیار ما قرار می‌دهد.\n" + "فرض کنید داده‌های عددی زیادی در مجموعه داده خود داریم. محاسبات آماری تک‌متغیره مانند میانگین، میانه، چارک‌ها و غیره را می‌توان به‌صورت جداگانه روی هر یک از ستون‌ها انجام داد. تابع `DataFrame.describe()` خلاصه‌ای آماری از ستون‌های عددی مجموعه داده را در اختیار ما قرار می‌دهد.\n" ] }, { @@ -332,7 +332,7 @@ }, "source": [ "### `DataFrame.head`\n", - "با استفاده از تمام توابع و ویژگی‌های بالا، ما یک نمای کلی از مجموعه داده‌ها به دست آورده‌ایم. می‌دانیم که چند نقطه داده وجود دارد، چند ویژگی وجود دارد، نوع داده هر ویژگی چیست و تعداد مقادیر غیر تهی برای هر ویژگی چقدر است.\n", + "با تمام توابع و ویژگی‌های بالا، ما یک دید کلی از مجموعه داده‌ها به دست آورده‌ایم. می‌دانیم که چند نقطه داده وجود دارد، چند ویژگی وجود دارد، نوع داده هر ویژگی چیست و تعداد مقادیر غیر تهی برای هر ویژگی چقدر است.\n", "\n", "حالا وقت آن است که خود داده‌ها را بررسی کنیم. بیایید ببینیم چند سطر اول (چند نقطه داده اول) از `DataFrame` ما چگونه به نظر می‌رسند:\n" ] @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "در خروجی اینجا، می‌توانیم پنج (۵) ورودی از مجموعه داده را ببینیم. اگر به شاخص در سمت چپ نگاه کنیم، متوجه می‌شویم که این‌ها پنج ردیف اول هستند.\n" + "همانطور که در خروجی اینجا مشاهده می‌کنیم، پنج (۵) ورودی از مجموعه داده‌ها وجود دارد. اگر به شاخص در سمت چپ نگاه کنیم، متوجه می‌شویم که این‌ها پنج ردیف اول هستند.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### تمرین:\n", "\n", - "از مثال داده‌شده در بالا مشخص است که به‌طور پیش‌فرض، `DataFrame.head` پنج ردیف اول یک `DataFrame` را برمی‌گرداند. آیا می‌توانید در سلول کد زیر راهی پیدا کنید که بیش از پنج ردیف را نمایش دهد؟\n" + "از مثال داده شده در بالا مشخص است که به طور پیش‌فرض، `DataFrame.head` پنج ردیف اول یک `DataFrame` را برمی‌گرداند. آیا می‌توانید در سلول کد زیر راهی پیدا کنید که بیش از پنج ردیف را نمایش دهد؟\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "راه دیگری برای مشاهده داده‌ها می‌تواند از انتها (به جای ابتدا) باشد. معادل مخالف `DataFrame.head`، تابع `DataFrame.tail` است که پنج ردیف آخر یک `DataFrame` را برمی‌گرداند:\n" + "راه دیگری برای مشاهده داده‌ها می‌تواند از انتها (به جای ابتدا) باشد. نقطه مقابل `DataFrame.head`، `DataFrame.tail` است که پنج ردیف آخر یک `DataFrame` را برمی‌گرداند:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "در عمل، مفید است که بتوانید به راحتی چند ردیف اول یا آخر یک `DataFrame` را بررسی کنید، به خصوص زمانی که به دنبال نقاط دورافتاده در مجموعه داده‌های مرتب شده هستید.\n", + "در عمل، مفید است که بتوانید به راحتی چند سطر اول یا چند سطر آخر یک `DataFrame` را بررسی کنید، به‌ویژه زمانی که به دنبال نقاط دورافتاده در مجموعه داده‌های مرتب شده هستید.\n", "\n", - "تمام توابع و ویژگی‌هایی که در بالا با کمک مثال‌های کد نشان داده شده‌اند، به ما کمک می‌کنند تا نمای کلی و حس داده‌ها را دریافت کنیم.\n", + "تمام توابع و ویژگی‌هایی که در بالا با کمک مثال‌های کد نشان داده شدند، به ما کمک می‌کنند تا نگاهی کلی به داده‌ها داشته باشیم.\n", "\n", - "> **نکته کلیدی:** حتی فقط با نگاه کردن به فراداده‌های مربوط به اطلاعات در یک DataFrame یا چند مقدار اول و آخر آن، می‌توانید فوراً ایده‌ای درباره اندازه، شکل و محتوای داده‌هایی که با آن‌ها سروکار دارید، به دست آورید.\n" + "> **نکته مهم:** حتی فقط با نگاه کردن به فراداده‌های مربوط به اطلاعات در یک DataFrame یا چند مقدار اول و آخر آن، می‌توانید فوراً ایده‌ای درباره اندازه، شکل و محتوای داده‌هایی که با آن‌ها سروکار دارید، به دست آورید.\n" ] }, { @@ -598,15 +598,15 @@ "### داده‌های گمشده\n", "بیایید به موضوع داده‌های گمشده بپردازیم. داده‌های گمشده زمانی رخ می‌دهند که هیچ مقداری در برخی از ستون‌ها ذخیره نشده باشد.\n", "\n", - "بیایید یک مثال بزنیم: فرض کنید کسی به وزن خود حساس است و فیلد وزن را در یک نظرسنجی پر نمی‌کند. در این صورت، مقدار وزن برای آن شخص خاص گمشده خواهد بود.\n", + "بیایید یک مثال بزنیم: فرض کنید کسی نسبت به وزن خود حساس است و فیلد وزن را در یک نظرسنجی پر نمی‌کند. در این صورت، مقدار وزن برای آن فرد خاص گم خواهد بود.\n", "\n", - "در اکثر مواقع، در مجموعه داده‌های دنیای واقعی، مقادیر گمشده وجود دارند.\n", + "در اکثر مواقع، در مجموعه داده‌های دنیای واقعی، مقادیر گمشده رخ می‌دهند.\n", "\n", - "**چگونگی مدیریت داده‌های گمشده توسط Pandas**\n", + "**نحوه مدیریت داده‌های گمشده توسط Pandas**\n", "\n", - "Pandas داده‌های گمشده را به دو روش مدیریت می‌کند. اولین روش که قبلاً در بخش‌های قبلی دیده‌اید: `NaN`، یا Not a Number. این در واقع یک مقدار خاص است که بخشی از مشخصات IEEE برای اعداد اعشاری است و فقط برای نشان دادن مقادیر گمشده اعشاری استفاده می‌شود.\n", + "Pandas داده‌های گمشده را به دو روش مدیریت می‌کند. اولین روش که قبلاً در بخش‌های قبلی دیده‌اید: `NaN` یا Not a Number. این در واقع یک مقدار خاص است که بخشی از مشخصات IEEE برای اعداد اعشاری است و فقط برای نشان دادن مقادیر گمشده اعشاری استفاده می‌شود.\n", "\n", - "برای مقادیر گمشده‌ای که اعشاری نیستند، pandas از شیء `None` در پایتون استفاده می‌کند. اگرچه ممکن است گیج‌کننده به نظر برسد که با دو نوع مقدار مختلف مواجه شوید که اساساً یک چیز را بیان می‌کنند، اما دلایل منطقی برنامه‌نویسی برای این انتخاب طراحی وجود دارد و در عمل، این رویکرد به pandas اجازه می‌دهد تا در اکثر موارد یک تعادل مناسب ارائه دهد. با این حال، هم `None` و هم `NaN` محدودیت‌هایی دارند که باید نسبت به نحوه استفاده از آن‌ها آگاه باشید.\n" + "برای مقادیر گمشده غیر از اعداد اعشاری، pandas از شیء `None` در پایتون استفاده می‌کند. ممکن است گیج‌کننده به نظر برسد که با دو نوع مقدار مواجه شوید که اساساً یک چیز را بیان می‌کنند، اما دلایل برنامه‌نویسی منطقی برای این انتخاب طراحی وجود دارد و در عمل، این رویکرد به pandas امکان می‌دهد تا برای اکثر موارد یک سازش خوب ارائه دهد. با این حال، هر دو `None` و `NaN` محدودیت‌هایی دارند که باید در مورد نحوه استفاده از آن‌ها به آن‌ها توجه کنید.\n" ] }, { @@ -616,8 +616,7 @@ }, "source": [ "### `None`: داده‌های گمشده غیر شناور\n", - "\n", - "از آنجا که `None` از زبان پایتون می‌آید، نمی‌توان از آن در آرایه‌های NumPy و pandas که نوع داده آن‌ها `'object'` نیست استفاده کرد. به یاد داشته باشید، آرایه‌های NumPy (و ساختارهای داده‌ای در pandas) فقط می‌توانند یک نوع داده را در خود جای دهند. این ویژگی قدرت فوق‌العاده‌ای به آن‌ها برای کارهای داده‌ای و محاسباتی در مقیاس بزرگ می‌دهد، اما انعطاف‌پذیری آن‌ها را نیز محدود می‌کند. چنین آرایه‌هایی باید به \"پایین‌ترین مخرج مشترک\" تبدیل شوند، یعنی نوع داده‌ای که همه چیز در آرایه را در بر می‌گیرد. وقتی `None` در آرایه باشد، به این معناست که شما با اشیاء پایتون کار می‌کنید.\n", + "از آنجا که `None` از زبان پایتون می‌آید، نمی‌توان از آن در آرایه‌های NumPy و pandas که نوع داده آن‌ها `'object'` نیست استفاده کرد. به یاد داشته باشید که آرایه‌های NumPy (و ساختارهای داده‌ای در pandas) فقط می‌توانند یک نوع داده را در خود جای دهند. این ویژگی قدرت فوق‌العاده‌ای به آن‌ها برای کار با داده‌های بزرگ و محاسبات می‌دهد، اما انعطاف‌پذیری آن‌ها را نیز محدود می‌کند. چنین آرایه‌هایی باید به \"پایین‌ترین مخرج مشترک\" ارتقا یابند، یعنی نوع داده‌ای که همه چیز در آرایه را در بر می‌گیرد. وقتی `None` در آرایه باشد، به این معناست که شما با اشیاء پایتون کار می‌کنید.\n", "\n", "برای مشاهده این موضوع در عمل، به آرایه نمونه زیر توجه کنید (به `dtype` آن دقت کنید):\n" ] @@ -658,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "واقعیت نوع داده‌های ارتقا یافته دو اثر جانبی به همراه دارد. اول، عملیات‌ها در سطح کد تفسیر شده پایتون انجام می‌شوند، نه کد کامپایل شده NumPy. به طور کلی، این بدان معناست که هر عملیاتی که شامل `Series` یا `DataFrames` با مقدار `None` باشد، کندتر خواهد بود. اگرچه احتمالاً این کاهش عملکرد را متوجه نخواهید شد، اما برای مجموعه داده‌های بزرگ ممکن است به یک مشکل تبدیل شود.\n", + "واقعیت نوع‌های داده‌ای که به بالا تبدیل می‌شوند، دو اثر جانبی به همراه دارد. اول، عملیات‌ها در سطح کد تفسیر شده‌ی پایتون انجام می‌شوند، نه کد کامپایل شده‌ی NumPy. به طور کلی، این به این معناست که هر عملیاتی که شامل `Series` یا `DataFrames` با مقدار `None` باشد، کندتر خواهد بود. اگرچه احتمالاً این کاهش عملکرد را متوجه نخواهید شد، اما برای مجموعه داده‌های بزرگ ممکن است به یک مشکل تبدیل شود.\n", "\n", - "اثر جانبی دوم از اثر اول ناشی می‌شود. از آنجا که `None` اساساً `Series` یا `DataFrame`ها را به دنیای پایتون معمولی بازمی‌گرداند، استفاده از توابع تجمیعی NumPy/pandas مانند `sum()` یا `min()` بر روی آرایه‌هایی که شامل مقدار `None` هستند، معمولاً منجر به خطا خواهد شد:\n" + "اثر جانبی دوم از اثر اول ناشی می‌شود. از آنجا که `None` اساساً `Series` یا `DataFrame`ها را به دنیای پایتون معمولی بازمی‌گرداند، استفاده از تجمیع‌های NumPy/pandas مانند `sum()` یا `min()` بر روی آرایه‌هایی که شامل مقدار ``None`` هستند، معمولاً منجر به خطا خواهد شد:\n" ] }, { @@ -708,9 +707,9 @@ "id": "pWvVHvETgRr9" }, "source": [ - "### `NaN`: مقادیر اعشاری گمشده\n", + "### `NaN`: مقادیر شناور گم‌شده\n", "\n", - "برخلاف `None`، NumPy (و به تبع آن pandas) از `NaN` برای عملیات سریع، برداری و ufuncها پشتیبانی می‌کند. خبر بد این است که هر عملیات ریاضی که روی `NaN` انجام شود، همیشه نتیجه‌اش `NaN` خواهد بود. برای مثال:\n" + "برخلاف `None`، NumPy (و به تبع آن pandas) از `NaN` برای عملیات سریع، برداری و ufunc‌ها پشتیبانی می‌کند. خبر بد این است که هر عملیات ریاضی که روی `NaN` انجام شود، همیشه نتیجه‌اش `NaN` خواهد بود. برای مثال:\n" ] }, { @@ -773,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "خبر خوب: تجمع‌ها که بر روی آرایه‌هایی با `NaN` اجرا می‌شوند، خطا ایجاد نمی‌کنند. خبر بد: نتایج به طور یکنواخت مفید نیستند:\n" + "خبر خوب: تجمیع‌ها که بر روی آرایه‌هایی با `NaN` اجرا می‌شوند، خطا ایجاد نمی‌کنند. خبر بد: نتایج به طور یکنواخت مفید نیستند:\n" ] }, { @@ -810,7 +809,7 @@ "id": "nhlnNJT7gRr_" }, "source": [ - "تمرین:\n" + "### تمرین:\n" ] }, { @@ -843,7 +842,7 @@ "source": [ "### `NaN` و `None`: مقادیر null در pandas\n", "\n", - "با اینکه `NaN` و `None` ممکن است رفتار کمی متفاوتی داشته باشند، pandas به گونه‌ای طراحی شده است که بتواند با آنها به صورت جایگزین کار کند. برای درک بهتر، یک `Series` از اعداد صحیح را در نظر بگیرید:\n" + "با اینکه `NaN` و `None` ممکن است رفتار کمی متفاوتی داشته باشند، pandas به گونه‌ای طراحی شده است که بتواند با آن‌ها به صورت جایگزین کار کند. برای درک بهتر این موضوع، یک `Series` از اعداد صحیح را در نظر بگیرید:\n" ] }, { @@ -883,7 +882,7 @@ "id": "WklCzqb8gRsB" }, "source": [ - "تمرین:\n" + "### تمرین:\n" ] }, { @@ -907,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "در فرآیند ارتقای نوع داده‌ها برای ایجاد یکنواختی در `Series` و `DataFrame`ها، pandas به راحتی مقادیر گمشده را بین `None` و `NaN` جابه‌جا می‌کند. به دلیل این ویژگی طراحی، مفید است که به `None` و `NaN` به عنوان دو نوع مختلف از \"تهی\" در pandas فکر کنید. در واقع، برخی از متدهای اصلی که برای کار با مقادیر گمشده در pandas استفاده می‌کنید، این ایده را در نام‌های خود منعکس می‌کنند:\n", + "در فرآیند ارتقای نوع داده‌ها برای ایجاد یکنواختی داده‌ها در `Series` و `DataFrame`ها، pandas به راحتی مقادیر گمشده را بین `None` و `NaN` تغییر می‌دهد. به دلیل این ویژگی طراحی، مفید است که به `None` و `NaN` به عنوان دو نوع مختلف از \"null\" در pandas فکر کنید. در واقع، برخی از روش‌های اصلی که برای مدیریت مقادیر گمشده در pandas استفاده می‌کنید، این ایده را در نام‌های خود منعکس می‌کنند:\n", "\n", - "- `isnull()`: یک ماسک بولی تولید می‌کند که مقادیر گمشده را نشان می‌دهد\n", - "- `notnull()`: برعکس `isnull()`\n", + "- `isnull()`: یک ماسک بولی ایجاد می‌کند که مقادیر گمشده را نشان می‌دهد\n", + "- `notnull()`: مخالف `isnull()`\n", "- `dropna()`: نسخه‌ای فیلتر شده از داده‌ها را برمی‌گرداند\n", - "- `fillna()`: نسخه‌ای از داده‌ها را با مقادیر گمشده پر شده یا جایگزین شده برمی‌گرداند\n", + "- `fillna()`: نسخه‌ای از داده‌ها را با مقادیر گمشده پر شده یا تخمین زده شده برمی‌گرداند\n", "\n", - "این متدها بسیار مهم هستند و باید در استفاده از آن‌ها مهارت پیدا کنید، بنابراین بیایید هر یک را با جزئیات بیشتری بررسی کنیم.\n" + "این روش‌ها بسیار مهم هستند و باید در استفاده از آنها مهارت پیدا کنید، بنابراین بیایید هر کدام را به طور عمیق بررسی کنیم.\n" ] }, { @@ -925,8 +924,8 @@ "source": [ "### شناسایی مقادیر null\n", "\n", - "حالا که اهمیت مقادیر گمشده را درک کردیم، باید قبل از رسیدگی به آن‌ها، این مقادیر را در مجموعه داده خود شناسایی کنیم. \n", - "هر دو متد `isnull()` و `notnull()` روش‌های اصلی شما برای شناسایی داده‌های null هستند. هر دو یک ماسک بولی روی داده‌های شما برمی‌گردانند.\n" + "حالا که اهمیت مقادیر گمشده را درک کردیم، باید قبل از رسیدگی به آن‌ها، آن‌ها را در مجموعه داده خود شناسایی کنیم. \n", + "هم `isnull()` و هم `notnull()` روش‌های اصلی شما برای شناسایی داده‌های null هستند. هر دو ماسک‌های بولی را بر روی داده‌های شما برمی‌گردانند.\n" ] }, { @@ -979,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "به خروجی دقت کنید. آیا چیزی شما را شگفت‌زده می‌کند؟ در حالی که `0` یک مقدار عددی صفر است، همچنان یک عدد صحیح معتبر محسوب می‌شود و pandas آن را به همین شکل در نظر می‌گیرد. `''` کمی پیچیده‌تر است. در بخش ۱ از آن برای نمایش یک رشته خالی استفاده کردیم، اما همچنان یک شیء رشته‌ای است و از نظر pandas به عنوان مقدار null در نظر گرفته نمی‌شود.\n", + "به خروجی با دقت نگاه کنید. آیا چیزی شما را شگفت‌زده می‌کند؟ در حالی که `0` یک مقدار عددی null است، با این حال یک عدد صحیح کاملاً معتبر است و pandas آن را به همین شکل در نظر می‌گیرد. `''` کمی پیچیده‌تر است. در بخش ۱ از آن برای نشان دادن یک مقدار رشته‌ای خالی استفاده کردیم، اما با این حال یک شیء رشته‌ای است و از نظر pandas به عنوان null در نظر گرفته نمی‌شود.\n", "\n", - "حالا بیایید این موضوع را از زاویه دیگری بررسی کنیم و این روش‌ها را به شکلی که در عمل بیشتر استفاده می‌کنید، به کار ببریم. شما می‌توانید ماسک‌های بولی را مستقیماً به عنوان یک شاخص ``Series`` یا ``DataFrame`` استفاده کنید، که می‌تواند زمانی که می‌خواهید با مقادیر گم‌شده (یا موجود) جداگانه کار کنید، مفید باشد.\n", + "حالا بیایید این موضوع را برعکس کنیم و این روش‌ها را به شکلی که در عمل بیشتر استفاده می‌کنید، به کار ببریم. شما می‌توانید ماسک‌های بولی را مستقیماً به عنوان یک ``Series`` یا ``DataFrame`` ایندکس استفاده کنید، که می‌تواند زمانی که می‌خواهید با مقادیر گم‌شده (یا موجود) جداگانه کار کنید، مفید باشد.\n", "\n", - "اگر بخواهیم تعداد کل مقادیر گم‌شده را بدانیم، می‌توانیم به سادگی یک جمع روی ماسکی که توسط متد `isnull()` تولید شده است، انجام دهیم.\n" + "اگر بخواهیم تعداد کل مقادیر گم‌شده را بدانیم، می‌توانیم فقط یک جمع روی ماسکی که توسط متد `isnull()` تولید شده است، انجام دهیم.\n" ] }, { @@ -1018,7 +1017,7 @@ "id": "PlBqEo3mgRsC" }, "source": [ - "تمرین:\n" + "### تمرین:\n" ] }, { @@ -1041,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**نکته کلیدی**: هر دو متد `isnull()` و `notnull()` نتایج مشابهی را هنگام استفاده در DataFrame‌ها تولید می‌کنند: آن‌ها نتایج و شاخص آن نتایج را نشان می‌دهند، که این موضوع هنگام کار با داده‌هایتان کمک بزرگی به شما خواهد کرد.\n" + "**نکته کلیدی**: هر دو روش `isnull()` و `notnull()` نتایج مشابهی را هنگام استفاده در DataFrames تولید می‌کنند: آنها نتایج و شاخص آن نتایج را نشان می‌دهند، که به شما کمک زیادی خواهد کرد وقتی با داده‌های خود کار می‌کنید.\n" ] }, { @@ -1050,20 +1049,20 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### مقابله با داده‌های گمشده\n", + "### برخورد با داده‌های گمشده\n", "\n", - "> **هدف یادگیری:** تا پایان این بخش، باید بدانید چگونه و چه زمانی مقادیر null را در DataFrame‌ها جایگزین یا حذف کنید.\n", + "> **هدف یادگیری:** تا پایان این بخش، باید بدانید چگونه و چه زمانی مقادیر خالی را در DataFrame‌ها جایگزین یا حذف کنید.\n", "\n", - "مدل‌های یادگیری ماشین نمی‌توانند به‌طور مستقیم با داده‌های گمشده کار کنند. بنابراین، قبل از اینکه داده‌ها را به مدل بدهیم، باید این مقادیر گمشده را مدیریت کنیم.\n", + "مدل‌های یادگیری ماشین نمی‌توانند به‌طور مستقیم با داده‌های گمشده کار کنند. بنابراین، قبل از اینکه داده‌ها را به مدل وارد کنیم، باید این مقادیر گمشده را مدیریت کنیم.\n", "\n", "نحوه مدیریت داده‌های گمشده دارای ملاحظات ظریفی است که می‌تواند بر تحلیل نهایی و نتایج واقعی شما تأثیر بگذارد.\n", "\n", - "به طور کلی دو روش اصلی برای مقابله با داده‌های گمشده وجود دارد:\n", + "به طور کلی دو روش اصلی برای برخورد با داده‌های گمشده وجود دارد:\n", "\n", - "1. حذف سطر حاوی مقدار گمشده\n", + "1. حذف ردیفی که مقدار گمشده دارد\n", "2. جایگزینی مقدار گمشده با یک مقدار دیگر\n", "\n", - "ما هر دو روش را به همراه مزایا و معایب آن‌ها به‌طور کامل بررسی خواهیم کرد.\n" + "ما هر دو روش را به همراه مزایا و معایب آن‌ها به‌طور مفصل بررسی خواهیم کرد.\n" ] }, { @@ -1074,11 +1073,11 @@ "source": [ "### حذف مقادیر تهی\n", "\n", - "مقدار داده‌ای که به مدل خود منتقل می‌کنیم تأثیر مستقیمی بر عملکرد آن دارد. حذف مقادیر تهی به این معناست که تعداد نقاط داده را کاهش می‌دهیم و در نتیجه اندازه مجموعه داده کوچک‌تر می‌شود. بنابراین، توصیه می‌شود زمانی که مجموعه داده بسیار بزرگ است، سطرهایی که دارای مقادیر تهی هستند حذف شوند.\n", + "مقدار داده‌ای که به مدل خود منتقل می‌کنیم تأثیر مستقیمی بر عملکرد آن دارد. حذف مقادیر تهی به این معناست که تعداد نقاط داده را کاهش می‌دهیم و در نتیجه اندازه مجموعه داده کاهش می‌یابد. بنابراین، توصیه می‌شود زمانی که مجموعه داده بسیار بزرگ است، سطرهایی با مقادیر تهی حذف شوند.\n", "\n", - "یک مورد دیگر ممکن است این باشد که یک سطر یا ستون خاص دارای تعداد زیادی مقادیر گم‌شده باشد. در این صورت، ممکن است حذف شوند زیرا به دلیل کمبود داده در آن سطر/ستون، ارزش زیادی به تحلیل ما اضافه نمی‌کنند.\n", + "یک مورد دیگر ممکن است این باشد که یک سطر یا ستون خاص دارای تعداد زیادی مقادیر گم‌شده باشد. در این صورت، ممکن است حذف شوند زیرا به تحلیل ما ارزش زیادی اضافه نمی‌کنند، چون بیشتر داده‌های آن سطر/ستون گم‌شده هستند.\n", "\n", - "علاوه بر شناسایی مقادیر گم‌شده، pandas روشی مناسب برای حذف مقادیر تهی از `Series` و `DataFrame`ها ارائه می‌دهد. برای مشاهده این موضوع در عمل، به `example3` بازمی‌گردیم. تابع `DataFrame.dropna()` به حذف سطرهایی که دارای مقادیر تهی هستند کمک می‌کند.\n" + "علاوه بر شناسایی مقادیر گم‌شده، pandas یک روش مناسب برای حذف مقادیر تهی از `Series` و `DataFrame`ها ارائه می‌دهد. برای مشاهده این موضوع در عمل، بیایید به `example3` برگردیم. تابع `DataFrame.dropna()` در حذف سطرهایی با مقادیر تهی کمک می‌کند.\n" ] }, { @@ -1117,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "توجه داشته باشید که این باید شبیه خروجی شما از `example3[example3.notnull()]` باشد. تفاوت اینجا این است که به جای فقط ایندکس کردن روی مقادیر ماسک‌شده، `dropna` آن مقادیر گمشده را از `Series` `example3` حذف کرده است.\n", + "توجه داشته باشید که این باید شبیه خروجی شما از `example3[example3.notnull()]` باشد. تفاوت اینجا این است که، به جای فقط ایندکس کردن روی مقادیر ماسک شده، `dropna` آن مقادیر گمشده را از `Series` `example3` حذف کرده است.\n", "\n", - "از آنجا که DataFrame‌ها دو بعدی هستند، گزینه‌های بیشتری برای حذف داده‌ها ارائه می‌دهند.\n" + "از آنجا که DataFrame‌ها دو بعدی هستند، گزینه‌های بیشتری برای حذف داده‌ها فراهم می‌کنند.\n" ] }, { @@ -1209,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "آیا متوجه شدید که pandas دو ستون را به نوع داده‌ی float تبدیل کرد تا بتواند مقادیر `NaN` را مدیریت کند؟\n", + "(آیا متوجه شدید که pandas دو ستون را به نوع float تبدیل کرد تا بتواند مقادیر `NaN` را مدیریت کند؟)\n", "\n", - "شما نمی‌توانید یک مقدار واحد را از یک `DataFrame` حذف کنید، بنابراین باید کل ردیف‌ها یا ستون‌ها را حذف کنید. بسته به کاری که انجام می‌دهید، ممکن است بخواهید یکی از این دو را انتخاب کنید، و pandas گزینه‌هایی برای هر دو فراهم می‌کند. از آنجا که در علم داده، ستون‌ها معمولاً نشان‌دهنده متغیرها و ردیف‌ها نشان‌دهنده مشاهدات هستند، احتمال بیشتری وجود دارد که ردیف‌های داده را حذف کنید؛ تنظیم پیش‌فرض برای `dropna()` این است که تمام ردیف‌هایی که شامل هر مقدار null هستند را حذف کند:\n" + "شما نمی‌توانید یک مقدار واحد را از یک `DataFrame` حذف کنید، بنابراین باید کل سطرها یا ستون‌ها را حذف کنید. بسته به کاری که انجام می‌دهید، ممکن است بخواهید یکی از این دو را انجام دهید، و به همین دلیل pandas گزینه‌هایی برای هر دو حالت به شما می‌دهد. از آنجا که در علم داده، ستون‌ها معمولاً متغیرها و سطرها مشاهدات را نشان می‌دهند، احتمال بیشتری وجود دارد که سطرهای داده را حذف کنید؛ تنظیم پیش‌فرض برای `dropna()` این است که تمام سطرهایی که شامل هر مقدار null هستند را حذف کند:\n" ] }, { @@ -1363,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "توجه داشته باشید که این می‌تواند مقدار زیادی از داده‌ها را حذف کند، به‌ویژه در مجموعه داده‌های کوچک‌تر. اگر بخواهید فقط سطرها یا ستون‌هایی را حذف کنید که چند مقدار خالی یا حتی تمام مقادیرشان خالی هستند، چه باید کرد؟ شما می‌توانید این تنظیمات را با استفاده از `dropna` و پارامترهای `how` و `thresh` مشخص کنید.\n", + "توجه داشته باشید که این روش می‌تواند مقدار زیادی از داده‌هایی را که ممکن است بخواهید نگه دارید، به‌ویژه در مجموعه داده‌های کوچک، حذف کند. اگر فقط بخواهید سطرها یا ستون‌هایی را حذف کنید که چند مقدار null یا حتی تمام مقادیرشان null هستند، چه باید کرد؟ شما می‌توانید این تنظیمات را با استفاده از پارامترهای `how` و `thresh` در `dropna` مشخص کنید.\n", "\n", - "به‌صورت پیش‌فرض، `how='any'` است (اگر می‌خواهید خودتان بررسی کنید یا ببینید این متد چه پارامترهای دیگری دارد، دستور `example4.dropna?` را در یک سلول کد اجرا کنید). شما می‌توانید به‌جای آن `how='all'` را مشخص کنید تا فقط سطرها یا ستون‌هایی که تمام مقادیرشان خالی هستند حذف شوند. بیایید مثال `DataFrame` خود را گسترش دهیم تا این موضوع را در تمرین بعدی مشاهده کنیم.\n" + "به‌طور پیش‌فرض، `how='any'` است (اگر می‌خواهید خودتان بررسی کنید یا ببینید این متد چه پارامترهای دیگری دارد، دستور `example4.dropna?` را در یک سلول کد اجرا کنید). به‌طور جایگزین، می‌توانید `how='all'` را مشخص کنید تا فقط سطرها یا ستون‌هایی که تمام مقادیرشان null هستند حذف شوند. بیایید مثال `DataFrame` خود را گسترش دهیم تا این موضوع را در تمرین بعدی مشاهده کنیم.\n" ] }, { @@ -1457,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "نکات کلیدی: \n", + "> نکات کلیدی: \n", "1. حذف مقادیر null تنها زمانی ایده خوبی است که مجموعه داده به اندازه کافی بزرگ باشد. \n", "2. ردیف‌ها یا ستون‌های کامل را می‌توان حذف کرد اگر بیشتر داده‌های آن‌ها از دست رفته باشد. \n", - "3. متد `DataFrame.dropna(axis=)` در حذف مقادیر null کمک می‌کند. آرگومان `axis` مشخص می‌کند که آیا ردیف‌ها باید حذف شوند یا ستون‌ها. \n", - "4. آرگومان `how` نیز قابل استفاده است. به طور پیش‌فرض روی مقدار `any` تنظیم شده است. بنابراین، فقط ردیف‌ها/ستون‌هایی که شامل هر مقدار null هستند حذف می‌شوند. می‌توان آن را روی مقدار `all` تنظیم کرد تا مشخص شود که فقط ردیف‌ها/ستون‌هایی که تمام مقادیرشان null هستند حذف شوند. \n" + "3. متد `DataFrame.dropna(axis=)` برای حذف مقادیر null کمک می‌کند. آرگومان `axis` مشخص می‌کند که آیا ردیف‌ها باید حذف شوند یا ستون‌ها. \n", + "4. آرگومان `how` نیز قابل استفاده است. به طور پیش‌فرض مقدار آن `any` است. بنابراین، فقط ردیف‌ها/ستون‌هایی که شامل هر مقدار null باشند حذف می‌شوند. می‌توان آن را به `all` تنظیم کرد تا مشخص شود که فقط ردیف‌ها/ستون‌هایی که تمام مقادیرشان null هستند حذف شوند. \n" ] }, { @@ -1470,7 +1469,7 @@ "id": "oXXSfQFHgRsF" }, "source": [ - "تمرین:\n" + "### تمرین:\n" ] }, { @@ -1568,7 +1567,7 @@ "id": "fmSFnzZegRsG" }, "source": [ - "اینجا، اولین و آخرین ردیف حذف شده‌اند، زیرا فقط دو مقدار غیر تهی دارند.\n" + "اینجا، اولین و آخرین سطر حذف شده‌اند، زیرا فقط دو مقدار غیر تهی دارند.\n" ] }, { @@ -1577,11 +1576,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### پر کردن مقادیر null\n", + "### پر کردن مقادیر خالی\n", "\n", - "گاهی اوقات منطقی است که مقادیر گمشده را با مقادیری که ممکن است معتبر باشند پر کنیم. چندین روش برای پر کردن مقادیر null وجود دارد. اولین روش استفاده از دانش حوزه (دانشی که بر اساس آن مجموعه داده ساخته شده است) برای تقریب زدن مقادیر گمشده است.\n", + "گاهی منطقی است که مقادیر خالی را با مقادیری که ممکن است معتبر باشند پر کنیم. چندین تکنیک برای پر کردن مقادیر خالی وجود دارد. اولین روش استفاده از دانش حوزه (دانش مربوط به موضوعی که مجموعه داده بر اساس آن است) برای تقریب زدن مقادیر خالی است.\n", "\n", - "شما می‌توانید از `isnull` برای انجام این کار به صورت مستقیم استفاده کنید، اما این کار می‌تواند زمان‌بر باشد، به خصوص اگر مقادیر زیادی برای پر کردن داشته باشید. از آنجا که این یک وظیفه رایج در علم داده است، pandas تابعی به نام `fillna` ارائه می‌دهد که یک کپی از `Series` یا `DataFrame` را برمی‌گرداند که در آن مقادیر گمشده با مقداری که شما انتخاب کرده‌اید جایگزین شده‌اند. بیایید یک مثال دیگر از `Series` ایجاد کنیم تا ببینیم این روش در عمل چگونه کار می‌کند.\n" + "شما می‌توانید از `isnull` برای انجام این کار به صورت مستقیم استفاده کنید، اما این کار ممکن است زمان‌بر باشد، به‌ویژه اگر تعداد زیادی مقدار برای پر کردن داشته باشید. از آنجا که این کار در علم داده بسیار رایج است، pandas تابع `fillna` را ارائه می‌دهد که یک نسخه کپی از `Series` یا `DataFrame` را با مقادیر خالی جایگزین شده با مقدار انتخابی شما برمی‌گرداند. بیایید یک مثال دیگر از `Series` ایجاد کنیم تا ببینیم این روش در عمل چگونه کار می‌کند.\n" ] }, { @@ -1591,9 +1590,9 @@ }, "source": [ "### داده‌های دسته‌بندی‌شده (غیر عددی)\n", - "ابتدا به داده‌های غیر عددی می‌پردازیم. در مجموعه داده‌ها، ستون‌هایی با داده‌های دسته‌بندی‌شده داریم. به عنوان مثال، جنسیت، درست یا نادرست و غیره.\n", + "ابتدا به داده‌های غیر عددی می‌پردازیم. در مجموعه داده‌ها، ستون‌هایی با داده‌های دسته‌بندی‌شده داریم. به عنوان مثال، جنسیت، درست یا غلط و غیره.\n", "\n", - "در بیشتر این موارد، مقادیر گمشده را با `مد` ستون جایگزین می‌کنیم. فرض کنید ۱۰۰ نقطه داده داریم و ۹۰ نفر گفته‌اند درست، ۸ نفر گفته‌اند نادرست و ۲ نفر چیزی وارد نکرده‌اند. در این صورت، می‌توانیم آن ۲ مقدار گمشده را با درست پر کنیم، با توجه به کل ستون.\n", + "در بیشتر این موارد، مقادیر گمشده را با `مد` ستون جایگزین می‌کنیم. فرض کنید ۱۰۰ نقطه داده داریم که ۹۰ نفر گفته‌اند درست، ۸ نفر گفته‌اند غلط و ۲ نفر چیزی وارد نکرده‌اند. در این صورت، می‌توانیم آن ۲ مقدار گمشده را با درست پر کنیم، با توجه به کل ستون.\n", "\n", "باز هم، در اینجا می‌توانیم از دانش حوزه استفاده کنیم. بیایید یک مثال از پر کردن با مد را بررسی کنیم.\n" ] @@ -1700,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "حالا، بیایید ابتدا مد را پیدا کنیم قبل از اینکه مقدار `None` را با مد پر کنیم.\n" + ] }, { "cell_type": "code", @@ -1735,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "بنابراین، ما None را با True جایگزین خواهیم کرد\n" + ] }, { "cell_type": "code", @@ -1845,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "همانطور که می‌بینیم، مقدار null جایگزین شده است. نیازی به گفتن نیست که می‌توانستیم هر چیزی را به جای `'True'` بنویسیم و جایگزین می‌شد.\n" + "همانطور که می‌بینیم، مقدار null جایگزین شده است. نیازی به گفتن نیست، ما می‌توانستیم هر چیزی را به جای `'True'` بنویسیم و آن جایگزین می‌شد.\n" ] }, { @@ -1857,12 +1860,12 @@ "### داده‌های عددی\n", "حالا به داده‌های عددی می‌رسیم. در اینجا دو روش رایج برای جایگزینی مقادیر گمشده وجود دارد:\n", "\n", - "1. جایگزینی با میانه‌ی سطر \n", - "2. جایگزینی با میانگین سطر \n", + "1. جایگزینی با میانه‌ی سطر\n", + "2. جایگزینی با میانگین سطر\n", "\n", "در صورتی که داده‌ها دارای انحراف و نقاط پرت باشند، از میانه استفاده می‌کنیم. دلیل این امر این است که میانه نسبت به نقاط پرت مقاوم است.\n", "\n", - "وقتی داده‌ها نرمال‌سازی شده باشند، می‌توانیم از میانگین استفاده کنیم، زیرا در این حالت میانگین و میانه به هم نزدیک خواهند بود.\n", + "وقتی داده‌ها نرمال‌سازی شده باشند، می‌توانیم از میانگین استفاده کنیم، زیرا در این حالت میانگین و میانه به یکدیگر بسیار نزدیک خواهند بود.\n", "\n", "ابتدا، یک ستون که به طور نرمال توزیع شده است را انتخاب می‌کنیم و مقدار گمشده را با میانگین ستون پر می‌کنیم.\n" ] @@ -1970,7 +1973,7 @@ "id": "ka7-wNfzSxbx" }, "source": [ - "میانگین ستون است\n" + "میانگین ستون برابر است با\n" ] }, { @@ -2004,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "پر کردن با میانگین\n" + ] }, { "cell_type": "code", @@ -2355,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "همانطور که می‌بینیم، مقدار NaN با میانه ستون جایگزین شده است\n" + "همانطور که می‌بینیم، مقدار NaN با میانه ستون جایگزین شده است.\n" ] }, { @@ -2397,7 +2402,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "شما می‌توانید تمام مقادیر خالی را با یک مقدار واحد، مانند `0` پر کنید:\n" + "شما می‌توانید تمام مقادیر خالی را با یک مقدار واحد، مانند `0`، پر کنید:\n" ] }, { @@ -2438,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "نکات کلیدی: \n", - "1. پر کردن مقادیر گمشده باید زمانی انجام شود که یا داده‌ها کم هستند یا استراتژی مشخصی برای پر کردن داده‌های گمشده وجود دارد. \n", - "2. می‌توان از دانش حوزه برای تخمین و پر کردن مقادیر گمشده استفاده کرد. \n", - "3. برای داده‌های دسته‌بندی‌شده، معمولاً مقادیر گمشده با مد ستون جایگزین می‌شوند. \n", - "4. برای داده‌های عددی، مقادیر گمشده معمولاً با میانگین (برای مجموعه داده‌های نرمال‌شده) یا میانه ستون‌ها پر می‌شوند. \n" + "> نکات کلیدی:\n", + "1. پر کردن مقادیر گمشده باید زمانی انجام شود که داده‌ها کم باشند یا استراتژی مشخصی برای پر کردن داده‌های گمشده وجود داشته باشد.\n", + "2. می‌توان از دانش حوزه برای تخمین و پر کردن مقادیر گمشده استفاده کرد.\n", + "3. برای داده‌های دسته‌بندی‌شده، معمولاً مقادیر گمشده با مد ستون جایگزین می‌شوند.\n", + "4. برای داده‌های عددی، مقادیر گمشده معمولاً با میانگین (برای مجموعه داده‌های نرمال‌شده) یا میانه ستون‌ها پر می‌شوند.\n" ] }, { @@ -2451,7 +2456,7 @@ "id": "FI9MmqFJgRsH" }, "source": [ - "تمرین:\n" + "### تمرین:\n" ] }, { @@ -2473,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "شما می‌توانید مقادیر تهی را **با مقدار قبلی پر کنید**، به این صورت که از آخرین مقدار معتبر برای پر کردن مقدار تهی استفاده کنید:\n" + "شما می‌توانید مقادیر null را **با مقدار قبلی پر کنید**، به این صورت که از آخرین مقدار معتبر برای پر کردن null استفاده کنید:\n" ] }, { @@ -2514,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "شما همچنین می‌توانید **پر کردن معکوس** را برای انتشار مقدار معتبر بعدی به عقب جهت پر کردن مقدار تهی انجام دهید:\n" + "شما همچنین می‌توانید **پر کردن معکوس** را انجام دهید تا مقدار معتبر بعدی را به عقب منتقل کرده و یک مقدار تهی را پر کنید:\n" ] }, { @@ -2556,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "همانطور که ممکن است حدس بزنید، این به همان صورت با DataFrames کار می‌کند، اما شما همچنین می‌توانید یک `axis` مشخص کنید که در امتداد آن مقادیر null را پر کنید:\n" + "همان‌طور که ممکن است حدس بزنید، این با DataFrames نیز به همین صورت کار می‌کند، اما شما همچنین می‌توانید یک `axis` مشخص کنید که در امتداد آن مقادیر null را پر کنید:\n" ] }, { @@ -2729,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "توجه کنید که وقتی مقدار قبلی برای پر کردن جلو در دسترس نیست، مقدار تهی باقی می‌ماند.\n" + "توجه کنید که وقتی مقدار قبلی برای پر کردن به جلو در دسترس نیست، مقدار تهی باقی می‌ماند.\n" ] }, { @@ -2762,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "شما می‌توانید در استفاده از `fillna` خلاق باشید. برای مثال، بیایید دوباره به `example4` نگاه کنیم، اما این بار مقادیر گمشده را با میانگین تمام مقادیر موجود در `DataFrame` پر کنیم:\n" + "شما می‌توانید در مورد نحوه استفاده از `fillna` خلاق باشید. برای مثال، بیایید دوباره به `example4` نگاه کنیم، اما این بار مقادیر گمشده را با میانگین تمام مقادیر موجود در `DataFrame` پر کنیم:\n" ] }, { @@ -2853,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "توجه کنید که ستون سوم هنوز بدون مقدار است: جهت پیش‌فرض برای پر کردن مقادیر به صورت ردیفی است.\n", + "توجه کنید که ستون ۳ هنوز بدون مقدار است: جهت پیش‌فرض برای پر کردن مقادیر به صورت سطری است.\n", "\n", - "> **نکته کلیدی:** روش‌های متعددی برای مدیریت مقادیر گمشده در مجموعه داده‌های شما وجود دارد. استراتژی خاصی که استفاده می‌کنید (حذف آن‌ها، جایگزینی آن‌ها، یا حتی نحوه جایگزینی آن‌ها) باید بر اساس ویژگی‌های خاص آن داده‌ها تعیین شود. هرچه بیشتر با مجموعه داده‌ها کار کنید و تعامل داشته باشید، حس بهتری برای مدیریت مقادیر گمشده پیدا خواهید کرد.\n" + "> **نکته مهم:** روش‌های مختلفی برای مدیریت مقادیر گمشده در مجموعه داده‌های شما وجود دارد. استراتژی خاصی که استفاده می‌کنید (حذف کردن، جایگزین کردن، یا حتی نحوه جایگزینی) باید بر اساس ویژگی‌های خاص آن داده‌ها تعیین شود. هرچه بیشتر با مجموعه داده‌ها کار کنید و تعامل داشته باشید، حس بهتری نسبت به نحوه مدیریت مقادیر گمشده پیدا خواهید کرد.\n" ] }, { @@ -2866,9 +2871,9 @@ "source": [ "### کدگذاری داده‌های دسته‌بندی‌شده\n", "\n", - "مدل‌های یادگیری ماشین فقط با اعداد و هر نوع داده عددی کار می‌کنند. این مدل‌ها نمی‌توانند تفاوت بین \"بله\" و \"خیر\" را تشخیص دهند، اما می‌توانند بین ۰ و ۱ تفاوت قائل شوند. بنابراین، پس از پر کردن مقادیر گمشده، باید داده‌های دسته‌بندی‌شده را به نوعی فرم عددی تبدیل کنیم تا مدل بتواند آن‌ها را درک کند.\n", + "مدل‌های یادگیری ماشین فقط با اعداد و هر نوع داده عددی کار می‌کنند. این مدل‌ها نمی‌توانند تفاوت بین \"بله\" و \"خیر\" را تشخیص دهند، اما می‌توانند بین ۰ و ۱ تمایز قائل شوند. بنابراین، پس از پر کردن مقادیر گمشده، باید داده‌های دسته‌بندی‌شده را به شکلی عددی تبدیل کنیم تا مدل بتواند آن‌ها را درک کند.\n", "\n", - "کدگذاری داده‌ها به دو روش قابل انجام است. در ادامه این روش‌ها را بررسی خواهیم کرد.\n" + "کدگذاری داده‌ها به دو روش قابل انجام است. در ادامه این دو روش را بررسی خواهیم کرد.\n" ] }, { @@ -2879,7 +2884,7 @@ "source": [ "**رمزگذاری برچسب**\n", "\n", - "رمزگذاری برچسب به طور کلی به معنای تبدیل هر دسته به یک عدد است. به عنوان مثال، فرض کنید یک مجموعه داده از مسافران هواپیما داریم و ستونی وجود دارد که کلاس آن‌ها را در میان موارد زیر نشان می‌دهد: ['کلاس تجاری', 'کلاس اقتصادی', 'کلاس درجه یک']. اگر رمزگذاری برچسب روی این ستون انجام شود، به [0,1,2] تبدیل می‌شود. بیایید با استفاده از کد یک مثال را ببینیم. از آنجا که در دفترچه‌های آینده `scikit-learn` را یاد خواهیم گرفت، در اینجا از آن استفاده نمی‌کنیم.\n" + "رمزگذاری برچسب اساساً تبدیل هر دسته به یک عدد است. برای مثال، فرض کنید یک مجموعه داده از مسافران خطوط هوایی داریم و ستونی وجود دارد که کلاس آن‌ها را در میان موارد زیر نشان می‌دهد ['کلاس تجاری', 'کلاس اقتصادی', 'کلاس اول']. اگر رمزگذاری برچسب روی این انجام شود، به [0,1,2] تبدیل می‌شود. بیایید یک مثال را از طریق کد ببینیم. از آنجا که در دفاتر آینده `scikit-learn` را یاد خواهیم گرفت، در اینجا از آن استفاده نمی‌کنیم.\n" ] }, { @@ -2987,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "برای انجام کدگذاری برچسب روی ستون اول، ابتدا باید یک نگاشت از هر کلاس به یک عدد توصیف کنیم، قبل از جایگزینی\n" + "برای انجام کدگذاری برچسب روی ستون اول، ابتدا باید یک نگاشت از هر کلاس به یک عدد تعریف کنیم، قبل از جایگزینی.\n" ] }, { @@ -3089,7 +3094,7 @@ "id": "ftnF-TyapOPt" }, "source": [ - "همانطور که می‌بینیم، خروجی با چیزی که انتظار داشتیم مطابقت دارد. پس، چه زمانی از کدگذاری برچسب استفاده می‌کنیم؟ کدگذاری برچسب در یکی یا هر دو مورد زیر استفاده می‌شود:\n", + "همان‌طور که می‌بینیم، خروجی با چیزی که انتظار داشتیم اتفاق بیفتد مطابقت دارد. پس، چه زمانی از کدگذاری برچسب استفاده می‌کنیم؟ کدگذاری برچسب در یکی یا هر دو مورد زیر استفاده می‌شود:\n", "1. زمانی که تعداد دسته‌ها زیاد باشد\n", "2. زمانی که دسته‌ها دارای ترتیب باشند.\n" ] @@ -3100,9 +3105,9 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**رمزگذاری یک‌بار**\n", + "**رمزگذاری یک‌بار (One Hot Encoding)**\n", "\n", - "نوع دیگری از رمزگذاری، رمزگذاری یک‌بار است. در این نوع رمزگذاری، هر دسته از ستون به‌عنوان یک ستون جداگانه اضافه می‌شود و هر نقطه داده بر اساس اینکه شامل آن دسته باشد یا نه، مقدار ۰ یا ۱ دریافت می‌کند. بنابراین، اگر n دسته مختلف وجود داشته باشد، n ستون به دیتافریم اضافه خواهد شد.\n", + "یکی دیگر از انواع رمزگذاری، رمزگذاری یک‌بار است. در این نوع رمزگذاری، هر دسته از ستون به‌عنوان یک ستون جداگانه اضافه می‌شود و هر نقطه داده بر اساس اینکه شامل آن دسته باشد یا نه، مقدار 0 یا 1 دریافت می‌کند. بنابراین، اگر n دسته مختلف وجود داشته باشد، n ستون به دیتافریم اضافه خواهد شد.\n", "\n", "برای مثال، بیایید همان مثال کلاس هواپیما را در نظر بگیریم. دسته‌ها عبارت بودند از: ['کلاس تجاری', 'کلاس اقتصادی', 'کلاس درجه یک']. بنابراین، اگر رمزگذاری یک‌بار انجام دهیم، سه ستون زیر به مجموعه داده اضافه خواهند شد: ['class_business class', 'class_economy class', 'class_first class'].\n" ] @@ -3212,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "بیایید رمزگذاری یک‌داغ را روی ستون اول انجام دهیم\n" + "بیایید رمزگذاری یک‌داغ را بر روی ستون اول انجام دهیم\n" ] }, { @@ -3337,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "هر ستون کدگذاری شده به صورت یک‌به‌یک شامل ۰ یا ۱ است که مشخص می‌کند آیا آن دسته‌بندی برای آن نقطه داده وجود دارد یا خیر.\n" + "هر ستون کدگذاری شده به صورت یک‌داغ شامل ۰ یا ۱ است که مشخص می‌کند آیا آن دسته‌بندی برای آن نقطه داده وجود دارد یا خیر.\n" ] }, { @@ -3346,11 +3351,10 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "چه زمانی از وان هات انکودینگ استفاده می‌کنیم؟ \n", - "وان هات انکودینگ در یکی یا هر دو مورد زیر استفاده می‌شود:\n", + "چه زمانی از کدگذاری یک‌داغ استفاده می‌کنیم؟ کدگذاری یک‌داغ در یکی یا هر دو مورد زیر استفاده می‌شود:\n", "\n", - "1. زمانی که تعداد دسته‌ها و اندازه دیتاست کوچک باشد. \n", - "2. زمانی که دسته‌ها هیچ ترتیب خاصی را دنبال نمی‌کنند. \n" + "1. زمانی که تعداد دسته‌ها و اندازه مجموعه داده کوچک باشد.\n", + "2. زمانی که دسته‌ها ترتیب خاصی را دنبال نمی‌کنند.\n" ] }, { @@ -3359,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "نکات کلیدی: \n", - "1. رمزگذاری برای تبدیل داده‌های غیر عددی به داده‌های عددی انجام می‌شود. \n", - "2. دو نوع رمزگذاری وجود دارد: رمزگذاری برچسبی و رمزگذاری یک‌داغ، که هر دو می‌توانند بر اساس نیازهای مجموعه داده انجام شوند. \n" + "> نکات کلیدی:\n", + "1. کدگذاری برای تبدیل داده‌های غیر عددی به داده‌های عددی انجام می‌شود.\n", + "2. دو نوع کدگذاری وجود دارد: کدگذاری برچسبی و کدگذاری یک‌داغ، که هر دو می‌توانند بر اساس نیازهای مجموعه داده انجام شوند.\n" ] }, { @@ -3372,9 +3376,9 @@ "source": [ "## حذف داده‌های تکراری\n", "\n", - "> **هدف یادگیری:** در پایان این بخش، باید بتوانید به راحتی مقادیر تکراری را در DataFrame‌ها شناسایی و حذف کنید.\n", + "> **هدف یادگیری:** تا پایان این زیر بخش، باید بتوانید داده‌های تکراری را در DataFrame‌ها شناسایی و حذف کنید.\n", "\n", - "علاوه بر داده‌های گمشده، در مجموعه داده‌های واقعی اغلب با داده‌های تکراری مواجه خواهید شد. خوشبختانه، pandas روشی ساده برای شناسایی و حذف ورودی‌های تکراری ارائه می‌دهد.\n" + "علاوه بر داده‌های گمشده، اغلب در مجموعه داده‌های دنیای واقعی با داده‌های تکراری مواجه خواهید شد. خوشبختانه، pandas روشی آسان برای شناسایی و حذف ورودی‌های تکراری ارائه می‌دهد.\n" ] }, { @@ -3385,7 +3389,7 @@ "source": [ "### شناسایی مقادیر تکراری: `duplicated`\n", "\n", - "شما می‌توانید به راحتی مقادیر تکراری را با استفاده از متد `duplicated` در pandas شناسایی کنید. این متد یک ماسک بولی برمی‌گرداند که نشان می‌دهد آیا یک ورودی در `DataFrame` تکراری از یک ورودی قبلی است یا خیر. بیایید یک مثال دیگر از `DataFrame` ایجاد کنیم تا این موضوع را در عمل ببینیم.\n" + "شما می‌توانید به راحتی مقادیر تکراری را با استفاده از متد `duplicated` در pandas شناسایی کنید. این متد یک ماسک بولی برمی‌گرداند که نشان می‌دهد آیا یک ورودی در `DataFrame` تکراری از ورودی قبلی است یا خیر. بیایید یک مثال دیگر از `DataFrame` ایجاد کنیم تا این موضوع را در عمل ببینیم.\n" ] }, { @@ -3515,7 +3519,7 @@ }, "source": [ "### حذف مقادیر تکراری: `drop_duplicates`\n", - "`drop_duplicates` به سادگی یک نسخه از داده‌ها را برمی‌گرداند که در آن تمام مقادیر `duplicated` برابر با `False` هستند:\n" + "`drop_duplicates` به سادگی نسخه‌ای از داده‌ها را برمی‌گرداند که در آن تمام مقادیر `duplicated` برابر با `False` هستند:\n" ] }, { @@ -3675,14 +3679,530 @@ "id": "GvX4og1EgRsL" }, "source": [ - "**نکته:** حذف داده‌های تکراری بخش ضروری تقریباً هر پروژه علم داده است. داده‌های تکراری می‌توانند نتایج تحلیل‌های شما را تغییر دهند و نتایج نادرستی به شما ارائه دهند!\n" + "> **نکته کلیدی:** حذف داده‌های تکراری بخش ضروری تقریباً هر پروژه علم داده است. داده‌های تکراری می‌توانند نتایج تحلیل‌های شما را تغییر دهند و نتایج نادرستی به شما ارائه دهند!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## بررسی کیفیت داده‌های دنیای واقعی\n", + "\n", + "> **هدف یادگیری:** در پایان این بخش، باید بتوانید مشکلات رایج کیفیت داده‌های دنیای واقعی مانند مقادیر دسته‌بندی ناسازگار، مقادیر عددی غیرعادی (مقادیر پرت)، و موجودیت‌های تکراری با تغییرات را شناسایی و اصلاح کنید.\n", + "\n", + "در حالی که مقادیر گمشده و تکراری‌های دقیق مشکلات رایجی هستند، مجموعه داده‌های دنیای واقعی اغلب شامل مشکلات ظریف‌تری هستند:\n", + "\n", + "1. **مقادیر دسته‌بندی ناسازگار**: یک دسته‌بندی مشابه با املای متفاوت (مثلاً \"USA\"، \"U.S.A\"، \"United States\")\n", + "2. **مقادیر عددی غیرعادی**: مقادیر پرت شدید که نشان‌دهنده خطاهای ورود داده هستند (مثلاً سن = 999)\n", + "3. **ردیف‌های تقریباً تکراری**: رکوردهایی که یک موجودیت مشابه را با تغییرات جزئی نشان می‌دهند\n", + "\n", + "بیایید تکنیک‌هایی برای شناسایی و مدیریت این مشکلات بررسی کنیم.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ایجاد یک مجموعه داده نمونه \"ناقص\"\n", + "\n", + "ابتدا، بیایید یک مجموعه داده نمونه ایجاد کنیم که شامل انواع مشکلاتی باشد که معمولاً در داده‌های دنیای واقعی با آن‌ها مواجه می‌شویم:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ۱. شناسایی مقادیر دسته‌بندی ناسازگار\n", + "\n", + "توجه کنید که ستون `country` دارای نمایش‌های مختلفی برای یک کشور است. بیایید این ناسازگاری‌ها را شناسایی کنیم:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### استانداردسازی مقادیر دسته‌بندی‌شده\n", + "\n", + "می‌توانیم یک نگاشت ایجاد کنیم تا این مقادیر را استاندارد کنیم. یک روش ساده این است که مقادیر را به حروف کوچک تبدیل کنیم و یک دیکشنری نگاشت ایجاد کنیم:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**جایگزین: استفاده از تطبیق مبهم**\n", + "\n", + "برای موارد پیچیده‌تر، می‌توانیم از تطبیق رشته‌ای مبهم با کتابخانه `rapidfuzz` استفاده کنیم تا به‌طور خودکار رشته‌های مشابه را شناسایی کنیم:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. شناسایی مقادیر عددی غیرعادی (Outliers)\n", + "\n", + "با بررسی ستون `age`، متوجه مقادیر مشکوکی مانند 199 و -5 می‌شویم. بیایید از روش‌های آماری برای شناسایی این مقادیر غیرعادی استفاده کنیم.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### استفاده از روش IQR (دامنه بین چارکی)\n", + "\n", + "روش IQR یک تکنیک آماری مقاوم برای شناسایی داده‌های پرت است که حساسیت کمتری به مقادیر بسیار زیاد یا بسیار کم دارد:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### استفاده از روش Z-Score\n", + "\n", + "روش Z-Score بر اساس انحراف معیار از میانگین، داده‌های پرت را شناسایی می‌کند:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### مدیریت داده‌های پرت\n", + "\n", + "پس از شناسایی، داده‌های پرت را می‌توان به روش‌های مختلفی مدیریت کرد:\n", + "1. **حذف**: حذف سطرهایی که داده‌های پرت دارند (اگر خطا باشند)\n", + "2. **محدود کردن**: جایگزینی با مقادیر مرزی\n", + "3. **جایگزینی با NaN**: به عنوان داده‌های گمشده در نظر گرفته شده و از تکنیک‌های جایگزینی استفاده شود\n", + "4. **نگه داشتن**: اگر مقادیر افراطی معتبر باشند\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. شناسایی سطرهای تقریباً مشابه\n", + "\n", + "توجه کنید که مجموعه داده ما چندین ورودی برای \"John Smith\" دارد با مقادیر کمی متفاوت. بیایید بر اساس شباهت نام، موارد مشابه احتمالی را شناسایی کنیم.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### یافتن موارد تقریباً مشابه با تطبیق مبهم\n", + "\n", + "برای تشخیص پیشرفته‌تر موارد مشابه، می‌توانیم از تطبیق مبهم برای یافتن نام‌های مشابه استفاده کنیم:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### مدیریت موارد تکراری\n", + "\n", + "پس از شناسایی، باید تصمیم بگیرید که چگونه موارد تکراری را مدیریت کنید:\n", + "1. **نگه داشتن اولین مورد**: از `drop_duplicates(keep='first')` استفاده کنید\n", + "2. **نگه داشتن آخرین مورد**: از `drop_duplicates(keep='last')` استفاده کنید\n", + "3. **تجمیع اطلاعات**: اطلاعات موجود در سطرهای تکراری را ترکیب کنید\n", + "4. **بررسی دستی**: برای بررسی انسانی علامت‌گذاری کنید\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### خلاصه: ایجاد یک خط لوله کامل برای پاکسازی داده‌ها\n", + "\n", + "بیایید همه چیز را در قالب یک خط لوله جامع برای پاکسازی داده‌ها جمع‌آوری کنیم:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 تمرین چالشی\n", + "\n", + "حالا نوبت شماست! در زیر یک ردیف جدید از داده‌ها با مشکلات کیفی متعدد آورده شده است. آیا می‌توانید:\n", + "\n", + "1. تمام مشکلات موجود در این ردیف را شناسایی کنید\n", + "2. کدی بنویسید که هر مشکل را پاکسازی کند\n", + "3. ردیف پاکسازی‌شده را به مجموعه داده اضافه کنید\n", + "\n", + "اینجا داده‌های مشکل‌دار آورده شده است:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### نکات کلیدی\n", + "\n", + "1. **دسته‌بندی‌های ناسازگار** در داده‌های واقعی رایج هستند. همیشه مقادیر یکتا را بررسی کنید و آن‌ها را با استفاده از نگاشت‌ها یا تطبیق مبهم استاندارد کنید.\n", + "\n", + "2. **مقادیر پرت** می‌توانند تحلیل شما را به شدت تحت تأثیر قرار دهند. از دانش حوزه همراه با روش‌های آماری (IQR، Z-score) برای شناسایی آن‌ها استفاده کنید.\n", + "\n", + "3. **نزدیک به تکراری‌ها** سخت‌تر از تکراری‌های دقیق قابل شناسایی هستند. از تطبیق مبهم و نرمال‌سازی داده‌ها (تبدیل به حروف کوچک، حذف فاصله‌های اضافی) برای شناسایی آن‌ها استفاده کنید.\n", + "\n", + "4. **پاک‌سازی داده‌ها فرآیندی تکراری است**. ممکن است نیاز باشد چندین تکنیک را اعمال کنید و نتایج را بررسی کنید تا مجموعه داده پاک‌سازی شده خود را نهایی کنید.\n", + "\n", + "5. **تصمیمات خود را مستند کنید**. مراحل پاک‌سازی که اعمال کرده‌اید و دلایل آن‌ها را ثبت کنید، زیرا این کار برای قابلیت بازتولید و شفافیت مهم است.\n", + "\n", + "> **بهترین روش:** همیشه یک نسخه از داده‌های اصلی \"کثیف\" خود را نگه دارید. هرگز فایل‌های داده منبع خود را بازنویسی نکنید - نسخه‌های پاک‌سازی شده با نام‌گذاری واضح مانند `data_cleaned.csv` ایجاد کنید.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**سلب مسئولیت**: \nاین سند با استفاده از سرویس ترجمه هوش مصنوعی [Co-op Translator](https://github.com/Azure/co-op-translator) ترجمه شده است. در حالی که ما تلاش می‌کنیم دقت را حفظ کنیم، لطفاً توجه داشته باشید که ترجمه‌های خودکار ممکن است شامل خطاها یا نادرستی‌ها باشند. سند اصلی به زبان اصلی آن باید به عنوان منبع معتبر در نظر گرفته شود. برای اطلاعات حساس، توصیه می‌شود از ترجمه حرفه‌ای انسانی استفاده کنید. ما مسئولیتی در قبال سوءتفاهم‌ها یا تفسیرهای نادرست ناشی از استفاده از این ترجمه نداریم.\n" + "\n---\n\n**سلب مسئولیت**: \nاین سند با استفاده از سرویس ترجمه هوش مصنوعی [Co-op Translator](https://github.com/Azure/co-op-translator) ترجمه شده است. در حالی که ما تلاش می‌کنیم ترجمه‌ها دقیق باشند، لطفاً توجه داشته باشید که ترجمه‌های خودکار ممکن است شامل خطاها یا نادرستی‌ها باشند. سند اصلی به زبان اصلی آن باید به عنوان منبع معتبر در نظر گرفته شود. برای اطلاعات حساس، توصیه می‌شود از ترجمه انسانی حرفه‌ای استفاده کنید. ما هیچ مسئولیتی در قبال سوءتفاهم‌ها یا تفسیرهای نادرست ناشی از استفاده از این ترجمه نداریم.\n" ] } ], @@ -3710,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:40:46+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:09:16+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "fa" } diff --git a/translations/fi/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/fi/2-Working-With-Data/08-data-preparation/notebook.ipynb index bea16560..e7ef121a 100644 --- a/translations/fi/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/fi/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -14,9 +14,9 @@ "\n", "> **Oppimistavoite:** Tämän alajakson lopussa sinun pitäisi osata löytää yleistä tietoa pandas DataFrame -tietojen sisällöstä.\n", "\n", - "Kun olet ladannut datasi pandas-kirjastoon, se on todennäköisesti `DataFrame`-muodossa. Mutta jos `DataFrame` sisältää 60 000 riviä ja 400 saraketta, mistä edes aloitat saadaksesi käsityksen siitä, mitä sinulla on käsissäsi? Onneksi pandas tarjoaa käteviä työkaluja, joilla voit nopeasti tarkastella `DataFrame`-kokonaisuuden tietoja sekä ensimmäisiä että viimeisiä rivejä.\n", + "Kun olet ladannut datasi pandas-kirjastoon, se on todennäköisesti `DataFrame`-muodossa. Mutta jos `DataFrame` sisältää 60 000 riviä ja 400 saraketta, mistä edes aloitat saadaksesi käsityksen siitä, mitä sinulla on käsissäsi? Onneksi pandas tarjoaa käteviä työkaluja, joilla voit nopeasti tarkastella `DataFrame`-kokonaisuuden tietoja sekä sen ensimmäisiä ja viimeisiä rivejä.\n", "\n", - "Tämän toiminnallisuuden tutkimiseksi tuomme käyttöön Pythonin scikit-learn-kirjaston ja käytämme ikonista datasettiä, jonka jokainen data-analyytikko on nähnyt satoja kertoja: brittiläisen biologin Ronald Fisherin *Iris*-datasetti, jota hän käytti vuonna 1936 julkaistussa artikkelissaan \"The use of multiple measurements in taxonomic problems\":\n" + "Tutkiaksemme tätä toiminnallisuutta, tuomme käyttöön Pythonin scikit-learn-kirjaston ja käytämme ikonista datasettiä, jonka jokainen data-analyytikko on nähnyt satoja kertoja: brittiläisen biologin Ronald Fisherin *Iris*-datasetti, jota hän käytti vuonna 1936 julkaistussa artikkelissaan \"The use of multiple measurements in taxonomic problems\":\n" ] }, { @@ -78,7 +78,7 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Kyseessä on 150 riviä ja 4 saraketta sisältävä data. Jokainen rivi edustaa yhtä datapistettä, ja jokainen sarake vastaa yhtä ominaisuutta, joka liittyy datafreimiin. Käytännössä siis on 150 datapistettä, joista jokaisella on 4 ominaisuutta.\n", + "Joten, käsittelemme 150 riviä ja 4 saraketta dataa. Jokainen rivi edustaa yhtä datapistettä, ja jokainen sarake edustaa yhtä ominaisuutta, joka liittyy datafreimiin. Periaatteessa siis on 150 datapistettä, joilla on kukin 4 ominaisuutta.\n", "\n", "`shape` on tässä datafreimin attribuutti eikä funktio, minkä vuoksi se ei pääty sulkuihin.\n" ] @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Siirrytään nyt neljään datan sarakkeeseen. Mitä kukin niistä tarkalleen ottaen edustaa? `columns`-attribuutti antaa meille dataframeen kuuluvien sarakkeiden nimet.\n" + "Siirrytään nyt neljään datan sarakkeeseen. Mitä kukin niistä tarkalleen ottaen edustaa? `columns`-attribuutti antaa meille dataframeen sisältyvien sarakkeiden nimet.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Kuten voimme nähdä, on neljä (4) saraketta. `columns`-attribuutti kertoo meille sarakkeiden nimet eikä käytännössä mitään muuta. Tämä attribuutti saa merkitystä, kun haluamme tunnistaa, mitä ominaisuuksia tietojoukko sisältää.\n" + "Kuten voimme nähdä, on neljä (4) saraketta. `columns`-attribuutti kertoo meille sarakkeiden nimet eikä käytännössä mitään muuta. Tämä attribuutti saa merkitystä, kun haluamme tunnistaa, mitä ominaisuuksia datasetti sisältää.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Tietomäärä (annettu `shape`-attribuutilla) ja ominaisuuksien tai sarakkeiden nimet (annettu `columns`-attribuutilla) kertovat meille jotain tietojoukosta. Nyt haluaisimme tutkia tietojoukkoa syvällisemmin. `DataFrame.info()`-funktio on tässä erittäin hyödyllinen.\n" + "Tietomäärä (annettu `shape`-attribuutilla) ja ominaisuuksien tai sarakkeiden nimet (annettu `columns`-attribuutilla) kertovat jotain datasta. Nyt haluaisimme tutkia datasettiä tarkemmin. `DataFrame.info()`-funktio on tässä erittäin hyödyllinen.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Tästä voimme tehdä muutamia havaintoja: \n", - "1. Kunkin sarakkeen tietotyyppi: Tässä datasetissä kaikki tiedot on tallennettu 64-bittisinä liukulukuina. \n", - "2. Ei-null-arvojen lukumäärä: Null-arvojen käsittely on tärkeä vaihe datan valmistelussa. Tämä käsitellään myöhemmin muistikirjassa. \n" + "Tästä voimme tehdä muutamia havaintoja:\n", + "1. Jokaisen sarakkeen tietotyyppi: Tässä datassa kaikki tiedot on tallennettu 64-bittisinä liukulukuina.\n", + "2. Ei-null-arvojen määrä: Null-arvojen käsittely on tärkeä vaihe datan valmistelussa. Tämä käsitellään myöhemmin muistikirjassa.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "Yllä oleva tulos näyttää kunkin sarakkeen kokonaisdatapisteiden määrän, keskiarvon, keskihajonnan, minimiarvon, alaneljänneksen (25%), mediaanin (50%), yläneljänneksen (75%) ja maksimiarvon.\n" + "Yllä oleva tulos näyttää kunkin sarakkeen kokonaisdatapisteiden määrän, keskiarvon, keskihajonnan, minimiarvon, alaneljänneksen (25 %), mediaanin (50 %), yläneljänneksen (75 %) ja maksimiarvon.\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "Kaikkien edellä mainittujen funktioiden ja attribuuttien avulla olemme saaneet yleiskuvan datasta. Tiedämme, kuinka monta datapistettä on, kuinka monta ominaisuutta on, kunkin ominaisuuden tietotyypin ja kuinka monta ei-null-arvoa kullekin ominaisuudelle.\n", + "Kaikkien edellä mainittujen funktioiden ja attribuuttien avulla olemme saaneet yleiskuvan datasta. Tiedämme, kuinka monta datapistettä datasetissä on, kuinka monta ominaisuutta siinä on, kunkin ominaisuuden tietotyypin sekä ei-null-arvojen määrän kullekin ominaisuudelle.\n", "\n", - "Nyt on aika tarkastella itse dataa. Katsotaan, miltä `DataFrame`:n ensimmäiset rivit (ensimmäiset datapisteet) näyttävät:\n" + "Nyt on aika tarkastella itse dataa. Katsotaan, miltä ensimmäiset rivit (ensimmäiset datapisteet) `DataFrame`:ssä näyttävät:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Kuten tässä tuloksessa näemme, datasetistä on viisi (5) merkintää. Jos katsomme vasemmalla olevaa indeksiä, huomaamme, että nämä ovat ensimmäiset viisi riviä.\n" + "Kun tarkastelemme tässä tulostetta, näemme viisi (5) tietueita datasetistä. Jos katsomme vasemmalla olevaa indeksiä, huomaamme, että nämä ovat datasetin ensimmäiset viisi riviä.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Harjoitus:\n", "\n", - "Yllä olevasta esimerkistä käy ilmi, että oletuksena `DataFrame.head` palauttaa `DataFrame`:n ensimmäiset viisi riviä. Alla olevassa koodisolussa, voitko keksiä tavan näyttää enemmän kuin viisi riviä?\n" + "Yllä olevasta esimerkistä käy ilmi, että oletuksena `DataFrame.head` palauttaa `DataFrame`-taulukon ensimmäiset viisi riviä. Voitko alla olevassa koodisolussa keksiä tavan näyttää enemmän kuin viisi riviä?\n" ] }, { @@ -584,9 +584,9 @@ "source": [ "Käytännössä on hyödyllistä pystyä helposti tarkastelemaan `DataFrame`-taulukon ensimmäisiä tai viimeisiä rivejä, erityisesti silloin, kun etsit poikkeamia järjestetyistä aineistoista.\n", "\n", - "Kaikki yllä esitetyt funktiot ja attribuutit, joita havainnollistetaan koodiesimerkkien avulla, auttavat meitä saamaan käsityksen datasta.\n", + "Kaikki yllä esitetyt funktiot ja attribuutit, joita havainnollistettiin koodiesimerkkien avulla, auttavat meitä saamaan käsityksen datasta.\n", "\n", - "> **Yhteenveto:** Jo pelkästään tarkastelemalla metatietoja `DataFrame`-taulukon sisällöstä tai sen ensimmäisiä ja viimeisiä arvoja, voit saada välittömän käsityksen datan koosta, muodosta ja sisällöstä, jonka kanssa työskentelet.\n" + "> **Yhteenveto:** Jo pelkästään tarkastelemalla metatietoja `DataFrame`-taulukon sisällöstä tai sen ensimmäisiä ja viimeisiä arvoja, voit nopeasti saada käsityksen datan koosta, muodosta ja sisällöstä, jonka kanssa työskentelet.\n" ] }, { @@ -595,18 +595,18 @@ "id": "TvurZyLSDxq_" }, "source": [ - "### Puuttuvat tiedot\n", - "Sukelletaanpa puuttuviin tietoihin. Puuttuvia tietoja syntyy, kun joissakin sarakkeissa ei ole tallennettua arvoa.\n", + "### Puuttuvat Tiedot\n", + "Tutustutaan puuttuviin tietoihin. Puuttuvat tiedot syntyvät, kun joissakin sarakkeissa ei ole tallennettu arvoa.\n", "\n", - "Otetaan esimerkki: sanotaan, että joku on tietoinen painostaan eikä täytä painokenttää kyselyssä. Tällöin kyseisen henkilön painoarvo puuttuu.\n", + "Otetaan esimerkki: joku on hyvin tarkka painostaan eikä täytä painokenttää kyselyssä. Tällöin kyseisen henkilön painoarvo jää puuttumaan.\n", "\n", - "Useimmiten puuttuvia arvoja esiintyy todellisten maailmandatassa.\n", + "Useimmiten todellisissa maailmankokoelmissa esiintyy puuttuvia arvoja.\n", "\n", "**Kuinka Pandas käsittelee puuttuvia tietoja**\n", "\n", - "Pandas käsittelee puuttuvia arvoja kahdella tavalla. Ensimmäinen, jonka olet nähnyt aiemmissa osioissa, on `NaN`, eli Not a Number. Tämä on itse asiassa erityinen arvo, joka kuuluu IEEE:n liukulukuja koskevaan määrittelyyn, ja sitä käytetään vain puuttuvien liukulukuarvojen merkitsemiseen.\n", + "Pandas käsittelee puuttuvia arvoja kahdella tavalla. Ensimmäinen tapa, jonka olet nähnyt aiemmissa osioissa, on `NaN`, eli Not a Number. Tämä on itse asiassa erityinen arvo, joka kuuluu IEEE:n liukulukumäärittelyyn, ja sitä käytetään vain puuttuvien liukulukuarvojen merkitsemiseen.\n", "\n", - "Muiden kuin liukulukujen puuttuvien arvojen kohdalla pandas käyttää Pythonin `None`-objektia. Vaikka saattaa tuntua hämmentävältä kohdata kaksi erilaista arvoa, jotka tarkoittavat pohjimmiltaan samaa asiaa, tälle suunnitteluratkaisulle on hyvät ohjelmalliset perusteet. Käytännössä tämä lähestymistapa mahdollistaa sen, että pandas pystyy tarjoamaan hyvän kompromissin valtaosassa tapauksia. Tästä huolimatta sekä `None` että `NaN` sisältävät rajoituksia, jotka on syytä pitää mielessä niiden käyttöä koskien.\n" + "Liukulukuja lukuun ottamatta puuttuvien arvojen kohdalla pandas käyttää Pythonin `None`-objektia. Vaikka voi tuntua hämmentävältä, että kohtaat kaksi erilaista arvoa, jotka periaatteessa tarkoittavat samaa asiaa, tälle suunnitteluratkaisulle on hyvät ohjelmalliset syyt. Käytännössä tämä lähestymistapa mahdollistaa sen, että pandas tarjoaa hyvän kompromissin valtaosassa tapauksista. Tästä huolimatta sekä `None` että `NaN` sisältävät rajoituksia, jotka sinun tulee ottaa huomioon niiden käyttöä koskien.\n" ] }, { @@ -615,8 +615,8 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: ei-float puuttuva data\n", - "Koska `None` on peräisin Pythonista, sitä ei voida käyttää NumPy- ja pandas-taulukoissa, joiden tietotyyppi ei ole `'object'`. Muista, että NumPy-taulukot (ja pandas-rakenteet) voivat sisältää vain yhtä tietotyyppiä. Tämä ominaisuus antaa niille valtavan tehon suurten tietomäärien ja laskennan käsittelyssä, mutta samalla se rajoittaa niiden joustavuutta. Tällaiset taulukot täytyy \"ylikääntää\" alhaisimpaan yhteiseen nimittäjään, eli tietotyyppiin, joka kattaa kaiken taulukossa olevan. Kun taulukossa on `None`, se tarkoittaa, että työskentelet Python-objektien kanssa.\n", + "### `None`: ei-kelluva puuttuva data\n", + "Koska `None` tulee Pythonista, sitä ei voida käyttää NumPy- ja pandas-taulukoissa, joiden tietotyyppi ei ole `'object'`. Muista, että NumPy-taulukot (ja pandas-tietorakenteet) voivat sisältää vain yhtä tietotyyppiä. Tämä ominaisuus antaa niille valtavan tehon suurten datamäärien ja laskentatyön käsittelyssä, mutta samalla se rajoittaa niiden joustavuutta. Tällaiset taulukot täytyy muuntaa \"pienimpään yhteiseen nimittäjään\", eli tietotyyppiin, joka kattaa kaiken taulukossa olevan. Kun taulukossa on `None`, se tarkoittaa, että työskentelet Python-objektien kanssa.\n", "\n", "Tarkastellaan tätä käytännössä seuraavan esimerkkitaulukon avulla (huomaa sen `dtype`):\n" ] @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Upcast-datatyyppien todellisuus tuo mukanaan kaksi sivuvaikutusta. Ensinnäkin, operaatiot suoritetaan tulkitun Python-koodin tasolla sen sijaan, että ne suoritettaisiin käännetyn NumPy-koodin tasolla. Käytännössä tämä tarkoittaa, että kaikki operaatiot, jotka sisältävät `Series`- tai `DataFrame`-objekteja, joissa on `None`, ovat hitaampia. Vaikka et todennäköisesti huomaisi tätä suorituskyvyn heikkenemistä, suurten tietoaineistojen kohdalla siitä saattaa tulla ongelma.\n", + "Upcast-tyyppien todellisuudella on kaksi sivuvaikutusta. Ensinnäkin operaatiot suoritetaan tulkitun Python-koodin tasolla sen sijaan, että ne suoritettaisiin käännetyn NumPy-koodin tasolla. Käytännössä tämä tarkoittaa, että kaikki operaatiot, jotka koskevat `Series`- tai `DataFrame`-objekteja, joissa on `None`, ovat hitaampia. Vaikka et todennäköisesti huomaisi tätä suorituskyvyn heikkenemistä, suurten tietoaineistojen kohdalla siitä saattaa tulla ongelma.\n", "\n", - "Toinen sivuvaikutus johtuu ensimmäisestä. Koska `None` käytännössä vetää `Series`- tai `DataFrame`-objektit takaisin perinteisen Pythonin maailmaan, NumPy/pandas-yhteenvedot, kuten `sum()` tai `min()`, taulukoissa, jotka sisältävät arvon ``None``, tuottavat yleensä virheen:\n" + "Toinen sivuvaikutus johtuu ensimmäisestä. Koska `None` käytännössä vetää `Series`- tai `DataFrame`-objektit takaisin perinteisen Pythonin maailmaan, NumPy/pandas-yhteenvedot, kuten `sum()` tai `min()`, taulukoissa, jotka sisältävät ``None``-arvon, tuottavat yleensä virheen:\n" ] }, { @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Keskeinen huomio**: Kokonaislukujen ja `None`-arvojen välinen yhteenlasku (ja muut operaatiot) on määrittelemätön, mikä voi rajoittaa sitä, mitä voit tehdä niitä sisältävien datasetien kanssa.\n" + "**Keskeinen huomio**: Kokonaislukujen ja `None`-arvojen välinen yhteenlasku (sekä muut operaatiot) on määrittelemätön, mikä voi rajoittaa sitä, mitä voit tehdä niitä sisältävien tietojoukkojen kanssa.\n" ] }, { @@ -709,7 +709,7 @@ "source": [ "### `NaN`: puuttuvat liukuluvut\n", "\n", - "Toisin kuin `None`, NumPy (ja siten pandas) tukee `NaN`-arvoja nopeiden, vektorisoitujen operaatioiden ja ufuncien kanssa. Huono uutinen on, että kaikki laskutoimitukset, jotka tehdään `NaN`-arvoilla, tuottavat aina `NaN`. Esimerkiksi:\n" + "Toisin kuin `None`, NumPy (ja siten pandas) tukee `NaN`:ia nopeiden, vektorisoitujen operaatioiden ja ufuncien avulla. Huono uutinen on, että kaikki aritmeettiset laskutoimitukset, jotka tehdään `NaN`:illa, tuottavat aina `NaN`:in. Esimerkiksi:\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Hyvät uutiset: `NaN`-arvoja sisältävillä taulukoilla suoritettavat aggregoinnit eivät aiheuta virheitä. Huonot uutiset: tulokset eivät ole tasaisesti hyödyllisiä:\n" + "Hyvät uutiset: aggregoinnit, jotka suoritetaan `NaN`-arvoja sisältävillä taulukoilla, eivät aiheuta virheitä. Huonot uutiset: tulokset eivät ole tasaisesti hyödyllisiä:\n" ] }, { @@ -831,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "Muista: `NaN` on tarkoitettu vain puuttuville liukulukuarvoille; kokonaisluvuille, merkkijonoille tai totuusarvoille ei ole vastaavaa `NaN`-arvoa.\n" + "Muista: `NaN` on vain puuttuvia liukulukuja varten; ei ole `NaN`-vastinetta kokonaisluvuille, merkkijonoille tai totuusarvoille.\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Pandasin `Series`- ja `DataFrame`-objekteissa tietotyyppien yhtenäistämiseksi tehtävässä ylöspäin muuntamisessa puuttuvat arvot voivat vaihtua vapaasti `None`- ja `NaN`-arvojen välillä. Tämän suunnitteluominaisuuden vuoksi voi olla hyödyllistä ajatella `None`- ja `NaN`-arvoja kahtena eri \"null\"-tyyppinä pandasissa. Itse asiassa jotkin keskeiset menetelmät, joita käytät puuttuvien arvojen käsittelyyn pandasissa, heijastavat tätä ajatusta nimissään:\n", + "Pandasissa tietotyyppien ylöspäin muuntamisen yhteydessä, kun pyritään luomaan tietojen yhtenäisyyttä `Series`- ja `DataFrame`-objekteissa, puuttuvat arvot voivat vaihtua joustavasti `None`- ja `NaN`-arvojen välillä. Tämän suunnitteluominaisuuden vuoksi voi olla hyödyllistä ajatella `None`- ja `NaN`-arvoja kahtena eri \"null\"-tyyppinä pandasissa. Itse asiassa jotkut keskeisistä menetelmistä, joita käytät puuttuvien arvojen käsittelyyn pandasissa, heijastavat tätä ajatusta nimissään:\n", "\n", - "- `isnull()`: Luo totuusarvomaskin, joka osoittaa puuttuvat arvot\n", + "- `isnull()`: Luo Boolean-maskin, joka osoittaa puuttuvat arvot\n", "- `notnull()`: `isnull()`-menetelmän vastakohta\n", "- `dropna()`: Palauttaa suodatetun version datasta\n", "- `fillna()`: Palauttaa kopion datasta, jossa puuttuvat arvot on täytetty tai imputoitu\n", "\n", - "Nämä ovat tärkeitä menetelmiä, jotka kannattaa hallita ja joiden kanssa on hyvä tulla sinuiksi, joten käydään ne läpi hieman tarkemmin.\n" + "Nämä menetelmät ovat tärkeitä hallita ja tuntea hyvin, joten käydään ne läpi yksityiskohtaisemmin.\n" ] }, { @@ -922,9 +922,9 @@ "id": "Yh5ifd9FgRsB" }, "source": [ - "### Null-arvojen tunnistaminen\n", + "### Null-arvojen havaitseminen\n", "\n", - "Kun olemme ymmärtäneet puuttuvien arvojen merkityksen, meidän täytyy tunnistaa ne aineistossamme ennen niiden käsittelyä. Sekä `isnull()` että `notnull()` ovat ensisijaisia menetelmiä null-datan tunnistamiseen. Molemmat palauttavat Boolean-maskin datasi päälle.\n" + "Kun olemme ymmärtäneet puuttuvien arvojen merkityksen, meidän täytyy havaita ne aineistossamme ennen niiden käsittelyä. Sekä `isnull()` että `notnull()` ovat ensisijaisia menetelmiä null-arvojen havaitsemiseen. Molemmat palauttavat Boolean-maskit aineistosi yli.\n" ] }, { @@ -977,11 +977,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Katso tarkkaan tulosta. Yllättääkö jokin siinä? Vaikka `0` on aritmeettinen nolla, se on silti täysin kelvollinen kokonaisluku, ja pandas käsittelee sitä sellaisena. `''` on hieman hienovaraisempi tapaus. Vaikka käytimme sitä osassa 1 edustamaan tyhjää merkkijonoarvoa, se on silti merkkijono-olio eikä pandasille null-arvon esitys.\n", + "Katso tarkasti tulosta. Yllättääkö jokin siinä? Vaikka `0` on aritmeettinen nolla, se on silti täysin kelvollinen kokonaisluku, ja pandas käsittelee sitä sellaisena. `''` on hieman hienovaraisempi tapaus. Vaikka käytimme sitä osassa 1 edustamaan tyhjää merkkijonoarvoa, se on silti merkkijono-objekti eikä pandasissa null-arvon edustaja.\n", "\n", - "Käännetäänpä tämä nyt toisin päin ja käytetään näitä menetelmiä tavalla, joka muistuttaa enemmän niiden käytännön soveltamista. Voit käyttää Boolen maskeja suoraan ``Series``- tai ``DataFrame``-indeksinä, mikä voi olla hyödyllistä, kun yrität käsitellä eristettyjä puuttuvia (tai olemassa olevia) arvoja.\n", + "Käännetäänpä tämä nyt toisin päin ja käytetään näitä menetelmiä enemmän sillä tavalla, kuin niitä käytetään käytännössä. Voit käyttää Boolen maskeja suoraan ``Series``- tai ``DataFrame``-indeksinä, mikä voi olla hyödyllistä, kun yrität käsitellä eristettyjä puuttuvia (tai olemassa olevia) arvoja.\n", "\n", - "Jos haluamme puuttuvien arvojen kokonaismäärän, voimme yksinkertaisesti laskea yhteen `isnull()`-menetelmän tuottaman maskin.\n" + "Jos haluamme puuttuvien arvojen kokonaismäärän, voimme yksinkertaisesti laskea yhteen maskin, jonka `isnull()`-metodi tuottaa.\n" ] }, { @@ -1050,7 +1050,7 @@ "source": [ "### Puuttuvien tietojen käsittely\n", "\n", - "> **Oppimistavoite:** Tämän osion lopussa sinun tulisi tietää, miten ja milloin korvata tai poistaa puuttuvat arvot DataFrameista.\n", + "> **Oppimistavoite:** Tämän alajakson lopussa sinun tulisi tietää, miten ja milloin korvata tai poistaa puuttuvat arvot DataFrameista.\n", "\n", "Koneoppimismallit eivät pysty käsittelemään puuttuvia tietoja itsestään. Siksi ennen datan syöttämistä malliin meidän täytyy käsitellä nämä puuttuvat arvot.\n", "\n", @@ -1059,9 +1059,9 @@ "Puuttuvien tietojen käsittelyyn on pääasiassa kaksi tapaa:\n", "\n", "1. Poista rivi, joka sisältää puuttuvan arvon\n", - "2. Korvaa puuttuva arvo jollakin toisella arvolla\n", + "2. Korvaa puuttuva arvo jollakin muulla arvolla\n", "\n", - "Käsittelemme molempia menetelmiä sekä niiden etuja ja haittoja yksityiskohtaisesti.\n" + "Käsittelemme molempia menetelmiä ja niiden etuja ja haittoja yksityiskohtaisesti.\n" ] }, { @@ -1070,13 +1070,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### Pudotetaan null-arvot\n", + "### Null-arvojen poistaminen\n", "\n", - "Datamäärä, jonka välitämme mallillemme, vaikuttaa suoraan sen suorituskykyyn. Null-arvojen pudottaminen tarkoittaa, että vähennämme datapisteiden määrää ja siten pienennämme datan kokoa. Siksi on suositeltavaa pudottaa rivit, joissa on null-arvoja, kun datasetti on melko suuri.\n", + "Mallillemme syötettävän datan määrä vaikuttaa suoraan sen suorituskykyyn. Null-arvojen poistaminen tarkoittaa, että vähennämme datapisteiden määrää ja siten pienennämme datasetin kokoa. Siksi on suositeltavaa poistaa rivit, joissa on null-arvoja, kun datasetti on melko suuri.\n", "\n", - "Toinen tilanne voi olla, että tietyssä rivissä tai sarakkeessa on paljon puuttuvia arvoja. Tällöin ne voidaan pudottaa, koska ne eivät todennäköisesti tuo paljon lisäarvoa analyysillemme, kun suurin osa datasta puuttuu kyseiseltä riviltä/sarakkeelta.\n", + "Toinen tilanne voi olla, että tietyssä rivissä tai sarakkeessa on paljon puuttuvia arvoja. Tällöin ne voidaan poistaa, koska ne eivät todennäköisesti tuo paljon lisäarvoa analyysillemme, kun suurin osa datasta puuttuu kyseiseltä riviltä tai sarakkeelta.\n", "\n", - "Puuttuvien arvojen tunnistamisen lisäksi pandas tarjoaa kätevän tavan poistaa null-arvot `Series`- ja `DataFrame`-objekteista. Katsotaanpa tätä käytännössä palaamalla `example3`:een. `DataFrame.dropna()`-funktio auttaa pudottamaan rivit, joissa on null-arvoja.\n" + "Sen lisäksi, että tunnistetaan puuttuvat arvot, pandas tarjoaa kätevän tavan poistaa null-arvoja `Series`- ja `DataFrame`-objekteista. Katsotaanpa tätä käytännössä palaamalla `example3`:een. `DataFrame.dropna()`-funktio auttaa poistamaan rivit, joissa on null-arvoja.\n" ] }, { @@ -1115,7 +1115,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "Huomaa, että tämä pitäisi näyttää samalta kuin tulos `example3[example3.notnull()]`. Erona tässä on, että sen sijaan, että vain indeksoitaisiin peitettyjä arvoja, `dropna` on poistanut nämä puuttuvat arvot `Series`-objektista `example3`.\n", + "Huomaa, että tämän pitäisi näyttää samalta kuin tulos `example3[example3.notnull()]`. Erona tässä on, että sen sijaan, että vain indeksoitaisiin maskattuja arvoja, `dropna` on poistanut puuttuvat arvot `Series`-objektista `example3`.\n", "\n", "Koska DataFrame-objekteilla on kaksi ulottuvuutta, ne tarjoavat enemmän vaihtoehtoja datan poistamiseen.\n" ] @@ -1207,9 +1207,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Huomasitko, että pandas muutti kaksi saraketta liukuluvuiksi mukautuakseen `NaN`-arvoihin?)\n", + "(Huomasitko, että pandas muutti kaksi saraketta liukuluvuiksi voidakseen käsitellä `NaN`-arvoja?)\n", "\n", - "Et voi poistaa yksittäistä arvoa `DataFrame`-objektista, joten sinun täytyy poistaa kokonaisia rivejä tai sarakkeita. Riippuen siitä, mitä olet tekemässä, saatat haluta tehdä jomman kumman, ja siksi pandas tarjoaa vaihtoehdot molempiin. Koska datatieteessä sarakkeet edustavat yleensä muuttujia ja rivit havaintoja, on todennäköisempää, että poistat rivejä datasta; `dropna()`-toiminnon oletusasetuksena on poistaa kaikki rivit, jotka sisältävät minkä tahansa null-arvon:\n" + "Et voi poistaa yksittäistä arvoa `DataFrame`-rakenteesta, joten sinun täytyy poistaa kokonaisia rivejä tai sarakkeita. Riippuen siitä, mitä olet tekemässä, saatat haluta tehdä jomman kumman, ja siksi pandas tarjoaa vaihtoehdot molempiin. Koska data-analytiikassa sarakkeet yleensä edustavat muuttujia ja rivit havaintoja, on todennäköisempää, että poistat rivejä datasta; `dropna()`-toiminnon oletusasetuksena on poistaa kaikki rivit, jotka sisältävät minkä tahansa null-arvon:\n" ] }, { @@ -1282,7 +1282,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "Jos tarpeellista, voit pudottaa NA-arvot sarakkeista. Käytä `axis=1` tehdäksesi niin:\n" + "Jos tarpeen, voit poistaa NA-arvot sarakkeista. Käytä `axis=1` tätä varten:\n" ] }, { @@ -1361,9 +1361,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Huomaa, että tämä voi poistaa paljon dataa, jonka haluaisit säilyttää, erityisesti pienemmissä aineistoissa. Mitä jos haluat poistaa rivejä tai sarakkeita, jotka sisältävät useita tai jopa kaikki null-arvot? Voit määrittää nämä asetukset `dropna`-metodissa käyttämällä `how`- ja `thresh`-parametreja.\n", + "Huomaa, että tämä voi poistaa paljon dataa, jonka haluaisit säilyttää, erityisesti pienemmissä aineistoissa. Entä jos haluat poistaa vain rivit tai sarakkeet, jotka sisältävät useita tai jopa kaikki null-arvot? Voit määrittää nämä asetukset `dropna`-metodissa käyttämällä `how`- ja `thresh`-parametreja.\n", "\n", - "Oletuksena `how='any'` (jos haluat tarkistaa itse tai nähdä, mitä muita parametreja metodilla on, suorita `example4.dropna?` koodisolussa). Voit vaihtoehtoisesti määrittää `how='all'`, jolloin poistetaan vain rivit tai sarakkeet, jotka sisältävät kaikki null-arvot. Laajennetaan esimerkkimme `DataFrame`-taulukkoa, jotta näemme tämän toiminnassa seuraavassa harjoituksessa.\n" + "Oletuksena `how='any'` (jos haluat tarkistaa itse tai nähdä, mitä muita parametreja metodilla on, suorita `example4.dropna?` koodisolussa). Voit vaihtoehtoisesti määrittää `how='all'`, jolloin poistetaan vain rivit tai sarakkeet, jotka sisältävät kaikki null-arvot. Laajennetaan esimerkkimme `DataFrame`-taulukkoa, jotta näet tämän toiminnassa seuraavassa harjoituksessa.\n" ] }, { @@ -1455,11 +1455,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> Tärkeimmät asiat: \n", + "> Keskeiset huomiot: \n", "1. Puuttuvien arvojen poistaminen on hyvä idea vain, jos tietojoukko on riittävän suuri. \n", "2. Kokonaisia rivejä tai sarakkeita voidaan poistaa, jos suurin osa niiden tiedoista puuttuu. \n", "3. `DataFrame.dropna(axis=)`-metodi auttaa puuttuvien arvojen poistamisessa. `axis`-argumentti määrittää, poistetaanko rivejä vai sarakkeita. \n", - "4. Myös `how`-argumenttia voidaan käyttää. Oletuksena se on asetettu arvoon `any`. Tämä tarkoittaa, että poistetaan vain ne rivit/sarakkeet, joissa on mitä tahansa puuttuvia arvoja. Se voidaan asettaa arvoon `all`, jolloin poistetaan vain ne rivit/sarakkeet, joissa kaikki arvot puuttuvat. \n" + "4. `how`-argumenttia voidaan myös käyttää. Oletuksena se on asetettu arvoon `any`, jolloin poistetaan vain ne rivit/sarakkeet, joissa on mitä tahansa puuttuvia arvoja. Sen voi asettaa arvoon `all`, jolloin poistetaan vain ne rivit/sarakkeet, joissa kaikki arvot ovat puuttuvia. \n" ] }, { @@ -1577,9 +1577,9 @@ "source": [ "### Puuttuvien arvojen täyttäminen\n", "\n", - "Joskus voi olla järkevää täyttää puuttuvat arvot sellaisilla, jotka voisivat olla kelvollisia. On olemassa muutamia tekniikoita puuttuvien arvojen täyttämiseen. Ensimmäinen on käyttää alakohtaista tietämystä (tietoa aiheesta, johon datasetti perustuu) arvioimaan puuttuvat arvot jollain tavalla.\n", + "Joskus voi olla järkevää korvata puuttuvat arvot sellaisilla, jotka voisivat olla päteviä. Puuttuvien arvojen täyttämiseen on muutamia tekniikoita. Ensimmäinen on käyttää alakohtaista tietämystä (tietoa aiheesta, johon datasetti perustuu) arvioimaan puuttuvat arvot jollain tavalla.\n", "\n", - "Voit käyttää `isnull`-funktiota tämän tekemiseen suoraan, mutta se voi olla työlästä, erityisesti jos täytettäviä arvoja on paljon. Koska tämä on niin yleinen tehtävä data-analytiikassa, pandas tarjoaa `fillna`-funktion, joka palauttaa kopion `Series`- tai `DataFrame`-objektista, jossa puuttuvat arvot on korvattu valitsemallasi arvolla. Luodaan toinen esimerkki `Series`-objekti, jotta nähdään, miten tämä toimii käytännössä.\n" + "Voit käyttää `isnull`-metodia tähän suoraan, mutta se voi olla työlästä, erityisesti jos täytettäviä arvoja on paljon. Koska tämä on niin yleinen tehtävä datatieteessä, pandas tarjoaa `fillna`-metodin, joka palauttaa kopion `Series`- tai `DataFrame`-objektista, jossa puuttuvat arvot on korvattu valitsemallasi arvolla. Luodaan toinen esimerkki `Series`-objekti, jotta nähdään, miten tämä toimii käytännössä.\n" ] }, { @@ -1588,12 +1588,12 @@ "id": "CE8S7louLezV" }, "source": [ - "### Kategoriset tiedot (Ei-numeeriset)\n", - "Aloitetaan ei-numeerisista tiedoista. Datoissa on usein sarakkeita, joissa on kategorisia tietoja, kuten sukupuoli, Totta tai Epätotta jne.\n", + "### Kategorinen data (ei-numeerinen)\n", + "Aloitetaan tarkastelemalla ei-numeerista dataa. Datoissa on usein sarakkeita, joissa on kategorista dataa, kuten sukupuoli, Totta tai Epätotta jne.\n", "\n", - "Useimmissa näistä tapauksista korvaamme puuttuvat arvot sarakkeen `moodilla`. Esimerkiksi, jos meillä on 100 datapistettä, joista 90 on vastannut Totta, 8 on vastannut Epätotta ja 2 ei ole vastannut mitään, voimme täyttää nämä 2 puuttuvaa arvoa Totta, ottaen huomioon koko sarakkeen.\n", + "Useimmissa tapauksissa puuttuvat arvot korvataan sarakkeen `moodilla`. Esimerkiksi, jos meillä on 100 datapistettä, joista 90 on vastannut Totta, 8 Epätotta ja 2 jättänyt vastaamatta, voimme täyttää nämä 2 puuttuvaa arvoa Totta, ottaen huomioon koko sarakkeen.\n", "\n", - "Tässäkin voimme käyttää asiantuntemusta. Otetaan esimerkki, jossa täytämme puuttuvat arvot moodilla.\n" + "Tässäkin voimme hyödyntää asiantuntemusta. Tarkastellaan esimerkkiä, jossa täytämme puuttuvat arvot moodilla.\n" ] }, { @@ -1698,7 +1698,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Nyt, etsitään ensin moodi ennen kuin täytetään `None`-arvo moodilla.\n" + ] }, { "cell_type": "code", @@ -1733,7 +1735,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Joten, korvaamme None arvolla True\n" + ] }, { "cell_type": "code", @@ -1843,7 +1847,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Kuten voimme nähdä, null-arvo on korvattu. Tarpeetonta sanoa, että olisimme voineet kirjoittaa mitä tahansa `'True'`-paikalle ja se olisi tullut korvatuksi.\n" + "Kuten voimme nähdä, null-arvo on korvattu. Tarpeetonta sanoa, että olisimme voineet kirjoittaa mitä tahansa `'True'`-paikalle, ja se olisi tullut korvatuksi.\n" ] }, { @@ -1855,14 +1859,14 @@ "### Numeerinen data\n", "Siirrytään nyt numeeriseen dataan. Tässä on kaksi yleistä tapaa korvata puuttuvat arvot:\n", "\n", - "1. Korvaa rivin mediaanilla\n", - "2. Korvaa rivin keskiarvolla\n", + "1. Korvaa rivin mediaanilla \n", + "2. Korvaa rivin keskiarvolla \n", "\n", - "Käytämme mediaania, kun data on vinoutunutta ja sisältää poikkeavia arvoja. Tämä johtuu siitä, että mediaani on kestävä poikkeaville arvoille.\n", + "Käytämme mediaania, kun data on vinoutunutta ja sisältää poikkeavia arvoja. Tämä johtuu siitä, että mediaani on kestävä poikkeamille.\n", "\n", "Kun data on normalisoitu, voimme käyttää keskiarvoa, koska siinä tapauksessa keskiarvo ja mediaani ovat melko lähellä toisiaan.\n", "\n", - "Ensiksi otetaan sarake, joka on normaalijakautunut, ja täytetään puuttuva arvo sarakkeen keskiarvolla.\n" + "Otetaan ensin sarake, joka on normaalijakautunut, ja täytetään puuttuva arvo sarakkeen keskiarvolla.\n" ] }, { @@ -2002,7 +2006,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Täyttö keskiarvolla\n" + ] }, { "cell_type": "code", @@ -2111,7 +2117,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Nyt kokeillaan toista tietokehystä, ja tällä kertaa korvaamme None-arvot sarakkeen mediaanilla.\n" + "Nyt kokeillaan toista dataframea, ja tällä kertaa korvaamme None-arvot sarakkeen mediaanilla.\n" ] }, { @@ -2251,7 +2257,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Täyttö mediaanilla\n" + ] }, { "cell_type": "code", @@ -2434,11 +2442,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Keskeiset huomiot: \n", - "1. Puuttuvien arvojen täyttäminen tulisi tehdä, kun dataa on vähän tai kun on olemassa strategia puuttuvien arvojen täyttämiseksi. \n", - "2. Alakohtaisia tietoja voidaan käyttää puuttuvien arvojen arvioimiseen ja täyttämiseen. \n", - "3. Kategorisessa datassa puuttuvat arvot korvataan useimmiten sarakkeen moodilla. \n", - "4. Numeerisessa datassa puuttuvat arvot täytetään yleensä sarakkeiden keskiarvolla (normalisoiduissa aineistoissa) tai mediaanilla. \n" + "> Keskeiset huomiot:\n", + "1. Puuttuvien arvojen täyttö tulisi tehdä, kun dataa on vähän tai kun on olemassa strategia puuttuvien arvojen täyttämiseksi.\n", + "2. Alakohtainen tieto voi auttaa puuttuvien arvojen täyttämisessä arvioimalla niitä.\n", + "3. Kategorisessa datassa puuttuvat arvot korvataan yleensä sarakkeen moodilla.\n", + "4. Numeraalisessa datassa puuttuvat arvot täytetään yleensä sarakkeen keskiarvolla (normalisoiduissa aineistoissa) tai mediaanilla.\n" ] }, { @@ -2469,7 +2477,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "Voit **täyttää eteenpäin** null-arvot, mikä tarkoittaa viimeisen kelvollisen arvon käyttämistä null-arvon täyttämiseen:\n" + "Voit **täyttää eteenpäin** null-arvot, eli käyttää viimeistä kelvollista arvoa null-arvon täyttämiseen:\n" ] }, { @@ -2510,7 +2518,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Voit myös **täyttää taaksepäin** propagoidaksesi seuraavan kelvollisen arvon taaksepäin täyttääksesi null-arvon:\n" + "Voit myös **täyttää taaksepäin** levittääksesi seuraavan kelvollisen arvon taaksepäin täyttääksesi null-arvon:\n" ] }, { @@ -2552,7 +2560,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "Kuten saattaisit arvata, tämä toimii samalla tavalla DataFramejen kanssa, mutta voit myös määrittää `axis`-parametrin, jonka mukaan täyttää null-arvot:\n" + "Kuten arvata saattaa, tämä toimii samalla tavalla DataFramejen kanssa, mutta voit myös määrittää `axis`-parametrin, jonka mukaan täyttää null-arvot:\n" ] }, { @@ -2758,7 +2766,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Voit olla luova `fillna`-toiminnon käytössä. Katsotaan esimerkiksi uudelleen `example4`, mutta tällä kertaa täytetään puuttuvat arvot `DataFrame`:n kaikkien arvojen keskiarvolla:\n" + "Voit olla luova `fillna`-menetelmän käytössä. Esimerkiksi tarkastellaan uudelleen `example4`:ää, mutta tällä kertaa täytetään puuttuvat arvot kaikkien `DataFrame`:n arvojen keskiarvolla:\n" ] }, { @@ -2849,9 +2857,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Huomaa, että sarake 3 on edelleen arvoton: oletussuuntana on täyttää arvot rivi kerrallaan.\n", + "Huomaa, että sarake 3 on edelleen arvoton: oletussuuntana on täyttää arvot rivikohtaisesti.\n", "\n", - "> **Yhteenveto:** Puuttuvien arvojen käsittelyyn on useita tapoja. Käyttämäsi strategia (arvojen poistaminen, korvaaminen tai tapa, jolla korvaat ne) tulisi määritellä kyseisen datan erityispiirteiden mukaan. Kehität paremman käsityksen puuttuvien arvojen käsittelystä sitä mukaa, kun käsittelet ja työskentelet datasetien parissa.\n" + "> **Yhteenveto:** Puuttuvien arvojen käsittelyyn datasetissä on useita tapoja. Käyttämäsi strategia (poistaminen, korvaaminen tai tapa, jolla korvaat ne) tulisi määritellä datan erityispiirteiden mukaan. Saat paremman käsityksen puuttuvien arvojen käsittelystä, kun työskentelet ja vuorovaikutat datasetien kanssa enemmän.\n" ] }, { @@ -2862,7 +2870,7 @@ "source": [ "### Kategorisen datan koodaus\n", "\n", - "Koneoppimismallit käsittelevät vain numeroita ja kaikenlaista numeerista dataa. Ne eivät pysty erottamaan kyllä ja ei -vastauksia, mutta ne voivat erottaa 0 ja 1 toisistaan. Joten, kun puuttuvat arvot on täytetty, meidän täytyy koodata kategorinen data numeeriseen muotoon, jotta malli ymmärtää sen.\n", + "Koneoppimismallit käsittelevät vain numeroita ja kaikenlaista numeerista dataa. Ne eivät pysty erottamaan kyllä- ja ei-vastauksia toisistaan, mutta ne voivat erottaa 0:n ja 1:n. Joten, kun puuttuvat arvot on täytetty, meidän täytyy koodata kategorinen data numeeriseen muotoon, jotta malli ymmärtää sen.\n", "\n", "Koodaus voidaan tehdä kahdella tavalla. Käymme ne läpi seuraavaksi.\n" ] @@ -2873,9 +2881,9 @@ "id": "uDq9SxB7mu5i" }, "source": [ - "**LABELIEN ENKODEROINTI**\n", + "**LUOKKAENKODERAUS**\n", "\n", - "Labelien enkoderointi tarkoittaa käytännössä jokaisen kategorian muuntamista numeroksi. Esimerkiksi, jos meillä on lentomatkustajien datasetti ja siinä on sarake, joka sisältää heidän matkustusluokkansa seuraavista vaihtoehdoista ['business class', 'economy class', 'first class']. Jos tähän sovelletaan labelien enkoderointia, se muunnetaan muotoon [0,1,2]. Katsotaanpa esimerkki koodin avulla. Koska tulevissa muistikirjoissa opimme käyttämään `scikit-learn`-kirjastoa, emme käytä sitä tässä.\n" + "Luokkaenkoderaus tarkoittaa käytännössä sitä, että jokainen kategoria muutetaan numeroksi. Esimerkiksi, jos meillä on lentomatkustajien datasetti, jossa on sarake heidän matkustusluokastaan seuraavien joukossa ['business class', 'economy class', 'first class'], luokkaenkoderaus muuttaisi nämä arvoiksi [0,1,2]. Katsotaanpa esimerkki koodin avulla. Koska tulevissa muistikirjoissa opettelemme käyttämään `scikit-learn`-kirjastoa, emme käytä sitä tässä.\n" ] }, { @@ -2983,7 +2991,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Jotta voimme suorittaa tunnistekoodauksen ensimmäiselle sarakkeelle, meidän on ensin määriteltävä luokista numeroksi tehtävä vastaavuus ennen korvaamista.\n" + "Jotta voimme suorittaa label encodingin ensimmäiselle sarakkeelle, meidän täytyy ensin määritellä luokkien ja numeroiden välinen vastaavuus ennen korvaamista.\n" ] }, { @@ -3085,7 +3093,7 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Kuten näemme, tulos vastaa odotuksiamme. Joten, milloin käytämme label encodingia? Label encodingia käytetään jommassakummassa tai molemmissa seuraavista tapauksista:\n", + "Kuten näemme, tulos vastaa odotuksiamme. Milloin siis käytämme label encodingia? Label encodingia käytetään jommassakummassa tai molemmissa seuraavista tapauksista:\n", "1. Kun kategorioiden määrä on suuri\n", "2. Kun kategoriat ovat järjestyksessä.\n" ] @@ -3098,7 +3106,7 @@ "source": [ "**ONE HOT ENCODING**\n", "\n", - "Toinen koodaustyyppi on One Hot Encoding. Tässä koodaustavassa jokainen sarakkeen kategoria lisätään omaksi sarakkeekseen, ja jokainen datapiste saa arvon 0 tai 1 sen mukaan, sisältääkö se kyseisen kategorian. Jos kategorioita on n kappaletta, datafreimiin lisätään n saraketta.\n", + "Toinen koodaustyyppi on One Hot Encoding. Tässä koodaustavassa jokainen sarakkeen kategoria lisätään erillisenä sarakkeena, ja jokainen datapiste saa arvon 0 tai 1 sen mukaan, sisältääkö se kyseisen kategorian. Jos kategorioita on n kappaletta, datafreimiin lisätään n saraketta.\n", "\n", "Esimerkiksi, otetaan sama lentokoneen luokkien esimerkki. Kategoriat olivat: ['business class', 'economy class', 'first class']. Jos suoritetaan One Hot Encoding, datasettiin lisätään seuraavat kolme saraketta: ['class_business class', 'class_economy class', 'class_first class'].\n" ] @@ -3342,9 +3350,9 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "Milloin käytämme one hot -enkoodausta? One hot -enkoodausta käytetään jommassakummassa tai molemmissa seuraavista tapauksista:\n", + "Milloin käytetään one hot -enkoodausta? One hot -enkoodausta käytetään jommassakummassa tai molemmissa seuraavista tapauksista:\n", "\n", - "1. Kun kategorioiden määrä ja aineiston koko ovat pienempiä.\n", + "1. Kun kategorioiden määrä ja datan koko ovat pienempiä.\n", "2. Kun kategorioilla ei ole erityistä järjestystä.\n" ] }, @@ -3354,9 +3362,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Tärkeimmät huomiot: \n", - "1. Koodaus tehdään muuntamaan ei-numeerinen data numeeriseksi dataksi. \n", - "2. Koodausta on kahta tyyppiä: Label-koodaus ja One Hot -koodaus, joita molempia voidaan käyttää datasetin tarpeiden mukaan. \n" + "> Keskeiset huomiot:\n", + "1. Koodaus tehdään muuntamaan ei-numeerinen data numeeriseksi dataksi.\n", + "2. Koodauksessa on kaksi tyyppiä: Label-koodaus ja One Hot -koodaus, joita voidaan käyttää datasetin tarpeiden mukaan.\n" ] }, { @@ -3365,11 +3373,11 @@ "id": "K8UXOJYRgRsJ" }, "source": [ - "## Poistetaan päällekkäiset tiedot\n", + "## Datan kaksoiskappaleiden poistaminen\n", "\n", - "> **Oppimistavoite:** Tämän alajakson lopussa sinun tulisi osata tunnistaa ja poistaa päällekkäiset arvot DataFrameista.\n", + "> **Oppimistavoite:** Tämän alajakson lopussa sinun pitäisi osata tunnistaa ja poistaa kaksoiskappaleet DataFrameista.\n", "\n", - "Puuttuvien tietojen lisäksi todellisissa tietoaineistoissa kohtaat usein myös päällekkäisiä tietoja. Onneksi pandas tarjoaa helpon tavan havaita ja poistaa päällekkäiset merkinnät.\n" + "Puuttuvan datan lisäksi todellisissa tietoaineistoissa törmätään usein myös kaksoiskappaleisiin. Onneksi pandas tarjoaa helpon tavan havaita ja poistaa kaksoiskappaleet.\n" ] }, { @@ -3378,9 +3386,9 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### Tunnistetaan duplikaatit: `duplicated`\n", + "### Tunnistetaan kaksoiskappaleet: `duplicated`\n", "\n", - "Voit helposti tunnistaa päällekkäiset arvot käyttämällä pandas-kirjaston `duplicated`-metodia, joka palauttaa Boolean-maskin, joka osoittaa, onko `DataFrame`-merkintä aiemman merkinnän duplikaatti. Luodaan toinen esimerkki `DataFrame` tämän toiminnon havainnollistamiseksi.\n" + "Voit helposti havaita kaksoiskappaleet käyttämällä pandas-kirjaston `duplicated`-metodia, joka palauttaa Boolean-maskin, joka osoittaa, onko `DataFrame`-tietue aiemman kaksoiskappale. Luodaan toinen esimerkkitietokehys, jotta näet tämän toiminnassa.\n" ] }, { @@ -3593,7 +3601,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Sekä `duplicated` että `drop_duplicates` oletuksena tarkastelevat kaikkia sarakkeita, mutta voit määrittää, että ne tarkastelevat vain tiettyä sarakejoukkoa `DataFrame`-objektissasi:\n" + "Sekä `duplicated` että `drop_duplicates` oletuksena tarkastelevat kaikkia sarakkeita, mutta voit määrittää, että ne tarkastelevat vain tiettyä osajoukkoa sarakkeista `DataFrame`-objektissasi:\n" ] }, { @@ -3669,7 +3677,525 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Yhteenveto:** Duplicaatin datan poistaminen on olennainen osa lähes jokaista data-analytiikkaprojektia. Duplicaatin data voi muuttaa analyysiesi tuloksia ja antaa sinulle virheellisiä tuloksia!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Todellisen maailman datan laadun tarkistukset\n", + "\n", + "> **Oppimistavoite:** Tämän osion lopussa sinun pitäisi osata tunnistaa ja korjata yleisiä todellisen maailman datan laatuongelmia, kuten epäjohdonmukaiset kategoriset arvot, poikkeavat numeeriset arvot (äärimmäiset poikkeamat) ja samankaltaiset entiteetit pienillä eroilla.\n", + "\n", + "Vaikka puuttuvat arvot ja täsmälleen samat duplikaatit ovat yleisiä ongelmia, todellisen maailman datassa esiintyy usein hienovaraisempia ongelmia:\n", + "\n", + "1. **Epäjohdonmukaiset kategoriset arvot**: Sama kategoria kirjoitettuna eri tavoin (esim. \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Poikkeavat numeeriset arvot**: Äärimmäiset poikkeamat, jotka viittaavat virheisiin datan syötössä (esim. ikä = 999)\n", + "3. **Lähes identtiset rivit**: Tietueet, jotka edustavat samaa entiteettiä pienillä eroilla\n", + "\n", + "Tutkitaan tekniikoita näiden ongelmien tunnistamiseen ja käsittelyyn.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Luodaan esimerkkidatasetti \"likaisesta\" datasta\n", + "\n", + "Aloitetaan luomalla esimerkkidatasetti, joka sisältää tyypillisiä ongelmia, joita kohtaamme todellisessa datassa:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Havaitse epäjohdonmukaiset kategoriset arvot\n", + "\n", + "Huomaa, että `country`-sarake sisältää useita esitystapoja samoille maille. Tunnistetaan nämä epäjohdonmukaisuudet:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Kategoristen arvojen standardisointi\n", + "\n", + "Voimme luoda kartoituksen näiden arvojen standardisoimiseksi. Yksinkertainen tapa on muuntaa arvot pieniksi kirjaimiksi ja luoda kartoitussanakirja:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Vaihtoehto: Epätarkka vertailu**\n", + "\n", + "Monimutkaisemmissa tapauksissa voimme käyttää epätarkkaa merkkijonojen vertailua `rapidfuzz`-kirjaston avulla havaitaksemme automaattisesti samankaltaiset merkkijonot:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Epänormaalien numeeristen arvojen (poikkeamien) tunnistaminen\n", + "\n", + "Kun tarkastelemme `age`-saraketta, huomaamme joitakin epäilyttäviä arvoja, kuten 199 ja -5. Käytetään tilastollisia menetelmiä näiden poikkeamien tunnistamiseen.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### IQR-menetelmän käyttö (Interkvartiilivälin menetelmä)\n", + "\n", + "IQR-menetelmä on vankka tilastollinen tekniikka poikkeavien arvojen tunnistamiseen, joka on vähemmän herkkä äärimmäisille arvoille:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Z-score-menetelmän käyttö\n", + "\n", + "Z-score-menetelmä tunnistaa poikkeamat keskiarvosta laskettujen keskihajontojen perusteella:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Poikkeamien käsittely\n", + "\n", + "Kun poikkeamat on havaittu, niitä voidaan käsitellä useilla tavoilla:\n", + "1. **Poista**: Poista rivit, joissa on poikkeamia (jos ne ovat virheitä)\n", + "2. **Rajoita**: Korvaa raja-arvoilla\n", + "3. **Korvaa NaN-arvolla**: Käsittele puuttuvana tietona ja käytä imputointitekniikoita\n", + "4. **Pidä**: Jos ne ovat oikeutettuja äärimmäisiä arvoja\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Lähes samankaltaisten rivien tunnistaminen\n", + "\n", + "Huomaa, että datassamme on useita merkintöjä \"John Smithille\" hieman erilaisilla arvoilla. Tunnistetaan mahdolliset kaksoiskappaleet nimien samankaltaisuuden perusteella.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Läheisten kaksoiskappaleiden löytäminen epätarkalla vastaavuudella\n", + "\n", + "Kehittyneempää kaksoiskappaleiden tunnistusta varten voimme käyttää epätarkkaa vastaavuutta löytääksemme samankaltaisia nimiä:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Käsittele duplikaatteja\n", + "\n", + "Kun duplikaatit on tunnistettu, sinun täytyy päättää, miten ne käsitellään:\n", + "1. **Pidä ensimmäinen esiintymä**: Käytä `drop_duplicates(keep='first')`\n", + "2. **Pidä viimeinen esiintymä**: Käytä `drop_duplicates(keep='last')`\n", + "3. **Yhdistä tiedot**: Yhdistä tietoja duplikaattiriveistä\n", + "4. **Manuaalinen tarkistus**: Merkitse ihmisen tarkistettavaksi\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Yhteenveto: Täydellinen datan puhdistusputki\n", + "\n", + "Kootaan kaikki yhteen kattavaksi puhdistusputkeksi:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Haasteharjoitus\n", + "\n", + "Nyt on sinun vuorosi! Alla on uusi tietorivi, jossa on useita laatuongelmia. Voitko:\n", + "\n", + "1. Tunnistaa kaikki ongelmat tässä rivissä\n", + "2. Kirjoittaa koodin jokaisen ongelman korjaamiseksi\n", + "3. Lisätä puhdistetun rivin tietojoukkoon\n", + "\n", + "Tässä on ongelmallinen data:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Keskeiset huomiot\n", + "\n", + "1. **Epäjohdonmukaiset kategoriat** ovat yleisiä todellisessa datassa. Tarkista aina yksilölliset arvot ja yhdenmukaista ne käyttämällä kartoituksia tai epätarkkaa vastaavuutta.\n", + "\n", + "2. **Poikkeamat** voivat vaikuttaa merkittävästi analyysiisi. Käytä alakohtaista tietämystä yhdistettynä tilastollisiin menetelmiin (IQR, Z-score) niiden havaitsemiseksi.\n", + "\n", + "3. **Lähes kaksoiskappaleet** ovat vaikeampia havaita kuin tarkat kaksoiskappaleet. Harkitse epätarkkaa vastaavuutta ja datan normalisointia (pienet kirjaimet, välilyöntien poisto) niiden tunnistamiseksi.\n", + "\n", + "4. **Datan puhdistus on iteratiivista**. Saatat joutua käyttämään useita tekniikoita ja tarkistamaan tulokset ennen kuin viimeistelet puhdistetun datasetin.\n", + "\n", + "5. **Dokumentoi päätöksesi**. Pidä kirjaa siitä, mitä puhdistusvaiheita sovelsit ja miksi, sillä tämä on tärkeää toistettavuuden ja läpinäkyvyyden kannalta.\n", + "\n", + "> **Paras käytäntö:** Säilytä aina kopio alkuperäisestä \"likaisesta\" datasta. Älä koskaan korvaa lähdedatatiedostoja – luo puhdistettuja versioita selkeillä nimeämiskäytännöillä, kuten `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", @@ -3703,8 +4229,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:43:43+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:26:42+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "fi" } diff --git a/translations/fr/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/fr/2-Working-With-Data/08-data-preparation/notebook.ipynb index 2e4b883f..30bcce83 100644 --- a/translations/fr/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/fr/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -10,13 +10,13 @@ "\n", "[Source originale du notebook tirée de *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio par Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", - "## Explorer les informations d'un `DataFrame`\n", + "## Exploration des informations du `DataFrame`\n", "\n", "> **Objectif d'apprentissage :** À la fin de cette sous-section, vous devriez être à l'aise pour trouver des informations générales sur les données stockées dans les DataFrames de pandas.\n", "\n", - "Une fois vos données chargées dans pandas, elles seront très probablement sous forme de `DataFrame`. Cependant, si le jeu de données dans votre `DataFrame` contient 60 000 lignes et 400 colonnes, comment commencer à comprendre ce avec quoi vous travaillez ? Heureusement, pandas offre des outils pratiques pour examiner rapidement les informations générales d'un `DataFrame`, ainsi que les premières et dernières lignes.\n", + "Une fois vos données chargées dans pandas, elles seront très probablement dans un `DataFrame`. Cependant, si le jeu de données dans votre `DataFrame` contient 60 000 lignes et 400 colonnes, comment commencer à comprendre ce avec quoi vous travaillez ? Heureusement, pandas offre des outils pratiques pour examiner rapidement des informations générales sur un `DataFrame`, ainsi que les premières et dernières lignes.\n", "\n", - "Pour explorer cette fonctionnalité, nous allons importer la bibliothèque Python scikit-learn et utiliser un jeu de données emblématique que tous les data scientists ont vu des centaines de fois : le jeu de données *Iris* du biologiste britannique Ronald Fisher, utilisé dans son article de 1936 \"The use of multiple measurements in taxonomic problems\".\n" + "Pour explorer cette fonctionnalité, nous allons importer la bibliothèque Python scikit-learn et utiliser un jeu de données emblématique que tous les data scientists ont vu des centaines de fois : le jeu de données *Iris* du biologiste britannique Ronald Fisher, utilisé dans son article de 1936 \"The use of multiple measurements in taxonomic problems\" :\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Nous avons chargé le jeu de données Iris dans la variable `iris_df`. Avant d'explorer les données, il serait utile de connaître le nombre de points de données que nous avons ainsi que la taille globale du jeu de données. Il est important d'avoir une idée du volume de données avec lequel nous travaillons.\n" + "Nous avons chargé le jeu de données Iris dans la variable `iris_df`. Avant d'explorer les données, il serait utile de connaître le nombre de points de données que nous avons ainsi que la taille globale du jeu de données. Il est important de se faire une idée du volume de données avec lequel nous travaillons.\n" ] }, { @@ -78,7 +78,7 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Nous avons donc 150 lignes et 4 colonnes de données. Chaque ligne représente un point de données et chaque colonne représente une seule caractéristique associée au tableau de données. En gros, il y a 150 points de données contenant chacun 4 caractéristiques.\n", + "Nous avons donc 150 lignes et 4 colonnes de données. Chaque ligne représente un point de données et chaque colonne représente une caractéristique unique associée au tableau de données. En gros, il y a 150 points de données contenant chacun 4 caractéristiques.\n", "\n", "`shape` ici est un attribut du tableau de données et non une fonction, c'est pourquoi il ne se termine pas par une paire de parenthèses.\n" ] @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Comme nous pouvons le voir, il y a quatre (4) colonnes. L'attribut `columns` nous indique le nom des colonnes et essentiellement rien d'autre. Cet attribut prend de l'importance lorsque nous voulons identifier les caractéristiques qu'un ensemble de données contient.\n" + "Comme nous pouvons le voir, il y a quatre (4) colonnes. L'attribut `columns` nous indique le nom des colonnes et rien d'autre. Cet attribut prend de l'importance lorsque nous voulons identifier les caractéristiques qu'un ensemble de données contient.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "La quantité de données (donnée par l'attribut `shape`) et le nom des caractéristiques ou colonnes (donné par l'attribut `columns`) nous donnent des informations sur le jeu de données. Maintenant, nous souhaitons explorer le jeu de données plus en profondeur. La fonction `DataFrame.info()` est très utile pour cela.\n" + "La quantité de données (donnée par l'attribut `shape`) et le nom des caractéristiques ou colonnes (donné par l'attribut `columns`) nous donnent des informations sur le jeu de données. Maintenant, nous voudrions explorer le jeu de données plus en profondeur. La fonction `DataFrame.info()` est très utile pour cela.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "À partir de là, nous pouvons faire quelques observations : \n", - "1. Le type de données de chaque colonne : Dans ce jeu de données, toutes les données sont stockées sous forme de nombres à virgule flottante 64 bits. \n", - "2. Nombre de valeurs non nulles : Gérer les valeurs nulles est une étape importante dans la préparation des données. Cela sera traité plus tard dans le notebook. \n" + "À partir d'ici, nous pouvons faire quelques observations :\n", + "1. Le type de données de chaque colonne : Dans ce jeu de données, toutes les données sont stockées sous forme de nombres à virgule flottante 64 bits.\n", + "2. Nombre de valeurs non nulles : La gestion des valeurs nulles est une étape importante dans la préparation des données. Cela sera traité plus tard dans le notebook.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "Le résultat ci-dessus montre le nombre total de points de données, la moyenne, l'écart type, le minimum, le premier quartile (25 %), la médiane (50 %), le troisième quartile (75 %) et la valeur maximale de chaque colonne.\n" + "La sortie ci-dessus montre le nombre total de points de données, la moyenne, l'écart-type, le minimum, le quartile inférieur (25 %), la médiane (50 %), le quartile supérieur (75 %) et la valeur maximale de chaque colonne.\n" ] }, { @@ -332,7 +332,7 @@ }, "source": [ "### `DataFrame.head`\n", - "Avec toutes les fonctions et attributs mentionnés ci-dessus, nous avons obtenu une vue d'ensemble du jeu de données. Nous savons combien de points de données il y a, combien de caractéristiques sont présentes, le type de données de chaque caractéristique et le nombre de valeurs non nulles pour chaque caractéristique.\n", + "Avec toutes les fonctions et attributs mentionnés ci-dessus, nous avons obtenu une vue d'ensemble du dataset. Nous savons combien de points de données il contient, combien de caractéristiques il possède, le type de données de chaque caractéristique et le nombre de valeurs non nulles pour chacune d'elles.\n", "\n", "Il est maintenant temps de regarder les données elles-mêmes. Voyons à quoi ressemblent les premières lignes (les premiers points de données) de notre `DataFrame` :\n" ] @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "En tant que résultat ici, nous pouvons voir cinq (5) entrées du jeu de données. Si nous regardons l'index à gauche, nous découvrons que ce sont les cinq premières lignes.\n" + "Comme le résultat ici, nous pouvons voir cinq (5) entrées du jeu de données. Si nous regardons l'index à gauche, nous découvrons que ce sont les cinq premières lignes.\n" ] }, { @@ -584,9 +584,9 @@ "source": [ "En pratique, il est utile de pouvoir examiner facilement les premières lignes ou les dernières lignes d'un `DataFrame`, en particulier lorsque vous recherchez des valeurs aberrantes dans des ensembles de données ordonnés.\n", "\n", - "Toutes les fonctions et attributs présentés ci-dessus à l'aide d'exemples de code nous aident à avoir un aperçu et une idée des données.\n", + "Toutes les fonctions et attributs présentés ci-dessus à l'aide d'exemples de code nous aident à avoir un aperçu et une idée du contenu des données.\n", "\n", - "> **À retenir :** Rien qu'en regardant les métadonnées sur les informations contenues dans un DataFrame ou les premières et dernières valeurs de celui-ci, vous pouvez obtenir une idée immédiate de la taille, de la forme et du contenu des données avec lesquelles vous travaillez.\n" + "> **À retenir :** Rien qu'en regardant les métadonnées sur les informations contenues dans un DataFrame ou les premières et dernières valeurs, vous pouvez avoir une idée immédiate de la taille, de la structure et du contenu des données avec lesquelles vous travaillez.\n" ] }, { @@ -595,10 +595,10 @@ "id": "TvurZyLSDxq_" }, "source": [ - "### Données Manquantes\n", + "### Données manquantes\n", "Plongeons dans le sujet des données manquantes. Les données manquantes surviennent lorsqu'aucune valeur n'est enregistrée dans certaines colonnes.\n", "\n", - "Prenons un exemple : supposons qu'une personne soucieuse de son poids ne remplisse pas le champ \"poids\" dans un sondage. Dans ce cas, la valeur du poids pour cette personne sera manquante.\n", + "Prenons un exemple : disons qu'une personne est préoccupée par son poids et ne remplit pas le champ correspondant dans un sondage. Dans ce cas, la valeur du poids pour cette personne sera manquante.\n", "\n", "La plupart du temps, dans les ensembles de données du monde réel, des valeurs manquantes apparaissent.\n", "\n", @@ -606,7 +606,7 @@ "\n", "Pandas gère les valeurs manquantes de deux manières. La première, que vous avez déjà vue dans les sections précédentes, est `NaN`, ou Not a Number. Il s'agit en réalité d'une valeur spéciale faisant partie de la spécification IEEE des nombres à virgule flottante, et elle est uniquement utilisée pour indiquer des valeurs flottantes manquantes.\n", "\n", - "Pour les valeurs manquantes autres que les nombres flottants, pandas utilise l'objet Python `None`. Bien qu'il puisse sembler déroutant de rencontrer deux types de valeurs différentes qui expriment essentiellement la même chose, il existe des raisons programmatiques solides derrière ce choix de conception. En pratique, cette approche permet à pandas d'offrir un bon compromis dans la grande majorité des cas. Cela dit, `None` et `NaN` comportent tous deux des restrictions dont vous devez être conscient en ce qui concerne leur utilisation.\n" + "Pour les valeurs manquantes autres que les nombres flottants, pandas utilise l'objet Python `None`. Bien qu'il puisse sembler déroutant de rencontrer deux types de valeurs différentes qui expriment essentiellement la même chose, il existe des raisons programmatiques solides derrière ce choix de conception. En pratique, cette approche permet à pandas d'offrir un bon compromis dans la grande majorité des cas. Cela dit, `None` et `NaN` comportent des restrictions dont vous devez être conscient en ce qui concerne leur utilisation.\n" ] }, { @@ -615,8 +615,8 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None` : données manquantes non flottantes\n", - "Étant donné que `None` provient de Python, il ne peut pas être utilisé dans les tableaux NumPy et pandas qui ne sont pas de type de données `'object'`. Rappelez-vous, les tableaux NumPy (et les structures de données dans pandas) ne peuvent contenir qu'un seul type de données. C'est ce qui leur confère leur immense puissance pour le traitement de données à grande échelle et les calculs, mais cela limite également leur flexibilité. Ces tableaux doivent être convertis au \"plus petit dénominateur commun\", c'est-à-dire le type de données qui peut englober tout le contenu du tableau. Lorsque `None` est présent dans le tableau, cela signifie que vous travaillez avec des objets Python.\n", + "### `None`: données manquantes non flottantes\n", + "Étant donné que `None` provient de Python, il ne peut pas être utilisé dans les tableaux NumPy et pandas qui ne sont pas de type de données `'object'`. Rappelez-vous que les tableaux NumPy (et les structures de données dans pandas) ne peuvent contenir qu'un seul type de données. C'est ce qui leur confère une puissance considérable pour le traitement de données à grande échelle et les calculs, mais cela limite également leur flexibilité. Ces tableaux doivent être convertis au \"plus petit dénominateur commun\", c'est-à-dire au type de données qui englobe tout dans le tableau. Lorsque `None` est présent dans le tableau, cela signifie que vous travaillez avec des objets Python.\n", "\n", "Pour voir cela en pratique, considérez l'exemple de tableau suivant (notez le `dtype` associé) :\n" ] @@ -657,7 +657,7 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "La réalité des types de données promus entraîne deux conséquences. Premièrement, les opérations seront effectuées au niveau du code Python interprété plutôt que du code NumPy compilé. En d'autres termes, cela signifie que toute opération impliquant des `Series` ou des `DataFrames` contenant `None` sera plus lente. Bien que vous ne remarquiez probablement pas cet impact sur les performances, cela pourrait devenir problématique pour des ensembles de données volumineux.\n", + "La réalité des types de données surélevés entraîne deux conséquences. Premièrement, les opérations seront effectuées au niveau du code Python interprété plutôt que du code NumPy compilé. En d'autres termes, cela signifie que toutes les opérations impliquant des `Series` ou des `DataFrames` contenant `None` seront plus lentes. Bien que vous ne remarquiez probablement pas cet impact sur les performances, cela pourrait devenir problématique pour des ensembles de données volumineux.\n", "\n", "La deuxième conséquence découle de la première. Étant donné que `None` ramène essentiellement les `Series` ou les `DataFrames` dans le monde du Python classique, l'utilisation d'agrégations NumPy/pandas comme `sum()` ou `min()` sur des tableaux contenant une valeur ``None`` produira généralement une erreur :\n" ] @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Conclusion clé** : L'addition (et d'autres opérations) entre des entiers et des valeurs `None` est indéfinie, ce qui peut limiter ce que vous pouvez faire avec des ensembles de données qui en contiennent.\n" + "**Conclusion clé** : L'addition (et autres opérations) entre des entiers et des valeurs `None` est indéfinie, ce qui peut limiter ce que vous pouvez faire avec des ensembles de données qui en contiennent.\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "La bonne nouvelle : les agrégations exécutées sur des tableaux contenant `NaN` ne génèrent pas d'erreurs. La mauvaise nouvelle : les résultats ne sont pas uniformément utiles :\n" + "La bonne nouvelle : les agrégations exécutées sur des tableaux contenant des `NaN` ne génèrent pas d'erreurs. La mauvaise nouvelle : les résultats ne sont pas uniformément utiles :\n" ] }, { @@ -842,7 +842,7 @@ "source": [ "### `NaN` et `None` : valeurs nulles dans pandas\n", "\n", - "Bien que `NaN` et `None` puissent se comporter légèrement différemment, pandas est conçu pour les traiter de manière interchangeable. Pour comprendre ce que cela signifie, prenons une `Series` d'entiers :\n" + "Bien que `NaN` et `None` puissent se comporter légèrement différemment, pandas est conçu pour les gérer de manière interchangeable. Pour comprendre ce que nous voulons dire, considérez une `Series` d'entiers :\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Dans le processus de conversion des types de données pour établir une homogénéité des données dans les `Series` et les `DataFrame`s, pandas peut facilement basculer entre les valeurs manquantes `None` et `NaN`. En raison de cette caractéristique de conception, il peut être utile de considérer `None` et `NaN` comme deux variantes différentes de \"null\" dans pandas. En effet, certains des principaux outils que vous utiliserez pour gérer les valeurs manquantes dans pandas reflètent cette idée dans leurs noms :\n", + "Dans le processus de conversion des types de données pour établir une homogénéité des données dans les `Series` et les `DataFrame`s, pandas peut facilement alterner entre les valeurs manquantes `None` et `NaN`. En raison de cette caractéristique de conception, il peut être utile de considérer `None` et `NaN` comme deux variantes différentes de \"null\" dans pandas. En effet, certains des principaux outils que vous utiliserez pour gérer les valeurs manquantes dans pandas reflètent cette idée dans leurs noms :\n", "\n", "- `isnull()`: Génère un masque booléen indiquant les valeurs manquantes\n", "- `notnull()`: Opposé de `isnull()`\n", "- `dropna()`: Renvoie une version filtrée des données\n", "- `fillna()`: Renvoie une copie des données avec les valeurs manquantes remplies ou imputées\n", "\n", - "Ce sont des méthodes importantes à maîtriser et avec lesquelles il est essentiel de se familiariser, alors examinons chacune d'elles en détail.\n" + "Ce sont des méthodes importantes à maîtriser et à utiliser avec aisance, alors examinons chacune d'elles en détail.\n" ] }, { @@ -925,7 +925,7 @@ "### Détection des valeurs nulles\n", "\n", "Maintenant que nous avons compris l'importance des valeurs manquantes, nous devons les détecter dans notre ensemble de données avant de les traiter. \n", - "Les méthodes `isnull()` et `notnull()` sont vos outils principaux pour détecter les données nulles. Elles renvoient toutes deux des masques booléens sur vos données.\n" + "Les méthodes `isnull()` et `notnull()` sont vos principales options pour détecter les données nulles. Elles renvoient toutes deux des masques booléens sur vos données.\n" ] }, { @@ -978,9 +978,9 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Regardez attentivement le contenu. Y a-t-il quelque chose qui vous surprend ? Bien que `0` soit un nul arithmétique, c'est néanmoins un entier tout à fait valide, et pandas le traite comme tel. `''` est un peu plus subtil. Bien que nous l'ayons utilisé dans la Section 1 pour représenter une valeur de chaîne vide, c'est néanmoins un objet de type chaîne et non une représentation de nul du point de vue de pandas.\n", + "Regardez attentivement le résultat. Est-ce que quelque chose vous surprend ? Bien que `0` soit un nul arithmétique, c'est néanmoins un entier parfaitement valide, et pandas le traite comme tel. `''` est un peu plus subtil. Bien que nous l'ayons utilisé dans la Section 1 pour représenter une valeur de chaîne vide, c'est néanmoins un objet de type chaîne et non une représentation de nul selon pandas.\n", "\n", - "Maintenant, retournons la situation et utilisons ces méthodes d'une manière plus proche de leur utilisation en pratique. Vous pouvez utiliser des masques booléens directement comme index d'une ``Series`` ou d'un ``DataFrame``, ce qui peut être utile lorsque vous essayez de travailler avec des valeurs manquantes (ou présentes) isolées.\n", + "Maintenant, retournons la situation et utilisons ces méthodes d'une manière plus proche de leur utilisation pratique. Vous pouvez utiliser des masques booléens directement comme index de ``Series`` ou ``DataFrame``, ce qui peut être utile lorsque vous essayez de travailler avec des valeurs manquantes (ou présentes) isolées.\n", "\n", "Si nous voulons le nombre total de valeurs manquantes, nous pouvons simplement effectuer une somme sur le masque produit par la méthode `isnull()`.\n" ] @@ -1040,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Conclusion clé** : Les méthodes `isnull()` et `notnull()` produisent des résultats similaires lorsque vous les utilisez dans des DataFrames : elles affichent les résultats et l'index de ces résultats, ce qui vous aidera énormément lorsque vous travaillez avec vos données.\n" + "**Conclusion clé** : Les méthodes `isnull()` et `notnull()` produisent des résultats similaires lorsque vous les utilisez dans des DataFrames : elles affichent les résultats ainsi que l'index de ces résultats, ce qui vous sera d'une grande aide lorsque vous travaillez avec vos données.\n" ] }, { @@ -1049,7 +1049,7 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### Gestion des données manquantes\n", + "### Gérer les données manquantes\n", "\n", "> **Objectif d'apprentissage :** À la fin de cette sous-section, vous devriez savoir comment et quand remplacer ou supprimer les valeurs nulles dans les DataFrames.\n", "\n", @@ -1062,7 +1062,7 @@ "1. Supprimer la ligne contenant la valeur manquante\n", "2. Remplacer la valeur manquante par une autre valeur\n", "\n", - "Nous discuterons en détail de ces deux méthodes ainsi que de leurs avantages et inconvénients.\n" + "Nous discuterons de ces deux méthodes ainsi que de leurs avantages et inconvénients en détail.\n" ] }, { @@ -1073,9 +1073,9 @@ "source": [ "### Suppression des valeurs nulles\n", "\n", - "La quantité de données que nous transmettons à notre modèle a un impact direct sur ses performances. Supprimer les valeurs nulles signifie que nous réduisons le nombre de points de données, et donc la taille de l'ensemble de données. Il est donc conseillé de supprimer les lignes contenant des valeurs nulles lorsque l'ensemble de données est assez volumineux.\n", + "La quantité de données que nous transmettons à notre modèle a un effet direct sur ses performances. Supprimer les valeurs nulles signifie que nous réduisons le nombre de points de données, et donc la taille du jeu de données. Il est donc conseillé de supprimer les lignes contenant des valeurs nulles lorsque le jeu de données est assez grand.\n", "\n", - "Un autre cas pourrait être qu'une certaine ligne ou colonne contient beaucoup de valeurs manquantes. Dans ce cas, elles peuvent être supprimées, car elles n'apporteraient pas beaucoup de valeur à notre analyse étant donné que la majorité des données de cette ligne/colonne est manquante.\n", + "Un autre cas pourrait être qu'une certaine ligne ou colonne contient beaucoup de valeurs manquantes. Dans ce cas, elles peuvent être supprimées car elles n'apporteraient pas beaucoup de valeur à notre analyse, étant donné que la plupart des données sont manquantes pour cette ligne/colonne.\n", "\n", "Au-delà de l'identification des valeurs manquantes, pandas offre un moyen pratique de supprimer les valeurs nulles des `Series` et des `DataFrame`. Pour voir cela en pratique, revenons à `example3`. La fonction `DataFrame.dropna()` permet de supprimer les lignes contenant des valeurs nulles.\n" ] @@ -1116,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "Notez que cela devrait ressembler à votre résultat de `example3[example3.notnull()]`. La différence ici est que, au lieu de simplement indexer les valeurs masquées, `dropna` a supprimé ces valeurs manquantes de la `Series` `example3`.\n", + "Notez que cela devrait ressembler à votre sortie de `example3[example3.notnull()]`. La différence ici est que, plutôt que de simplement indexer les valeurs masquées, `dropna` a supprimé ces valeurs manquantes de la `Series` `example3`.\n", "\n", - "Étant donné que les DataFrames ont deux dimensions, ils offrent davantage d'options pour supprimer des données.\n" + "Étant donné que les DataFrames ont deux dimensions, ils offrent plus d'options pour supprimer des données.\n" ] }, { @@ -1210,7 +1210,7 @@ "source": [ "(Avez-vous remarqué que pandas a converti deux des colonnes en flottants pour gérer les `NaN` ?)\n", "\n", - "Vous ne pouvez pas supprimer une seule valeur d'un `DataFrame`, vous devez donc supprimer des lignes ou des colonnes entières. Selon ce que vous faites, vous pourriez préférer l'une ou l'autre option, et pandas vous offre des possibilités pour les deux. Étant donné qu'en science des données, les colonnes représentent généralement des variables et les lignes représentent des observations, il est plus courant de supprimer des lignes de données ; le paramètre par défaut de `dropna()` est de supprimer toutes les lignes contenant des valeurs nulles :\n" + "Vous ne pouvez pas supprimer une seule valeur d'un `DataFrame`, vous devez donc supprimer des lignes ou des colonnes entières. Selon ce que vous faites, vous pourriez préférer l'une ou l'autre option, et pandas vous offre des possibilités pour les deux. Étant donné qu'en science des données, les colonnes représentent généralement des variables et les lignes des observations, il est plus courant de supprimer des lignes de données ; le paramètre par défaut de `dropna()` est de supprimer toutes les lignes contenant des valeurs nulles :\n" ] }, { @@ -1362,7 +1362,7 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Notez que cela peut supprimer beaucoup de données que vous pourriez vouloir conserver, en particulier dans des ensembles de données plus petits. Que faire si vous souhaitez simplement supprimer des lignes ou des colonnes contenant plusieurs valeurs nulles, voire uniquement des valeurs nulles ? Vous pouvez spécifier ces paramètres dans `dropna` avec les arguments `how` et `thresh`.\n", + "Notez que cela peut supprimer beaucoup de données que vous pourriez vouloir conserver, en particulier dans des ensembles de données plus petits. Que faire si vous souhaitez simplement supprimer les lignes ou colonnes contenant plusieurs valeurs nulles, voire toutes ? Vous pouvez spécifier ces paramètres dans `dropna` avec les arguments `how` et `thresh`.\n", "\n", "Par défaut, `how='any'` (si vous souhaitez vérifier par vous-même ou voir quels autres paramètres la méthode propose, exécutez `example4.dropna?` dans une cellule de code). Vous pouvez également spécifier `how='all'` pour ne supprimer que les lignes ou colonnes contenant uniquement des valeurs nulles. Étendons notre exemple de `DataFrame` pour voir cela en action dans le prochain exercice.\n" ] @@ -1460,7 +1460,7 @@ "1. Supprimer les valeurs nulles est une bonne idée uniquement si le jeu de données est suffisamment grand. \n", "2. Des lignes ou colonnes entières peuvent être supprimées si la majorité de leurs données sont manquantes. \n", "3. La méthode `DataFrame.dropna(axis=)` permet de supprimer les valeurs nulles. L'argument `axis` indique si ce sont les lignes ou les colonnes qui doivent être supprimées. \n", - "4. L'argument `how` peut également être utilisé. Par défaut, il est défini sur `any`. Ainsi, seules les lignes/colonnes contenant une ou plusieurs valeurs nulles sont supprimées. Il peut être défini sur `all` pour spécifier que seules les lignes/colonnes où toutes les valeurs sont nulles seront supprimées. \n" + "4. L'argument `how` peut également être utilisé. Par défaut, il est défini sur `any`. Ainsi, seules les lignes/colonnes contenant des valeurs nulles sont supprimées. Il peut être défini sur `all` pour spécifier que seules les lignes/colonnes où toutes les valeurs sont nulles seront supprimées. \n" ] }, { @@ -1578,7 +1578,7 @@ "source": [ "### Remplir les valeurs nulles\n", "\n", - "Il peut parfois être judicieux de remplacer les valeurs manquantes par des valeurs qui pourraient être valides. Il existe plusieurs techniques pour remplir les valeurs nulles. La première consiste à utiliser les connaissances du domaine (connaissance du sujet sur lequel le jeu de données est basé) pour approximativement estimer les valeurs manquantes.\n", + "Il est parfois logique de remplacer les valeurs manquantes par des valeurs qui pourraient être valides. Il existe plusieurs techniques pour remplir les valeurs nulles. La première consiste à utiliser les connaissances du domaine (connaissance du sujet sur lequel repose le jeu de données) pour estimer d'une manière ou d'une autre les valeurs manquantes.\n", "\n", "Vous pourriez utiliser `isnull` pour effectuer cette opération directement, mais cela peut être fastidieux, surtout si vous avez beaucoup de valeurs à remplir. Étant donné que cette tâche est très courante en science des données, pandas propose `fillna`, qui retourne une copie de la `Series` ou du `DataFrame` avec les valeurs manquantes remplacées par celles de votre choix. Créons un autre exemple de `Series` pour voir comment cela fonctionne en pratique.\n" ] @@ -1590,11 +1590,11 @@ }, "source": [ "### Données catégoriques (non numériques)\n", - "Commençons par les données non numériques. Dans les ensembles de données, nous avons des colonnes contenant des données catégoriques. Par exemple : Genre, Vrai ou Faux, etc.\n", + "Commençons par les données non numériques. Dans les ensembles de données, nous avons des colonnes contenant des données catégoriques. Par exemple, le genre, Vrai ou Faux, etc.\n", "\n", - "Dans la plupart de ces cas, nous remplaçons les valeurs manquantes par le `mode` de la colonne. Supposons que nous avons 100 points de données, dont 90 indiquent Vrai, 8 indiquent Faux et 2 n'ont pas répondu. Alors, nous pouvons remplir les 2 valeurs manquantes avec Vrai, en prenant en compte l'ensemble de la colonne.\n", + "Dans la plupart de ces cas, nous remplaçons les valeurs manquantes par la `mode` de la colonne. Supposons que nous avons 100 points de données, dont 90 indiquent Vrai, 8 indiquent Faux et 2 n'ont pas répondu. Alors, nous pouvons remplir les 2 valeurs manquantes avec Vrai, en prenant en compte l'ensemble de la colonne.\n", "\n", - "Encore une fois, ici, nous pouvons utiliser nos connaissances du domaine. Prenons un exemple de remplissage avec le mode.\n" + "Encore une fois, ici, nous pouvons utiliser des connaissances spécifiques au domaine. Prenons un exemple de remplissage avec la mode.\n" ] }, { @@ -1699,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Maintenant, trouvons d'abord la mode avant de remplir la valeur `None` avec la mode.\n" + ] }, { "cell_type": "code", @@ -1734,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Donc, nous remplacerons None par True\n" + ] }, { "cell_type": "code", @@ -1859,11 +1863,11 @@ "1. Remplacer par la médiane de la ligne \n", "2. Remplacer par la moyenne de la ligne \n", "\n", - "Nous utilisons la médiane dans le cas de données asymétriques avec des valeurs aberrantes. En effet, la médiane est robuste face aux valeurs aberrantes.\n", + "On remplace par la médiane dans le cas de données asymétriques avec des valeurs aberrantes. En effet, la médiane est robuste face aux valeurs aberrantes.\n", "\n", - "Lorsque les données sont normalisées, nous pouvons utiliser la moyenne, car dans ce cas, la moyenne et la médiane seront assez proches.\n", + "Lorsque les données sont normalisées, on peut utiliser la moyenne, car dans ce cas, la moyenne et la médiane seront assez proches.\n", "\n", - "Tout d'abord, prenons une colonne qui suit une distribution normale et remplissons les valeurs manquantes avec la moyenne de la colonne.\n" + "Prenons d'abord une colonne qui suit une distribution normale et remplissons les valeurs manquantes avec la moyenne de la colonne.\n" ] }, { @@ -2003,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Remplissage avec la moyenne\n" + ] }, { "cell_type": "code", @@ -2252,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Remplissage avec la médiane\n" + ] }, { "cell_type": "code", @@ -2352,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Comme nous pouvons le voir, la valeur NaN a été remplacée par la médiane de la colonne\n" + "Comme nous pouvons le voir, la valeur NaN a été remplacée par la médiane de la colonne.\n" ] }, { @@ -2436,8 +2444,8 @@ }, "source": [ "> Points clés :\n", - "1. Remplir les valeurs manquantes doit être fait soit lorsqu'il y a peu de données, soit lorsqu'il existe une stratégie pour combler les données manquantes.\n", - "2. Les connaissances du domaine peuvent être utilisées pour estimer et remplir les valeurs manquantes.\n", + "1. Remplir les valeurs manquantes doit être envisagé lorsqu'il y a peu de données ou lorsqu'une stratégie est définie pour combler ces lacunes.\n", + "2. Les connaissances du domaine peuvent être utilisées pour estimer et compléter les valeurs manquantes.\n", "3. Pour les données catégoriques, les valeurs manquantes sont généralement remplacées par la mode de la colonne.\n", "4. Pour les données numériques, les valeurs manquantes sont souvent remplacées par la moyenne (pour les ensembles de données normalisés) ou la médiane des colonnes.\n" ] @@ -2469,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "Vous pouvez **remplir par propagation** les valeurs nulles, ce qui consiste à utiliser la dernière valeur valide pour remplir une valeur nulle :\n" + ] }, { "cell_type": "code", @@ -2509,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Vous pouvez également **remplir en arrière** pour propager la prochaine valeur valide en arrière afin de remplir un nul :\n" + "Vous pouvez également **remplir en arrière** pour propager la prochaine valeur valide en arrière afin de remplir une valeur nulle :\n" ] }, { @@ -2724,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Notez que lorsqu'une valeur précédente n'est pas disponible pour le remplissage vers l'avant, la valeur nulle reste.\n" + "Remarquez que lorsqu'une valeur précédente n'est pas disponible pour le remplissage vers l'avant, la valeur nulle reste.\n" ] }, { @@ -2757,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Vous pouvez être créatif dans l'utilisation de `fillna`. Par exemple, examinons à nouveau `example4`, mais cette fois remplissons les valeurs manquantes avec la moyenne de toutes les valeurs dans le `DataFrame` :\n" + "Vous pouvez être créatif quant à la manière d'utiliser `fillna`. Par exemple, examinons à nouveau `example4`, mais cette fois remplissons les valeurs manquantes avec la moyenne de toutes les valeurs dans le `DataFrame` :\n" ] }, { @@ -2848,7 +2858,7 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Notez que la colonne 3 est toujours sans valeur : la direction par défaut est de remplir les valeurs ligne par ligne.\n", + "Remarquez que la colonne 3 est toujours sans valeur : la direction par défaut est de remplir les valeurs ligne par ligne.\n", "\n", "> **À retenir :** Il existe plusieurs façons de gérer les valeurs manquantes dans vos ensembles de données. La stratégie spécifique que vous utilisez (les supprimer, les remplacer, ou même la manière dont vous les remplacez) doit être dictée par les particularités de ces données. Vous développerez une meilleure intuition pour traiter les valeurs manquantes à mesure que vous manipulerez et interagirez avec des ensembles de données.\n" ] @@ -2861,9 +2871,9 @@ "source": [ "### Encodage des données catégorielles\n", "\n", - "Les modèles d'apprentissage automatique ne traitent que des chiffres et de toute forme de données numériques. Ils ne pourront pas faire la différence entre un Oui et un Non, mais ils pourront distinguer entre 0 et 1. Ainsi, après avoir rempli les valeurs manquantes, nous devons encoder les données catégorielles sous une forme numérique pour que le modèle puisse les comprendre.\n", + "Les modèles d'apprentissage automatique ne traitent que des chiffres et de toute forme de données numériques. Ils ne peuvent pas faire la différence entre un Oui et un Non, mais ils peuvent distinguer entre 0 et 1. Ainsi, après avoir rempli les valeurs manquantes, nous devons encoder les données catégorielles sous une forme numérique pour que le modèle puisse les comprendre.\n", "\n", - "L'encodage peut être réalisé de deux manières. Nous allons les aborder ensuite.\n" + "L'encodage peut être réalisé de deux manières. Nous allons les examiner ensuite.\n" ] }, { @@ -2874,7 +2884,7 @@ "source": [ "**ENCODAGE DES ÉTIQUETTES**\n", "\n", - "L'encodage des étiquettes consiste essentiellement à convertir chaque catégorie en un nombre. Par exemple, supposons que nous avons un jeu de données de passagers aériens et qu'il y a une colonne contenant leur classe parmi les suivantes : ['classe affaires', 'classe économique', 'première classe']. Si un encodage des étiquettes est appliqué, cela serait transformé en [0,1,2]. Voyons un exemple à travers du code. Comme nous allons apprendre `scikit-learn` dans les prochains notebooks, nous ne l'utiliserons pas ici.\n" + "L'encodage des étiquettes consiste essentiellement à convertir chaque catégorie en un numéro. Par exemple, supposons que nous avons un ensemble de données sur les passagers d'une compagnie aérienne et qu'il y a une colonne indiquant leur classe parmi les suivantes ['classe affaires', 'classe économique', 'première classe']. Si un encodage des étiquettes est effectué, cela serait transformé en [0,1,2]. Voyons un exemple avec du code. Comme nous allons apprendre `scikit-learn` dans les prochains notebooks, nous ne l'utiliserons pas ici.\n" ] }, { @@ -2982,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Pour effectuer un encodage des étiquettes sur la première colonne, nous devons d'abord décrire une correspondance entre chaque classe et un numéro, avant de remplacer\n" + "Pour effectuer l'encodage des étiquettes sur la première colonne, nous devons d'abord décrire une correspondance entre chaque classe et un numéro, avant de remplacer.\n" ] }, { @@ -3084,7 +3094,7 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Comme nous pouvons le constater, le résultat correspond à ce que nous avions prévu. Alors, quand utilise-t-on l'encodage des labels ? L'encodage des labels est utilisé dans l'un ou les deux cas suivants :\n", + "Comme nous pouvons le constater, le résultat correspond à ce que nous avions prévu. Alors, quand utilise-t-on l'encodage des étiquettes ? L'encodage des étiquettes est utilisé dans l'un ou les deux cas suivants :\n", "1. Lorsque le nombre de catégories est élevé\n", "2. Lorsque les catégories sont ordonnées.\n" ] @@ -3099,7 +3109,7 @@ "\n", "Un autre type d'encodage est l'encodage One Hot. Dans ce type d'encodage, chaque catégorie de la colonne est ajoutée comme une colonne distincte, et chaque point de données recevra un 0 ou un 1 en fonction de la présence ou non de cette catégorie. Ainsi, s'il y a n catégories différentes, n colonnes seront ajoutées au dataframe.\n", "\n", - "Par exemple, prenons le même exemple de classe d'avion. Les catégories étaient : ['business class', 'economy class', 'first class']. Donc, si nous effectuons un encodage One Hot, les trois colonnes suivantes seront ajoutées au jeu de données : ['class_business class', 'class_economy class', 'class_first class'].\n" + "Par exemple, prenons le même exemple des classes d'avion. Les catégories étaient : ['classe affaires', 'classe économique', 'première classe']. Donc, si nous effectuons un encodage One Hot, les trois colonnes suivantes seront ajoutées au jeu de données : ['classe_classe affaires', 'classe_classe économique', 'classe_première classe'].\n" ] }, { @@ -3207,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "Effectuons un encodage one-hot sur la première colonne\n" + "Effectuons un encodage one hot sur la première colonne\n" ] }, { @@ -3332,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Chaque colonne encodée en one-hot contient 0 ou 1, ce qui spécifie si cette catégorie existe pour ce point de données.\n" + "Chaque colonne encodée en one-hot contient 0 ou 1, ce qui indique si cette catégorie existe pour ce point de données.\n" ] }, { @@ -3353,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Points clés : \n", - "1. Le codage est effectué pour convertir des données non numériques en données numériques. \n", - "2. Il existe deux types de codage : le codage par étiquettes et le codage One Hot, qui peuvent être réalisés en fonction des besoins du jeu de données. \n" + "> Points clés :\n", + "1. Le codage est effectué pour convertir des données non numériques en données numériques.\n", + "2. Il existe deux types de codage : le codage par étiquettes et le codage One Hot, qui peuvent être réalisés en fonction des besoins du jeu de données.\n" ] }, { @@ -3368,7 +3378,7 @@ "\n", "> **Objectif d'apprentissage :** À la fin de cette sous-section, vous devriez être à l'aise pour identifier et supprimer les valeurs dupliquées dans les DataFrames.\n", "\n", - "En plus des données manquantes, vous rencontrerez souvent des données dupliquées dans des ensembles de données réels. Heureusement, pandas offre un moyen simple de détecter et de supprimer les entrées dupliquées.\n" + "En plus des données manquantes, vous rencontrerez souvent des données dupliquées dans les ensembles de données réels. Heureusement, pandas offre un moyen simple de détecter et de supprimer les entrées dupliquées.\n" ] }, { @@ -3379,7 +3389,7 @@ "source": [ "### Identifier les doublons : `duplicated`\n", "\n", - "Vous pouvez facilement repérer les valeurs en double en utilisant la méthode `duplicated` de pandas, qui renvoie un masque booléen indiquant si une entrée dans un `DataFrame` est un doublon d'une précédente. Créons un autre exemple de `DataFrame` pour voir cela en action.\n" + "Vous pouvez facilement repérer les valeurs en double en utilisant la méthode `duplicated` de pandas, qui renvoie un masque booléen indiquant si une entrée dans un `DataFrame` est un doublon d'une précédente. Créons un autre exemple de `DataFrame` pour voir cela en pratique.\n" ] }, { @@ -3592,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Les deux `duplicated` et `drop_duplicates` considèrent par défaut toutes les colonnes, mais vous pouvez spécifier qu'ils examinent uniquement un sous-ensemble de colonnes dans votre `DataFrame` :\n" + "Les fonctions `duplicated` et `drop_duplicates` considèrent par défaut toutes les colonnes, mais vous pouvez spécifier qu'elles examinent uniquement un sous-ensemble de colonnes dans votre `DataFrame` :\n" ] }, { @@ -3668,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Conclusion :** Supprimer les données dupliquées est une étape essentielle de presque tous les projets de science des données. Les données dupliquées peuvent modifier les résultats de vos analyses et vous fournir des résultats inexacts !\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Vérifications de la qualité des données dans le monde réel\n", + "\n", + "> **Objectif d'apprentissage :** À la fin de cette section, vous devriez être à l'aise pour détecter et corriger les problèmes courants de qualité des données dans le monde réel, notamment les valeurs catégoriques incohérentes, les valeurs numériques anormales (valeurs aberrantes) et les entités dupliquées avec des variations.\n", + "\n", + "Bien que les valeurs manquantes et les doublons exacts soient des problèmes fréquents, les ensembles de données réels contiennent souvent des problèmes plus subtils :\n", + "\n", + "1. **Valeurs catégoriques incohérentes** : Une même catégorie écrite différemment (par exemple, \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Valeurs numériques anormales** : Des valeurs extrêmes qui indiquent des erreurs de saisie (par exemple, âge = 999)\n", + "3. **Lignes quasi-duplicatées** : Des enregistrements représentant la même entité avec de légères variations\n", + "\n", + "Explorons les techniques pour détecter et gérer ces problèmes.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Création d'un exemple de jeu de données \"sale\"\n", + "\n", + "Tout d'abord, créons un exemple de jeu de données contenant les types de problèmes que l'on rencontre fréquemment dans les données du monde réel :\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Détection des valeurs catégoriques incohérentes\n", + "\n", + "Remarquez que la colonne `country` contient plusieurs représentations pour les mêmes pays. Identifions ces incohérences :\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Standardisation des valeurs catégoriques\n", + "\n", + "Nous pouvons créer une correspondance pour standardiser ces valeurs. Une approche simple consiste à convertir en minuscules et à créer un dictionnaire de correspondance :\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternative : Utiliser la correspondance approximative**\n", + "\n", + "Pour des cas plus complexes, nous pouvons utiliser la correspondance de chaînes approximative avec la bibliothèque `rapidfuzz` pour détecter automatiquement des chaînes similaires :\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Détection des valeurs numériques anormales (Outliers)\n", + "\n", + "En examinant la colonne `age`, nous avons des valeurs suspectes comme 199 et -5. Utilisons des méthodes statistiques pour détecter ces valeurs aberrantes.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Utilisation de la méthode IQR (Intervalle Interquartile)\n", + "\n", + "La méthode IQR est une technique statistique robuste pour la détection des valeurs aberrantes, moins sensible aux valeurs extrêmes :\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Utilisation de la méthode du score Z\n", + "\n", + "La méthode du score Z identifie les valeurs aberrantes en fonction des écarts-types par rapport à la moyenne :\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Gestion des valeurs aberrantes\n", + "\n", + "Une fois détectées, les valeurs aberrantes peuvent être traitées de plusieurs manières :\n", + "1. **Supprimer** : Retirer les lignes contenant des valeurs aberrantes (si ce sont des erreurs)\n", + "2. **Limiter** : Remplacer par des valeurs limites\n", + "3. **Remplacer par NaN** : Considérer comme des données manquantes et utiliser des techniques d'imputation\n", + "4. **Conserver** : Si ce sont des valeurs extrêmes légitimes\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Détection des lignes quasi-duplicatées\n", + "\n", + "Remarquez que notre ensemble de données contient plusieurs entrées pour \"John Smith\" avec des valeurs légèrement différentes. Identifions les doublons potentiels en nous basant sur la similarité des noms.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Recherche de quasi-doublons avec la correspondance approximative\n", + "\n", + "Pour une détection de doublons plus avancée, nous pouvons utiliser la correspondance approximative pour trouver des noms similaires :\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Gestion des doublons\n", + "\n", + "Une fois identifiés, vous devez décider comment gérer les doublons :\n", + "1. **Conserver la première occurrence** : Utilisez `drop_duplicates(keep='first')`\n", + "2. **Conserver la dernière occurrence** : Utilisez `drop_duplicates(keep='last')`\n", + "3. **Agréger les informations** : Combiner les informations des lignes en doublon\n", + "4. **Revue manuelle** : Marquer pour une vérification humaine\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Résumé : Pipeline complet de nettoyage des données\n", + "\n", + "Regroupons tout cela dans un pipeline de nettoyage complet :\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Exercice de défi\n", + "\n", + "C'est à vous de jouer ! Voici une nouvelle ligne de données avec plusieurs problèmes de qualité. Pouvez-vous :\n", + "\n", + "1. Identifier tous les problèmes dans cette ligne\n", + "2. Écrire du code pour corriger chaque problème\n", + "3. Ajouter la ligne nettoyée au jeu de données\n", + "\n", + "Voici les données problématiques :\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Points Clés\n", + "\n", + "1. **Catégories incohérentes** sont fréquentes dans les données réelles. Vérifiez toujours les valeurs uniques et standardisez-les à l'aide de correspondances ou de méthodes de rapprochement approximatif.\n", + "\n", + "2. **Les valeurs aberrantes** peuvent avoir un impact significatif sur votre analyse. Utilisez vos connaissances du domaine combinées à des méthodes statistiques (IQR, score Z) pour les détecter.\n", + "\n", + "3. **Les quasi-duplicatas** sont plus difficiles à repérer que les duplicatas exacts. Pensez à utiliser des techniques de rapprochement approximatif et à normaliser les données (mise en minuscule, suppression des espaces) pour les identifier.\n", + "\n", + "4. **Le nettoyage des données est itératif**. Vous devrez peut-être appliquer plusieurs techniques et examiner les résultats avant de finaliser votre ensemble de données nettoyé.\n", + "\n", + "5. **Documentez vos décisions**. Notez les étapes de nettoyage que vous avez appliquées et les raisons, car cela est essentiel pour la reproductibilité et la transparence.\n", + "\n", + "> **Bonne pratique :** Conservez toujours une copie de vos données \"brutes\" originales. Ne remplacez jamais vos fichiers sources - créez des versions nettoyées avec des conventions de nommage claires comme `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Avertissement** : \nCe document a été traduit à l'aide du service de traduction automatique [Co-op Translator](https://github.com/Azure/co-op-translator). Bien que nous nous efforcions d'assurer l'exactitude, veuillez noter que les traductions automatisées peuvent contenir des erreurs ou des inexactitudes. Le document original dans sa langue d'origine doit être considéré comme la source faisant autorité. Pour des informations critiques, il est recommandé de recourir à une traduction professionnelle réalisée par un humain. Nous ne sommes pas responsables des malentendus ou des interprétations erronées résultant de l'utilisation de cette traduction.\n" + "\n---\n\n**Avertissement** : \nCe document a été traduit à l'aide du service de traduction automatique [Co-op Translator](https://github.com/Azure/co-op-translator). Bien que nous nous efforcions d'assurer l'exactitude, veuillez noter que les traductions automatisées peuvent contenir des erreurs ou des inexactitudes. Le document original dans sa langue d'origine doit être considéré comme la source faisant autorité. Pour des informations critiques, il est recommandé de recourir à une traduction humaine professionnelle. Nous ne sommes pas responsables des malentendus ou des interprétations erronées résultant de l'utilisation de cette traduction.\n" ] } ], @@ -3702,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:46:20+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T18:52:54+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "fr" } diff --git a/translations/he/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/he/2-Working-With-Data/08-data-preparation/notebook.ipynb index 9c32bd0f..60a718e7 100644 --- a/translations/he/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/he/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -10,13 +10,13 @@ "\n", "[מקור המחברת המקורית מתוך *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio מאת Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", - "## חקירת מידע מתוך `DataFrame`\n", + "## חקר מידע ב-`DataFrame`\n", "\n", - "> **מטרת הלמידה:** בסיום תת-הפרק הזה, תרגישו בנוח למצוא מידע כללי על הנתונים המאוחסנים ב-DataFrames של pandas.\n", + "> **מטרת הלמידה:** בסיום תת-הסעיף הזה, תרגישו בנוח למצוא מידע כללי על הנתונים המאוחסנים ב-DataFrames של pandas.\n", "\n", - "לאחר שטענתם את הנתונים שלכם ל-pandas, סביר להניח שהם יהיו בתוך `DataFrame`. אבל אם מערך הנתונים ב-`DataFrame` שלכם מכיל 60,000 שורות ו-400 עמודות, איך בכלל מתחילים להבין עם מה אתם עובדים? למרבה המזל, pandas מספקת כלים נוחים שמאפשרים להסתכל במהירות על מידע כללי על ה-`DataFrame`, בנוסף לשורות הראשונות והאחרונות.\n", + "לאחר שטענתם את הנתונים שלכם ל-pandas, סביר להניח שהם יהיו בתוך `DataFrame`. אבל אם מערך הנתונים ב-`DataFrame` שלכם מכיל 60,000 שורות ו-400 עמודות, איך בכלל מתחילים להבין עם מה אתם עובדים? למרבה המזל, pandas מספקת כלים נוחים כדי להסתכל במהירות על מידע כללי על `DataFrame` בנוסף לשורות הראשונות והאחרונות.\n", "\n", - "כדי לחקור את הפונקציונליות הזו, נייבא את ספריית scikit-learn של Python ונשתמש במערך נתונים איקוני שכל מדען נתונים ראה מאות פעמים: מערך הנתונים *Iris* של הביולוג הבריטי רונלד פישר, ששימש במאמרו משנת 1936 \"The use of multiple measurements in taxonomic problems\":\n" + "כדי לחקור את הפונקציונליות הזו, נייבא את ספריית scikit-learn של Python ונשתמש במערך נתונים איקוני שכל מדען נתונים ראה מאות פעמים: מערך הנתונים *Iris* של הביולוג הבריטי רונלד פישר, ששימש במאמרו משנת 1936 \"השימוש במדידות מרובות בבעיות טקסונומיות\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "טענו את מאגר הנתונים של איריס לתוך המשתנה `iris_df`. לפני שנצלול לתוך הנתונים, יהיה מועיל לדעת כמה נקודות נתונים יש לנו ומה הגודל הכולל של מאגר הנתונים. זה שימושי להסתכל על היקף הנתונים שאנו מתמודדים איתם.\n" + "טענו את מאגר הנתונים של איריס למשתנה `iris_df`. לפני שנצלול לתוך הנתונים, יהיה מועיל לדעת את מספר נקודות הנתונים שיש לנו ואת הגודל הכולל של מאגר הנתונים. זה שימושי להסתכל על נפח הנתונים שאנו מתמודדים איתו.\n" ] }, { @@ -78,7 +78,7 @@ "id": "smE7AGzOhxk2" }, "source": [ - "אז, אנחנו מתמודדים עם 150 שורות ו-4 עמודות של נתונים. כל שורה מייצגת נקודת נתונים אחת וכל עמודה מייצגת תכונה אחת הקשורה למסגרת הנתונים. כלומר, יש לנו בעצם 150 נקודות נתונים שכל אחת מהן מכילה 4 תכונות.\n", + "אז, אנחנו מתמודדים עם 150 שורות ו-4 עמודות של נתונים. כל שורה מייצגת נקודת נתונים אחת וכל עמודה מייצגת תכונה אחת הקשורה למסגרת הנתונים. כלומר, ישנם 150 נקודות נתונים שכל אחת מהן מכילה 4 תכונות.\n", "\n", "`shape` כאן הוא מאפיין של מסגרת הנתונים ולא פונקציה, ולכן הוא לא מסתיים בזוג סוגריים.\n" ] @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "בואו נעבור עכשיו אל ארבעת העמודות של הנתונים. מה בדיוק כל אחת מהן מייצגת? המאפיין `columns` ייתן לנו את שמות העמודות בתוך ה-DataFrame.\n" + "בואו נעבור עכשיו ל-4 העמודות של הנתונים. מה בדיוק כל אחת מהן מייצגת? התכונה `columns` תספק לנו את שמות העמודות בתוך ה-DataFrame.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "כפי שאנו יכולים לראות, ישנם ארבעה (4) עמודות. מאפיין ה-`columns` אומר לנו את שמות העמודות ובסיסית לא יותר מזה. מאפיין זה מקבל חשיבות כאשר אנו רוצים לזהות את המאפיינים שמכיל מערך הנתונים.\n" + "כפי שאנו יכולים לראות, ישנם ארבעה (4) עמודות. תכונת `columns` אומרת לנו את שמות העמודות ובסיסית לא יותר מזה. תכונה זו מקבלת חשיבות כאשר אנו רוצים לזהות את המאפיינים שהמערך נתונים מכיל.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "כמות הנתונים (ניתנת על ידי המאפיין `shape`) ושמות התכונות או העמודות (ניתנים על ידי המאפיין `columns`) מספקים לנו מידע על מערך הנתונים. כעת, נרצה להעמיק יותר במערך הנתונים. הפונקציה `DataFrame.info()` שימושית מאוד למטרה זו.\n" + "כמות הנתונים (ניתנת על ידי המאפיין `shape`) ושמות התכונות או העמודות (ניתנים על ידי המאפיין `columns`) מספקים לנו מידע מסוים על מערך הנתונים. כעת, נרצה להעמיק יותר במערך הנתונים. הפונקציה `DataFrame.info()` שימושית מאוד לצורך זה.\n" ] }, { @@ -180,10 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "מכאן, ניתן להסיק כמה תובנות:\n", - "\n", - "1. סוג הנתונים של כל עמודה: במערך הנתונים הזה, כל הנתונים מאוחסנים כמספרים בנקודה צפה בפורמט 64-ביט. \n", - "2. מספר הערכים שאינם Null: התמודדות עם ערכים חסרים היא שלב חשוב בהכנת הנתונים. נעסוק בכך בהמשך במחברת. \n" + "מכאן, ניתן להסיק כמה תצפיות:\n", + "1. סוג הנתונים של כל עמודה: במאגר הנתונים הזה, כל הנתונים נשמרים כמספרים בנקודה צפה בגודל 64 ביט.\n", + "2. מספר הערכים שאינם Null: טיפול בערכים חסרים הוא שלב חשוב בהכנת הנתונים. הנושא יטופל בהמשך במחברת.\n" ] }, { @@ -323,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "הפלט לעיל מציג את המספר הכולל של נקודות הנתונים, ממוצע, סטיית תקן, מינימום, רבעון תחתון (25%), חציון (50%), רבעון עליון (75%) והערך המרבי של כל עמודה.\n" + "הפלט לעיל מציג את המספר הכולל של נקודות הנתונים, ממוצע, סטיית תקן, מינימום, רבעון תחתון (25%), חציון (50%), רבעון עליון (75%) והערך המקסימלי של כל עמודה.\n" ] }, { @@ -335,7 +334,7 @@ "### `DataFrame.head`\n", "עם כל הפונקציות והתכונות שהוזכרו לעיל, קיבלנו מבט כולל על מערך הנתונים. אנחנו יודעים כמה נקודות נתונים יש, כמה מאפיינים קיימים, סוג הנתונים של כל מאפיין ומספר הערכים שאינם null עבור כל מאפיין.\n", "\n", - "עכשיו הגיע הזמן להסתכל על הנתונים עצמם. בואו נראה איך נראים השורות הראשונות (נקודות הנתונים הראשונות) של ה-`DataFrame` שלנו:\n" + "עכשיו הגיע הזמן להסתכל על הנתונים עצמם. בואו נראה איך נראות השורות הראשונות (נקודות הנתונים הראשונות) של ה-`DataFrame` שלנו:\n" ] }, { @@ -442,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "כפי שניתן לראות כאן, יש לנו חמישה (5) רשומות של מערך הנתונים. אם נסתכל על האינדקס בצד שמאל, נגלה שאלו הם חמשת השורות הראשונות.\n" + "כפי שניתן לראות כאן, ישנם חמישה (5) רשומות של מערך הנתונים. אם נסתכל על האינדקס בצד שמאל, נגלה שאלו הם חמשת השורות הראשונות.\n" ] }, { @@ -453,7 +452,7 @@ "source": [ "### תרגיל:\n", "\n", - "מהדוגמה שניתנה למעלה, ברור שברירת המחדל של `DataFrame.head` היא להחזיר את חמש השורות הראשונות של `DataFrame`. בתא הקוד למטה, האם תוכל למצוא דרך להציג יותר מחמש שורות?\n" + "מהדוגמה שניתנה לעיל, ברור שברירת המחדל של `DataFrame.head` היא להחזיר את חמש השורות הראשונות של `DataFrame`. בתא הקוד למטה, האם תוכל למצוא דרך להציג יותר מחמש שורות?\n" ] }, { @@ -476,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "דרך נוספת להסתכל על הנתונים יכולה להיות מהסוף (במקום מההתחלה). ההפך מ-`DataFrame.head` הוא `DataFrame.tail`, שמחזיר את חמש השורות האחרונות של `DataFrame`:\n" + "דרך נוספת להסתכל על הנתונים יכולה להיות מהסוף (במקום מההתחלה). ההיפך מ-`DataFrame.head` הוא `DataFrame.tail`, שמחזיר את חמש השורות האחרונות של ה-`DataFrame`:\n" ] }, { @@ -583,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "בפועל, זה שימושי להיות מסוגלים לבדוק בקלות את השורות הראשונות או האחרונות של `DataFrame`, במיוחד כשאתם מחפשים ערכים חריגים במערכי נתונים מסודרים.\n", + "בפועל, זה שימושי להיות מסוגל לבדוק בקלות את השורות הראשונות או האחרונות של `DataFrame`, במיוחד כאשר מחפשים ערכים חריגים במערכי נתונים מסודרים.\n", "\n", "כל הפונקציות והתכונות שהוצגו לעיל בעזרת דוגמאות קוד, עוזרות לנו לקבל תחושה כללית של הנתונים.\n", "\n", - "> **מסקנה:** אפילו רק על ידי הסתכלות על המטא-נתונים של המידע ב-DataFrame או על הערכים הראשונים והאחרונים שבו, ניתן לקבל מיד מושג על הגודל, הצורה והתוכן של הנתונים שאתם מתמודדים איתם.\n" + "> **תובנה:** אפילו רק על ידי הסתכלות על המטא-נתונים של המידע ב-DataFrame או על הערכים הראשונים והאחרונים שבו, ניתן לקבל מיד מושג על הגודל, הצורה והתוכן של הנתונים שאיתם אתם מתמודדים.\n" ] }, { @@ -597,17 +596,17 @@ }, "source": [ "### נתונים חסרים\n", - "בואו נצלול לנושא של נתונים חסרים. נתונים חסרים מתרחשים כאשר אין ערך שמאוחסן בחלק מהעמודות.\n", + "בואו נצלול לנושא הנתונים החסרים. נתונים חסרים מתרחשים כאשר אין ערך שמאוחסן בחלק מהעמודות.\n", "\n", - "ניקח דוגמה: נניח שמישהו מודע למשקל שלו/שלה ולא ממלא את שדה המשקל בסקר. במקרה כזה, ערך המשקל עבור אותו אדם יהיה חסר.\n", + "בואו ניקח דוגמה: נניח שמישהו מודע למשקל שלו/שלה ולא ממלא את שדה המשקל בסקר. במקרה כזה, ערך המשקל עבור אותו אדם יהיה חסר.\n", "\n", - "ברוב המקרים, בסטים של נתונים מהעולם האמיתי, ערכים חסרים הם תופעה נפוצה.\n", + "ברוב המקרים, במאגרי נתונים בעולם האמיתי, ערכים חסרים הם דבר שכיח.\n", "\n", - "**איך Pandas מתמודדת עם נתונים חסרים**\n", + "**איך Pandas מתמודד עם נתונים חסרים**\n", "\n", - "Pandas מתמודדת עם ערכים חסרים בשתי דרכים. הדרך הראשונה, שראיתם כבר בחלקים קודמים, היא `NaN`, או Not a Number. זהו למעשה ערך מיוחד שהוא חלק מהמפרט של IEEE עבור נקודה צפה, והוא משמש רק לציון ערכים חסרים מסוג נקודה צפה.\n", + "Pandas מתמודד עם ערכים חסרים בשתי דרכים. הראשונה, שראיתם קודם לכן בסעיפים קודמים: `NaN`, או Not a Number. זהו למעשה ערך מיוחד שהוא חלק מהמפרט של IEEE עבור נקודה צפה, והוא משמש רק לציון ערכים חסרים מסוג נקודה צפה.\n", "\n", - "עבור ערכים חסרים שאינם מסוג נקודה צפה, pandas משתמשת באובייקט `None` של Python. למרות שזה עשוי להיראות מבלבל שתיתקלו בשני סוגים שונים של ערכים שמציינים למעשה את אותו הדבר, יש סיבות תכנותיות טובות לבחירה עיצובית זו, ובפועל, גישה זו מאפשרת ל-pandas לספק פשרה טובה עבור רוב המקרים. עם זאת, גם ל-`None` וגם ל-`NaN` יש מגבלות שחשוב להיות מודעים אליהן בכל הנוגע לאופן שבו ניתן להשתמש בהם.\n" + "עבור ערכים חסרים שאינם מסוג נקודה צפה, pandas משתמש באובייקט `None` של Python. למרות שזה עשוי להיראות מבלבל שתיתקלו בשני סוגים שונים של ערכים שמביעים למעשה את אותו הדבר, יש סיבות תכנותיות טובות לבחירה הזו, ובפועל, הגישה הזו מאפשרת ל-pandas לספק פשרה טובה עבור רוב המקרים. עם זאת, גם `None` וגם `NaN` נושאים מגבלות שחשוב להיות מודעים אליהן בכל הנוגע לאופן שבו ניתן להשתמש בהם.\n" ] }, { @@ -616,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: נתוני חסר שאינם מסוג float \n", - "מכיוון ש-`None` מגיע מ-Python, לא ניתן להשתמש בו במערכים של NumPy ו-pandas שאינם מסוג הנתונים `'object'`. זכרו, מערכי NumPy (והמבנים ב-pandas) יכולים להכיל רק סוג אחד של נתונים. זה מה שמעניק להם את הכוח העצום לעבודה עם נתונים בקנה מידה גדול וביצוע חישובים, אך גם מגביל את הגמישות שלהם. מערכים כאלה חייבים לבצע המרה לסוג הנתונים \"המכנה המשותף הנמוך ביותר\", כלומר סוג הנתונים שיכיל את כל הערכים במערך. כאשר `None` נמצא במערך, המשמעות היא שאתם עובדים עם אובייקטים של Python.\n", + "### `None`: נתוני חסר שאינם מסוג float\n", + "מכיוון ש-`None` מגיע מ-Python, לא ניתן להשתמש בו במערכים של NumPy ו-pandas שאינם מסוג הנתונים `'object'`. זכרו, מערכים של NumPy (והמבנים ב-pandas) יכולים להכיל רק סוג אחד של נתונים. זה מה שמעניק להם את הכוח העצום לעבודה עם נתונים בקנה מידה גדול וביצוע חישובים, אך גם מגביל את הגמישות שלהם. מערכים כאלה חייבים להתאים את עצמם ל\"מחנה המשותף הנמוך ביותר\", סוג הנתונים שיכלול את כל מה שנמצא במערך. כאשר `None` נמצא במערך, זה אומר שאתם עובדים עם אובייקטים של Python.\n", "\n", - "כדי לראות זאת בפעולה, שקלו את מערך הדוגמה הבא (שימו לב ל-`dtype` שלו):\n" + "כדי לראות זאת בפעולה, שימו לב לדוגמה הבאה של מערך (שימו לב ל-`dtype` שלו):\n" ] }, { @@ -658,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "המציאות של המרת סוגי נתונים כלפי מעלה מביאה עמה שני תופעות לוואי. ראשית, פעולות יתבצעו ברמת הקוד המפורש של Python ולא ברמת הקוד המהודר של NumPy. למעשה, המשמעות היא שכל פעולה הכוללת `Series` או `DataFrames` עם `None` בתוכם תהיה איטית יותר. למרות שסביר להניח שלא תבחינו בפגיעה בביצועים, עבור מערכי נתונים גדולים זה עשוי להפוך לבעיה.\n", + "המציאות של העלאת סוגי נתונים מביאה עמה שני תופעות לוואי. ראשית, פעולות יתבצעו ברמת הקוד המפורש של Python במקום ברמת הקוד המהודר של NumPy. למעשה, המשמעות היא שכל פעולה שכוללת `Series` או `DataFrames` עם `None` בתוכם תהיה איטית יותר. למרות שסביר להניח שלא תבחין בפגיעה בביצועים, עבור מערכי נתונים גדולים זה עשוי להפוך לבעיה.\n", "\n", - "תופעת הלוואי השנייה נובעת מהראשונה. מכיוון ש-`None` למעשה מחזיר את ה-`Series` או ה-`DataFrame`s לעולם של Python הבסיסי, שימוש בפונקציות צבירה של NumPy/pandas כמו `sum()` או `min()` על מערכים המכילים ערך ``None`` בדרך כלל יגרום לשגיאה:\n" + "תופעת הלוואי השנייה נובעת מהראשונה. מכיוון ש-`None` למעשה מחזיר את ה-`Series` או ה-`DataFrame`s לעולם של Python רגיל, שימוש באגרגציות של NumPy/pandas כמו `sum()` או `min()` על מערכים שמכילים ערך ``None`` בדרך כלל יגרום לשגיאה:\n" ] }, { @@ -710,7 +709,7 @@ "source": [ "### `NaN`: ערכי float חסרים\n", "\n", - "בניגוד ל-`None`, NumPy (ולכן גם pandas) תומכים ב-`NaN` עבור פעולות ווקטוריות מהירות ו-ufuncs. החדשות הרעות הן שכל פעולה אריתמטית שמתבצעת על `NaN` תמיד תוביל ל-`NaN`. לדוגמה:\n" + "בניגוד ל-`None`, NumPy (ולכן גם pandas) תומך ב-`NaN` עבור פעולות ווקטוריות מהירות ו-ufuncs. החדשות הרעות הן שכל פעולה אריתמטית שמתבצעת על `NaN` תמיד תוביל ל-`NaN`. לדוגמה:\n" ] }, { @@ -773,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "החדשות הטובות: אגרגציות שפועלות על מערכים עם `NaN` בתוכם לא מציגות שגיאות. החדשות הרעות: התוצאות אינן מועילות באופן אחיד:\n" + "החדשות הטובות: אגרגציות שרצות על מערכים עם `NaN` בתוכם לא מציגות שגיאות. החדשות הרעות: התוצאות אינן מועילות באופן אחיד:\n" ] }, { @@ -832,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "זכור: `NaN` מיועד רק לערכים חסרים מסוג נקודה צפה; אין מקבילה ל-`NaN` עבור מספרים שלמים, מחרוזות או ערכי בוליאן.\n" + "זכור: `NaN` מיועד רק לערכים חסרים בנקודה צפה; אין מקבילה של `NaN` עבור מספרים שלמים, מחרוזות או ערכי בוליאן.\n" ] }, { @@ -843,7 +842,7 @@ "source": [ "### `NaN` ו-`None`: ערכים ריקים ב-pandas\n", "\n", - "למרות ש-`NaN` ו-`None` יכולים להתנהג בצורה מעט שונה, pandas נבנה כך שיוכל לטפל בהם באופן חלופי. כדי להבין למה הכוונה, בואו נבחן `Series` של מספרים שלמים:\n" + "למרות ש-`NaN` ו-`None` יכולים להתנהג בצורה מעט שונה, pandas נבנתה כך שתוכל להתמודד איתם באופן חלופי. כדי להבין למה הכוונה, בואו נבחן `Series` של מספרים שלמים:\n" ] }, { @@ -907,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "במהלך תהליך של המרה כלפי מעלה (upcasting) של סוגי נתונים לצורך יצירת אחידות בנתונים ב-`Series` וב-`DataFrame`s, pandas תבצע באופן חופשי החלפה של ערכים חסרים בין `None` ל-`NaN`. בשל מאפיין עיצוב זה, יכול להיות מועיל לחשוב על `None` ו-`NaN` כשני סוגים שונים של \"null\" ב-pandas. למעשה, חלק מהשיטות המרכזיות שתשתמשו בהן לטיפול בערכים חסרים ב-pandas משקפות רעיון זה בשמותיהן:\n", + "בתהליך של המרת סוגי נתונים לצורך יצירת אחידות נתונים ב-`Series` וב-`DataFrame`s, pandas תחליף באופן חופשי ערכים חסרים בין `None` ל-`NaN`. בשל מאפיין עיצוב זה, יכול להיות מועיל לחשוב על `None` ו-`NaN` כשני סוגים שונים של \"null\" ב-pandas. למעשה, חלק מהשיטות המרכזיות שבהן תשתמשו לטיפול בערכים חסרים ב-pandas משקפות את הרעיון הזה בשמותיהן:\n", "\n", - "- `isnull()`: מייצרת מסכה בוליאנית שמציינת ערכים חסרים\n", - "- `notnull()`: ההפך של `isnull()`\n", + "- `isnull()`: יוצרת מסכה בוליאנית שמצביעה על ערכים חסרים\n", + "- `notnull()`: ההפך מ-`isnull()`\n", "- `dropna()`: מחזירה גרסה מסוננת של הנתונים\n", - "- `fillna()`: מחזירה עותק של הנתונים שבו הערכים החסרים מולאו או הושלמו\n", + "- `fillna()`: מחזירה עותק של הנתונים עם ערכים חסרים שמולאו או הושלמו\n", "\n", - "אלו שיטות חשובות שכדאי לשלוט בהן ולהרגיש בנוח איתן, אז בואו נעבור עליהן לעומק.\n" + "אלו שיטות חשובות שכדאי לשלוט בהן ולהרגיש בנוח להשתמש בהן, אז בואו נעבור עליהן לעומק.\n" ] }, { @@ -925,7 +924,7 @@ "source": [ "### זיהוי ערכים חסרים\n", "\n", - "כעת, לאחר שהבנו את החשיבות של ערכים חסרים, עלינו לזהות אותם במערך הנתונים שלנו לפני שנתמודד איתם. \n", + "עכשיו, כשאנחנו מבינים את החשיבות של ערכים חסרים, עלינו לזהות אותם במערך הנתונים שלנו לפני שנתמודד איתם. \n", "הפונקציות `isnull()` ו-`notnull()` הן השיטות העיקריות שלך לזיהוי נתונים חסרים. שתיהן מחזירות מסכות בוליאניות על הנתונים שלך.\n" ] }, @@ -979,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "האם משהו בתוצאה מפתיע אותך? בעוד ש-`0` הוא אפס אריתמטי, הוא עדיין מספר שלם תקין לחלוטין, ו-pandas מתייחסת אליו ככזה. `''` הוא מעט יותר עדין. בעוד שבפרק 1 השתמשנו בו כדי לייצג ערך מחרוזת ריקה, הוא עדיין אובייקט מחרוזת ולא ייצוג של null מבחינת pandas.\n", + "התבוננו היטב בתוצאה. האם משהו בה מפתיע אתכם? בעוד ש-`0` הוא ערך אפס אריתמטי, הוא עדיין מספר שלם תקין לחלוטין, ו-pandas מתייחסת אליו ככזה. `''` הוא מעט יותר מעודן. למרות שהשתמשנו בו בסעיף 1 כדי לייצג ערך מחרוזת ריקה, הוא עדיין אובייקט מחרוזת ולא ייצוג של ערך null מבחינת pandas.\n", "\n", - "עכשיו, בואו נהפוך את זה ונשתמש בשיטות הללו בצורה שיותר דומה לאופן שבו תשתמשו בהן בפועל. ניתן להשתמש במסכות בוליאניות ישירות כ-``Series`` או כ-``DataFrame`` אינדקס, מה שיכול להיות שימושי כאשר מנסים לעבוד עם ערכים חסרים (או קיימים) מבודדים.\n", + "כעת, בואו נהפוך את זה ונשתמש בשיטות הללו בצורה שיותר דומה לאופן שבו תשתמשו בהן בפועל. ניתן להשתמש במסכות בוליאניות ישירות כ-``Series`` או כ-``DataFrame`` אינדקס, מה שיכול להיות שימושי כאשר מנסים לעבוד עם ערכים חסרים (או קיימים) מבודדים.\n", "\n", - "אם אנחנו רוצים את המספר הכולל של ערכים חסרים, אנחנו יכולים פשוט לבצע סכימה על המסכה שמיוצרת על ידי השיטה `isnull()`.\n" + "אם נרצה את המספר הכולל של הערכים החסרים, נוכל פשוט לבצע סכימה על המסכה שמיוצרת על ידי השיטה `isnull()`.\n" ] }, { @@ -1041,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**מסקנה עיקרית**: הן השיטות `isnull()` והן `notnull()` מפיקות תוצאות דומות כאשר משתמשים בהן ב-DataFrames: הן מציגות את התוצאות ואת האינדקס של אותן תוצאות, מה שיעזור לך מאוד כאשר אתה מתמודד עם הנתונים שלך.\n" + "**מסקנה עיקרית**: הן השיטות `isnull()` והן `notnull()` מפיקות תוצאות דומות כאשר משתמשים בהן ב-DataFrames: הן מציגות את התוצאות ואת האינדקס של אותן תוצאות, מה שיעזור לכם מאוד כאשר אתם מתמודדים עם הנתונים שלכם.\n" ] }, { @@ -1054,14 +1053,14 @@ "\n", "> **מטרת הלמידה:** בסיום תת-הסעיף הזה, תדעו כיצד ומתי להחליף או להסיר ערכים חסרים מ-DataFrames.\n", "\n", - "מודלים של למידת מכונה אינם יכולים להתמודד עם נתונים חסרים בעצמם. לכן, לפני שמעבירים את הנתונים למודל, יש לטפל בערכים החסרים.\n", + "מודלים של למידת מכונה אינם יכולים להתמודד עם נתונים חסרים בעצמם. לכן, לפני שמעבירים את הנתונים למודל, יש לטפל בערכים החסרים הללו.\n", "\n", "האופן שבו מטפלים בנתונים חסרים נושא עמו פשרות עדינות, ויכול להשפיע על הניתוח הסופי ועל התוצאות בעולם האמיתי.\n", "\n", "ישנן בעיקר שתי דרכים להתמודד עם נתונים חסרים:\n", "\n", - "1. להסיר את השורה שמכילה את הערך החסר \n", - "2. להחליף את הערך החסר בערך אחר \n", + "1. להסיר את השורה שמכילה את הערך החסר\n", + "2. להחליף את הערך החסר בערך אחר\n", "\n", "נדון בשתי השיטות הללו וביתרונותיהן וחסרונותיהן בפירוט.\n" ] @@ -1074,9 +1073,9 @@ "source": [ "### הסרת ערכים חסרים\n", "\n", - "כמות הנתונים שאנחנו מעבירים למודל שלנו משפיעה ישירות על הביצועים שלו. הסרת ערכים חסרים משמעותה שאנחנו מצמצמים את מספר נקודות הנתונים, ובכך מקטינים את גודל מערך הנתונים. לכן, מומלץ להסיר שורות עם ערכים חסרים כאשר מערך הנתונים גדול יחסית.\n", + "כמות הנתונים שאנו מעבירים למודל שלנו משפיעה ישירות על ביצועיו. הסרת ערכים חסרים משמעותה הפחתת מספר נקודות הנתונים, ולכן הקטנת גודל מערך הנתונים. לכן, מומלץ להסיר שורות עם ערכים חסרים כאשר מערך הנתונים גדול למדי.\n", "\n", - "מקרה נוסף יכול להיות ששורה או עמודה מסוימת מכילה הרבה ערכים חסרים. במקרה כזה, ניתן להסיר אותם מכיוון שהם לא יוסיפו ערך רב לניתוח שלנו, שכן רוב הנתונים חסרים עבור אותה שורה/עמודה.\n", + "מקרה נוסף יכול להיות ששורה או עמודה מסוימת מכילה הרבה ערכים חסרים. אז ניתן להסיר אותם מכיוון שהם לא יוסיפו ערך רב לניתוח שלנו, שכן רוב הנתונים חסרים עבור אותה שורה/עמודה.\n", "\n", "מעבר לזיהוי ערכים חסרים, pandas מספקת דרך נוחה להסיר ערכים חסרים מ-`Series` ו-`DataFrame`s. כדי לראות זאת בפעולה, נחזור ל-`example3`. הפונקציה `DataFrame.dropna()` מסייעת בהסרת שורות עם ערכים חסרים.\n" ] @@ -1117,7 +1116,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "שימו לב שזה צריך להיראות כמו הפלט שלכם מ- `example3[example3.notnull()]`. ההבדל כאן הוא שבמקום רק לאנדקס את הערכים המוסתרים, `dropna` הסיר את הערכים החסרים האלה מתוך ה- `Series` `example3`.\n", + "שימו לב שזה אמור להיראות כמו הפלט שלכם מ- `example3[example3.notnull()]`. ההבדל כאן הוא שבמקום רק לבצע אינדוקס על הערכים המוסתרים, `dropna` הסיר את הערכים החסרים מה- `Series` `example3`.\n", "\n", "מכיוון של- DataFrames יש שתי ממדים, הם מציעים יותר אפשרויות להסרת נתונים.\n" ] @@ -1209,7 +1208,7 @@ "id": "66wwdHZrgRsE" }, "source": [ - "האם שמתם לב שפנדס שדרג שניים מהעמודות לסוג נתונים float כדי להתאים את ה-`NaN`s?\n", + "(האם שמתם לב שפנדס שדרג שניים מהעמודות לסוג נתונים float כדי להתאים את הערכים `NaN`?)\n", "\n", "לא ניתן להסיר ערך יחיד מתוך `DataFrame`, ולכן יש להסיר שורות או עמודות שלמות. תלוי במה שאתם עושים, ייתכן שתרצו לבצע אחד מהשניים, ולכן פנדס נותן לכם אפשרויות לשניהם. מכיוון שבמדעי הנתונים עמודות בדרך כלל מייצגות משתנים ושורות מייצגות תצפיות, סביר יותר שתסירו שורות של נתונים; ההגדרה המחדלית של `dropna()` היא להסיר את כל השורות שמכילות ערכים ריקים כלשהם:\n" ] @@ -1363,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "שימו לב שזה יכול להוביל לאיבוד של הרבה נתונים שייתכן שתרצו לשמור, במיוחד במערכי נתונים קטנים יותר. מה אם אתם רוצים פשוט להסיר שורות או עמודות שמכילות מספר רב או אפילו את כל הערכים הריקים? אתם יכולים להגדיר זאת באמצעות `dropna` עם הפרמטרים `how` ו-`thresh`.\n", + "שימו לב שזה יכול לגרום לאיבוד של הרבה נתונים שייתכן שתרצו לשמור, במיוחד במערכי נתונים קטנים. מה אם אתם רוצים פשוט להסיר שורות או עמודות שמכילות מספר רב של ערכים ריקים או אפילו את כולם? אתם יכולים להגדיר את ההגדרות הללו ב-`dropna` באמצעות הפרמטרים `how` ו-`thresh`.\n", "\n", - "כברירת מחדל, `how='any'` (אם תרצו לבדוק בעצמכם או לראות אילו פרמטרים נוספים יש לשיטה, הריצו `example4.dropna?` בתא קוד). לחלופין, תוכלו להגדיר `how='all'` כדי להסיר רק שורות או עמודות שמכילות את כל הערכים הריקים. בואו נרחיב את דוגמת ה-`DataFrame` שלנו כדי לראות זאת בפעולה בתרגיל הבא.\n" + "כברירת מחדל, `how='any'` (אם תרצו לבדוק בעצמכם או לראות אילו פרמטרים נוספים יש לשיטה, הריצו `example4.dropna?` בתא קוד). לחלופין, תוכלו להגדיר `how='all'` כדי להסיר רק שורות או עמודות שמכילות את כל הערכים כריקים. בואו נרחיב את דוגמת ה-`DataFrame` שלנו כדי לראות זאת בפעולה בתרגיל הבא.\n" ] }, { @@ -1457,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> נקודות מפתח: \n", - "1. מחיקת ערכים ריקים היא רעיון טוב רק אם מערך הנתונים גדול מספיק. \n", - "2. ניתן למחוק שורות או עמודות שלמות אם רוב הנתונים בהן חסרים. \n", - "3. השיטה `DataFrame.dropna(axis=)` מסייעת במחיקת ערכים ריקים. הפרמטר `axis` מציין האם למחוק שורות או עמודות. \n", - "4. ניתן להשתמש גם בפרמטר `how`. כברירת מחדל הוא מוגדר כ-`any`, כך שהוא מוחק רק את השורות/עמודות שמכילות ערכים ריקים כלשהם. ניתן להגדיר אותו כ-`all` כדי לציין שנמחק רק שורות/עמודות שבהן כל הערכים ריקים. \n" + "> נקודות חשובות:\n", + "1. כדאי להסיר ערכים חסרים רק אם מערך הנתונים גדול מספיק.\n", + "2. ניתן להסיר שורות או עמודות שלמות אם רוב הנתונים בהן חסרים.\n", + "3. השיטה `DataFrame.dropna(axis=)` מסייעת בהסרת ערכים חסרים. הפרמטר `axis` מציין האם להסיר שורות או עמודות.\n", + "4. ניתן להשתמש גם בפרמטר `how`. כברירת מחדל הוא מוגדר כ-`any`, כך שהוא מסיר רק שורות/עמודות שמכילות ערכים חסרים כלשהם. ניתן להגדיר אותו כ-`all` כדי לציין שנסיר רק שורות/עמודות שבהן כל הערכים חסרים.\n" ] }, { @@ -1581,7 +1580,7 @@ "\n", "לפעמים יש היגיון למלא ערכים חסרים באלה שיכולים להיות תקפים. יש כמה טכניקות למילוי ערכים חסרים. הראשונה היא שימוש בידע תחום (ידע על הנושא שעליו מבוסס מערך הנתונים) כדי להעריך בצורה כלשהי את הערכים החסרים.\n", "\n", - "ניתן להשתמש ב-`isnull` כדי לעשות זאת במקום, אך זה יכול להיות מייגע, במיוחד אם יש לך הרבה ערכים למלא. מכיוון שזו משימה נפוצה כל כך במדעי הנתונים, pandas מספקת את `fillna`, שמחזירה עותק של ה-`Series` או ה-`DataFrame` עם הערכים החסרים מוחלפים באלה שתבחר. בואו ניצור דוגמה נוספת של `Series` כדי לראות איך זה עובד בפועל.\n" + "ניתן להשתמש ב-`isnull` כדי לעשות זאת במקום, אבל זה יכול להיות מייגע, במיוחד אם יש הרבה ערכים למלא. מכיוון שזו משימה נפוצה כל כך במדעי הנתונים, pandas מספקת את `fillna`, שמחזירה עותק של ה-`Series` או ה-`DataFrame` עם הערכים החסרים מוחלפים באלה שתבחר. בואו ניצור דוגמה נוספת של `Series` כדי לראות איך זה עובד בפועל.\n" ] }, { @@ -1591,7 +1590,7 @@ }, "source": [ "### נתונים קטגוריים (לא מספריים)\n", - "ראשית, נתמקד בנתונים שאינם מספריים. במאגרי נתונים, יש לנו עמודות עם נתונים קטגוריים. לדוגמה, מגדר, נכון או לא נכון וכו'.\n", + "ראשית, נבחן נתונים שאינם מספריים. במערכי נתונים, יש לנו עמודות עם נתונים קטגוריים. לדוגמה, מגדר, נכון או לא נכון וכו'.\n", "\n", "ברוב המקרים הללו, אנו מחליפים ערכים חסרים ב-`mode` של העמודה. נניח שיש לנו 100 נקודות נתונים, 90 מהן ציינו נכון, 8 ציינו לא נכון ו-2 לא מילאו. במקרה כזה, נוכל למלא את ה-2 עם נכון, בהתחשב בעמודה כולה.\n", "\n", @@ -1700,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "עכשיו, בואו קודם נמצא את השכיח לפני שממלאים את הערך `None` בשכיח.\n" + ] }, { "cell_type": "code", @@ -1735,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "אז, נחליף None ב-True\n" + ] }, { "cell_type": "code", @@ -1845,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "כפי שאנו יכולים לראות, הערך null הוחלף. מיותר לציין, יכולנו לכתוב כל דבר במקום `'True'` וזה היה מוחלף.\n" + "כפי שאנחנו יכולים לראות, הערך הריק הוחלף. מיותר לציין, שיכולנו לכתוב כל דבר במקום או `'True'` וזה היה מוחלף.\n" ] }, { @@ -1860,7 +1863,7 @@ "1. החלפה עם החציון של השורה \n", "2. החלפה עם הממוצע של השורה \n", "\n", - "אנו מחליפים עם החציון במקרה של נתונים מוטים עם ערכים חריגים. זאת מכיוון שהחציון עמיד בפני ערכים חריגים.\n", + "אנו מחליפים עם החציון במקרה של נתונים מוטים עם ערכים חריגים. הסיבה לכך היא שחציון עמיד בפני ערכים חריגים.\n", "\n", "כאשר הנתונים מנורמלים, ניתן להשתמש בממוצע, שכן במקרה כזה, הממוצע והחציון יהיו די קרובים.\n", "\n", @@ -2004,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "מילוי עם ממוצע\n" + ] }, { "cell_type": "code", @@ -2113,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "עכשיו בואו ננסה מסגרת נתונים אחרת, והפעם נחליף את הערכים None במדיאן של העמודה.\n" + "עכשיו בואו ננסה מסגרת נתונים אחרת, והפעם נחליף את הערכים None במדד של העמודה.\n" ] }, { @@ -2355,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "כפי שאנו יכולים לראות, ערך NaN הוחלף על ידי החציון של העמודה\n" + "כפי שאנו יכולים לראות, ערך ה-NaN הוחלף במדיאן של העמודה\n" ] }, { @@ -2397,7 +2402,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "אתה יכול למלא את כל הערכים הריקים עם ערך יחיד, כגון `0`:\n" + ":אתה יכול למלא את כל הערכים החסרים עם ערך יחיד, כמו `0`\n" ] }, { @@ -2438,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> נקודות מפתח: \n", - "1. יש למלא ערכים חסרים כאשר יש מעט נתונים או כאשר קיימת אסטרטגיה למלא את הנתונים החסרים. \n", - "2. ניתן להשתמש בידע תחום כדי למלא ערכים חסרים על ידי הערכה שלהם. \n", - "3. עבור נתונים קטגוריים, לרוב, ערכים חסרים מוחלפים בערך השכיח (mode) של העמודה. \n", - "4. עבור נתונים מספריים, ערכים חסרים בדרך כלל ממולאים עם הממוצע (עבור מערכי נתונים מנורמלים) או החציון של העמודות. \n" + "> נקודות חשובות:\n", + "1. יש למלא ערכים חסרים כאשר יש מעט נתונים או כאשר קיימת אסטרטגיה למילוי הנתונים החסרים.\n", + "2. ניתן להשתמש בידע תחום כדי למלא ערכים חסרים על ידי הערכתם.\n", + "3. עבור נתונים קטגוריים, בדרך כלל מחליפים ערכים חסרים במצב (mode) של העמודה.\n", + "4. עבור נתונים מספריים, ערכים חסרים ממולאים בדרך כלל בממוצע (עבור מערכי נתונים מנורמלים) או במדיאן של העמודות.\n" ] }, { @@ -2514,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "אתה יכול גם **למלא אחורה** כדי להפיץ את הערך התקף הבא אחורה למילוי null:\n" + "אתה יכול גם **למלא אחורה** כדי להפיץ את הערך התקף הבא אחורה למילוי ערך ריק:\n" ] }, { @@ -2556,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "כפי שאתה יכול לנחש, זה עובד באותו אופן עם DataFrames, אבל אתה יכול גם לציין `axis` לאורך אותו למלא ערכים ריקים:\n" + "כפי שאתה יכול לנחש, זה עובד באותו אופן עם DataFrames, אבל אתה יכול גם לציין `axis` לאורך אשר למלא ערכים ריקים:\n" ] }, { @@ -2855,7 +2860,7 @@ "source": [ "שימו לב שעמודה 3 עדיין חסרת ערך: הכיוון ברירת המחדל הוא למלא ערכים לפי שורות.\n", "\n", - "> **מסקנה:** ישנן דרכים רבות להתמודד עם ערכים חסרים במערכי הנתונים שלכם. האסטרטגיה הספציפית שבה תשתמשו (הסרתם, החלפתם, או אפילו איך להחליפם) צריכה להיות מותאמת למאפיינים של הנתונים הללו. אתם תפתחו תחושה טובה יותר כיצד להתמודד עם ערכים חסרים ככל שתעבדו ותתקשרו יותר עם מערכי נתונים.\n" + "> **מסקנה:** ישנן דרכים רבות להתמודד עם ערכים חסרים במערכי הנתונים שלכם. האסטרטגיה הספציפית שבה תשתמשו (הסרתם, החלפתם, או אפילו איך להחליף אותם) צריכה להיות מותאמת למאפיינים של הנתונים הללו. ככל שתתעסקו ותתקשרו יותר עם מערכי נתונים, תפתחו תחושה טובה יותר כיצד להתמודד עם ערכים חסרים.\n" ] }, { @@ -2866,7 +2871,7 @@ "source": [ "### קידוד נתונים קטגוריים\n", "\n", - "מודלים של למידת מכונה מתמודדים רק עם מספרים וכל סוג של נתונים מספריים. הם לא יוכלו להבחין בין \"כן\" ל\"לא\", אבל כן יוכלו להבדיל בין 0 ל-1. לכן, לאחר שמילאנו את הערכים החסרים, עלינו לקודד את הנתונים הקטגוריים לצורה מספרית כלשהי כדי שהמודל יוכל להבין אותם.\n", + "מודלים של למידת מכונה מתמודדים רק עם מספרים וכל סוג של נתונים מספריים. הם לא יוכלו להבחין בין \"כן\" ל-\"לא\", אבל כן יוכלו להבדיל בין 0 ל-1. לכן, לאחר מילוי הערכים החסרים, עלינו לקודד את הנתונים הקטגוריים לצורה מספרית כלשהי כדי שהמודל יוכל להבין אותם.\n", "\n", "ניתן לבצע קידוד בשתי דרכים. נדון בהן בהמשך.\n" ] @@ -2879,7 +2884,7 @@ "source": [ "**קידוד תוויות**\n", "\n", - "קידוד תוויות הוא בעצם המרה של כל קטגוריה למספר. לדוגמה, נניח שיש לנו מערך נתונים של נוסעי טיסות ויש עמודה שמכילה את המחלקה שלהם מבין ['מחלקת עסקים', 'מחלקת תיירים', 'מחלקה ראשונה']. אם נבצע קידוד תוויות על זה, זה יומר ל-[0,1,2]. בואו נראה דוגמה באמצעות קוד. מכיוון שנלמד את `scikit-learn` במחברות הבאות, לא נשתמש בו כאן.\n" + "קידוד תוויות הוא בעצם המרה של כל קטגוריה למספר. לדוגמה, נניח שיש לנו מערך נתונים של נוסעי טיסות ויש עמודה שמכילה את סוג המחלקה שלהם מבין ['מחלקת עסקים', 'מחלקת תיירים', 'מחלקה ראשונה']. אם נעשה קידוד תוויות על זה, זה יומר ל-[0,1,2]. בואו נראה דוגמה באמצעות קוד. מכיוון שנלמד את `scikit-learn` במחברות הבאות, לא נשתמש בו כאן.\n" ] }, { @@ -2987,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "כדי לבצע קידוד תוויות על העמודה הראשונה, עלינו תחילה לתאר מיפוי מכל מחלקה למספר, לפני ההחלפה\n" + "כדי לבצע קידוד תוויות על העמודה הראשונה, עלינו תחילה לתאר מיפוי מכל מחלקה למספר, לפני ההחלפה.\n" ] }, { @@ -3089,7 +3094,7 @@ "id": "ftnF-TyapOPt" }, "source": [ - "כפי שאנחנו יכולים לראות, התוצאה תואמת למה שחשבנו שיקרה. אז, מתי משתמשים בקידוד תוויות? משתמשים בקידוד תוויות באחד או בשני המקרים הבאים:\n", + "כפי שאנחנו רואים, התוצאה תואמת למה שחשבנו שיקרה. אז, מתי משתמשים בקידוד תוויות? קידוד תוויות משמש באחד או בשני המקרים הבאים:\n", "1. כאשר מספר הקטגוריות גדול\n", "2. כאשר הקטגוריות מסודרות לפי סדר.\n" ] @@ -3100,11 +3105,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**קידוד One Hot**\n", + "**קידוד ONE HOT**\n", "\n", - "סוג נוסף של קידוד הוא קידוד One Hot. בקידוד מסוג זה, כל קטגוריה בעמודה מתווספת כעמודה נפרדת, וכל נקודת נתונים תקבל ערך 0 או 1 בהתאם לשאלה האם היא מכילה את אותה קטגוריה. כלומר, אם יש n קטגוריות שונות, יתווספו n עמודות למסגרת הנתונים.\n", + "סוג נוסף של קידוד הוא קידוד One Hot. בקידוד זה, כל קטגוריה בעמודה מתווספת כעמודה נפרדת, וכל נקודת נתונים תקבל 0 או 1 בהתאם לשאלה האם היא מכילה את אותה קטגוריה. כלומר, אם יש n קטגוריות שונות, יתווספו n עמודות ל-DataFrame.\n", "\n", - "לדוגמה, ניקח את אותו דוגמה של מחלקות במטוס. הקטגוריות היו: ['business class', 'economy class', 'first class']. אם נבצע קידוד One Hot, שלוש העמודות הבאות יתווספו למאגר הנתונים: ['class_business class', 'class_economy class', 'class_first class'].\n" + "לדוגמה, ניקח שוב את הדוגמה של מחלקות המטוס. הקטגוריות היו: ['business class', 'economy class', 'first class']. אם נבצע קידוד One Hot, שלוש העמודות הבאות יתווספו למאגר הנתונים: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3337,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "כל עמודה מקודדת חם מכילה 0 או 1, שמציינים האם הקטגוריה קיימת עבור נקודת הנתונים.\n" + "כל עמודה מקודדת חם מכילה 0 או 1, אשר מציינים האם הקטגוריה קיימת עבור נקודת הנתונים הזו.\n" ] }, { @@ -3346,7 +3351,7 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "מתי משתמשים ב-One Hot Encoding? משתמשים ב-One Hot Encoding באחד או בשני המקרים הבאים:\n", + "מתי משתמשים בקידוד One Hot? קידוד One Hot משמש באחד או בשני המקרים הבאים:\n", "\n", "1. כאשר מספר הקטגוריות וגודל מערך הנתונים קטן.\n", "2. כאשר הקטגוריות אינן עוקבות אחר סדר מסוים.\n" @@ -3358,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> נקודות מפתח: \n", - "1. קידוד מתבצע כדי להמיר נתונים שאינם מספריים לנתונים מספריים. \n", - "2. ישנם שני סוגי קידוד: קידוד תוויות (Label encoding) וקידוד One Hot, שניהם יכולים להתבצע בהתאם לדרישות מערך הנתונים. \n" + "> נקודות חשובות:\n", + "1. קידוד מתבצע כדי להמיר נתונים שאינם מספריים לנתונים מספריים.\n", + "2. ישנם שני סוגי קידוד: קידוד תוויות וקידוד One Hot, שניתן לבצע בהתאם לדרישות של מערך הנתונים.\n" ] }, { @@ -3371,7 +3376,7 @@ "source": [ "## הסרת נתונים כפולים\n", "\n", - "> **מטרת הלמידה:** בסיום תת-הסעיף הזה, עליכם להרגיש בנוח לזהות ולהסיר ערכים כפולים מ-DataFrames.\n", + "> **מטרת הלמידה:** בסיום תת-הסעיף הזה, אתם אמורים להרגיש בנוח לזהות ולהסיר ערכים כפולים מ-DataFrames.\n", "\n", "בנוסף לנתונים חסרים, לעיתים קרובות תיתקלו בנתונים כפולים במערכי נתונים בעולם האמיתי. למרבה המזל, pandas מספקת דרך פשוטה לזיהוי והסרת רשומות כפולות.\n" ] @@ -3384,7 +3389,7 @@ "source": [ "### זיהוי כפילויות: `duplicated`\n", "\n", - "ניתן לזהות ערכים כפולים בקלות באמצעות השיטה `duplicated` ב-pandas, שמחזירה מסכה בוליאנית המצביעה האם ערך ב-`DataFrame` הוא כפול של ערך קודם. בואו ניצור דוגמה נוספת של `DataFrame` כדי לראות זאת בפעולה.\n" + "ניתן לזהות בקלות ערכים כפולים באמצעות השיטה `duplicated` ב-pandas, שמחזירה מסכה בוליאנית שמציינת האם ערך ב-`DataFrame` הוא כפול של ערך קודם. בואו ניצור דוגמה נוספת של `DataFrame` כדי לראות זאת בפעולה.\n" ] }, { @@ -3514,7 +3519,7 @@ }, "source": [ "### הסרת כפילויות: `drop_duplicates`\n", - "`drop_duplicates` מחזירה פשוט עותק של הנתונים שבו כל הערכים שהם `duplicated` הם `False`:\n" + "`drop_duplicates` פשוט מחזיר עותק של הנתונים שבו כל הערכים של `duplicated` הם `False`:\n" ] }, { @@ -3674,14 +3679,530 @@ "id": "GvX4og1EgRsL" }, "source": [ - "**עיקרי הדברים:** הסרת נתונים כפולים היא חלק חיוני כמעט בכל פרויקט מדעי נתונים. נתונים כפולים יכולים לשנות את תוצאות הניתוחים שלך ולספק לך תוצאות לא מדויקות!\n" + "> **עיקרי הדברים:** הסרת נתונים כפולים היא חלק חיוני כמעט בכל פרויקט מדעי נתונים. נתונים כפולים יכולים לשנות את תוצאות הניתוחים שלך ולספק לך תוצאות לא מדויקות!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## בדיקות איכות נתונים בעולם האמיתי\n", + "\n", + "> **מטרת הלמידה:** בסיום החלק הזה, תרגישו בנוח לזהות ולתקן בעיות איכות נתונים נפוצות בעולם האמיתי, כולל ערכים קטגוריים לא עקביים, ערכים מספריים חריגים (נקודות קיצון) וישויות כפולות עם וריאציות.\n", + "\n", + "בעוד שערכים חסרים וכפילויות מדויקות הם בעיות נפוצות, מערכי נתונים בעולם האמיתי מכילים לעיתים בעיות עדינות יותר:\n", + "\n", + "1. **ערכים קטגוריים לא עקביים**: אותה קטגוריה נכתבת בצורה שונה (לדוגמה, \"USA\", \"U.S.A\", \"United States\")\n", + "2. **ערכים מספריים חריגים**: נקודות קיצון קיצוניות שמצביעות על שגיאות הזנה (לדוגמה, גיל = 999)\n", + "3. **שורות כמעט כפולות**: רשומות שמייצגות את אותה ישות עם וריאציות קלות\n", + "\n", + "בואו נחקור טכניקות לזיהוי וטיפול בבעיות אלו.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### יצירת מערך נתונים \"מלוכלך\" לדוגמה\n", + "\n", + "ראשית, בואו ניצור מערך נתונים לדוגמה שמכיל את סוגי הבעיות שאנו נתקלים בהן לעיתים קרובות בנתונים מהעולם האמיתי:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. זיהוי ערכים קטגוריים לא עקביים\n", + "\n", + "שימו לב שעמודת `country` מכילה ייצוגים שונים לאותן מדינות. בואו נזהה את חוסר העקביות הזה:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### סטנדרטיזציה של ערכים קטגוריים\n", + "\n", + "ניתן ליצור מיפוי כדי לסטנדרטיזציה של הערכים הללו. גישה פשוטה היא להמיר לאותיות קטנות וליצור מילון מיפוי:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**חלופה: שימוש בהתאמה מטושטשת**\n", + "\n", + "במקרים מורכבים יותר, ניתן להשתמש בהתאמת מחרוזות מטושטשת עם ספריית `rapidfuzz` כדי לזהות באופן אוטומטי מחרוזות דומות:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. זיהוי ערכים מספריים חריגים (חריגות)\n", + "\n", + "בהתבוננות בעמודת `age`, יש לנו כמה ערכים חשודים כמו 199 ו-5-. בואו נשתמש בשיטות סטטיסטיות כדי לזהות את החריגות הללו.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### שימוש בשיטת IQR (טווח בין-רבעוני)\n", + "\n", + "שיטת IQR היא טכניקה סטטיסטית חזקה לזיהוי ערכים חריגים, שפחות רגישה לערכים קיצוניים:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### שימוש בשיטת Z-Score\n", + "\n", + "שיטת Z-Score מזהה חריגות בהתבסס על סטיות תקן מהממוצע:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### טיפול בערכים חריגים\n", + "\n", + "לאחר זיהוי, ניתן לטפל בערכים חריגים בכמה דרכים:\n", + "1. **הסרה**: מחיקת שורות עם ערכים חריגים (אם מדובר בשגיאות)\n", + "2. **הגבלה**: החלפה בערכי גבול\n", + "3. **החלפה ב-NaN**: התייחסות כנתונים חסרים ושימוש בטכניקות השלמה\n", + "4. **שמירה**: אם מדובר בערכים קיצוניים לגיטימיים\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. זיהוי שורות כמעט-כפולות\n", + "\n", + "שימו לב שבמערכת הנתונים שלנו יש מספר רשומות עבור \"John Smith\" עם ערכים מעט שונים. בואו נזהה כפילויות פוטנציאליות בהתבסס על דמיון בשמות.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### מציאת כפילויות קרובות באמצעות התאמה מטושטשת\n", + "\n", + "לזיהוי כפילויות מתוחכם יותר, ניתן להשתמש בהתאמה מטושטשת כדי למצוא שמות דומים:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### טיפול בכפילויות\n", + "\n", + "לאחר זיהוי, יש להחליט כיצד לטפל בכפילויות:\n", + "1. **שמירה על ההופעה הראשונה**: השתמשו ב-`drop_duplicates(keep='first')`\n", + "2. **שמירה על ההופעה האחרונה**: השתמשו ב-`drop_duplicates(keep='last')`\n", + "3. **איגוד מידע**: שילוב מידע משורות כפולות\n", + "4. **סקירה ידנית**: סימון לבדיקה אנושית\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### סיכום: צינור ניקוי נתונים מלא\n", + "\n", + "בואו נשלב הכל לצינור ניקוי נתונים מקיף:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 תרגיל אתגר\n", + "\n", + "עכשיו תורך! להלן שורה חדשה של נתונים עם מספר בעיות איכות. האם תוכל:\n", + "\n", + "1. לזהות את כל הבעיות בשורה זו\n", + "2. לכתוב קוד לניקוי כל בעיה\n", + "3. להוסיף את השורה הנקייה למאגר הנתונים\n", + "\n", + "הנה הנתונים הבעייתיים:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### נקודות מרכזיות\n", + "\n", + "1. **קטגוריות לא עקביות** נפוצות בנתונים מהעולם האמיתי. תמיד בדקו ערכים ייחודיים וסטנדרטיזציה שלהם באמצעות מיפויים או התאמה מטושטשת.\n", + "\n", + "2. **ערכים חריגים** יכולים להשפיע באופן משמעותי על הניתוח שלכם. השתמשו בידע מקצועי בשילוב עם שיטות סטטיסטיות (IQR, Z-score) כדי לזהות אותם.\n", + "\n", + "3. **כמעט כפילויות** קשה יותר לזהות מאשר כפילויות מדויקות. שקלו להשתמש בהתאמה מטושטשת ובנירמול נתונים (הפיכת אותיות לקטנות, הסרת רווחים) כדי לזהות אותן.\n", + "\n", + "4. **ניקוי נתונים הוא תהליך איטרטיבי**. ייתכן שתצטרכו ליישם מספר טכניקות ולסקור את התוצאות לפני שתסיימו את ערכת הנתונים הנקייה.\n", + "\n", + "5. **תעדו את ההחלטות שלכם**. עקבו אחר שלבי הניקוי שביצעתם והסיבות לכך, שכן זה חשוב לשחזור ולשקיפות.\n", + "\n", + "> **שיטה מומלצת:** תמיד שמרו עותק של הנתונים המקוריים \"המלוכלכים\". לעולם אל תדרסו את קבצי הנתונים המקוריים שלכם - צרו גרסאות נקיות עם שמות ברורים כמו `data_cleaned.csv`.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**כתב ויתור**: \nמסמך זה תורגם באמצעות שירות תרגום מבוסס בינה מלאכותית [Co-op Translator](https://github.com/Azure/co-op-translator). בעוד שאנו שואפים לדיוק, יש להיות מודעים לכך שתרגומים אוטומטיים עשויים להכיל שגיאות או אי דיוקים. המסמך המקורי בשפתו המקורית צריך להיחשב כמקור הסמכותי. עבור מידע קריטי, מומלץ להשתמש בתרגום מקצועי על ידי אדם. איננו נושאים באחריות לאי הבנות או לפרשנויות שגויות הנובעות משימוש בתרגום זה.\n" + "\n---\n\n**כתב ויתור**: \nמסמך זה תורגם באמצעות שירות תרגום מבוסס בינה מלאכותית [Co-op Translator](https://github.com/Azure/co-op-translator). למרות שאנו שואפים לדיוק, יש לקחת בחשבון שתרגומים אוטומטיים עשויים להכיל שגיאות או אי דיוקים. המסמך המקורי בשפתו המקורית צריך להיחשב כמקור סמכותי. עבור מידע קריטי, מומלץ להשתמש בתרגום מקצועי על ידי אדם. איננו נושאים באחריות לאי הבנות או לפרשנויות שגויות הנובעות משימוש בתרגום זה.\n" ] } ], @@ -3709,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:49:11+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:33:02+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "he" } diff --git a/translations/hi/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/hi/2-Working-With-Data/08-data-preparation/notebook.ipynb index 6552740a..882af53a 100644 --- a/translations/hi/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/hi/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# डेटा तैयारी\n", "\n", - "[मूल नोटबुक स्रोत *डेटा साइंस: डेटा साइंस के लिए मशीन लर्निंग का परिचय, पायथन और मशीन लर्निंग स्टूडियो द्वारा ली स्टॉट*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[मूल नोटबुक स्रोत *डेटा साइंस: डेटा साइंस के लिए मशीन लर्निंग का परिचय, पायथन और मशीन लर्निंग स्टूडियो* ली स्टॉट द्वारा](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## `DataFrame` जानकारी का अन्वेषण\n", "\n", - "> **सीखने का लक्ष्य:** इस उपखंड के अंत तक, आप pandas DataFrames में संग्रहीत डेटा के बारे में सामान्य जानकारी प्राप्त करने में सहज हो जाएंगे।\n", + "> **लक्ष्य:** इस उपखंड के अंत तक, आपको pandas DataFrames में संग्रहीत डेटा के बारे में सामान्य जानकारी प्राप्त करने में सहज होना चाहिए।\n", "\n", - "एक बार जब आप अपना डेटा pandas में लोड कर लेते हैं, तो यह अधिकतर मामलों में `DataFrame` में होगा। लेकिन अगर आपके `DataFrame` में 60,000 पंक्तियाँ और 400 कॉलम हैं, तो आप यह समझना कैसे शुरू करेंगे कि आप किसके साथ काम कर रहे हैं? सौभाग्य से, pandas कुछ सुविधाजनक टूल प्रदान करता है जो `DataFrame` की समग्र जानकारी के साथ-साथ शुरुआती और अंतिम कुछ पंक्तियों को जल्दी से देखने में मदद करते हैं।\n", + "जब आपने अपना डेटा pandas में लोड कर लिया है, तो यह अधिक संभावना है कि यह `DataFrame` में होगा। हालांकि, यदि आपके `DataFrame` में 60,000 पंक्तियाँ और 400 स्तंभ हैं, तो आप यह समझना कैसे शुरू करेंगे कि आप किसके साथ काम कर रहे हैं? सौभाग्य से, pandas कुछ सुविधाजनक उपकरण प्रदान करता है जो `DataFrame` की समग्र जानकारी के साथ-साथ शुरुआती और अंतिम कुछ पंक्तियों को जल्दी से देखने में मदद करते हैं।\n", "\n", - "इस कार्यक्षमता का अन्वेषण करने के लिए, हम Python की scikit-learn लाइब्रेरी को इम्पोर्ट करेंगे और एक प्रसिद्ध डेटा सेट का उपयोग करेंगे जिसे हर डेटा वैज्ञानिक ने सैकड़ों बार देखा है: ब्रिटिश जीवविज्ञानी रोनाल्ड फिशर का *Iris* डेटा सेट, जिसे उन्होंने 1936 के अपने पेपर \"The use of multiple measurements in taxonomic problems\" में उपयोग किया था:\n" + "इस कार्यक्षमता का अन्वेषण करने के लिए, हम Python scikit-learn लाइब्रेरी को आयात करेंगे और एक प्रसिद्ध डेटा सेट का उपयोग करेंगे जिसे हर डेटा वैज्ञानिक ने सैकड़ों बार देखा है: ब्रिटिश जीवविज्ञानी रोनाल्ड फिशर का *Iris* डेटा सेट, जो उनकी 1936 की पेपर \"The use of multiple measurements in taxonomic problems\" में उपयोग किया गया था:\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "हमने Iris Dataset को वेरिएबल `iris_df` में लोड किया है। डेटा में गहराई से जाने से पहले, यह जानना उपयोगी होगा कि हमारे पास कितने डेटा पॉइंट्स हैं और पूरे डेटासेट का आकार क्या है। यह देखना महत्वपूर्ण है कि हम कितने डेटा की मात्रा के साथ काम कर रहे हैं।\n" + "हमने Iris Dataset को `iris_df` नामक वेरिएबल में लोड किया है। डेटा में गहराई से जाने से पहले, यह जानना महत्वपूर्ण होगा कि हमारे पास कितने डेटा पॉइंट्स हैं और पूरे डेटासेट का आकार क्या है। यह देखना उपयोगी होता है कि हम कितने डेटा की मात्रा के साथ काम कर रहे हैं।\n" ] }, { @@ -78,7 +78,7 @@ "id": "smE7AGzOhxk2" }, "source": [ - "हम 150 पंक्तियों और 4 स्तंभों के डेटा के साथ काम कर रहे हैं। प्रत्येक पंक्ति एक डेटा पॉइंट का प्रतिनिधित्व करती है और प्रत्येक स्तंभ डेटा फ्रेम से संबंधित एकल विशेषता को दर्शाता है। तो मूल रूप से, 150 डेटा पॉइंट्स हैं, जिनमें प्रत्येक में 4 विशेषताएँ शामिल हैं।\n", + "तो, हम 150 पंक्तियों और 4 स्तंभों के डेटा से निपट रहे हैं। प्रत्येक पंक्ति एक डेटा पॉइंट का प्रतिनिधित्व करती है और प्रत्येक स्तंभ डेटा फ्रेम से जुड़े एकल फीचर का प्रतिनिधित्व करता है। तो मूल रूप से, 150 डेटा पॉइंट हैं, जिनमें प्रत्येक में 4 फीचर शामिल हैं।\n", "\n", "`shape` यहाँ डेटा फ्रेम का एक गुण है और कोई फ़ंक्शन नहीं है, यही कारण है कि यह कोष्ठकों की एक जोड़ी के साथ समाप्त नहीं होता।\n" ] @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "अब हम डेटा की 4 कॉलम्स में चलते हैं। इनमें से प्रत्येक वास्तव में क्या दर्शाता है? `columns` attribute हमें डेटा फ्रेम में कॉलम्स के नाम देगा।\n" + "अब हम डेटा की 4 कॉलम्स पर ध्यान देते हैं। इनमें से प्रत्येक वास्तव में क्या दर्शाती है? `columns` एट्रिब्यूट हमें डेटा फ्रेम में कॉलम्स के नाम देगा।\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "जैसा कि हम देख सकते हैं, चार(4) कॉलम हैं। `columns` गुण हमें कॉलमों के नाम बताता है और मूल रूप से कुछ और नहीं। यह गुण तब महत्वपूर्ण हो जाता है जब हम यह पहचानना चाहते हैं कि एक डेटासेट में कौन-कौन से फीचर्स शामिल हैं।\n" + "जैसा कि हम देख सकते हैं, यहाँ चार(4) कॉलम हैं। `columns` एट्रिब्यूट हमें कॉलम के नाम बताता है और मूल रूप से कुछ और नहीं। यह एट्रिब्यूट तब महत्वपूर्ण हो जाता है जब हम यह पहचानना चाहते हैं कि किसी डेटासेट में कौन-कौन से फीचर्स शामिल हैं।\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "डेटा की मात्रा (`shape` attribute द्वारा दी गई) और फीचर्स या कॉलम्स के नाम (`columns` attribute द्वारा दिए गए) हमें डेटासेट के बारे में कुछ जानकारी देते हैं। अब, हम डेटासेट में और गहराई से जाना चाहेंगे। `DataFrame.info()` फ़ंक्शन इसके लिए काफी उपयोगी है।\n" + "डेटा की मात्रा (`shape` attribute द्वारा दी गई) और फीचर्स या कॉलम के नाम (`columns` attribute द्वारा दिए गए) हमें डेटासेट के बारे में कुछ जानकारी देते हैं। अब, हम डेटासेट में और गहराई से जाना चाहेंगे। `DataFrame.info()` फ़ंक्शन इसके लिए काफी उपयोगी है।\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "यहां से, हम कुछ महत्वपूर्ण अवलोकन कर सकते हैं:\n", + "यहां से, हम कुछ टिप्पणियां कर सकते हैं:\n", "1. प्रत्येक कॉलम का डेटा प्रकार: इस डेटा सेट में, सभी डेटा 64-बिट फ्लोटिंग-पॉइंट नंबर के रूप में संग्रहीत हैं।\n", - "2. गैर-नल मानों की संख्या: नल मानों को संभालना डेटा तैयारी में एक महत्वपूर्ण कदम है। इसे बाद में नोटबुक में संभाला जाएगा।\n" + "2. नॉन-नल मानों की संख्या: नल मानों को संभालना डेटा तैयारी में एक महत्वपूर्ण कदम है। इसे नोटबुक में बाद में संभाला जाएगा।\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "मान लीजिए हमारे डेटा सेट में बहुत सारा संख्यात्मक डेटा है। औसत, माध्यिका, चतुर्थांश आदि जैसे एकविवरणीय सांख्यिकीय गणनाएँ प्रत्येक कॉलम पर अलग-अलग की जा सकती हैं। `DataFrame.describe()` फ़ंक्शन हमें डेटा सेट के संख्यात्मक कॉलम का सांख्यिकीय सारांश प्रदान करता है।\n" + "मान लीजिए हमारे डेटा सेट में बहुत सारा संख्यात्मक डेटा है। एकविवरणात्मक सांख्यिकीय गणनाएँ जैसे औसत, माध्यिका, चतुर्थांश आदि प्रत्येक कॉलम पर अलग-अलग की जा सकती हैं। `DataFrame.describe()` फ़ंक्शन हमें डेटा सेट के संख्यात्मक कॉलम का सांख्यिकीय सारांश प्रदान करता है।\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "ऊपर दिया गया आउटपुट प्रत्येक कॉलम के कुल डेटा पॉइंट्स, औसत, मानक विचलन, न्यूनतम, निचला चतुर्थक (25%), माध्यिका (50%), ऊपरी चतुर्थक (75%) और अधिकतम मान को दिखाता है।\n" + "ऊपर दिया गया आउटपुट प्रत्येक कॉलम के कुल डेटा पॉइंट्स, औसत, मानक विचलन, न्यूनतम, निचला चतुर्थक (25%), माध्य (50%), ऊपरी चतुर्थक (75%) और अधिकतम मान को दिखाता है।\n" ] }, { @@ -332,7 +332,7 @@ }, "source": [ "### `DataFrame.head`\n", - "ऊपर दिए गए सभी फ़ंक्शन्स और एट्रिब्यूट्स के साथ, हमने डेटासेट का एक उच्च-स्तरीय अवलोकन प्राप्त कर लिया है। हमें पता है कि इसमें कितने डेटा पॉइंट्स हैं, कितनी विशेषताएँ (features) हैं, प्रत्येक विशेषता का डेटा प्रकार क्या है, और प्रत्येक विशेषता के लिए कितने non-null मान हैं।\n", + "ऊपर दिए गए सभी फ़ंक्शन्स और एट्रिब्यूट्स के साथ, हमने डेटासेट का एक उच्च-स्तरीय दृष्टिकोण प्राप्त कर लिया है। हमें पता है कि कितने डेटा पॉइंट्स हैं, कितनी विशेषताएँ हैं, प्रत्येक विशेषता का डेटा प्रकार क्या है और प्रत्येक विशेषता के लिए कितने नॉन-नल वैल्यूज़ हैं।\n", "\n", "अब समय है डेटा को खुद देखने का। चलिए देखते हैं कि हमारे `DataFrame` की शुरुआती कुछ पंक्तियाँ (शुरुआती कुछ डेटा पॉइंट्स) कैसी दिखती हैं:\n" ] @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "यहाँ आउटपुट में, हम डेटा सेट के पाँच(5) प्रविष्टियाँ देख सकते हैं। यदि हम बाईं ओर के इंडेक्स को देखें, तो हमें पता चलता है कि ये पहली पाँच पंक्तियाँ हैं।\n" + "आउटपुट में, हम डेटा सेट के पाँच (5) प्रविष्टियाँ देख सकते हैं। यदि हम बाईं ओर के इंडेक्स को देखें, तो पता चलता है कि ये पहली पाँच पंक्तियाँ हैं।\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### अभ्यास:\n", "\n", - "उपरोक्त उदाहरण से यह स्पष्ट है कि डिफ़ॉल्ट रूप से `DataFrame.head` एक `DataFrame` की पहली पाँच पंक्तियाँ लौटाता है। नीचे दिए गए कोड सेल में, क्या आप पाँच से अधिक पंक्तियाँ प्रदर्शित करने का तरीका ढूंढ सकते हैं?\n" + "ऊपर दिए गए उदाहरण से यह स्पष्ट है कि डिफ़ॉल्ट रूप से `DataFrame.head` एक `DataFrame` की पहली पांच पंक्तियाँ लौटाता है। नीचे दिए गए कोड सेल में, क्या आप यह पता लगा सकते हैं कि पाँच से अधिक पंक्तियाँ कैसे प्रदर्शित की जाएं?\n" ] }, { @@ -584,9 +584,9 @@ "source": [ "व्यवहार में, यह उपयोगी होता है कि आप आसानी से `DataFrame` की शुरुआती कुछ पंक्तियों या अंतिम कुछ पंक्तियों की जांच कर सकें, खासकर जब आप क्रमबद्ध डेटा सेट में असामान्य मान खोज रहे हों।\n", "\n", - "ऊपर दिए गए कोड उदाहरणों की मदद से दिखाए गए सभी फ़ंक्शन और गुण हमें डेटा की झलक और अनुभव प्राप्त करने में मदद करते हैं।\n", + "ऊपर दिखाए गए सभी फ़ंक्शन और गुण, कोड उदाहरणों की मदद से, हमें डेटा की झलक और अनुभव प्राप्त करने में मदद करते हैं।\n", "\n", - "> **मुख्य बात:** केवल `DataFrame` में मौजूद जानकारी के मेटाडेटा को देखकर या उसकी शुरुआती और अंतिम कुछ मानों को देखकर, आप तुरंत उस डेटा के आकार, संरचना और सामग्री के बारे में एक विचार प्राप्त कर सकते हैं, जिसके साथ आप काम कर रहे हैं।\n" + "> **मुख्य बात:** केवल `DataFrame` में जानकारी के मेटाडेटा को देखकर या इसकी शुरुआती और अंतिम कुछ मानों को देखकर, आप जिस डेटा से निपट रहे हैं उसकी आकार, संरचना और सामग्री के बारे में तुरंत एक विचार प्राप्त कर सकते हैं।\n" ] }, { @@ -595,20 +595,18 @@ "id": "TvurZyLSDxq_" }, "source": [ - "### डेटा की कमी \n", - "आइए डेटा की कमी के बारे में समझें। डेटा की कमी तब होती है, जब कुछ कॉलम्स में कोई मान संग्रहीत नहीं होता। \n", + "### डेटा की कमी\n", + "आइए डेटा की कमी के बारे में जानें। डेटा की कमी तब होती है, जब कुछ कॉलम में कोई मान संग्रहीत नहीं होता है।\n", "\n", - "एक उदाहरण लेते हैं: मान लीजिए कोई व्यक्ति अपने वजन को लेकर सचेत है और सर्वे में वजन वाले फील्ड को खाली छोड़ देता है। तो उस व्यक्ति के लिए वजन का मान गायब होगा। \n", + "एक उदाहरण लेते हैं: मान लीजिए कोई व्यक्ति अपने वजन को लेकर सचेत है और सर्वेक्षण में वजन वाले फील्ड को नहीं भरता है। तो उस व्यक्ति के लिए वजन का मान गायब होगा।\n", "\n", - "अधिकतर समय, वास्तविक दुनिया के डेटासेट्स में गायब मान देखने को मिलते हैं। \n", + "अधिकतर समय, वास्तविक दुनिया के डेटासेट्स में, मान गायब होने की समस्या होती है।\n", "\n", - "**Pandas डेटा की कमी को कैसे संभालता है** \n", + "**Pandas डेटा की कमी को कैसे संभालता है**\n", "\n", - "Pandas दो तरीकों से गायब मानों को संभालता है। पहला तरीका आपने पहले के सेक्शन्स में देखा होगा: `NaN`, या Not a Number। यह वास्तव में एक विशेष मान है जो IEEE फ्लोटिंग-पॉइंट स्पेसिफिकेशन का हिस्सा है और इसे केवल गायब फ्लोटिंग-पॉइंट मानों को दर्शाने के लिए उपयोग किया जाता है। \n", + "Pandas दो तरीकों से गायब मानों को संभालता है। पहला तरीका आपने पहले के सेक्शन्स में देखा होगा: `NaN`, या Not a Number। यह वास्तव में IEEE फ्लोटिंग-पॉइंट स्पेसिफिकेशन का एक विशेष मान है और इसे केवल गायब फ्लोटिंग-पॉइंट मानों को इंगित करने के लिए उपयोग किया जाता है।\n", "\n", - "फ्लोट्स के अलावा अन्य गायब मानों के लिए, pandas Python के `None` ऑब्जेक्ट का उपयोग करता है। हालांकि यह थोड़ा भ्रमित कर सकता है कि आपको दो अलग-अलग प्रकार के मान मिलेंगे जो मूल रूप से एक ही बात कहते हैं, लेकिन इस डिज़ाइन विकल्प के पीछे ठोस प्रोग्रामिंग कारण हैं। व्यवहार में, इस दृष्टिकोण को अपनाने से pandas अधिकांश मामलों के लिए एक अच्छा संतुलन प्रदान करता है। \n", - "\n", - "इसके बावजूद, `None` और `NaN` दोनों में कुछ सीमाएँ होती हैं, जिनका उपयोग करते समय आपको ध्यान रखना होगा।\n" + "फ्लोट्स के अलावा गायब मानों के लिए, pandas Python के `None` ऑब्जेक्ट का उपयोग करता है। हालांकि यह थोड़ा भ्रमित करने वाला लग सकता है कि आपको दो अलग-अलग प्रकार के मान मिलते हैं जो मूल रूप से एक ही बात कहते हैं, लेकिन इस डिज़ाइन विकल्प के पीछे ठोस प्रोग्रामेटिक कारण हैं। और व्यवहार में, इस रास्ते पर जाने से pandas अधिकांश मामलों के लिए एक अच्छा संतुलन प्रदान करने में सक्षम होता है। इसके बावजूद, `None` और `NaN` दोनों में कुछ सीमाएँ होती हैं जिनके बारे में आपको सतर्क रहना चाहिए कि उन्हें कैसे उपयोग किया जा सकता है।\n" ] }, { @@ -618,9 +616,9 @@ }, "source": [ "### `None`: गैर-फ्लोट गायब डेटा\n", - "क्योंकि `None` Python से आता है, इसे उन NumPy और pandas arrays में उपयोग नहीं किया जा सकता जो डेटा प्रकार `'object'` के नहीं हैं। याद रखें, NumPy arrays (और pandas में डेटा संरचनाएं) केवल एक प्रकार के डेटा को ही समाहित कर सकते हैं। यही उन्हें बड़े पैमाने पर डेटा और गणनात्मक कार्यों के लिए उनकी जबरदस्त शक्ति देता है, लेकिन यह उनकी लचीलापन को भी सीमित करता है। ऐसे arrays को \"सबसे सामान्य हर प्रकार\" में बदलना पड़ता है, यानी ऐसा डेटा प्रकार जो array में सब कुछ समाहित कर सके। जब array में `None` होता है, तो इसका मतलब है कि आप Python objects के साथ काम कर रहे हैं।\n", + "क्योंकि `None` Python से आता है, इसे NumPy और pandas के उन arrays में उपयोग नहीं किया जा सकता जिनका डेटा प्रकार `'object'` नहीं है। याद रखें, NumPy arrays (और pandas में डेटा संरचनाएं) केवल एक प्रकार के डेटा को ही समाहित कर सकते हैं। यही कारण है कि वे बड़े पैमाने पर डेटा और गणनात्मक कार्यों के लिए अत्यधिक शक्तिशाली हैं, लेकिन यह उनकी लचीलापन को भी सीमित करता है। ऐसे arrays को \"न्यूनतम सामान्य भाजक\" में बदलना पड़ता है, यानी वह डेटा प्रकार जो array में सब कुछ समाहित कर सके। जब array में `None` होता है, तो इसका मतलब है कि आप Python objects के साथ काम कर रहे हैं।\n", "\n", - "इसे क्रियान्वित होते हुए देखने के लिए, निम्नलिखित उदाहरण array पर विचार करें (इसके `dtype` पर ध्यान दें):\n" + "इसका उदाहरण देखने के लिए, निम्नलिखित array पर विचार करें (इसके `dtype` पर ध्यान दें):\n" ] }, { @@ -659,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "अपकास्ट डेटा प्रकारों की वास्तविकता के साथ दो प्रभाव जुड़े होते हैं। पहला, ऑपरेशन्स इंटरप्रेटेड Python कोड के स्तर पर किए जाते हैं, न कि कंपाइल्ड NumPy कोड के स्तर पर। मूल रूप से, इसका मतलब है कि `Series` या `DataFrames` जिनमें `None` शामिल है, उनके साथ किए गए ऑपरेशन्स धीमे होंगे। हालांकि, आप शायद इस प्रदर्शन में कमी को महसूस न करें, लेकिन बड़े डेटा सेट्स के लिए यह एक समस्या बन सकती है।\n", + "अपकास्ट डेटा प्रकारों की वास्तविकता के साथ दो प्रभाव जुड़े होते हैं। पहला, ऑपरेशन्स इंटरप्रेटेड Python कोड के स्तर पर किए जाते हैं, न कि कंपाइल्ड NumPy कोड के स्तर पर। इसका मतलब यह है कि यदि `Series` या `DataFrames` में `None` शामिल है, तो उनसे जुड़े ऑपरेशन्स धीमे होंगे। हालांकि, आप शायद इस प्रदर्शन में गिरावट को महसूस न करें, लेकिन बड़े डेटा सेट्स के लिए यह समस्या बन सकती है।\n", "\n", - "दूसरा प्रभाव पहले से जुड़ा हुआ है। क्योंकि `None` मूल रूप से `Series` या `DataFrame`s को वापस साधारण Python की दुनिया में खींच लेता है, NumPy/pandas एग्रीगेशन जैसे `sum()` या `min()` का उपयोग उन arrays पर जिनमें ``None`` मान होता है, आमतौर पर एक त्रुटि उत्पन्न करेगा:\n" + "दूसरा प्रभाव पहले वाले से जुड़ा हुआ है। क्योंकि `None` मूल रूप से `Series` या `DataFrame`s को सामान्य Python की दुनिया में वापस ले जाता है, ऐसे में यदि आप NumPy/pandas एग्रीगेशन जैसे `sum()` या `min()` का उपयोग उन arrays पर करते हैं जिनमें ``None`` मान होता है, तो आमतौर पर एक त्रुटि उत्पन्न होगी:\n" ] }, { @@ -699,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**मुख्य निष्कर्ष**: पूर्णांकों और `None` मानों के बीच जोड़ (और अन्य संचालन) अपरिभाषित है, जो उन डेटासेट्स के साथ आपके कार्यों को सीमित कर सकता है जिनमें ये शामिल हैं।\n" + ] }, { "cell_type": "markdown", @@ -707,9 +707,9 @@ "id": "pWvVHvETgRr9" }, "source": [ - "### `NaN`: गुम फ्लोट मान\n", + "### `NaN`: गायब फ्लोट मान\n", "\n", - "`None` के विपरीत, NumPy (और इसलिए pandas) अपने तेज, वेक्टराइज्ड ऑपरेशन्स और ufuncs के लिए `NaN` का समर्थन करता है। बुरी खबर यह है कि `NaN` पर किया गया कोई भी गणितीय ऑपरेशन हमेशा `NaN` ही देता है। उदाहरण के लिए:\n" + "`None` के विपरीत, NumPy (और इसलिए pandas) अपने तेज, वेक्टराइज्ड ऑपरेशन्स और ufuncs के लिए `NaN` का समर्थन करता है। बुरी खबर यह है कि `NaN` पर किया गया कोई भी अंकगणितीय ऑपरेशन हमेशा `NaN` ही देता है। उदाहरण के लिए:\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "अच्छी खबर: `NaN` वाले arrays पर चलने वाले समूहन त्रुटियाँ उत्पन्न नहीं करते। बुरी खबर: परिणाम समान रूप से उपयोगी नहीं हैं:\n" + "अच्छी खबर: `NaN` वाले ऐरे पर चलने वाले समेकन त्रुटियां उत्पन्न नहीं करते। बुरी खबर: परिणाम समान रूप से उपयोगी नहीं होते:\n" ] }, { @@ -808,7 +808,9 @@ "metadata": { "id": "nhlnNJT7gRr_" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -828,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "याद रखें: `NaN` केवल गायब फ्लोटिंग-पॉइंट मानों के लिए है; पूर्णांक, स्ट्रिंग्स, या बूलियन के लिए कोई `NaN` समकक्ष नहीं है।\n" + ] }, { "cell_type": "markdown", @@ -838,7 +842,7 @@ "source": [ "### `NaN` और `None`: pandas में null मान\n", "\n", - "हालांकि `NaN` और `None` का व्यवहार थोड़ा अलग हो सकता है, फिर भी pandas इन्हें एक-दूसरे के साथ संभालने के लिए डिज़ाइन किया गया है। इसे समझने के लिए, एक `Series` का उदाहरण लें जिसमें पूर्णांक हैं:\n" + "हालांकि `NaN` और `None` का व्यवहार थोड़ा अलग हो सकता है, फिर भी pandas इन्हें एक-दूसरे के स्थान पर संभालने के लिए बनाया गया है। इसे समझने के लिए, आइए एक `Series` के उदाहरण पर विचार करें जिसमें पूर्णांक हैं:\n" ] }, { @@ -877,7 +881,9 @@ "metadata": { "id": "WklCzqb8gRsB" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -900,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "डेटा प्रकारों को समान बनाने के लिए `Series` और `DataFrame`s में अपकास्टिंग प्रक्रिया के दौरान, pandas आसानी से गायब मानों को `None` और `NaN` के बीच बदल सकता है। इस डिज़ाइन फीचर के कारण, pandas में `None` और `NaN` को \"null\" के दो अलग-अलग प्रकार के रूप में सोचना उपयोगी हो सकता है। वास्तव में, pandas में गायब मानों को संभालने के लिए उपयोग किए जाने वाले कुछ मुख्य तरीकों के नाम भी इस विचार को दर्शाते हैं:\n", + "`Series` और `DataFrame` में डेटा की समानता स्थापित करने के लिए डेटा प्रकारों को अपकास्ट करने की प्रक्रिया में, pandas आसानी से गायब मानों को `None` और `NaN` के बीच बदल सकता है। इस डिज़ाइन फीचर के कारण, pandas में `None` और `NaN` को \"null\" के दो अलग-अलग प्रकार के रूप में सोचना उपयोगी हो सकता है। वास्तव में, pandas में गायब मानों को संभालने के लिए उपयोग किए जाने वाले कुछ मुख्य तरीकों के नाम इस विचार को दर्शाते हैं:\n", "\n", "- `isnull()`: गायब मानों को इंगित करने वाला एक बूलियन मास्क बनाता है\n", "- `notnull()`: `isnull()` का विपरीत\n", - "- `dropna()`: डेटा का एक फ़िल्टर किया हुआ संस्करण लौटाता है\n", - "- `fillna()`: डेटा की एक कॉपी लौटाता है जिसमें गायब मान भरे या अनुमानित किए गए हों\n", + "- `dropna()`: डेटा का फ़िल्टर किया हुआ संस्करण लौटाता है\n", + "- `fillna()`: डेटा की एक प्रति लौटाता है जिसमें गायब मान भरे या अनुमानित किए गए हों\n", "\n", - "ये महत्वपूर्ण विधियाँ हैं जिन्हें समझना और इनसे सहज होना आवश्यक है, तो आइए हम इन्हें विस्तार से समझते हैं।\n" + "ये महत्वपूर्ण विधियां हैं जिन्हें समझना और इनके साथ सहज होना आवश्यक है, इसलिए आइए इन्हें विस्तार से समझते हैं।\n" ] }, { @@ -918,8 +924,8 @@ "source": [ "### null मानों का पता लगाना\n", "\n", - "अब जब हमने गायब मानों के महत्व को समझ लिया है, तो हमें उन्हें संभालने से पहले अपने डेटा सेट में उनका पता लगाना होगा। \n", - "`isnull()` और `notnull()` दोनों null डेटा का पता लगाने के लिए आपके प्राथमिक तरीके हैं। दोनों आपके डेटा पर Boolean मास्क लौटाते हैं।\n" + "अब जब हमने गायब मानों के महत्व को समझ लिया है, तो हमें उन्हें संभालने से पहले अपने डेटा सेट में उनका पता लगाना होगा। \n", + "`isnull()` और `notnull()` दोनों null डेटा का पता लगाने के लिए आपके मुख्य तरीके हैं। दोनों आपके डेटा पर Boolean मास्क लौटाते हैं।\n" ] }, { @@ -972,9 +978,9 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "इस आउटपुट को ध्यान से देखें। क्या इसमें कुछ ऐसा है जो आपको चौंकाता है? जबकि `0` एक अंकगणितीय शून्य है, यह फिर भी एक पूरी तरह से मान्य पूर्णांक है और pandas इसे उसी रूप में मानता है। `''` थोड़ा अधिक सूक्ष्म है। जबकि हमने इसे सेक्शन 1 में एक खाली स्ट्रिंग मान को दर्शाने के लिए उपयोग किया था, यह फिर भी एक स्ट्रिंग ऑब्जेक्ट है और pandas के दृष्टिकोण से इसे null का प्रतिनिधित्व नहीं माना जाता।\n", + "आउटपुट को ध्यान से देखें। क्या इसमें कुछ ऐसा है जो आपको चौंकाता है? जबकि `0` एक गणितीय शून्य है, यह फिर भी एक पूरी तरह से मान्य पूर्णांक है और pandas इसे उसी रूप में मानता है। `''` थोड़ा अधिक सूक्ष्म है। हमने इसे सेक्शन 1 में एक खाली स्ट्रिंग मान को दर्शाने के लिए उपयोग किया था, लेकिन pandas के दृष्टिकोण से यह फिर भी एक स्ट्रिंग ऑब्जेक्ट है और इसे null का प्रतिनिधित्व नहीं माना जाता।\n", "\n", - "अब, आइए इसे उलटते हैं और इन विधियों का उपयोग उस तरीके से करते हैं जैसा आप इन्हें व्यावहारिक रूप से उपयोग करेंगे। आप Boolean मास्क को सीधे एक ``Series`` या ``DataFrame`` इंडेक्स के रूप में उपयोग कर सकते हैं, जो तब उपयोगी हो सकता है जब आप अलग-थलग गायब (या मौजूद) मानों के साथ काम करने की कोशिश कर रहे हों।\n", + "अब, इसे उलटते हैं और इन विधियों का उपयोग उस तरीके से करते हैं जैसा आप इन्हें व्यावहारिक रूप से उपयोग करेंगे। आप Boolean मास्क को सीधे ``Series`` या ``DataFrame`` इंडेक्स के रूप में उपयोग कर सकते हैं, जो तब उपयोगी हो सकता है जब आप अलग-अलग गायब (या मौजूद) मानों के साथ काम करने की कोशिश कर रहे हों।\n", "\n", "यदि हमें गायब मानों की कुल संख्या चाहिए, तो हम बस `isnull()` विधि द्वारा उत्पन्न मास्क पर एक sum कर सकते हैं।\n" ] @@ -1010,7 +1016,9 @@ "metadata": { "id": "PlBqEo3mgRsC" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -1031,7 +1039,9 @@ "metadata": { "id": "D_jWN7mHgRsD" }, - "source": [] + "source": [ + "**मुख्य निष्कर्ष**: `isnull()` और `notnull()` दोनों विधियाँ समान परिणाम उत्पन्न करती हैं जब आप उन्हें डेटा फ्रेम में उपयोग करते हैं: वे परिणाम और उन परिणामों के इंडेक्स दिखाती हैं, जो आपके डेटा के साथ काम करते समय आपको बहुत मदद करेंगे।\n" + ] }, { "cell_type": "markdown", @@ -1041,18 +1051,18 @@ "source": [ "### डेटा की कमी से निपटना\n", "\n", - "> **सीखने का लक्ष्य:** इस उपखंड के अंत तक, आपको यह पता होना चाहिए कि DataFrames से null मानों को कब और कैसे बदलना या हटाना है।\n", + "> **लक्ष्य:** इस अनुभाग के अंत तक, आप जान जाएंगे कि DataFrames से null मानों को कब और कैसे बदलना या हटाना है।\n", "\n", - "मशीन लर्निंग मॉडल स्वयं डेटा की कमी को संभाल नहीं सकते। इसलिए, मॉडल में डेटा पास करने से पहले, हमें इन गायब मानों से निपटना होता है।\n", + "मशीन लर्निंग मॉडल स्वयं डेटा की कमी को संभाल नहीं सकते। इसलिए, मॉडल में डेटा पास करने से पहले, हमें इन गायब मानों से निपटना होगा।\n", "\n", - "गायब डेटा को संभालने का तरीका सूक्ष्म समझौते लेकर आता है, जो आपके अंतिम विश्लेषण और वास्तविक दुनिया के परिणामों को प्रभावित कर सकता है।\n", + "गायब डेटा को संभालने का तरीका सूक्ष्म समझौतों के साथ आता है, और यह आपके अंतिम विश्लेषण और वास्तविक दुनिया के परिणामों को प्रभावित कर सकता है।\n", "\n", "गायब डेटा से निपटने के मुख्यतः दो तरीके हैं:\n", "\n", - "1. उस पंक्ति को हटा दें जिसमें गायब मान है \n", - "2. गायब मान को किसी अन्य मान से बदल दें \n", + "1. उस पंक्ति को हटा दें जिसमें गायब मान है\n", + "2. गायब मान को किसी अन्य मान से बदल दें\n", "\n", - "हम इन दोनों तरीकों और उनके फायदे और नुकसान को विस्तार से चर्चा करेंगे। \n" + "हम इन दोनों तरीकों और उनके फायदे और नुकसान को विस्तार से चर्चा करेंगे।\n" ] }, { @@ -1063,11 +1073,11 @@ "source": [ "### null मानों को हटाना\n", "\n", - "हमारे मॉडल को दी जाने वाली डेटा की मात्रा उसके प्रदर्शन पर सीधे प्रभाव डालती है। null मानों को हटाने का मतलब है कि हम डेटा पॉइंट्स की संख्या कम कर रहे हैं, और इस प्रकार डेटासेट का आकार भी कम कर रहे हैं। इसलिए, जब डेटासेट काफी बड़ा हो, तो null मानों वाली पंक्तियों को हटाना उचित होता है।\n", + "हमारे मॉडल को दी जाने वाली डेटा की मात्रा उसके प्रदर्शन पर सीधे प्रभाव डालती है। null मानों को हटाने का मतलब है कि हम डेटा पॉइंट्स की संख्या कम कर रहे हैं, और इस प्रकार डेटासेट का आकार भी घटा रहे हैं। इसलिए, जब डेटासेट काफी बड़ा हो, तो null मानों वाली पंक्तियों को हटाना उचित होता है।\n", "\n", - "एक और स्थिति हो सकती है कि किसी विशेष पंक्ति या स्तंभ में बहुत सारे missing values हों। ऐसे में उन्हें हटाया जा सकता है क्योंकि वे हमारे विश्लेषण में ज्यादा मूल्य नहीं जोड़ेंगे, क्योंकि उस पंक्ति/स्तंभ के अधिकांश डेटा गायब हैं।\n", + "एक और स्थिति हो सकती है जब किसी विशेष पंक्ति या कॉलम में बहुत सारे missing values हों। ऐसे में उन्हें हटाया जा सकता है क्योंकि वे हमारे विश्लेषण में ज्यादा मूल्य नहीं जोड़ेंगे, क्योंकि उस पंक्ति/कॉलम के अधिकांश डेटा गायब हैं।\n", "\n", - "missing values की पहचान करने के अलावा, pandas `Series` और `DataFrame`s से null मानों को हटाने का एक सुविधाजनक तरीका प्रदान करता है। इसे क्रियान्वित होते हुए देखने के लिए, चलिए `example3` पर वापस चलते हैं। `DataFrame.dropna()` फ़ंक्शन null मानों वाली पंक्तियों को हटाने में मदद करता है।\n" + "missing values की पहचान करने के अलावा, pandas null मानों को `Series` और `DataFrame`s से हटाने का एक सुविधाजनक तरीका प्रदान करता है। इसे क्रियान्वित होते हुए देखने के लिए, चलिए `example3` पर वापस चलते हैं। `DataFrame.dropna()` फ़ंक्शन null मानों वाली पंक्तियों को हटाने में मदद करता है।\n" ] }, { @@ -1106,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "ध्यान दें कि यह आपके आउटपुट की तरह दिखना चाहिए `example3[example3.notnull()]`। यहाँ अंतर यह है कि, केवल मास्क किए गए मानों पर इंडेक्सिंग करने के बजाय, `dropna` ने `Series` `example3` से उन गायब मानों को हटा दिया है।\n", + "ध्यान दें कि यह आपके `example3[example3.notnull()]` के आउटपुट जैसा दिखना चाहिए। यहाँ अंतर यह है कि, केवल मास्क किए गए मानों पर इंडेक्सिंग करने के बजाय, `dropna` ने `Series` `example3` से उन गायब मानों को हटा दिया है।\n", "\n", - "क्योंकि DataFrames में दो आयाम होते हैं, वे डेटा को हटाने के लिए अधिक विकल्प प्रदान करते हैं।\n" + "क्योंकि DataFrames दो आयामों वाले होते हैं, वे डेटा को हटाने के लिए अधिक विकल्प प्रदान करते हैं।\n" ] }, { @@ -1200,7 +1210,7 @@ "source": [ "(क्या आपने देखा कि pandas ने `NaN`s को समायोजित करने के लिए दो कॉलम को फ्लोट्स में अपकास्ट कर दिया?)\n", "\n", - "आप `DataFrame` से एकल मान को हटा नहीं सकते, इसलिए आपको पूरी पंक्तियाँ या कॉलम हटाने होंगे। यह इस बात पर निर्भर करता है कि आप क्या कर रहे हैं, आप इनमें से किसी एक को चुन सकते हैं, और इसलिए pandas आपको दोनों विकल्प देता है। क्योंकि डेटा साइंस में, कॉलम आमतौर पर वेरिएबल्स को और पंक्तियाँ ऑब्ज़र्वेशन को दर्शाते हैं, आप अधिक संभावना रखते हैं कि डेटा की पंक्तियाँ हटाएँ; `dropna()` का डिफ़ॉल्ट सेटिंग यह है कि वह सभी पंक्तियाँ हटाएगा जिनमें कोई भी null मान हो:\n" + "आप `DataFrame` से एकल मान को हटा नहीं सकते, इसलिए आपको पूरी पंक्तियाँ या कॉलम हटाने होंगे। जो आप कर रहे हैं उसके आधार पर, आप इनमें से किसी एक को चुन सकते हैं, और इसलिए pandas आपको दोनों विकल्प देता है। क्योंकि डेटा विज्ञान में, कॉलम आमतौर पर चर का प्रतिनिधित्व करते हैं और पंक्तियाँ अवलोकन का, आप अधिक संभावना रखते हैं कि डेटा की पंक्तियाँ हटाएँ; `dropna()` के लिए डिफ़ॉल्ट सेटिंग यह है कि वह सभी पंक्तियाँ हटा देता है जिनमें कोई भी null मान होता है:\n" ] }, { @@ -1273,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "यदि आवश्यक हो, तो आप स्तंभों से NA मान हटा सकते हैं। ऐसा करने के लिए `axis=1` का उपयोग करें:\n" + "यदि आवश्यक हो, तो आप कॉलम से NA मानों को हटा सकते हैं। ऐसा करने के लिए `axis=1` का उपयोग करें:\n" ] }, { @@ -1352,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "ध्यान दें कि यह विशेष रूप से छोटे डेटा सेट में वह डेटा हटा सकता है जिसे आप रखना चाह सकते हैं। अगर आप केवल उन पंक्तियों या स्तंभों को हटाना चाहते हैं जिनमें कई या सभी मान शून्य (null) हैं, तो आप `dropna` में `how` और `thresh` पैरामीटर सेट कर सकते हैं।\n", + "ध्यान दें कि यह बहुत सारे डेटा को हटा सकता है जिसे आप रखना चाह सकते हैं, खासकर छोटे डेटा सेट में। अगर आप केवल उन पंक्तियों या स्तंभों को हटाना चाहते हैं जिनमें कई या सभी null मान हैं, तो आप `dropna` में `how` और `thresh` पैरामीटर सेट कर सकते हैं।\n", "\n", - "डिफ़ॉल्ट रूप से, `how='any'` होता है (यदि आप स्वयं जांचना चाहते हैं या देखना चाहते हैं कि इस विधि में अन्य कौन-कौन से पैरामीटर हैं, तो एक कोड सेल में `example4.dropna?` चलाएं)। आप वैकल्पिक रूप से `how='all'` निर्दिष्ट कर सकते हैं ताकि केवल उन पंक्तियों या स्तंभों को हटाया जाए जिनमें सभी मान शून्य (null) हैं। चलिए अगले अभ्यास में इसे क्रियान्वित करने के लिए हमारे उदाहरण `DataFrame` को विस्तारित करते हैं।\n" + "डिफ़ॉल्ट रूप से, `how='any'` होता है (यदि आप इसे स्वयं जांचना चाहते हैं या देखना चाहते हैं कि इस विधि में अन्य कौन-कौन से पैरामीटर हैं, तो एक कोड सेल में `example4.dropna?` चलाएं)। आप वैकल्पिक रूप से `how='all'` निर्दिष्ट कर सकते हैं ताकि केवल उन पंक्तियों या स्तंभों को हटाया जाए जिनमें सभी null मान हों। चलिए हमारे उदाहरण `DataFrame` को अगले अभ्यास में विस्तार से देखते हैं ताकि इसे क्रियान्वित होते हुए देख सकें।\n" ] }, { @@ -1446,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> मुख्य बातें: \n", - "1. केवल तभी null मानों को हटाना एक अच्छा विचार है जब डेटा सेट पर्याप्त बड़ा हो। \n", - "2. पूरी पंक्तियों या स्तंभों को हटाया जा सकता है यदि उनमें से अधिकांश डेटा गायब हो। \n", - "3. `DataFrame.dropna(axis=)` विधि null मानों को हटाने में मदद करती है। `axis` तर्क यह दर्शाता है कि पंक्तियों को हटाना है या स्तंभों को। \n", - "4. `how` तर्क का भी उपयोग किया जा सकता है। डिफ़ॉल्ट रूप से यह `any` पर सेट होता है। इसलिए, यह केवल उन पंक्तियों/स्तंभों को हटाता है जिनमें कोई भी null मान होता है। इसे `all` पर सेट किया जा सकता है ताकि यह निर्दिष्ट किया जा सके कि हम केवल उन पंक्तियों/स्तंभों को हटाएंगे जहां सभी मान null हैं। \n" + "> मुख्य बातें:\n", + "1. केवल तभी null मानों को हटाना अच्छा विचार है जब डेटा सेट पर्याप्त बड़ा हो।\n", + "2. पूरी पंक्तियाँ या स्तंभ हटाए जा सकते हैं यदि उनमें अधिकांश डेटा गायब हो।\n", + "3. `DataFrame.dropna(axis=)` विधि null मानों को हटाने में मदद करती है। `axis` तर्क यह दर्शाता है कि पंक्तियाँ हटाई जाएँगी या स्तंभ।\n", + "4. `how` तर्क का भी उपयोग किया जा सकता है। डिफ़ॉल्ट रूप से इसे `any` पर सेट किया गया है। इसलिए, यह केवल उन पंक्तियों/स्तंभों को हटाता है जिनमें कोई भी null मान हो। इसे `all` पर सेट किया जा सकता है ताकि केवल उन पंक्तियों/स्तंभों को हटाया जाए जहाँ सभी मान null हों।\n" ] }, { @@ -1458,7 +1468,9 @@ "metadata": { "id": "oXXSfQFHgRsF" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -1480,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "`thresh` पैरामीटर आपको अधिक सूक्ष्म नियंत्रण देता है: आप यह सेट करते हैं कि किसी पंक्ति या स्तंभ में *गैर-शून्य* मानों की संख्या कितनी होनी चाहिए ताकि उसे बनाए रखा जा सके:\n" + "`thresh` पैरामीटर आपको अधिक सूक्ष्म नियंत्रण देता है: आप यह निर्धारित करते हैं कि किसी पंक्ति या स्तंभ में *गैर-शून्य* मानों की संख्या कितनी होनी चाहिए ताकि उसे बनाए रखा जा सके:\n" ] }, { @@ -1554,7 +1566,9 @@ "metadata": { "id": "fmSFnzZegRsG" }, - "source": [] + "source": [ + "यहाँ, पहली और आखिरी पंक्ति को हटा दिया गया है, क्योंकि उनमें केवल दो गैर-शून्य मान हैं।\n" + ] }, { "cell_type": "markdown", @@ -1562,11 +1576,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### खाली मान भरना\n", + "### खाली मानों को भरना\n", "\n", - "कभी-कभी खाली मानों को ऐसे मानों से भरना समझदारी हो सकती है जो वैध हो सकते हैं। खाली मानों को भरने के लिए कुछ तकनीकें होती हैं। पहली तकनीक है डोमेन ज्ञान (जिस विषय पर डेटा सेट आधारित है उसका ज्ञान) का उपयोग करके किसी तरह से खाली मानों का अनुमान लगाना। \n", + "कभी-कभी यह समझदारी होती है कि गायब मानों को ऐसे मानों से भरा जाए जो वैध हो सकते हैं। खाली मानों को भरने के लिए कुछ तकनीकें हैं। पहली तकनीक है डोमेन ज्ञान (डेटासेट जिस विषय पर आधारित है उसका ज्ञान) का उपयोग करके किसी तरह से गायब मानों का अनुमान लगाना।\n", "\n", - "आप `isnull` का उपयोग करके इसे सीधे कर सकते हैं, लेकिन यह थकाऊ हो सकता है, खासकर जब आपके पास भरने के लिए बहुत सारे मान हों। चूंकि यह डेटा साइंस में एक सामान्य कार्य है, pandas `fillna` प्रदान करता है, जो `Series` या `DataFrame` की एक कॉपी लौटाता है, जिसमें खाली मानों को आपके द्वारा चुने गए मानों से बदल दिया जाता है। चलिए एक और उदाहरण `Series` बनाते हैं ताकि यह समझ सकें कि यह व्यावहारिक रूप से कैसे काम करता है।\n" + "आप `isnull` का उपयोग करके इसे सीधे कर सकते हैं, लेकिन यह थकाऊ हो सकता है, खासकर जब आपके पास भरने के लिए बहुत सारे मान हों। चूंकि यह डेटा विज्ञान में एक सामान्य कार्य है, pandas `fillna` प्रदान करता है, जो `Series` या `DataFrame` की एक कॉपी लौटाता है जिसमें गायब मानों को आपके द्वारा चुने गए मानों से बदल दिया गया है। चलिए एक और उदाहरण `Series` बनाते हैं ताकि देख सकें कि यह व्यवहार में कैसे काम करता है।\n" ] }, { @@ -1576,11 +1590,11 @@ }, "source": [ "### श्रेणीबद्ध डेटा (गैर-संख्या)\n", - "सबसे पहले, आइए गैर-संख्या डेटा पर विचार करें। डेटा सेट्स में, हमारे पास श्रेणीबद्ध डेटा वाले कॉलम होते हैं। जैसे लिंग, सत्य या असत्य आदि।\n", + "पहले हम गैर-संख्या डेटा पर विचार करते हैं। डेटा सेट्स में, हमारे पास श्रेणीबद्ध डेटा वाले कॉलम होते हैं। जैसे, लिंग, सत्य या असत्य आदि।\n", "\n", - "इनमें से अधिकांश मामलों में, हम गायब मानों को कॉलम के `mode` से बदलते हैं। मान लीजिए, हमारे पास 100 डेटा पॉइंट्स हैं और उनमें से 90 ने सत्य कहा है, 8 ने असत्य कहा है और 2 ने कुछ नहीं भरा है। तो, हम उन 2 को सत्य से भर सकते हैं, पूरे कॉलम को ध्यान में रखते हुए।\n", + "इनमें से अधिकांश मामलों में, हम गायब मानों को कॉलम के `mode` से बदलते हैं। मान लीजिए, हमारे पास 100 डेटा पॉइंट्स हैं, जिनमें से 90 ने सत्य कहा है, 8 ने असत्य कहा है और 2 ने कुछ नहीं भरा है। तो, हम उन 2 को सत्य से भर सकते हैं, पूरे कॉलम को ध्यान में रखते हुए।\n", "\n", - "फिर से, यहां हम डोमेन ज्ञान का उपयोग कर सकते हैं। आइए `mode` से भरने का एक उदाहरण देखें।\n" + "फिर से, यहां हम डोमेन ज्ञान का उपयोग कर सकते हैं। चलिए `mode` से भरने का एक उदाहरण देखते हैं।\n" ] }, { @@ -1685,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "अब, पहले मोड ढूंढते हैं इससे पहले कि `None` मान को मोड से भरें।\n" + ] }, { "cell_type": "code", @@ -1720,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "तो, हम None को True से बदल देंगे\n" + ] }, { "cell_type": "code", @@ -1829,7 +1847,9 @@ "metadata": { "id": "SktitLxxOR16" }, - "source": [] + "source": [ + "जैसा कि हम देख सकते हैं, null मान को बदल दिया गया है। यह कहने की आवश्यकता नहीं है कि हम `'True'` के स्थान पर कुछ भी लिख सकते थे और वह प्रतिस्थापित हो जाता।\n" + ] }, { "cell_type": "markdown", @@ -1838,16 +1858,16 @@ }, "source": [ "### संख्यात्मक डेटा\n", - "अब, संख्यात्मक डेटा की बात करते हैं। यहां, हमारे पास गायब मानों को भरने के दो सामान्य तरीके हैं:\n", + "अब, संख्यात्मक डेटा की बात करते हैं। यहां, गायब मानों को भरने के दो सामान्य तरीके हैं:\n", "\n", - "1. पंक्ति के माध्यिका (Median) से बदलें \n", - "2. पंक्ति के औसत (Mean) से बदलें \n", + "1. पंक्ति के माध्यिका (Median) से भरें \n", + "2. पंक्ति के औसत (Mean) से भरें \n", "\n", - "हम माध्यिका का उपयोग करते हैं, जब डेटा में बाहरी मान (Outliers) के साथ असंतुलन होता है। इसका कारण यह है कि माध्यिका बाहरी मानों के प्रति संवेदनशील नहीं होती है।\n", + "हम माध्यिका का उपयोग करते हैं, जब डेटा में असंतुलन और बाहरी मान (outliers) होते हैं। इसका कारण यह है कि माध्यिका बाहरी मानों के प्रति संवेदनशील नहीं होती है।\n", "\n", - "जब डेटा सामान्यीकृत होता है, तो हम औसत का उपयोग कर सकते हैं, क्योंकि उस स्थिति में औसत और माध्यिका लगभग समान होते हैं।\n", + "जब डेटा सामान्यीकृत (normalized) होता है, तो हम औसत का उपयोग कर सकते हैं, क्योंकि उस स्थिति में औसत और माध्यिका लगभग समान होते हैं।\n", "\n", - "सबसे पहले, आइए एक कॉलम लें जो सामान्य वितरण में हो और उसमें गायब मान को कॉलम के औसत से भरें।\n" + "पहले, आइए एक ऐसा कॉलम लें जो सामान्य वितरण (normally distributed) में हो और उसमें गायब मान को कॉलम के औसत से भरें।\n" ] }, { @@ -1987,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "औसत से भरना\n" + ] }, { "cell_type": "code", @@ -2086,7 +2108,9 @@ "metadata": { "id": "CwpVFCrPTC5z" }, - "source": [] + "source": [ + "जैसा कि हम देख सकते हैं, गायब मान को उसके औसत से बदल दिया गया है।\n" + ] }, { "cell_type": "markdown", @@ -2234,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "मध्यिका से भरना\n" + ] }, { "cell_type": "code", @@ -2334,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "जैसा कि हम देख सकते हैं, NaN मान को कॉलम के माध्यिका से बदल दिया गया है\n" + "जैसा कि हम देख सकते हैं, NaN मान को कॉलम के माध्यिका से बदल दिया गया है।\n" ] }, { @@ -2418,10 +2444,10 @@ }, "source": [ "> मुख्य बातें:\n", - "1. गायब मानों को तभी भरना चाहिए जब डेटा कम हो या गायब डेटा को भरने के लिए कोई रणनीति हो। \n", - "2. डोमेन ज्ञान का उपयोग करके गायब मानों को अनुमानित करके भरा जा सकता है। \n", - "3. श्रेणीबद्ध डेटा के लिए, आमतौर पर गायब मानों को कॉलम के मोड से प्रतिस्थापित किया जाता है। \n", - "4. संख्यात्मक डेटा के लिए, गायब मानों को आमतौर पर कॉलम के औसत (सामान्यीकृत डेटासेट के लिए) या माध्यिका से भरा जाता है। \n" + "1. गायब मानों को भरना तब किया जाना चाहिए जब डेटा कम हो या गायब डेटा को भरने की कोई रणनीति हो।\n", + "2. डोमेन ज्ञान का उपयोग करके गायब मानों को अनुमानित करके भरा जा सकता है।\n", + "3. श्रेणीबद्ध डेटा के लिए, आमतौर पर गायब मानों को कॉलम के मोड से प्रतिस्थापित किया जाता है।\n", + "4. संख्यात्मक डेटा के लिए, गायब मानों को आमतौर पर कॉलम के औसत (सामान्यीकृत डेटासेट के लिए) या माध्यिका से भरा जाता है।\n" ] }, { @@ -2429,7 +2455,9 @@ "metadata": { "id": "FI9MmqFJgRsH" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -2449,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "आप null मानों को **forward-fill** कर सकते हैं, जिसका अर्थ है अंतिम मान्य मान का उपयोग करके null को भरना:\n" + ] }, { "cell_type": "code", @@ -2489,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "आप अगले मान्य मान को पीछे की ओर प्रसारित करने के लिए **बैक-फिल** भी कर सकते हैं ताकि एक शून्य को भर सकें:\n" + "आप अगले मान्य मान को पीछे की ओर फैलाने के लिए **बैक-फिल** भी कर सकते हैं ताकि एक शून्य को भर सकें:\n" ] }, { @@ -2703,14 +2733,18 @@ "metadata": { "id": "ZeMc-I1EgRsI" }, - "source": [] + "source": [ + "ध्यान दें कि जब पिछले मान आगे भरने के लिए उपलब्ध नहीं होता है, तो शून्य मान बना रहता है।\n" + ] }, { "cell_type": "markdown", "metadata": { "id": "eeAoOU0RgRsJ" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -2733,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "आप `fillna` का उपयोग कैसे करते हैं, इसके बारे में रचनात्मक हो सकते हैं। उदाहरण के लिए, चलिए `example4` को फिर से देखते हैं, लेकिन इस बार चलिए `DataFrame` में सभी मानों के औसत से गायब मानों को भरते हैं:\n" + "आप `fillna` का उपयोग करने के तरीके के बारे में रचनात्मक हो सकते हैं। उदाहरण के लिए, चलिए फिर से `example4` को देखते हैं, लेकिन इस बार चलिए `DataFrame` में सभी मानों के औसत से गायब मानों को भरते हैं:\n" ] }, { @@ -2824,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "ध्यान दें कि कॉलम 3 अभी भी खाली है: डिफ़ॉल्ट दिशा पंक्ति-वार मान भरने की है।\n", + "ध्यान दें कि कॉलम 3 अभी भी खाली है: डिफ़ॉल्ट दिशा पंक्तियों के अनुसार मान भरने की है।\n", "\n", - "> **सारांश:** आपके डेटा सेट में गायब मानों को संभालने के कई तरीके हैं। आप जो विशेष रणनीति अपनाते हैं (उन्हें हटाना, बदलना, या यहां तक कि उन्हें कैसे बदलना है) वह उस डेटा की विशिष्टताओं पर निर्भर होनी चाहिए। जितना अधिक आप डेटा सेट्स को संभालेंगे और उनके साथ काम करेंगे, गायब मानों को संभालने की समझ उतनी ही बेहतर होगी।\n" + "> **मुख्य बात:** आपके डेटा सेट में गायब मानों को संभालने के कई तरीके हैं। आप जो विशेष रणनीति अपनाते हैं (उन्हें हटाना, बदलना, या यहां तक कि कैसे बदलना है) वह उस डेटा की विशेषताओं पर निर्भर होनी चाहिए। जैसे-जैसे आप अधिक डेटा सेट के साथ काम करेंगे और उनका विश्लेषण करेंगे, गायब मानों को संभालने का बेहतर तरीका समझ में आएगा।\n" ] }, { @@ -2837,7 +2871,7 @@ "source": [ "### श्रेणीबद्ध डेटा को एन्कोड करना\n", "\n", - "मशीन लर्निंग मॉडल केवल संख्याओं और किसी भी प्रकार के संख्यात्मक डेटा के साथ काम करते हैं। यह \"हाँ\" और \"नहीं\" के बीच का अंतर नहीं समझ पाएगा, लेकिन यह 0 और 1 के बीच का अंतर पहचान सकता है। इसलिए, गायब मानों को भरने के बाद, हमें श्रेणीबद्ध डेटा को किसी संख्यात्मक रूप में एन्कोड करना होगा ताकि मॉडल इसे समझ सके।\n", + "मशीन लर्निंग मॉडल केवल संख्याओं और किसी भी प्रकार के संख्यात्मक डेटा के साथ काम करते हैं। यह Yes और No के बीच का अंतर नहीं समझ पाएगा, लेकिन यह 0 और 1 के बीच का अंतर पहचान सकता है। इसलिए, गायब मानों को भरने के बाद, हमें श्रेणीबद्ध डेटा को किसी संख्यात्मक रूप में एन्कोड करना होगा ताकि मॉडल इसे समझ सके।\n", "\n", "एन्कोडिंग दो तरीकों से की जा सकती है। हम अगले भाग में इन तरीकों पर चर्चा करेंगे।\n" ] @@ -2850,7 +2884,7 @@ "source": [ "**लेबल एन्कोडिंग**\n", "\n", - "लेबल एन्कोडिंग का मतलब है कि प्रत्येक श्रेणी को एक संख्या में बदलना। उदाहरण के लिए, मान लीजिए हमारे पास एयरलाइन यात्रियों का एक डेटासेट है और उसमें एक कॉलम है जिसमें उनकी श्रेणी दी गई है, जैसे ['बिजनेस क्लास', 'इकोनॉमी क्लास', 'फर्स्ट क्लास']। अगर इस पर लेबल एन्कोडिंग की जाती है, तो इसे [0,1,2] में बदल दिया जाएगा। चलिए इसे कोड के माध्यम से एक उदाहरण के रूप में देखते हैं। चूंकि हम आगामी नोटबुक्स में `scikit-learn` सीखने वाले हैं, इसलिए हम इसे यहां उपयोग नहीं करेंगे।\n" + "लेबल एन्कोडिंग मूल रूप से प्रत्येक श्रेणी को एक संख्या में बदलने की प्रक्रिया है। उदाहरण के लिए, मान लीजिए हमारे पास एयरलाइन यात्रियों का एक डेटासेट है और उसमें एक कॉलम है जिसमें उनकी श्रेणी ['बिजनेस क्लास', 'इकोनॉमी क्लास', 'फर्स्ट क्लास'] दी गई है। यदि इस पर लेबल एन्कोडिंग की जाती है, तो इसे [0,1,2] में परिवर्तित किया जाएगा। आइए इसे कोड के माध्यम से एक उदाहरण के रूप में देखें। चूंकि हम आगामी नोटबुक्स में `scikit-learn` सीखने वाले हैं, इसलिए हम इसे यहां उपयोग नहीं करेंगे।\n" ] }, { @@ -2958,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "पहले कॉलम पर लेबल एन्कोडिंग करने के लिए, हमें पहले प्रत्येक वर्ग से एक संख्या तक का मैपिंग वर्णित करना होगा, उसके बाद प्रतिस्थापन करना होगा।\n" + "पहले कॉलम पर लेबल एन्कोडिंग करने के लिए, हमें पहले प्रत्येक वर्ग से एक संख्या तक का मैपिंग वर्णित करना होगा, उसके बाद उसे बदलना होगा।\n" ] }, { @@ -3060,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "जैसा कि हम देख सकते हैं, परिणाम वही है जिसकी हमें उम्मीद थी। तो, लेबल एन्कोडिंग का उपयोग कब किया जाता है? लेबल एन्कोडिंग का उपयोग निम्नलिखित में से किसी एक या दोनों स्थितियों में किया जाता है: \n", - "1. जब श्रेणियों की संख्या अधिक हो \n", - "2. जब श्रेणियां क्रम में हों। \n" + "जैसा कि हम देख सकते हैं, आउटपुट वही है जो हमने सोचा था कि होगा। तो, लेबल एन्कोडिंग का उपयोग कब किया जाता है? लेबल एन्कोडिंग का उपयोग निम्नलिखित में से किसी एक या दोनों मामलों में किया जाता है:\n", + "1. जब श्रेणियों की संख्या अधिक हो\n", + "2. जब श्रेणियां क्रम में हों।\n" ] }, { @@ -3073,7 +3107,7 @@ "source": [ "**वन हॉट एनकोडिंग**\n", "\n", - "वन हॉट एनकोडिंग एक और प्रकार का एनकोडिंग है। इस प्रकार के एनकोडिंग में, कॉलम की प्रत्येक श्रेणी को एक अलग कॉलम के रूप में जोड़ा जाता है और प्रत्येक डेटा पॉइंट को 0 या 1 मिलता है, इस आधार पर कि उसमें वह श्रेणी है या नहीं। तो, यदि n अलग-अलग श्रेणियां हैं, तो n कॉलम डेटा फ्रेम में जोड़े जाएंगे।\n", + "एनकोडिंग का एक और प्रकार वन हॉट एनकोडिंग है। इस प्रकार की एनकोडिंग में, कॉलम की प्रत्येक श्रेणी को एक अलग कॉलम के रूप में जोड़ा जाता है और प्रत्येक डेटा पॉइंट को 0 या 1 मिलता है, इस आधार पर कि उसमें वह श्रेणी है या नहीं। तो, यदि n अलग-अलग श्रेणियां हैं, तो n कॉलम डेटा फ्रेम में जोड़े जाएंगे।\n", "\n", "उदाहरण के लिए, चलिए वही हवाई जहाज वर्ग का उदाहरण लेते हैं। श्रेणियां थीं: ['बिजनेस क्लास', 'इकोनॉमी क्लास', 'फर्स्ट क्लास']। तो, यदि हम वन हॉट एनकोडिंग करते हैं, तो निम्नलिखित तीन कॉलम डेटासेट में जोड़े जाएंगे: ['class_business class', 'class_economy class', 'class_first class']।\n" ] @@ -3183,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "आइए पहले कॉलम पर वन हॉट एनकोडिंग करें\n" + "आइए हम पहली स्तंभ पर वन हॉट एनकोडिंग करें।\n" ] }, { @@ -3308,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "प्रत्येक हॉट एन्कोडेड कॉलम में 0 या 1 होता है, जो यह निर्दिष्ट करता है कि उस डेटा पॉइंट के लिए वह श्रेणी मौजूद है या नहीं।\n" + "प्रत्येक वन-हॉट एन्कोडेड कॉलम में 0 या 1 होता है, जो यह निर्दिष्ट करता है कि उस डेटा पॉइंट के लिए वह श्रेणी मौजूद है या नहीं।\n" ] }, { @@ -3317,7 +3351,7 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "हम वन-हॉट एन्कोडिंग का उपयोग कब करते हैं? वन-हॉट एन्कोडिंग का उपयोग निम्नलिखित में से एक या दोनों स्थितियों में किया जाता है:\n", + "हम वन हॉट एनकोडिंग का उपयोग कब करते हैं? वन हॉट एनकोडिंग का उपयोग निम्नलिखित में से किसी एक या दोनों स्थितियों में किया जाता है:\n", "\n", "1. जब श्रेणियों की संख्या और डेटा सेट का आकार छोटा हो।\n", "2. जब श्रेणियों का कोई विशेष क्रम न हो।\n" @@ -3342,9 +3376,9 @@ "source": [ "## डुप्लिकेट डेटा हटाना\n", "\n", - "> **सीखने का उद्देश्य:** इस उपखंड के अंत तक, आप DataFrames से डुप्लिकेट मानों की पहचान करने और उन्हें हटाने में सहज हो जाएंगे।\n", + "> **लक्ष्य:** इस उपखंड के अंत तक, आप DataFrames से डुप्लिकेट मानों की पहचान करने और उन्हें हटाने में सहज हो जाएंगे।\n", "\n", - "गायब डेटा के अलावा, वास्तविक दुनिया के डेटासेट्स में आपको अक्सर डुप्लिकेट डेटा भी मिलेगा। सौभाग्य से, pandas डुप्लिकेट प्रविष्टियों का पता लगाने और उन्हें हटाने का एक आसान तरीका प्रदान करता है।\n" + "गायब डेटा के अलावा, वास्तविक दुनिया के डेटा सेट में अक्सर डुप्लिकेट डेटा का सामना करना पड़ता है। सौभाग्य से, pandas डुप्लिकेट प्रविष्टियों का पता लगाने और उन्हें हटाने का एक आसान तरीका प्रदान करता है।\n" ] }, { @@ -3353,9 +3387,9 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### डुप्लिकेट पहचानना: `duplicated`\n", + "### डुप्लीकेट पहचानना: `duplicated`\n", "\n", - "आप pandas में `duplicated` मेथड का उपयोग करके आसानी से डुप्लिकेट मानों को पहचान सकते हैं। यह एक बूलियन मास्क लौटाता है, जो यह दर्शाता है कि `DataFrame` में कोई प्रविष्टि पहले की किसी प्रविष्टि की डुप्लिकेट है या नहीं। इसे क्रियान्वित करने के लिए, आइए एक और उदाहरण `DataFrame` बनाते हैं।\n" + "आप pandas में `duplicated` मेथड का उपयोग करके आसानी से डुप्लीकेट मानों को पहचान सकते हैं। यह एक Boolean मास्क लौटाता है जो यह दर्शाता है कि `DataFrame` में कोई प्रविष्टि पहले की प्रविष्टि का डुप्लीकेट है या नहीं। आइए इसे क्रियान्वित करने के लिए एक और उदाहरण `DataFrame` बनाते हैं।\n" ] }, { @@ -3568,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "`duplicated` और `drop_duplicates` दोनों डिफ़ॉल्ट रूप से सभी कॉलम पर विचार करते हैं, लेकिन आप निर्दिष्ट कर सकते हैं कि वे आपके `DataFrame` में केवल कॉलम के एक उपसमुच्चय की जांच करें:\n" + "`duplicated` और `drop_duplicates` डिफ़ॉल्ट रूप से सभी कॉलमों पर विचार करते हैं लेकिन आप निर्दिष्ट कर सकते हैं कि वे आपके `DataFrame` में केवल कॉलमों के एक उपसमूह की जांच करें:\n" ] }, { @@ -3644,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **निष्कर्ष:** डुप्लिकेट डेटा को हटाना लगभग हर डेटा-साइंस प्रोजेक्ट का एक आवश्यक हिस्सा है। डुप्लिकेट डेटा आपके विश्लेषण के परिणामों को बदल सकता है और आपको गलत परिणाम दे सकता है!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## वास्तविक दुनिया में डेटा गुणवत्ता जांच\n", + "\n", + "> **लक्ष्य:** इस अनुभाग के अंत तक, आप सामान्य वास्तविक दुनिया के डेटा गुणवत्ता मुद्दों का पता लगाने और उन्हें सुधारने में सहज महसूस करेंगे, जिनमें असंगत श्रेणी मान, असामान्य संख्यात्मक मान (आउटलायर), और हल्के बदलावों के साथ डुप्लिकेट संस्थाएं शामिल हैं।\n", + "\n", + "हालांकि गायब मान और सटीक डुप्लिकेट आम समस्याएं हैं, वास्तविक दुनिया के डेटा सेट में अक्सर अधिक सूक्ष्म समस्याएं होती हैं:\n", + "\n", + "1. **असंगत श्रेणी मान**: एक ही श्रेणी का अलग-अलग तरीके से लिखा जाना (जैसे, \"USA\", \"U.S.A\", \"United States\")\n", + "2. **असामान्य संख्यात्मक मान**: अत्यधिक आउटलायर जो डेटा प्रविष्टि त्रुटियों को दर्शाते हैं (जैसे, उम्र = 999)\n", + "3. **निकट-डुप्लिकेट पंक्तियां**: रिकॉर्ड जो हल्के बदलावों के साथ एक ही इकाई का प्रतिनिधित्व करते हैं\n", + "\n", + "आइए इन समस्याओं का पता लगाने और उन्हें संभालने की तकनीकों का अन्वेषण करें।\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### एक नमूना \"गंदा\" डेटा सेट बनाना\n", + "\n", + "सबसे पहले, चलिए एक नमूना डेटा सेट बनाते हैं जिसमें वे समस्याएं शामिल हों जो हम आमतौर पर वास्तविक दुनिया के डेटा में सामना करते हैं:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. असंगत श्रेणीबद्ध मानों का पता लगाना\n", + "\n", + "ध्यान दें कि `country` कॉलम में एक ही देशों के लिए कई प्रतिनिधित्व हैं। आइए इन असंगतताओं की पहचान करें:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### श्रेणीबद्ध मानों को मानकीकृत करना\n", + "\n", + "हम इन मानों को मानकीकृत करने के लिए एक मैपिंग बना सकते हैं। एक सरल तरीका है कि उन्हें छोटे अक्षरों में बदलें और एक मैपिंग डिक्शनरी बनाएं:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**विकल्प: फजी मैचिंग का उपयोग करना**\n", + "\n", + "अधिक जटिल मामलों के लिए, हम `rapidfuzz` लाइब्रेरी का उपयोग करके फजी स्ट्रिंग मैचिंग का उपयोग कर सकते हैं ताकि समान स्ट्रिंग्स को स्वचालित रूप से पहचान सकें:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. असामान्य संख्यात्मक मान (आउटलायर) का पता लगाना\n", + "\n", + "`age` कॉलम को देखते हुए, हमारे पास कुछ संदिग्ध मान हैं जैसे 199 और -5। चलिए इन आउटलायर का पता लगाने के लिए सांख्यिकीय विधियों का उपयोग करते हैं।\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### IQR (इंटरक्वारटाइल रेंज) विधि का उपयोग करना\n", + "\n", + "IQR विधि एक मजबूत सांख्यिकीय तकनीक है जो बाहरी मानों का पता लगाने के लिए उपयोग की जाती है और यह चरम मानों के प्रति कम संवेदनशील होती है:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Z-स्कोर विधि का उपयोग करना\n", + "\n", + "Z-स्कोर विधि औसत से मानक विचलन के आधार पर बाहरी मानों की पहचान करती है:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### आउटलायर्स का प्रबंधन\n", + "\n", + "एक बार पहचानने के बाद, आउटलायर्स को कई तरीकों से संभाला जा सकता है:\n", + "1. **हटाना**: आउटलायर्स वाली पंक्तियों को हटा दें (यदि वे त्रुटियां हैं)\n", + "2. **सीमित करना**: सीमा मानों से बदलें\n", + "3. **NaN से बदलें**: इसे गायब डेटा मानें और इम्प्यूटेशन तकनीकों का उपयोग करें\n", + "4. **रखें**: यदि वे वैध चरम मान हैं\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. निकट-डुप्लिकेट पंक्तियों का पता लगाना\n", + "\n", + "ध्यान दें कि हमारे डेटा सेट में \"John Smith\" के लिए कई प्रविष्टियाँ हैं जिनमें थोड़े अलग मान हैं। चलिए नाम की समानता के आधार पर संभावित डुप्लिकेट की पहचान करते हैं।\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### फजी मैचिंग के साथ निकट-डुप्लिकेट्स ढूंढना\n", + "\n", + "अधिक उन्नत डुप्लिकेट पहचान के लिए, हम समान नामों को ढूंढने के लिए फजी मैचिंग का उपयोग कर सकते हैं:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### डुप्लीकेट्स का प्रबंधन\n", + "\n", + "पहचानने के बाद, आपको तय करना होगा कि डुप्लीकेट्स को कैसे संभालना है:\n", + "1. **पहली घटना रखें**: `drop_duplicates(keep='first')` का उपयोग करें\n", + "2. **अंतिम घटना रखें**: `drop_duplicates(keep='last')` का उपयोग करें\n", + "3. **जानकारी को समेकित करें**: डुप्लीकेट पंक्तियों से जानकारी को मिलाएं\n", + "4. **मैन्युअल समीक्षा**: मानव समीक्षा के लिए चिह्नित करें\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### सारांश: संपूर्ण डेटा सफाई पाइपलाइन\n", + "\n", + "आइए इसे एक व्यापक सफाई पाइपलाइन में एकत्रित करें:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 चुनौती अभ्यास\n", + "\n", + "अब आपकी बारी है! नीचे एक नई पंक्ति दी गई है जिसमें कई गुणवत्ता संबंधी समस्याएं हैं। क्या आप:\n", + "\n", + "1. इस पंक्ति में सभी समस्याओं की पहचान कर सकते हैं\n", + "2. प्रत्येक समस्या को ठीक करने के लिए कोड लिख सकते हैं\n", + "3. साफ की गई पंक्ति को डेटा सेट में जोड़ सकते हैं\n", + "\n", + "यहां समस्याग्रस्त डेटा है:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### मुख्य बातें\n", + "\n", + "1. **असंगत श्रेणियां** वास्तविक दुनिया के डेटा में आम होती हैं। हमेशा अद्वितीय मानों की जांच करें और उन्हें मैपिंग या फजी मैचिंग का उपयोग करके मानकीकृत करें।\n", + "\n", + "2. **आउटलायर्स** आपके विश्लेषण को काफी प्रभावित कर सकते हैं। इन्हें पहचानने के लिए डोमेन ज्ञान के साथ सांख्यिकीय विधियों (IQR, Z-score) का उपयोग करें।\n", + "\n", + "3. **निकट-डुप्लिकेट्स** को पहचानना सटीक डुप्लिकेट्स की तुलना में कठिन होता है। इन्हें पहचानने के लिए फजी मैचिंग और डेटा को सामान्यीकृत करना (लोअरकेस करना, व्हाइटस्पेस हटाना) पर विचार करें।\n", + "\n", + "4. **डेटा सफाई एक पुनरावृत्त प्रक्रिया है।** आपको कई तकनीकों को लागू करने और परिणामों की समीक्षा करने की आवश्यकता हो सकती है, इससे पहले कि आप अपने साफ किए गए डेटा सेट को अंतिम रूप दें।\n", + "\n", + "5. **अपने निर्णयों का दस्तावेजीकरण करें।** आपने कौन-कौन से सफाई कदम उठाए और क्यों, इसका रिकॉर्ड रखें, क्योंकि यह पुनरुत्पादन और पारदर्शिता के लिए महत्वपूर्ण है।\n", + "\n", + "> **सर्वोत्तम अभ्यास:** हमेशा अपने मूल \"गंदे\" डेटा की एक प्रति रखें। कभी भी अपने स्रोत डेटा फाइलों को अधिलेखित न करें - साफ किए गए संस्करण बनाएं और उन्हें स्पष्ट नामकरण जैसे `data_cleaned.csv` के साथ सहेजें।\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**अस्वीकरण**: \nयह दस्तावेज़ AI अनुवाद सेवा [Co-op Translator](https://github.com/Azure/co-op-translator) का उपयोग करके अनुवादित किया गया है। जबकि हम सटीकता सुनिश्चित करने का प्रयास करते हैं, कृपया ध्यान दें कि स्वचालित अनुवाद में त्रुटियां या अशुद्धियां हो सकती हैं। मूल भाषा में उपलब्ध मूल दस्तावेज़ को प्रामाणिक स्रोत माना जाना चाहिए। महत्वपूर्ण जानकारी के लिए, पेशेवर मानव अनुवाद की सिफारिश की जाती है। इस अनुवाद के उपयोग से उत्पन्न किसी भी गलतफहमी या गलत व्याख्या के लिए हम जिम्मेदार नहीं हैं।\n" + "\n---\n\n**अस्वीकरण**: \nयह दस्तावेज़ AI अनुवाद सेवा [Co-op Translator](https://github.com/Azure/co-op-translator) का उपयोग करके अनुवादित किया गया है। जबकि हम सटीकता सुनिश्चित करने का प्रयास करते हैं, कृपया ध्यान दें कि स्वचालित अनुवाद में त्रुटियां या अशुद्धियां हो सकती हैं। मूल भाषा में उपलब्ध मूल दस्तावेज़ को आधिकारिक स्रोत माना जाना चाहिए। महत्वपूर्ण जानकारी के लिए, पेशेवर मानव अनुवाद की सिफारिश की जाती है। इस अनुवाद के उपयोग से उत्पन्न किसी भी गलतफहमी या गलत व्याख्या के लिए हम जिम्मेदार नहीं हैं।\n" ] } ], @@ -3678,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:51:47+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:35:33+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "hi" } diff --git a/translations/hk/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/hk/2-Working-With-Data/08-data-preparation/notebook.ipynb index 77c0c6e6..162064e1 100644 --- a/translations/hk/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/hk/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -12,11 +12,11 @@ "\n", "## 探索 `DataFrame` 資訊\n", "\n", - "> **學習目標:** 完成本小節後,您應該能夠熟悉如何查找存儲在 pandas DataFrame 中的數據的一般資訊。\n", + "> **學習目標:** 完成本小節後,您應該能夠熟練地查找存儲在 pandas DataFrame 中的數據的一般資訊。\n", "\n", - "當您將數據載入到 pandas 中時,數據通常會以 `DataFrame` 的形式存在。然而,如果您的 `DataFrame` 中的數據集有 60,000 行和 400 列,您該如何開始了解自己正在處理的內容呢?幸運的是,pandas 提供了一些方便的工具,可以快速查看 `DataFrame` 的整體資訊,以及前幾行和後幾行的數據。\n", + "當您將數據載入 pandas 後,數據通常會以 `DataFrame` 的形式存在。然而,如果您的 `DataFrame` 中的數據集有 60,000 行和 400 列,您該如何開始了解自己正在處理的內容呢?幸運的是,pandas 提供了一些方便的工具,可以快速查看 `DataFrame` 的整體資訊,以及前幾行和後幾行的內容。\n", "\n", - "為了探索這些功能,我們將導入 Python 的 scikit-learn 庫,並使用一個每位數據科學家都看過數百次的經典數據集:英國生物學家 Ronald Fisher 在他1936年的論文《多重測量在分類問題中的應用》中使用的 *Iris* 數據集:\n" + "為了探索這些功能,我們將導入 Python 的 scikit-learn 庫,並使用一個每位數據科學家都看過數百次的經典數據集:英國生物學家 Ronald Fisher 在其 1936 年的論文《The use of multiple measurements in taxonomic problems》中使用的 *Iris* 數據集:\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "我們已將 Iris 數據集加載到變數 `iris_df` 中。在深入分析數據之前,了解我們擁有的數據點數量以及整個數據集的大小是很有價值的。這有助於我們了解正在處理的數據量。\n" + "我們已經將 Iris 數據集載入到變數 `iris_df` 中。在深入分析數據之前,了解我們擁有的數據點數量以及整個數據集的大小是很有價值的。查看我們正在處理的數據量是很有幫助的。\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "所以,我們正在處理150行和4列的數據。每一行代表一個數據點,而每一列則代表與數據框相關的一個特徵。基本上,就是150個數據點,每個數據點包含4個特徵。\n", + "我們正在處理 150 行和 4 列的數據。每一行代表一個數據點,每一列代表與數據框相關的一個特徵。基本上,這裡有 150 個數據點,每個數據點包含 4 個特徵。\n", "\n", - "`shape` 在這裡是數據框的一個屬性,而不是一個函數,所以它的結尾並沒有一對括號。\n" + "`shape` 在這裡是數據框的一個屬性,而不是一個函數,所以它的後面沒有一對括號。\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "現在讓我們看看這個數據框的四個欄位。每個欄位到底代表什麼?`columns` 屬性會告訴我們數據框中欄位的名稱。\n" + "現在讓我們深入了解這個數據框的四個欄位。每個欄位具體代表什麼呢?`columns` 屬性將提供數據框中欄位的名稱。\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "正如我們所見,有四(4)列。`columns` 屬性告訴我們列的名稱,基本上沒有其他內容。當我們想要識別數據集包含的特徵時,這個屬性就顯得重要了。\n" + "正如我們所見,有四(4)列。`columns`屬性告訴我們列的名稱,基本上沒有其他內容。當我們想要識別數據集包含的特徵時,這個屬性就顯得重要了。\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "透過 `shape` 屬性提供的數據量以及 `columns` 屬性提供的特徵或欄位名稱,可以讓我們了解一些關於數據集的資訊。現在,我們希望更深入地探索這個數據集。`DataFrame.info()` 函數非常有用。\n" + "透過 `shape` 屬性提供的數據量以及透過 `columns` 屬性提供的特徵或列名稱,可以讓我們對數據集有初步了解。現在,我們希望更深入地探索數據集。`DataFrame.info()` 函數在這方面非常有用。\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "從這裡,我們可以作出以下幾點觀察: \n", - "1. 每列的數據類型:在這個數據集中,所有數據都以64位浮點數的形式存儲。 \n", - "2. 非空值的數量:處理空值是數據準備中的一個重要步驟,稍後會在筆記本中處理。 \n" + "從這裡,我們可以作出以下幾點觀察:\n", + "1. 每列的數據類型:在這個數據集中,所有數據都以64位浮點數形式存儲。\n", + "2. 非空值的數量:處理空值是數據準備中的重要步驟,稍後會在筆記本中處理。\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "假設我們的數據集包含大量數值數據。可以對每個欄位單獨進行單變量統計計算,例如平均值、中位數、四分位數等。`DataFrame.describe()` 函數為我們提供了數據集中數值欄位的統計摘要。\n" + "假設我們的數據集中有大量的數值數據。像平均值、中位數、四分位數等單變量統計計算可以分別對每一列進行。`DataFrame.describe()` 函數可以為我們提供數據集中數值列的統計摘要。\n" ] }, { @@ -334,7 +334,7 @@ "### `DataFrame.head`\n", "透過以上所有的函數和屬性,我們已經對數據集有了一個高層次的概覽。我們知道數據集中有多少個數據點,有多少個特徵,每個特徵的數據類型,以及每個特徵中非空值的數量。\n", "\n", - "現在是時候看看數據本身了。讓我們看看我們的 `DataFrame` 的前幾行(前幾個數據點)是什麼樣子:\n" + "現在是時候看看數據本身了。讓我們來看看我們的 `DataFrame` 的前幾行(前幾個數據點)是什麼樣子:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "作為這裡的輸出,我們可以看到數據集的五(5)個條目。如果我們查看左側的索引,我們會發現這是前五行。\n" + "在此輸出中,我們可以看到數據集的五(5)個條目。如果查看左側的索引,我們會發現這是前五行。\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### 練習:\n", "\n", - "從上述範例可以看出,預設情況下,`DataFrame.head` 會返回 `DataFrame` 的前五行。在下面的程式碼區塊中,你能找到一種方法來顯示多於五行的內容嗎?\n" + "從上面的例子可以看出,預設情況下,`DataFrame.head` 會返回 `DataFrame` 的前五行。在下面的程式碼單元中,你能找到方法顯示超過五行嗎?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "另一種查看數據的方法是從結尾開始(而不是從開頭)。`DataFrame.head` 的相反方法是 `DataFrame.tail`,它會返回 `DataFrame` 的最後五行:\n" + "另一種查看數據的方法是從結尾開始(而不是從開頭)。`DataFrame.head` 的反面是 `DataFrame.tail`,它會返回 `DataFrame` 的最後五行:\n" ] }, { @@ -586,7 +586,7 @@ "\n", "上面展示的所有函數和屬性,通過代碼示例的幫助,讓我們能夠快速了解數據的概況。\n", "\n", - "> **重點提示:** 即使僅僅查看 `DataFrame` 中的元數據或前幾個和後幾個值,也能讓你立即了解所處理數據的大小、形狀和內容。\n" + "> **重點提示:** 即使僅僅查看 `DataFrame` 的元數據或其中的前幾個和最後幾個值,也能讓你立即對所處理數據的大小、形狀和內容有一個初步的了解。\n" ] }, { @@ -598,15 +598,15 @@ "### 缺失數據\n", "讓我們深入了解缺失數據。缺失數據是指某些欄位中沒有存儲任何值。\n", "\n", - "舉個例子:假設某人對自己的體重非常在意,因此在調查中沒有填寫體重欄位。那麼,該人的體重值就會是缺失的。\n", + "舉個例子:假設某人對自己的體重非常在意,因此在調查中不填寫體重欄位。那麼,該人的體重值就會是缺失的。\n", "\n", "在現實世界的數據集中,缺失值是非常常見的。\n", "\n", "**Pandas 如何處理缺失數據**\n", "\n", - "Pandas 有兩種方式來處理缺失值。第一種方式你可能在之前的章節中已經見過:`NaN`,即「非數值」(Not a Number)。這實際上是一個特殊值,是 IEEE 浮點規範的一部分,僅用於表示缺失的浮點值。\n", + "Pandas 有兩種方式來處理缺失值。第一種方式你可能在之前的章節中已經見過:`NaN`,即「非數字」(Not a Number)。這實際上是一個特殊值,是 IEEE 浮點規範的一部分,僅用於表示缺失的浮點值。\n", "\n", - "對於非浮點類型的缺失值,Pandas 使用 Python 的 `None` 對象。雖然遇到兩種不同的值來表示同樣的事情可能會讓人感到困惑,但這種設計選擇有其合理的編程原因。在實際應用中,這種方式使得 Pandas 能夠在絕大多數情況下提供良好的平衡。不過,`None` 和 `NaN` 都有一些限制,使用時需要注意它們的適用範圍和使用方式。\n" + "對於非浮點類型的缺失值,Pandas 使用 Python 的 `None` 對象。雖然遇到兩種不同的值來表示同樣的事情可能會讓人感到困惑,但這種設計選擇有其合理的編程原因。實際上,這樣的設計使得 Pandas 能夠在絕大多數情況下提供良好的平衡。不過,無論是 `None` 還是 `NaN`,它們都帶有一些限制,這些限制需要注意,特別是在使用它們時的方式上。\n" ] }, { @@ -615,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`:非浮點類型的缺失數據\n", - "由於 `None` 是來自 Python 的,因此它無法用於數據類型不是 `'object'` 的 NumPy 和 pandas 陣列。請記住,NumPy 陣列(以及 pandas 中的數據結構)只能包含一種類型的數據。這正是它們在大規模數據和計算工作中具有強大功能的原因,但同時也限制了它們的靈活性。這類陣列必須向“最低公分母”進行上轉型,也就是能夠涵蓋陣列中所有內容的數據類型。如果陣列中包含 `None`,這意味著你正在處理 Python 對象。\n", + "### `None`:非浮點型的缺失數據\n", + "由於 `None` 是 Python 的一部分,因此它不能用於數據類型不是 `'object'` 的 NumPy 和 pandas 陣列。請記住,NumPy 陣列(以及 pandas 中的數據結構)只能包含一種數據類型。這正是它們在大規模數據和計算工作中展現強大能力的原因,但同時也限制了它們的靈活性。這類陣列必須向“最低共同分母”進行類型提升,即能夠涵蓋陣列中所有內容的數據類型。當陣列中包含 `None` 時,意味著您正在處理 Python 對象。\n", "\n", - "以下是一個示例陣列(注意它的 `dtype`)來展示這一點:\n" + "以下示例陣列可以幫助您理解這一點(注意它的 `dtype`):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "上轉數據類型的現實情況帶來了兩個副作用。首先,操作將在解釋執行的 Python 代碼層面進行,而不是在編譯的 NumPy 代碼層面進行。本質上,這意味著任何涉及包含 `None` 的 `Series` 或 `DataFrame` 的操作都會變得較慢。雖然你可能不會注意到這種性能影響,但對於大型數據集來說,這可能會成為一個問題。\n", + "數據類型向上轉型的現實帶來了兩個副作用。首先,操作將在解釋型的 Python 代碼層面執行,而不是編譯型的 NumPy 代碼層面。基本上,這意味著任何涉及包含 `None` 的 `Series` 或 `DataFrame` 的操作都會變得較慢。雖然你可能不會注意到這種性能下降,但對於大型數據集來說,這可能會成為一個問題。\n", "\n", - "第二個副作用源於第一個副作用。由於 `None` 本質上將 `Series` 或 `DataFrame` 拉回到原生 Python 的世界,因此對包含 `None` 值的數組使用 NumPy/pandas 的聚合函數(例如 `sum()` 或 `min()`)通常會產生錯誤:\n" + "第二個副作用源於第一個副作用。由於 `None` 本質上將 `Series` 或 `DataFrame` 拉回到原生 Python 的世界,因此在包含 ``None`` 值的數組上使用像 `sum()` 或 `min()` 這樣的 NumPy/pandas 聚合操作通常會產生錯誤:\n" ] }, { @@ -709,7 +709,7 @@ "source": [ "### `NaN`:缺失的浮點值\n", "\n", - "與 `None` 不同,NumPy(因此也包括 pandas)支援使用 `NaN` 來進行快速的向量化操作和 ufuncs。壞消息是,任何對 `NaN` 進行的算術運算,結果都會是 `NaN`。例如:\n" + "與 `None` 不同,NumPy(因此也包括 pandas)支援使用 `NaN` 來進行快速的向量化操作和 ufuncs。壞消息是,任何涉及 `NaN` 的算術運算結果都會是 `NaN`。例如:\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "好消息:在包含 `NaN` 的數組上運行的聚合不會出現錯誤。壞消息:結果並非一律有用:\n" + "好消息:在包含 `NaN` 的數組上運行的聚合不會出現錯誤。壞消息:結果並不一律有用:\n" ] }, { @@ -830,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "請記住:`NaN` 只適用於缺失的浮點值;整數、字符串或布爾值並沒有 `NaN` 的等效。\n" + ] }, { "cell_type": "markdown", @@ -840,7 +842,7 @@ "source": [ "### `NaN` 和 `None`:pandas 中的空值\n", "\n", - "雖然 `NaN` 和 `None` 的行為可能有些不同,但 pandas 仍然能夠將它們互換處理。為了更清楚地了解,請看以下一個整數的 `Series`:\n" + "儘管 `NaN` 和 `None` 的行為可能略有不同,但 pandas 已設計成可以互換處理它們。為了更清楚地了解,請考慮一個整數的 `Series`:\n" ] }, { @@ -904,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "在將資料類型向上轉型以建立 `Series` 和 `DataFrame` 的資料一致性時,pandas 會自動在 `None` 和 `NaN` 之間切換缺失值。由於這種設計特性,將 `None` 和 `NaN` 視為 pandas 中兩種不同形式的「空值」會更容易理解。事實上,pandas 中一些處理缺失值的核心方法名稱也反映了這個概念:\n", + "在將數據類型向上轉型以建立 `Series` 和 `DataFrame` 的數據一致性過程中,pandas 會自動在缺失值之間切換 `None` 和 `NaN`。由於這種設計特性,將 `None` 和 `NaN` 視為 pandas 中兩種不同形式的「空值」是很有幫助的。事實上,pandas 中一些處理缺失值的核心方法名稱也反映了這一點:\n", "\n", - "- `isnull()`: 生成一個布林遮罩,標示出缺失值的位置\n", - "- `notnull()`: 與 `isnull()` 相反\n", - "- `dropna()`: 返回一個已過濾掉缺失值的資料版本\n", - "- `fillna()`: 返回一個已填補或補全缺失值的資料副本\n", + "- `isnull()`:生成一個布爾掩碼,用於指示缺失值\n", + "- `notnull()`:與 `isnull()` 相反\n", + "- `dropna()`:返回過濾後的數據版本\n", + "- `fillna()`:返回填充或估算缺失值後的數據副本\n", "\n", - "這些方法非常重要,熟練掌握它們對於處理缺失值至關重要,因此我們將逐一深入探討這些方法。\n" + "這些方法非常重要,掌握並熟悉它們是必不可少的,因此我們將逐一深入探討這些方法。\n" ] }, { @@ -922,8 +924,8 @@ "source": [ "### 檢測空值\n", "\n", - "既然我們已經了解缺失值的重要性,在處理它們之前,我們需要先在數據集中檢測它們。 \n", - "`isnull()` 和 `notnull()` 是檢測空值的主要方法。這兩個方法都會對數據返回布林掩碼。\n" + "既然我們已經了解了缺失值的重要性,在處理它們之前,我們需要在數據集中檢測它們。 \n", + "`isnull()` 和 `notnull()` 是檢測空值的主要方法。這兩個方法都會返回布爾掩碼,覆蓋你的數據。\n" ] }, { @@ -976,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "仔細看看輸出內容。有沒有任何部分讓你感到意外?雖然 `0` 是一個算術上的「空值」,但它仍然是一個完全有效的整數,而 pandas 也將其視為如此。至於 `''`,情況稍微微妙一點。雖然我們在第 1 節中使用它來表示一個空字串值,但對 pandas 而言,它仍然是一個字串物件,而不是空值的表示。\n", + "仔細看看輸出結果,有沒有令你感到驚訝的地方?雖然 `0` 是一個算術上的空值,但它仍然是一個完全有效的整數,pandas 也將其視為整數。至於 `''` 則稍微微妙一些。雖然我們在第 1 節中使用它來表示空字串值,但它本質上仍然是一個字串物件,而不是 pandas 所認為的空值。\n", "\n", - "現在,讓我們換個角度,將這些方法以更接近實際使用的方式來應用。你可以直接將布林遮罩用作 ``Series`` 或 ``DataFrame`` 的索引,這在處理孤立的缺失值(或存在值)時非常有用。\n", + "現在,讓我們換個角度,使用這些方法更接近實際應用的方式。你可以直接使用布林遮罩作為 ``Series`` 或 ``DataFrame`` 的索引,這在處理孤立的缺失值(或存在值)時非常有用。\n", "\n", - "如果我們想要計算缺失值的總數,只需對 `isnull()` 方法生成的遮罩進行一次加總即可。\n" + "如果我們想要計算缺失值的總數,只需對 `isnull()` 方法生成的遮罩進行求和即可。\n" ] }, { @@ -1038,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**關鍵重點**:當你在 DataFrame 中使用 `isnull()` 和 `notnull()` 方法時,它們會產生相似的結果:顯示結果及其索引,這將在你處理數據時對你有極大的幫助。\n" + "**主要重點**:當在資料框中使用 `isnull()` 和 `notnull()` 方法時,兩者會產生相似的結果:它們會顯示結果以及這些結果的索引,這將在您處理數據時提供極大的幫助。\n" ] }, { @@ -1049,11 +1051,11 @@ "source": [ "### 處理缺失數據\n", "\n", - "> **學習目標:** 完成本小節後,你應該了解如何以及何時替換或移除 DataFrame 中的空值。\n", + "> **學習目標:** 完成本小節後,您應該了解如何以及何時替換或移除 DataFrame 中的空值。\n", "\n", "機器學習模型無法直接處理缺失數據。因此,在將數據傳入模型之前,我們需要先處理這些缺失值。\n", "\n", - "處理缺失數據的方法涉及微妙的取捨,可能會影響你的最終分析結果以及實際應用的效果。\n", + "如何處理缺失數據涉及微妙的取捨,可能會影響您的最終分析結果以及實際應用的效果。\n", "\n", "主要有兩種處理缺失數據的方法:\n", "\n", @@ -1071,11 +1073,11 @@ "source": [ "### 刪除空值\n", "\n", - "我們傳遞給模型的數據量會直接影響其性能。刪除空值意味著我們減少了數據點的數量,從而縮小了數據集的規模。因此,當數據集相當大的時候,建議刪除包含空值的行。\n", + "我們傳遞給模型的數據量會直接影響其性能。刪除空值意味著減少數據點的數量,從而減少數據集的大小。因此,當數據集相當大時,建議刪除包含空值的行。\n", "\n", - "另一種情況可能是某一行或某一列有大量缺失值。在這種情況下,它們可能會被刪除,因為該行/列的大部分數據都缺失,對我們的分析幫助不大。\n", + "另一種情況可能是某一行或列有大量缺失值。在這種情況下,可以刪除它們,因為該行/列的大部分數據都缺失,對分析的價值不大。\n", "\n", - "除了識別缺失值之外,pandas 還提供了一種方便的方法來從 `Series` 和 `DataFrame` 中移除空值。為了實際了解這一點,我們可以回到 `example3`。`DataFrame.dropna()` 函數可以幫助刪除包含空值的行。\n" + "除了識別缺失值之外,pandas 還提供了一種方便的方法來從 `Series` 和 `DataFrame` 中移除空值。為了更好地理解這一點,我們可以回到 `example3`。`DataFrame.dropna()` 函數可以幫助刪除包含空值的行。\n" ] }, { @@ -1114,7 +1116,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "請注意,這應該看起來像你的輸出 `example3[example3.notnull()]`。這裡的不同之處在於,`dropna` 不僅僅是基於遮罩值進行索引,而是從 `Series` `example3` 中移除了那些缺失值。\n", + "請注意,這應該看起來像您從 `example3[example3.notnull()]` 的輸出。這裡的不同之處在於,`dropna` 不僅僅是基於遮罩值進行索引,而是已經從 `Series` `example3` 中移除了那些缺失值。\n", "\n", "由於 DataFrame 是二維的,因此它提供了更多刪除數據的選項。\n" ] @@ -1206,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(你有留意到 pandas 將其中兩列數據提升為浮點數以容納 `NaN` 嗎?)\n", + "(你是否注意到 pandas 將其中兩列提升為浮點型,以容納 `NaN` 值?)\n", "\n", - "你無法從 `DataFrame` 中刪除單個值,因此你必須刪除整行或整列。根據你的需求,你可能會選擇其中一種方式,因此 pandas 提供了兩種選項。由於在數據科學中,列通常代表變量,而行代表觀測值,因此你更有可能刪除數據行;`dropna()` 的預設設定是刪除所有包含任何空值的行:\n" + "你無法從 `DataFrame` 中刪除單個值,因此必須刪除整行或整列。根據你的需求,你可能需要選擇其中一種方式,因此 pandas 提供了兩種選項。在數據科學中,列通常代表變量,行則代表觀察值,因此你更可能刪除數據的行;`dropna()` 的預設設定是刪除所有包含任何空值的行:\n" ] }, { @@ -1281,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "如果有需要,你可以從列中刪除 NA 值。使用 `axis=1` 來執行:\n" + "如果需要,您可以從列中刪除 NA 值。使用 `axis=1` 來完成:\n" ] }, { @@ -1360,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "請注意,這可能會刪除許多您可能想保留的數據,特別是在較小的數據集中。如果您只想刪除包含多個甚至全部空值的行或列,該怎麼辦?您可以在 `dropna` 中使用 `how` 和 `thresh` 參數來指定這些設置。\n", + "請注意,這可能會刪除許多您可能希望保留的數據,特別是在較小的數據集中。如果您只想刪除包含多個甚至所有空值的行或列該怎麼辦?您可以在 `dropna` 中使用 `how` 和 `thresh` 參數來指定這些設置。\n", "\n", - "預設情況下,`how='any'`(如果您想自行檢查或查看該方法的其他參數,可以在程式碼單元中執行 `example4.dropna?`)。您也可以選擇指定 `how='all'`,這樣只會刪除包含所有空值的行或列。我們來擴展我們的範例 `DataFrame`,在下一個練習中看看這是如何運作的。\n" + "預設情況下,`how='any'`(如果您想自行檢查或查看該方法的其他參數,可以在代碼單元中運行 `example4.dropna?`)。您也可以選擇指定 `how='all'`,以便僅刪除包含所有空值的行或列。讓我們擴展示例 `DataFrame`,在下一個練習中看看這是如何運作的。\n" ] }, { @@ -1456,9 +1458,9 @@ "source": [ "> 關鍵要點:\n", "1. 只有在數據集足夠大的情況下,刪除空值才是明智的選擇。\n", - "2. 如果整行或整列的大部分數據都缺失,可以考慮刪除。\n", + "2. 如果整行或整列的大部分數據都缺失,可以刪除這些行或列。\n", "3. `DataFrame.dropna(axis=)` 方法可用於刪除空值。`axis` 參數表示是刪除行還是列。\n", - "4. `how` 參數也可以使用。默認情況下設置為 `any`,因此它只會刪除包含任何空值的行或列。可以將其設置為 `all`,以指定僅刪除所有值均為空的行或列。\n" + "4. `how` 參數也可以使用。默認情況下設置為 `any`,因此它只刪除包含任何空值的行或列。可以設置為 `all`,以指定僅刪除所有值均為空的行或列。\n" ] }, { @@ -1467,7 +1469,7 @@ "id": "oXXSfQFHgRsF" }, "source": [ - "### 運動:\n" + "### 運動:\n" ] }, { @@ -1490,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "`thresh` 參數為您提供更細緻的控制:您可以設定一行或一列需要擁有的*非空*值的數量,才能被保留:\n" + "`thresh` 參數提供更細緻的控制:您設定一行或一列需要擁有的*非空*值的數量,以便保留該行或列:\n" ] }, { @@ -1576,9 +1578,9 @@ "source": [ "### 填充空值\n", "\n", - "有時候填補缺失值為可能有效的值是合理的。有幾種方法可以用來填充空值。第一種方法是使用領域知識(即對數據集所基於的主題的了解)來大致估算缺失值。\n", + "有時候,用可能有效的值來填充缺失值是合理的。有幾種方法可以填充空值。第一種方法是使用領域知識(即數據集所基於主題的知識)來大致估算缺失值。\n", "\n", - "你可以使用 `isnull` 直接進行操作,但這可能會很繁瑣,特別是當你需要填充大量值時。由於這在數據科學中是一個非常常見的任務,pandas 提供了 `fillna` 方法,它會返回一個 `Series` 或 `DataFrame` 的副本,並將缺失值替換為你選擇的值。讓我們創建另一個例子 `Series`,來看看這在實際操作中是如何工作的。\n" + "你可以使用 `isnull` 直接進行操作,但這可能會很繁瑣,特別是當你需要填充大量值時。由於這是數據科學中非常常見的任務,pandas 提供了 `fillna` 方法,它會返回一個 `Series` 或 `DataFrame` 的副本,並將缺失值替換為你選擇的值。讓我們創建另一個示例 `Series`,來看看這在實際操作中的效果。\n" ] }, { @@ -1587,12 +1589,12 @@ "id": "CE8S7louLezV" }, "source": [ - "### 類別型數據(非數字)\n", - "首先,我們來看看非數字型數據。在數據集裡,我們有一些包含類別型數據的欄位,例如性別、True 或 False 等。\n", + "### 類別型數據(非數字型)\n", + "首先讓我們來看看非數字型數據。在數據集中,我們有一些包含類別型數據的欄位,例如性別、True 或 False 等。\n", "\n", - "在大多數情況下,我們會用該欄位的 `眾數` 來替換缺失值。假設我們有 100 個數據點,其中 90 個選擇 True,8 個選擇 False,還有 2 個未填寫。那麼,我們可以用 True 填補這 2 個缺失值,基於整個欄位的情況。\n", + "在大多數情況下,我們會用該欄位的 `眾數` 來替換缺失值。假設我們有 100 個數據點,其中 90 個選擇 True,8 個選擇 False,還有 2 個未填寫。那麼,我們可以將這 2 個未填寫的值替換為 True,基於整個欄位的情況。\n", "\n", - "此外,我們也可以在這裡運用領域知識。讓我們來看一個用眾數填補的例子。\n" + "此外,我們也可以在這裡使用領域知識。讓我們來看一個用眾數填充的例子。\n" ] }, { @@ -1697,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "現在,讓我們先找到眾數,再用眾數填充 `None` 值。\n" + ] }, { "cell_type": "code", @@ -1732,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "所以,我們將把 None 替換為 True\n" + ] }, { "cell_type": "code", @@ -1842,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "正如我們所見,空值已被替換。毋庸置疑,我們本可以在 `'True'` 的位置寫任何內容,並且它都會被替換。\n" + "正如我們所見,空值已被替換。毋庸置疑,我們本可以在此處寫任何內容或 `'True'`,它都會被替代。\n" ] }, { @@ -1852,16 +1858,16 @@ }, "source": [ "### 數值數據\n", - "現在來談談數值數據。在這裡,我們有兩種常見的方法來替換缺失值:\n", + "現在來談談數值數據。這裡有兩種常見的方法來替換缺失值:\n", "\n", - "1. 用該行的中位數替換 \n", - "2. 用該行的平均值替換 \n", + "1. 用行的中位數替換\n", + "2. 用行的平均值替換\n", "\n", - "當數據存在偏態且有異常值時,我們會選擇用中位數替換。這是因為中位數對異常值具有穩健性。\n", + "如果數據偏斜且有異常值,我們會選擇用中位數替換。因為中位數對異常值具有穩健性。\n", "\n", "當數據已經正規化時,我們可以使用平均值,因為在這種情況下,平均值和中位數會非常接近。\n", "\n", - "首先,我們選擇一個呈正態分佈的列,並用該列的平均值填補缺失值。\n" + "首先,我們選擇一個正態分佈的列,並用該列的平均值填充缺失值。\n" ] }, { @@ -2001,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "用平均值填充\n" + ] }, { "cell_type": "code", @@ -2101,7 +2109,7 @@ "id": "CwpVFCrPTC5z" }, "source": [ - "正如我們所見,缺失值已被其平均值取代。\n" + "正如我們所見,缺失值已被其平均值替換。\n" ] }, { @@ -2250,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "以中位數填充\n" + ] }, { "cell_type": "code", @@ -2350,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "正如我們所見,NaN 值已被該列的中位數取代\n" + "如我們所見,NaN 值已被該列的中位數取代\n" ] }, { @@ -2433,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> 關鍵重點:\n", - "1. 當數據較少或有策略填補缺失數據時,應進行缺失值填補。\n", + "> 主要重點:\n", + "1. 填補缺失值應在數據較少或有策略填補缺失值的情況下進行。\n", "2. 可以利用領域知識來估算並填補缺失值。\n", - "3. 對於分類數據,缺失值通常以該列的眾數替代。\n", - "4. 對於數值數據,缺失值通常以平均值(針對已正規化的數據集)或該列的中位數填補。\n" + "3. 對於分類數據,通常使用該列的眾數來替代缺失值。\n", + "4. 對於數值型數據,缺失值通常使用該列的平均值(針對已正規化的數據集)或中位數來填補。\n" ] }, { @@ -2509,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "您還可以**向後填充**,將下一個有效值向後傳播以填充空值:\n" + "您亦可**回填**以向後傳播下一個有效值來填補空值:\n" ] }, { @@ -2551,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "正如你可能猜到的,這與 DataFrame 的操作方式相同,但你也可以指定一個 `axis` 來填充空值:\n" + "正如你可能猜到的,這與 DataFrames 的操作方式相同,但你也可以指定一個 `axis` 來填充空值:\n" ] }, { @@ -2724,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "請注意,當前向填充時沒有可用的先前值,空值將保持不變。\n" + "請注意,當前一個值不可用於向前填充時,空值將保持不變。\n" ] }, { @@ -2757,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "您可以創意地使用 `fillna`。例如,我們再看看 `example4`,但這次我們用 `DataFrame` 中所有值的平均值來填補缺失值:\n" + "您可以創意地使用 `fillna`。例如,我們再次查看 `example4`,但這次我們將缺失值填充為 `DataFrame` 中所有值的平均值:\n" ] }, { @@ -2850,7 +2860,7 @@ "source": [ "注意,第 3 欄仍然是空的:預設方向是按行填充值。\n", "\n", - "> **重點提示:** 處理數據集中缺失值的方法有很多。你採用的具體策略(移除、替換,甚至替換的方式)應該根據該數據的具體情況來決定。隨著你處理和接觸更多數據集,你將更能掌握如何應對缺失值的技巧。\n" + "> **重點提示:** 處理數據集中缺失值的方法有很多。你採用的具體策略(刪除、替換,甚至替換的方式)應該根據該數據的具體情況來決定。隨著你處理和接觸更多數據集,你將更能掌握如何應對缺失值的技巧。\n" ] }, { @@ -2861,7 +2871,7 @@ "source": [ "### 編碼分類數據\n", "\n", - "機器學習模型只能處理數字和任何形式的數值數據。它無法分辨 Yes 和 No,但能夠區分 0 和 1。因此,在填補缺失值之後,我們需要將分類數據編碼成某種數值形式,讓模型能夠理解。\n", + "機器學習模型只能處理數字和任何形式的數值數據。它無法分辨「是」和「否」,但能區分 0 和 1。因此,在填補缺失值之後,我們需要將分類數據編碼成某種數字形式,讓模型能夠理解。\n", "\n", "編碼可以通過兩種方式完成。我們接下來會討論這些方法。\n" ] @@ -2874,7 +2884,7 @@ "source": [ "**標籤編碼**\n", "\n", - "標籤編碼基本上是將每個類別轉換為一個數字。例如,假設我們有一個航空乘客的數據集,其中有一列包含以下類別:['商務艙', '經濟艙', '頭等艙']。如果對這些類別進行標籤編碼,則會被轉換為 [0,1,2]。讓我們通過程式碼來看一個例子。由於我們會在接下來的筆記本中學習 `scikit-learn`,所以這裡不會使用它。\n" + "標籤編碼基本上是將每個類別轉換為一個數字。例如,假設我們有一個航空乘客的數據集,其中有一列包含他們的艙位類別,類別包括 ['商務艙', '經濟艙', '頭等艙']。如果對這些類別進行標籤編碼,則會被轉換為 [0,1,2]。讓我們通過代碼示例來看看。由於我們會在接下來的筆記本中學習 `scikit-learn`,所以這裡不會使用它。\n" ] }, { @@ -2982,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "要對第一列進行標籤編碼,我們必須先描述每個類別到數字的映射,然後再進行替換\n" + "要對第一列進行標籤編碼,我們首先需要描述每個類別到數字的映射,然後再進行替換\n" ] }, { @@ -3084,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "正如我們所見,輸出結果與我們預期的一致。那麼,我們什麼時候應該使用標籤編碼呢?標籤編碼適用於以下其中一種或兩種情況:\n", - "1. 當分類數量很多時\n", - "2. 當分類具有順序性時\n" + "正如我們所見,輸出結果與我們預期的一致。那麼,我們什麼時候使用標籤編碼呢?標籤編碼通常在以下情況之一或兩者中使用:\n", + "1. 當類別數量很大時\n", + "2. 當類別具有順序性時。\n" ] }, { @@ -3095,11 +3105,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**獨熱編碼(One Hot Encoding)**\n", + "**獨熱編碼**\n", "\n", - "另一種編碼方式是獨熱編碼。在這種編碼方式中,每個欄位的類別會被新增為一個獨立的欄位,而每個數據點會根據是否包含該類別被賦予 0 或 1。因此,如果有 n 個不同的類別,數據框架中將會新增 n 個欄位。\n", + "另一種編碼方式是獨熱編碼。在這種編碼方式中,每個欄位的類別都會被新增為一個獨立的欄位,而每個數據點會根據是否包含該類別而被賦予 0 或 1 的值。因此,如果有 n 個不同的類別,則會在資料框中新增 n 個欄位。\n", "\n", - "例如,我們以飛機艙等的例子來說。類別包括:['商務艙', '經濟艙', '頭等艙']。那麼,如果我們執行獨熱編碼,數據集中將會新增以下三個欄位:['class_business class', 'class_economy class', 'class_first class']。\n" + "例如,讓我們以同樣的飛機艙等例子來說。類別包括:['商務艙', '經濟艙', '頭等艙']。如果我們進行獨熱編碼,以下三個欄位將被新增到數據集中:['class_business class', 'class_economy class', 'class_first class']。\n" ] }, { @@ -3332,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "每個獨熱編碼列包含 0 或 1,指定該數據點是否存在該類別。\n" + "每個獨熱編碼的列包含 0 或 1,指定該數據點是否存在該類別。\n" ] }, { @@ -3341,7 +3351,7 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "什麼時候使用獨熱編碼?獨熱編碼通常在以下其中一種或兩種情況下使用:\n", + "我們何時使用獨熱編碼?獨熱編碼通常在以下其中一種或兩種情況下使用:\n", "\n", "1. 當分類數量和數據集的規模較小時。\n", "2. 當分類沒有特定的順序時。\n" @@ -3353,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> 關鍵重點:\n", - "1. 編碼的目的是將非數值數據轉換為數值數據。\n", - "2. 編碼主要分為兩種類型:標籤編碼和獨熱編碼,兩者可根據數據集的需求進行選擇和應用。\n" + "> 主要重點:\n", + "1. 編碼是將非數值數據轉換為數值數據的過程。\n", + "2. 編碼分為兩種類型:標籤編碼和獨熱編碼,可根據數據集的需求進行選擇。\n" ] }, { @@ -3366,9 +3376,9 @@ "source": [ "## 移除重複數據\n", "\n", - "> **學習目標:** 完成本小節後,你應該能夠熟練地識別並移除 DataFrame 中的重複值。\n", + "> **學習目標:** 完成本小節後,您應該能夠熟練識別並移除 DataFrame 中的重複值。\n", "\n", - "除了缺失數據外,你在處理真實世界的數據集時,經常會遇到重複的數據。幸運的是,pandas 提供了一個簡便的方法來檢測和移除重複的條目。\n" + "除了缺失數據外,您在現實世界的數據集中經常會遇到重複的數據。幸運的是,pandas 提供了一個簡便的方法來檢測和移除重複的條目。\n" ] }, { @@ -3377,9 +3387,9 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### 識別重複項目:`duplicated`\n", + "### 識別重複值:`duplicated`\n", "\n", - "你可以使用 pandas 的 `duplicated` 方法輕鬆找出重複的值。該方法會返回一個布林遮罩,指示 `DataFrame` 中某個條目是否是之前條目的重複項。讓我們建立另一個範例 `DataFrame` 來看看這個方法的運作方式。\n" + "你可以使用 pandas 的 `duplicated` 方法輕鬆找出重複值。該方法會返回一個布林遮罩,指示 `DataFrame` 中某個條目是否是之前條目的重複值。我們來創建另一個範例 `DataFrame`,看看這個方法的實際應用。\n" ] }, { @@ -3508,8 +3518,8 @@ "id": "0eDRJD4SgRsK" }, "source": [ - "### 刪除重複值:`drop_duplicates`\n", - "`drop_duplicates` 會返回一份數據的副本,其中所有 `duplicated` 值均為 `False`:\n" + "### 刪除重複項:`drop_duplicates`\n", + "`drop_duplicates` 會返回一份數據副本,其中所有 `duplicated` 值均為 `False`:\n" ] }, { @@ -3668,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **重點:** 移除重複數據是幾乎每個數據科學項目中不可或缺的一部分。重複數據可能會改變分析結果,並導致不準確的結論!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 真實世界數據質量檢查\n", + "\n", + "> **學習目標:** 在本節結束時,你應該能夠熟練地檢測和修正常見的真實世界數據質量問題,包括不一致的分類值、異常的數值(離群值)以及帶有變化的重複實體。\n", + "\n", + "雖然缺失值和完全重複的數據是常見問題,但真實世界的數據集往往還包含更微妙的問題:\n", + "\n", + "1. **不一致的分類值**:同一分類以不同方式拼寫(例如:\"USA\"、\"U.S.A\"、\"United States\")\n", + "2. **異常的數值**:極端的離群值,可能表明數據輸入錯誤(例如,年齡 = 999)\n", + "3. **近似重複的行**:表示同一實體但有輕微變化的記錄\n", + "\n", + "接下來,我們將探討檢測和處理這些問題的技術。\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 建立一個範例「髒」數據集\n", + "\n", + "首先,讓我們建立一個範例數據集,其中包含我們在真實世界數據中常見的問題類型:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. 檢測不一致的分類值\n", + "\n", + "注意到 `country` 欄位中,同一個國家有多種表示方式。讓我們找出這些不一致之處:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 標準化分類值\n", + "\n", + "我們可以建立一個映射來標準化這些值。一個簡單的方法是將值轉換為小寫,並建立一個映射字典:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**替代方法:使用模糊匹配**\n", + "\n", + "對於更複雜的情況,我們可以使用 `rapidfuzz` 庫進行模糊字符串匹配,自動檢測相似的字符串:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. 檢測異常數值(離群值)\n", + "\n", + "查看 `age` 欄位時,我們發現一些可疑的數值,例如 199 和 -5。讓我們使用統計方法來檢測這些離群值。\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 使用 IQR(四分位距)方法\n", + "\n", + "IQR 方法是一種穩健的統計技術,用於檢測異常值,對極端值的敏感度較低:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 使用 Z 分數方法\n", + "\n", + "Z 分數方法根據與平均值的標準差來識別異常值:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 處理異常值\n", + "\n", + "一旦檢測到異常值,可以用以下幾種方式處理:\n", + "1. **移除**:刪除包含異常值的行(如果它們是錯誤)\n", + "2. **限制**:用邊界值替換\n", + "3. **替換為 NaN**:視為缺失數據並使用填補技術\n", + "4. **保留**:如果它們是合法的極端值\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. 檢測近似重複的行\n", + "\n", + "注意,我們的數據集中有多個 \"John Smith\" 的條目,且數值略有不同。我們來基於名字相似度識別潛在的重複項。\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 使用模糊匹配尋找近似重複項\n", + "\n", + "為了進行更高級的重複檢測,我們可以使用模糊匹配來尋找相似的名稱:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 處理重複項目\n", + "\n", + "一旦識別出來後,你需要決定如何處理重複項目:\n", + "1. **保留第一次出現**:使用 `drop_duplicates(keep='first')`\n", + "2. **保留最後一次出現**:使用 `drop_duplicates(keep='last')`\n", + "3. **聚合信息**:合併重複行的資訊\n", + "4. **人工審查**:標記以供人工審查\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 摘要:完整的數據清理流程\n", + "\n", + "讓我們將所有內容整合成一個全面的清理流程:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 挑戰練習\n", + "\n", + "現在輪到你了!以下是一行包含多個質量問題的新數據。你能否:\n", + "\n", + "1. 找出這行數據中的所有問題\n", + "2. 編寫程式碼來清理每個問題\n", + "3. 將清理後的數據添加到數據集\n", + "\n", + "以下是有問題的數據:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 關鍵要點\n", + "\n", + "1. **分類不一致**在真實世界的數據中很常見。務必檢查唯一值,並使用映射或模糊匹配來標準化它們。\n", + "\n", + "2. **異常值**可能會對分析產生重大影響。結合領域知識和統計方法(如 IQR、Z-score)來檢測它們。\n", + "\n", + "3. **近似重複項**比完全重複項更難檢測。考慮使用模糊匹配並對數據進行標準化(如轉小寫、去除空格)來識別它們。\n", + "\n", + "4. **數據清理是迭代的過程**。可能需要應用多種技術並審查結果,才能最終完成清理後的數據集。\n", + "\n", + "5. **記錄你的決策**。追蹤你所採用的清理步驟及其原因,這對於可重現性和透明度非常重要。\n", + "\n", + "> **最佳實踐:**務必保留一份原始的“髒”數據副本。切勿覆蓋你的源數據文件——創建清理版本並使用清晰的命名規則,例如 `data_cleaned.csv`。\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**免責聲明**: \n本文件已使用人工智能翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。原始語言的文件應被視為權威來源。對於重要信息,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋概不負責。\n" + "\n---\n\n**免責聲明**: \n本文件已使用人工智能翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要信息,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋概不負責。\n" ] } ], @@ -3702,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T08:25:17+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:22:23+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "hk" } diff --git a/translations/hr/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/hr/2-Working-With-Data/08-data-preparation/notebook.ipynb index 7de900e5..9b416315 100644 --- a/translations/hr/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/hr/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# Priprema podataka\n", "\n", - "[Izvorni bilježnički zapis iz *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Izvorni bilježnik preuzet iz *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## Istraživanje informacija o `DataFrame`\n", "\n", "> **Cilj učenja:** Na kraju ovog pododjeljka trebali biste se osjećati ugodno u pronalaženju općih informacija o podacima pohranjenim u pandas DataFrameovima.\n", "\n", - "Kada učitate svoje podatke u pandas, vrlo je vjerojatno da će biti u obliku `DataFrame`. Međutim, ako vaš `DataFrame` sadrži 60.000 redaka i 400 stupaca, kako uopće započeti s razumijevanjem s čime radite? Srećom, pandas nudi nekoliko praktičnih alata za brzo pregledavanje općih informacija o `DataFrame`, uz mogućnost pregleda prvih i posljednjih nekoliko redaka.\n", + "Kada učitate svoje podatke u pandas, vrlo je vjerojatno da će biti u obliku `DataFrame`. Međutim, ako vaš `DataFrame` sadrži 60.000 redaka i 400 stupaca, kako uopće početi dobivati osjećaj za ono s čime radite? Srećom, pandas pruža nekoliko praktičnih alata za brzo pregledavanje općih informacija o `DataFrameu`, uz mogućnost pregleda prvih nekoliko i posljednjih nekoliko redaka.\n", "\n", - "Kako bismo istražili ovu funkcionalnost, uvest ćemo Python biblioteku scikit-learn i koristiti jedan od najpoznatijih skupova podataka koji je svaki podatkovni znanstvenik vidio stotine puta: skup podataka britanskog biologa Ronalda Fishera *Iris* korišten u njegovom radu iz 1936. godine \"The use of multiple measurements in taxonomic problems\":\n" + "Kako bismo istražili ovu funkcionalnost, uvest ćemo Python biblioteku scikit-learn i koristiti jedan poznati skup podataka koji je svaki data scientist vidio stotine puta: skup podataka britanskog biologa Ronalda Fishera *Iris* korišten u njegovom radu iz 1936. godine \"The use of multiple measurements in taxonomic problems\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Učitali smo Iris Dataset u varijablu `iris_df`. Prije nego što se detaljnije posvetimo podacima, bilo bi korisno znati broj podatkovnih točaka koje imamo i ukupnu veličinu skupa podataka. Korisno je pogledati obujam podataka s kojima radimo.\n" + "Učitali smo Iris Dataset u varijablu `iris_df`. Prije nego što se detaljnije pozabavimo podacima, bilo bi korisno znati broj podatkovnih točaka koje imamo i ukupnu veličinu skupa podataka. Korisno je pogledati obujam podataka s kojima radimo.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Dakle, imamo 150 redaka i 4 stupca podataka. Svaki redak predstavlja jednu podatkovnu točku, a svaki stupac predstavlja jednu značajku povezanu s okvirom podataka. Dakle, u osnovi, postoji 150 podatkovnih točaka, od kojih svaka sadrži 4 značajke.\n", + "Dakle, imamo 150 redaka i 4 stupca podataka. Svaki redak predstavlja jednu podatkovnu točku, a svaki stupac predstavlja jednu značajku povezanu s podatkovnim okvirom. Dakle, u osnovi, postoji 150 podatkovnih točaka koje sadrže po 4 značajke.\n", "\n", - "`shape` je ovdje atribut okvira podataka, a ne funkcija, zbog čega ne završava s parom zagrada.\n" + "`shape` je ovdje atribut podatkovnog okvira, a ne funkcija, zbog čega ne završava s parom zagrada.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Sada ćemo se posvetiti 4 stupca podataka. Što točno svaki od njih predstavlja? Atribut `columns` će nam dati imena stupaca u dataframeu.\n" + "Sada ćemo se posvetiti 4 stupca podataka. Što točno svaki od njih predstavlja? Atribut `columns` će nam dati nazive stupaca u dataframeu.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Kao što možemo vidjeti, postoje četiri (4) stupca. Atribut `columns` nam govori imena stupaca i zapravo ništa drugo. Ovaj atribut postaje važan kada želimo identificirati značajke koje skup podataka sadrži.\n" + "Kao što možemo vidjeti, postoje četiri(4) stupca. Atribut `columns` nam govori imena stupaca i zapravo ništa drugo. Ovaj atribut postaje važan kada želimo identificirati značajke koje skup podataka sadrži.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Količina podataka (dana atributom `shape`) i nazivi značajki ili stupaca (dani atributom `columns`) govore nam nešto o skupu podataka. Sada bismo željeli detaljnije istražiti skup podataka. Funkcija `DataFrame.info()` vrlo je korisna za to.\n" + "Količina podataka (dana atributom `shape`) i nazivi značajki ili stupaca (dani atributom `columns`) daju nam određene informacije o skupu podataka. Sada bismo željeli detaljnije istražiti skup podataka. Funkcija `DataFrame.info()` vrlo je korisna za to.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Odavde možemo uočiti nekoliko stvari: \n", - "1. Tip podataka za svaki stupac: U ovom skupu podataka, svi podaci su pohranjeni kao 64-bitni brojevi s pomičnim zarezom. \n", - "2. Broj vrijednosti koje nisu null: Rješavanje null vrijednosti važan je korak u pripremi podataka. Time ćemo se pozabaviti kasnije u bilježnici. \n" + "Odavde možemo uočiti nekoliko stvari:\n", + "1. Tip podataka za svaki stupac: U ovom skupu podataka svi su podaci pohranjeni kao 64-bitni brojevi s pomičnim zarezom.\n", + "2. Broj vrijednosti koje nisu null: Rješavanje null vrijednosti važan je korak u pripremi podataka. Time ćemo se pozabaviti kasnije u bilježnici.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Recimo da imamo puno numeričkih podataka u našem skupu podataka. Jednostavne statističke izračune poput srednje vrijednosti, medijana, kvartila itd. možemo napraviti za svaki stupac zasebno. Funkcija `DataFrame.describe()` pruža nam statistički sažetak numeričkih stupaca skupa podataka.\n" + "Recimo da imamo puno numeričkih podataka u našem skupu podataka. Jednostavne statističke kalkulacije poput srednje vrijednosti, medijana, kvartila itd. mogu se izračunati za svaki stupac pojedinačno. Funkcija `DataFrame.describe()` pruža nam statistički sažetak numeričkih stupaca skupa podataka.\n" ] }, { @@ -332,7 +332,7 @@ }, "source": [ "### `DataFrame.head`\n", - "Uz sve gore navedene funkcije i atribute, dobili smo pregled na visokoj razini skupa podataka. Znamo koliko ima podataka, koliko ima značajki, koji je tip podataka svake značajke i koliko svaka značajka ima vrijednosti koje nisu null.\n", + "Uz sve gore navedene funkcije i atribute, dobili smo pregled na visokoj razini skupa podataka. Znamo koliko ima podataka, koliko ima značajki, koji je tip podataka svake značajke i broj vrijednosti koje nisu null za svaku značajku.\n", "\n", "Sada je vrijeme da pogledamo same podatke. Pogledajmo kako izgledaju prvih nekoliko redaka (prvih nekoliko točaka podataka) našeg `DataFrame`:\n" ] @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Kao što vidimo u izlazu, ovdje imamo pet (5) unosa skupa podataka. Ako pogledamo indeks s lijeve strane, otkrivamo da su to prvih pet redaka.\n" + "Kao što vidimo u izlazu, prikazano je pet (5) unosa iz skupa podataka. Ako pogledamo indeks s lijeve strane, otkrivamo da su to prvih pet redaka.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Vježba:\n", "\n", - "Iz gornjeg primjera jasno je da `DataFrame.head` prema zadanim postavkama vraća prvih pet redaka `DataFramea`. Možete li u donjoj ćeliji koda pronaći način za prikaz više od pet redaka?\n" + "Iz gornjeg primjera jasno je da `DataFrame.head` prema zadanim postavkama vraća prvih pet redaka `DataFramea`. Možete li u donjoj ćeliji koda smisliti način za prikaz više od pet redaka?\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "U praksi je korisno moći lako pregledati prvih nekoliko redaka ili posljednjih nekoliko redaka `DataFramea`, posebno kada tražite odstupanja u uređenim skupovima podataka.\n", + "U praksi je korisno moći lako pregledati prvih nekoliko redaka ili posljednjih nekoliko redaka `DataFrame`-a, osobito kada tražite odstupanja u uređenim skupovima podataka.\n", "\n", - "Sve funkcije i atributi prikazani gore uz pomoć primjera koda pomažu nam da steknemo uvid i osjećaj za podatke.\n", + "Sve funkcije i atributi prikazani gore uz pomoć primjera koda pomažu nam da steknemo uvid u podatke.\n", "\n", - "> **Zaključak:** Čak i samo pregledavanjem metapodataka o informacijama u `DataFrameu` ili prvih i posljednjih nekoliko vrijednosti u njemu, možete odmah dobiti ideju o veličini, obliku i sadržaju podataka s kojima radite.\n" + "> **Zaključak:** Već i samo pregledavanjem metapodataka o informacijama u DataFrame-u ili prvih i posljednjih nekoliko vrijednosti u njemu možete odmah dobiti ideju o veličini, obliku i sadržaju podataka s kojima radite.\n" ] }, { @@ -595,18 +595,18 @@ "id": "TvurZyLSDxq_" }, "source": [ - "### Nedostajući Podaci\n", - "Pogledajmo nedostajuće podatke. Nedostajući podaci javljaju se kada neka vrijednost nije pohranjena u nekim stupcima.\n", + "### Nedostajući podaci\n", + "Pogledajmo pobliže nedostajuće podatke. Nedostajući podaci javljaju se kada neka vrijednost nije pohranjena u nekim stupcima.\n", "\n", - "Uzmimo primjer: recimo da je netko svjestan svoje težine i ne ispuni polje za težinu u anketi. Tada će vrijednost težine za tu osobu nedostajati.\n", + "Uzmimo primjer: recimo da je netko osjetljiv na svoju težinu i ne ispuni polje za težinu u anketi. Tada će vrijednost težine za tu osobu nedostajati.\n", "\n", - "Većinu vremena, u stvarnim skupovima podataka, javljaju se nedostajuće vrijednosti.\n", + "U većini slučajeva, u stvarnim skupovima podataka, javljaju se nedostajuće vrijednosti.\n", "\n", "**Kako Pandas obrađuje nedostajuće podatke**\n", "\n", - "Pandas obrađuje nedostajuće vrijednosti na dva načina. Prvi ste već vidjeli u prethodnim odjeljcima: `NaN`, ili Not a Number. Ovo je zapravo posebna vrijednost koja je dio IEEE specifikacije za brojeve s pomičnim zarezom i koristi se samo za označavanje nedostajućih vrijednosti s pomičnim zarezom.\n", + "Pandas obrađuje nedostajuće vrijednosti na dva načina. Prvi ste već vidjeli u prethodnim odjeljcima: `NaN`, ili Not a Number (nije broj). Ovo je zapravo posebna vrijednost koja je dio IEEE specifikacije za brojeve s pomičnim zarezom i koristi se samo za označavanje nedostajućih vrijednosti s pomičnim zarezom.\n", "\n", - "Za nedostajuće vrijednosti koje nisu brojevi s pomičnim zarezom, pandas koristi Python objekt `None`. Iako se može činiti zbunjujućim da ćete naići na dvije različite vrste vrijednosti koje u suštini znače isto, postoje opravdani programerski razlozi za ovaj dizajnerski izbor, a u praksi, ovakav pristup omogućuje pandas biblioteci da pruži dobar kompromis u velikoj većini slučajeva. Unatoč tome, i `None` i `NaN` imaju ograničenja na koja morate obratiti pažnju u vezi s načinom na koji se mogu koristiti.\n" + "Za nedostajuće vrijednosti koje nisu brojevi s pomičnim zarezom, pandas koristi Python objekt `None`. Iako se može činiti zbunjujućim da ćete naići na dvije različite vrste vrijednosti koje u suštini znače isto, postoje opravdani programerski razlozi za ovaj izbor dizajna, a u praksi, ovakav pristup omogućuje pandas biblioteci da pruži dobar kompromis u velikoj većini slučajeva. Unatoč tome, i `None` i `NaN` imaju ograničenja na koja morate obratiti pažnju u vezi s načinom na koji se mogu koristiti.\n" ] }, { @@ -615,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: ne-float nedostajući podaci\n", - "Budući da `None` dolazi iz Pythona, ne može se koristiti u NumPy i pandas nizovima koji nisu tipa podataka `'object'`. Zapamtite, NumPy nizovi (i strukture podataka u pandas-u) mogu sadržavati samo jednu vrstu podataka. Ovo im daje ogromnu snagu za rad s velikim količinama podataka i računalne operacije, ali također ograničava njihovu fleksibilnost. Takvi nizovi moraju se \"promaknuti\" na \"najniži zajednički nazivnik\", tj. tip podataka koji će obuhvatiti sve u nizu. Kada je `None` u nizu, to znači da radite s Python objektima.\n", + "### `None`: nedostajući podaci koji nisu tipa float\n", + "Budući da `None` dolazi iz Pythona, ne može se koristiti u NumPy i pandas nizovima koji nisu tipa podataka `'object'`. Zapamtite, NumPy nizovi (i strukture podataka u pandas) mogu sadržavati samo jednu vrstu podataka. To im daje ogromnu snagu za rad s velikim količinama podataka i računalne operacije, ali također ograničava njihovu fleksibilnost. Takvi nizovi moraju se \"promijeniti\" u \"najniži zajednički nazivnik\", odnosno tip podataka koji može obuhvatiti sve u nizu. Kada je `None` prisutan u nizu, to znači da radite s Python objektima.\n", "\n", - "Da biste to vidjeli u praksi, razmotrite sljedeći primjer niza (obratite pažnju na `dtype` za njega):\n" + "Da biste to vidjeli u praksi, razmotrite sljedeći primjer niza (obratite pažnju na `dtype`):\n" ] }, { @@ -657,7 +657,7 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Stvarnost promjene tipova podataka prema višim tipovima nosi sa sobom dvije nuspojave. Prvo, operacije će se izvršavati na razini interpretiranog Python koda, a ne kompajliranog NumPy koda. U suštini, to znači da će sve operacije koje uključuju `Series` ili `DataFrame` s `None` vrijednostima biti sporije. Iako vjerojatno nećete primijetiti ovaj pad performansi, kod velikih skupova podataka to bi moglo postati problem.\n", + "Stvarnost promjene tipova podataka prema višem tipu nosi sa sobom dvije nuspojave. Prvo, operacije će se izvršavati na razini interpretiranog Python koda, a ne kompajliranog NumPy koda. U suštini, to znači da će sve operacije koje uključuju `Series` ili `DataFrame` s vrijednostima `None` biti sporije. Iako vjerojatno nećete primijetiti ovaj pad performansi, kod velikih skupova podataka to bi moglo postati problem.\n", "\n", "Druga nuspojava proizlazi iz prve. Budući da `None` u osnovi vraća `Series` ili `DataFrame` u svijet običnog Pythona, korištenje NumPy/pandas agregacija poput `sum()` ili `min()` na nizovima koji sadrže vrijednost ``None`` općenito će rezultirati pogreškom:\n" ] @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Ključna točka**: Zbrajanje (i druge operacije) između cijelih brojeva i vrijednosti `None` nije definirano, što može ograničiti mogućnosti rada s skupovima podataka koji ih sadrže.\n" + "**Ključna točka**: Zbrajanje (i druge operacije) između cijelih brojeva i vrijednosti `None` nije definirano, što može ograničiti rad s skupovima podataka koji ih sadrže.\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Dobra vijest: agregacije koje se izvode na nizovima s `NaN` u njima ne uzrokuju pogreške. Loša vijest: rezultati nisu jednako korisni:\n" + "Dobre vijesti: agregacije koje se izvode na nizovima s `NaN` u njima ne uzrokuju pogreške. Loše vijesti: rezultati nisu jednako korisni:\n" ] }, { @@ -831,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "Zapamti: `NaN` je samo za nedostajuće vrijednosti s pomičnim zarezom; ne postoji ekvivalent `NaN` za cijele brojeve, stringove ili Booleove vrijednosti.\n" + "Zapamtite: `NaN` je samo za nedostajuće vrijednosti s pomičnim zarezom; ne postoji ekvivalent `NaN` za cijele brojeve, stringove ili Booleove vrijednosti.\n" ] }, { @@ -840,9 +840,9 @@ "id": "kj6EKdsAgRsA" }, "source": [ - "### `NaN` i `None`: null vrijednosti u pandasu\n", + "### `NaN` i `None`: null vrijednosti u pandas\n", "\n", - "Iako se `NaN` i `None` mogu ponašati donekle različito, pandas je ipak dizajniran da ih obrađuje naizmjenično. Da bismo objasnili što mislimo, razmotrimo `Series` s cijelim brojevima:\n" + "Iako se `NaN` i `None` mogu ponašati malo drugačije, pandas je ipak dizajniran da ih obrađuje naizmjenično. Da biste vidjeli na što mislimo, razmotrite `Series` s cijelim brojevima:\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "U procesu promjene tipova podataka radi uspostavljanja homogenosti podataka u `Series` i `DataFrame` objektima, pandas će bez problema zamijeniti nedostajuće vrijednosti između `None` i `NaN`. Zbog ove značajke dizajna, korisno je razmišljati o `None` i `NaN` kao dvije različite vrste \"null\" vrijednosti u pandas-u. Zapravo, neki od osnovnih metoda koje ćete koristiti za rad s nedostajućim vrijednostima u pandas-u odražavaju ovu ideju u svojim nazivima:\n", + "U procesu promjene tipova podataka na više razine kako bi se uspostavila homogenost podataka u `Series` i `DataFrame` objektima, pandas će bez problema zamijeniti nedostajuće vrijednosti između `None` i `NaN`. Zbog ove značajke dizajna, korisno je razmišljati o `None` i `NaN` kao dvije različite vrste \"null\" vrijednosti u pandas. Zapravo, neki od osnovnih metoda koje ćete koristiti za rad s nedostajućim vrijednostima u pandas odražavaju ovu ideju u svojim nazivima:\n", "\n", - "- `isnull()`: Generira Booleansku masku koja označava nedostajuće vrijednosti\n", + "- `isnull()`: Generira Booleovu masku koja označava nedostajuće vrijednosti\n", "- `notnull()`: Suprotno od `isnull()`\n", "- `dropna()`: Vraća filtriranu verziju podataka\n", "- `fillna()`: Vraća kopiju podataka s popunjenim ili imputiranim nedostajućim vrijednostima\n", "\n", - "Ovo su važne metode koje treba savladati i s kojima se treba osjećati ugodno, pa ćemo ih detaljnije razmotriti.\n" + "Ovo su važne metode koje treba savladati i s kojima se treba osjećati ugodno, pa ćemo ih detaljnije obraditi.\n" ] }, { @@ -925,7 +925,7 @@ "### Otkrivanje null vrijednosti\n", "\n", "Sada kada smo razumjeli važnost nedostajućih vrijednosti, trebamo ih otkriti u našem skupu podataka prije nego što ih obradimo. \n", - "I `isnull()` i `notnull()` su vaše osnovne metode za otkrivanje null podataka. Obje vraćaju Booleanske maske preko vaših podataka.\n" + "I `isnull()` i `notnull()` su osnovne metode za otkrivanje null podataka. Obje vraćaju Booleanske maske preko vaših podataka.\n" ] }, { @@ -978,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Pogledajte pažljivo rezultat. Iznenađuje li vas nešto od toga? Iako je `0` aritmetička nula, ipak je savršeno dobar cijeli broj, a pandas ga tako i tretira. `''` je malo suptilniji. Iako smo ga koristili u odjeljku 1 za predstavljanje prazne vrijednosti stringa, ipak je objekt tipa string i nije prikaz null vrijednosti s obzirom na način na koji pandas to interpretira.\n", + "Pogledajte pažljivo rezultat. Iznenađuje li vas nešto? Iako je `0` aritmetička nula, ipak je potpuno valjan cijeli broj i pandas ga tako tretira. `''` je malo suptilniji. Iako smo ga u Poglavlju 1 koristili za predstavljanje prazne vrijednosti stringa, ipak je objekt tipa string i nije prikaz null vrijednosti prema pandas-u.\n", "\n", - "Sada, okrenimo ovo i koristimo ove metode na način koji je bliži stvarnoj praksi. Boolean maske možete koristiti izravno kao indeks ``Series`` ili ``DataFrame``, što može biti korisno kada pokušavate raditi s izoliranim vrijednostima koje nedostaju (ili su prisutne).\n", + "Sada, okrenimo perspektivu i koristimo ove metode na način koji je bliži stvarnoj praksi. Boolean maske možete koristiti izravno kao indeks ``Series`` ili ``DataFrame``, što može biti korisno kada radite s izoliranim nedostajućim (ili prisutnim) vrijednostima.\n", "\n", - "Ako želimo ukupan broj vrijednosti koje nedostaju, jednostavno možemo napraviti zbroj preko maske koju generira metoda `isnull()`.\n" + "Ako želimo ukupan broj nedostajućih vrijednosti, jednostavno možemo napraviti zbroj maske koju generira metoda `isnull()`.\n" ] }, { @@ -1053,16 +1053,16 @@ "\n", "> **Cilj učenja:** Na kraju ovog pododjeljka trebali biste znati kako i kada zamijeniti ili ukloniti null vrijednosti iz DataFrameova.\n", "\n", - "Modeli strojnog učenja ne mogu sami obrađivati nedostajuće podatke. Stoga, prije nego što podatke proslijedimo modelu, moramo se pozabaviti tim nedostajućim vrijednostima.\n", + "Modeli strojnog učenja ne mogu sami obraditi nedostajuće podatke. Stoga, prije nego što podatke proslijedimo modelu, moramo se pozabaviti tim nedostajućim vrijednostima.\n", "\n", - "Način na koji se rješavaju nedostajući podaci nosi sa sobom suptilne kompromise i može utjecati na vašu konačnu analizu i ishode u stvarnom svijetu.\n", + "Način na koji se nedostajući podaci obrađuju nosi sa sobom suptilne kompromise, može utjecati na vašu konačnu analizu i rezultate u stvarnom svijetu.\n", "\n", - "Postoje dva glavna načina za rješavanje nedostajućih podataka:\n", + "Postoje dva glavna načina rješavanja nedostajućih podataka:\n", "\n", - "1. Uklanjanje retka koji sadrži nedostajuću vrijednost \n", - "2. Zamjena nedostajuće vrijednosti nekom drugom vrijednošću \n", + "1. Uklanjanje retka koji sadrži nedostajuću vrijednost\n", + "2. Zamjena nedostajuće vrijednosti nekom drugom vrijednošću\n", "\n", - "Razmotrit ćemo obje ove metode te njihove prednosti i nedostatke u detalje.\n" + "Razmotrit ćemo obje metode i njihove prednosti i nedostatke detaljno.\n" ] }, { @@ -1073,11 +1073,11 @@ "source": [ "### Uklanjanje null vrijednosti\n", "\n", - "Količina podataka koju prosljeđujemo našem modelu ima izravan utjecaj na njegovu izvedbu. Uklanjanje null vrijednosti znači da smanjujemo broj podataka, a time i veličinu skupa podataka. Stoga je preporučljivo ukloniti retke s null vrijednostima kada je skup podataka prilično velik.\n", + "Količina podataka koju prosljeđujemo našem modelu ima izravan utjecaj na njegovu učinkovitost. Uklanjanje null vrijednosti znači da smanjujemo broj podataka, a time i veličinu skupa podataka. Stoga je preporučljivo ukloniti retke s null vrijednostima kada je skup podataka prilično velik.\n", "\n", - "Drugi primjer može biti situacija u kojoj određeni redak ili stupac ima mnogo nedostajućih vrijednosti. U tom slučaju, oni se mogu ukloniti jer ne bi značajno doprinijeli našoj analizi s obzirom na to da većina podataka za taj redak/stupac nedostaje.\n", + "Drugi slučaj može biti da određeni redak ili stupac ima mnogo nedostajućih vrijednosti. Tada ih je možda najbolje ukloniti jer ne bi značajno pridonijeli našoj analizi s obzirom na to da većina podataka za taj redak/stupac nedostaje.\n", "\n", - "Osim identificiranja nedostajućih vrijednosti, pandas pruža praktičan način za uklanjanje null vrijednosti iz `Series` i `DataFrame` objekata. Da bismo to vidjeli na djelu, vratimo se na `example3`. Funkcija `DataFrame.dropna()` pomaže u uklanjanju redaka s null vrijednostima.\n" + "Osim identificiranja nedostajućih vrijednosti, pandas pruža praktičan način za uklanjanje null vrijednosti iz `Series` i `DataFrame` objekata. Da bismo to vidjeli u praksi, vratimo se na `example3`. Funkcija `DataFrame.dropna()` pomaže u uklanjanju redaka s null vrijednostima.\n" ] }, { @@ -1116,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "Imajte na umu da bi ovo trebalo izgledati kao vaš izlaz iz `example3[example3.notnull()]`. Razlika ovdje je u tome što, umjesto da se samo indeksira na maskirane vrijednosti, `dropna` je uklonio te nedostajuće vrijednosti iz `Series` `example3`.\n", + "Imajte na umu da bi ovo trebalo izgledati kao vaš izlaz iz `example3[example3.notnull()]`. Razlika ovdje je u tome što je, umjesto samo indeksiranja na maskirane vrijednosti, `dropna` uklonio te nedostajuće vrijednosti iz `Series` `example3`.\n", "\n", - "Budući da DataFrameovi imaju dvije dimenzije, nude više opcija za uklanjanje podataka.\n" + "Budući da DataFrames imaju dvije dimenzije, nude više opcija za uklanjanje podataka.\n" ] }, { @@ -1208,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Jeste li primijetili da je pandas promijenio tip dvaju stupaca u float kako bi prilagodio `NaN` vrijednosti?)\n", + "(Jeste li primijetili da je pandas promijenio tip podataka za dva stupca u float kako bi prilagodio `NaN` vrijednosti?)\n", "\n", - "Ne možete ukloniti pojedinačnu vrijednost iz `DataFrame`, pa morate ukloniti cijele redove ili stupce. Ovisno o tome što radite, možda ćete htjeti učiniti jedno ili drugo, a pandas vam daje opcije za oba. Budući da u znanosti o podacima stupci općenito predstavljaju varijable, a redovi predstavljaju opažanja, vjerojatnije je da ćete ukloniti redove podataka; zadana postavka za `dropna()` je uklanjanje svih redova koji sadrže bilo kakve null vrijednosti:\n" + "Ne možete ukloniti pojedinačnu vrijednost iz `DataFrame`, već morate ukloniti cijele redove ili stupce. Ovisno o tome što radite, možda ćete htjeti učiniti jedno ili drugo, a pandas vam nudi opcije za oba. Budući da u znanosti o podacima stupci obično predstavljaju varijable, a redovi predstavljaju opažanja, češće ćete uklanjati redove podataka; zadana postavka za `dropna()` je uklanjanje svih redova koji sadrže bilo kakve null vrijednosti:\n" ] }, { @@ -1362,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Imajte na umu da ovo može ukloniti puno podataka koje biste možda željeli zadržati, posebno u manjim skupovima podataka. Što ako želite ukloniti samo retke ili stupce koji sadrže nekoliko ili čak sve null vrijednosti? Te postavke specificirate u `dropna` pomoću parametara `how` i `thresh`.\n", + "Primijetite da ovo može ukloniti puno podataka koje možda želite zadržati, posebno u manjim skupovima podataka. Što ako želite ukloniti samo retke ili stupce koji sadrže nekoliko ili čak sve null vrijednosti? Te postavke možete odrediti u `dropna` pomoću parametara `how` i `thresh`.\n", "\n", - "Prema zadanim postavkama, `how='any'` (ako želite sami provjeriti ili vidjeti koje druge parametre metoda ima, pokrenite `example4.dropna?` u ćeliji koda). Alternativno, možete specificirati `how='all'` kako biste uklonili samo retke ili stupce koji sadrže sve null vrijednosti. Proširimo naš primjer `DataFrame` kako bismo to vidjeli na djelu u sljedećoj vježbi.\n" + "Prema zadanim postavkama, `how='any'` (ako želite sami provjeriti ili vidjeti koje druge parametre metoda ima, pokrenite `example4.dropna?` u ćeliji koda). Alternativno, možete odrediti `how='all'` kako biste uklonili samo retke ili stupce koji sadrže sve null vrijednosti. Proširimo naš primjer `DataFrame` kako bismo to vidjeli u praksi u sljedećoj vježbi.\n" ] }, { @@ -1458,9 +1458,9 @@ "source": [ "> Ključne točke: \n", "1. Uklanjanje null vrijednosti dobra je ideja samo ako je skup podataka dovoljno velik. \n", - "2. Cijeli redci ili stupci mogu se ukloniti ako im nedostaje većina podataka. \n", - "3. Metoda `DataFrame.dropna(axis=)` pomaže u uklanjanju null vrijednosti. Argument `axis` označava hoće li se uklanjati redci ili stupci. \n", - "4. Može se koristiti i argument `how`. Prema zadanim postavkama postavljen je na `any`. Dakle, uklanja samo one redce/stupce koji sadrže bilo kakve null vrijednosti. Može se postaviti na `all` kako bi se specificiralo da ćemo ukloniti samo one redce/stupce gdje su sve vrijednosti null. \n" + "2. Cijeli redovi ili stupci mogu se ukloniti ako im nedostaje većina podataka. \n", + "3. Metoda `DataFrame.dropna(axis=)` pomaže u uklanjanju null vrijednosti. Argument `axis` označava hoće li se uklanjati redovi ili stupci. \n", + "4. Može se koristiti i argument `how`. Po zadanim postavkama postavljen je na `any`. Dakle, uklanja samo one redove/stupce koji sadrže bilo kakve null vrijednosti. Može se postaviti na `all` kako bi se odredilo da ćemo ukloniti samo one redove/stupce gdje su sve vrijednosti null. \n" ] }, { @@ -1492,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "Parametar `thresh` daje vam precizniju kontrolu: postavljate broj *ne-null* vrijednosti koje redak ili stupac mora imati da bi se zadržao:\n" + "Parametar `thresh` omogućuje precizniju kontrolu: postavljate broj *ne-null* vrijednosti koje redak ili stupac mora imati kako bi bio zadržan:\n" ] }, { @@ -1567,7 +1567,7 @@ "id": "fmSFnzZegRsG" }, "source": [ - "Ovdje su prvi i zadnji redak uklonjeni jer sadrže samo dvije vrijednosti koje nisu null.\n" + "Ovdje su prva i zadnja redak uklonjeni jer sadrže samo dvije vrijednosti koje nisu null.\n" ] }, { @@ -1578,9 +1578,9 @@ "source": [ "### Popunjavanje null vrijednosti\n", "\n", - "Ponekad ima smisla popuniti nedostajuće vrijednosti onima koje bi mogle biti valjane. Postoji nekoliko tehnika za popunjavanje null vrijednosti. Prva je korištenje domenskog znanja (znanje o temi na kojoj se temelji skup podataka) kako bi se na neki način približno odredile nedostajuće vrijednosti.\n", + "Ponekad ima smisla popuniti nedostajuće vrijednosti onima koje bi mogle biti valjane. Postoji nekoliko tehnika za popunjavanje null vrijednosti. Prva je korištenje znanja o domeni (znanja o temi na kojoj se temelji skup podataka) kako bi se na neki način približno odredile nedostajuće vrijednosti.\n", "\n", - "Možete koristiti `isnull` za ovo izravno, ali to može biti zamorno, posebno ako imate puno vrijednosti za popuniti. Budući da je ovo tako čest zadatak u znanosti o podacima, pandas pruža `fillna`, koji vraća kopiju `Series` ili `DataFrame` s nedostajućim vrijednostima zamijenjenim onima koje odaberete. Napravimo još jedan primjer `Series` kako bismo vidjeli kako ovo funkcionira u praksi.\n" + "Možete koristiti `isnull` za popunjavanje vrijednosti izravno, ali to može biti zamorno, osobito ako imate puno vrijednosti za popuniti. Budući da je ovo tako čest zadatak u znanosti o podacima, pandas pruža `fillna`, koji vraća kopiju `Series` ili `DataFrame` s nedostajućim vrijednostima zamijenjenim vrijednostima po vašem izboru. Napravimo još jedan primjer `Series` kako bismo vidjeli kako ovo funkcionira u praksi.\n" ] }, { @@ -1589,12 +1589,12 @@ "id": "CE8S7louLezV" }, "source": [ - "### Kategorijski podaci (Nenumerički)\n", - "Prvo razmotrimo nenumeričke podatke. U skupovima podataka imamo stupce s kategorijskim podacima. Npr. Spol, Istina ili Laž itd.\n", + "### Kategorijski podaci (ne-numerički)\n", + "Prvo ćemo razmotriti ne-numeričke podatke. U skupovima podataka imamo stupce s kategorijskim podacima, npr. Spol, Istina ili Laž itd.\n", "\n", - "U većini ovih slučajeva, nedostajuće vrijednosti zamjenjujemo `modom` stupca. Recimo, imamo 100 podataka, od kojih je 90 reklo Istina, 8 je reklo Laž, a 2 nisu popunjena. Tada možemo popuniti ta 2 s Istina, uzimajući u obzir cijeli stupac.\n", + "U većini ovih slučajeva, nedostajuće vrijednosti zamjenjujemo `modom` stupca. Recimo, imamo 100 podataka, od kojih je 90 označilo Istina, 8 označilo Laž, a 2 nisu popunjena. Tada možemo popuniti ta 2 s Istina, uzimajući u obzir cijeli stupac.\n", "\n", - "Opet, ovdje možemo koristiti i domensko znanje. Razmotrimo primjer popunjavanja s modom.\n" + "Opet, ovdje možemo koristiti znanje iz domene. Razmotrimo primjer popunjavanja pomoću moda.\n" ] }, { @@ -1699,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Sad, prvo pronađimo modus prije nego što popunimo vrijednost `None` s modusom.\n" + ] }, { "cell_type": "code", @@ -1734,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Dakle, zamijenit ćemo None s True\n" + ] }, { "cell_type": "code", @@ -1856,14 +1860,14 @@ "### Numerički podaci\n", "Sada prelazimo na numeričke podatke. Ovdje imamo dva uobičajena načina za zamjenu nedostajućih vrijednosti:\n", "\n", - "1. Zamjena s medijanom retka \n", - "2. Zamjena s aritmetičkom sredinom retka \n", + "1. Zamjena s medijanom reda\n", + "2. Zamjena s prosjekom reda\n", "\n", - "Zamjenjujemo s medijanom u slučaju asimetričnih podataka s odstupajućim vrijednostima. To je zato što je medijan otporan na odstupanja.\n", + "Medijan koristimo u slučaju da su podaci iskrivljeni i sadrže ekstremne vrijednosti. To je zato što je medijan otporan na ekstremne vrijednosti.\n", "\n", - "Kada su podaci normalizirani, možemo koristiti aritmetičku sredinu, jer su u tom slučaju sredina i medijan prilično blizu.\n", + "Kada su podaci normalizirani, možemo koristiti prosjek, jer su u tom slučaju prosjek i medijan prilično blizu.\n", "\n", - "Prvo, uzmimo stupac koji je normalno distribuiran i popunimo nedostajuću vrijednost s aritmetičkom sredinom tog stupca.\n" + "Prvo, uzmimo stupac koji je normalno distribuiran i popunimo nedostajuće vrijednosti prosjekom tog stupca.\n" ] }, { @@ -2003,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Popunjavanje s prosjekom\n" + ] }, { "cell_type": "code", @@ -2112,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Sada pokušajmo s drugim podatkovnim okvirom, i ovaj put ćemo zamijeniti vrijednosti None s medijanom stupca.\n" + "Sad pokušajmo s drugim dataframeom, i ovaj put ćemo zamijeniti vrijednosti None s medijanom stupca.\n" ] }, { @@ -2252,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Popunjavanje s medijanom\n" + ] }, { "cell_type": "code", @@ -2352,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Kao što možemo vidjeti, NaN vrijednost je zamijenjena medianom stupca\n" + "Kao što možemo vidjeti, NaN vrijednost je zamijenjena medianom stupca.\n" ] }, { @@ -2436,10 +2444,10 @@ }, "source": [ "> Ključne točke:\n", - "1. Popunjavanje nedostajućih vrijednosti treba se obaviti kada postoji manje podataka ili kada postoji strategija za popunjavanje nedostajućih podataka.\n", + "1. Popunjavanje nedostajućih vrijednosti treba provesti kada postoji malo podataka ili kada postoji strategija za popunjavanje nedostajućih podataka.\n", "2. Znanje o domeni može se koristiti za popunjavanje nedostajućih vrijednosti njihovim približavanjem.\n", - "3. Za kategorijske podatke, nedostajuće vrijednosti se najčešće zamjenjuju modusom stupca.\n", - "4. Za numeričke podatke, nedostajuće vrijednosti obično se popunjavaju srednjom vrijednošću (za normalizirane skupove podataka) ili medijanom stupaca.\n" + "3. Kod kategorijskih podataka, nedostajuće vrijednosti najčešće se zamjenjuju modom stupca.\n", + "4. Kod numeričkih podataka, nedostajuće vrijednosti obično se popunjavaju srednjom vrijednošću (za normalizirane skupove podataka) ili medijanom stupca.\n" ] }, { @@ -2470,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "Možete **popuniti unaprijed** null vrijednosti, što znači koristiti zadnju valjanu vrijednost za popunjavanje null vrijednosti:\n" + "Možete **popuniti unaprijed** null vrijednosti, što znači koristiti posljednju valjanu vrijednost za popunjavanje null vrijednosti:\n" ] }, { @@ -2511,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Također možete **popuniti unatrag** kako biste unatrag propagirali sljedeću valjanu vrijednost za popunjavanje null vrijednosti:\n" + "Također možete **popuniti unatrag** kako biste propagirali sljedeću valjanu vrijednost unatrag za popunjavanje null vrijednosti:\n" ] }, { @@ -2759,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Možete biti kreativni u korištenju `fillna`. Na primjer, pogledajmo ponovno `example4`, ali ovaj put popunimo nedostajuće vrijednosti prosjekom svih vrijednosti u `DataFrame`:\n" + "Možete biti kreativni u načinu na koji koristite `fillna`. Na primjer, pogledajmo ponovno `example4`, ali ovaj put popunimo nedostajuće vrijednosti prosjekom svih vrijednosti u `DataFrame`:\n" ] }, { @@ -2850,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Primijetite da je stupac 3 još uvijek bez vrijednosti: zadani smjer je popunjavanje vrijednosti redom.\n", + "Primijetite da stupac 3 još uvijek nema vrijednosti: zadani smjer je popunjavanje vrijednosti po redovima.\n", "\n", - "> **Zaključak:** Postoji više načina za rješavanje nedostajućih vrijednosti u vašim skupovima podataka. Specifična strategija koju koristite (uklanjanje, zamjena ili čak način na koji ih zamjenjujete) trebala bi biti određena specifičnostima tih podataka. Razvit ćete bolji osjećaj za rješavanje nedostajućih vrijednosti što više radite i komunicirate s skupovima podataka.\n" + "> **Zaključak:** Postoji više načina za rješavanje nedostajućih vrijednosti u vašim skupovima podataka. Specifična strategija koju koristite (uklanjanje, zamjena ili način zamjene) trebala bi biti određena specifičnostima tih podataka. Razvijat ćete bolji osjećaj za rješavanje nedostajućih vrijednosti što više radite i komunicirate s podacima.\n" ] }, { @@ -2863,7 +2871,7 @@ "source": [ "### Kodiranje kategorijskih podataka\n", "\n", - "Modeli strojnog učenja rade isključivo s brojevima i bilo kojim oblikom numeričkih podataka. Ne mogu razlikovati između \"Da\" i \"Ne\", ali mogu razlikovati između 0 i 1. Dakle, nakon što popunimo nedostajuće vrijednosti, potrebno je kodirati kategorijske podatke u neki numerički oblik kako bi ih model mogao razumjeti.\n", + "Modeli strojnog učenja rade isključivo s brojevima i bilo kojim oblikom numeričkih podataka. Ne mogu razlikovati \"Da\" od \"Ne\", ali mogu razlikovati 0 od 1. Dakle, nakon popunjavanja nedostajućih vrijednosti, potrebno je kodirati kategorijske podatke u neki numerički oblik kako bi ih model mogao razumjeti.\n", "\n", "Kodiranje se može obaviti na dva načina. O njima ćemo raspravljati u nastavku.\n" ] @@ -2984,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Da bismo izvršili kodiranje oznaka na prvom stupcu, prvo moramo opisati preslikavanje svake klase u broj, prije zamjene\n" + "Da bismo izvršili kodiranje oznaka na prvom stupcu, prvo moramo opisati mapiranje svake klase na broj, prije zamjene\n" ] }, { @@ -3086,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Kao što možemo vidjeti, rezultat odgovara onome što smo očekivali. Dakle, kada koristimo kodiranje oznaka? Kodiranje oznaka se koristi u jednom ili oba sljedeća slučaja:\n", + "Kao što možemo vidjeti, izlaz odgovara onome što smo očekivali. Dakle, kada koristimo kodiranje oznaka? Kodiranje oznaka koristi se u jednom ili oba sljedeća slučaja:\n", "1. Kada je broj kategorija velik\n", - "2. Kada su kategorije poredane po redoslijedu.\n" + "2. Kada su kategorije poredane.\n" ] }, { @@ -3099,9 +3107,9 @@ "source": [ "**JEDNOSTRUKO KODIRANJE (ONE HOT ENCODING)**\n", "\n", - "Druga vrsta kodiranja je Jednostruko Kodiranje (One Hot Encoding). Kod ove vrste kodiranja, svaka kategorija iz stupca dodaje se kao zaseban stupac, a svaka podatkovna točka dobiva vrijednost 0 ili 1 ovisno o tome sadrži li tu kategoriju. Dakle, ako postoji n različitih kategorija, n stupaca će biti dodano u dataframe.\n", + "Druga vrsta kodiranja je Jednostruko Kodiranje (One Hot Encoding). Kod ove vrste kodiranja, svaka kategorija iz stupca dodaje se kao zaseban stupac, a svaka podatkovna točka dobiva vrijednost 0 ili 1 ovisno o tome sadrži li tu kategoriju. Dakle, ako postoji n različitih kategorija, n stupaca će biti dodano u podatkovni okvir.\n", "\n", - "Na primjer, uzmimo isti primjer klase u zrakoplovu. Kategorije su bile: ['business class', 'economy class', 'first class']. Dakle, ako primijenimo jednostruko kodiranje, sljedeća tri stupca bit će dodana u skup podataka: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Na primjer, uzmimo isti primjer klasa u avionu. Kategorije su bile: ['business class', 'economy class', 'first class']. Dakle, ako primijenimo jednostruko kodiranje, sljedeća tri stupca će biti dodana u skup podataka: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3379,9 +3387,9 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### Prepoznavanje duplikata: `duplicated`\n", + "### Identificiranje duplikata: `duplicated`\n", "\n", - "Duplikatne vrijednosti možete lako prepoznati koristeći metodu `duplicated` u pandas biblioteci, koja vraća Booleovu masku koja označava je li unos u `DataFrame` duplikat ranijeg unosa. Napravimo još jedan primjer `DataFrame` kako bismo vidjeli kako to funkcionira.\n" + "Duplikate možete lako uočiti pomoću metode `duplicated` u pandas, koja vraća Booleovu masku koja pokazuje je li unos u `DataFrame` duplikat ranijeg unosa. Napravimo još jedan primjer `DataFrame` kako bismo vidjeli kako to funkcionira.\n" ] }, { @@ -3511,7 +3519,7 @@ }, "source": [ "### Uklanjanje duplikata: `drop_duplicates`\n", - "`drop_duplicates` jednostavno vraća kopiju podataka za koje su sve vrijednosti `duplicated` postavljene na `False`:\n" + "`drop_duplicates` jednostavno vraća kopiju podataka za koje su sve vrijednosti označene kao `duplicated` postavljene na `False`:\n" ] }, { @@ -3670,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Zaključak:** Uklanjanje dupliciranih podataka ključni je dio gotovo svakog projekta u području podatkovne znanosti. Duplicirani podaci mogu promijeniti rezultate vaših analiza i dati netočne rezultate!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Provjere kvalitete podataka u stvarnom svijetu\n", + "\n", + "> **Cilj učenja:** Na kraju ovog dijela trebali biste biti sposobni prepoznati i ispraviti uobičajene probleme kvalitete podataka u stvarnom svijetu, uključujući nekonzistentne kategorijske vrijednosti, nenormalne numeričke vrijednosti (iznimke) i duplicirane entitete s varijacijama.\n", + "\n", + "Iako su nedostajuće vrijednosti i točne duplicirane vrijednosti uobičajeni problemi, skupovi podataka iz stvarnog svijeta često sadrže suptilnije probleme:\n", + "\n", + "1. **Nekonzistentne kategorijske vrijednosti**: Ista kategorija napisana na različite načine (npr. \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Nenormalne numeričke vrijednosti**: Ekstremne iznimke koje ukazuju na pogreške pri unosu podataka (npr. dob = 999)\n", + "3. **Gotovo duplicirani redovi**: Zapisi koji predstavljaju isti entitet s malim varijacijama\n", + "\n", + "Istražimo tehnike za otkrivanje i rješavanje ovih problema.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Stvaranje uzorka \"neurednog\" skupa podataka\n", + "\n", + "Prvo, stvorimo uzorak skupa podataka koji sadrži vrste problema s kojima se često susrećemo u stvarnim podacima:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Otkrivanje nedosljednih kategorijskih vrijednosti\n", + "\n", + "Primijetite da stupac `country` ima više prikaza za iste zemlje. Idemo identificirati te nedosljednosti:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Standardizacija kategorijskih vrijednosti\n", + "\n", + "Možemo stvoriti mapiranje za standardizaciju ovih vrijednosti. Jednostavan pristup je pretvoriti u mala slova i stvoriti rječnik za mapiranje:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternativa: Korištenje nepreciznog podudaranja**\n", + "\n", + "Za složenije slučajeve, možemo koristiti neprecizno podudaranje nizova s bibliotekom `rapidfuzz` kako bismo automatski otkrili slične nizove:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Otkrivanje neuobičajenih numeričkih vrijednosti (iznimki)\n", + "\n", + "Promatrajući stupac `age`, imamo neke sumnjive vrijednosti poput 199 i -5. Koristit ćemo statističke metode za otkrivanje ovih iznimki.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Korištenje metode IQR (interkvartilnog raspona)\n", + "\n", + "Metoda IQR je pouzdana statistička tehnika za otkrivanje odstupanja koja je manje osjetljiva na ekstremne vrijednosti:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Korištenje Z-score metode\n", + "\n", + "Metoda Z-score identificira odstupanja na temelju standardnih devijacija od srednje vrijednosti:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Rukovanje odstupanjima\n", + "\n", + "Nakon što su otkrivena, odstupanja se mogu riješiti na nekoliko načina:\n", + "1. **Ukloniti**: Izbaciti retke s odstupanjima (ako su pogreške)\n", + "2. **Ograničiti**: Zamijeniti graničnim vrijednostima\n", + "3. **Zamijeniti s NaN**: Tretirati kao nedostajuće podatke i koristiti tehnike imputacije\n", + "4. **Zadržati**: Ako su legitimne ekstremne vrijednosti\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Otkrivanje gotovo identičnih redaka\n", + "\n", + "Primijetite da naš skup podataka ima više unosa za \"John Smith\" s malo različitim vrijednostima. Identificirajmo potencijalne duplicirane unose na temelju sličnosti imena.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Pronalaženje gotovo identičnih podudarnosti pomoću nejasnog podudaranja\n", + "\n", + "Za naprednije otkrivanje dupliciranih podataka, možemo koristiti nejasno podudaranje za pronalaženje sličnih imena:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Rukovanje dupliciranim podacima\n", + "\n", + "Nakon što ih identificirate, trebate odlučiti kako postupiti s dupliciranim podacima:\n", + "1. **Zadržati prvu pojavu**: Koristite `drop_duplicates(keep='first')`\n", + "2. **Zadržati zadnju pojavu**: Koristite `drop_duplicates(keep='last')`\n", + "3. **Agregirati informacije**: Kombinirajte informacije iz dupliciranih redaka\n", + "4. **Ručno pregledati**: Označite za pregled od strane čovjeka\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Sažetak: Kompletan proces čišćenja podataka\n", + "\n", + "Složimo sve zajedno u cjelovit proces čišćenja podataka:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Vježba izazova\n", + "\n", + "Sad je vaš red! Ispod je novi red podataka s više problema s kvalitetom. Možete li:\n", + "\n", + "1. Identificirati sve probleme u ovom redu\n", + "2. Napisati kod za ispravljanje svakog problema\n", + "3. Dodati očišćeni red u skup podataka\n", + "\n", + "Evo problematičnih podataka:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Ključne točke\n", + "\n", + "1. **Nekonzistentne kategorije** česte su u stvarnim podacima. Uvijek provjerite jedinstvene vrijednosti i standardizirajte ih pomoću mapiranja ili nejasnog podudaranja.\n", + "\n", + "2. **Izvanredne vrijednosti** mogu značajno utjecati na vašu analizu. Koristite znanje o domeni u kombinaciji sa statističkim metodama (IQR, Z-score) za njihovo otkrivanje.\n", + "\n", + "3. **Gotovo duplicirani podaci** teže se otkrivaju od točnih duplikata. Razmislite o korištenju nejasnog podudaranja i normalizacije podataka (pretvaranje u mala slova, uklanjanje razmaka) za njihovo prepoznavanje.\n", + "\n", + "4. **Čišćenje podataka je iterativno**. Možda ćete morati primijeniti više tehnika i pregledati rezultate prije nego što finalizirate očišćeni skup podataka.\n", + "\n", + "5. **Dokumentirajte svoje odluke**. Vodite evidenciju o koracima čišćenja koje ste primijenili i razlozima za to, jer je to važno za reprodukciju i transparentnost.\n", + "\n", + "> **Najbolja praksa:** Uvijek sačuvajte kopiju svojih originalnih \"nečistih\" podataka. Nikada nemojte prepisivati izvorne datoteke s podacima - kreirajte očišćene verzije s jasnim konvencijama imenovanja, poput `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Odricanje od odgovornosti**: \nOvaj dokument je preveden pomoću AI usluge za prevođenje [Co-op Translator](https://github.com/Azure/co-op-translator). Iako nastojimo osigurati točnost, imajte na umu da automatski prijevodi mogu sadržavati pogreške ili netočnosti. Izvorni dokument na izvornom jeziku treba smatrati autoritativnim izvorom. Za ključne informacije preporučuje se profesionalni prijevod od strane ljudskog prevoditelja. Ne preuzimamo odgovornost za bilo kakva nesporazuma ili pogrešna tumačenja koja proizlaze iz korištenja ovog prijevoda.\n" + "\n---\n\n**Odricanje od odgovornosti**: \nOvaj dokument je preveden pomoću AI usluge za prevođenje [Co-op Translator](https://github.com/Azure/co-op-translator). Iako nastojimo osigurati točnost, imajte na umu da automatski prijevodi mogu sadržavati pogreške ili netočnosti. Izvorni dokument na izvornom jeziku treba smatrati autoritativnim izvorom. Za ključne informacije preporučuje se profesionalni prijevod od strane čovjeka. Ne preuzimamo odgovornost za nesporazume ili pogrešna tumačenja koja mogu proizaći iz korištenja ovog prijevoda.\n" ] } ], @@ -3704,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:54:35+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T21:12:52+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "hr" } diff --git a/translations/hu/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/hu/2-Working-With-Data/08-data-preparation/notebook.ipynb index 35b2b0ee..7a5cfcf1 100644 --- a/translations/hu/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/hu/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# Adatelőkészítés\n", "\n", - "[Az eredeti jegyzet forrása: *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Az eredeti jegyzetfüzet forrása: *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## A `DataFrame` információinak felfedezése\n", "\n", "> **Tanulási cél:** Ennek az alfejezetnek a végére képes leszel általános információkat találni a pandas DataFrame-ekben tárolt adatokról.\n", "\n", - "Miután betöltötted az adatokat a pandasba, nagy valószínűséggel egy `DataFrame` formátumban lesznek. De ha a `DataFrame`-edben lévő adatállomány 60,000 sorból és 400 oszlopból áll, hogyan kezdhetsz neki annak, hogy átlásd, mivel dolgozol? Szerencsére a pandas biztosít néhány kényelmes eszközt, amelyekkel gyorsan áttekintheted egy `DataFrame` általános információit, valamint az első és utolsó néhány sort.\n", + "Miután betöltötted az adataidat a pandasba, nagy valószínűséggel egy `DataFrame`-ben lesznek. De ha a `DataFrame`-edben lévő adathalmaz 60 000 sort és 400 oszlopot tartalmaz, hogyan kezdhetsz neki annak, hogy átlásd, mivel dolgozol? Szerencsére a pandas biztosít néhány kényelmes eszközt, amelyekkel gyorsan áttekintheted egy `DataFrame` általános információit, valamint az első és utolsó néhány sort.\n", "\n", - "Ennek a funkciónak a felfedezéséhez importálni fogjuk a Python scikit-learn könyvtárat, és használni fogunk egy ikonikus adatállományt, amelyet minden adatkutató már több százszor látott: a brit biológus Ronald Fisher *Iris* adatállományát, amelyet az 1936-os \"A több mérések használata taxonómiai problémákban\" című tanulmányában használt:\n" + "Ennek a funkciónak a felfedezéséhez importálni fogjuk a Python scikit-learn könyvtárát, és használni fogunk egy ikonikus adathalmazt, amelyet minden adatkutató több százszor látott már: a brit biológus, Ronald Fisher *Iris* adathalmazát, amelyet az 1936-os \"The use of multiple measurements in taxonomic problems\" című tanulmányában használt:\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Betöltöttük az Iris adathalmazt az `iris_df` változóba. Mielőtt mélyebben belemerülnénk az adatokba, érdemes lenne megtudni, hány adatpontunk van, és mekkora az adathalmaz teljes mérete. Hasznos lehet áttekinteni, mekkora adatmennyiséggel dolgozunk.\n" + "Betöltöttük az Iris adathalmazt az `iris_df` változóba. Mielőtt mélyebben belemerülnénk az adatokba, érdemes lenne megtudni, hány adatpontunk van, és mekkora az adathalmaz teljes mérete. Hasznos ránézni az adatok mennyiségére, amivel dolgozunk.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Tehát, 150 sor és 4 oszlopnyi adatról van szó. Minden sor egy adatpontot képvisel, és minden oszlop egy-egy jellemzőt tartalmaz, amely az adatkerethez kapcsolódik. Alapvetően tehát 150 adatpont van, mindegyik 4 jellemzővel.\n", + "Tehát 150 sorral és 4 oszloppal rendelkező adatokkal dolgozunk. Minden sor egy adatpontot képvisel, és minden oszlop egyetlen jellemzőt, amely az adatkerethez kapcsolódik. Alapvetően tehát 150 adatpont van, amelyek mindegyike 4 jellemzőt tartalmaz.\n", "\n", - "A `shape` itt az adatkeret egy attribútuma, nem pedig egy függvény, ezért nem zárul zárójelekkel.\n" + "A `shape` itt az adatkeret egy attribútuma, nem pedig egy függvény, ezért nem zárul zárójelek párjával.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Most nézzük meg a 4 adat oszlopot. Mit is jelentenek pontosan? A `columns` attribútum megadja nekünk az oszlopok nevét a dataframe-ben.\n" + "Most nézzük meg a 4 adat oszlopot. Mit is jelentenek pontosan? A `columns` attribútum megadja a dataframe oszlopainak nevét.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Az adatok mennyisége (amit a `shape` attribútum ad meg) és a jellemzők vagy oszlopok nevei (amit a `columns` attribútum ad meg) már adnak némi információt az adathalmazról. Most szeretnénk mélyebben belemerülni az adathalmazba. Ebben nagyon hasznos a `DataFrame.info()` függvény.\n" + "Az adatmennyiség (amit a `shape` attribútum ad meg) és a jellemzők vagy oszlopok nevei (amit a `columns` attribútum ad meg) már adnak némi információt az adathalmazról. Most azonban mélyebben szeretnénk belemerülni az adathalmazba. Ebben a `DataFrame.info()` függvény nagyon hasznos lehet.\n" ] }, { @@ -181,9 +181,8 @@ }, "source": [ "Innen néhány megfigyelést tehetünk:\n", - "\n", - "1. Az egyes oszlopok adattípusa: Ebben az adathalmazban az összes adat 64 bites lebegőpontos számként van tárolva. \n", - "2. Nem null értékek száma: A null értékek kezelése fontos lépés az adatelőkészítés során. Ezzel később foglalkozunk a notebookban.\n" + "1. Az egyes oszlopok adattípusa: Ebben az adathalmazban az összes adat 64 bites lebegőpontos számként van tárolva.\n", + "2. Nem null értékek száma: A null értékek kezelése fontos lépés az adatelőkészítés során. Ezzel később foglalkozunk a jegyzetfüzetben.\n" ] }, { @@ -193,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Tegyük fel, hogy sok numerikus adat található az adatállományunkban. Egyváltozós statisztikai számítások, mint például az átlag, medián, kvartilisek stb., elvégezhetők az egyes oszlopokon külön-külön. A `DataFrame.describe()` függvény statisztikai összefoglalót nyújt az adatállomány numerikus oszlopairól.\n" + "Tegyük fel, hogy rengeteg numerikus adat van az adatállományunkban. Egyváltozós statisztikai számításokat, mint például az átlag, medián, kvartilisek stb., elvégezhetünk az egyes oszlopokon külön-külön. A `DataFrame.describe()` függvény statisztikai összefoglalót nyújt az adatállomány numerikus oszlopairól.\n" ] }, { @@ -333,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "Az összes fent említett függvénnyel és attribútummal már kaptunk egy átfogó képet az adathalmazról. Tudjuk, hány adatpont van benne, hány jellemző található, az egyes jellemzők adattípusát, valamint az egyes jellemzők nem null értékeinek számát.\n", + "Az összes fent említett függvénnyel és attribútummal már kaptunk egy átfogó képet az adathalmazról. Tudjuk, hány adatpont van benne, hány jellemző található, minden jellemző adat típusa, valamint az egyes jellemzők nem null értékeinek száma.\n", "\n", - "Most itt az ideje, hogy magát az adatot is megnézzük. Nézzük meg, hogyan néznek ki a `DataFrame` első néhány sora (az első néhány adatpont):\n" + "Most itt az ideje, hogy magát az adatokat is megnézzük. Nézzük meg, hogyan néznek ki az első néhány sor (az első néhány adatpont) a `DataFrame`-ben:\n" ] }, { @@ -442,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "A kimenetben itt láthatjuk az adathalmaz öt (5) bejegyzését. Ha megnézzük a bal oldali indexet, kiderül, hogy ezek az első öt sor.\n" + "A kimenet alapján itt öt (5) bejegyzést láthatunk az adathalmazból. Ha megnézzük a bal oldali indexet, kiderül, hogy ezek az első öt sor.\n" ] }, { @@ -453,7 +452,7 @@ "source": [ "### Feladat:\n", "\n", - "A fenti példából egyértelmű, hogy alapértelmezés szerint a `DataFrame.head` az első öt sort adja vissza egy `DataFrame`-ből. Az alábbi kódcella alapján ki tudsz találni egy módot arra, hogy több mint öt sort jeleníts meg?\n" + "A fenti példából egyértelmű, hogy alapértelmezés szerint a `DataFrame.head` az első öt sort adja vissza egy `DataFrame`-ből. Az alábbi kódcella segítségével ki tudsz találni egy módot arra, hogy több mint öt sort jeleníts meg?\n" ] }, { @@ -476,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Egy másik módja az adatok megtekintésének az, ha a végét nézzük (nem az elejét). A `DataFrame.head` ellentéte a `DataFrame.tail`, amely a `DataFrame` utolsó öt sorát adja vissza:\n" + "Egy másik módja az adatok megtekintésének a végéről (nem az elejéről) történhet. A `DataFrame.head` ellentéte a `DataFrame.tail`, amely a `DataFrame` utolsó öt sorát adja vissza:\n" ] }, { @@ -587,7 +586,7 @@ "\n", "Az összes fent bemutatott függvény és attribútum, amelyeket kódpéldák segítségével ismertettünk, segít abban, hogy betekintést nyerjünk az adatokba.\n", "\n", - "> **Tanulság:** Már pusztán azzal, hogy megnézzük a `DataFrame` metaadatait vagy az első és utolsó néhány értéket, azonnali képet kaphatunk az adatok méretéről, alakjáról és tartalmáról, amelyekkel dolgozunk.\n" + "> **Tanulság:** Már pusztán azzal, hogy megnézzük a `DataFrame`-ben található információk metaadatait, vagy az első és utolsó néhány értéket, azonnali képet kaphatunk az adatok méretéről, alakjáról és tartalmáról, amelyekkel dolgozunk.\n" ] }, { @@ -597,17 +596,17 @@ }, "source": [ "### Hiányzó adatok\n", - "Merüljünk el a hiányzó adatok témájában. Hiányzó adatok akkor fordulnak elő, amikor egyes oszlopokban nincs érték tárolva.\n", + "Nézzük meg közelebbről a hiányzó adatokat. Hiányzó adatok akkor fordulnak elő, amikor egyes oszlopokban nincs érték tárolva.\n", "\n", - "Vegyünk egy példát: tegyük fel, hogy valaki nagyon odafigyel a testsúlyára, és nem tölti ki a testsúly mezőt egy kérdőívben. Ebben az esetben az adott személy testsúly értéke hiányozni fog.\n", + "Vegyünk egy példát: mondjuk valaki nagyon odafigyel a testsúlyára, és nem tölti ki a testsúly mezőt egy kérdőívben. Ebben az esetben az adott személy testsúlyának értéke hiányozni fog.\n", "\n", - "A valós adathalmazokban a hiányzó értékek gyakran előfordulnak.\n", + "A valós adathalmazokban gyakran előfordulnak hiányzó értékek.\n", "\n", "**Hogyan kezeli a Pandas a hiányzó adatokat**\n", "\n", - "A Pandas kétféleképpen kezeli a hiányzó értékeket. Az első, amit már korábbi szakaszokban láthattál, a `NaN`, vagyis Not a Number. Ez valójában egy speciális érték, amely az IEEE lebegőpontos specifikáció része, és kizárólag a hiányzó lebegőpontos értékek jelzésére használják.\n", + "A Pandas kétféleképpen kezeli a hiányzó értékeket. Az elsőt már láthattad korábbi szakaszokban: `NaN`, vagyis Not a Number. Ez valójában egy speciális érték, amely az IEEE lebegőpontos szabvány része, és kizárólag a hiányzó lebegőpontos értékek jelzésére használják.\n", "\n", - "A lebegőpontos értékeken kívüli hiányzó adatok esetében a Pandas a Python `None` objektumát használja. Bár zavarónak tűnhet, hogy két különböző típusú értékkel találkozol, amelyek lényegében ugyanazt jelentik, ennek a tervezési döntésnek programozási szempontból megalapozott okai vannak. A gyakorlatban ez a megközelítés lehetővé teszi, hogy a Pandas a legtöbb esetben jó kompromisszumot nyújtson. Ennek ellenére mind a `None`, mind a `NaN` bizonyos korlátozásokkal jár, amelyekre figyelned kell, különösen azzal kapcsolatban, hogy hogyan használhatók.\n" + "A lebegőpontos értékeken kívüli hiányzó értékek esetében a Pandas a Python `None` objektumát használja. Bár elsőre zavarónak tűnhet, hogy két különböző típusú értékkel találkozol, amelyek lényegében ugyanazt jelentik, ennek a tervezési döntésnek programozási szempontból megvan az oka. A gyakorlatban ez a megközelítés lehetővé teszi, hogy a Pandas a legtöbb esetben jó kompromisszumot kínáljon. Ennek ellenére mind a `None`, mind a `NaN` bizonyos korlátozásokkal jár, amelyeket figyelembe kell venni azzal kapcsolatban, hogy hogyan használhatók.\n" ] }, { @@ -616,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: nem-float hiányzó adatok\n", - "Mivel a `None` a Pythonból származik, nem használható olyan NumPy és pandas tömbökben, amelyek adattípusa nem `'object'`. Ne feledd, a NumPy tömbök (és a pandas adatstruktúrák) csak egyféle adattípust tartalmazhatnak. Ez adja meg számukra azt a hatalmas erejüket a nagyszabású adat- és számítási munkákhoz, de egyben korlátozza is a rugalmasságukat. Az ilyen tömböknek a „legkisebb közös nevezőre” kell átalakulniuk, azaz arra az adattípusra, amely mindent magába foglal a tömbben. Ha a tömbben `None` található, az azt jelenti, hogy Python objektumokkal dolgozol.\n", + "### `None`: nem lebegőpontos hiányzó adatok\n", + "Mivel a `None` a Pythonból származik, nem használható olyan NumPy és pandas tömbökben, amelyek adat típusa nem `'object'`. Ne feledd, hogy a NumPy tömbök (és a pandas adatstruktúrái) csak egyféle adatot tartalmazhatnak. Ez adja meg a hatalmas erejüket a nagyszabású adat- és számítási munkákhoz, de egyben korlátozza a rugalmasságukat is. Az ilyen tömböknek a „legkisebb közös nevezőre” kell átalakulniuk, azaz arra az adattípusra, amely mindent magába foglal a tömbben. Ha a tömbben `None` található, az azt jelenti, hogy Python objektumokkal dolgozol.\n", "\n", - "Hogy ezt a gyakorlatban is lásd, nézd meg a következő példatömböt (figyeld meg a `dtype` értékét):\n" + "Hogy ezt működés közben lásd, nézd meg az alábbi példatömböt (figyeld meg a `dtype` értékét):\n" ] }, { @@ -658,7 +657,7 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "A feljebb konvertált adattípusok valósága két mellékhatással jár. Először is, a műveletek az értelmezett Python kód szintjén fognak végbemenni, nem pedig a lefordított NumPy kód szintjén. Ez lényegében azt jelenti, hogy bármilyen művelet, amely `Series` vagy `DataFrame` objektumokat tartalmaz `None` értékkel, lassabb lesz. Bár valószínűleg nem fogod észrevenni ezt a teljesítménycsökkenést, nagyobb adathalmazok esetén problémát jelenthet.\n", + "A feljebb emelt adattípusok valósága két mellékhatással jár. Először is, a műveletek az értelmezett Python kód szintjén fognak végbemenni, nem pedig a lefordított NumPy kód szintjén. Ez lényegében azt jelenti, hogy bármilyen művelet, amely `Series` vagy `DataFrame` objektumokat tartalmaz `None` értékkel, lassabb lesz. Bár valószínűleg nem vennéd észre ezt a teljesítménycsökkenést, nagy adathalmazok esetén problémát okozhat.\n", "\n", "A második mellékhatás az elsőből ered. Mivel a `None` lényegében visszahúzza a `Series` vagy `DataFrame` objektumokat a hagyományos Python világába, a NumPy/pandas aggregációk, mint például a `sum()` vagy a `min()`, olyan tömbökön, amelyek tartalmaznak egy ``None`` értéket, általában hibát fognak eredményezni:\n" ] @@ -699,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Fő tanulság**: Az egész számok és a `None` értékek közötti összeadás (és más műveletek) nincs definiálva, ami korlátozhatja az ilyen értékeket tartalmazó adathalmazokkal végezhető műveleteket.\n" + "**Fontos tanulság**: Az összeadás (és más műveletek) az egész számok és a `None` értékek között nincs definiálva, ami korlátozhatja az ilyen értékeket tartalmazó adathalmazokkal végezhető műveleteket.\n" ] }, { @@ -773,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "A jó hír: a `NaN` értékeket tartalmazó tömbökön futó aggregációk nem okoznak hibákat. A rossz hír: az eredmények nem egyformán hasznosak:\n" + "A jó hír: az `NaN` értékeket tartalmazó tömbökön futó aggregációk nem dobálnak hibákat. A rossz hír: az eredmények nem egyformán hasznosak:\n" ] }, { @@ -832,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "Ne feledd: a `NaN` csak a hiányzó lebegőpontos értékekre vonatkozik; nincs `NaN` megfelelője az egész számok, sztringek vagy logikai értékek esetében.\n" + "Ne feledd: `NaN` csak a hiányzó lebegőpontos értékekre vonatkozik; nincs `NaN` megfelelője az egész számok, sztringek vagy logikai értékek esetében.\n" ] }, { @@ -907,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "A `Series` és `DataFrame` adattípusok egységesítéséhez szükséges típuskonverzió során a pandas hajlandó a hiányzó értékeket `None` és `NaN` között váltogatni. Ennek a tervezési jellemzőnek köszönhetően hasznos lehet úgy gondolni a `None`-ra és a `NaN`-ra, mint a \"null\" két különböző változatára a pandasban. Valójában néhány alapvető módszer, amelyeket a hiányzó értékek kezelésére használunk a pandasban, ezt az elképzelést tükrözi az elnevezésükben:\n", + "A `Series` és `DataFrame` adatok homogenitásának biztosítása érdekében a pandas hajlandó a hiányzó értékeket `None` és `NaN` között váltogatni. Ennek a tervezési jellemzőnek köszönhetően hasznos lehet úgy gondolni a `None`-ra és a `NaN`-ra, mint a \"null\" két különböző változatára a pandasban. Valójában néhány alapvető metódus, amelyet a hiányzó értékek kezelésére használunk a pandasban, ezt az elképzelést tükrözi az elnevezésükben:\n", "\n", - "- `isnull()`: Egy logikai maszkot generál, amely jelzi a hiányzó értékeket\n", + "- `isnull()`: Booleán maszkot generál, amely jelzi a hiányzó értékeket\n", "- `notnull()`: Az `isnull()` ellentéte\n", - "- `dropna()`: A szűrt adatokat adja vissza\n", - "- `fillna()`: Az adat másolatát adja vissza, amelyben a hiányzó értékek kitöltve vagy imputálva vannak\n", + "- `dropna()`: Az adat szűrt változatát adja vissza\n", + "- `fillna()`: Az adat egy másolatát adja vissza, amelyben a hiányzó értékek ki vannak töltve vagy pótolva\n", "\n", - "Ezek fontos módszerek, amelyeket érdemes elsajátítani és magabiztosan használni, ezért nézzük meg őket részletesebben.\n" + "Ezeket a metódusokat érdemes alaposan elsajátítani és megszokni, ezért nézzük meg őket részletesebben.\n" ] }, { @@ -923,10 +922,10 @@ "id": "Yh5ifd9FgRsB" }, "source": [ - "### Null értékek felismerése\n", + "### Null értékek észlelése\n", "\n", - "Most, hogy megértettük a hiányzó értékek fontosságát, fel kell ismernünk őket az adatainkban, mielőtt foglalkoznánk velük. \n", - "Az `isnull()` és a `notnull()` a két fő módszer a null értékek felismerésére. Mindkettő logikai maszkokat ad vissza az adatokra vonatkozóan.\n" + "Most, hogy megértettük a hiányzó értékek fontosságát, fel kell ismernünk őket az adatainkban, mielőtt kezelni tudnánk őket. \n", + "Az `isnull()` és a `notnull()` a két fő módszer a null értékek észlelésére. Mindkettő logikai maszkot ad vissza az adatok felett.\n" ] }, { @@ -979,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Nézzük meg közelebbről az eredményt. Meglepett valami? Bár a `0` egy aritmetikai nullának számít, mégis egy teljesen érvényes egész szám, és a pandas is így kezeli. A `''` egy kicsit trükkösebb. Míg az 1. szakaszban üres szövegértékként használtuk, valójában egy szövegobjektum, és a pandas szempontjából nem tekinthető nullának.\n", + "Nézd meg alaposan az eredményt. Meglep valami benne? Bár a `0` egy aritmetikai nullának számít, mégis egy teljesen jó egész szám, és a pandas is így kezeli. A `''` egy kicsit trükkösebb. Míg az 1. szakaszban üres sztring értékként használtuk, valójában egy sztring objektum, és a pandas szempontjából nem tekinthető nullának.\n", "\n", - "Most fordítsuk meg a dolgot, és használjuk ezeket a módszereket olyan módon, ahogyan a gyakorlatban is alkalmazni fogjuk őket. A logikai maszkokat közvetlenül használhatjuk ``Series`` vagy ``DataFrame`` indexként, ami hasznos lehet, ha elszigetelt hiányzó (vagy meglévő) értékekkel szeretnénk dolgozni.\n", + "Most fordítsuk meg a dolgot, és használjuk ezeket a metódusokat olyan módon, ahogyan gyakorlatban is alkalmazni fogjuk őket. A logikai maszkokat közvetlenül használhatjuk ``Series`` vagy ``DataFrame`` indexként, ami hasznos lehet, ha elszigetelt hiányzó (vagy meglévő) értékekkel szeretnénk dolgozni.\n", "\n", - "Ha meg akarjuk tudni a hiányzó értékek teljes számát, egyszerűen összegezhetjük a `isnull()` metódus által létrehozott maszkot.\n" + "Ha meg akarjuk kapni a hiányzó értékek teljes számát, egyszerűen összegezhetjük az `isnull()` metódus által létrehozott maszkot.\n" ] }, { @@ -1041,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Fő tanulság**: Mind az `isnull()`, mind a `notnull()` metódusok hasonló eredményeket hoznak, amikor DataFrame-ekben használod őket: megmutatják az eredményeket és azok indexét, ami óriási segítséget nyújt, amikor az adataiddal dolgozol.\n" + "**Fő tanulság**: Mind az `isnull()`, mind a `notnull()` metódusok hasonló eredményeket adnak, amikor DataFrame-ekben használjuk őket: megmutatják az eredményeket és azok indexeit, ami óriási segítséget nyújt az adatok kezelésében.\n" ] }, { @@ -1052,16 +1051,16 @@ "source": [ "### Hiányzó adatok kezelése\n", "\n", - "> **Tanulási cél:** Ennek az alfejezetnek a végére tudni fogod, hogyan és mikor kell helyettesíteni vagy eltávolítani a hiányzó értékeket a DataFrame-ekből.\n", + "> **Tanulási cél:** Ennek az alfejezetnek a végére tudni fogod, hogyan és mikor érdemes null értékeket helyettesíteni vagy eltávolítani a DataFrame-ekből.\n", "\n", - "A gépi tanulási modellek önmagukban nem tudnak mit kezdeni a hiányzó adatokkal. Ezért, mielőtt az adatokat átadnánk a modellnek, foglalkoznunk kell ezekkel a hiányzó értékekkel.\n", + "A gépi tanulási modellek önmagukban nem tudnak hiányzó adatokkal dolgozni. Ezért, mielőtt az adatokat átadnánk a modellnek, foglalkoznunk kell ezekkel a hiányzó értékekkel.\n", "\n", - "A hiányzó adatok kezelése finom kompromisszumokat hordoz magában, és hatással lehet a végső elemzésre, valamint a valós eredményekre.\n", + "A hiányzó adatok kezelése finom kompromisszumokat hordoz magában, és hatással lehet a végső elemzésre, valamint a valós életben elért eredményekre.\n", "\n", "Alapvetően két módja van a hiányzó adatok kezelésének:\n", "\n", - "1. Az a sor eltávolítása, amelyik hiányzó értéket tartalmaz\n", - "2. A hiányzó érték helyettesítése valamilyen másik értékkel\n", + "1. Az adott hiányzó értéket tartalmazó sor törlése\n", + "2. A hiányzó érték helyettesítése valamilyen más értékkel\n", "\n", "Mindkét módszert részletesen megvitatjuk, beleértve azok előnyeit és hátrányait.\n" ] @@ -1072,13 +1071,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### Null értékek elhagyása\n", + "### Null értékek eltávolítása\n", "\n", - "Az adatmennyiség, amelyet a modellünknek átadunk, közvetlen hatással van annak teljesítményére. A null értékek elhagyása azt jelenti, hogy csökkentjük az adatpontok számát, és ezzel együtt az adathalmaz méretét is. Ezért ajánlott elhagyni azokat a sorokat, amelyek null értékeket tartalmaznak, különösen akkor, ha az adathalmaz meglehetősen nagy.\n", + "Az adatmennyiség, amelyet a modellünknek átadunk, közvetlen hatással van annak teljesítményére. A null értékek eltávolítása azt jelenti, hogy csökkentjük az adatpontok számát, és ezzel együtt az adathalmaz méretét is. Ezért ajánlott a null értékeket tartalmazó sorok eltávolítása, ha az adathalmaz meglehetősen nagy.\n", "\n", - "Egy másik eset lehet, hogy egy adott sor vagy oszlop sok hiányzó értéket tartalmaz. Ilyenkor ezeket el lehet hagyni, mivel nem sok értéket adnának az elemzésünkhöz, hiszen az adott sor/oszlop adatai nagyrészt hiányoznak.\n", + "Egy másik eset lehet, hogy egy adott sor vagy oszlop sok hiányzó értéket tartalmaz. Ilyenkor ezeket el lehet távolítani, mivel nem sok értéket adnának az elemzésünkhöz, hiszen az adott sor/oszlop adatai nagyrészt hiányoznak.\n", "\n", - "A hiányzó értékek azonosításán túl a pandas kényelmes eszközt biztosít a null értékek eltávolítására `Series` és `DataFrame` objektumokból. Hogy ezt gyakorlatban is lássuk, térjünk vissza az `example3`-hoz. A `DataFrame.dropna()` függvény segít a null értékeket tartalmazó sorok elhagyásában.\n" + "A hiányzó értékek azonosításán túl a pandas kényelmes eszközt biztosít a null értékek eltávolítására `Series` és `DataFrame` objektumokból. Hogy ezt gyakorlatban is lássuk, térjünk vissza az `example3`-hoz. A `DataFrame.dropna()` függvény segít a null értékeket tartalmazó sorok eltávolításában.\n" ] }, { @@ -1117,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "Ne feledje, hogy ennek úgy kell kinéznie, mint az `example3[example3.notnull()]` kimenete. A különbség itt az, hogy ahelyett, hogy csak a maszkolt értékekre indexelne, a `dropna` eltávolította azokat a hiányzó értékeket a `Series` `example3`-ból.\n", + "Figyelj arra, hogy ennek úgy kell kinéznie, mint az `example3[example3.notnull()]` kimenete. A különbség itt az, hogy ahelyett, hogy csak a maszkolt értékekre indexelne, a `dropna` eltávolította azokat a hiányzó értékeket a `Series` `example3`-ból.\n", "\n", - "Mivel a DataFrame-eknek két dimenziójuk van, több lehetőséget kínálnak az adatok elhagyására.\n" + "Mivel a DataFrame-eknek két dimenziójuk van, több lehetőséget kínálnak az adatok eltávolítására.\n" ] }, { @@ -1211,7 +1210,7 @@ "source": [ "(Észrevetted, hogy a pandas két oszlopot is float típusra konvertált, hogy kezelje a `NaN` értékeket?)\n", "\n", - "Egyetlen értéket nem tudsz eltávolítani egy `DataFrame`-ből, ezért teljes sorokat vagy oszlopokat kell törölnöd. Attól függően, hogy mit szeretnél elérni, az egyik vagy a másik megoldást választhatod, és a pandas mindkettőhöz biztosít lehetőségeket. Mivel az adatelemzésben az oszlopok általában változókat, a sorok pedig megfigyeléseket jelentenek, valószínűbb, hogy sorokat fogsz eltávolítani az adatokból; a `dropna()` alapértelmezett beállítása az, hogy minden olyan sort töröl, amely bármilyen null értéket tartalmaz:\n" + "Egyetlen értéket nem lehet eltávolítani egy `DataFrame`-ből, ezért teljes sorokat vagy oszlopokat kell törölni. Attól függően, hogy mit szeretnél elérni, az egyik vagy a másik megoldást választhatod, és a pandas mindkettőre lehetőséget kínál. Mivel az adatelemzésben az oszlopok általában változókat, a sorok pedig megfigyeléseket jelentenek, gyakrabban fordul elő, hogy sorokat törlünk; a `dropna()` alapértelmezett beállítása az, hogy minden olyan sort eltávolít, amelyben null értékek találhatók:\n" ] }, { @@ -1363,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Ne feledje, hogy ez sok adatot elveszíthet, amelyet esetleg meg szeretne tartani, különösen kisebb adathalmazok esetén. Mi van akkor, ha csak azokat a sorokat vagy oszlopokat szeretné eltávolítani, amelyek több vagy akár az összes értékükben nullák? Ezeket a beállításokat a `dropna` metódusban adhatja meg a `how` és `thresh` paraméterekkel.\n", + "Figyelj arra, hogy ez sok olyan adatot eltávolíthat, amelyet esetleg meg szeretnél tartani, különösen kisebb adathalmazok esetén. Mi van akkor, ha csak azokat a sorokat vagy oszlopokat szeretnéd eltávolítani, amelyekben több vagy akár az összes érték null? Ezt a beállítást a `dropna` metódusban a `how` és `thresh` paraméterekkel adhatod meg.\n", "\n", - "Alapértelmezés szerint a `how='any'` van beállítva (ha szeretné ellenőrizni, vagy megnézni, milyen más paraméterek érhetők el a metódusban, futtassa a `example4.dropna?` parancsot egy kódcellában). Alternatívaként megadhatja a `how='all'` értéket is, hogy csak azokat a sorokat vagy oszlopokat távolítsa el, amelyekben minden érték null. Bővítsük ki példánk `DataFrame`-jét, hogy a következő gyakorlatban ezt működés közben is láthassuk.\n" + "Alapértelmezés szerint `how='any'` (ha magad szeretnéd ellenőrizni, vagy megnézni, milyen más paraméterek érhetők el a metódusban, futtasd a `example4.dropna?` parancsot egy kódcellában). Alternatívaként megadhatod a `how='all'` értéket, hogy csak azokat a sorokat vagy oszlopokat távolítsd el, amelyekben minden érték null. Bővítsük ki az `DataFrame` példánkat, hogy a következő gyakorlatban láthassuk ezt működés közben.\n" ] }, { @@ -1458,10 +1457,10 @@ }, "source": [ "> Főbb tanulságok: \n", - "1. A null értékek elhagyása csak akkor jó ötlet, ha az adathalmaz elég nagy. \n", - "2. Teljes sorokat vagy oszlopokat el lehet hagyni, ha az adatok nagy része hiányzik. \n", - "3. A `DataFrame.dropna(axis=)` metódus segít a null értékek elhagyásában. Az `axis` argumentum jelzi, hogy sorokat vagy oszlopokat kell-e elhagyni. \n", - "4. A `how` argumentumot is lehet használni. Alapértelmezés szerint az értéke `any`. Ezért csak azokat a sorokat/oszlopokat hagyja el, amelyekben bármilyen null érték található. Be lehet állítani `all` értékre is, hogy csak azokat a sorokat/oszlopokat hagyjuk el, ahol minden érték null. \n" + "1. A hiányzó értékek elhagyása csak akkor jó ötlet, ha az adathalmaz elég nagy. \n", + "2. Teljes sorokat vagy oszlopokat el lehet hagyni, ha az adatok többsége hiányzik. \n", + "3. A `DataFrame.dropna(axis=)` metódus segít a hiányzó értékek elhagyásában. Az `axis` argumentum jelzi, hogy sorokat vagy oszlopokat kell elhagyni. \n", + "4. A `how` argumentum is használható. Alapértelmezés szerint az értéke `any`. Ezért csak azokat a sorokat/oszlopokat hagyja el, amelyekben bármilyen hiányzó érték van. Beállítható `all` értékre is, hogy csak azokat a sorokat/oszlopokat hagyjuk el, ahol minden érték hiányzik. \n" ] }, { @@ -1493,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "A `thresh` paraméter finomabb szabályozást biztosít: megadja, hogy egy sorban vagy oszlopban hány *nem-null* értéknek kell lennie ahhoz, hogy megtartsa.\n" + "A `thresh` paraméter finomabb szabályozást biztosít: megadja, hogy egy sorban vagy oszlopban hány *nem-null* értéknek kell lennie ahhoz, hogy megtartásra kerüljön:\n" ] }, { @@ -1568,7 +1567,7 @@ "id": "fmSFnzZegRsG" }, "source": [ - "Itt az első és az utolsó sor ki lett hagyva, mert csak két nem null értéket tartalmaznak.\n" + "Itt az első és az utolsó sor el lett távolítva, mert csak két nem null értéket tartalmaznak.\n" ] }, { @@ -1579,9 +1578,9 @@ "source": [ "### Hiányzó értékek kitöltése\n", "\n", - "Néha van értelme a hiányzó értékeket olyanokkal pótolni, amelyek érvényesek lehetnek. Több technika is létezik a null értékek kitöltésére. Az első módszer a Domain Knowledge (a dataset alapjául szolgáló téma ismerete) használata, hogy valamilyen módon megközelítsük a hiányzó értékeket.\n", + "Néha érdemes a hiányzó értékeket olyanokkal helyettesíteni, amelyek érvényesek lehetnek. Több módszer is létezik a null értékek kitöltésére. Az első módszer az, hogy Domain Tudást (a dataset alapjául szolgáló témával kapcsolatos ismereteket) használunk a hiányzó értékek valamilyen módon történő becslésére.\n", "\n", - "Használhatod az `isnull` függvényt, hogy ezt helyben elvégezd, de ez fáradságos lehet, különösen, ha sok értéket kell kitölteni. Mivel ez egy nagyon gyakori feladat az adatelemzésben, a pandas biztosítja a `fillna` függvényt, amely egy másolatot ad vissza a `Series` vagy `DataFrame` objektumról, ahol a hiányzó értékeket az általad választott értékekkel helyettesíti. Hozzunk létre egy másik példát egy `Series` objektummal, hogy lássuk, hogyan működik ez a gyakorlatban.\n" + "Használhatod az `isnull` függvényt a kitöltéshez közvetlenül, de ez fárasztó lehet, különösen akkor, ha sok értéket kell pótolni. Mivel ez egy nagyon gyakori feladat az adatelemzésben, a pandas biztosítja a `fillna` függvényt, amely egy másolatot ad vissza a `Series` vagy `DataFrame` objektumról, ahol a hiányzó értékek az általad választott értékkel lettek helyettesítve. Hozzunk létre egy másik példát egy `Series` objektummal, hogy lássuk, hogyan működik ez a gyakorlatban.\n" ] }, { @@ -1591,9 +1590,9 @@ }, "source": [ "### Kategóriális adatok (Nem numerikus)\n", - "Először nézzük meg a nem numerikus adatokat. Az adathalmazokban vannak oszlopok kategóriális adatokkal. Például: Nem, Igaz vagy Hamis stb.\n", + "Először nézzük meg a nem numerikus adatokat. Az adathalmazokban találhatunk oszlopokat kategóriális adatokkal, például nem, igaz vagy hamis stb.\n", "\n", - "A legtöbb ilyen esetben a hiányzó értékeket az oszlop `móduszával` helyettesítjük. Tegyük fel, hogy van 100 adatpontunk, amelyek közül 90 Igaz, 8 Hamis, és 2 nincs kitöltve. Ekkor a hiányzó 2 értéket kitölthetjük Igaz értékkel, figyelembe véve az egész oszlopot.\n", + "A legtöbb ilyen esetben a hiányzó értékeket az oszlop `móduszával` helyettesítjük. Tegyük fel, hogy van 100 adatpontunk, amelyek közül 90 azt mondta, hogy igaz, 8 azt mondta, hogy hamis, és 2 nem adott választ. Ekkor a hiányzó 2 értéket kitölthetjük igazként, figyelembe véve az egész oszlopot.\n", "\n", "Itt ismét használhatunk szakmai ismereteket. Nézzünk egy példát a módusszal való kitöltésre.\n" ] @@ -1700,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Most először találjuk meg a móduszt, mielőtt a `None` értéket kitöltenénk a módusszal.\n" + ] }, { "cell_type": "code", @@ -1735,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Tehát None-t True-ra cseréljük.\n" + ] }, { "cell_type": "code", @@ -1855,16 +1858,16 @@ }, "source": [ "### Numerikus adatok\n", - "Most térjünk rá a numerikus adatokra. Itt két gyakori módszer van a hiányzó értékek pótlására:\n", + "Most térjünk rá a numerikus adatokra. Itt két általános módszer létezik a hiányzó értékek pótlására:\n", "\n", - "1. Sor mediánjával való pótlás\n", - "2. Sor átlagával való pótlás\n", + "1. Helyettesítés a sor mediánjával\n", + "2. Helyettesítés a sor átlagával\n", "\n", - "A mediánnal pótoljuk, ha az adatok ferde eloszlásúak és tartalmaznak kiugró értékeket. Ennek oka, hogy a medián ellenálló a kiugró értékekkel szemben.\n", + "A mediánt használjuk, ha az adatok ferde eloszlásúak és tartalmaznak kiugró értékeket. Ennek oka, hogy a medián ellenálló a kiugró értékekkel szemben.\n", "\n", - "Amikor az adatok normalizáltak, használhatjuk az átlagot, mivel ebben az esetben az átlag és a medián nagyon közel lesz egymáshoz.\n", + "Amikor az adatok normalizáltak, használhatjuk az átlagot, mivel ebben az esetben az átlag és a medián nagyon közel áll egymáshoz.\n", "\n", - "Először vegyünk egy oszlopot, amely normál eloszlású, és töltsük ki a hiányzó értéket az oszlop átlagával.\n" + "Először vegyünk egy oszlopot, amely normál eloszlású, és töltsük ki a hiányzó értékeket az oszlop átlagával.\n" ] }, { @@ -2004,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Kitöltés átlaggal\n" + ] }, { "cell_type": "code", @@ -2113,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Most nézzünk meg egy másik adatkeretet, és ezúttal a None értékeket a oszlop mediánjával fogjuk helyettesíteni.\n" + "Most próbáljunk ki egy másik adatkeretet, és ezúttal a None értékeket a oszlop mediánjával fogjuk helyettesíteni.\n" ] }, { @@ -2253,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Kitöltés mediánnal\n" + ] }, { "cell_type": "code", @@ -2353,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Amint láthatjuk, a NaN értéket a oszlop mediánjával helyettesítették.\n" + "Amint láthatjuk, a NaN értéket a oszlop mediánjával helyettesítettük.\n" ] }, { @@ -2395,7 +2402,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "Kitöltheti az összes null értéket egyetlen értékkel, például `0`:\n" + "Az összes null értéket kitöltheted egyetlen értékkel, például `0`:\n" ] }, { @@ -2436,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Főbb tanulságok: \n", - "1. A hiányzó értékek kitöltését akkor érdemes elvégezni, ha kevés az adat, vagy ha van egy stratégia a hiányzó adatok pótlására. \n", - "2. A hiányzó értékek becslésére felhasználható a szakterületi ismeret. \n", - "3. Kategorikus adatok esetén a hiányzó értékeket többnyire az oszlop móduszával helyettesítik. \n", - "4. Numerikus adatok esetén a hiányzó értékeket általában az oszlopok átlagával (normalizált adathalmazok esetén) vagy mediánjával töltik ki. \n" + "> Főbb tanulságok:\n", + "1. A hiányzó értékek kitöltését akkor érdemes elvégezni, ha kevés adat áll rendelkezésre, vagy ha van egy stratégia a hiányzó adatok pótlására.\n", + "2. A hiányzó értékek becsléséhez felhasználható a szakterületi ismeret.\n", + "3. Kategorikus adatok esetében a hiányzó értékeket általában az oszlop móduszával helyettesítik.\n", + "4. Numerikus adatok esetében a hiányzó értékeket általában az oszlopok átlagával (normalizált adatok esetén) vagy mediánjával töltik ki.\n" ] }, { @@ -2471,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "Kitöltheti a null értékeket **előre kitöltéssel**, ami azt jelenti, hogy az utolsó érvényes értéket használja a null kitöltésére:\n" + "Kitöltheted a null értékeket **előre kitöltéssel**, ami azt jelenti, hogy az utolsó érvényes értéket használod a nullák kitöltésére:\n" ] }, { @@ -2512,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "A következő érvényes értéket **visszafelé kitöltéssel** is terjesztheti, hogy kitöltse a nullát:\n" + "A következő érvényes értéket **visszatöltéssel** is visszafelé terjesztheti, hogy kitöltse a nullát:\n" ] }, { @@ -2554,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "Amint sejtheted, ez ugyanígy működik DataFrame-ekkel, de megadhatsz egy `axis` értéket is, amely mentén kitöltheted a null értékeket:\n" + "Ahogy sejtheted, ez ugyanígy működik DataFrame-ekkel is, de megadhatsz egy `axis` értéket is, amely mentén kitöltheted a null értékeket:\n" ] }, { @@ -2727,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Figyelje meg, hogy amikor egy korábbi érték nem áll rendelkezésre előre kitöltéshez, a null érték megmarad.\n" + "Figyeljük meg, hogy amikor egy korábbi érték nem áll rendelkezésre előre kitöltéshez, a null érték megmarad.\n" ] }, { @@ -2760,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Használhatod kreatívan a `fillna` funkciót. Például nézzük meg újra az `example4`-et, de ezúttal töltsük ki a hiányzó értékeket a `DataFrame` összes értékének átlagával:\n" + "Lehetsz kreatív a `fillna` használatában. Például nézzük meg újra az `example4`-et, de ezúttal töltsük ki a hiányzó értékeket a `DataFrame` összes értékének átlagával:\n" ] }, { @@ -2851,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Figyeld meg, hogy a 3. oszlop továbbra is érték nélküli: az alapértelmezett irány az, hogy az értékeket soronként töltjük ki.\n", + "Figyeld meg, hogy a 3. oszlop továbbra is értéktelen: az alapértelmezett irány az értékek soronkénti kitöltése.\n", "\n", - "> **Tanulság:** Számos módja van a hiányzó értékek kezelésének az adathalmazokban. Az, hogy melyik stratégiát választod (eltávolítás, helyettesítés, vagy akár az, hogyan helyettesíted őket), az adott adatok sajátosságaitól függ. Minél többet foglalkozol és dolgozol adathalmazokkal, annál jobb érzéked lesz a hiányzó értékek kezeléséhez.\n" + "> **Tanulság:** Számos módja van a hiányzó értékek kezelésének az adathalmazokban. Az alkalmazott konkrét stratégia (eltávolítás, helyettesítés, vagy akár az, hogy hogyan helyettesíted őket) az adott adatok sajátosságaitól függ. Minél többet foglalkozol és dolgozol adathalmazokkal, annál jobb érzéked lesz a hiányzó értékek kezeléséhez.\n" ] }, { @@ -2862,11 +2869,11 @@ "id": "bauDnESIl9FH" }, "source": [ - "### Kategorikus adatok kódolása\n", + "### Kategóriális adatok kódolása\n", "\n", - "A gépi tanulási modellek kizárólag számokkal és bármilyen numerikus adattal tudnak dolgozni. Nem tudják megkülönböztetni az \"Igen\"-t a \"Nem\"-től, de a 0 és 1 közötti különbséget már igen. Ezért, miután kitöltöttük a hiányzó értékeket, a kategorikus adatokat valamilyen numerikus formára kell kódolnunk, hogy a modell megértse.\n", + "A gépi tanulási modellek kizárólag számokkal és bármilyen numerikus adattal dolgoznak. Nem tudják megkülönböztetni például az \"Igen\"-t és a \"Nem\"-et, de képesek különbséget tenni 0 és 1 között. Ezért, miután kitöltöttük a hiányzó értékeket, a kategóriális adatokat valamilyen numerikus formára kell kódolni, hogy a modell megértse.\n", "\n", - "A kódolás kétféleképpen végezhető el. Ezeket a következőkben tárgyaljuk.\n" + "A kódolás kétféleképpen végezhető el. A következőkben ezeket fogjuk megvitatni.\n" ] }, { @@ -2875,9 +2882,9 @@ "id": "uDq9SxB7mu5i" }, "source": [ - "**CÍMKEKÓDOLÁS**\n", + "**CÍMKÉK KÓDOLÁSA**\n", "\n", - "A címkekódolás lényege, hogy minden kategóriát egy számra alakítunk. Például, tegyük fel, hogy van egy légitársasági utasokból álló adatállományunk, amely tartalmaz egy oszlopot az utasok osztályával a következő kategóriák közül: ['business class', 'economy class', 'first class']. Ha címkekódolást alkalmazunk, ez átalakul [0,1,2] formára. Nézzünk meg egy példát kóddal. Mivel a következő jegyzetfüzetekben a `scikit-learn` könyvtárat fogjuk tanulni, itt nem fogjuk használni.\n" + "A címkék kódolása lényegében azt jelenti, hogy minden kategóriát egy számra alakítunk. Például, tegyük fel, hogy van egy légitársasági utasokról szóló adatállományunk, amelyben van egy oszlop, amely az utasok osztályát tartalmazza a következők közül: ['business class', 'economy class', 'first class']. Ha címkekódolást alkalmazunk erre, akkor ez [0,1,2]-re alakulna. Nézzünk egy példát kóddal. Mivel a következő jegyzetekben a `scikit-learn` könyvtárat fogjuk tanulni, itt nem fogjuk használni.\n" ] }, { @@ -2985,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Az első oszlop címkéinek kódolásához először meg kell határoznunk egy leképezést, amely minden osztályt egy számhoz rendel, mielőtt kicserélnénk.\n" + "Az 1. oszlop címkéinek kódolásához először meg kell határoznunk egy leképezést, amely minden osztályt egy számhoz rendel, mielőtt kicserélnénk.\n" ] }, { @@ -3087,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Amint láthatjuk, az eredmény megfelel annak, amit vártunk. Tehát mikor használjuk a címke kódolást? A címke kódolást az alábbi esetekben használjuk: \n", - "1. Ha a kategóriák száma nagy \n", - "2. Ha a kategóriák sorrendben vannak. \n" + "Amint láthatjuk, az eredmény megfelel annak, amit vártunk. Tehát mikor használjuk a címke kódolást? A címke kódolást az alábbi esetekben használjuk:\n", + "1. Ha a kategóriák száma nagy\n", + "2. Ha a kategóriák sorrendben vannak.\n" ] }, { @@ -3100,9 +3107,9 @@ "source": [ "**EGY HOT ENCODING**\n", "\n", - "Az egyik kódolási típus az Egy Hot Encoding. Ennél a kódolási típusnál az oszlop minden kategóriája külön oszlopként kerül hozzáadásra, és minden adatpont 0-t vagy 1-et kap attól függően, hogy tartalmazza-e az adott kategóriát. Tehát, ha n különböző kategória van, n oszlop kerül hozzáfűzésre az adatkerethez.\n", + "Az Egy Hot Encoding egy másik típusú kódolás. Ennél a kódolási típusnál az oszlop minden kategóriája külön oszlopként kerül hozzáadásra, és minden adatpont 0-t vagy 1-et kap attól függően, hogy tartalmazza-e az adott kategóriát. Tehát, ha n különböző kategória van, n oszlop kerül hozzáfűzésre az adatkerethez.\n", "\n", - "Például vegyük ugyanazt a repülőgép osztály példát. A kategóriák a következők voltak: ['business class', 'economy class', 'first class']. Ha egy hot encodingot hajtunk végre, a következő három oszlop kerül hozzáadásra az adathalmazhoz: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Például vegyük ugyanazt a repülőgép osztály példát. A kategóriák a következők voltak: ['business class', 'economy class', 'first class']. Ha egy hot kódolást végzünk, a következő három oszlop kerül hozzáadásra az adathalmazhoz: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3210,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "Végezzük el az egyértékű kódolást az első oszlopon\n" + "Végezzük el az egyértékű kódolást az első oszlopon.\n" ] }, { @@ -3344,10 +3351,10 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "Mikor használjuk a one hot encodingot? A one hot encodingot az alábbi esetekben használjuk:\n", + "Mikor használjuk az egyhot kódolást? Az egyhot kódolást az alábbi esetekben alkalmazzuk:\n", "\n", "1. Amikor a kategóriák száma és az adathalmaz mérete kisebb.\n", - "2. Amikor a kategóriák között nincs meghatározott sorrend.\n" + "2. Amikor a kategóriák között nincs különösebb sorrend.\n" ] }, { @@ -3356,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Főbb tanulságok: \n", - "1. Az enkódolás célja, hogy a nem numerikus adatokat numerikus adatokká alakítsa. \n", - "2. Kétféle enkódolás létezik: címkeenkódolás és One Hot enkódolás, amelyek a dataset igényei alapján alkalmazhatók. \n" + "> Főbb tanulságok:\n", + "1. Az kódolás célja, hogy a nem numerikus adatokat numerikus adatokká alakítsa.\n", + "2. Kétféle kódolás létezik: címke kódolás és One Hot kódolás, amelyek a dataset igényei alapján végezhetők el.\n" ] }, { @@ -3369,9 +3376,9 @@ "source": [ "## Duplikált adatok eltávolítása\n", "\n", - "> **Tanulási cél:** Ennek az alfejezetnek a végére képesnek kell lenned azonosítani és eltávolítani a duplikált értékeket a DataFrame-ekből.\n", + "> **Tanulási cél:** Ennek az alfejezetnek a végére képesnek kell lenned azonosítani és eltávolítani a duplikált értékeket DataFrame-ekből.\n", "\n", - "A hiányzó adatok mellett gyakran találkozhatsz duplikált adatokkal is a valós adathalmazokban. Szerencsére a pandas egyszerű eszközöket kínál a duplikált bejegyzések felismerésére és eltávolítására.\n" + "A hiányzó adatok mellett gyakran találkozhatsz duplikált adatokkal a valós adatállományokban. Szerencsére a pandas egyszerű módot kínál a duplikált bejegyzések észlelésére és eltávolítására.\n" ] }, { @@ -3382,7 +3389,7 @@ "source": [ "### Duplikátumok azonosítása: `duplicated`\n", "\n", - "A duplikált értékeket könnyen észlelheted a pandas `duplicated` metódusával, amely egy logikai maszkot ad vissza, jelezve, hogy egy `DataFrame` bejegyzés egy korábbi bejegyzés duplikátuma-e. Hozzunk létre egy újabb példát egy `DataFrame`-re, hogy ezt működés közben lássuk.\n" + "A duplikált értékeket könnyedén felismerheted a pandas `duplicated` metódusával, amely egy logikai maszkot ad vissza, jelezve, hogy egy `DataFrame` bejegyzés egy korábbi bejegyzés duplikátuma-e. Hozzunk létre egy újabb példát `DataFrame`-re, hogy ezt működés közben lássuk.\n" ] }, { @@ -3512,7 +3519,7 @@ }, "source": [ "### Duplikátumok eltávolítása: `drop_duplicates`\n", - "A `drop_duplicates` egyszerűen visszaadja az adatokat egy másolatban, amelyben minden `duplicated` érték `False`:\n" + "A `drop_duplicates` egyszerűen visszaadja az adatokat úgy, hogy minden `duplicated` érték `False`:\n" ] }, { @@ -3595,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Mind a `duplicated`, mind a `drop_duplicates` alapértelmezés szerint az összes oszlopot figyelembe veszi, de megadhatja, hogy csak az `DataFrame` egy oszlopcsoportját vizsgálják:\n" + "Mind a `duplicated`, mind a `drop_duplicates` alapértelmezés szerint az összes oszlopot figyelembe veszi, de megadhatja, hogy csak az `DataFrame` egy oszloprészhalmazát vizsgálják:\n" ] }, { @@ -3671,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Tanulság:** A duplikált adatok eltávolítása szinte minden adat-tudományi projekt alapvető része. A duplikált adatok megváltoztathatják az elemzések eredményeit, és pontatlan eredményeket adhatnak!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Valós adatok minőségi ellenőrzése\n", + "\n", + "> **Tanulási cél:** A szakasz végére képes leszel felismerni és javítani a valós adatok minőségi problémáit, például az ellentmondásos kategóriás értékeket, a szokatlan numerikus értékeket (szélsőséges értékek) és a variációkkal rendelkező duplikált entitásokat.\n", + "\n", + "Bár a hiányzó értékek és az egyértelmű duplikátumok gyakori problémák, a valós adathalmazok gyakran tartalmaznak ennél finomabb hibákat:\n", + "\n", + "1. **Ellentmondásos kategóriás értékek**: Ugyanaz a kategória eltérően van leírva (pl. \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Szokatlan numerikus értékek**: Szélsőséges értékek, amelyek adatbeviteli hibákra utalnak (pl. életkor = 999)\n", + "3. **Közel duplikált sorok**: Olyan rekordok, amelyek ugyanazt az entitást képviselik, de kisebb eltérésekkel\n", + "\n", + "Nézzük meg, milyen technikákkal lehet ezeket a problémákat felismerni és kezelni.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Mintapélda \"Piszkos\" Adatkészlet Létrehozása\n", + "\n", + "Először hozzunk létre egy mintapéldát, amely tartalmazza azokat a problémákat, amelyekkel gyakran találkozunk a valós adatokban:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Az inkonzisztens kategóriás értékek felismerése\n", + "\n", + "Figyeljük meg, hogy a `country` oszlopban ugyanazon országoknak többféle megjelenítése van. Azonosítsuk ezeket az inkonzisztenciákat:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Kategóriák értékeinek standardizálása\n", + "\n", + "Létrehozhatunk egy leképezést ezeknek az értékeknek a standardizálására. Egy egyszerű megközelítés az, hogy kisbetűssé alakítjuk őket, és létrehozunk egy leképezési szótárat:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternatíva: Homályos egyezés használata**\n", + "\n", + "Bonyolultabb esetekben használhatjuk a `rapidfuzz` könyvtárat homályos szövegösszehasonlításra, hogy automatikusan felismerjük a hasonló szövegeket:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Szokatlan numerikus értékek (kiugró értékek) észlelése\n", + "\n", + "Az `age` oszlopban találunk néhány gyanús értéket, például 199 és -5. Használjunk statisztikai módszereket ezeknek a kiugró értékeknek az észlelésére.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Az IQR (Interkvartilis Terjedelem) Módszer Használata\n", + "\n", + "Az IQR módszer egy megbízható statisztikai technika a kiugró értékek azonosítására, amely kevésbé érzékeny a szélsőséges értékekre:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Z-score módszer használata\n", + "\n", + "A Z-score módszer az átlagtól való szórások alapján azonosítja a kiugró értékeket:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Szélsőséges értékek kezelése\n", + "\n", + "Miután azonosítottuk, a szélsőséges értékeket többféleképpen kezelhetjük:\n", + "1. **Eltávolítás**: Töröljük a szélsőséges értékeket tartalmazó sorokat (ha hibásak)\n", + "2. **Korlátozás**: Helyettesítsük határértékekkel\n", + "3. **NaN-nal helyettesítés**: Hiányzó adatként kezeljük, és imputációs technikákat alkalmazunk\n", + "4. **Meghagyás**: Ha jogosan extrém értékek\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Hasonló sorok észlelése\n", + "\n", + "Figyeljük meg, hogy az adatainkban többször szerepel \"John Smith\" kissé eltérő értékekkel. Azonosítsuk a lehetséges duplikátumokat névhasználati hasonlóság alapján.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Közeli duplikátumok keresése homályos egyezéssel\n", + "\n", + "A kifinomultabb duplikátum-észlelés érdekében homályos egyezést használhatunk hasonló nevek megtalálására:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Duplikátumok kezelése\n", + "\n", + "Miután azonosítottad, el kell döntened, hogyan kezeld a duplikátumokat:\n", + "1. **Az első előfordulás megtartása**: Használd a `drop_duplicates(keep='first')` parancsot\n", + "2. **Az utolsó előfordulás megtartása**: Használd a `drop_duplicates(keep='last')` parancsot\n", + "3. **Információk összesítése**: Kombináld az információkat a duplikált sorokból\n", + "4. **Kézi ellenőrzés**: Jelöld meg emberi ellenőrzésre\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Összefoglaló: Teljes adat-tisztítási folyamat\n", + "\n", + "Rakjuk össze mindent egy átfogó tisztítási folyamatba:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Kihívás Gyakorlat\n", + "\n", + "Most rajtad a sor! Az alábbiakban egy új adat sor található, amely több minőségi problémát tartalmaz. Meg tudod:\n", + "\n", + "1. Azonosítani az összes problémát ebben a sorban\n", + "2. Írni kódot minden probléma kijavítására\n", + "3. Hozzáadni a megtisztított sort az adathalmazhoz\n", + "\n", + "Íme a problémás adatok:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Fő tanulságok\n", + "\n", + "1. **Kategóriák következetlensége** gyakori a valós adatokban. Mindig ellenőrizd az egyedi értékeket, és szabványosítsd őket térképezéssel vagy homályos egyezés használatával.\n", + "\n", + "2. **Szélsőséges értékek** jelentősen befolyásolhatják az elemzést. Használj szakmai ismereteket és statisztikai módszereket (IQR, Z-score) a kimutatásukhoz.\n", + "\n", + "3. **Közel azonos duplikátumok** nehezebben észlelhetők, mint a pontos másolatok. Fontold meg a homályos egyezés és az adatok normalizálásának (kisbetűsítés, szóközök eltávolítása) alkalmazását az azonosításukhoz.\n", + "\n", + "4. **Az adattisztítás iteratív folyamat**. Lehet, hogy több technikát kell alkalmaznod, és át kell tekintened az eredményeket, mielőtt véglegesíted a tisztított adatállományt.\n", + "\n", + "5. **Dokumentáld a döntéseidet**. Kövesd nyomon, milyen tisztítási lépéseket alkalmaztál és miért, mivel ez fontos az újraalkothatóság és az átláthatóság szempontjából.\n", + "\n", + "> **Legjobb gyakorlat:** Mindig őrizd meg az eredeti \"piszkos\" adatokat. Soha ne írd felül a forrásadat fájlokat – hozz létre tisztított verziókat egyértelmű elnevezési konvenciókkal, például `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Felelősség kizárása**: \nEz a dokumentum az AI fordítási szolgáltatás, a [Co-op Translator](https://github.com/Azure/co-op-translator) segítségével lett lefordítva. Bár törekszünk a pontosságra, kérjük, vegye figyelembe, hogy az automatikus fordítások hibákat vagy pontatlanságokat tartalmazhatnak. Az eredeti dokumentum az eredeti nyelvén tekintendő hiteles forrásnak. Kritikus információk esetén javasolt professzionális emberi fordítást igénybe venni. Nem vállalunk felelősséget semmilyen félreértésért vagy téves értelmezésért, amely a fordítás használatából eredhet.\n" + "\n---\n\n**Felelősség kizárása**: \nEz a dokumentum az [Co-op Translator](https://github.com/Azure/co-op-translator) AI fordítási szolgáltatás segítségével került lefordításra. Bár törekszünk a pontosságra, kérjük, vegye figyelembe, hogy az automatikus fordítások hibákat vagy pontatlanságokat tartalmazhatnak. Az eredeti dokumentum az eredeti nyelvén tekintendő hiteles forrásnak. Fontos információk esetén javasolt professzionális emberi fordítást igénybe venni. Nem vállalunk felelősséget semmilyen félreértésért vagy téves értelmezésért, amely a fordítás használatából eredhet.\n" ] } ], @@ -3705,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T21:57:32+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:52:43+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "hu" } diff --git a/translations/id/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/id/2-Working-With-Data/08-data-preparation/notebook.ipynb index 28bc3c46..e1e5aac6 100644 --- a/translations/id/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/id/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -12,11 +12,11 @@ "\n", "## Mengeksplorasi informasi `DataFrame`\n", "\n", - "> **Tujuan pembelajaran:** Di akhir subbagian ini, Anda diharapkan merasa nyaman dalam menemukan informasi umum tentang data yang disimpan dalam pandas DataFrames.\n", + "> **Tujuan pembelajaran:** Pada akhir subbagian ini, Anda diharapkan nyaman dalam menemukan informasi umum tentang data yang disimpan dalam pandas DataFrames.\n", "\n", - "Setelah Anda memuat data ke dalam pandas, kemungkinan besar data tersebut akan berada dalam bentuk `DataFrame`. Namun, jika data dalam `DataFrame` Anda memiliki 60.000 baris dan 400 kolom, bagaimana Anda mulai memahami apa yang sedang Anda kerjakan? Untungnya, pandas menyediakan beberapa alat yang praktis untuk dengan cepat melihat informasi keseluruhan tentang sebuah `DataFrame`, selain beberapa baris pertama dan terakhir.\n", + "Setelah Anda memuat data ke dalam pandas, kemungkinan besar data tersebut akan berada dalam bentuk `DataFrame`. Namun, jika data dalam `DataFrame` Anda memiliki 60.000 baris dan 400 kolom, bagaimana Anda mulai memahami apa yang sedang Anda kerjakan? Untungnya, pandas menyediakan beberapa alat yang praktis untuk dengan cepat melihat informasi umum tentang sebuah `DataFrame` selain beberapa baris pertama dan terakhir.\n", "\n", - "Untuk mengeksplorasi fungsi ini, kita akan mengimpor pustaka Python scikit-learn dan menggunakan dataset ikonik yang hampir semua data scientist pernah lihat ratusan kali: dataset *Iris* milik ahli biologi Inggris Ronald Fisher yang digunakan dalam makalahnya tahun 1936 \"The use of multiple measurements in taxonomic problems\":\n" + "Untuk mengeksplorasi fungsi ini, kita akan mengimpor pustaka Python scikit-learn dan menggunakan dataset ikonik yang telah dilihat oleh setiap ilmuwan data ratusan kali: dataset *Iris* milik ahli biologi Inggris Ronald Fisher yang digunakan dalam makalahnya tahun 1936 \"The use of multiple measurements in taxonomic problems\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Kita telah memuat Dataset Iris ke dalam variabel `iris_df`. Sebelum mendalami data, akan sangat berguna untuk mengetahui jumlah data yang kita miliki dan ukuran keseluruhan dataset. Penting untuk melihat seberapa besar volume data yang sedang kita tangani.\n" + "Kami telah memuat Dataset Iris ke dalam variabel `iris_df`. Sebelum mendalami data, akan sangat berguna untuk mengetahui jumlah data yang kita miliki dan ukuran keseluruhan dataset. Penting untuk melihat volume data yang sedang kita hadapi.\n" ] }, { @@ -78,7 +78,7 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Jadi, kita sedang mengolah 150 baris dan 4 kolom data. Setiap baris mewakili satu titik data dan setiap kolom mewakili satu fitur yang terkait dengan kerangka data. Jadi, pada dasarnya ada 150 titik data yang masing-masing memiliki 4 fitur.\n", + "Jadi, kita sedang menangani 150 baris dan 4 kolom data. Setiap baris mewakili satu titik data dan setiap kolom mewakili satu fitur yang terkait dengan kerangka data. Jadi pada dasarnya, ada 150 titik data yang masing-masing memiliki 4 fitur.\n", "\n", "`shape` di sini adalah atribut dari kerangka data dan bukan sebuah fungsi, itulah sebabnya tidak diakhiri dengan sepasang tanda kurung.\n" ] @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Sekarang mari kita bahas 4 kolom data. Apa sebenarnya yang diwakili oleh masing-masing kolom tersebut? Atribut `columns` akan memberikan kita nama-nama kolom dalam dataframe.\n" + "Sekarang mari kita bahas 4 kolom data. Apa sebenarnya yang masing-masing kolom wakili? Atribut `columns` akan memberikan kita nama-nama kolom dalam dataframe.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Seperti yang dapat kita lihat, ada empat(4) kolom. Atribut `columns` memberi tahu kita nama kolom dan pada dasarnya tidak ada yang lain. Atribut ini menjadi penting ketika kita ingin mengidentifikasi fitur yang terdapat dalam dataset.\n" + "Seperti yang dapat kita lihat, ada empat(4) kolom. Atribut `columns` memberi tahu kita nama kolom dan pada dasarnya tidak ada yang lain. Atribut ini menjadi penting ketika kita ingin mengidentifikasi fitur yang dimiliki oleh sebuah dataset.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Jumlah data (diberikan oleh atribut `shape`) dan nama fitur atau kolom (diberikan oleh atribut `columns`) memberikan informasi tentang dataset. Sekarang, kita ingin menggali lebih dalam tentang dataset. Fungsi `DataFrame.info()` sangat berguna untuk ini.\n" + "Jumlah data (diberikan oleh atribut `shape`) dan nama fitur atau kolom (diberikan oleh atribut `columns`) memberikan informasi tentang dataset. Sekarang, kita ingin menggali lebih dalam ke dalam dataset. Fungsi `DataFrame.info()` sangat berguna untuk ini.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Dari sini, kita dapat membuat beberapa pengamatan: \n", - "1. Tipe Data dari setiap kolom: Dalam dataset ini, semua data disimpan sebagai angka floating-point 64-bit. \n", - "2. Jumlah nilai Non-Null: Menangani nilai null adalah langkah penting dalam persiapan data. Hal ini akan ditangani nanti di notebook. \n" + "Dari sini, kita dapat membuat beberapa pengamatan:\n", + "1. Tipe Data dari setiap kolom: Dalam dataset ini, semua data disimpan sebagai angka floating-point 64-bit.\n", + "2. Jumlah nilai Non-Null: Menangani nilai null adalah langkah penting dalam persiapan data. Hal ini akan ditangani nanti di notebook.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Misalkan kita memiliki banyak data numerik dalam dataset kita. Perhitungan statistik univariat seperti rata-rata, median, kuartil, dll. dapat dilakukan pada setiap kolom secara individual. Fungsi `DataFrame.describe()` memberikan kita ringkasan statistik dari kolom-kolom numerik dalam sebuah dataset.\n" + "Misalkan kita memiliki banyak data numerik dalam dataset kita. Perhitungan statistik univariat seperti rata-rata, median, kuartil, dll. dapat dilakukan pada masing-masing kolom secara individual. Fungsi `DataFrame.describe()` memberikan ringkasan statistik dari kolom-kolom numerik dalam sebuah dataset.\n" ] }, { @@ -334,7 +334,7 @@ "### `DataFrame.head`\n", "Dengan semua fungsi dan atribut di atas, kita telah mendapatkan gambaran umum tentang dataset. Kita tahu berapa banyak data yang ada, berapa banyak fitur yang ada, tipe data dari setiap fitur, dan jumlah nilai non-null untuk setiap fitur.\n", "\n", - "Sekarang saatnya melihat data itu sendiri. Mari kita lihat seperti apa beberapa baris pertama (beberapa titik data pertama) dari `DataFrame` kita:\n" + "Sekarang saatnya melihat datanya sendiri. Mari kita lihat seperti apa beberapa baris pertama (beberapa data pertama) dari `DataFrame` kita:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Sebagai output di sini, kita dapat melihat lima(5) entri dari dataset. Jika kita melihat indeks di sebelah kiri, kita menemukan bahwa ini adalah lima baris pertama.\n" + "Sebagai output di sini, kita dapat melihat lima (5) entri dari dataset. Jika kita melihat indeks di sebelah kiri, kita menemukan bahwa ini adalah lima baris pertama.\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Cara lain untuk melihat data adalah dari bagian akhir (bukan dari awal). Kebalikan dari `DataFrame.head` adalah `DataFrame.tail`, yang mengembalikan lima baris terakhir dari sebuah `DataFrame`:\n" + "Cara lain untuk melihat data adalah dari akhir (bukan dari awal). Kebalikan dari `DataFrame.head` adalah `DataFrame.tail`, yang mengembalikan lima baris terakhir dari sebuah `DataFrame`:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "Dalam praktiknya, sangat berguna untuk dapat dengan mudah memeriksa beberapa baris pertama atau beberapa baris terakhir dari sebuah `DataFrame`, terutama ketika Anda mencari nilai-nilai yang tidak biasa dalam dataset yang terurut.\n", + "Dalam praktiknya, sangat berguna untuk dapat dengan mudah memeriksa beberapa baris pertama atau beberapa baris terakhir dari sebuah `DataFrame`, terutama ketika Anda mencari nilai outlier dalam dataset yang terurut.\n", "\n", "Semua fungsi dan atribut yang ditunjukkan di atas dengan bantuan contoh kode membantu kita mendapatkan gambaran dan pemahaman tentang data.\n", "\n", - "> **Kesimpulan:** Bahkan hanya dengan melihat metadata tentang informasi dalam sebuah DataFrame atau beberapa nilai pertama dan terakhir di dalamnya, Anda dapat langsung mendapatkan gambaran tentang ukuran, bentuk, dan isi data yang sedang Anda hadapi.\n" + "> **Kesimpulan:** Bahkan hanya dengan melihat metadata tentang informasi dalam sebuah DataFrame atau beberapa nilai pertama dan terakhir di dalamnya, Anda dapat langsung mendapatkan gambaran tentang ukuran, bentuk, dan isi data yang sedang Anda tangani.\n" ] }, { @@ -598,15 +598,15 @@ "### Data yang Hilang\n", "Mari kita bahas tentang data yang hilang. Data yang hilang terjadi ketika tidak ada nilai yang disimpan di beberapa kolom.\n", "\n", - "Mari kita ambil contoh: misalnya seseorang sangat peduli dengan berat badannya dan tidak mengisi kolom berat badan dalam sebuah survei. Maka, nilai berat badan untuk orang tersebut akan hilang.\n", + "Mari kita ambil contoh: misalnya seseorang sangat memperhatikan berat badannya dan tidak mengisi kolom berat badan dalam sebuah survei. Maka, nilai berat badan untuk orang tersebut akan hilang.\n", "\n", "Sebagian besar waktu, dalam dataset dunia nyata, nilai yang hilang sering terjadi.\n", "\n", "**Bagaimana Pandas Menangani Data yang Hilang**\n", "\n", - "Pandas menangani nilai yang hilang dengan dua cara. Cara pertama sudah pernah Anda lihat di bagian sebelumnya: `NaN`, atau Not a Number. Ini sebenarnya adalah nilai khusus yang merupakan bagian dari spesifikasi floating-point IEEE dan hanya digunakan untuk menunjukkan nilai floating-point yang hilang.\n", + "Pandas menangani nilai yang hilang dengan dua cara. Cara pertama yang sudah pernah Anda lihat di bagian sebelumnya adalah `NaN`, atau Not a Number. Ini sebenarnya adalah nilai khusus yang merupakan bagian dari spesifikasi floating-point IEEE dan hanya digunakan untuk menunjukkan nilai floating-point yang hilang.\n", "\n", - "Untuk nilai yang hilang selain tipe float, pandas menggunakan objek Python `None`. Meskipun mungkin terlihat membingungkan bahwa Anda akan menemukan dua jenis nilai yang pada dasarnya mengatakan hal yang sama, ada alasan programatik yang kuat untuk pilihan desain ini dan, dalam praktiknya, pendekatan ini memungkinkan pandas memberikan kompromi yang baik untuk sebagian besar kasus. Meskipun demikian, baik `None` maupun `NaN` memiliki batasan yang perlu Anda perhatikan terkait bagaimana mereka dapat digunakan.\n" + "Untuk nilai yang hilang selain tipe float, pandas menggunakan objek Python `None`. Meskipun mungkin terlihat membingungkan bahwa Anda akan menemukan dua jenis nilai yang pada dasarnya menyampaikan hal yang sama, ada alasan programatik yang kuat untuk pilihan desain ini, dan dalam praktiknya, pendekatan ini memungkinkan pandas memberikan kompromi yang baik untuk sebagian besar kasus. Meskipun demikian, baik `None` maupun `NaN` memiliki batasan yang perlu Anda perhatikan terkait bagaimana mereka dapat digunakan.\n" ] }, { @@ -616,7 +616,7 @@ }, "source": [ "### `None`: data hilang non-float\n", - "Karena `None` berasal dari Python, nilai ini tidak dapat digunakan dalam array NumPy dan pandas yang bukan bertipe data `'object'`. Ingatlah, array NumPy (dan struktur data dalam pandas) hanya dapat berisi satu jenis data. Hal ini memberikan kekuatan besar untuk pekerjaan data dan komputasi berskala besar, tetapi juga membatasi fleksibilitasnya. Array semacam itu harus diubah ke \"denominator terendah,\" yaitu tipe data yang dapat mencakup semua elemen dalam array. Ketika `None` ada di dalam array, itu berarti Anda sedang bekerja dengan objek Python.\n", + "Karena `None` berasal dari Python, ia tidak dapat digunakan dalam array NumPy dan pandas yang bukan bertipe data `'object'`. Ingat, array NumPy (dan struktur data dalam pandas) hanya dapat berisi satu jenis data. Inilah yang memberikan kekuatan besar untuk pekerjaan data dan komputasi skala besar, tetapi juga membatasi fleksibilitasnya. Array semacam itu harus diubah ke \"penyebut umum terendah,\" yaitu tipe data yang dapat mencakup semua elemen dalam array. Ketika `None` ada dalam array, itu berarti Anda sedang bekerja dengan objek Python.\n", "\n", "Untuk melihat ini dalam praktik, perhatikan contoh array berikut (perhatikan `dtype` untuk array tersebut):\n" ] @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Realitas dari tipe data upcast membawa dua efek samping bersamanya. Pertama, operasi akan dilakukan pada tingkat kode Python yang diinterpretasikan daripada kode NumPy yang dikompilasi. Pada dasarnya, ini berarti bahwa operasi apa pun yang melibatkan `Series` atau `DataFrame` dengan `None` di dalamnya akan lebih lambat. Meskipun Anda mungkin tidak menyadari penurunan kinerja ini, untuk dataset yang besar, hal ini bisa menjadi masalah.\n", + "Realitas tipe data yang di-upcast membawa dua efek samping bersamanya. Pertama, operasi akan dilakukan pada tingkat kode Python yang diinterpretasikan daripada kode NumPy yang dikompilasi. Pada dasarnya, ini berarti bahwa setiap operasi yang melibatkan `Series` atau `DataFrames` dengan `None` di dalamnya akan lebih lambat. Meskipun Anda mungkin tidak menyadari penurunan kinerja ini, untuk dataset yang besar, hal ini bisa menjadi masalah.\n", "\n", - "Efek samping kedua berasal dari yang pertama. Karena `None` pada dasarnya menarik `Series` atau `DataFrame` kembali ke dunia Python biasa, menggunakan agregasi NumPy/pandas seperti `sum()` atau `min()` pada array yang mengandung nilai ``None`` umumnya akan menghasilkan error:\n" + "Efek samping kedua berasal dari yang pertama. Karena `None` pada dasarnya membawa `Series` atau `DataFrame` kembali ke dunia Python biasa, menggunakan agregasi NumPy/pandas seperti `sum()` atau `min()` pada array yang mengandung nilai ``None`` umumnya akan menghasilkan error:\n" ] }, { @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Kesimpulan utama**: Penjumlahan (dan operasi lainnya) antara bilangan bulat dan nilai `None` tidak terdefinisi, yang dapat membatasi apa yang dapat Anda lakukan dengan kumpulan data yang mengandungnya.\n" + "**Inti utama**: Penjumlahan (dan operasi lainnya) antara bilangan bulat dan nilai `None` tidak terdefinisi, yang dapat membatasi apa yang dapat Anda lakukan dengan kumpulan data yang mengandungnya.\n" ] }, { @@ -709,7 +709,7 @@ "source": [ "### `NaN`: nilai float yang hilang\n", "\n", - "Berbeda dengan `None`, NumPy (dan oleh karena itu pandas) mendukung `NaN` untuk operasi vektorisasi dan ufuncs yang cepat. Berita buruknya adalah bahwa setiap operasi aritmatika yang dilakukan pada `NaN` selalu menghasilkan `NaN`. Sebagai contoh:\n" + "Berbeda dengan `None`, NumPy (dan oleh karena itu pandas) mendukung `NaN` untuk operasi vektorisasi yang cepat dan ufuncs. Berita buruknya adalah bahwa setiap operasi aritmatika yang dilakukan pada `NaN` selalu menghasilkan `NaN`. Sebagai contoh:\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Kabar baiknya: agregasi yang dijalankan pada array dengan `NaN` di dalamnya tidak menghasilkan error. Kabar buruknya: hasilnya tidak selalu berguna:\n" + "Berita baiknya: agregasi yang dijalankan pada array dengan `NaN` di dalamnya tidak menghasilkan error. Berita buruknya: hasilnya tidak selalu berguna:\n" ] }, { @@ -830,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "Ingat: `NaN` hanya untuk nilai floating-point yang hilang; tidak ada padanan `NaN` untuk bilangan bulat, string, atau Boolean.\n" + ] }, { "cell_type": "markdown", @@ -904,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Dalam proses menaikkan tipe data untuk memastikan keseragaman data dalam `Series` dan `DataFrame`, pandas dengan mudah akan mengganti nilai yang hilang antara `None` dan `NaN`. Karena fitur desain ini, akan membantu jika kita memandang `None` dan `NaN` sebagai dua jenis \"null\" yang berbeda dalam pandas. Memang, beberapa metode inti yang akan Anda gunakan untuk menangani nilai yang hilang di pandas mencerminkan gagasan ini dalam nama mereka:\n", + "Dalam proses menaikkan tipe data untuk memastikan keseragaman data dalam `Series` dan `DataFrame`, pandas dengan mudah mengganti nilai yang hilang antara `None` dan `NaN`. Karena fitur desain ini, akan membantu jika kita memandang `None` dan `NaN` sebagai dua jenis \"null\" yang berbeda dalam pandas. Bahkan, beberapa metode inti yang akan Anda gunakan untuk menangani nilai yang hilang dalam pandas mencerminkan ide ini dalam nama mereka:\n", "\n", "- `isnull()`: Menghasilkan masker Boolean yang menunjukkan nilai yang hilang\n", "- `notnull()`: Kebalikan dari `isnull()`\n", "- `dropna()`: Mengembalikan versi data yang telah difilter\n", "- `fillna()`: Mengembalikan salinan data dengan nilai yang hilang diisi atau diimputasi\n", "\n", - "Metode-metode ini penting untuk dikuasai dan dipahami dengan baik, jadi mari kita bahas masing-masing secara mendalam.\n" + "Metode-metode ini sangat penting untuk dikuasai dan dipahami dengan baik, jadi mari kita bahas masing-masing secara mendalam.\n" ] }, { @@ -922,8 +924,8 @@ "source": [ "### Mendeteksi nilai null\n", "\n", - "Sekarang setelah kita memahami pentingnya nilai yang hilang, kita perlu mendeteksinya dalam dataset kita sebelum menanganinya. \n", - "Baik `isnull()` maupun `notnull()` adalah metode utama Anda untuk mendeteksi data null. Keduanya mengembalikan masker Boolean pada data Anda.\n" + "Setelah kita memahami pentingnya nilai yang hilang, kita perlu mendeteksinya dalam dataset kita sebelum mengatasinya. \n", + "Baik `isnull()` maupun `notnull()` adalah metode utama untuk mendeteksi data null. Keduanya mengembalikan masker Boolean pada data Anda.\n" ] }, { @@ -976,9 +978,9 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Perhatikan baik-baik hasilnya. Apakah ada yang mengejutkan Anda? Meskipun `0` adalah nilai nol dalam aritmatika, itu tetap merupakan bilangan bulat yang valid, dan pandas memperlakukannya seperti itu. `''` sedikit lebih halus. Meskipun kita menggunakannya di Bagian 1 untuk merepresentasikan nilai string kosong, itu tetap merupakan objek string dan bukan representasi null sejauh yang pandas ketahui.\n", + "Perhatikan dengan seksama hasilnya. Apakah ada yang mengejutkan Anda? Meskipun `0` adalah nol aritmatika, itu tetap merupakan bilangan bulat yang valid dan pandas memperlakukannya seperti itu. `''` sedikit lebih rumit. Meskipun kita menggunakannya di Bagian 1 untuk mewakili nilai string kosong, itu tetap merupakan objek string dan bukan representasi null sejauh yang pandas ketahui.\n", "\n", - "Sekarang, mari kita balikkan situasi ini dan gunakan metode-metode ini dengan cara yang lebih mirip dengan bagaimana Anda akan menggunakannya dalam praktik. Anda dapat menggunakan masker Boolean langsung sebagai indeks ``Series`` atau ``DataFrame``, yang bisa berguna saat mencoba bekerja dengan nilai yang hilang (atau ada) secara terisolasi.\n", + "Sekarang, mari kita balikkan ini dan gunakan metode-metode ini dengan cara yang lebih mirip dengan bagaimana Anda akan menggunakannya dalam praktik. Anda dapat menggunakan masker Boolean langsung sebagai indeks ``Series`` atau ``DataFrame``, yang bisa berguna saat mencoba bekerja dengan nilai yang hilang (atau ada) secara terpisah.\n", "\n", "Jika kita ingin jumlah total nilai yang hilang, kita cukup melakukan penjumlahan pada masker yang dihasilkan oleh metode `isnull()`.\n" ] @@ -1047,20 +1049,20 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### Menangani Data yang Hilang\n", + "### Menangani data yang hilang\n", "\n", - "> **Tujuan pembelajaran:** Di akhir subbagian ini, Anda seharusnya memahami bagaimana dan kapan mengganti atau menghapus nilai null dari DataFrame.\n", + "> **Tujuan pembelajaran:** Pada akhir bagian ini, Anda harus mengetahui cara dan kapan mengganti atau menghapus nilai null dari DataFrames.\n", "\n", - "Model Machine Learning tidak dapat menangani data yang hilang secara langsung. Oleh karena itu, sebelum data dimasukkan ke dalam model, kita perlu menangani nilai-nilai yang hilang ini.\n", + "Model Machine Learning tidak dapat menangani data yang hilang secara langsung. Oleh karena itu, sebelum memberikan data ke model, kita perlu menangani nilai-nilai yang hilang ini.\n", "\n", - "Cara menangani data yang hilang memiliki kompromi yang halus, dapat memengaruhi analisis akhir Anda dan hasil di dunia nyata.\n", + "Cara menangani data yang hilang memiliki pertimbangan yang cukup rumit, dapat memengaruhi analisis akhir Anda dan hasil di dunia nyata.\n", "\n", "Ada dua cara utama untuk menangani data yang hilang:\n", "\n", "1. Menghapus baris yang mengandung nilai yang hilang\n", "2. Mengganti nilai yang hilang dengan nilai lain\n", "\n", - "Kita akan membahas kedua metode ini beserta kelebihan dan kekurangannya secara mendetail.\n" + "Kita akan membahas kedua metode ini beserta kelebihan dan kekurangannya secara rinci.\n" ] }, { @@ -1071,11 +1073,11 @@ "source": [ "### Menghapus nilai null\n", "\n", - "Jumlah data yang kita masukkan ke model memiliki pengaruh langsung terhadap kinerjanya. Menghapus nilai null berarti kita mengurangi jumlah data, sehingga mengurangi ukuran dataset. Oleh karena itu, disarankan untuk menghapus baris dengan nilai null ketika dataset cukup besar.\n", + "Jumlah data yang kita berikan kepada model memiliki pengaruh langsung terhadap kinerjanya. Menghapus nilai null berarti kita mengurangi jumlah data, sehingga mengurangi ukuran dataset. Oleh karena itu, disarankan untuk menghapus baris dengan nilai null ketika dataset cukup besar.\n", "\n", - "Contoh lainnya adalah ketika sebuah baris atau kolom tertentu memiliki banyak nilai yang hilang. Dalam kasus ini, baris atau kolom tersebut mungkin dihapus karena tidak akan memberikan banyak nilai tambah pada analisis kita, mengingat sebagian besar datanya hilang.\n", + "Contoh lainnya adalah ketika sebuah baris atau kolom memiliki banyak nilai yang hilang. Dalam kasus ini, baris atau kolom tersebut mungkin dihapus karena tidak akan memberikan banyak nilai pada analisis kita, mengingat sebagian besar datanya hilang.\n", "\n", - "Selain mengidentifikasi nilai yang hilang, pandas menyediakan cara yang praktis untuk menghapus nilai null dari `Series` dan `DataFrame`. Untuk melihat ini dalam praktik, mari kita kembali ke `example3`. Fungsi `DataFrame.dropna()` membantu menghapus baris dengan nilai null.\n" + "Selain mengidentifikasi nilai yang hilang, pandas menyediakan cara yang praktis untuk menghapus nilai null dari `Series` dan `DataFrame`. Untuk melihat cara kerjanya, mari kita kembali ke `example3`. Fungsi `DataFrame.dropna()` membantu dalam menghapus baris dengan nilai null.\n" ] }, { @@ -1114,7 +1116,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "Perhatikan bahwa ini seharusnya terlihat seperti output dari `example3[example3.notnull()]`. Perbedaannya di sini adalah, alih-alih hanya melakukan pengindeksan pada nilai yang dimask, `dropna` telah menghapus nilai yang hilang dari `Series` `example3`.\n", + "Perhatikan bahwa ini seharusnya terlihat seperti output dari `example3[example3.notnull()]`. Perbedaannya di sini adalah, alih-alih hanya melakukan pengindeksan pada nilai yang dimask, `dropna` telah menghapus nilai-nilai yang hilang dari `Series` `example3`.\n", "\n", "Karena DataFrame memiliki dua dimensi, mereka memberikan lebih banyak opsi untuk menghapus data.\n" ] @@ -1206,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Apakah Anda memperhatikan bahwa pandas mengubah tipe dua kolom menjadi float untuk mengakomodasi `NaN`?)\n", + "(Apakah Anda menyadari bahwa pandas mengubah tipe dua kolom menjadi float untuk menyesuaikan dengan `NaN`?)\n", "\n", - "Anda tidak dapat menghapus satu nilai saja dari sebuah `DataFrame`, jadi Anda harus menghapus seluruh baris atau kolom. Tergantung pada apa yang Anda lakukan, Anda mungkin ingin memilih salah satu dari keduanya, dan karena itu pandas memberikan opsi untuk keduanya. Karena dalam ilmu data, kolom umumnya mewakili variabel dan baris mewakili observasi, Anda lebih mungkin untuk menghapus baris data; pengaturan default untuk `dropna()` adalah menghapus semua baris yang mengandung nilai null:\n" + "Anda tidak dapat menghapus satu nilai dari sebuah `DataFrame`, jadi Anda harus menghapus seluruh baris atau kolom. Bergantung pada apa yang Anda lakukan, Anda mungkin ingin memilih salah satu dari keduanya, dan pandas memberikan opsi untuk keduanya. Karena dalam ilmu data, kolom umumnya mewakili variabel dan baris mewakili observasi, Anda lebih mungkin untuk menghapus baris data; pengaturan default untuk `dropna()` adalah menghapus semua baris yang mengandung nilai null:\n" ] }, { @@ -1360,7 +1362,7 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Perhatikan bahwa ini dapat menghilangkan banyak data yang mungkin ingin Anda simpan, terutama dalam dataset yang lebih kecil. Bagaimana jika Anda hanya ingin menghapus baris atau kolom yang mengandung beberapa atau bahkan semua nilai null? Anda dapat menentukan pengaturan tersebut dalam `dropna` dengan parameter `how` dan `thresh`.\n", + "Perhatikan bahwa ini dapat menghapus banyak data yang mungkin ingin Anda simpan, terutama dalam dataset yang lebih kecil. Bagaimana jika Anda hanya ingin menghapus baris atau kolom yang mengandung beberapa atau bahkan semua nilai null? Anda dapat menentukan pengaturan tersebut dalam `dropna` dengan parameter `how` dan `thresh`.\n", "\n", "Secara default, `how='any'` (jika Anda ingin memeriksa sendiri atau melihat parameter lain yang dimiliki metode ini, jalankan `example4.dropna?` dalam sel kode). Sebagai alternatif, Anda dapat menentukan `how='all'` untuk hanya menghapus baris atau kolom yang mengandung semua nilai null. Mari kita perluas contoh `DataFrame` kita untuk melihat ini dalam aksi pada latihan berikutnya.\n" ] @@ -1458,7 +1460,7 @@ "1. Menghapus nilai null adalah ide yang baik hanya jika dataset cukup besar. \n", "2. Baris atau kolom penuh dapat dihapus jika sebagian besar datanya hilang. \n", "3. Metode `DataFrame.dropna(axis=)` membantu dalam menghapus nilai null. Argumen `axis` menunjukkan apakah baris atau kolom yang akan dihapus. \n", - "4. Argumen `how` juga dapat digunakan. Secara default, nilainya diatur ke `any`. Jadi, hanya baris/kolom yang mengandung nilai null yang akan dihapus. Nilai ini dapat diatur ke `all` untuk menentukan bahwa kita hanya akan menghapus baris/kolom di mana semua nilainya null. \n" + "4. Argumen `how` juga dapat digunakan. Secara default, nilainya diatur ke `any`. Jadi, hanya baris/kolom yang mengandung nilai null yang akan dihapus. Nilainya dapat diatur ke `all` untuk menentukan bahwa kita hanya akan menghapus baris/kolom di mana semua nilainya null. \n" ] }, { @@ -1490,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "Parameter `thresh` memberi Anda kontrol yang lebih rinci: Anda menetapkan jumlah nilai *non-null* yang harus dimiliki oleh sebuah baris atau kolom agar tetap dipertahankan:\n" + "Parameter `thresh` memberikan kontrol yang lebih rinci: Anda menetapkan jumlah nilai *non-null* yang harus dimiliki oleh sebuah baris atau kolom agar tetap dipertahankan:\n" ] }, { @@ -1576,9 +1578,9 @@ "source": [ "### Mengisi Nilai Null\n", "\n", - "Terkadang masuk akal untuk mengisi nilai yang hilang dengan nilai yang mungkin valid. Ada beberapa teknik untuk mengisi nilai null. Yang pertama adalah menggunakan Pengetahuan Domain (pengetahuan tentang subjek yang menjadi dasar dataset) untuk memperkirakan nilai yang hilang.\n", + "Kadang-kadang masuk akal untuk mengisi nilai yang hilang dengan nilai yang mungkin valid. Ada beberapa teknik untuk mengisi nilai null. Yang pertama adalah menggunakan Pengetahuan Domain (pengetahuan tentang subjek yang menjadi dasar dataset) untuk memperkirakan nilai yang hilang.\n", "\n", - "Anda bisa menggunakan `isnull` untuk melakukan ini secara langsung, tetapi itu bisa melelahkan, terutama jika Anda memiliki banyak nilai yang harus diisi. Karena ini adalah tugas yang sangat umum dalam data science, pandas menyediakan `fillna`, yang mengembalikan salinan `Series` atau `DataFrame` dengan nilai yang hilang diganti dengan nilai pilihan Anda. Mari kita buat contoh `Series` lain untuk melihat bagaimana ini bekerja dalam praktik.\n" + "Anda bisa menggunakan `isnull` untuk melakukan ini secara langsung, tetapi itu bisa melelahkan, terutama jika Anda memiliki banyak nilai yang harus diisi. Karena ini adalah tugas yang sangat umum dalam ilmu data, pandas menyediakan `fillna`, yang mengembalikan salinan dari `Series` atau `DataFrame` dengan nilai yang hilang diganti dengan nilai pilihan Anda. Mari kita buat contoh `Series` lain untuk melihat bagaimana ini bekerja dalam praktik.\n" ] }, { @@ -1590,9 +1592,9 @@ "### Data Kategorikal (Non-numerik)\n", "Pertama, mari kita bahas data non-numerik. Dalam dataset, kita memiliki kolom dengan data kategorikal. Contohnya: Jenis Kelamin, Benar atau Salah, dll.\n", "\n", - "Dalam sebagian besar kasus ini, kita mengganti nilai yang hilang dengan `modus` dari kolom tersebut. Misalnya, kita memiliki 100 data, di mana 90 mengatakan Benar, 8 mengatakan Salah, dan 2 tidak diisi. Maka, kita dapat mengisi 2 data yang kosong dengan Benar, dengan mempertimbangkan keseluruhan kolom.\n", + "Dalam sebagian besar kasus ini, kita mengganti nilai yang hilang dengan `modus` dari kolom tersebut. Misalnya, kita memiliki 100 data, di mana 90 mengatakan Benar, 8 mengatakan Salah, dan 2 tidak mengisi. Maka, kita dapat mengisi 2 data yang kosong dengan Benar, dengan mempertimbangkan seluruh kolom.\n", "\n", - "Sekali lagi, di sini kita juga dapat menggunakan pengetahuan domain. Mari kita lihat contoh pengisian dengan modus.\n" + "Sekali lagi, di sini kita dapat menggunakan pengetahuan domain. Mari kita lihat contoh pengisian dengan modus.\n" ] }, { @@ -1697,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Sekarang, mari kita cari modus terlebih dahulu sebelum mengisi nilai `None` dengan modus.\n" + ] }, { "cell_type": "code", @@ -1732,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Jadi, kita akan mengganti None dengan True\n" + ] }, { "cell_type": "code", @@ -1842,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Seperti yang kita lihat, nilai null telah digantikan. Tidak perlu dikatakan, kita bisa menulis apa saja sebagai pengganti `'True'` dan itu akan tersubstitusi.\n" + "Seperti yang dapat kita lihat, nilai null telah digantikan. Tidak perlu dikatakan, kita bisa saja menulis apa pun sebagai pengganti atau `'True'` dan itu akan tersubstitusi.\n" ] }, { @@ -1852,14 +1858,14 @@ }, "source": [ "### Data Numerik\n", - "Sekarang, mari kita bahas tentang data numerik. Di sini, ada dua cara umum untuk menggantikan nilai yang hilang:\n", + "Sekarang, kita beralih ke data numerik. Di sini, ada dua cara umum untuk mengganti nilai yang hilang:\n", "\n", "1. Mengganti dengan Median dari baris\n", "2. Mengganti dengan Mean dari baris\n", "\n", - "Kita mengganti dengan Median jika datanya memiliki distribusi yang miring dengan outlier. Hal ini karena median lebih tahan terhadap outlier.\n", + "Kita mengganti dengan Median jika data memiliki distribusi yang miring dengan outlier. Hal ini karena median lebih tahan terhadap outlier.\n", "\n", - "Ketika data sudah dinormalisasi, kita dapat menggunakan mean, karena dalam kasus tersebut, mean dan median akan cukup dekat.\n", + "Ketika data sudah dinormalisasi, kita bisa menggunakan mean, karena dalam kasus tersebut, mean dan median akan cukup dekat.\n", "\n", "Pertama, mari kita ambil sebuah kolom yang terdistribusi normal dan isi nilai yang hilang dengan mean dari kolom tersebut.\n" ] @@ -2001,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Mengisi dengan rata-rata\n" + ] }, { "cell_type": "code", @@ -2250,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Mengisi dengan median\n" + ] }, { "cell_type": "code", @@ -2350,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Seperti yang dapat kita lihat, nilai NaN telah digantikan oleh median dari kolom\n" + "Seperti yang kita lihat, nilai NaN telah digantikan oleh median dari kolom.\n" ] }, { @@ -2436,7 +2446,7 @@ "> Poin-poin penting:\n", "1. Mengisi nilai yang hilang sebaiknya dilakukan ketika data yang tersedia sedikit atau ada strategi untuk mengisi data yang hilang.\n", "2. Pengetahuan domain dapat digunakan untuk mengisi nilai yang hilang dengan cara memperkirakannya.\n", - "3. Untuk data kategorikal, biasanya nilai yang hilang digantikan dengan modus dari kolom tersebut.\n", + "3. Untuk data kategorikal, biasanya nilai yang hilang diganti dengan modus dari kolom tersebut.\n", "4. Untuk data numerik, nilai yang hilang biasanya diisi dengan rata-rata (untuk dataset yang sudah dinormalisasi) atau median dari kolom tersebut.\n" ] }, @@ -2468,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "Anda dapat **forward-fill** nilai null, yaitu menggunakan nilai valid terakhir untuk mengisi null:\n" + "Anda dapat **mengisi ke depan** nilai null, yaitu menggunakan nilai valid terakhir untuk mengisi null:\n" ] }, { @@ -2551,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "Seperti yang mungkin Anda tebak, ini bekerja dengan cara yang sama pada DataFrame, tetapi Anda juga dapat menentukan `axis` untuk mengisi nilai null:\n" + "Seperti yang mungkin Anda duga, ini bekerja sama dengan DataFrame, tetapi Anda juga dapat menentukan `axis` sepanjang mana untuk mengisi nilai null:\n" ] }, { @@ -2757,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Anda dapat menjadi kreatif dalam menggunakan `fillna`. Sebagai contoh, mari kita lihat kembali `example4`, tetapi kali ini mari kita isi nilai yang hilang dengan rata-rata dari semua nilai dalam `DataFrame`:\n" + "Anda dapat menjadi kreatif dalam menggunakan `fillna`. Sebagai contoh, mari kita lihat kembali `example4`, tetapi kali ini kita isi nilai yang hilang dengan rata-rata dari semua nilai dalam `DataFrame`:\n" ] }, { @@ -2848,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Perhatikan bahwa kolom 3 masih tidak memiliki nilai: arah defaultnya adalah mengisi nilai secara baris demi baris.\n", + "Perhatikan bahwa kolom 3 masih tidak memiliki nilai: arah default adalah mengisi nilai secara baris demi baris.\n", "\n", - "> **Intisari:** Ada berbagai cara untuk menangani nilai yang hilang dalam dataset Anda. Strategi spesifik yang Anda gunakan (menghapusnya, menggantinya, atau bahkan bagaimana Anda menggantinya) harus ditentukan oleh karakteristik data tersebut. Anda akan mengembangkan pemahaman yang lebih baik tentang cara menangani nilai yang hilang seiring dengan semakin seringnya Anda bekerja dan berinteraksi dengan dataset.\n" + "> **Kesimpulan:** Ada berbagai cara untuk menangani nilai yang hilang dalam dataset Anda. Strategi spesifik yang Anda gunakan (menghapusnya, menggantinya, atau bahkan bagaimana Anda menggantinya) harus ditentukan oleh karakteristik data tersebut. Anda akan semakin memahami cara menangani nilai yang hilang seiring dengan semakin seringnya Anda bekerja dan berinteraksi dengan dataset.\n" ] }, { @@ -2872,9 +2882,9 @@ "id": "uDq9SxB7mu5i" }, "source": [ - "**PENGODEAN LABEL** \n", + "**PENGKODEAN LABEL**\n", "\n", - "Pengodean label pada dasarnya adalah mengonversi setiap kategori menjadi sebuah angka. Sebagai contoh, misalkan kita memiliki dataset penumpang pesawat dan terdapat sebuah kolom yang berisi kelas mereka di antara ['business class', 'economy class', 'first class']. Jika pengodean label dilakukan pada kolom ini, maka akan diubah menjadi [0,1,2]. Mari kita lihat contohnya melalui kode. Karena kita akan mempelajari `scikit-learn` di notebook berikutnya, kita tidak akan menggunakannya di sini.\n" + "Pengkodean label pada dasarnya adalah mengubah setiap kategori menjadi angka. Sebagai contoh, misalkan kita memiliki dataset penumpang pesawat dan terdapat kolom yang berisi kelas mereka di antara ['kelas bisnis', 'kelas ekonomi', 'kelas pertama']. Jika pengkodean label dilakukan pada data ini, maka akan diubah menjadi [0,1,2]. Mari kita lihat contohnya melalui kode. Karena kita akan mempelajari `scikit-learn` di notebook berikutnya, kita tidak akan menggunakannya di sini.\n" ] }, { @@ -2982,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Untuk melakukan label encoding pada kolom pertama, kita harus terlebih dahulu mendeskripsikan pemetaan dari setiap kelas ke sebuah angka, sebelum mengganti\n" + "Untuk melakukan label encoding pada kolom pertama, kita harus terlebih dahulu mendeskripsikan pemetaan dari setiap kelas ke angka, sebelum menggantinya.\n" ] }, { @@ -3084,7 +3094,7 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Seperti yang kita lihat, hasilnya sesuai dengan apa yang kita perkirakan. Jadi, kapan kita menggunakan label encoding? Label encoding digunakan dalam salah satu atau kedua kasus berikut:\n", + "Seperti yang kita lihat, hasilnya sesuai dengan apa yang kita pikirkan akan terjadi. Jadi, kapan kita menggunakan label encoding? Label encoding digunakan dalam salah satu atau kedua kasus berikut:\n", "1. Ketika jumlah kategori sangat banyak\n", "2. Ketika kategori memiliki urutan tertentu.\n" ] @@ -3332,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Setiap kolom hot encoded berisi 0 atau 1, yang menunjukkan apakah kategori tersebut ada untuk titik data tersebut.\n" + "Setiap kolom yang di-encode one hot berisi 0 atau 1, yang menunjukkan apakah kategori tersebut ada untuk titik data tersebut.\n" ] }, { @@ -3344,7 +3354,7 @@ "Kapan kita menggunakan one hot encoding? One hot encoding digunakan dalam salah satu atau kedua kasus berikut:\n", "\n", "1. Ketika jumlah kategori dan ukuran dataset lebih kecil.\n", - "2. Ketika kategori tidak memiliki urutan tertentu.\n" + "2. Ketika kategori tidak mengikuti urutan tertentu.\n" ] }, { @@ -3353,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Poin Penting:\n", + "> Poin-Poin Penting:\n", "1. Encoding dilakukan untuk mengubah data non-numerik menjadi data numerik.\n", - "2. Ada dua jenis encoding: Label encoding dan One Hot encoding, yang keduanya dapat dilakukan berdasarkan kebutuhan dataset.\n" + "2. Ada dua jenis encoding: Label encoding dan One Hot encoding, yang keduanya dapat dilakukan sesuai kebutuhan dataset.\n" ] }, { @@ -3364,9 +3374,9 @@ "id": "K8UXOJYRgRsJ" }, "source": [ - "## Menghapus data duplikat\n", + "## Menghapus Data Duplikat\n", "\n", - "> **Tujuan pembelajaran:** Pada akhir subbagian ini, Anda diharapkan dapat dengan mudah mengidentifikasi dan menghapus nilai duplikat dari DataFrames.\n", + "> **Tujuan pembelajaran:** Di akhir subbagian ini, Anda seharusnya merasa nyaman dalam mengidentifikasi dan menghapus nilai duplikat dari DataFrame.\n", "\n", "Selain data yang hilang, Anda sering kali akan menemukan data duplikat dalam dataset dunia nyata. Untungnya, pandas menyediakan cara yang mudah untuk mendeteksi dan menghapus entri duplikat.\n" ] @@ -3379,7 +3389,7 @@ "source": [ "### Mengidentifikasi duplikat: `duplicated`\n", "\n", - "Anda dapat dengan mudah menemukan nilai duplikat menggunakan metode `duplicated` di pandas, yang mengembalikan masker Boolean yang menunjukkan apakah sebuah entri dalam `DataFrame` adalah duplikat dari entri sebelumnya. Mari kita buat contoh `DataFrame` lain untuk melihat cara kerjanya.\n" + "Anda dapat dengan mudah menemukan nilai duplikat menggunakan metode `duplicated` di pandas, yang mengembalikan masker Boolean yang menunjukkan apakah suatu entri dalam `DataFrame` adalah duplikat dari entri sebelumnya. Mari kita buat contoh `DataFrame` lain untuk melihat cara kerjanya.\n" ] }, { @@ -3668,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Kesimpulan:** Menghapus data duplikat adalah bagian penting dari hampir setiap proyek ilmu data. Data duplikat dapat mengubah hasil analisis Anda dan memberikan hasil yang tidak akurat!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pemeriksaan Kualitas Data di Dunia Nyata\n", + "\n", + "> **Tujuan pembelajaran:** Pada akhir bagian ini, Anda diharapkan mampu mendeteksi dan memperbaiki masalah kualitas data umum di dunia nyata, termasuk nilai kategori yang tidak konsisten, nilai numerik yang tidak wajar (outlier), dan entitas duplikat dengan variasi.\n", + "\n", + "Meskipun nilai yang hilang dan duplikat yang persis sama adalah masalah yang umum, dataset di dunia nyata sering kali mengandung masalah yang lebih halus:\n", + "\n", + "1. **Nilai kategori yang tidak konsisten**: Kategori yang sama ditulis dengan cara berbeda (misalnya, \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Nilai numerik yang tidak wajar**: Outlier ekstrem yang menunjukkan kesalahan entri data (misalnya, usia = 999)\n", + "3. **Baris yang hampir duplikat**: Rekaman yang mewakili entitas yang sama dengan sedikit variasi\n", + "\n", + "Mari kita jelajahi teknik untuk mendeteksi dan menangani masalah-masalah ini.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Membuat Dataset \"Kotor\" Contoh\n", + "\n", + "Pertama, mari kita buat dataset contoh yang berisi jenis masalah yang sering kita temui dalam data dunia nyata:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Mendeteksi Nilai Kategorikal yang Tidak Konsisten\n", + "\n", + "Perhatikan kolom `country` memiliki beberapa representasi untuk negara yang sama. Mari kita identifikasi ketidakkonsistenan ini:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Standarisasi Nilai Kategorikal\n", + "\n", + "Kita dapat membuat pemetaan untuk menstandarisasi nilai-nilai ini. Pendekatan sederhana adalah dengan mengubah ke huruf kecil dan membuat kamus pemetaan:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternatif: Menggunakan Pencocokan Fuzzy**\n", + "\n", + "Untuk kasus yang lebih kompleks, kita dapat menggunakan pencocokan string fuzzy dengan pustaka `rapidfuzz` untuk mendeteksi string yang mirip secara otomatis:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Mendeteksi Nilai Numerik yang Tidak Normal (Outlier)\n", + "\n", + "Melihat kolom `age`, terdapat beberapa nilai mencurigakan seperti 199 dan -5. Mari gunakan metode statistik untuk mendeteksi outlier ini.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Menggunakan Metode IQR (Interquartile Range)\n", + "\n", + "Metode IQR adalah teknik statistik yang tangguh untuk mendeteksi pencilan yang kurang sensitif terhadap nilai ekstrem:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Menggunakan Metode Z-Score\n", + "\n", + "Metode Z-score mengidentifikasi nilai pencilan berdasarkan deviasi standar dari rata-rata:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Menangani Outlier\n", + "\n", + "Setelah terdeteksi, outlier dapat ditangani dengan beberapa cara:\n", + "1. **Hapus**: Buang baris yang mengandung outlier (jika itu adalah kesalahan)\n", + "2. **Batasi**: Ganti dengan nilai batas\n", + "3. **Ganti dengan NaN**: Perlakukan sebagai data yang hilang dan gunakan teknik imputasi\n", + "4. **Pertahankan**: Jika itu adalah nilai ekstrem yang sah\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Mendeteksi Baris yang Hampir Duplikat\n", + "\n", + "Perhatikan bahwa dataset kita memiliki beberapa entri untuk \"John Smith\" dengan nilai yang sedikit berbeda. Mari kita identifikasi kemungkinan duplikat berdasarkan kesamaan nama.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Menemukan Duplikat yang Mirip dengan Pencocokan Fuzzy\n", + "\n", + "Untuk deteksi duplikat yang lebih canggih, kita dapat menggunakan pencocokan fuzzy untuk menemukan nama yang serupa:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Menangani Duplikasi\n", + "\n", + "Setelah diidentifikasi, Anda perlu memutuskan bagaimana menangani duplikasi:\n", + "1. **Simpan kemunculan pertama**: Gunakan `drop_duplicates(keep='first')`\n", + "2. **Simpan kemunculan terakhir**: Gunakan `drop_duplicates(keep='last')`\n", + "3. **Gabungkan informasi**: Kombinasikan informasi dari baris yang duplikat\n", + "4. **Tinjauan manual**: Tandai untuk ditinjau oleh manusia\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Ringkasan: Pipeline Pembersihan Data Lengkap\n", + "\n", + "Mari kita gabungkan semuanya ke dalam pipeline pembersihan yang komprehensif:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Latihan Tantangan\n", + "\n", + "Sekarang giliran Anda! Di bawah ini terdapat baris data baru dengan beberapa masalah kualitas. Bisakah Anda:\n", + "\n", + "1. Mengidentifikasi semua masalah dalam baris ini\n", + "2. Menulis kode untuk membersihkan setiap masalah\n", + "3. Menambahkan baris yang telah dibersihkan ke dalam dataset\n", + "\n", + "Berikut adalah data yang bermasalah:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Poin Penting\n", + "\n", + "1. **Kategori yang tidak konsisten** sering ditemukan dalam data dunia nyata. Selalu periksa nilai unik dan standarisasi menggunakan pemetaan atau pencocokan fuzzy.\n", + "\n", + "2. **Outlier** dapat secara signifikan memengaruhi analisis Anda. Gunakan pengetahuan domain yang dikombinasikan dengan metode statistik (IQR, Z-score) untuk mendeteksinya.\n", + "\n", + "3. **Hampir duplikat** lebih sulit dideteksi dibandingkan duplikat yang persis sama. Pertimbangkan menggunakan pencocokan fuzzy dan normalisasi data (huruf kecil, menghapus spasi) untuk mengidentifikasinya.\n", + "\n", + "4. **Pembersihan data bersifat iteratif**. Anda mungkin perlu menerapkan beberapa teknik dan meninjau hasilnya sebelum menyelesaikan dataset yang telah dibersihkan.\n", + "\n", + "5. **Dokumentasikan keputusan Anda**. Catat langkah-langkah pembersihan yang Anda terapkan dan alasannya, karena ini penting untuk reproduktibilitas dan transparansi.\n", + "\n", + "> **Praktik Terbaik:** Selalu simpan salinan data \"kotor\" asli Anda. Jangan pernah menimpa file data sumber Anda - buat versi yang telah dibersihkan dengan konvensi penamaan yang jelas seperti `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Penafian**: \nDokumen ini telah diterjemahkan menggunakan layanan penerjemahan AI [Co-op Translator](https://github.com/Azure/co-op-translator). Meskipun kami berusaha untuk memberikan hasil yang akurat, harap diingat bahwa terjemahan otomatis mungkin mengandung kesalahan atau ketidakakuratan. Dokumen asli dalam bahasa aslinya harus dianggap sebagai sumber yang otoritatif. Untuk informasi yang bersifat kritis, disarankan menggunakan jasa penerjemahan profesional oleh manusia. Kami tidak bertanggung jawab atas kesalahpahaman atau penafsiran yang keliru yang timbul dari penggunaan terjemahan ini.\n" + "\n---\n\n**Penafian**: \nDokumen ini telah diterjemahkan menggunakan layanan penerjemahan AI [Co-op Translator](https://github.com/Azure/co-op-translator). Meskipun kami berusaha untuk memberikan hasil yang akurat, harap diketahui bahwa terjemahan otomatis mungkin mengandung kesalahan atau ketidakakuratan. Dokumen asli dalam bahasa aslinya harus dianggap sebagai sumber yang otoritatif. Untuk informasi yang bersifat kritis, disarankan menggunakan jasa penerjemahan manusia profesional. Kami tidak bertanggung jawab atas kesalahpahaman atau interpretasi yang keliru yang timbul dari penggunaan terjemahan ini.\n" ] } ], @@ -3702,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T22:00:06+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:39:23+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "id" } diff --git a/translations/it/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/it/2-Working-With-Data/08-data-preparation/notebook.ipynb index 4b2ca740..68326ab2 100644 --- a/translations/it/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/it/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# Preparazione dei dati\n", "\n", - "[Notebook originale tratto da *Data Science: Introduzione al Machine Learning per Data Science Python e Machine Learning Studio di Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Notebook originale tratto da *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio di Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", - "## Esplorare le informazioni di `DataFrame`\n", + "## Esplorare le informazioni del `DataFrame`\n", "\n", "> **Obiettivo di apprendimento:** Alla fine di questa sottosezione, dovresti sentirti a tuo agio nel trovare informazioni generali sui dati memorizzati nei DataFrame di pandas.\n", "\n", - "Una volta che hai caricato i tuoi dati in pandas, è molto probabile che siano in un `DataFrame`. Tuttavia, se il set di dati nel tuo `DataFrame` ha 60.000 righe e 400 colonne, come puoi iniziare a capire con cosa stai lavorando? Fortunatamente, pandas offre alcuni strumenti pratici per esaminare rapidamente le informazioni generali su un `DataFrame`, oltre alle prime e ultime righe.\n", + "Una volta caricati i tuoi dati in pandas, è molto probabile che siano in un `DataFrame`. Tuttavia, se il set di dati nel tuo `DataFrame` ha 60.000 righe e 400 colonne, come puoi iniziare a capire con cosa stai lavorando? Fortunatamente, pandas offre alcuni strumenti pratici per visualizzare rapidamente informazioni generali su un `DataFrame`, oltre alle prime e ultime righe.\n", "\n", - "Per esplorare questa funzionalità, importeremo la libreria Python scikit-learn e utilizzeremo un dataset iconico che ogni data scientist ha visto centinaia di volte: il set di dati *Iris* del biologo britannico Ronald Fisher, utilizzato nel suo articolo del 1936 \"L'uso di misurazioni multiple nei problemi tassonomici\":\n" + "Per esplorare questa funzionalità, importeremo la libreria Python scikit-learn e utilizzeremo un dataset iconico che ogni data scientist ha visto centinaia di volte: il dataset *Iris* del biologo britannico Ronald Fisher, utilizzato nel suo articolo del 1936 \"The use of multiple measurements in taxonomic problems\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Abbiamo caricato il dataset Iris nella variabile `iris_df`. Prima di analizzare i dati, sarebbe utile sapere quanti punti dati abbiamo e la dimensione complessiva del dataset. È importante avere un'idea del volume di dati con cui stiamo lavorando.\n" + "Abbiamo caricato il dataset Iris nella variabile `iris_df`. Prima di analizzare i dati, sarebbe utile sapere il numero di punti dati che abbiamo e la dimensione complessiva del dataset. È utile osservare il volume di dati con cui stiamo lavorando.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Passiamo ora alle 4 colonne di dati. Cosa rappresenta esattamente ciascuna di esse? L'attributo `columns` ci fornirà i nomi delle colonne nel dataframe.\n" + "Passiamo ora alle 4 colonne di dati. Cosa rappresentano esattamente ciascuna di esse? L'attributo `columns` ci fornirà i nomi delle colonne nel dataframe.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Come possiamo vedere, ci sono quattro(4) colonne. L'attributo `columns` ci indica il nome delle colonne e fondamentalmente nient'altro. Questo attributo assume importanza quando vogliamo identificare le caratteristiche contenute in un dataset.\n" + "Come possiamo vedere, ci sono quattro (4) colonne. L'attributo `columns` ci indica il nome delle colonne e fondamentalmente nient'altro. Questo attributo assume importanza quando vogliamo identificare le caratteristiche contenute in un dataset.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Da qui possiamo fare alcune osservazioni: \n", - "1. Il tipo di dato di ogni colonna: In questo dataset, tutti i dati sono memorizzati come numeri in virgola mobile a 64 bit. \n", - "2. Numero di valori non nulli: Gestire i valori nulli è un passaggio importante nella preparazione dei dati. Questo verrà affrontato più avanti nel notebook. \n" + "Da qui possiamo fare alcune osservazioni:\n", + "1. Il tipo di dato di ogni colonna: In questo dataset, tutti i dati sono memorizzati come numeri in virgola mobile a 64 bit.\n", + "2. Numero di valori non nulli: Gestire i valori nulli è un passaggio importante nella preparazione dei dati. Verrà affrontato più avanti nel notebook.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "L'output sopra mostra il numero totale di punti dati, la media, la deviazione standard, il minimo, il quartile inferiore (25%), la mediana (50%), il quartile superiore (75%) e il valore massimo di ciascuna colonna.\n" + "L'output sopra mostra il numero totale di punti dati, la media, la deviazione standard, il minimo, il quartile inferiore (25%), la mediana (50%), il quartile superiore (75%) e il valore massimo di ogni colonna.\n" ] }, { @@ -332,7 +332,7 @@ }, "source": [ "### `DataFrame.head`\n", - "Con tutte le funzioni e gli attributi sopra menzionati, abbiamo ottenuto una visione generale del dataset. Sappiamo quanti punti dati ci sono, quante caratteristiche ci sono, il tipo di dato di ciascuna caratteristica e il numero di valori non nulli per ciascuna caratteristica.\n", + "Con tutte le funzioni e gli attributi sopra menzionati, abbiamo ottenuto una visione generale del dataset. Sappiamo quanti punti dati ci sono, quante caratteristiche ci sono, il tipo di dato di ciascuna caratteristica e il numero di valori non nulli per ogni caratteristica.\n", "\n", "Ora è il momento di osservare i dati stessi. Vediamo come appaiono le prime righe (i primi punti dati) del nostro `DataFrame`:\n" ] @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Come output qui, possiamo vedere cinque (5) voci del dataset. Se guardiamo l'indice a sinistra, scopriamo che queste sono le prime cinque righe.\n" + "Come risultato qui, possiamo vedere cinque (5) voci del dataset. Se guardiamo l'indice a sinistra, scopriamo che queste sono le prime cinque righe.\n" ] }, { @@ -584,9 +584,9 @@ "source": [ "In pratica, è utile poter esaminare facilmente le prime righe o le ultime righe di un `DataFrame`, soprattutto quando si cercano valori anomali in dataset ordinati.\n", "\n", - "Tutte le funzioni e gli attributi mostrati sopra con l'aiuto di esempi di codice ci aiutano a ottenere una visione d'insieme dei dati.\n", + "Tutte le funzioni e gli attributi mostrati sopra con l'aiuto di esempi di codice ci aiutano a ottenere una visione generale dei dati.\n", "\n", - "> **Conclusione:** Anche solo osservando i metadati relativi alle informazioni in un DataFrame o i primi e ultimi valori in esso, puoi farti un'idea immediata della dimensione, forma e contenuto dei dati con cui stai lavorando.\n" + "> **Conclusione:** Anche solo osservando i metadati relativi alle informazioni in un DataFrame o i primi e gli ultimi valori, è possibile farsi un'idea immediata della dimensione, forma e contenuto dei dati con cui si sta lavorando.\n" ] }, { @@ -596,17 +596,17 @@ }, "source": [ "### Dati Mancanti\n", - "Esploriamo i dati mancanti. I dati mancanti si verificano quando non viene memorizzato alcun valore in alcune colonne.\n", + "Esaminiamo i dati mancanti. I dati mancanti si verificano quando non viene memorizzato alcun valore in alcune colonne.\n", "\n", - "Prendiamo un esempio: supponiamo che qualcuno sia molto attento al proprio peso e non compili il campo relativo al peso in un sondaggio. In questo caso, il valore del peso per quella persona sarà mancante.\n", + "Prendiamo un esempio: supponiamo che qualcuno sia molto attento al proprio peso e non compili il campo relativo al peso in un sondaggio. In tal caso, il valore del peso per quella persona sarà mancante.\n", "\n", "Nella maggior parte dei casi, nei dataset del mondo reale, si verificano valori mancanti.\n", "\n", "**Come Pandas gestisce i dati mancanti**\n", "\n", - "Pandas gestisce i valori mancanti in due modi. Il primo, che hai già visto nelle sezioni precedenti, è `NaN`, ovvero Not a Number. Questo è in realtà un valore speciale che fa parte della specifica IEEE per i numeri in virgola mobile ed è utilizzato esclusivamente per indicare valori mancanti in virgola mobile.\n", + "Pandas gestisce i valori mancanti in due modi. Il primo lo hai già visto nelle sezioni precedenti: `NaN`, ovvero Not a Number. Questo è in realtà un valore speciale che fa parte della specifica IEEE per i numeri in virgola mobile ed è utilizzato esclusivamente per indicare valori mancanti in virgola mobile.\n", "\n", - "Per i valori mancanti diversi dai numeri in virgola mobile, pandas utilizza l'oggetto `None` di Python. Anche se potrebbe sembrare confuso incontrare due tipi diversi di valori che indicano essenzialmente la stessa cosa, ci sono valide ragioni programmatiche per questa scelta progettuale e, in pratica, questa soluzione consente a pandas di offrire un buon compromesso nella stragrande maggioranza dei casi. Detto ciò, sia `None` che `NaN` presentano delle limitazioni di cui devi essere consapevole riguardo al modo in cui possono essere utilizzati.\n" + "Per i valori mancanti diversi dai numeri in virgola mobile, pandas utilizza l'oggetto Python `None`. Anche se potrebbe sembrare confuso incontrare due tipi diversi di valori che indicano essenzialmente la stessa cosa, ci sono valide ragioni programmatiche per questa scelta progettuale e, nella pratica, seguire questa strada consente a pandas di offrire un buon compromesso per la stragrande maggioranza dei casi. Detto ciò, sia `None` che `NaN` presentano delle limitazioni di cui devi essere consapevole riguardo al modo in cui possono essere utilizzati.\n" ] }, { @@ -616,7 +616,7 @@ }, "source": [ "### `None`: dati mancanti non di tipo float\n", - "Poiché `None` proviene da Python, non può essere utilizzato in array di NumPy e pandas che non hanno il tipo di dato `'object'`. Ricorda che gli array di NumPy (e le strutture dati in pandas) possono contenere solo un tipo di dato. Questo è ciò che conferisce loro un'enorme potenza per il lavoro su larga scala con dati e calcoli, ma limita anche la loro flessibilità. Tali array devono essere convertiti al \"denominatore comune più basso\", ovvero il tipo di dato che può includere tutto ciò che si trova nell'array. Quando `None` è presente nell'array, significa che stai lavorando con oggetti Python.\n", + "Poiché `None` proviene da Python, non può essere utilizzato in array di NumPy e pandas che non hanno il tipo di dato `'object'`. Ricorda che gli array di NumPy (e le strutture dati in pandas) possono contenere solo un tipo di dato. Questo è ciò che conferisce loro un'enorme potenza per il lavoro con dati su larga scala e per calcoli, ma limita anche la loro flessibilità. Tali array devono essere convertiti al \"denominatore comune più basso\", ovvero il tipo di dato che può includere tutto ciò che si trova nell'array. Quando `None` è presente nell'array, significa che stai lavorando con oggetti Python.\n", "\n", "Per vedere questo in pratica, considera il seguente esempio di array (nota il `dtype` associato):\n" ] @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "La realtà dei tipi di dati promossi comporta due effetti collaterali. Primo, le operazioni verranno eseguite a livello di codice Python interpretato piuttosto che di codice NumPy compilato. In sostanza, ciò significa che qualsiasi operazione che coinvolga `Series` o `DataFrame` contenenti `None` sarà più lenta. Anche se probabilmente non noteresti questo calo di prestazioni, per dataset di grandi dimensioni potrebbe diventare un problema.\n", + "La realtà dei tipi di dati promossi comporta due effetti collaterali. Primo, le operazioni verranno eseguite a livello di codice Python interpretato piuttosto che di codice NumPy compilato. In sostanza, ciò significa che qualsiasi operazione che coinvolga `Series` o `DataFrames` contenenti `None` sarà più lenta. Anche se probabilmente non noteresti questo calo di prestazioni, per dataset di grandi dimensioni potrebbe diventare un problema.\n", "\n", - "Il secondo effetto collaterale deriva dal primo. Poiché `None` essenzialmente riporta `Series` o `DataFrame` nel mondo del Python standard, l'uso di aggregazioni NumPy/pandas come `sum()` o `min()` su array che contengono un valore ``None`` generalmente produrrà un errore:\n" + "Il secondo effetto collaterale deriva dal primo. Poiché `None` essenzialmente riporta `Series` o `DataFrame` nel mondo del Python standard, l'utilizzo di aggregazioni NumPy/pandas come `sum()` o `min()` su array che contengono un valore ``None`` generalmente produrrà un errore:\n" ] }, { @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**Punto chiave**: L'addizione (e altre operazioni) tra interi e valori `None` è indefinita, il che può limitare ciò che si può fare con i dataset che li contengono.\n" + ] }, { "cell_type": "markdown", @@ -707,7 +709,7 @@ "source": [ "### `NaN`: valori float mancanti\n", "\n", - "A differenza di `None`, NumPy (e quindi pandas) supporta `NaN` per le sue operazioni veloci, vettoriali e ufunc. La cattiva notizia è che qualsiasi operazione aritmetica eseguita su `NaN` restituisce sempre `NaN`. Ad esempio:\n" + "A differenza di `None`, NumPy (e quindi pandas) supporta `NaN` per le sue operazioni vettoriali rapide e le ufunc. La cattiva notizia è che qualsiasi operazione aritmetica eseguita su `NaN` restituisce sempre `NaN`. Ad esempio:\n" ] }, { @@ -770,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "La buona notizia: le aggregazioni eseguite su array con `NaN` al loro interno non generano errori. La cattiva notizia: i risultati non sono uniformemente utili:\n" + "La buona notizia: le aggregazioni eseguite su array contenenti `NaN` non generano errori. La cattiva notizia: i risultati non sono uniformemente utili:\n" ] }, { @@ -806,7 +808,9 @@ "metadata": { "id": "nhlnNJT7gRr_" }, - "source": [] + "source": [ + "### Esercizio:\n" + ] }, { "cell_type": "code", @@ -826,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "Ricorda: `NaN` è solo per valori in virgola mobile mancanti; non esiste un equivalente di `NaN` per interi, stringhe o Booleani.\n" + ] }, { "cell_type": "markdown", @@ -875,7 +881,9 @@ "metadata": { "id": "WklCzqb8gRsB" }, - "source": [] + "source": [ + "### Esercizio:\n" + ] }, { "cell_type": "code", @@ -898,7 +906,7 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Nel processo di conversione dei tipi di dati per stabilire l'omogeneità nei `Series` e nei `DataFrame`, pandas passerà volentieri i valori mancanti tra `None` e `NaN`. A causa di questa caratteristica progettuale, può essere utile pensare a `None` e `NaN` come due diverse varianti di \"null\" in pandas. Infatti, alcuni dei metodi principali che utilizzerai per gestire i valori mancanti in pandas riflettono questa idea nei loro nomi:\n", + "Nel processo di conversione dei tipi di dati per stabilire l'omogeneità dei dati in `Series` e `DataFrame`, pandas passerà facilmente i valori mancanti tra `None` e `NaN`. A causa di questa caratteristica progettuale, può essere utile pensare a `None` e `NaN` come due diverse varianti di \"null\" in pandas. Infatti, alcuni dei metodi principali che utilizzerai per gestire i valori mancanti in pandas riflettono questa idea nei loro nomi:\n", "\n", "- `isnull()`: Genera una maschera booleana che indica i valori mancanti\n", "- `notnull()`: Opposto di `isnull()`\n", @@ -914,10 +922,10 @@ "id": "Yh5ifd9FgRsB" }, "source": [ - "### Rilevare i valori nulli\n", + "### Rilevare valori nulli\n", "\n", "Ora che abbiamo compreso l'importanza dei valori mancanti, dobbiamo rilevarli nel nostro dataset prima di gestirli. \n", - "Sia `isnull()` che `notnull()` sono i tuoi metodi principali per individuare i dati nulli. Entrambi restituiscono maschere booleane sui tuoi dati.\n" + "Sia `isnull()` che `notnull()` sono i metodi principali per rilevare dati nulli. Entrambi restituiscono maschere booleane sui tuoi dati.\n" ] }, { @@ -970,9 +978,9 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Osserva attentamente il risultato. C'è qualcosa che ti sorprende? Sebbene `0` sia un valore nullo dal punto di vista aritmetico, è comunque un intero valido e pandas lo tratta come tale. `''` è un po' più sottile. Anche se lo abbiamo usato nella Sezione 1 per rappresentare un valore di stringa vuota, è comunque un oggetto stringa e non una rappresentazione di null secondo pandas.\n", + "Osserva attentamente il risultato. C'è qualcosa che ti sorprende? Sebbene `0` sia un valore nullo aritmetico, è comunque un intero perfettamente valido e pandas lo tratta come tale. `''` è un po' più sottile. Anche se lo abbiamo usato nella Sezione 1 per rappresentare un valore di stringa vuota, rimane comunque un oggetto stringa e non una rappresentazione di null secondo pandas.\n", "\n", - "Ora, invertiamo la prospettiva e utilizziamo questi metodi in un modo più simile a quello che useresti nella pratica. Puoi utilizzare le maschere booleane direttamente come indice di una ``Series`` o di un ``DataFrame``, il che può essere utile quando si cerca di lavorare con valori mancanti (o presenti) isolati.\n", + "Ora, invertiamo la prospettiva e utilizziamo questi metodi in un modo più simile a quello che userai nella pratica. Puoi utilizzare le maschere booleane direttamente come indice di una ``Series`` o di un ``DataFrame``, il che può essere utile quando si cerca di lavorare con valori mancanti (o presenti) isolati.\n", "\n", "Se vogliamo il numero totale di valori mancanti, possiamo semplicemente fare una somma sulla maschera prodotta dal metodo `isnull()`.\n" ] @@ -1008,7 +1016,9 @@ "metadata": { "id": "PlBqEo3mgRsC" }, - "source": [] + "source": [ + "### Esercizio:\n" + ] }, { "cell_type": "code", @@ -1030,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Conclusione principale**: Sia il metodo `isnull()` che il metodo `notnull()` producono risultati simili quando li usi nei DataFrame: mostrano i risultati e l'indice di quei risultati, il che ti aiuterà enormemente mentre lavori con i tuoi dati.\n" + "**Conclusione chiave**: Sia il metodo `isnull()` che il metodo `notnull()` producono risultati simili quando li usi nei DataFrame: mostrano i risultati e l'indice di quei risultati, il che ti aiuterà enormemente mentre lavori con i tuoi dati.\n" ] }, { @@ -1043,16 +1053,16 @@ "\n", "> **Obiettivo di apprendimento:** Alla fine di questa sottosezione, dovresti sapere come e quando sostituire o rimuovere i valori nulli dai DataFrame.\n", "\n", - "I modelli di Machine Learning non possono gestire direttamente i dati mancanti. Pertanto, prima di passare i dati al modello, è necessario affrontare questi valori mancanti.\n", + "I modelli di Machine Learning non sono in grado di gestire direttamente i dati mancanti. Pertanto, prima di passare i dati al modello, è necessario affrontare questi valori mancanti.\n", "\n", - "Il modo in cui si gestiscono i dati mancanti comporta compromessi sottili, che possono influenzare la tua analisi finale e i risultati nel mondo reale.\n", + "Il modo in cui i dati mancanti vengono gestiti comporta sottili compromessi, può influenzare la tua analisi finale e gli esiti nel mondo reale.\n", "\n", "Ci sono principalmente due modi per gestire i dati mancanti:\n", "\n", - "1. Eliminare la riga che contiene il valore mancante \n", - "2. Sostituire il valore mancante con un altro valore \n", + "1. Eliminare la riga che contiene il valore mancante\n", + "2. Sostituire il valore mancante con un altro valore\n", "\n", - "Discuteremo entrambi questi metodi e i loro pro e contro in dettaglio.\n" + "Discuteremo entrambe queste metodologie e i loro pro e contro in dettaglio.\n" ] }, { @@ -1063,7 +1073,7 @@ "source": [ "### Eliminazione dei valori nulli\n", "\n", - "La quantità di dati che passiamo al nostro modello ha un effetto diretto sulle sue prestazioni. Eliminare i valori nulli significa ridurre il numero di punti dati e, di conseguenza, diminuire la dimensione del dataset. Pertanto, è consigliabile eliminare le righe con valori nulli quando il dataset è piuttosto grande.\n", + "La quantità di dati che passiamo al nostro modello ha un effetto diretto sulle sue prestazioni. Eliminare i valori nulli significa ridurre il numero di punti dati e, di conseguenza, ridurre la dimensione del dataset. Pertanto, è consigliabile eliminare le righe con valori nulli quando il dataset è piuttosto grande.\n", "\n", "Un altro caso potrebbe essere che una certa riga o colonna abbia molti valori mancanti. In tal caso, potrebbero essere eliminate perché non aggiungerebbero molto valore alla nostra analisi, dato che la maggior parte dei dati è mancante per quella riga/colonna.\n", "\n", @@ -1198,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Ti sei accorto che pandas ha convertito due delle colonne in float per gestire i `NaN`?)\n", + "(Hai notato che pandas ha convertito due delle colonne in float per gestire i `NaN`?)\n", "\n", - "Non puoi eliminare un singolo valore da un `DataFrame`, quindi devi eliminare intere righe o colonne. A seconda di ciò che stai facendo, potresti voler fare una cosa o l'altra, e quindi pandas ti offre opzioni per entrambe. Poiché nella scienza dei dati le colonne generalmente rappresentano variabili e le righe rappresentano osservazioni, è più probabile che tu voglia eliminare righe di dati; l'impostazione predefinita per `dropna()` è quella di eliminare tutte le righe che contengono valori nulli:\n" + "Non puoi eliminare un singolo valore da un `DataFrame`, quindi devi eliminare intere righe o colonne. A seconda di ciò che stai facendo, potresti preferire una delle due opzioni, e pandas ti offre entrambe. Poiché, nella scienza dei dati, le colonne generalmente rappresentano variabili e le righe rappresentano osservazioni, è più probabile che tu voglia eliminare righe di dati; l'impostazione predefinita di `dropna()` è quella di eliminare tutte le righe che contengono valori nulli:\n" ] }, { @@ -1352,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Tieni presente che questo può eliminare molti dati che potresti voler conservare, specialmente nei dataset più piccoli. E se volessi eliminare solo le righe o le colonne che contengono diversi o addirittura tutti i valori nulli? Puoi specificare queste impostazioni in `dropna` utilizzando i parametri `how` e `thresh`.\n", + "Nota che questo può eliminare molti dati che potresti voler conservare, soprattutto nei dataset più piccoli. E se volessi eliminare solo le righe o le colonne che contengono diversi o addirittura tutti i valori nulli? Puoi specificare queste impostazioni in `dropna` utilizzando i parametri `how` e `thresh`.\n", "\n", - "Per impostazione predefinita, `how='any'` (se vuoi verificare di persona o vedere quali altri parametri ha il metodo, esegui `example4.dropna?` in una cella di codice). In alternativa, potresti specificare `how='all'` per eliminare solo le righe o le colonne che contengono tutti valori nulli. Espandiamo il nostro esempio di `DataFrame` per vedere questo in azione nel prossimo esercizio.\n" + "Per impostazione predefinita, `how='any'` (se vuoi verificare di persona o vedere quali altri parametri ha il metodo, esegui `example4.dropna?` in una cella di codice). In alternativa, potresti specificare `how='all'` per eliminare solo le righe o colonne che contengono tutti i valori nulli. Espandiamo il nostro esempio di `DataFrame` per vedere questo in azione nel prossimo esercizio.\n" ] }, { @@ -1446,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> Punti chiave: \n", - "1. Eliminare i valori nulli è una buona idea solo se il dataset è abbastanza grande. \n", - "2. Intere righe o colonne possono essere eliminate se la maggior parte dei loro dati è mancante. \n", - "3. Il metodo `DataFrame.dropna(axis=)` aiuta a eliminare i valori nulli. L'argomento `axis` indica se eliminare righe o colonne. \n", - "4. Si può anche utilizzare l'argomento `how`. Per impostazione predefinita è impostato su `any`. Quindi, elimina solo quelle righe/colonne che contengono qualsiasi valore nullo. Può essere impostato su `all` per specificare che elimineremo solo quelle righe/colonne in cui tutti i valori sono nulli. \n" + "> Punti chiave:\n", + "1. Eliminare i valori nulli è una buona idea solo se il dataset è abbastanza grande.\n", + "2. Intere righe o colonne possono essere eliminate se la maggior parte dei loro dati è mancante.\n", + "3. Il metodo `DataFrame.dropna(axis=)` aiuta a eliminare i valori nulli. L'argomento `axis` indica se devono essere eliminate le righe o le colonne.\n", + "4. È possibile utilizzare anche l'argomento `how`. Per impostazione predefinita, è settato su `any`. Quindi, elimina solo quelle righe/colonne che contengono qualsiasi valore nullo. Può essere impostato su `all` per specificare che elimineremo solo quelle righe/colonne in cui tutti i valori sono nulli.\n" ] }, { @@ -1458,7 +1468,9 @@ "metadata": { "id": "oXXSfQFHgRsF" }, - "source": [] + "source": [ + "### Esercizio:\n" + ] }, { "cell_type": "code", @@ -1554,7 +1566,9 @@ "metadata": { "id": "fmSFnzZegRsG" }, - "source": [] + "source": [ + "Qui, la prima e l'ultima riga sono state eliminate, perché contengono solo due valori non nulli.\n" + ] }, { "cell_type": "markdown", @@ -1562,11 +1576,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### Compilare i valori nulli\n", + "### Compilare valori nulli\n", "\n", "A volte ha senso riempire i valori mancanti con quelli che potrebbero essere validi. Esistono alcune tecniche per riempire i valori nulli. La prima consiste nell'utilizzare la Conoscenza del Dominio (conoscenza dell'argomento su cui si basa il dataset) per approssimare in qualche modo i valori mancanti.\n", "\n", - "Puoi utilizzare `isnull` per farlo direttamente, ma questo può essere faticoso, soprattutto se hai molti valori da riempire. Poiché questa è un'operazione molto comune in data science, pandas fornisce `fillna`, che restituisce una copia della `Series` o del `DataFrame` con i valori mancanti sostituiti con uno a tua scelta. Creiamo un altro esempio di `Series` per vedere come funziona in pratica.\n" + "Puoi utilizzare `isnull` per farlo direttamente, ma può essere laborioso, soprattutto se hai molti valori da riempire. Poiché questa è un'operazione molto comune nella scienza dei dati, pandas fornisce `fillna`, che restituisce una copia della `Series` o del `DataFrame` con i valori mancanti sostituiti con uno a tua scelta. Creiamo un'altra `Series` di esempio per vedere come funziona nella pratica.\n" ] }, { @@ -1576,9 +1590,9 @@ }, "source": [ "### Dati Categoriali (Non-numerici)\n", - "Per prima cosa consideriamo i dati non numerici. Nei dataset, abbiamo colonne con dati categoriali. Ad esempio, Genere, Vero o Falso, ecc.\n", + "Per prima cosa consideriamo i dati non numerici. Nei dataset, ci sono colonne con dati categoriali, ad esempio: Genere, Vero o Falso, ecc.\n", "\n", - "Nella maggior parte di questi casi, sostituiamo i valori mancanti con la `moda` della colonna. Supponiamo di avere 100 punti dati, 90 hanno indicato Vero, 8 hanno indicato Falso e 2 non hanno risposto. In questo caso, possiamo riempire i 2 valori mancanti con Vero, considerando l'intera colonna.\n", + "Nella maggior parte di questi casi, sostituiamo i valori mancanti con la `moda` della colonna. Supponiamo di avere 100 punti dati, di cui 90 hanno indicato Vero, 8 hanno indicato Falso e 2 non hanno compilato. In questo caso, possiamo riempire i 2 valori mancanti con Vero, considerando l'intera colonna.\n", "\n", "Anche qui possiamo utilizzare la conoscenza del dominio. Consideriamo un esempio di riempimento con la moda.\n" ] @@ -1685,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Ora, troviamo prima la moda prima di riempire il valore `None` con la moda.\n" + ] }, { "cell_type": "code", @@ -1720,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Quindi, sostituiremo None con True\n" + ] }, { "cell_type": "code", @@ -1829,7 +1847,9 @@ "metadata": { "id": "SktitLxxOR16" }, - "source": [] + "source": [ + "Come possiamo vedere, il valore nullo è stato sostituito. Inutile dire che avremmo potuto scrivere qualsiasi cosa al posto di `'True'` e sarebbe stato sostituito.\n" + ] }, { "cell_type": "markdown", @@ -1838,10 +1858,10 @@ }, "source": [ "### Dati Numerici\n", - "Ora, passiamo ai dati numerici. Qui abbiamo due modi comuni per sostituire i valori mancanti:\n", + "Passiamo ora ai dati numerici. Qui abbiamo due modi comuni per sostituire i valori mancanti:\n", "\n", - "1. Sostituire con la mediana della riga \n", - "2. Sostituire con la media della riga \n", + "1. Sostituire con la mediana della riga\n", + "2. Sostituire con la media della riga\n", "\n", "Sostituiamo con la mediana nel caso di dati asimmetrici con valori anomali. Questo perché la mediana è robusta rispetto ai valori anomali.\n", "\n", @@ -1987,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Riempimento con la media\n" + ] }, { "cell_type": "code", @@ -2086,7 +2108,9 @@ "metadata": { "id": "CwpVFCrPTC5z" }, - "source": [] + "source": [ + "Come possiamo vedere, il valore mancante è stato sostituito con la sua media.\n" + ] }, { "cell_type": "markdown", @@ -2234,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Riempimento con mediana\n" + ] }, { "cell_type": "code", @@ -2376,7 +2402,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "Puoi riempire tutte le voci nulle con un unico valore, come `0`:\n" + "Puoi riempire tutte le voci nulle con un singolo valore, come `0`:\n" ] }, { @@ -2418,10 +2444,10 @@ }, "source": [ "> Punti chiave:\n", - "1. Riempire i valori mancanti dovrebbe essere fatto solo quando ci sono pochi dati o quando esiste una strategia per colmare i dati mancanti.\n", + "1. La compilazione dei valori mancanti dovrebbe essere effettuata quando c'è meno dati o quando esiste una strategia per riempire i dati mancanti.\n", "2. La conoscenza del dominio può essere utilizzata per stimare e riempire i valori mancanti.\n", - "3. Per i dati categorici, spesso i valori mancanti vengono sostituiti con la moda della colonna.\n", - "4. Per i dati numerici, i valori mancanti vengono solitamente riempiti con la media (per dataset normalizzati) o con la mediana delle colonne.\n" + "3. Per i dati categorici, i valori mancanti vengono spesso sostituiti con la moda della colonna.\n", + "4. Per i dati numerici, i valori mancanti vengono solitamente riempiti con la media (per dataset normalizzati) o la mediana delle colonne.\n" ] }, { @@ -2429,7 +2455,9 @@ "metadata": { "id": "FI9MmqFJgRsH" }, - "source": [] + "source": [ + "### Esercizio:\n" + ] }, { "cell_type": "code", @@ -2449,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "Puoi **riempire in avanti** i valori nulli, utilizzando l'ultimo valore valido per riempire un nullo:\n" + ] }, { "cell_type": "code", @@ -2489,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Puoi anche **riempire all'indietro** per propagare il prossimo valore valido all'indietro per riempire un null:\n" + "Puoi anche **riempire a ritroso** per propagare il prossimo valore valido all'indietro per riempire un valore nullo:\n" ] }, { @@ -2703,14 +2733,18 @@ "metadata": { "id": "ZeMc-I1EgRsI" }, - "source": [] + "source": [ + "Nota che quando un valore precedente non è disponibile per il riempimento in avanti, il valore nullo rimane.\n" + ] }, { "cell_type": "markdown", "metadata": { "id": "eeAoOU0RgRsJ" }, - "source": [] + "source": [ + "### Esercizio:\n" + ] }, { "cell_type": "code", @@ -2826,7 +2860,7 @@ "source": [ "Nota che la colonna 3 è ancora priva di valori: la direzione predefinita è quella di riempire i valori riga per riga.\n", "\n", - "> **Conclusione:** Esistono diversi modi per gestire i valori mancanti nei tuoi dataset. La strategia specifica che utilizzi (rimuoverli, sostituirli o anche il modo in cui li sostituisci) dovrebbe essere determinata dalle particolarità di quei dati. Acquisirai una maggiore consapevolezza su come affrontare i valori mancanti man mano che gestirai e interagirai con i dataset.\n" + "> **Conclusione:** Esistono diversi modi per gestire i valori mancanti nei tuoi dataset. La strategia specifica che utilizzi (rimuoverli, sostituirli o anche il modo in cui li sostituisci) dovrebbe essere determinata dalle caratteristiche specifiche di quei dati. Acquisirai una maggiore consapevolezza su come affrontare i valori mancanti man mano che gestirai e interagirai con i dataset.\n" ] }, { @@ -2835,9 +2869,9 @@ "id": "bauDnESIl9FH" }, "source": [ - "### Codifica dei Dati Categoriali\n", + "### Codifica dei dati categorici\n", "\n", - "I modelli di machine learning lavorano esclusivamente con numeri e qualsiasi tipo di dato numerico. Non sono in grado di distinguere tra un Sì e un No, ma possono differenziare tra 0 e 1. Quindi, dopo aver riempito i valori mancanti, è necessario codificare i dati categoriali in una forma numerica affinché il modello possa comprenderli.\n", + "I modelli di machine learning lavorano esclusivamente con numeri e qualsiasi tipo di dato numerico. Non sono in grado di distinguere tra un Sì e un No, ma possono differenziare tra 0 e 1. Quindi, dopo aver riempito i valori mancanti, è necessario codificare i dati categorici in una forma numerica affinché il modello possa comprenderli.\n", "\n", "La codifica può essere effettuata in due modi. Li discuteremo di seguito.\n" ] @@ -2958,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Per eseguire la codifica delle etichette sulla prima colonna, dobbiamo prima descrivere una mappatura da ogni classe a un numero, prima di sostituire\n" + "Per eseguire la codifica delle etichette sulla prima colonna, dobbiamo prima descrivere una mappatura da ogni classe a un numero, prima di sostituire.\n" ] }, { @@ -3060,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Come possiamo vedere, il risultato corrisponde a ciò che ci aspettavamo. Quindi, quando si utilizza l'encoding delle etichette? L'encoding delle etichette viene utilizzato in uno o entrambi i seguenti casi: \n", - "1. Quando il numero di categorie è elevato \n", - "2. Quando le categorie sono ordinate. \n" + "Come possiamo vedere, l'output corrisponde a ciò che pensavamo sarebbe successo. Quindi, quando utilizziamo l'etichettatura delle categorie? L'etichettatura delle categorie viene utilizzata in uno o entrambi i seguenti casi:\n", + "1. Quando il numero di categorie è elevato\n", + "2. Quando le categorie sono ordinate.\n" ] }, { @@ -3075,7 +3109,7 @@ "\n", "Un altro tipo di codifica è la One Hot Encoding. In questo tipo di codifica, ogni categoria della colonna viene aggiunta come una colonna separata e ogni punto dati riceverà uno 0 o un 1 in base al fatto che contenga o meno quella categoria. Quindi, se ci sono n categorie diverse, n colonne verranno aggiunte al dataframe.\n", "\n", - "Ad esempio, prendiamo lo stesso esempio della classe dell'aeroplano. Le categorie erano: ['business class', 'economy class', 'first class']. Quindi, se eseguiamo la One Hot Encoding, le seguenti tre colonne verranno aggiunte al dataset: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Ad esempio, prendiamo lo stesso esempio delle classi di aeroplani. Le categorie erano: ['business class', 'economy class', 'first class']. Quindi, se applichiamo la One Hot Encoding, le seguenti tre colonne verranno aggiunte al dataset: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3317,7 +3351,7 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "Quando utilizziamo la codifica one hot? La codifica one hot viene utilizzata in uno o entrambi i seguenti casi:\n", + "Quando si utilizza la codifica one hot? La codifica one hot viene utilizzata in uno o entrambi i seguenti casi:\n", "\n", "1. Quando il numero di categorie e la dimensione del dataset sono ridotti.\n", "2. Quando le categorie non seguono un ordine particolare.\n" @@ -3330,7 +3364,7 @@ }, "source": [ "> Punti chiave:\n", - "1. La codifica viene utilizzata per convertire dati non numerici in dati numerici.\n", + "1. La codifica viene effettuata per convertire i dati non numerici in dati numerici.\n", "2. Esistono due tipi di codifica: codifica delle etichette e codifica One Hot, entrambe possono essere eseguite in base alle esigenze del dataset.\n" ] }, @@ -3342,9 +3376,9 @@ "source": [ "## Rimozione dei dati duplicati\n", "\n", - "> **Obiettivo di apprendimento:** Alla fine di questa sottosezione, dovresti sentirti a tuo agio nell'identificare e rimuovere valori duplicati dai DataFrame.\n", + "> **Obiettivo di apprendimento:** Alla fine di questa sottosezione, dovresti sentirti a tuo agio nell'identificare e rimuovere i valori duplicati dai DataFrame.\n", "\n", - "Oltre ai dati mancanti, nei dataset reali ti capiterà spesso di incontrare dati duplicati. Fortunatamente, pandas offre un metodo semplice per rilevare e rimuovere le voci duplicate.\n" + "Oltre ai dati mancanti, spesso incontrerai dati duplicati nei dataset del mondo reale. Fortunatamente, pandas offre un metodo semplice per rilevare e rimuovere le voci duplicate.\n" ] }, { @@ -3568,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Sia `duplicated` che `drop_duplicates` considerano per default tutte le colonne, ma puoi specificare che esaminino solo un sottoinsieme di colonne nel tuo `DataFrame`:\n" + "Sia `duplicated` che `drop_duplicates` considerano di default tutte le colonne, ma puoi specificare che esaminino solo un sottoinsieme di colonne nel tuo `DataFrame`:\n" ] }, { @@ -3644,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Conclusione:** Rimuovere i dati duplicati è una parte essenziale di quasi ogni progetto di data science. I dati duplicati possono alterare i risultati delle tue analisi e fornire risultati inaccurati!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Controlli di qualità dei dati nel mondo reale\n", + "\n", + "> **Obiettivo di apprendimento:** Al termine di questa sezione, dovresti sentirti a tuo agio nel rilevare e correggere i problemi comuni di qualità dei dati nel mondo reale, inclusi valori categorici incoerenti, valori numerici anomali (outlier) e entità duplicate con variazioni.\n", + "\n", + "Sebbene i valori mancanti e i duplicati esatti siano problemi comuni, i dataset del mondo reale spesso contengono problemi più sottili:\n", + "\n", + "1. **Valori categorici incoerenti**: La stessa categoria scritta in modo diverso (ad esempio, \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Valori numerici anomali**: Outlier estremi che indicano errori di inserimento dati (ad esempio, età = 999)\n", + "3. **Righe quasi duplicate**: Record che rappresentano la stessa entità con leggere variazioni\n", + "\n", + "Esploriamo le tecniche per rilevare e gestire questi problemi.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Creare un Dataset \"Sporco\" di Esempio\n", + "\n", + "Per iniziare, creiamo un dataset di esempio che contenga i tipi di problemi che incontriamo comunemente nei dati del mondo reale:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Rilevare Valori Categoriali Incoerenti\n", + "\n", + "Nota che la colonna `country` ha diverse rappresentazioni per gli stessi paesi. Identifichiamo queste incoerenze:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Standardizzare i Valori Categoriali\n", + "\n", + "Possiamo creare una mappatura per standardizzare questi valori. Un approccio semplice è convertire tutto in minuscolo e creare un dizionario di mappatura:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternativa: Utilizzo del Fuzzy Matching**\n", + "\n", + "Per casi più complessi, possiamo utilizzare il fuzzy string matching con la libreria `rapidfuzz` per rilevare automaticamente stringhe simili:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Rilevamento di Valori Numerici Anomali (Outliers)\n", + "\n", + "Osservando la colonna `age`, ci sono alcuni valori sospetti come 199 e -5. Utilizziamo metodi statistici per rilevare questi outliers.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Utilizzo del Metodo IQR (Intervallo Interquartile)\n", + "\n", + "Il metodo IQR è una tecnica statistica robusta per il rilevamento degli outlier, meno sensibile ai valori estremi:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Utilizzo del Metodo Z-Score\n", + "\n", + "Il metodo Z-score identifica i valori anomali basandosi sulle deviazioni standard dalla media:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Gestione degli outlier\n", + "\n", + "Una volta rilevati, gli outlier possono essere gestiti in diversi modi:\n", + "1. **Rimuovere**: Eliminare le righe con outlier (se sono errori)\n", + "2. **Limitare**: Sostituire con valori limite\n", + "3. **Sostituire con NaN**: Trattarli come dati mancanti e utilizzare tecniche di imputazione\n", + "4. **Mantenere**: Se sono valori estremi legittimi\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Rilevamento di righe quasi duplicate\n", + "\n", + "Nota che il nostro dataset contiene più voci per \"John Smith\" con valori leggermente diversi. Identifichiamo i potenziali duplicati basandoci sulla somiglianza dei nomi.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Trovare quasi duplicati con il fuzzy matching\n", + "\n", + "Per una rilevazione più avanzata dei duplicati, possiamo utilizzare il fuzzy matching per trovare nomi simili:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Gestione dei duplicati\n", + "\n", + "Una volta identificati, devi decidere come gestire i duplicati:\n", + "1. **Mantenere la prima occorrenza**: Usa `drop_duplicates(keep='first')`\n", + "2. **Mantenere l'ultima occorrenza**: Usa `drop_duplicates(keep='last')`\n", + "3. **Aggregare le informazioni**: Combina le informazioni dalle righe duplicate\n", + "4. **Revisione manuale**: Segnala per una revisione umana\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Riepilogo: Pipeline Completa di Pulizia dei Dati\n", + "\n", + "Mettiamo tutto insieme in una pipeline completa di pulizia:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Esercizio di Sfida\n", + "\n", + "Ora tocca a te! Qui sotto c'è una nuova riga di dati con diversi problemi di qualità. Riesci a:\n", + "\n", + "1. Identificare tutti i problemi in questa riga\n", + "2. Scrivere il codice per correggere ogni problema\n", + "3. Aggiungere la riga corretta al dataset\n", + "\n", + "Ecco i dati problematici:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Punti Chiave\n", + "\n", + "1. **Categorie incoerenti** sono comuni nei dati del mondo reale. Controlla sempre i valori unici e standardizzali utilizzando mappature o confronti approssimativi.\n", + "\n", + "2. **Valori anomali** possono influenzare significativamente la tua analisi. Usa la conoscenza del dominio combinata con metodi statistici (IQR, Z-score) per rilevarli.\n", + "\n", + "3. **Quasi-duplicati** sono più difficili da individuare rispetto ai duplicati esatti. Considera l'uso di confronti approssimativi e la normalizzazione dei dati (conversione in minuscolo, rimozione degli spazi) per identificarli.\n", + "\n", + "4. **La pulizia dei dati è iterativa**. Potresti dover applicare più tecniche e rivedere i risultati prima di finalizzare il tuo dataset pulito.\n", + "\n", + "5. **Documenta le tue decisioni**. Tieni traccia dei passaggi di pulizia che hai applicato e del motivo, poiché questo è importante per la riproducibilità e la trasparenza.\n", + "\n", + "> **Migliore Pratica:** Conserva sempre una copia dei tuoi dati originali \"sporchi\". Non sovrascrivere mai i file di origine dei dati - crea versioni pulite con convenzioni di denominazione chiare come `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Disclaimer (Avvertenza)**: \nQuesto documento è stato tradotto utilizzando il servizio di traduzione automatica [Co-op Translator](https://github.com/Azure/co-op-translator). Sebbene ci impegniamo per garantire l'accuratezza, si prega di tenere presente che le traduzioni automatiche possono contenere errori o imprecisioni. Il documento originale nella sua lingua nativa dovrebbe essere considerato la fonte autorevole. Per informazioni critiche, si raccomanda una traduzione professionale effettuata da un traduttore umano. Non siamo responsabili per eventuali malintesi o interpretazioni errate derivanti dall'uso di questa traduzione.\n" + "\n---\n\n**Clausola di esclusione della responsabilità**: \nQuesto documento è stato tradotto utilizzando il servizio di traduzione automatica [Co-op Translator](https://github.com/Azure/co-op-translator). Sebbene ci impegniamo per garantire l'accuratezza, si prega di notare che le traduzioni automatiche possono contenere errori o imprecisioni. Il documento originale nella sua lingua nativa dovrebbe essere considerato la fonte autorevole. Per informazioni critiche, si raccomanda una traduzione professionale effettuata da un traduttore umano. Non siamo responsabili per eventuali incomprensioni o interpretazioni errate derivanti dall'uso di questa traduzione.\n" ] } ], @@ -3678,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T22:02:38+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:59:35+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "it" } diff --git a/translations/ja/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/ja/2-Working-With-Data/08-data-preparation/notebook.ipynb index 0dab0c56..d901c507 100644 --- a/translations/ja/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/ja/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# データ準備\n", "\n", - "[オリジナルノートブックの出典: *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[元のノートブックの出典: *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", - "## `DataFrame`情報の探索\n", + "## `DataFrame`の情報を探索する\n", "\n", - "> **学習目標:** このセクションの終わりまでに、pandasのDataFrameに格納されたデータの一般的な情報を見つける方法に慣れることができます。\n", + "> **学習目標:** このセクションの終わりまでに、pandasのDataFrameに保存されたデータの一般的な情報を見つけることに慣れることができます。\n", "\n", - "データをpandasに読み込むと、ほとんどの場合、それは`DataFrame`の形式になります。しかし、もしその`DataFrame`に60,000行と400列のデータが含まれていたら、どのようにしてそのデータの概要を把握し始めればよいのでしょうか?幸いなことに、pandasは`DataFrame`全体の情報や最初と最後の数行を素早く確認するための便利なツールを提供しています。\n", + "データをpandasに読み込むと、ほとんどの場合、それは`DataFrame`の形式になります。しかし、もしその`DataFrame`に60,000行と400列のデータが含まれていたら、どのようにして扱うデータの概要を把握すればよいのでしょうか?幸いなことに、pandasは`DataFrame`の全体的な情報を素早く確認するための便利なツールを提供しており、最初の数行や最後の数行も簡単に確認できます。\n", "\n", - "この機能を探索するために、Pythonのscikit-learnライブラリをインポートし、すべてのデータサイエンティストが何百回も目にしたことがある象徴的なデータセットを使用します。それは、イギリスの生物学者ロナルド・フィッシャーが1936年の論文「分類問題における複数測定の利用」で使用した*アヤメ*データセットです。\n" + "この機能を探索するために、Pythonのscikit-learnライブラリをインポートし、データサイエンティストなら誰もが何度も目にしたことのある象徴的なデータセットを使用します。それは、英国の生物学者ロナルド・フィッシャーが1936年の論文「分類学的問題における複数の測定値の使用」で使用した*アイリス*データセットです。\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "変数 `iris_df` に Iris データセットを読み込みました。データを詳しく見る前に、データポイントの数やデータセット全体のサイズを把握することは有益です。扱っているデータの量を確認するのは役立ちます。\n" + "変数 `iris_df` に Iris データセットを読み込みました。データを詳しく調べる前に、データポイントの数やデータセット全体のサイズを把握することは重要です。扱っているデータの量を確認するのは有益です。\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "つまり、150行と4列のデータを扱っています。各行は1つのデータポイントを表し、各列はデータフレームに関連する1つの特徴を表しています。要するに、150個のデータポイントがあり、それぞれに4つの特徴が含まれています。\n", + "つまり、150行4列のデータを扱っています。各行は1つのデータポイントを表し、各列はデータフレームに関連する1つの特徴を表します。要するに、150のデータポイントがあり、それぞれに4つの特徴が含まれています。\n", "\n", - "`shape`はデータフレームの属性であり、関数ではないため、括弧で終わっていません。\n" + "`shape`はデータフレームの属性であり、関数ではないため、括弧で終わらないのです。\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "では、データの4つの列について見ていきましょう。それぞれの列が具体的に何を表しているのか?`columns`属性を使用すると、データフレーム内の列名を取得することができます。\n" + "では、データの4つの列について詳しく見ていきましょう。それぞれの列が具体的に何を表しているのかを確認します。`columns`属性を使用すると、データフレーム内の列名を取得できます。\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "私たちが見るように、4つの列があります。`columns`属性は列の名前を教えてくれるだけで、基本的にそれ以外のことは何も教えてくれません。この属性は、データセットが含む特徴を特定したいときに重要性を持ちます。\n" + "私たちが見るように、4つの列があります。`columns`属性は列の名前を教えてくれるだけで、基本的にそれ以外の情報はありません。この属性は、データセットが含む特徴を特定したいときに重要性を持ちます。\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "データの量(`shape`属性で示される)や特徴や列の名前(`columns`属性で示される)は、データセットについて何かを教えてくれます。次に、データセットをさらに詳しく調べたいと思います。その際に、`DataFrame.info()`関数は非常に役立ちます。\n" + "データの量(`shape`属性で示される)や特徴や列の名前(`columns`属性で示される)は、データセットについて何かを教えてくれます。さて、データセットをさらに深く掘り下げたいと思います。その際に、`DataFrame.info()`関数は非常に役立ちます。\n" ] }, { @@ -182,7 +182,7 @@ "source": [ "ここから、いくつかの観察ができます:\n", "1. 各列のデータ型:このデータセットでは、すべてのデータが64ビット浮動小数点数として保存されています。\n", - "2. 非Null値の数:Null値を処理することは、データ準備において重要なステップです。これについては、後ほどノートブック内で対処します。\n" + "2. 非NULL値の数:NULL値を処理することは、データ準備において重要なステップです。この処理は後でノートブック内で行います。\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "上記の出力は、各列のデータポイントの総数、平均、標準偏差、最小値、下位四分位数(25%)、中央値(50%)、上位四分位数(75%)、および最大値を示しています。\n" + "上記の出力は、各列のデータポイントの総数、平均、標準偏差、最小値、下位四分位数(25%)、中央値(50%)、上位四分位数(75%)、最大値を示しています。\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "これまでの関数や属性を使って、データセットの概要を把握しました。データポイントの数、特徴量の数、各特徴量のデータ型、そして各特徴量の非null値の数が分かりました。\n", + "これまでに紹介した関数や属性を使って、データセットの概要を把握しました。データポイントの数、特徴量の数、各特徴量のデータ型、そして各特徴量の非null値の数が分かりました。\n", "\n", - "次は、実際のデータを確認する段階です。`DataFrame`の最初の数行(最初のいくつかのデータポイント)がどのようになっているか見てみましょう。\n" + "次は、実際のデータを確認する段階です。`DataFrame`の最初の数行(最初のいくつかのデータポイント)がどのようになっているか見てみましょう:\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "データを見る別の方法として、始まりではなく終わりから見ることができます。`DataFrame.head`の反対が`DataFrame.tail`であり、`DataFrame`の最後の5行を返します:\n" + "データを見るもう一つの方法は、始まりではなく終わりから見ることです。`DataFrame.head`の反対にあたるのが`DataFrame.tail`で、これは`DataFrame`の最後の5行を返します:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "データセットが順序付けられている場合、特に外れ値を探しているときには、`DataFrame`の最初の数行や最後の数行を簡単に確認できることが実用的です。\n", + "実際には、特に順序付けられたデータセットで外れ値を探している場合、`DataFrame`の最初の数行や最後の数行を簡単に確認できることが便利です。\n", "\n", - "上記でコード例を使って示したすべての関数や属性は、データの外観や感触を把握するのに役立ちます。\n", + "コード例を使って示したすべての関数や属性は、データの概要や感触を得るのに役立ちます。\n", "\n", - "> **ポイント:** `DataFrame`内の情報に関するメタデータや、最初および最後の数値を確認するだけでも、扱っているデータのサイズ、形状、内容について即座に把握することができます。\n" + "> **ポイント:** `DataFrame`内の情報に関するメタデータや、最初と最後の数値を確認するだけでも、扱っているデータのサイズ、形状、内容について即座に把握することができます。\n" ] }, { @@ -596,17 +596,17 @@ }, "source": [ "### 欠損データ\n", - "欠損データについて見ていきましょう。欠損データとは、いくつかの列に値が保存されていない場合に発生します。\n", + "欠損データについて詳しく見ていきましょう。欠損データとは、いくつかの列に値が保存されていない場合に発生します。\n", "\n", - "例を挙げてみましょう。例えば、ある人が自分の体重を気にしていて、アンケートの体重欄を記入しないとします。その場合、その人の体重の値は欠損となります。\n", + "例を挙げてみましょう。例えば、ある人が自分の体重を気にしていて、アンケートの体重欄を記入しないとします。この場合、その人の体重の値は欠損となります。\n", "\n", "現実世界のデータセットでは、欠損値が発生することがほとんどです。\n", "\n", - "**Pandasが欠損データを処理する方法**\n", + "**Pandasによる欠損データの処理方法**\n", "\n", "Pandasは欠損値を2つの方法で処理します。1つ目は、以前のセクションで見たことがある`NaN`(Not a Number)です。これは実際にはIEEE浮動小数点仕様の一部であり、欠損した浮動小数点値を示すためだけに使用される特別な値です。\n", "\n", - "浮動小数点以外の欠損値に対しては、PandasはPythonの`None`オブジェクトを使用します。2種類の異なる値が本質的に同じことを示しているように見えるため混乱するかもしれませんが、この設計選択には合理的なプログラム上の理由があります。そして実際には、この方法を採用することで、Pandasはほとんどのケースにおいて良い妥協点を提供することができます。それにもかかわらず、`None`と`NaN`の両方には、それらがどのように使用できるかに関して注意すべき制約があります。\n" + "浮動小数点以外の欠損値については、PandasはPythonの`None`オブジェクトを使用します。2種類の値が本質的に同じことを示しているのに遭遇するのは混乱するかもしれませんが、この設計選択には合理的なプログラム上の理由があります。実際、この方法を採用することで、Pandasは大多数のケースにおいて良い妥協点を提供することができます。それにもかかわらず、`None`と`NaN`の両方には、それらの使用方法に関して注意すべき制約があることを覚えておく必要があります。\n" ] }, { @@ -615,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: 非浮動小数点の欠損データ\n", - "`None` は Python 由来のため、データ型が `'object'` でない NumPy や pandas の配列では使用できません。覚えておいてください。NumPy 配列(および pandas のデータ構造)は、1種類のデータ型しか含むことができません。これが、大規模なデータ処理や計算作業における強力な性能をもたらす一方で、柔軟性を制限する要因にもなっています。このような配列は「最小公倍数」のデータ型、つまり配列内のすべてを包含できるデータ型にアップキャストされる必要があります。配列内に `None` が含まれる場合、それは Python オブジェクトを扱っていることを意味します。\n", + "### `None`: 非浮動小数点型の欠損データ\n", + "`None`はPythonから来ているため、データ型が`'object'`でないNumPyやpandasの配列では使用できません。NumPy配列(およびpandasのデータ構造)は、1種類のデータ型しか含むことができません。これが、大規模なデータ処理や計算作業における強力な性能を提供する理由ですが、同時に柔軟性を制限する要因にもなります。このような配列は「最小公分母」に型をアップキャストする必要があり、配列内のすべてを包含するデータ型に変換されます。配列に`None`が含まれる場合、それはPythonオブジェクトを扱っていることを意味します。\n", "\n", - "これを実際に確認するために、以下の例の配列を考えてみてください(その `dtype` に注目してください):\n" + "これを実際に確認するために、以下の例の配列を考えてみましょう(その`dtype`に注目してください):\n" ] }, { @@ -657,7 +657,7 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "アップキャストされたデータ型の現実には、2つの副作用が伴います。まず、操作がコンパイルされたNumPyコードではなく、解釈されたPythonコードのレベルで実行されるという点です。つまり、`None`を含む`Series`や`DataFrame`を扱う操作は遅くなるということです。このパフォーマンスの低下はおそらく気づかない程度かもしれませんが、大規模なデータセットでは問題になる可能性があります。\n", + "アップキャストされたデータ型の現実には、2つの副作用が伴います。まず、操作がコンパイルされたNumPyコードではなく、解釈されたPythonコードのレベルで実行されるようになります。つまり、`None`を含む`Series`や`DataFrame`を操作する場合、処理速度が遅くなるということです。このパフォーマンス低下はおそらく気づかない程度かもしれませんが、大規模なデータセットでは問題になる可能性があります。\n", "\n", "2つ目の副作用は、1つ目から派生しています。`None`が本質的に`Series`や`DataFrame`を通常のPythonの世界に引き戻してしまうため、`sum()`や`min()`のようなNumPy/pandasの集計関数を`None`を含む配列に対して使用すると、一般的にエラーが発生します。\n" ] @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**重要なポイント**: 整数と`None`値の間の加算(およびその他の操作)は未定義であり、それによりそれらを含むデータセットでできることが制限される可能性があります。\n" + "**重要なポイント**: 整数と`None`値の間の加算(およびその他の演算)は未定義であり、それらを含むデータセットでできることを制限する可能性があります。\n" ] }, { @@ -707,9 +707,9 @@ "id": "pWvVHvETgRr9" }, "source": [ - "### `NaN`: 浮動小数点値の欠損\n", + "### `NaN`: 欠損した浮動小数点値\n", "\n", - "`None`とは異なり、NumPy(そしてpandas)は高速でベクトル化された操作やufuncをサポートするために`NaN`を使用します。問題点として、`NaN`に対して行われる算術演算は常に`NaN`を返します。例えば:\n" + "`None`とは異なり、NumPy(そしてpandas)は高速でベクトル化された操作やufuncのために`NaN`をサポートしています。悪いニュースとしては、`NaN`に対して行われる算術演算は常に`NaN`を返すという点です。例えば:\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "良いニュース:`NaN` を含む配列で集計を実行してもエラーは発生しません。悪いニュース:結果は一様に有用ではありません。\n" + "良いニュース: `NaN` を含む配列で集計を実行してもエラーは発生しません。悪いニュース: 結果は一様に有用ではありません。\n" ] }, { @@ -831,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "`NaN`は浮動小数点値が欠落している場合にのみ使用されます。整数、文字列、またはブール値には`NaN`に相当するものはありません。\n" + "覚えておいてください: `NaN` は欠損している浮動小数点値のためだけのものであり、整数、文字列、またはブール値には `NaN` に相当するものはありません。\n" ] }, { @@ -842,7 +842,7 @@ "source": [ "### `NaN` と `None`: pandas における null 値\n", "\n", - "`NaN` と `None` は多少異なる動作をすることがありますが、pandas はそれらを同じように扱えるように設計されています。その意味を確認するために、整数の `Series` を考えてみましょう:\n" + "`NaN` と `None` は多少異なる動作をすることがありますが、pandas はそれらを同じように扱えるように設計されています。これを確認するために、整数の `Series` を考えてみましょう:\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "データ型を統一するために`Series`や`DataFrame`で型をアップキャストする過程で、pandasは欠損値を`None`と`NaN`の間で自由に切り替えます。この設計上の特徴から、pandasでは`None`と`NaN`を「null」の2つの異なる形態として考えると便利です。実際、pandasで欠損値を扱うために使用する主要なメソッドの名前には、この考え方が反映されています。\n", + "データ型をアップキャストして`Series`や`DataFrame`内でデータの均一性を確保する過程で、pandasは欠損値を`None`と`NaN`の間で自由に切り替えます。この設計上の特徴から、pandasでは`None`と`NaN`を「null」の2つの異なる形態として考えると便利です。実際、pandasで欠損値を扱うための主要なメソッドの名前には、この考え方が反映されています。\n", "\n", - "- `isnull()`: 欠損値を示すブールマスクを生成\n", - "- `notnull()`: `isnull()`の反対\n", - "- `dropna()`: データのフィルタリングされたバージョンを返す\n", - "- `fillna()`: 欠損値を埋めるか補完したデータのコピーを返す\n", + "- `isnull()`: 欠損値を示すブールマスクを生成します\n", + "- `notnull()`: `isnull()`の逆の動作をします\n", + "- `dropna()`: 欠損値を除去したデータのフィルタリング版を返します\n", + "- `fillna()`: 欠損値を埋めるか補完したデータのコピーを返します\n", "\n", - "これらのメソッドは非常に重要で、使いこなせるようになることが求められます。それぞれについて詳しく見ていきましょう。\n" + "これらのメソッドは非常に重要で、使いこなせるようになることが求められます。それでは、それぞれのメソッドについて詳しく見ていきましょう。\n" ] }, { @@ -925,7 +925,7 @@ "### 欠損値の検出\n", "\n", "欠損値の重要性を理解したところで、それらを処理する前にデータセット内で検出する必要があります。 \n", - "`isnull()` と `notnull()` の両方が、欠損データを検出するための主要なメソッドです。どちらもデータに対してブールマスクを返します。\n" + "`isnull()` と `notnull()` の両方が欠損データを検出するための主要なメソッドです。これらはどちらもデータに対してブールマスクを返します。\n" ] }, { @@ -978,9 +978,9 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "出力をよく見てください。何か驚く点はありますか?`0`は算術的には「無」を表しますが、それでも完全に有効な整数であり、pandasもそのように扱います。一方で、`''`は少し微妙です。セクション1で空の文字列値を表すために使用しましたが、それでも文字列オブジェクトであり、pandasにとっては「null」を表すものではありません。\n", + "出力をよく見てください。何か驚くことはありますか?`0`は算術的には「null」ですが、それでも完全に有効な整数であり、pandasはそれをそのように扱います。一方、`''`は少し微妙です。セクション1で空の文字列値を表すために使用しましたが、それでも文字列オブジェクトであり、pandasにとっては「null」を表すものではありません。\n", "\n", - "さて、これを逆にして、実際に使うような形でこれらのメソッドを使用してみましょう。Booleanマスクを直接``Series``や``DataFrame``のインデックスとして使用することができます。これは、欠損値(または存在する値)を分離して操作しようとする際に便利です。\n", + "さて、これを逆にして、実際に使用する方法に近い形でこれらのメソッドを使ってみましょう。Booleanマスクを直接``Series``や``DataFrame``のインデックスとして使用することができ、欠損値(または存在する値)を個別に操作する際に便利です。\n", "\n", "欠損値の総数を知りたい場合は、`isnull()`メソッドによって生成されたマスクに対して単純に合計を取るだけで済みます。\n" ] @@ -1040,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**重要なポイント**: DataFrameで`isnull()`と`notnull()`メソッドを使用すると、どちらも似たような結果を生成します。それらは結果とそのインデックスを表示し、データを扱う際に非常に役立ちます。\n" + "**重要なポイント**: `isnull()` と `notnull()` メソッドは、DataFrameで使用すると似たような結果を生成します。それらは結果とそのインデックスを表示し、データを扱う際に非常に役立ちます。\n" ] }, { @@ -1051,16 +1051,16 @@ "source": [ "### 欠損データの処理\n", "\n", - "> **学習目標:** このセクションの終わりまでに、DataFrameから欠損値を置き換える方法や削除するタイミングを理解できるようになります。\n", + "> **学習目標:** このセクションの終わりまでに、DataFrameから欠損値を置き換えるべきか、または削除するべきかを判断できるようになります。\n", "\n", "機械学習モデルは欠損データをそのまま扱うことができません。そのため、データをモデルに渡す前に、これらの欠損値を処理する必要があります。\n", "\n", "欠損データの処理方法には微妙なトレードオフが伴い、最終的な分析結果や現実世界での成果に影響を与える可能性があります。\n", "\n", - "欠損データを処理する主な方法は以下の2つです:\n", + "欠損データを処理する方法は主に以下の2つです:\n", "\n", - "1. 欠損値を含む行を削除する\n", - "2. 欠損値を他の値で置き換える\n", + "1. 欠損値を含む行を削除する \n", + "2. 欠損値を他の値で置き換える \n", "\n", "これらの方法について、それぞれの利点と欠点を詳しく説明していきます。\n" ] @@ -1075,9 +1075,9 @@ "\n", "モデルに渡すデータ量は、その性能に直接影響を与えます。欠損値を削除するということは、データポイントの数を減らし、データセットのサイズを縮小することを意味します。そのため、データセットが非常に大きい場合には、欠損値を含む行を削除することが推奨されます。\n", "\n", - "また、特定の行や列に欠損値が多く含まれている場合、それらを削除することもあります。なぜなら、その行や列のほとんどのデータが欠けているため、分析にあまり価値を加えない可能性があるからです。\n", + "また、特定の行や列に欠損値が多く含まれている場合もあります。その場合、それらを削除することが考えられます。なぜなら、その行や列のほとんどのデータが欠損しているため、分析にあまり価値を加えない可能性があるからです。\n", "\n", - "欠損値を特定するだけでなく、pandasは`Series`や`DataFrame`から欠損値を削除する便利な方法を提供しています。これを実際に確認するために、`example3`に戻りましょう。`DataFrame.dropna()`関数は、欠損値を含む行を削除するのに役立ちます。\n" + "欠損値を特定するだけでなく、pandasは`Series`や`DataFrame`から欠損値を削除する便利な方法を提供しています。これを実際に試してみるために、`example3`に戻りましょう。`DataFrame.dropna()`関数は、欠損値を含む行を削除するのに役立ちます。\n" ] }, { @@ -1116,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "`example3[example3.notnull()]` の出力に似ていることに注意してください。ここでの違いは、マスクされた値をインデックスするだけではなく、`dropna` が `Series` `example3` から欠損値を削除した点です。\n", + "`example3[example3.notnull()]` の出力と似ていることに注意してください。ここでの違いは、マスクされた値に基づいてインデックスを付けるだけではなく、`dropna` が `Series` `example3` から欠損値を削除した点です。\n", "\n", - "DataFrame は2次元であるため、データを削除する際により多くの選択肢があります。\n" + "DataFrame は2次元であるため、データを削除する際により多くのオプションが利用可能です。\n" ] }, { @@ -1208,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(pandasが2つの列を`NaN`に対応するために浮動小数点型にアップキャストしたことに気づきましたか?)\n", + "(pandasが`NaN`を処理するために2つの列を浮動小数点型にアップキャストしたことに気づきましたか?)\n", "\n", - "`DataFrame`から単一の値を削除することはできないため、行または列全体を削除する必要があります。行う内容によって、どちらかを選ぶことになるでしょう。そのため、pandasは両方の選択肢を提供しています。データサイエンスでは、一般的に列は変数を表し、行は観測値を表すため、データの行を削除することが多くなります。`dropna()`のデフォルト設定では、null値を含むすべての行を削除するようになっています。\n" + "`DataFrame`から単一の値を削除することはできないため、行または列全体を削除する必要があります。作業内容によって、どちらかを選ぶ必要があり、pandasはその両方のオプションを提供しています。データサイエンスでは、列が一般的に変数を表し、行が観測値を表すため、データの行を削除することが多いです。`dropna()`のデフォルト設定では、null値を含むすべての行を削除します。\n" ] }, { @@ -1283,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "必要に応じて、列からNA値を削除することができます。`axis=1`を使用してください。\n" + "必要に応じて、列からNA値を削除できます。これを行うには、`axis=1`を使用してください。\n" ] }, { @@ -1362,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "データが少ない場合、保持したいデータが多く失われる可能性があります。では、いくつか、またはすべての値がnullである行や列だけを削除したい場合はどうすればよいでしょうか?その場合、`dropna`の`how`および`thresh`パラメータを設定します。\n", + "これにより、特に小規模なデータセットでは、保持したいデータが多く失われる可能性があることに注意してください。では、いくつか、またはすべての値がnullである行や列だけを削除したい場合はどうすればよいでしょうか?その設定は、`dropna`の`how`および`thresh`パラメータで指定します。\n", "\n", - "デフォルトでは、`how='any'`が設定されています(自分で確認したり、他のパラメータを確認したい場合は、コードセルで`example4.dropna?`を実行してください)。代わりに`how='all'`を指定することで、すべての値がnullである行や列だけを削除することもできます。次の演習で、この動作を確認するために例の`DataFrame`を拡張してみましょう。\n" + "デフォルトでは、`how='any'`です(自分で確認したり、メソッドに他にどのようなパラメータがあるかを確認したい場合は、コードセルで`example4.dropna?`を実行してください)。代わりに`how='all'`を指定することで、すべての値がnullである行や列だけを削除することもできます。次の演習で、この動作を確認するために例の`DataFrame`を拡張してみましょう。\n" ] }, { @@ -1457,10 +1457,10 @@ }, "source": [ "> 主なポイント:\n", - "1. データセットが十分に大きい場合に限り、欠損値を削除するのは良いアイデアです。\n", - "2. データの大部分が欠損している行や列は削除することができます。\n", - "3. `DataFrame.dropna(axis=)` メソッドは欠損値を削除するのに役立ちます。`axis` 引数は、行を削除するのか列を削除するのかを指定します。\n", - "4. `how` 引数も使用できます。デフォルトでは `any` に設定されています。そのため、欠損値を含む行や列のみが削除されます。`all` に設定すると、すべての値が欠損している行や列のみを削除するよう指定できます。\n" + "1. データセットが十分に大きい場合に限り、欠損値を削除するのが良い選択です。\n", + "2. データの大部分が欠損している場合は、行や列全体を削除することができます。\n", + "3. `DataFrame.dropna(axis=)` メソッドは欠損値を削除する際に役立ちます。`axis` 引数は、行を削除するか列を削除するかを指定します。\n", + "4. `how` 引数も使用可能です。デフォルトでは `any` に設定されており、欠損値を含む行や列のみを削除します。`all` に設定すると、すべての値が欠損している行や列のみを削除することを指定できます。\n" ] }, { @@ -1492,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "`thresh` パラメーターは、より細かい制御を提供します。行や列を保持するために必要な *非ヌル* 値の数を設定します。\n" + "`thresh` パラメーターは、より細かい制御を提供します: 行または列を保持するために必要な *非ヌル* 値の数を設定します。\n" ] }, { @@ -1567,7 +1567,7 @@ "id": "fmSFnzZegRsG" }, "source": [ - "最初と最後の行は、非NULL値が2つしか含まれていないため削除されました。\n" + "ここでは、最初と最後の行が削除されています。これらの行には非NULL値が2つしか含まれていないためです。\n" ] }, { @@ -1580,7 +1580,7 @@ "\n", "欠損値を有効な値で補完することが理にかなう場合があります。欠損値を補完するためのいくつかの手法があります。最初の方法は、ドメイン知識(データセットが基づいている対象分野の知識)を活用して欠損値をある程度推定することです。\n", "\n", - "`isnull`を使って欠損値を補完することもできますが、多くの値を補完する必要がある場合は手間がかかることがあります。このような作業はデータサイエンスでは非常に一般的なため、pandasは`fillna`を提供しています。`fillna`は、欠損値を指定した値で置き換えた`Series`や`DataFrame`のコピーを返します。これが実際にどのように機能するかを確認するために、別の例として`Series`を作成してみましょう。\n" + "`isnull`を使って欠損値を補完することもできますが、多くの値を補完する必要がある場合は手間がかかることがあります。このような作業はデータサイエンスでは非常に一般的なため、pandasは`fillna`を提供しています。これを使うと、欠損値を指定した値で置き換えた`Series`や`DataFrame`のコピーを返します。実際にどのように動作するかを確認するために、別の例として`Series`を作成してみましょう。\n" ] }, { @@ -1590,9 +1590,9 @@ }, "source": [ "### カテゴリカルデータ(非数値)\n", - "まずは非数値データについて考えてみましょう。データセットには、カテゴリカルデータを含む列があります。例えば、性別や「True」または「False」などです。\n", + "まずは非数値データについて考えてみましょう。データセットには、カテゴリカルデータを含む列があります。例えば、性別やTrue/Falseなどです。\n", "\n", - "これらのケースのほとんどでは、欠損値をその列の`最頻値(mode)`で置き換えます。例えば、100件のデータポイントがあり、90件が「True」、8件が「False」、2件が未記入だったとします。この場合、列全体を考慮して、未記入の2件を「True」で埋めることができます。\n", + "これらの場合の多くでは、欠損値をその列の`最頻値(mode)`で置き換えます。例えば、100件のデータポイントがあり、90件がTrue、8件がFalse、2件が未記入だったとします。この場合、列全体を考慮して、未記入の2件をTrueで埋めることができます。\n", "\n", "さらに、ここではドメイン知識を活用することもできます。最頻値で埋める例を考えてみましょう。\n" ] @@ -1699,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "まず、`None`の値をモードで埋める前に、モードを見つけましょう。\n" + ] }, { "cell_type": "code", @@ -1734,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "それでは、NoneをTrueに置き換えます。\n" + ] }, { "cell_type": "code", @@ -1844,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "null値が置き換えられたことがわかります。言うまでもなく、`'True'`の代わりに何でも書くことができ、それが置き換えられたでしょう。\n" + "ご覧の通り、null値は置き換えられました。言うまでもなく、`'True'`の代わりに何でも書くことができ、それが置き換えられたでしょう。\n" ] }, { @@ -1859,11 +1863,11 @@ "1. 行の中央値で置き換える \n", "2. 行の平均値で置き換える \n", "\n", - "データが外れ値を含む偏った分布の場合は、中央値で置き換えます。これは、中央値が外れ値に対して頑健だからです。\n", + "外れ値を含む偏ったデータの場合は、中央値で置き換えます。これは、中央値が外れ値に対して頑健だからです。\n", "\n", "データが正規化されている場合は平均値を使用できます。この場合、平均値と中央値はほぼ同じになるからです。\n", "\n", - "まず、正規分布している列を取り、その列の平均値で欠損値を埋めてみましょう。\n" + "まず、正規分布している列を取り上げ、その列の平均値で欠損値を埋めてみましょう。\n" ] }, { @@ -2003,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "平均値で埋める\n" + ] }, { "cell_type": "code", @@ -2252,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "中央値で埋める\n" + ] }, { "cell_type": "code", @@ -2352,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "NaN値が列の中央値に置き換えられたことがわかります\n" + "NaN値が列の中央値に置き換えられたことがわかります。\n" ] }, { @@ -2435,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> 重要なポイント:\n", - "1. 欠損値を埋める作業は、データが少ない場合や欠損値を埋めるための戦略がある場合に行うべきです。\n", - "2. ドメイン知識を活用して、欠損値を近似的に埋めることができます。\n", - "3. カテゴリデータの場合、多くの場合、欠損値はその列の最頻値(モード)で置き換えられます。\n", - "4. 数値データの場合、欠損値は通常、平均値(正規化されたデータセットの場合)または列の中央値で埋められます。\n" + "> 主なポイント:\n", + "1. 欠損値の補完は、データが少ない場合や欠損値を補完するための戦略がある場合に行うべきです。\n", + "2. ドメイン知識を活用して、欠損値を推定して補完することができます。\n", + "3. カテゴリカルデータの場合、多くの場合、欠損値はその列の最頻値で置き換えられます。\n", + "4. 数値データの場合、欠損値は通常、平均値(正規化されたデータセットの場合)または列の中央値で補完されます。\n" ] }, { @@ -2470,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "ヌル値を**前方埋め**することができます。これは、最後の有効な値を使用してヌルを埋める方法です。\n" + "null値を**前方埋め**することができます。これは、最後の有効な値を使用してnullを埋めることです。\n" ] }, { @@ -2553,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "データフレームでも同じように機能しますが、null値を埋める軸を指定することもできます:\n" + "データフレームでも同様に機能しますが、null値を埋める軸を指定することもできます。\n" ] }, { @@ -2726,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "前の値が前方埋めに利用できない場合、null値がそのまま残ることに注意してください。\n" + "前の値が前方埋めに利用できない場合、欠損値はそのまま残ることに注意してください。\n" ] }, { @@ -2759,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "`fillna` の使い方については創造的であることができます。例えば、再び `example4` を見てみましょう。ただし、今回は欠損値を `DataFrame` 内のすべての値の平均で埋めてみます。\n" + "あなたは `fillna` の使い方について創造的になることができます。例えば、もう一度 `example4` を見てみましょう。ただし、今回は欠損値を `DataFrame` 内のすべての値の平均値で埋めてみます。\n" ] }, { @@ -2850,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "3列目がまだ値を持っていないことに注意してください: デフォルトの方向は行ごとに値を埋めることです。\n", + "列3がまだ値がないことに注意してください。デフォルトの方向は行ごとに値を埋めることです。\n", "\n", - "> **ポイント:** データセット内の欠損値を処理する方法は複数あります。使用する具体的な戦略(削除、置換、またはどのように置換するか)は、そのデータの特性によって決定されるべきです。データセットを扱い、操作する経験を積むことで、欠損値への対処方法についてより良い感覚を身につけることができます。\n" + "> **ポイント:** データセット内の欠損値を処理する方法は複数あります。使用する具体的な戦略(削除、置換、またはどのように置換するか)は、そのデータの特性によって決まるべきです。データセットを扱い、操作する経験を積むことで、欠損値の処理方法についてより良い感覚を身につけることができます。\n" ] }, { @@ -2863,7 +2871,7 @@ "source": [ "### カテゴリカルデータのエンコード\n", "\n", - "機械学習モデルは数値データのみを扱うことができます。「Yes」と「No」の違いを理解することはできませんが、「0」と「1」の違いは区別できます。そのため、欠損値を埋めた後、モデルが理解できるようにカテゴリカルデータを数値形式にエンコードする必要があります。\n", + "機械学習モデルは数値データのみを扱います。モデルは「Yes」と「No」の違いを理解することはできませんが、「0」と「1」の違いは区別できます。そのため、欠損値を埋めた後、モデルが理解できるようにカテゴリカルデータを数値形式にエンコードする必要があります。\n", "\n", "エンコードには2つの方法があります。次にそれらについて説明します。\n" ] @@ -2876,7 +2884,7 @@ "source": [ "**ラベルエンコーディング**\n", "\n", - "ラベルエンコーディングとは、各カテゴリを数値に変換することを指します。例えば、航空会社の乗客に関するデータセットがあり、次のようなクラスを含む列があるとします:['business class', 'economy class', 'first class']。この列にラベルエンコーディングを適用すると、[0, 1, 2] に変換されます。コードを使って例を見てみましょう。今後のノートブックで `scikit-learn` を学ぶ予定なので、ここでは使用しません。\n" + "ラベルエンコーディングとは、各カテゴリを数字に変換することを指します。例えば、航空会社の乗客に関するデータセットがあり、列に以下のクラスが含まれているとします:['business class', 'economy class', 'first class']。これにラベルエンコーディングを適用すると、[0,1,2]に変換されます。コードを使った例を見てみましょう。今後のノートブックで`scikit-learn`を学ぶ予定なので、ここでは使用しません。\n" ] }, { @@ -2984,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "1列目にラベルエンコーディングを行うには、各クラスを数値に対応付けるマッピングをまず記述し、その後置き換える必要があります。\n" + "1列目でラベルエンコーディングを行うには、各クラスを数値に対応付けるマッピングをまず記述し、その後置き換える必要があります。\n" ] }, { @@ -3086,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "予想通りの結果が得られました。では、ラベルエンコーディングはいつ使用するのでしょうか?ラベルエンコーディングは、以下のいずれか、または両方の場合に使用されます:\n", - "1. カテゴリの数が多い場合\n", - "2. カテゴリに順序がある場合\n" + "ご覧の通り、出力は予想通りの結果となっています。では、ラベルエンコーディングはいつ使用するのでしょうか?ラベルエンコーディングは以下のいずれか、または両方の場合に使用されます:\n", + "1. カテゴリーの数が多い場合\n", + "2. カテゴリーに順序がある場合\n" ] }, { @@ -3099,9 +3107,9 @@ "source": [ "**ワンホットエンコーディング**\n", "\n", - "もう一つのエンコーディングの種類として、ワンホットエンコーディングがあります。このエンコーディングでは、列の各カテゴリが個別の列として追加され、各データポイントはそのカテゴリを含むかどうかに基づいて0または1を取得します。したがって、異なるカテゴリがn個ある場合、データフレームにn個の列が追加されます。\n", + "ワンホットエンコーディングは、別の種類のエンコーディング方法です。この方法では、列の各カテゴリが個別の列として追加され、各データポイントはそのカテゴリを含むかどうかに基づいて0または1を取得します。つまり、異なるカテゴリがn個ある場合、データフレームにn個の列が追加されます。\n", "\n", - "例えば、同じ飛行機のクラスの例を考えてみましょう。カテゴリは次の通りでした: ['business class', 'economy class', 'first class']。この場合、ワンホットエンコーディングを実行すると、次の3つの列がデータセットに追加されます: ['class_business class', 'class_economy class', 'class_first class']。\n" + "例えば、同じ飛行機のクラスの例を考えてみましょう。カテゴリは次の通りでした: ['business class', 'economy class', 'first class']。ワンホットエンコーディングを実行すると、次の3つの列がデータセットに追加されます: ['class_business class', 'class_economy class', 'class_first class']。\n" ] }, { @@ -3209,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "1列目に対してワンホットエンコーディングを行いましょう\n" + "1列目に対してワンホットエンコーディングを実行しましょう。\n" ] }, { @@ -3343,9 +3351,9 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "ワンホットエンコーディングはいつ使用するのか?ワンホットエンコーディングは、以下のいずれかまたは両方の場合に使用されます:\n", + "ワンホットエンコーディングは、以下のいずれかまたは両方の場合に使用されます:\n", "\n", - "1. カテゴリーの数やデータセットのサイズが小さい場合。\n", + "1. カテゴリーの数とデータセットのサイズが小さい場合。\n", "2. カテゴリーに特定の順序がない場合。\n" ] }, @@ -3357,7 +3365,7 @@ "source": [ "> 主なポイント:\n", "1. エンコーディングは、非数値データを数値データに変換するために行われます。\n", - "2. エンコーディングにはラベルエンコーディングとワンホットエンコーディングの2種類があり、データセットの要求に応じて実行できます。\n" + "2. エンコーディングにはラベルエンコーディングとワンホットエンコーディングの2種類があり、データセットの要件に応じて実行できます。\n" ] }, { @@ -3370,7 +3378,7 @@ "\n", "> **学習目標:** このセクションの終わりまでに、DataFrameから重複した値を特定し削除する方法に慣れることができます。\n", "\n", - "欠損データに加えて、実際のデータセットでは重複したデータに遭遇することがよくあります。幸いなことに、pandasは重複したエントリを検出し削除する簡単な方法を提供しています。\n" + "欠損データに加えて、現実世界のデータセットでは重複したデータに遭遇することがよくあります。幸いなことに、pandasは重複したエントリを検出し削除する簡単な方法を提供しています。\n" ] }, { @@ -3381,7 +3389,7 @@ "source": [ "### 重複を特定する: `duplicated`\n", "\n", - "pandasの`duplicated`メソッドを使えば、重複した値を簡単に見つけることができます。このメソッドは、`DataFrame`内のエントリが以前のものと重複しているかどうかを示すブールマスクを返します。これを実際に確認するために、別の例として`DataFrame`を作成してみましょう。\n" + "pandasの`duplicated`メソッドを使えば、重複した値を簡単に見つけることができます。このメソッドは、`DataFrame`内のエントリが以前のものと重複しているかどうかを示すブールマスクを返します。これを実際に試すために、別の例の`DataFrame`を作成してみましょう。\n" ] }, { @@ -3670,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **重要なポイント:** 重複データを削除することは、ほぼすべてのデータサイエンスプロジェクトにおいて重要な部分です。重複データは分析結果を変え、不正確な結果をもたらす可能性があります!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 実世界のデータ品質チェック\n", + "\n", + "> **学習目標:** このセクションを終える頃には、実世界のデータ品質問題を検出し修正する方法に慣れ、例えば不一致のあるカテゴリ値、異常な数値(外れ値)、そしてバリエーションのある重複エンティティなどに対応できるようになります。\n", + "\n", + "欠損値や完全な重複は一般的な問題ですが、実世界のデータセットにはより微妙な問題が含まれることがよくあります。\n", + "\n", + "1. **不一致のあるカテゴリ値**: 同じカテゴリが異なる綴りで表記されている場合(例: \"USA\", \"U.S.A\", \"United States\")\n", + "2. **異常な数値**: データ入力ミスを示す極端な外れ値(例: 年齢 = 999)\n", + "3. **ほぼ重複した行**: わずかな違いで同じエンティティを表すレコード\n", + "\n", + "これらの問題を検出し対処するための手法を見ていきましょう。\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### サンプルの「汚れた」データセットを作成する\n", + "\n", + "まず、現実世界のデータでよく遭遇する問題を含むサンプルデータセットを作成しましょう。\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. 一貫性のないカテゴリ値の検出\n", + "\n", + "`country`列には、同じ国に対して複数の表記が存在しています。この不一致を特定してみましょう。\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### カテゴリ値の標準化\n", + "\n", + "これらの値を標準化するためにマッピングを作成することができます。簡単な方法として、小文字に変換してマッピング辞書を作成する方法があります:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**代替案: ファジーマッチングの使用**\n", + "\n", + "より複雑なケースでは、`rapidfuzz`ライブラリを使用してファジー文字列マッチングを行い、類似した文字列を自動的に検出することができます:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. 異常な数値(外れ値)の検出\n", + "\n", + "`age`列を見てみると、199や-5のような怪しい値があります。統計的手法を使ってこれらの外れ値を検出してみましょう。\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### IQR(四分位範囲)法の使用\n", + "\n", + "IQR法は、極端な値に対して感度が低い、外れ値検出のための堅牢な統計手法です:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Zスコア法の使用\n", + "\n", + "Zスコア法は、平均からの標準偏差に基づいて外れ値を特定します:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 外れ値の処理\n", + "\n", + "外れ値を検出した後は、以下の方法で処理することができます:\n", + "1. **削除**: 外れ値を含む行を削除する(それが誤りの場合)\n", + "2. **上限設定**: 境界値で置き換える\n", + "3. **NaNに置き換える**: 欠損値として扱い、補完技術を使用する\n", + "4. **保持**: 正当な極端値である場合はそのまま保持する\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. 近似重複行の検出\n", + "\n", + "データセットには「John Smith」に関する複数のエントリがあり、値が少し異なっていることに気づきました。名前の類似性に基づいて潜在的な重複を特定してみましょう。\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### ファジーマッチングによる類似データの検出\n", + "\n", + "より高度な重複検出を行うために、ファジーマッチングを使用して似た名前を見つけることができます:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 重複の処理\n", + "\n", + "重複を特定したら、どのように処理するかを決める必要があります:\n", + "1. **最初の出現を保持**: `drop_duplicates(keep='first')` を使用\n", + "2. **最後の出現を保持**: `drop_duplicates(keep='last')` を使用\n", + "3. **情報を集約**: 重複した行の情報を統合\n", + "4. **手動で確認**: 人によるレビューのためにフラグを立てる\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 要約: 完全なデータクリーニングパイプライン\n", + "\n", + "すべてをまとめて、包括的なクリーニングパイプラインを作成しましょう:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 チャレンジ演習\n", + "\n", + "さあ、あなたの番です!以下に品質上の問題が複数ある新しいデータ行があります。次のことができますか?\n", + "\n", + "1. この行のすべての問題を特定する\n", + "2. 各問題を修正するコードを書く\n", + "3. 修正した行をデータセットに追加する\n", + "\n", + "こちらが問題のあるデータです:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 重要なポイント\n", + "\n", + "1. **カテゴリの不一致**は現実世界のデータでよく見られます。ユニークな値を確認し、マッピングやあいまい一致を使って標準化することが重要です。\n", + "\n", + "2. **外れ値**は分析に大きな影響を与える可能性があります。統計的手法(IQRやZスコア)とドメイン知識を組み合わせて検出しましょう。\n", + "\n", + "3. **類似重複**は完全な重複よりも検出が難しいです。あいまい一致を使用したり、データを正規化(小文字化や空白の削除)して特定することを検討してください。\n", + "\n", + "4. **データクリーニングは反復的なプロセス**です。複数の手法を適用し、結果を確認しながら最終的なクリーンデータセットを作成する必要があります。\n", + "\n", + "5. **決定を記録する**ことが重要です。どのクリーニング手順を適用したか、そしてその理由を記録しておくことで、再現性と透明性を確保できます。\n", + "\n", + "> **ベストプラクティス:** 元の「汚れた」データのコピーを必ず保存してください。元のデータファイルを上書きせず、`data_cleaned.csv`のような明確な命名規則でクリーンバージョンを作成しましょう。\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**免責事項**: \nこの文書は、AI翻訳サービス [Co-op Translator](https://github.com/Azure/co-op-translator) を使用して翻訳されています。正確性を追求しておりますが、自動翻訳には誤りや不正確な部分が含まれる可能性があることをご承知ください。元の言語で記載された文書が正式な情報源とみなされるべきです。重要な情報については、専門の人間による翻訳を推奨します。この翻訳の使用に起因する誤解や誤った解釈について、当方は責任を負いません。\n" + "\n---\n\n**免責事項**: \nこの文書は、AI翻訳サービス[Co-op Translator](https://github.com/Azure/co-op-translator)を使用して翻訳されています。正確性を追求しておりますが、自動翻訳には誤りや不正確な部分が含まれる可能性があります。元の言語で記載された文書を正式な情報源としてお考えください。重要な情報については、専門の人間による翻訳を推奨します。この翻訳の使用に起因する誤解や誤解釈について、当社は一切の責任を負いません。\n" ] } ], @@ -3704,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T22:05:33+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:28:58+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "ja" } diff --git a/translations/ko/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/ko/2-Working-With-Data/08-data-preparation/notebook.ipynb index 045660d4..43a32a11 100644 --- a/translations/ko/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/ko/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -12,11 +12,11 @@ "\n", "## `DataFrame` 정보 탐색\n", "\n", - "> **학습 목표:** 이 절의 끝까지 학습하면 pandas DataFrame에 저장된 데이터에 대한 일반적인 정보를 찾는 데 익숙해질 것입니다.\n", + "> **학습 목표:** 이 절의 끝까지 학습하면 pandas의 DataFrame에 저장된 데이터에 대한 일반적인 정보를 찾는 데 익숙해질 것입니다.\n", "\n", - "데이터를 pandas에 로드하면 대부분의 경우 `DataFrame` 형태로 저장됩니다. 하지만 `DataFrame`에 있는 데이터 세트가 60,000개의 행과 400개의 열로 구성되어 있다면, 어디서부터 작업을 시작해야 할지 막막할 수 있습니다. 다행히도 pandas는 `DataFrame`의 전체적인 정보를 빠르게 확인할 수 있는 편리한 도구를 제공하며, 첫 몇 행과 마지막 몇 행도 쉽게 볼 수 있습니다.\n", + "데이터를 pandas에 로드하면 대부분의 경우 `DataFrame` 형태로 저장됩니다. 하지만 `DataFrame`에 있는 데이터셋이 60,000개의 행과 400개의 열로 구성되어 있다면, 어디서부터 작업을 시작해야 할지 막막할 수 있습니다. 다행히도 pandas는 `DataFrame`의 전체적인 정보를 빠르게 확인할 수 있는 몇 가지 편리한 도구를 제공합니다. 이 도구들은 데이터의 처음 몇 행과 마지막 몇 행을 확인하는 기능도 포함하고 있습니다.\n", "\n", - "이 기능을 탐색하기 위해 Python의 scikit-learn 라이브러리를 가져오고, 모든 데이터 과학자가 수백 번은 봤을 유명한 데이터 세트를 사용할 것입니다. 이는 영국 생물학자 로널드 피셔가 1936년 논문 \"분류 문제에서 다중 측정값의 사용\"에서 사용한 *Iris* 데이터 세트입니다.\n" + "이 기능을 탐색하기 위해 Python의 scikit-learn 라이브러리를 가져오고, 모든 데이터 과학자가 수백 번은 봤을 법한 상징적인 데이터셋을 사용할 것입니다. 이 데이터셋은 영국 생물학자 로널드 피셔(Ronald Fisher)가 1936년 논문 \"The use of multiple measurements in taxonomic problems\"에서 사용한 *Iris* 데이터셋입니다:\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "우리는 Iris 데이터셋을 변수 `iris_df`에 로드했습니다. 데이터를 분석하기 전에, 우리가 가진 데이터 포인트의 수와 데이터셋의 전체 크기를 아는 것이 중요합니다. 우리가 다루고 있는 데이터의 규모를 확인하는 것은 유용합니다.\n" + "우리는 Iris 데이터셋을 변수 `iris_df`에 로드했습니다. 데이터를 분석하기 전에, 우리가 가진 데이터 포인트의 수와 데이터셋의 전체 크기를 아는 것이 유용할 것입니다. 우리가 다루고 있는 데이터의 양을 확인하는 것은 중요합니다.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "우리는 150개의 행과 4개의 열로 구성된 데이터를 다루고 있습니다. 각 행은 하나의 데이터 포인트를 나타내며, 각 열은 데이터 프레임과 연관된 하나의 특징을 나타냅니다. 즉, 총 150개의 데이터 포인트가 있으며, 각각 4개의 특징을 포함하고 있습니다.\n", + "우리는 150개의 행과 4개의 열로 구성된 데이터를 다루고 있습니다. 각 행은 하나의 데이터 포인트를 나타내며, 각 열은 데이터 프레임과 관련된 하나의 특징을 나타냅니다. 즉, 기본적으로 150개의 데이터 포인트가 각각 4개의 특징을 포함하고 있는 것입니다.\n", "\n", - "여기서 `shape`는 데이터 프레임의 속성(attribute)이지 함수가 아니기 때문에 괄호로 끝나지 않습니다.\n" + "`shape`는 여기서 데이터 프레임의 속성이며 함수가 아니기 때문에 괄호로 끝나지 않습니다.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "이제 데이터의 4개 열로 넘어가 보겠습니다. 각각의 열은 정확히 무엇을 나타낼까요? `columns` 속성은 데이터프레임에서 열의 이름을 알려줍니다.\n" + "이제 데이터의 4개 열로 넘어가 보겠습니다. 각각의 열은 정확히 무엇을 나타낼까요? `columns` 속성은 데이터프레임의 열 이름을 알려줍니다.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "우리가 볼 수 있듯이, 네(4) 개의 열이 있습니다. `columns` 속성은 열의 이름을 알려주며 기본적으로 다른 정보는 제공하지 않습니다. 이 속성은 데이터셋이 포함하는 특징을 식별하고자 할 때 중요성을 갖습니다.\n" + "우리가 볼 수 있듯이, 네(4) 개의 열이 있습니다. `columns` 속성은 열의 이름을 알려주며 기본적으로 그 외에는 아무것도 알려주지 않습니다. 이 속성은 데이터셋이 포함하는 특징을 식별하고자 할 때 중요성을 갖습니다.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "`shape` 속성이 제공하는 데이터 양과 `columns` 속성이 제공하는 특징 또는 열 이름은 데이터셋에 대해 일부 정보를 알려줍니다. 이제 데이터셋을 더 깊이 탐구하고 싶을 것입니다. `DataFrame.info()` 함수는 이를 위해 매우 유용합니다.\n" + "`shape` 속성이 제공하는 데이터 양과 `columns` 속성이 제공하는 특징 또는 열 이름은 데이터셋에 대해 일부 정보를 알려줍니다. 이제 데이터셋을 더 깊이 탐구하고 싶을 것입니다. `DataFrame.info()` 함수는 이에 매우 유용합니다.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "여기에서 몇 가지 관찰을 할 수 있습니다:\n", + "여기서 몇 가지 관찰을 할 수 있습니다:\n", "1. 각 열의 데이터 유형: 이 데이터셋에서는 모든 데이터가 64비트 부동소수점 숫자로 저장되어 있습니다.\n", - "2. 비-Null 값의 개수: Null 값을 처리하는 것은 데이터 준비 과정에서 중요한 단계입니다. 이는 노트북에서 나중에 다룰 예정입니다.\n" + "2. Non-Null 값의 개수: null 값을 처리하는 것은 데이터 준비에서 중요한 단계입니다. 이는 나중에 노트북에서 처리될 예정입니다.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "데이터셋에 수많은 숫자 데이터가 있다고 가정해봅시다. 평균, 중앙값, 사분위수 등과 같은 단변량 통계 계산은 각 열별로 개별적으로 수행할 수 있습니다. `DataFrame.describe()` 함수는 데이터셋의 숫자 열에 대한 통계 요약을 제공합니다.\n" + "데이터셋에 많은 수치 데이터가 있다고 가정해봅시다. 평균, 중앙값, 사분위수 등과 같은 단변량 통계 계산은 각 열별로 개별적으로 수행할 수 있습니다. `DataFrame.describe()` 함수는 데이터셋의 수치 열에 대한 통계 요약을 제공합니다.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "위의 출력은 각 열의 총 데이터 포인트 수, 평균, 표준 편차, 최소값, 하위 사분위수(25%), 중앙값(50%), 상위 사분위수(75%) 및 최대값을 보여줍니다.\n" + "위의 출력은 각 열의 데이터 포인트 총 수, 평균, 표준 편차, 최소값, 하위 사분위수(25%), 중앙값(50%), 상위 사분위수(75%) 및 최대값을 보여줍니다.\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "위의 모든 함수와 속성을 통해 데이터셋에 대한 전반적인 개요를 파악했습니다. 데이터 포인트가 몇 개인지, 특징이 몇 개인지, 각 특징의 데이터 타입은 무엇인지, 그리고 각 특징에 비어 있지 않은 값이 몇 개인지 알게 되었습니다.\n", + "위의 모든 함수와 속성을 통해 데이터셋에 대한 전반적인 개요를 얻었습니다. 데이터 포인트가 몇 개인지, 특징이 몇 개인지, 각 특징의 데이터 타입과 각 특징의 non-null 값 개수를 알게 되었습니다.\n", "\n", - "이제 실제 데이터를 살펴볼 차례입니다. `DataFrame`의 첫 몇 행(첫 몇 개의 데이터 포인트)이 어떻게 생겼는지 확인해봅시다:\n" + "이제 실제 데이터를 살펴볼 시간입니다. `DataFrame`의 첫 몇 행(첫 몇 데이터 포인트)이 어떻게 생겼는지 확인해봅시다:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "여기 출력에서 데이터셋의 다섯(5) 개 항목을 볼 수 있습니다. 왼쪽의 인덱스를 보면 이것이 첫 다섯 행임을 알 수 있습니다.\n" + "여기 출력에서 우리는 데이터셋의 다섯(5) 개 항목을 볼 수 있습니다. 왼쪽의 인덱스를 보면, 이것들이 첫 다섯 행이라는 것을 알 수 있습니다.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### 연습 문제:\n", "\n", - "위 예제에서 알 수 있듯이, 기본적으로 `DataFrame.head`는 `DataFrame`의 처음 다섯 행을 반환합니다. 아래 코드 셀에서 다섯 행보다 더 많은 행을 표시하는 방법을 찾아볼 수 있겠습니까?\n" + "위의 예제에서 기본적으로 `DataFrame.head`는 `DataFrame`의 처음 다섯 행을 반환한다는 것이 분명합니다. 아래 코드 셀에서 다섯 행보다 더 많은 행을 표시하는 방법을 찾아낼 수 있나요?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "데이터를 보는 또 다른 방법은 시작이 아닌 끝에서부터 보는 것입니다. `DataFrame.head`의 반대는 `DataFrame.tail`로, `DataFrame`의 마지막 다섯 행을 반환합니다:\n" + "데이터를 보는 또 다른 방법은 시작이 아닌 끝에서부터 보는 것입니다. `DataFrame.head`의 반대는 `DataFrame.tail`로, 이는 `DataFrame`의 마지막 다섯 행을 반환합니다:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "데이터셋에서 이상값을 찾을 때, 특히 정렬된 데이터셋을 다룰 때 `DataFrame`의 처음 몇 행이나 마지막 몇 행을 쉽게 확인할 수 있는 기능은 매우 유용합니다.\n", + "실제로, `DataFrame`의 처음 몇 행이나 마지막 몇 행을 쉽게 확인할 수 있는 기능은 특히 정렬된 데이터셋에서 이상값을 찾을 때 유용합니다.\n", "\n", - "위에서 코드 예제를 통해 보여준 모든 함수와 속성은 데이터를 살펴보고 이해하는 데 도움을 줍니다.\n", + "위에서 코드 예제를 통해 보여준 모든 함수와 속성은 데이터를 이해하고 파악하는 데 도움을 줍니다.\n", "\n", - "> **핵심 요점:** `DataFrame`의 정보에 대한 메타데이터나 처음과 마지막 몇 개의 값을 확인하는 것만으로도, 다루고 있는 데이터의 크기, 형태, 그리고 내용을 즉각적으로 파악할 수 있습니다.\n" + "> **핵심 요점:** `DataFrame`의 정보에 대한 메타데이터나 처음과 마지막 몇 개의 값을 보는 것만으로도, 다루고 있는 데이터의 크기, 형태, 그리고 내용을 즉각적으로 파악할 수 있습니다.\n" ] }, { @@ -596,17 +596,17 @@ }, "source": [ "### 누락된 데이터\n", - "누락된 데이터에 대해 알아봅시다. 누락된 데이터는 일부 열에 값이 저장되지 않았을 때 발생합니다.\n", + "누락된 데이터에 대해 알아봅시다. 누락된 데이터는 일부 열에 값이 저장되지 않은 경우 발생합니다.\n", "\n", - "예를 들어, 누군가 자신의 체중에 대해 민감하여 설문조사에서 체중 항목을 작성하지 않는다고 가정해봅시다. 그러면 해당 사람의 체중 값은 누락되게 됩니다.\n", + "예를 들어, 어떤 사람이 자신의 체중에 대해 민감하여 설문조사에서 체중 항목을 작성하지 않는다고 가정해봅시다. 그러면 해당 사람의 체중 값은 누락되게 됩니다.\n", "\n", "대부분의 경우, 실제 데이터셋에서는 누락된 값이 발생합니다.\n", "\n", "**Pandas가 누락된 데이터를 처리하는 방법**\n", "\n", - "Pandas는 누락된 값을 두 가지 방식으로 처리합니다. 첫 번째는 이전 섹션에서 본 적이 있는 `NaN`(Not a Number)입니다. 이는 실제로 IEEE 부동소수점 사양의 일부로, 누락된 부동소수점 값을 나타내기 위해 사용되는 특별한 값입니다.\n", + "Pandas는 누락된 값을 두 가지 방식으로 처리합니다. 첫 번째는 이전 섹션에서 본 적이 있는 `NaN`(Not a Number)입니다. 이는 실제로 IEEE 부동소수점 사양의 일부로, 누락된 부동소수점 값을 나타내는 데만 사용되는 특별한 값입니다.\n", "\n", - "부동소수점 외의 누락된 값에 대해서는 pandas가 Python의 `None` 객체를 사용합니다. 두 가지 다른 종류의 값이 본질적으로 동일한 의미를 전달하는 것처럼 보일 수 있지만, 이러한 설계 선택에는 합리적인 프로그래밍 이유가 있습니다. 실제로 이러한 접근 방식은 대부분의 경우에 대해 pandas가 적절한 절충안을 제공할 수 있도록 합니다. 그럼에도 불구하고, `None`과 `NaN` 모두 사용 방법과 관련하여 주의해야 할 제한 사항이 있습니다.\n" + "부동소수점 외의 누락된 값에 대해서는 pandas가 Python의 `None` 객체를 사용합니다. 두 가지 다른 종류의 값이 본질적으로 동일한 의미를 전달하는 것처럼 보일 수 있지만, 이러한 설계 선택에는 타당한 프로그래밍적 이유가 있으며, 실제로 이러한 접근 방식은 대부분의 경우에 대해 pandas가 적절한 절충안을 제공할 수 있도록 합니다. 그럼에도 불구하고, `None`과 `NaN` 모두 사용 방법과 관련하여 주의해야 할 제한 사항이 있다는 점을 기억해야 합니다.\n" ] }, { @@ -615,8 +615,8 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: 비-부동 소수점 누락 데이터\n", - "`None`은 Python에서 비롯되었기 때문에 데이터 유형이 `'object'`가 아닌 NumPy와 pandas 배열에서는 사용할 수 없습니다. NumPy 배열(그리고 pandas의 데이터 구조)은 오직 한 가지 유형의 데이터만 포함할 수 있다는 점을 기억하세요. 이것이 대규모 데이터와 계산 작업에서 엄청난 성능을 제공하는 이유이지만, 동시에 유연성을 제한하는 요인이기도 합니다. 이러한 배열은 \"최소 공통 분모\"로 업캐스트해야 하며, 배열 내 모든 것을 포함할 수 있는 데이터 유형으로 변환됩니다. 배열에 `None`이 포함되어 있다면, 이는 Python 객체를 다루고 있다는 것을 의미합니다.\n", + "### `None`: 비-부동소수점 결측 데이터\n", + "`None`은 Python에서 비롯되었기 때문에 데이터 유형이 `'object'`가 아닌 NumPy 및 pandas 배열에서는 사용할 수 없습니다. NumPy 배열(및 pandas의 데이터 구조)은 한 가지 유형의 데이터만 포함할 수 있습니다. 이는 대규모 데이터 및 계산 작업에서 엄청난 성능을 제공하지만, 동시에 유연성을 제한하기도 합니다. 이러한 배열은 \"최소 공통 분모\"로 업캐스트해야 하며, 이는 배열 내 모든 것을 포함할 수 있는 데이터 유형을 의미합니다. 배열에 `None`이 포함되어 있다면, 이는 Python 객체를 사용하고 있다는 뜻입니다.\n", "\n", "이를 실제로 확인하려면 다음 예제 배열을 살펴보세요 (`dtype`를 주목하세요):\n" ] @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "업캐스트 데이터 타입의 현실은 두 가지 부작용을 동반합니다. 첫째, 연산이 컴파일된 NumPy 코드가 아닌, 해석된 Python 코드 수준에서 수행됩니다. 기본적으로 이는 `Series`나 `DataFrame`에 `None`이 포함된 경우, 해당 연산이 더 느려진다는 것을 의미합니다. 이러한 성능 저하를 눈치채지 못할 수도 있지만, 대규모 데이터셋에서는 문제가 될 수 있습니다.\n", + "업캐스트 데이터 타입의 현실은 두 가지 부작용을 동반합니다. 첫째, 연산이 컴파일된 NumPy 코드가 아닌 해석된 Python 코드 수준에서 수행됩니다. 기본적으로 이는 `None`이 포함된 `Series`나 `DataFrame`과 관련된 모든 연산이 더 느려진다는 것을 의미합니다. 이러한 성능 저하를 눈치채지 못할 수도 있지만, 대규모 데이터셋에서는 문제가 될 수 있습니다.\n", "\n", - "두 번째 부작용은 첫 번째에서 비롯됩니다. `None`이 본질적으로 `Series`나 `DataFrame`을 일반 Python의 세계로 끌어들이기 때문에, `sum()`이나 `min()`과 같은 NumPy/pandas 집계 함수를 `None` 값을 포함한 배열에 사용하면 일반적으로 오류가 발생합니다:\n" + "두 번째 부작용은 첫 번째에서 비롯됩니다. `None`이 본질적으로 `Series`나 `DataFrame`을 일반 Python의 세계로 끌어들이기 때문에, `sum()`이나 `min()` 같은 NumPy/pandas 집계 함수를 `None` 값을 포함한 배열에 사용하면 일반적으로 오류가 발생합니다:\n" ] }, { @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**핵심 요점**: 정수와 `None` 값 간의 덧셈(및 기타 연산)은 정의되지 않으므로 이를 포함하는 데이터셋에서 수행할 수 있는 작업이 제한될 수 있습니다.\n" + ] }, { "cell_type": "markdown", @@ -705,9 +707,9 @@ "id": "pWvVHvETgRr9" }, "source": [ - "### `NaN`: 부재한 실수 값\n", + "### `NaN`: 누락된 부동소수점 값\n", "\n", - "`None`과는 달리, NumPy(그리고 pandas)는 빠르고 벡터화된 연산 및 ufunc을 위해 `NaN`을 지원합니다. 문제는 `NaN`에 대해 수행된 모든 산술 연산이 항상 `NaN`을 결과로 낸다는 점입니다. 예를 들어:\n" + "`None`과는 달리, NumPy(따라서 pandas도)는 빠르고 벡터화된 연산 및 ufunc을 위해 `NaN`을 지원합니다. 문제는 `NaN`에 대해 수행된 모든 산술 연산은 항상 `NaN`을 반환한다는 점입니다. 예를 들어:\n" ] }, { @@ -770,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "좋은 소식: `NaN`이 포함된 배열에서 실행되는 집계는 오류를 발생시키지 않습니다. 나쁜 소식: 결과가 일관되게 유용하지는 않습니다:\n" + "좋은 소식: `NaN`이 포함된 배열에서 실행되는 집계는 오류를 발생시키지 않습니다. 나쁜 소식: 결과가 일관되게 유용하지는 않습니다.\n" ] }, { @@ -829,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "`NaN`은 부동 소수점 값이 누락된 경우에만 사용됩니다. 정수, 문자열 또는 불리언에는 `NaN`에 해당하는 값이 없습니다.\n" + "기억하세요: `NaN`은 부동 소수점 값이 누락된 경우에만 사용됩니다. 정수, 문자열 또는 불리언에는 `NaN`에 해당하는 값이 없습니다.\n" ] }, { @@ -840,7 +842,7 @@ "source": [ "### `NaN`과 `None`: pandas에서의 null 값\n", "\n", - "`NaN`과 `None`이 약간 다르게 작동할 수는 있지만, pandas는 이 둘을 서로 교환하여 처리할 수 있도록 설계되었습니다. 이를 이해하기 위해 정수로 이루어진 `Series`를 살펴보세요:\n" + "`NaN`과 `None`이 약간 다르게 작동할 수는 있지만, pandas는 이 둘을 교환 가능하도록 처리하도록 설계되었습니다. 이를 이해하기 위해 정수로 구성된 `Series`를 살펴보세요:\n" ] }, { @@ -904,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "데이터 유형의 동질성을 유지하기 위해 `Series`와 `DataFrame`에서 데이터 유형을 업캐스팅하는 과정에서 pandas는 결측값을 `None`과 `NaN` 사이에서 자유롭게 전환합니다. 이러한 설계 특징 때문에 pandas에서 `None`과 `NaN`을 \"null\"의 두 가지 다른 형태로 생각하는 것이 유용할 수 있습니다. 실제로, pandas에서 결측값을 처리하기 위해 사용하는 핵심 메서드 중 일부는 이러한 아이디어를 이름에 반영하고 있습니다:\n", + "데이터의 동질성을 유지하기 위해 `Series`와 `DataFrame`에서 데이터 유형을 업캐스팅하는 과정에서 pandas는 결측값을 `None`과 `NaN` 사이에서 자유롭게 전환합니다. 이러한 설계 특징 때문에 pandas에서는 `None`과 `NaN`을 \"null\"의 두 가지 다른 형태로 생각하는 것이 유용할 수 있습니다. 실제로 pandas에서 결측값을 처리하기 위해 사용하는 핵심 메서드 중 일부는 이러한 아이디어를 이름에 반영하고 있습니다:\n", "\n", - "- `isnull()`: 결측값을 나타내는 Boolean 마스크를 생성\n", + "- `isnull()`: 결측값을 나타내는 Boolean 마스크를 생성합니다\n", "- `notnull()`: `isnull()`의 반대\n", - "- `dropna()`: 필터링된 데이터 버전을 반환\n", - "- `fillna()`: 결측값을 채우거나 대체한 데이터 복사본을 반환\n", + "- `dropna()`: 필터링된 데이터 버전을 반환합니다\n", + "- `fillna()`: 결측값을 채우거나 대체한 데이터 복사본을 반환합니다\n", "\n", - "이 메서드들은 익숙해지고 숙달해야 할 중요한 기능들입니다. 이제 각각을 좀 더 깊이 살펴보겠습니다.\n" + "이 메서드들은 익숙해지고 숙달해야 할 중요한 기능이므로, 각각을 조금 더 깊이 살펴보겠습니다.\n" ] }, { @@ -920,10 +922,10 @@ "id": "Yh5ifd9FgRsB" }, "source": [ - "### 결측값 감지하기\n", + "### null 값 감지하기\n", "\n", - "결측값의 중요성을 이해했으니, 이를 처리하기 전에 데이터셋에서 결측값을 감지해야 합니다. \n", - "`isnull()`과 `notnull()`은 결측 데이터를 감지하기 위한 주요 메서드입니다. 두 메서드 모두 데이터에 대해 Boolean 마스크를 반환합니다.\n" + "누락된 값의 중요성을 이해했으니, 이를 처리하기 전에 데이터셋에서 누락된 값을 감지해야 합니다. \n", + "`isnull()`과 `notnull()`은 null 데이터를 감지하기 위한 주요 메서드입니다. 두 메서드는 데이터에 대해 Boolean 마스크를 반환합니다.\n" ] }, { @@ -976,9 +978,9 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "출력 내용을 자세히 살펴보세요. 놀라운 점이 있나요? `0`은 산술적으로는 null이지만, 여전히 완벽한 정수이며 pandas는 이를 정수로 처리합니다. `''`는 조금 더 미묘합니다. Section 1에서 빈 문자열 값을 나타내기 위해 사용했지만, pandas 관점에서는 여전히 문자열 객체이며 null을 나타내는 것이 아닙니다.\n", + "출력 결과를 자세히 살펴보세요. 어떤 점이 놀랍게 느껴지나요? `0`은 산술적으로는 null이지만, 여전히 완벽한 정수이며 pandas는 이를 정수로 처리합니다. `''`는 조금 더 미묘합니다. Section 1에서 빈 문자열 값을 나타내기 위해 사용했지만, pandas 관점에서는 여전히 문자열 객체일 뿐 null을 나타내는 것은 아닙니다.\n", "\n", - "이제 방향을 바꿔서 이러한 메서드들을 실제로 사용하는 방식에 더 가깝게 사용해 보겠습니다. Boolean 마스크를 직접 ``Series`` 또는 ``DataFrame`` 인덱스로 사용할 수 있으며, 이는 누락된 값(또는 존재하는 값)을 분리하여 작업할 때 유용할 수 있습니다.\n", + "이제 방향을 바꿔서 실무에서 사용할 방식으로 이러한 메서드를 사용해 보겠습니다. Boolean 마스크를 직접 ``Series`` 또는 ``DataFrame`` 인덱스로 사용할 수 있으며, 이는 누락된 값(또는 존재하는 값)을 분리하여 작업할 때 유용할 수 있습니다.\n", "\n", "누락된 값의 총 개수를 알고 싶다면, `isnull()` 메서드로 생성된 마스크에 대해 단순히 합계를 구하면 됩니다.\n" ] @@ -1038,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**핵심 요점**: `isnull()` 및 `notnull()` 메서드는 DataFrame에서 사용할 때 유사한 결과를 생성합니다. 이 메서드들은 결과와 해당 결과의 인덱스를 보여주며, 데이터를 다룰 때 큰 도움이 됩니다.\n" + "**핵심 요점**: `isnull()` 및 `notnull()` 메서드는 DataFrame에서 사용할 때 유사한 결과를 생성합니다. 이 메서드들은 결과와 해당 결과의 인덱스를 보여주며, 데이터를 처리하는 데 큰 도움이 됩니다.\n" ] }, { @@ -1047,18 +1049,18 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### 결측 데이터 처리하기\n", + "### 누락된 데이터 처리하기\n", "\n", "> **학습 목표:** 이 절을 마치면 DataFrame에서 null 값을 대체하거나 제거하는 방법과 시기를 알게 됩니다.\n", "\n", - "머신 러닝 모델은 결측 데이터를 자체적으로 처리할 수 없습니다. 따라서 데이터를 모델에 전달하기 전에 이러한 결측 값을 처리해야 합니다.\n", + "머신러닝 모델은 스스로 누락된 데이터를 처리할 수 없습니다. 따라서 데이터를 모델에 전달하기 전에 이러한 누락된 값을 처리해야 합니다.\n", "\n", - "결측 데이터를 처리하는 방식은 미묘한 트레이드오프를 포함하며, 최종 분석 결과와 실제 결과에 영향을 미칠 수 있습니다.\n", + "누락된 데이터를 처리하는 방식은 미묘한 트레이드오프를 포함하며, 최종 분석 및 실제 결과에 영향을 미칠 수 있습니다.\n", "\n", - "결측 데이터를 처리하는 주요 방법은 두 가지입니다:\n", + "누락된 데이터를 처리하는 주요 방법은 다음 두 가지입니다:\n", "\n", - "1. 결측 값을 포함한 행을 삭제하기\n", - "2. 결측 값을 다른 값으로 대체하기\n", + "1. 누락된 값을 포함한 행을 삭제하기\n", + "2. 누락된 값을 다른 값으로 대체하기\n", "\n", "이 두 가지 방법과 각각의 장단점에 대해 자세히 논의해 보겠습니다.\n" ] @@ -1069,13 +1071,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### 결측값 제거하기\n", + "### null 값 제거하기\n", "\n", - "모델에 전달하는 데이터의 양은 성능에 직접적인 영향을 미칩니다. 결측값을 제거한다는 것은 데이터 포인트의 수를 줄이고, 따라서 데이터셋의 크기를 줄이는 것을 의미합니다. 데이터셋이 상당히 클 경우, 결측값이 있는 행을 제거하는 것이 권장됩니다.\n", + "모델에 전달하는 데이터의 양은 성능에 직접적인 영향을 미칩니다. null 값을 제거한다는 것은 데이터 포인트의 수를 줄이고, 따라서 데이터셋의 크기를 줄이는 것을 의미합니다. 따라서 데이터셋이 상당히 클 경우 null 값이 있는 행을 제거하는 것이 권장됩니다.\n", "\n", - "또 다른 경우로는 특정 행이나 열에 결측값이 너무 많을 때가 있습니다. 이 경우, 해당 행이나 열은 대부분의 데이터가 누락되어 있어 분석에 큰 가치를 더하지 못하기 때문에 제거될 수 있습니다.\n", + "또 다른 경우로는 특정 행이나 열에 많은 누락된 값이 있을 때입니다. 이 경우 대부분의 데이터가 누락되어 있어 분석에 큰 가치를 더하지 못하기 때문에 해당 행이나 열을 제거할 수 있습니다.\n", "\n", - "결측값을 식별하는 것을 넘어, pandas는 `Series`와 `DataFrame`에서 결측값을 제거할 수 있는 편리한 방법을 제공합니다. 이를 실제로 확인하기 위해 `example3`로 돌아가 봅시다. `DataFrame.dropna()` 함수는 결측값이 있는 행을 제거하는 데 도움을 줍니다.\n" + "누락된 값을 식별하는 것을 넘어, pandas는 `Series`와 `DataFrame`에서 null 값을 제거하는 편리한 방법을 제공합니다. 이를 실제로 확인하기 위해 `example3`로 돌아가 보겠습니다. `DataFrame.dropna()` 함수는 null 값이 있는 행을 제거하는 데 도움을 줍니다.\n" ] }, { @@ -1114,7 +1116,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "이것은 `example3[example3.notnull()]`의 출력과 같아 보입니다. 여기서 차이점은 마스크된 값만 인덱싱하는 대신, `dropna`가 `Series` `example3`에서 누락된 값을 제거했다는 점입니다.\n", + "`example3[example3.notnull()]`의 출력과 비슷하게 보여야 합니다. 여기서 차이점은 마스크된 값만 인덱싱하는 대신, `dropna`가 `Series` `example3`에서 누락된 값을 제거했다는 점입니다.\n", "\n", "DataFrame은 두 개의 차원을 가지므로 데이터를 제거하는 데 더 많은 옵션을 제공합니다.\n" ] @@ -1206,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(판다스가 `NaN` 값을 처리하기 위해 두 개의 열을 부동소수점(float)으로 업캐스트한 것을 눈치채셨나요?)\n", + "(팬더가 `NaN`을 처리하기 위해 두 개의 열을 부동소수점으로 업캐스트한 것을 눈치채셨나요?)\n", "\n", - "`DataFrame`에서 단일 값을 삭제할 수는 없으므로 전체 행이나 열을 삭제해야 합니다. 수행하려는 작업에 따라 둘 중 하나를 선택해야 하며, 판다스는 이를 위해 두 가지 옵션을 제공합니다. 데이터 과학에서는 일반적으로 열이 변수를 나타내고 행이 관측치를 나타내기 때문에, 데이터를 삭제할 때 행을 삭제하는 경우가 더 많습니다. `dropna()`의 기본 설정은 null 값을 포함하는 모든 행을 삭제하는 것입니다:\n" + "`DataFrame`에서 단일 값을 삭제할 수는 없으므로 전체 행이나 열을 삭제해야 합니다. 수행하려는 작업에 따라 둘 중 하나를 선택할 수 있으며, 팬더는 두 가지 옵션을 제공합니다. 데이터 과학에서는 일반적으로 열이 변수(variable)를 나타내고 행이 관측값(observation)을 나타내기 때문에 데이터를 삭제할 때 행을 삭제하는 경우가 더 많습니다. `dropna()`의 기본 설정은 null 값을 포함하는 모든 행을 삭제하는 것입니다:\n" ] }, { @@ -1281,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "필요한 경우 열에서 NA 값을 제거할 수 있습니다. 이를 위해 `axis=1`을 사용하세요:\n" + "필요한 경우 열에서 NA 값을 제거할 수 있습니다. 이를 위해 `axis=1`을 사용하십시오:\n" ] }, { @@ -1360,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "데이터가 적은 경우, 특히 작은 데이터셋에서는 유지하고 싶은 데이터를 많이 잃을 수 있습니다. 그렇다면 null 값이 몇 개 있거나 심지어 모두 null 값인 행이나 열만 삭제하고 싶다면 어떻게 해야 할까요? `dropna`의 `how`와 `thresh` 매개변수를 사용하여 이를 설정할 수 있습니다.\n", + "이 방법은 특히 작은 데이터셋에서 유지하고 싶은 많은 데이터를 삭제할 수 있다는 점을 유의하세요. 만약 여러 개의 null 값이 포함된 행이나 열, 또는 모든 값이 null인 행이나 열만 삭제하고 싶다면 어떻게 해야 할까요? `dropna`에서 `how`와 `thresh` 매개변수를 설정하여 이를 지정할 수 있습니다.\n", "\n", - "기본적으로 `how='any'`로 설정되어 있습니다 (직접 확인하거나 메서드의 다른 매개변수를 보고 싶다면 코드 셀에서 `example4.dropna?`를 실행해 보세요). 대신 `how='all'`을 지정하여 모든 값이 null인 행이나 열만 삭제하도록 설정할 수도 있습니다. 다음 연습에서 이 동작을 확인하기 위해 예제 `DataFrame`을 확장해 보겠습니다.\n" + "기본적으로 `how='any'`로 설정되어 있습니다(직접 확인하거나 메서드의 다른 매개변수를 보고 싶다면 코드 셀에서 `example4.dropna?`를 실행해 보세요). 대신 `how='all'`을 지정하여 모든 값이 null인 행이나 열만 삭제하도록 설정할 수도 있습니다. 다음 연습에서 이를 확인하기 위해 예제 `DataFrame`을 확장해 보겠습니다.\n" ] }, { @@ -1490,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "`thresh` 매개변수는 더 세밀한 제어를 제공합니다. 행 또는 열이 유지되기 위해 가져야 하는 *null이 아닌* 값의 수를 설정합니다.\n" + "`thresh` 매개변수는 더 세밀한 제어를 제공합니다. 행이나 열이 유지되기 위해 필요한 *null이 아닌* 값의 개수를 설정합니다.\n" ] }, { @@ -1565,7 +1567,7 @@ "id": "fmSFnzZegRsG" }, "source": [ - "여기서 첫 번째와 마지막 행은 삭제되었습니다. 왜냐하면 해당 행들은 비null 값이 두 개만 포함하고 있기 때문입니다.\n" + "여기서 첫 번째와 마지막 행은 삭제되었습니다. 왜냐하면 해당 행들은 두 개의 비어 있지 않은 값만 포함하고 있기 때문입니다.\n" ] }, { @@ -1576,9 +1578,9 @@ "source": [ "### 누락된 값 채우기\n", "\n", - "때로는 누락된 값을 유효할 수 있는 값으로 채우는 것이 합리적일 수 있습니다. 누락된 값을 채우는 몇 가지 방법이 있습니다. 첫 번째는 데이터셋이 기반하고 있는 주제에 대한 도메인 지식(전문 지식)을 활용하여 누락된 값을 대략적으로 추정하는 것입니다.\n", + "때로는 누락된 값을 유효할 수 있는 값으로 채우는 것이 합리적일 때가 있습니다. 누락된 값을 채우는 몇 가지 기술이 있습니다. 첫 번째는 도메인 지식(데이터셋이 기반하고 있는 주제에 대한 지식)을 사용하여 누락된 값을 대략적으로 추정하는 방법입니다.\n", "\n", - "`isnull`을 사용하여 직접 누락된 값을 채울 수도 있지만, 채워야 할 값이 많을 경우 이는 번거로울 수 있습니다. 데이터 과학에서 이러한 작업이 매우 흔하기 때문에 pandas는 `fillna`를 제공합니다. 이 함수는 누락된 값을 사용자가 선택한 값으로 대체한 `Series` 또는 `DataFrame`의 복사본을 반환합니다. 실제로 어떻게 작동하는지 보기 위해 또 다른 예제 `Series`를 만들어 보겠습니다.\n" + "`isnull`을 사용하여 직접 누락된 값을 채울 수도 있지만, 채워야 할 값이 많을 경우 이는 번거로울 수 있습니다. 데이터 과학에서 매우 흔한 작업이기 때문에 pandas는 `fillna`를 제공합니다. 이 함수는 누락된 값을 사용자가 선택한 값으로 대체한 `Series` 또는 `DataFrame`의 복사본을 반환합니다. 실제로 어떻게 작동하는지 보기 위해 또 다른 예제 `Series`를 만들어 보겠습니다.\n" ] }, { @@ -1587,10 +1589,10 @@ "id": "CE8S7louLezV" }, "source": [ - "### 범주형 데이터(비수치형)\n", - "먼저 비수치형 데이터를 살펴보겠습니다. 데이터셋에는 범주형 데이터를 가진 열이 있습니다. 예를 들어, 성별, 참 또는 거짓 등이 있습니다.\n", + "### 범주형 데이터(비숫자)\n", + "먼저 비숫자 데이터를 살펴보겠습니다. 데이터셋에는 범주형 데이터가 포함된 열이 있습니다. 예: 성별, 참 또는 거짓 등.\n", "\n", - "이러한 경우 대부분, 누락된 값을 해당 열의 `최빈값(mode)`으로 대체합니다. 예를 들어, 데이터 포인트가 100개 있고, 그중 90개가 참(True), 8개가 거짓(False), 2개가 응답하지 않았다고 가정해봅시다. 이 경우, 전체 열을 고려하여 누락된 2개를 참(True)으로 채울 수 있습니다.\n", + "이러한 경우 대부분에서, 누락된 값을 해당 열의 `최빈값(mode)`으로 대체합니다. 예를 들어, 데이터 포인트가 100개 있고, 그중 90개가 참(True), 8개가 거짓(False), 2개가 미기입 상태라면, 전체 열을 고려하여 누락된 2개를 참(True)으로 채울 수 있습니다.\n", "\n", "여기에서도 도메인 지식을 활용할 수 있습니다. 최빈값으로 채우는 예를 살펴보겠습니다.\n" ] @@ -1697,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "이제 `None` 값을 모드로 채우기 전에 먼저 모드를 찾아봅시다.\n" + ] }, { "cell_type": "code", @@ -1732,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "그래서, 우리는 None을 True로 대체할 것입니다.\n" + ] }, { "cell_type": "code", @@ -1852,16 +1858,16 @@ }, "source": [ "### 숫자 데이터\n", - "이제 숫자 데이터로 넘어가 보겠습니다. 여기에서는 결측값을 대체하는 두 가지 일반적인 방법이 있습니다:\n", + "이제 숫자 데이터로 넘어가 보겠습니다. 여기서는 누락된 값을 대체하는 두 가지 일반적인 방법이 있습니다:\n", "\n", - "1. 행의 중앙값으로 대체하기\n", - "2. 행의 평균값으로 대체하기\n", + "1. 행의 중앙값으로 대체하기 \n", + "2. 행의 평균값으로 대체하기 \n", "\n", "데이터가 이상치로 인해 왜곡된 경우에는 중앙값으로 대체합니다. 이는 중앙값이 이상치에 강건하기 때문입니다.\n", "\n", "데이터가 정규화된 경우에는 평균값을 사용할 수 있습니다. 이 경우 평균값과 중앙값이 거의 비슷하기 때문입니다.\n", "\n", - "먼저, 정규 분포를 따르는 열을 선택하고 해당 열의 평균값으로 결측값을 채워 보겠습니다.\n" + "먼저, 정규 분포를 따르는 열을 선택하고 해당 열의 평균값으로 누락된 값을 채워 보겠습니다.\n" ] }, { @@ -2001,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "평균으로 채우기\n" + ] }, { "cell_type": "code", @@ -2101,7 +2109,7 @@ "id": "CwpVFCrPTC5z" }, "source": [ - "누락된 값이 평균으로 대체된 것을 볼 수 있습니다.\n" + "우리가 볼 수 있듯이, 누락된 값이 평균으로 대체되었습니다.\n" ] }, { @@ -2110,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "이제 다른 데이터프레임을 시도해보고, 이번에는 None 값을 해당 열의 중앙값으로 대체하겠습니다.\n" + "이제 다른 데이터프레임을 시도해 보겠습니다. 이번에는 None 값을 해당 열의 중앙값으로 대체하겠습니다.\n" ] }, { @@ -2250,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "중앙값으로 채우기\n" + ] }, { "cell_type": "code", @@ -2350,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "NaN 값이 열의 중앙값으로 대체된 것을 볼 수 있습니다.\n" + "우리가 볼 수 있듯이, NaN 값이 해당 열의 중앙값으로 대체되었습니다.\n" ] }, { @@ -2392,7 +2402,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "null 항목을 모두 하나의 값, 예를 들어 `0`으로 채울 수 있습니다.\n" + "모든 null 항목을 단일 값, 예를 들어 `0`으로 채울 수 있습니다:\n" ] }, { @@ -2434,10 +2444,10 @@ }, "source": [ "> 주요 요점:\n", - "1. 누락된 값을 채우는 작업은 데이터가 적거나 누락된 데이터를 채울 전략이 있을 때 수행해야 합니다.\n", - "2. 도메인 지식을 활용하여 누락된 값을 근사치로 채울 수 있습니다.\n", + "1. 누락된 값을 채우는 작업은 데이터가 적거나 누락된 데이터를 채우는 전략이 있을 때 수행해야 합니다.\n", + "2. 도메인 지식을 활용하여 누락된 값을 근사적으로 채울 수 있습니다.\n", "3. 범주형 데이터의 경우, 대부분 누락된 값은 해당 열의 최빈값으로 대체됩니다.\n", - "4. 수치형 데이터의 경우, 누락된 값은 일반적으로 평균(정규화된 데이터셋의 경우) 또는 열의 중앙값으로 채워집니다.\n" + "4. 숫자형 데이터의 경우, 누락된 값은 일반적으로 평균(정규화된 데이터셋의 경우) 또는 열의 중앙값으로 채워집니다.\n" ] }, { @@ -2467,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "널 값을 **앞으로 채우기**로 채울 수 있습니다. 이는 마지막 유효 값을 사용하여 널 값을 채우는 것입니다.\n" + ] }, { "cell_type": "code", @@ -2507,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "다음 유효 값을 뒤로 전파하여 null을 채우기 위해 **백필**할 수도 있습니다:\n" + "다음 유효 값을 뒤로 전파하여 null을 채우기 위해 **백필**할 수도 있습니다.\n" ] }, { @@ -2722,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "이전 값이 전진 채우기에 사용할 수 없을 때, null 값이 그대로 유지됩니다.\n" + "이전 값이 전진 채우기에 사용할 수 없을 때, null 값이 그대로 유지된다는 점을 유의하세요.\n" ] }, { @@ -2755,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "당신은 `fillna`를 사용하는 방법에 대해 창의적으로 접근할 수 있습니다. 예를 들어, `example4`를 다시 살펴보되, 이번에는 `DataFrame`의 모든 값의 평균으로 누락된 값을 채워봅시다:\n" + "당신은 `fillna`를 사용하는 방법에 대해 창의적일 수 있습니다. 예를 들어, 다시 `example4`를 살펴보지만 이번에는 누락된 값을 `DataFrame`의 모든 값의 평균으로 채워봅시다:\n" ] }, { @@ -2846,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "3열은 여전히 값이 없는 상태입니다: 기본 방향은 행 단위로 값을 채우는 것입니다.\n", + "3열이 여전히 값이 없는 상태임을 주목하세요: 기본 방향은 행 단위로 값을 채우는 것입니다.\n", "\n", - "> **핵심 요점:** 데이터셋에서 누락된 값을 처리하는 방법은 여러 가지가 있습니다. 어떤 특정 전략을 사용할지(값을 제거하거나, 대체하거나, 또는 어떻게 대체할지)는 해당 데이터의 특성에 따라 결정되어야 합니다. 데이터셋을 다루고 상호작용할수록 누락된 값을 처리하는 방법에 대한 감각이 더욱 발전할 것입니다.\n" + "> **핵심 요점:** 데이터셋에서 누락된 값을 처리하는 방법은 여러 가지가 있습니다. 누락된 값을 제거하거나, 대체하거나, 대체 방법을 선택하는 전략은 해당 데이터의 특성에 따라 결정되어야 합니다. 데이터셋을 더 많이 다루고 상호작용할수록 누락된 값을 처리하는 방법에 대한 감각이 더욱 발전할 것입니다.\n" ] }, { @@ -2859,7 +2871,7 @@ "source": [ "### 범주형 데이터 인코딩\n", "\n", - "머신러닝 모델은 숫자와 모든 형태의 숫자 데이터만 처리할 수 있습니다. 모델은 '예'와 '아니오'의 차이를 이해할 수 없지만, 0과 1의 차이는 구분할 수 있습니다. 따라서 누락된 값을 채운 후, 모델이 이해할 수 있도록 범주형 데이터를 숫자 형태로 인코딩해야 합니다.\n", + "머신러닝 모델은 숫자와 모든 형태의 숫자 데이터만 처리할 수 있습니다. 모델은 'Yes'와 'No'의 차이를 이해할 수 없지만, 0과 1은 구분할 수 있습니다. 따라서 누락된 값을 채운 후, 모델이 이해할 수 있도록 범주형 데이터를 숫자 형태로 인코딩해야 합니다.\n", "\n", "인코딩은 두 가지 방법으로 수행할 수 있습니다. 다음에서 이를 논의하겠습니다.\n" ] @@ -2872,7 +2884,7 @@ "source": [ "**레이블 인코딩**\n", "\n", - "레이블 인코딩은 각 범주를 숫자로 변환하는 방식입니다. 예를 들어, 항공사 승객 데이터셋이 있고, 해당 데이터셋에 ['business class', 'economy class', 'first class']와 같은 클래스가 포함된 열이 있다고 가정해봅시다. 이 열에 레이블 인코딩을 적용하면 [0, 1, 2]로 변환됩니다. 코드 예제를 통해 이를 살펴보겠습니다. 앞으로의 노트북에서 `scikit-learn`을 학습할 예정이므로 여기서는 사용하지 않겠습니다.\n" + "레이블 인코딩은 기본적으로 각 카테고리를 숫자로 변환하는 것입니다. 예를 들어, 항공사 승객 데이터셋이 있고, 해당 데이터셋에 ['비즈니스 클래스', '이코노미 클래스', '퍼스트 클래스'] 중 하나의 클래스를 포함하는 열이 있다고 가정해봅시다. 이 열에 레이블 인코딩을 적용하면 [0, 1, 2]로 변환됩니다. 코드로 예제를 살펴보겠습니다. 앞으로의 노트북에서 `scikit-learn`을 학습할 예정이므로 여기서는 사용하지 않겠습니다.\n" ] }, { @@ -2980,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "1열에 대해 라벨 인코딩을 수행하려면, 각 클래스에서 숫자로의 매핑을 먼저 설명한 후 교체해야 합니다.\n" + "1열에 레이블 인코딩을 수행하려면 각 클래스에서 숫자로의 매핑을 먼저 설명한 후 교체해야 합니다.\n" ] }, { @@ -3082,7 +3094,7 @@ "id": "ftnF-TyapOPt" }, "source": [ - "우리가 예상했던 결과와 일치하는 것을 볼 수 있습니다. 그렇다면, 라벨 인코딩은 언제 사용해야 할까요? 라벨 인코딩은 다음과 같은 경우에 사용됩니다:\n", + "우리가 볼 수 있듯이, 출력은 우리가 예상했던 것과 일치합니다. 그렇다면 라벨 인코딩은 언제 사용해야 할까요? 라벨 인코딩은 다음과 같은 경우에 사용됩니다:\n", "1. 카테고리의 수가 많을 때\n", "2. 카테고리가 순서대로 정렬되어 있을 때\n" ] @@ -3093,11 +3105,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**원-핫 인코딩**\n", + "**원핫 인코딩**\n", "\n", - "원-핫 인코딩은 또 다른 유형의 인코딩 방식입니다. 이 방식에서는 열의 각 카테고리가 별도의 열로 추가되며, 각 데이터 포인트는 해당 카테고리를 포함하는지 여부에 따라 0 또는 1을 받게 됩니다. 따라서 서로 다른 카테고리가 n개 있다면, 데이터프레임에 n개의 열이 추가됩니다.\n", + "원핫 인코딩은 또 다른 유형의 인코딩 방식입니다. 이 인코딩 방식에서는 열의 각 카테고리가 별도의 열로 추가되며, 각 데이터 포인트는 해당 카테고리를 포함하는지 여부에 따라 0 또는 1을 받게 됩니다. 따라서 서로 다른 카테고리가 n개 있다면, 데이터프레임에 n개의 열이 추가됩니다.\n", "\n", - "예를 들어, 같은 비행기 클래스 예제를 사용해 보겠습니다. 카테고리는 ['business class', 'economy class', 'first class']였습니다. 원-핫 인코딩을 수행하면, 데이터셋에 다음 세 개의 열이 추가됩니다: ['class_business class', 'class_economy class', 'class_first class'].\n" + "예를 들어, 같은 비행기 클래스 예제를 사용해 보겠습니다. 카테고리는 ['business class', 'economy class', 'first class']였습니다. 원핫 인코딩을 수행하면, 데이터셋에 다음 세 개의 열이 추가됩니다: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3205,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "1열에 대해 원-핫 인코딩을 수행합시다\n" + "1열에 대해 원-핫 인코딩을 수행합시다.\n" ] }, { @@ -3330,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "각 원-핫 인코딩된 열은 해당 데이터 포인트에 그 범주가 존재하는지 여부를 지정하는 0 또는 1을 포함합니다.\n" + "각각의 원-핫 인코딩된 열은 0 또는 1을 포함하며, 이는 해당 데이터 포인트에 그 카테고리가 존재하는지를 나타냅니다.\n" ] }, { @@ -3339,10 +3351,10 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "언제 원-핫 인코딩을 사용하나요? 원-핫 인코딩은 다음 경우 중 하나 또는 둘 모두에 사용됩니다:\n", + "원-핫 인코딩은 다음과 같은 경우에 사용됩니다:\n", "\n", - "1. 카테고리 수와 데이터셋 크기가 작은 경우.\n", - "2. 카테고리가 특정한 순서를 따르지 않는 경우.\n" + "1. 카테고리 수와 데이터셋 크기가 작을 때.\n", + "2. 카테고리가 특정한 순서를 따르지 않을 때.\n" ] }, { @@ -3364,9 +3376,9 @@ "source": [ "## 중복 데이터 제거하기\n", "\n", - "> **학습 목표:** 이 절의 끝까지 학습하면 DataFrame에서 중복 값을 식별하고 제거하는 데 익숙해질 것입니다.\n", + "> **학습 목표:** 이 절을 마치면 DataFrame에서 중복 값을 식별하고 제거하는 데 익숙해질 것입니다.\n", "\n", - "누락된 데이터 외에도 실제 데이터셋에서는 중복된 데이터를 자주 접하게 됩니다. 다행히도 pandas는 중복 항목을 감지하고 제거하는 간단한 방법을 제공합니다.\n" + "누락된 데이터 외에도 실제 데이터셋에서 중복된 데이터를 자주 접하게 됩니다. 다행히도 pandas는 중복 항목을 감지하고 제거하는 간단한 방법을 제공합니다.\n" ] }, { @@ -3377,7 +3389,7 @@ "source": [ "### 중복 항목 식별: `duplicated`\n", "\n", - "pandas의 `duplicated` 메서드를 사용하면 중복 값을 쉽게 확인할 수 있습니다. 이 메서드는 `DataFrame`에서 이전 항목과 중복된 항목인지 여부를 나타내는 Boolean 마스크를 반환합니다. 이를 직접 확인하기 위해 또 다른 예제 `DataFrame`을 만들어 보겠습니다.\n" + "pandas의 `duplicated` 메서드를 사용하면 중복 값을 쉽게 확인할 수 있습니다. 이 메서드는 `DataFrame`에서 이전 항목과 중복인지 여부를 나타내는 Boolean 마스크를 반환합니다. 이를 직접 확인하기 위해 또 다른 예제 `DataFrame`을 만들어 보겠습니다.\n" ] }, { @@ -3507,7 +3519,7 @@ }, "source": [ "### 중복 제거: `drop_duplicates`\n", - "`drop_duplicates`는 `duplicated` 값이 모두 `False`인 데이터를 복사하여 반환합니다:\n" + "`drop_duplicates`는 `duplicated` 값이 모두 `False`인 데이터의 복사본을 반환합니다:\n" ] }, { @@ -3590,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "`duplicated`와 `drop_duplicates`는 기본적으로 모든 열을 고려하지만, `DataFrame`에서 특정 열만 검사하도록 지정할 수 있습니다:\n" + "`duplicated`와 `drop_duplicates`는 기본적으로 모든 열을 고려하지만, `DataFrame`에서 특정 열의 부분 집합만을 검사하도록 지정할 수 있습니다:\n" ] }, { @@ -3666,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **요점:** 중복 데이터를 제거하는 것은 거의 모든 데이터 과학 프로젝트에서 필수적인 부분입니다. 중복 데이터는 분석 결과를 변경하고 부정확한 결과를 초래할 수 있습니다!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 실제 데이터 품질 점검\n", + "\n", + "> **학습 목표:** 이 섹션을 마치면, 실제 데이터에서 발생하는 일반적인 품질 문제를 감지하고 수정하는 데 익숙해질 것입니다. 여기에는 불일치하는 범주형 값, 비정상적인 숫자 값(이상치), 그리고 변형된 중복 엔티티가 포함됩니다.\n", + "\n", + "누락된 값과 정확히 동일한 중복은 흔한 문제지만, 실제 데이터셋에는 더 미묘한 문제가 포함되어 있는 경우가 많습니다:\n", + "\n", + "1. **불일치하는 범주형 값**: 동일한 범주가 다르게 표기된 경우 (예: \"USA\", \"U.S.A\", \"United States\")\n", + "2. **비정상적인 숫자 값**: 데이터 입력 오류를 나타내는 극단적인 이상치 (예: 나이 = 999)\n", + "3. **유사 중복 행**: 약간의 변형으로 동일한 엔티티를 나타내는 기록\n", + "\n", + "이러한 문제를 감지하고 처리하는 기술을 살펴보겠습니다.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### \"더러운\" 샘플 데이터셋 생성하기\n", + "\n", + "먼저, 실제 데이터에서 흔히 접하는 문제 유형을 포함한 샘플 데이터셋을 만들어 보겠습니다:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. 일관되지 않은 범주형 값 감지\n", + "\n", + "`country` 열에 동일한 국가에 대해 여러 표현이 있는 것을 확인할 수 있습니다. 이러한 불일치를 찾아봅시다:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 범주형 값 표준화\n", + "\n", + "이 값을 표준화하기 위해 매핑을 생성할 수 있습니다. 간단한 방법은 소문자로 변환하고 매핑 딕셔너리를 만드는 것입니다:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**대안: 퍼지 매칭 사용**\n", + "\n", + "더 복잡한 경우에는 `rapidfuzz` 라이브러리를 사용하여 유사한 문자열을 자동으로 감지하는 퍼지 문자열 매칭을 사용할 수 있습니다:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. 비정상적인 숫자 값(이상치) 감지\n", + "\n", + "`age` 열을 살펴보면 199과 -5 같은 의심스러운 값들이 있습니다. 통계적 방법을 사용하여 이러한 이상치를 감지해 봅시다.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### IQR(사분위 범위) 방법 사용\n", + "\n", + "IQR 방법은 극단적인 값에 덜 민감한 이상치 탐지에 적합한 강력한 통계 기법입니다:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Z-Score 방법 사용\n", + "\n", + "Z-Score 방법은 평균에서 표준편차를 기준으로 이상치를 식별합니다:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 이상치 처리\n", + "\n", + "이상치를 감지한 후에는 여러 가지 방법으로 처리할 수 있습니다:\n", + "1. **제거**: 오류인 경우 이상치가 포함된 행을 삭제\n", + "2. **캡**: 경계값으로 대체\n", + "3. **NaN으로 대체**: 누락된 데이터로 간주하고 대체 기법을 사용\n", + "4. **유지**: 정당한 극단값인 경우 그대로 유지\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. 유사한 행 감지\n", + "\n", + "우리 데이터셋에는 \"John Smith\"에 대한 여러 항목이 약간 다른 값으로 포함되어 있는 것을 볼 수 있습니다. 이름의 유사성을 기준으로 잠재적인 중복 항목을 식별해 봅시다.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 퍼지 매칭을 사용한 유사 항목 찾기\n", + "\n", + "더 정교한 중복 탐지를 위해 퍼지 매칭을 사용하여 유사한 이름을 찾을 수 있습니다:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 중복 처리\n", + "\n", + "중복을 확인한 후에는 이를 어떻게 처리할지 결정해야 합니다:\n", + "1. **첫 번째 항목 유지**: `drop_duplicates(keep='first')` 사용\n", + "2. **마지막 항목 유지**: `drop_duplicates(keep='last')` 사용\n", + "3. **정보 집계**: 중복된 행의 정보를 결합\n", + "4. **수동 검토**: 사람이 직접 검토하도록 표시\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 요약: 완전한 데이터 정리 파이프라인\n", + "\n", + "이제 모든 것을 종합하여 포괄적인 정리 파이프라인을 만들어 봅시다:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 도전 과제\n", + "\n", + "이제 여러분의 차례입니다! 아래는 여러 품질 문제가 있는 새로운 데이터 행입니다. 여러분은 다음을 수행할 수 있나요?\n", + "\n", + "1. 이 행에서 모든 문제를 식별하기\n", + "2. 각 문제를 정리하는 코드를 작성하기\n", + "3. 정리된 행을 데이터셋에 추가하기\n", + "\n", + "다음은 문제가 있는 데이터입니다:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 주요 요점\n", + "\n", + "1. **일관되지 않은 카테고리**는 실제 데이터에서 흔히 발생합니다. 고유 값을 확인하고 매핑 또는 퍼지 매칭을 사용하여 표준화하세요.\n", + "\n", + "2. **이상치**는 분석에 큰 영향을 미칠 수 있습니다. 도메인 지식과 통계적 방법(IQR, Z-점수)을 결합하여 이상치를 감지하세요.\n", + "\n", + "3. **유사 중복 데이터**는 정확히 중복된 데이터보다 감지하기 어렵습니다. 퍼지 매칭을 사용하고 데이터를 정규화(소문자 변환, 공백 제거)하여 이를 식별하는 것을 고려하세요.\n", + "\n", + "4. **데이터 정제는 반복적**입니다. 여러 기술을 적용하고 결과를 검토한 후에 최종적으로 정제된 데이터를 확정해야 할 수도 있습니다.\n", + "\n", + "5. **결정을 문서화하세요**. 어떤 정제 단계를 적용했는지와 그 이유를 기록하세요. 이는 재현성과 투명성을 위해 중요합니다.\n", + "\n", + "> **최고의 실천 방법:** 항상 원본 \"더러운\" 데이터를 복사해 두세요. 소스 데이터 파일을 덮어쓰지 말고 `data_cleaned.csv`와 같은 명확한 이름 규칙을 사용하여 정제된 버전을 만드세요.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**면책 조항**: \n이 문서는 AI 번역 서비스 [Co-op Translator](https://github.com/Azure/co-op-translator)를 사용하여 번역되었습니다. 정확성을 위해 최선을 다하고 있으나, 자동 번역에는 오류나 부정확성이 포함될 수 있습니다. 원본 문서의 원어 버전을 권위 있는 출처로 간주해야 합니다. 중요한 정보의 경우, 전문적인 인간 번역을 권장합니다. 이 번역 사용으로 인해 발생하는 오해나 잘못된 해석에 대해 책임을 지지 않습니다.\n" + "\n---\n\n**면책 조항**: \n이 문서는 AI 번역 서비스 [Co-op Translator](https://github.com/Azure/co-op-translator)를 사용하여 번역되었습니다. 정확성을 위해 최선을 다하고 있으나, 자동 번역에는 오류나 부정확성이 포함될 수 있습니다. 원본 문서의 원어 버전을 권위 있는 자료로 간주해야 합니다. 중요한 정보의 경우, 전문적인 인간 번역을 권장합니다. 이 번역 사용으로 인해 발생하는 오해나 잘못된 해석에 대해 당사는 책임을 지지 않습니다.\n" ] } ], @@ -3700,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T22:08:08+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:32:10+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "ko" } diff --git a/translations/lt/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/lt/2-Working-With-Data/08-data-preparation/notebook.ipynb index 40c9530b..57938f64 100644 --- a/translations/lt/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/lt/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -12,11 +12,11 @@ "\n", "## `DataFrame` informacijos tyrinėjimas\n", "\n", - "> **Mokymosi tikslas:** Šios poskyrio pabaigoje turėtumėte jaustis patogiai ieškodami bendros informacijos apie duomenis, saugomus pandas `DataFrame`.\n", + "> **Mokymosi tikslas:** Šios poskirsnio pabaigoje turėtumėte jaustis patogiai ieškodami bendros informacijos apie pandas `DataFrame` saugomus duomenis.\n", "\n", - "Kai jau įkėlėte savo duomenis į pandas, jie greičiausiai bus `DataFrame` formatu. Tačiau, jei jūsų `DataFrame` duomenų rinkinys turi 60 000 eilučių ir 400 stulpelių, nuo ko pradėti, kad suprastumėte, su kuo dirbate? Laimei, pandas suteikia keletą patogių įrankių, leidžiančių greitai peržiūrėti bendrą informaciją apie `DataFrame`, taip pat pirmąsias ir paskutines kelias eilutes.\n", + "Kai jau įkėlėte savo duomenis į pandas, jie greičiausiai bus `DataFrame` formatu. Tačiau, jei jūsų `DataFrame` duomenų rinkinys turi 60 000 eilučių ir 400 stulpelių, nuo ko pradėti, kad suprastumėte, su kuo dirbate? Laimei, pandas siūlo keletą patogių įrankių, leidžiančių greitai peržiūrėti bendrą informaciją apie `DataFrame`, taip pat pirmąsias ir paskutines kelias eilutes.\n", "\n", - "Norėdami išbandyti šią funkcionalumą, importuosime Python scikit-learn biblioteką ir naudosime ikonišką duomenų rinkinį, kurį kiekvienas duomenų mokslininkas yra matęs šimtus kartų: britų biologo Ronaldo Fisherio *Iris* duomenų rinkinį, naudotą jo 1936 metų straipsnyje „Daugybinių matavimų naudojimas taksonomijos problemose“:\n" + "Norėdami išbandyti šią funkcionalumą, importuosime Python biblioteką scikit-learn ir naudosime ikoninius duomenis, kuriuos kiekvienas duomenų mokslininkas yra matęs šimtus kartų: britų biologo Ronaldo Fisherio *Iris* duomenų rinkinį, naudotą jo 1936 metų straipsnyje „Daugybinių matavimų naudojimas taksonomijos problemose“:\n" ] }, { @@ -78,7 +78,7 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Taigi, mes turime 150 eilučių ir 4 stulpelius duomenų. Kiekviena eilutė atspindi vieną duomenų tašką, o kiekvienas stulpelis – vieną savybę, susijusią su duomenų rėmeliu. Taigi, iš esmės yra 150 duomenų taškų, kuriuose kiekviename yra po 4 savybes.\n", + "Taigi, mes dirbame su 150 eilučių ir 4 stulpeliais duomenų. Kiekviena eilutė atspindi vieną duomenų tašką, o kiekvienas stulpelis – vieną su duomenų rėmeliu susijusią savybę. Taigi, iš esmės yra 150 duomenų taškų, kurių kiekvienas turi 4 savybes.\n", "\n", "`shape` čia yra duomenų rėmelio atributas, o ne funkcija, todėl jis nesibaigia skliausteliais.\n" ] @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Dabar pereikime prie 4 duomenų stulpelių. Ką tiksliai kiekvienas iš jų reiškia? `columns` atributas suteiks mums stulpelių pavadinimus duomenų rėmelyje.\n" + "Dabar pereikime prie 4 duomenų stulpelių. Ką tiksliai kiekvienas iš jų reiškia? `columns` atributas pateiks mums stulpelių pavadinimus duomenų rėmelyje.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Kaip matome, yra keturios (4) stulpeliai. `columns` atributas nurodo stulpelių pavadinimus ir iš esmės nieko daugiau. Šis atributas tampa svarbus, kai norime nustatyti, kokias savybes turi duomenų rinkinys.\n" + "Kaip matome, yra keturios (4) stulpeliai. `columns` atributas nurodo stulpelių pavadinimus ir iš esmės nieko daugiau. Šis atributas tampa svarbus, kai norime nustatyti, kokias ypatybes duomenų rinkinys turi.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Duomenų kiekis (nurodytas `shape` atributu) ir savybių ar stulpelių pavadinimai (nurodyti `columns` atributu) suteikia mums tam tikrą informaciją apie duomenų rinkinį. Dabar norėtume giliau pažvelgti į duomenų rinkinį. Funkcija `DataFrame.info()` yra labai naudinga šiuo atveju.\n" + "Duomenų kiekis (nurodytas per `shape` atributą) ir savybių arba stulpelių pavadinimai (nurodyti per `columns` atributą) suteikia mums tam tikrą informaciją apie duomenų rinkinį. Dabar norėtume giliau pasinerti į duomenų rinkinį. Funkcija `DataFrame.info()` yra labai naudinga šiuo atveju.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Iš čia galime padaryti keletą pastebėjimų: \n", - "1. Kiekvienos stulpelio duomenų tipas: Šiame duomenų rinkinyje visi duomenys yra saugomi kaip 64 bitų slankiojo kablelio skaičiai. \n", - "2. Ne-null reikšmių skaičius: Darbas su null reikšmėmis yra svarbus duomenų paruošimo žingsnis. Tai bus aptarta vėliau užrašų knygelėje. \n" + "Iš čia galime padaryti kelias pastabas: \n", + "1. Kiekvieno stulpelio duomenų tipas: Šiame duomenų rinkinyje visi duomenys saugomi kaip 64 bitų slankiojo kablelio skaičiai. \n", + "2. Ne-null reikšmių skaičius: Darbas su null reikšmėmis yra svarbus duomenų paruošimo etapas. Tai bus sprendžiama vėliau šiame užrašų knygelėje. \n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Tarkime, turime daug skaitinių duomenų savo duomenų rinkinyje. Vieno kintamojo statistiniai skaičiavimai, tokie kaip vidurkis, mediana, kvartiliai ir pan., gali būti atliekami kiekvienai stulpeliui atskirai. Funkcija `DataFrame.describe()` pateikia statistinę santrauką apie skaitinius duomenų rinkinio stulpelius.\n" + "Tarkime, turime daug skaitinių duomenų savo duomenų rinkinyje. Vieno kintamojo statistiniai skaičiavimai, tokie kaip vidurkis, mediana, kvartiliai ir pan., gali būti atliekami kiekvienam stulpeliui atskirai. Funkcija `DataFrame.describe()` pateikia statistinę santrauką apie skaitinius duomenų rinkinio stulpelius.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "Rezultatas aukščiau rodo bendrą duomenų taškų skaičių, vidurkį, standartinį nuokrypį, minimumą, apatinį kvartilį (25%), medianą (50%), viršutinį kvartilį (75%) ir maksimalų kiekvienos stulpelio reikšmę.\n" + "Pateiktas rezultatas rodo bendrą duomenų taškų skaičių, vidurkį, standartinį nuokrypį, mažiausią reikšmę, apatinį kvartilį (25%), medianą (50%), viršutinį kvartilį (75%) ir didžiausią kiekvienos stulpelio reikšmę.\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "Turėdami visas aukščiau paminėtas funkcijas ir atributus, jau turime bendrą duomenų rinkinio vaizdą. Žinome, kiek yra duomenų taškų, kiek yra požymių, kokio tipo yra kiekvienas požymis ir kiek kiekvienas požymis turi nenulinių reikšmių.\n", + "Naudodami visas aukščiau paminėtas funkcijas ir atributus, jau turime bendrą duomenų rinkinio vaizdą. Žinome, kiek yra duomenų taškų, kiek yra savybių, kiekvienos savybės duomenų tipą ir kiek yra nenulinių reikšmių kiekvienai savybei.\n", "\n", - "Dabar laikas pažvelgti į pačius duomenis. Pažiūrėkime, kaip atrodo pirmosios kelios mūsų `DataFrame` eilutės (pirmieji keli duomenų taškai):\n" + "Dabar metas pažvelgti į pačius duomenis. Pažiūrėkime, kaip atrodo pirmosios kelios eilutės (pirmieji keli duomenų taškai) mūsų `DataFrame`:\n" ] }, { @@ -450,9 +450,9 @@ "id": "oj7GkrTdgRry" }, "source": [ - "### Pratimas:\n", + "### Užduotis:\n", "\n", - "Iš pateikto pavyzdžio aišku, kad pagal numatytuosius nustatymus `DataFrame.head` grąžina pirmas penkias `DataFrame` eilutes. Ar galite sugalvoti būdą, kaip parodyti daugiau nei penkias eilutes žemiau esančiame kodo langelyje?\n" + "Iš pateikto pavyzdžio aišku, kad pagal numatytuosius nustatymus `DataFrame.head` grąžina pirmas penkias `DataFrame` eilutes. Ar galite žemiau esančiame kodo langelyje sugalvoti būdą, kaip parodyti daugiau nei penkias eilutes?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Kitas būdas peržiūrėti duomenis yra nuo pabaigos (vietoj pradžios). Priešingybė `DataFrame.head` yra `DataFrame.tail`, kuris grąžina paskutines penkias `DataFrame` eilutes:\n" + "Kitas būdas peržiūrėti duomenis yra nuo pabaigos (užuot pradėjus nuo pradžios). Priešingybė `DataFrame.head` yra `DataFrame.tail`, kuris grąžina paskutines penkias `DataFrame` eilutes:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "Praktiškai yra naudinga lengvai peržiūrėti pirmas kelias arba paskutines kelias `DataFrame` eilutes, ypač kai ieškote išskirtinių reikšmių tvarkinguose duomenų rinkiniuose.\n", + "Praktikoje naudinga lengvai peržiūrėti pirmas kelias arba paskutines kelias `DataFrame` eilutes, ypač kai ieškote išskirtinių reikšmių tvarkinguose duomenų rinkiniuose.\n", "\n", "Visos aukščiau pateiktos funkcijos ir atributai, parodyti su kodo pavyzdžiais, padeda mums susidaryti įspūdį apie duomenis.\n", "\n", - "> **Svarbiausia mintis:** Net vien pažvelgus į metaduomenis apie informaciją `DataFrame` arba į pirmas ir paskutines kelias reikšmes, galite iš karto susidaryti įspūdį apie duomenų dydį, formą ir turinį, su kuriais dirbate.\n" + "> **Svarbiausia mintis:** Net paprasčiausiai pažvelgus į metaduomenis apie informaciją `DataFrame` arba į pirmas ir paskutines kelias reikšmes, galite iš karto susidaryti vaizdą apie duomenų dydį, formą ir turinį, su kuriais dirbate.\n" ] }, { @@ -595,16 +595,16 @@ "id": "TvurZyLSDxq_" }, "source": [ - "### Trūkstami Duomenys\n", + "### Trūkstami duomenys\n", "Panagrinėkime trūkstamus duomenis. Trūkstami duomenys atsiranda, kai kai kuriuose stulpeliuose nėra išsaugota jokia reikšmė.\n", "\n", - "Pavyzdžiui: tarkime, kažkas yra labai susirūpinęs savo svoriu ir nepildo svorio lauko apklausoje. Tokiu atveju, to žmogaus svorio reikšmė bus trūkstama.\n", + "Pavyzdžiui: tarkime, kažkas labai rūpinasi savo svoriu ir nepildo svorio laukelio apklausoje. Tokiu atveju to asmens svorio reikšmė bus trūkstama.\n", "\n", "Dažniausiai realaus pasaulio duomenų rinkiniuose pasitaiko trūkstamų reikšmių.\n", "\n", "**Kaip Pandas tvarko trūkstamus duomenis**\n", "\n", - "Pandas trūkstamas reikšmes tvarko dviem būdais. Pirmasis būdas, kurį jau matėte ankstesnėse dalyse, yra `NaN`, arba Not a Number (ne skaičius). Tai iš tikrųjų yra speciali reikšmė, kuri yra IEEE slankiojo kablelio specifikacijos dalis ir naudojama tik trūkstamoms slankiojo kablelio reikšmėms nurodyti.\n", + "Pandas trūkstamas reikšmes tvarko dviem būdais. Pirmąjį jau matėte ankstesnėse dalyse: `NaN`, arba Not a Number (ne skaičius). Tai iš tikrųjų yra speciali reikšmė, kuri yra IEEE slankiojo kablelio specifikacijos dalis ir naudojama tik trūkstamoms slankiojo kablelio reikšmėms nurodyti.\n", "\n", "Kitoms trūkstamoms reikšmėms, išskyrus slankiojo kablelio reikšmes, pandas naudoja Python objektą `None`. Nors gali atrodyti painu, kad susidursite su dviem skirtingais reikšmių tipais, kurie iš esmės reiškia tą patį, yra pagrįstų programavimo priežasčių, kodėl buvo pasirinktas toks dizainas. Praktikoje toks sprendimas leidžia pandas pasiekti gerą kompromisą daugeliu atvejų. Nepaisant to, tiek `None`, tiek `NaN` turi apribojimų, kuriuos reikia žinoti, atsižvelgiant į tai, kaip jie gali būti naudojami.\n" ] @@ -615,8 +615,8 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: trūkstami duomenys, kurie nėra skaičiai\n", - "Kadangi `None` yra iš Python, jis negali būti naudojamas NumPy ir pandas masyvuose, kurių duomenų tipas nėra `'object'`. Atminkite, kad NumPy masyvai (ir pandas duomenų struktūros) gali turėti tik vieno tipo duomenis. Tai suteikia jiems didžiulę galią dirbant su didelio masto duomenimis ir atliekant skaičiavimus, tačiau tuo pačiu apriboja jų lankstumą. Tokie masyvai turi būti perkelti į „mažiausią bendrą vardiklį“, duomenų tipą, kuris apima viską masyve. Kai masyve yra `None`, tai reiškia, kad dirbate su Python objektais.\n", + "### `None`: ne skaičių trūkstami duomenys\n", + "Kadangi `None` yra iš Python, jo negalima naudoti NumPy ir pandas masyvuose, kurių duomenų tipas nėra `'object'`. Atminkite, kad NumPy masyvai (ir pandas duomenų struktūros) gali turėti tik vieno tipo duomenis. Tai suteikia jiems didžiulę galią dirbant su didelio masto duomenimis ir atliekant skaičiavimus, tačiau tuo pačiu riboja jų lankstumą. Tokie masyvai turi būti konvertuoti į „mažiausią bendrą vardiklį“, t. y. duomenų tipą, kuris apims viską masyve. Kai masyve yra `None`, tai reiškia, kad dirbate su Python objektais.\n", "\n", "Norėdami tai pamatyti praktiškai, apsvarstykite šį pavyzdinį masyvą (atkreipkite dėmesį į jo `dtype`):\n" ] @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Realybė, susijusi su duomenų tipų konvertavimu į aukštesnį lygį, turi dvi pasekmes. Pirma, operacijos bus vykdomos interpretuojamo Python kodo lygiu, o ne kompiliuoto NumPy kodo lygiu. Iš esmės tai reiškia, kad bet kokios operacijos, susijusios su `Series` ar `DataFrame` objektais, kuriuose yra `None`, bus lėtesnės. Nors greičiausiai šio našumo sumažėjimo nepastebėsite, didelių duomenų rinkinių atveju tai gali tapti problema.\n", + "Duomenų tipų konvertavimas į aukštesnį lygį turi du šalutinius poveikius. Pirma, operacijos bus vykdomos interpretuojamo Python kodo lygiu, o ne kompiliuoto NumPy kodo lygiu. Iš esmės tai reiškia, kad bet kokios operacijos, susijusios su `Series` ar `DataFrame` objektais, kuriuose yra `None`, bus lėtesnės. Nors greičiausiai nepastebėsite šio našumo sumažėjimo, dideliems duomenų rinkiniams tai gali tapti problema.\n", "\n", - "Antroji pasekmė kyla iš pirmosios. Kadangi `None` iš esmės grąžina `Series` ar `DataFrame` į paprasto Python pasaulį, naudojant NumPy/pandas agregavimo funkcijas, tokias kaip `sum()` ar `min()`, masyvuose, kuriuose yra `None` reikšmė, paprastai bus sugeneruota klaida:\n" + "Antrasis šalutinis poveikis kyla iš pirmojo. Kadangi `None` iš esmės grąžina `Series` ar `DataFrame` į paprasto Python pasaulį, naudojant NumPy/pandas agregacijas, tokias kaip `sum()` ar `min()`, masyvuose, kuriuose yra ``None`` reikšmė, paprastai bus generuojama klaida:\n" ] }, { @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Pagrindinė mintis**: Sudėtis (ir kitos operacijos) tarp sveikųjų skaičių ir `None` reikšmių yra neapibrėžta, todėl tai gali apriboti galimybes dirbti su duomenų rinkiniais, kuriuose jos yra.\n" + "**Svarbiausia išvada**: Sudėtis (ir kitos operacijos) tarp sveikųjų skaičių ir `None` reikšmių yra neapibrėžta, todėl tai gali apriboti, ką galima atlikti su duomenų rinkiniais, kuriuose jos yra.\n" ] }, { @@ -709,7 +709,7 @@ "source": [ "### `NaN`: trūkstamos slankiojo kablelio reikšmės\n", "\n", - "Skirtingai nei `None`, NumPy (ir todėl pandas) palaiko `NaN`, kad būtų galima atlikti greitas, vektorizuotas operacijas ir ufuncs. Bloga žinia yra ta, kad bet kokia aritmetika, atliekama su `NaN`, visada duoda `NaN`. Pavyzdžiui:\n" + "Skirtingai nuo `None`, NumPy (ir todėl pandas) palaiko `NaN`, kad būtų galima atlikti greitas, vektorizuotas operacijas ir ufuncs. Bloga žinia yra ta, kad bet kokia aritmetinė operacija su `NaN` visada duoda `NaN`. Pavyzdžiui:\n" ] }, { @@ -831,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "Atminkite: `NaN` yra skirtas tik trūkstamoms slankiojo kablelio reikšmėms; nėra `NaN` ekvivalento sveikiesiems skaičiams, eilutėms ar loginėms reikšmėms.\n" + "Atminkite: `NaN` yra skirtas tik trūkstamoms slankiojo kablelio reikšmėms; nėra `NaN` atitikmens sveikiesiems skaičiams, eilutėms ar loginėms reikšmėms.\n" ] }, { @@ -840,9 +840,9 @@ "id": "kj6EKdsAgRsA" }, "source": [ - "### `NaN` ir `None`: null reikšmės pandas bibliotekoje\n", + "### `NaN` ir `None`: null reikšmės pandas\n", "\n", - "Nors `NaN` ir `None` gali elgtis šiek tiek skirtingai, pandas biblioteka yra sukurta taip, kad su jais būtų galima dirbti kaip su lygiavertėmis reikšmėmis. Kad tai suprastume, pažiūrėkime į `Series` su sveikaisiais skaičiais:\n" + "Nors `NaN` ir `None` gali elgtis šiek tiek skirtingai, pandas vis tiek sukurta taip, kad galėtų juos tvarkyti kaip lygiaverčius. Kad suprastumėte, ką turime omenyje, apsvarstykite `Series` su sveikaisiais skaičiais:\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Pandas, siekdama užtikrinti duomenų homogeniškumą `Series` ir `DataFrame` objektuose, lengvai keičia trūkstamas reikšmes tarp `None` ir `NaN`. Dėl šios dizaino ypatybės naudinga galvoti apie `None` ir `NaN` kaip apie dvi skirtingas „null“ reikšmių formas pandas bibliotekoje. Iš tiesų, kai kurie pagrindiniai metodai, kuriuos naudosite tvarkydami trūkstamas reikšmes pandas, atspindi šią idėją savo pavadinimuose:\n", + "Atliekant duomenų tipų konvertavimą į aukštesnį lygį, siekiant užtikrinti duomenų homogeniškumą `Series` ir `DataFrame` objektuose, pandas lengvai keičia trūkstamas reikšmes tarp `None` ir `NaN`. Dėl šios dizaino ypatybės naudinga galvoti apie `None` ir `NaN` kaip apie dvi skirtingas „null“ reikšmių formas pandas bibliotekoje. Iš tiesų, kai kurie pagrindiniai metodai, kuriuos naudosite dirbdami su trūkstamomis reikšmėmis pandas, atspindi šią idėją savo pavadinimuose:\n", "\n", "- `isnull()`: Sukuria loginę kaukę, nurodančią trūkstamas reikšmes\n", "- `notnull()`: Priešingas `isnull()`\n", "- `dropna()`: Grąžina filtruotą duomenų versiją\n", - "- `fillna()`: Grąžina duomenų kopiją su užpildytomis arba įterptomis trūkstamomis reikšmėmis\n", + "- `fillna()`: Grąžina duomenų kopiją su užpildytomis arba įvertintomis trūkstamomis reikšmėmis\n", "\n", - "Šie metodai yra labai svarbūs, todėl verta juos gerai išmokti ir jaustis patogiai juos naudojant. Dabar išsamiau aptarkime kiekvieną iš jų.\n" + "Tai yra svarbūs metodai, kuriuos verta išmokti ir gerai suprasti, todėl panagrinėkime juos kiekvieną išsamiau.\n" ] }, { @@ -922,10 +922,10 @@ "id": "Yh5ifd9FgRsB" }, "source": [ - "### Nustatyti null reikšmes\n", + "### Aptikti null reikšmes\n", "\n", - "Dabar, kai supratome trūkstamų reikšmių svarbą, turime jas nustatyti savo duomenų rinkinyje, prieš pradėdami jas tvarkyti. \n", - "Tiek `isnull()`, tiek `notnull()` yra pagrindiniai metodai, skirti nustatyti null duomenis. Abu grąžina Boole'o kaukes jūsų duomenims.\n" + "Dabar, kai supratome, kodėl trūkstamos reikšmės yra svarbios, turime jas aptikti savo duomenų rinkinyje, prieš pradėdami jas tvarkyti. \n", + "Tiek `isnull()`, tiek `notnull()` yra pagrindiniai metodai, skirti aptikti null duomenis. Abu metodai grąžina Boole'o kaukes jūsų duomenims.\n" ] }, { @@ -978,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Ar atidžiai pažvelgėte į rezultatą? Ar kas nors jus nustebino? Nors `0` yra aritmetinis nulis, jis vis tiek yra visiškai tinkamas sveikasis skaičius, ir pandas jį taip ir traktuoja. `''` yra šiek tiek subtilesnis atvejis. Nors 1 skyriuje jį naudojome kaip tuščios eilutės reikšmę, vis dėlto tai yra eilutės objektas, o ne null reprezentacija pandas požiūriu.\n", + "Atidžiai pažvelkite į rezultatą. Ar kas nors jus nustebino? Nors `0` yra aritmetinis nulis, jis vis tiek yra visiškai tinkamas sveikasis skaičius, ir pandas jį taip ir traktuoja. `''` yra šiek tiek subtilesnis. Nors 1 skyriuje jį naudojome kaip tuščios eilutės reikšmę, jis vis tiek yra eilutės objektas, o ne null reprezentacija pandas požiūriu.\n", "\n", - "Dabar apverskime situaciją ir naudokime šiuos metodus taip, kaip juos naudosite praktiškai. Boolean kaukes galite naudoti tiesiogiai kaip ``Series`` arba ``DataFrame`` indeksą, kas gali būti naudinga dirbant su izoliuotomis trūkstamomis (arba esamomis) reikšmėmis.\n", + "Dabar apsukime situaciją ir panaudokime šiuos metodus taip, kaip dažniausiai juos naudosite praktikoje. Boolean kaukes galite naudoti tiesiogiai kaip ``Series`` arba ``DataFrame`` indeksą, kas gali būti naudinga dirbant su izoliuotomis trūkstamomis (arba esamomis) reikšmėmis.\n", "\n", - "Jei norime gauti bendrą trūkstamų reikšmių skaičių, galime tiesiog atlikti sumą pagal kaukę, kurią sukuria `isnull()` metodas.\n" + "Jei norime sužinoti bendrą trūkstamų reikšmių skaičių, tiesiog galime atlikti sumą per kaukę, kurią sukuria `isnull()` metodas.\n" ] }, { @@ -1040,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Pagrindinė mintis**: Tiek `isnull()`, tiek `notnull()` metodai duoda panašius rezultatus, kai juos naudojate „DataFrame“: jie parodo rezultatus ir tų rezultatų indeksą, kas labai padės jums dirbant su savo duomenimis.\n" + "**Svarbiausia**: Tiek `isnull()`, tiek `notnull()` metodai duoda panašius rezultatus, kai juos naudojate „DataFrame“ objektuose: jie parodo rezultatus ir tų rezultatų indeksus, kurie jums labai padės dirbant su duomenimis.\n" ] }, { @@ -1051,9 +1051,9 @@ "source": [ "### Darbas su trūkstamais duomenimis\n", "\n", - "> **Mokymosi tikslas:** Šio poskyrio pabaigoje turėtumėte žinoti, kaip ir kada pakeisti arba pašalinti null reikšmes iš DataFrame.\n", + "> **Mokymosi tikslas:** Šios poskyrio pabaigoje turėtumėte žinoti, kaip ir kada pakeisti arba pašalinti null reikšmes iš DataFrames.\n", "\n", - "Mašininio mokymosi modeliai patys negali apdoroti trūkstamų duomenų. Todėl prieš perduodant duomenis modeliui, turime išspręsti šių trūkstamų reikšmių problemą.\n", + "Mašininio mokymosi modeliai patys negali apdoroti trūkstamų duomenų. Todėl prieš perduodant duomenis modeliui, turime išspręsti šias trūkstamas reikšmes.\n", "\n", "Kaip tvarkomi trūkstami duomenys, turi subtilių kompromisų, kurie gali paveikti jūsų galutinę analizę ir realaus pasaulio rezultatus.\n", "\n", @@ -1062,7 +1062,7 @@ "1. Pašalinti eilutę, kurioje yra trūkstama reikšmė\n", "2. Pakeisti trūkstamą reikšmę kita reikšme\n", "\n", - "Mes aptarsime abu šiuos metodus ir jų privalumus bei trūkumus išsamiai.\n" + "Abi šias metodikas aptarsime išsamiai, įskaitant jų privalumus ir trūkumus.\n" ] }, { @@ -1073,9 +1073,9 @@ "source": [ "### Null reikšmių pašalinimas\n", "\n", - "Duomenų kiekis, kurį perduodame savo modeliui, tiesiogiai veikia jo našumą. Pašalinus null reikšmes, sumažiname duomenų taškų skaičių, o kartu ir duomenų rinkinio dydį. Todėl rekomenduojama pašalinti eilutes su null reikšmėmis, kai duomenų rinkinys yra pakankamai didelis.\n", + "Duomenų kiekis, kurį perduodame savo modeliui, tiesiogiai veikia jo našumą. Pašalinus null reikšmes, sumažiname duomenų taškų skaičių, o kartu ir duomenų rinkinio dydį. Todėl patartina pašalinti eilutes su null reikšmėmis, kai duomenų rinkinys yra pakankamai didelis.\n", "\n", - "Kitas atvejis gali būti, kai tam tikra eilutė ar stulpelis turi daug trūkstamų reikšmių. Tokiu atveju jie gali būti pašalinti, nes jie nepridės daug vertės mūsų analizei, kadangi didžioji dalis duomenų toje eilutėje/stulpelyje yra trūkstama.\n", + "Kitas atvejis gali būti, kai tam tikra eilutė ar stulpelis turi daug trūkstamų reikšmių. Tokiu atveju jie gali būti pašalinti, nes jie nedaug prisidėtų prie mūsų analizės, kadangi dauguma duomenų toje eilutėje/stulpelyje yra trūkstami.\n", "\n", "Be trūkstamų reikšmių identifikavimo, pandas suteikia patogų būdą pašalinti null reikšmes iš `Series` ir `DataFrame`. Kad pamatytume, kaip tai veikia, grįžkime prie `example3`. Funkcija `DataFrame.dropna()` padeda pašalinti eilutes su null reikšmėmis.\n" ] @@ -1118,7 +1118,7 @@ "source": [ "Atkreipkite dėmesį, kad tai turėtų atrodyti kaip jūsų išvestis iš `example3[example3.notnull()]`. Skirtumas čia yra tas, kad vietoj tiesiog indeksavimo pagal užmaskuotas reikšmes, `dropna` pašalino tas trūkstamas reikšmes iš `Series` `example3`.\n", "\n", - "Kadangi DataFrames turi dvi dimensijas, jie suteikia daugiau galimybių duomenims pašalinti.\n" + "Kadangi `DataFrame` turi dvi dimensijas, jos suteikia daugiau galimybių duomenims pašalinti.\n" ] }, { @@ -1208,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Ar pastebėjote, kad pandas pakeitė dviejų stulpelių tipą į float, kad būtų galima įtraukti `NaN`?)\n", + "(Ar pastebėjote, kad pandas pakeitė dviejų stulpelių tipą į float, kad galėtų apdoroti `NaN` reikšmes?)\n", "\n", - "Negalite pašalinti vienos reikšmės iš `DataFrame`, todėl turite pašalinti visas eilutes arba stulpelius. Priklausomai nuo to, ką darote, galite pasirinkti vieną ar kitą variantą, todėl pandas suteikia galimybes abiem. Kadangi duomenų moksle stulpeliai paprastai atspindi kintamuosius, o eilutės – stebėjimus, dažniau pašalinamos duomenų eilutės; numatytasis `dropna()` nustatymas yra pašalinti visas eilutes, kuriose yra bet kokių null reikšmių:\n" + "Negalite pašalinti vienos reikšmės iš `DataFrame`, todėl turite pašalinti visas eilutes arba stulpelius. Priklausomai nuo to, ką darote, galite norėti pasirinkti vieną ar kitą variantą, todėl pandas suteikia galimybę naudoti abu. Kadangi duomenų moksle stulpeliai paprastai atspindi kintamuosius, o eilutės – stebėjimus, dažniau pašalinamos eilutės su duomenimis; numatytasis `dropna()` nustatymas yra pašalinti visas eilutes, kuriose yra bet kokių null reikšmių:\n" ] }, { @@ -1362,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Atkreipkite dėmesį, kad tai gali pašalinti daug duomenų, kuriuos galbūt norėtumėte išsaugoti, ypač mažesniuose duomenų rinkiniuose. O kas, jei norite pašalinti tik tas eilutes ar stulpelius, kuriuose yra kelios arba net visos null reikšmės? Šiuos nustatymus galite nurodyti `dropna` funkcijoje naudodami `how` ir `thresh` parametrus.\n", + "Atkreipkite dėmesį, kad tai gali pašalinti daug duomenų, kuriuos galbūt norėtumėte išsaugoti, ypač mažesniuose duomenų rinkiniuose. O kas, jei norite pašalinti tik tas eilutes ar stulpelius, kuriuose yra keli arba net visi null reikšmės? Šiuos nustatymus galite nurodyti `dropna` naudojant `how` ir `thresh` parametrus.\n", "\n", - "Pagal numatytuosius nustatymus `how='any'` (jei norite patys patikrinti arba pamatyti, kokius kitus parametrus metodas turi, paleiskite `example4.dropna?` kodo langelyje). Taip pat galite nurodyti `how='all`, kad būtų pašalintos tik tos eilutės ar stulpeliai, kuriuose yra visos null reikšmės. Išplėskime mūsų pavyzdinį `DataFrame`, kad pamatytume tai veikiant kitame pratime.\n" + "Pagal numatytuosius nustatymus `how='any'` (jei norite patikrinti patys arba pamatyti, kokius kitus parametrus turi šis metodas, vykdykite `example4.dropna?` kodų langelyje). Taip pat galite nurodyti `how='all'`, kad pašalintumėte tik tas eilutes ar stulpelius, kuriuose yra visos null reikšmės. Išplėskime mūsų pavyzdinį `DataFrame`, kad pamatytume tai veikiant kitame pratime.\n" ] }, { @@ -1457,10 +1457,10 @@ }, "source": [ "> Pagrindinės mintys: \n", - "1. Naudinga pašalinti null reikšmes tik tada, jei duomenų rinkinys yra pakankamai didelis. \n", - "2. Pilnas eilutes arba stulpelius galima pašalinti, jei dauguma jų duomenų trūksta. \n", - "3. Metodas `DataFrame.dropna(axis=)` padeda pašalinti null reikšmes. Argumentas `axis` nurodo, ar reikia pašalinti eilutes, ar stulpelius. \n", - "4. Taip pat galima naudoti argumentą `how`. Pagal numatytuosius nustatymus jis nustatytas į `any`. Tai reiškia, kad bus pašalintos tik tos eilutės/stulpeliai, kuriuose yra bet kokių null reikšmių. Jį galima nustatyti į `all`, kad būtų pašalintos tik tos eilutės/stulpeliai, kur visi duomenys yra null. \n" + "1. Naikinti null reikšmes verta tik tada, kai duomenų rinkinys yra pakankamai didelis. \n", + "2. Pilnos eilutės ar stulpeliai gali būti pašalinti, jei dauguma jų duomenų trūksta. \n", + "3. `DataFrame.dropna(axis=)` metodas padeda pašalinti null reikšmes. Argumentas `axis` nurodo, ar reikia šalinti eilutes, ar stulpelius. \n", + "4. Taip pat galima naudoti argumentą `how`. Pagal numatytąją reikšmę jis nustatytas kaip `any`. Taigi, pašalinamos tik tos eilutės/stulpeliai, kuriuose yra bet kokių null reikšmių. Jį galima nustatyti kaip `all`, kad būtų pašalintos tik tos eilutės/stulpeliai, kur visi duomenys yra null. \n" ] }, { @@ -1492,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "`thresh` parametras suteikia jums smulkesnę kontrolę: jūs nustatote *ne-null* reikšmių skaičių, kurį eilutė arba stulpelis turi turėti, kad būtų išsaugotas:\n" + "`thresh` parametras suteikia jums smulkesnę kontrolę: jūs nustatote *ne-null* reikšmių skaičių, kurį eilutė ar stulpelis turi turėti, kad būtų išsaugotas:\n" ] }, { @@ -1576,11 +1576,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### Užpildyti null reikšmes\n", + "### Užpildymas trūkstamomis reikšmėmis\n", "\n", - "Kartais yra prasminga užpildyti trūkstamas reikšmes tokiomis, kurios galėtų būti tinkamos. Yra keletas būdų, kaip užpildyti null reikšmes. Pirmasis būdas – naudoti Srities Žinias (žinias apie temą, kuria pagrįstas duomenų rinkinys), kad kažkaip apytiksliai nustatytumėte trūkstamas reikšmes.\n", + "Kartais prasminga užpildyti trūkstamas reikšmes tokiomis, kurios galėtų būti tinkamos. Yra keletas būdų, kaip užpildyti null reikšmes. Pirmasis – pasitelkti domeno žinias (žinias apie temą, kuria pagrįstas duomenų rinkinys), kad būtų galima apytiksliai nustatyti trūkstamas reikšmes.\n", "\n", - "Galite naudoti `isnull`, kad tai atliktumėte vietoje, tačiau tai gali būti varginantis procesas, ypač jei turite daug reikšmių, kurias reikia užpildyti. Kadangi tai yra labai dažna užduotis duomenų moksle, pandas siūlo `fillna`, kuris grąžina `Series` arba `DataFrame` kopiją su trūkstamomis reikšmėmis, pakeistomis jūsų pasirinktomis reikšmėmis. Sukurkime kitą `Series` pavyzdį, kad pamatytume, kaip tai veikia praktiškai.\n" + "Galite naudoti `isnull`, kad tai atliktumėte vietoje, tačiau tai gali būti varginantis procesas, ypač jei turite daug reikšmių, kurias reikia užpildyti. Kadangi tai yra labai dažna užduotis duomenų moksle, pandas siūlo `fillna`, kuris grąžina `Series` arba `DataFrame` kopiją su trūkstamomis reikšmėmis, pakeistomis jūsų pasirinktomis. Sukurkime dar vieną `Series` pavyzdį, kad pamatytume, kaip tai veikia praktiškai.\n" ] }, { @@ -1590,11 +1590,11 @@ }, "source": [ "### Kategoriniai duomenys (ne skaitiniai)\n", - "Pirmiausia aptarkime ne skaitinius duomenis. Duomenų rinkiniuose turime stulpelius su kategoriniais duomenimis. Pvz., lytis, Tiesa arba Klaidinga ir pan.\n", + "Pirmiausia apsvarstykime ne skaitinius duomenis. Duomenų rinkiniuose turime stulpelius su kategoriniais duomenimis, pvz., lytis, tiesa arba melas ir pan.\n", "\n", - "Daugeliu atvejų trūkstamas reikšmes pakeičiame stulpelio `moda`. Tarkime, turime 100 duomenų taškų, iš kurių 90 nurodė Tiesa, 8 nurodė Klaidinga, o 2 neatsakė. Tuomet tuos 2 galime užpildyti Tiesa, atsižvelgdami į visą stulpelį.\n", + "Daugeliu atvejų trūkstamas reikšmes pakeičiame stulpelio `moda`. Tarkime, turime 100 duomenų taškų, iš kurių 90 nurodė „Tiesa“, 8 nurodė „Melas“, o 2 neatsakė. Tuomet tuos 2 galime užpildyti „Tiesa“, atsižvelgdami į visą stulpelį.\n", "\n", - "Vėlgi, čia galime pasinaudoti srities žiniomis. Pažvelkime į pavyzdį, kaip užpildyti naudojant modą.\n" + "Vėlgi, čia galime pasinaudoti srities žiniomis. Pavyzdžiui, apsvarstykime užpildymą pagal modą.\n" ] }, { @@ -1699,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Dabar pirmiausia suraskime modą prieš užpildydami `None` reikšmę moda.\n" + ] }, { "cell_type": "code", @@ -1734,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Taigi, mes pakeisime None į True\n" + ] }, { "cell_type": "code", @@ -1853,15 +1857,15 @@ "id": "heYe1I0dOmQ_" }, "source": [ - "### Skaitiniai duomenys\n", - "Dabar pereikime prie skaitinių duomenų. Čia turime du įprastus būdus, kaip pakeisti trūkstamas reikšmes:\n", + "### Skaitiniai Duomenys\n", + "Dabar pereikime prie skaitinių duomenų. Čia yra du dažniausiai naudojami būdai, kaip pakeisti trūkstamas reikšmes:\n", "\n", - "1. Pakeisti eilutės medianos reikšme \n", - "2. Pakeisti eilutės vidurkiu \n", + "1. Pakeisti eilutės mediana\n", + "2. Pakeisti eilutės vidurkiu\n", "\n", - "Mediana naudojama, kai duomenys yra iškreipti ir turi išskirčių. Taip yra todėl, kad mediana yra atspari išskirtims.\n", + "Mediana naudojama, kai duomenys yra iškreipti ir turi išskirtis. Taip yra todėl, kad mediana yra atspari išskirtims.\n", "\n", - "Kai duomenys yra normalizuoti, galime naudoti vidurkį, nes tokiu atveju vidurkis ir mediana bus gana panašūs.\n", + "Kai duomenys yra normalizuoti, galima naudoti vidurkį, nes tokiu atveju vidurkis ir mediana bus gana panašūs.\n", "\n", "Pirmiausia paimkime stulpelį, kuris yra normaliai pasiskirstęs, ir užpildykime trūkstamą reikšmę stulpelio vidurkiu.\n" ] @@ -2003,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Užpildymas vidurkiu\n" + ] }, { "cell_type": "code", @@ -2112,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Dabar išbandykime kitą duomenų rėmelį, ir šį kartą pakeisime None reikšmes stulpelio mediana.\n" + "Dabar pabandykime kitą duomenų rėmelį, ir šį kartą pakeisime None reikšmes stulpelio mediana.\n" ] }, { @@ -2252,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Užpildymas medianos reikšme\n" + ] }, { "cell_type": "code", @@ -2352,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Kaip matome, NaN reikšmė buvo pakeista stulpelio mediana\n" + "Kaip matome, NaN reikšmė buvo pakeista stulpelio mediana.\n" ] }, { @@ -2435,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Pagrindinės įžvalgos: \n", - "1. Trūkstamas reikšmes reikėtų užpildyti, kai duomenų yra mažai arba kai yra strategija, kaip užpildyti trūkstamus duomenis. \n", - "2. Trūkstamas reikšmes galima užpildyti remiantis srities žiniomis, jas apytiksliai įvertinant. \n", - "3. Kategoriniams duomenims dažniausiai trūkstamos reikšmės pakeičiamos stulpelio moda. \n", - "4. Skaitiniams duomenims trūkstamos reikšmės paprastai užpildomos stulpelio vidurkiu (normalizuotų duomenų atveju) arba mediana. \n" + "> Pagrindinės mintys:\n", + "1. Trūkstamas reikšmes reikėtų užpildyti, kai duomenų yra mažai arba kai yra strategija, kaip užpildyti trūkstamus duomenis.\n", + "2. Trūkstamas reikšmes galima užpildyti naudojant srities žinias, jas apytiksliai įvertinant.\n", + "3. Kategoriniams duomenims dažniausiai trūkstamos reikšmės pakeičiamos stulpelio moda.\n", + "4. Skaitiniams duomenims trūkstamos reikšmės paprastai užpildomos stulpelio vidurkiu (normalizuotų duomenų atveju) arba mediana.\n" ] }, { @@ -2470,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "Jūs galite **užpildyti pirmyn** null reikšmes, naudodami paskutinę galiojančią reikšmę null reikšmei užpildyti:\n" + "Galite **užpildyti pirmyn** null reikšmes, naudodami paskutinę galiojančią reikšmę null reikšmei užpildyti:\n" ] }, { @@ -2511,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Jūs taip pat galite **atgal užpildyti**, kad paskleistumėte kitą galiojančią reikšmę atgal, užpildydami nulį:\n" + "Taip pat galite **užpildyti atgal**, kad paskleistumėte kitą galiojančią reikšmę atgal ir užpildytumėte null:\n" ] }, { @@ -2850,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Atkreipkite dėmesį, kad trečioje stulpelyje vis dar nėra reikšmių: numatytoji kryptis yra užpildyti reikšmes eilutėmis.\n", + "Atkreipkite dėmesį, kad 3 stulpelis vis dar neturi reikšmių: numatytoji kryptis yra užpildyti reikšmes eilutėmis.\n", "\n", - "> **Svarbiausia mintis:** Yra daugybė būdų, kaip spręsti trūkstamų reikšmių problemą jūsų duomenų rinkiniuose. Konkreti strategija, kurią pasirinksite (pašalinimas, pakeitimas ar net tai, kaip pakeisite), turėtų būti diktuojama konkrečiais duomenų ypatumais. Kuo daugiau dirbsite su duomenų rinkiniais ir juos analizuosite, tuo geriau suprasite, kaip elgtis su trūkstamomis reikšmėmis.\n" + "> **Svarbu:** Yra daugybė būdų, kaip spręsti trūkstamų reikšmių problemą jūsų duomenų rinkiniuose. Konkreti strategija (jų pašalinimas, pakeitimas ar net tai, kaip juos pakeisite) turėtų būti nustatoma pagal konkrečius duomenų ypatumus. Kuo daugiau dirbsite su duomenų rinkiniais, tuo geriau suprasite, kaip tvarkyti trūkstamas reikšmes.\n" ] }, { @@ -2863,7 +2871,7 @@ "source": [ "### Kategorinių duomenų kodavimas\n", "\n", - "Mašininio mokymosi modeliai dirba tik su skaičiais ir bet kokia skaitine informacija. Jie negali atskirti „Taip“ nuo „Ne“, tačiau gali atskirti 0 nuo 1. Todėl, užpildžius trūkstamas reikšmes, turime koduoti kategorinius duomenis į tam tikrą skaitinę formą, kad modelis juos suprastų.\n", + "Mašininio mokymosi modeliai dirba tik su skaičiais ir bet kokia skaitine informacija. Jie negalės atskirti „Taip“ nuo „Ne“, tačiau galės atskirti 0 nuo 1. Todėl, užpildžius trūkstamas reikšmes, reikia koduoti kategorinius duomenis į tam tikrą skaitinę formą, kad modelis juos suprastų.\n", "\n", "Kodavimą galima atlikti dviem būdais. Toliau aptarsime juos.\n" ] @@ -2874,9 +2882,9 @@ "id": "uDq9SxB7mu5i" }, "source": [ - "**ŽYMĖS KODAVIMAS**\n", + "**ETIKEČIŲ KODAVIMAS**\n", "\n", - "Žymės kodavimas iš esmės reiškia kiekvienos kategorijos pavertimą skaičiumi. Pavyzdžiui, tarkime, turime oro linijų keleivių duomenų rinkinį, kuriame yra stulpelis su jų klase iš šių variantų: ['verslo klasė', 'ekonominė klasė', 'pirmoji klasė']. Jei būtų atliktas žymės kodavimas, tai būtų paversta į [0,1,2]. Pažiūrėkime pavyzdį per kodą. Kadangi artimiausiuose užrašuose mokysimės naudoti `scikit-learn`, čia jo nenaudosime.\n" + "Etikečių kodavimas iš esmės reiškia kiekvienos kategorijos pavertimą skaičiumi. Pavyzdžiui, tarkime, turime oro linijų keleivių duomenų rinkinį, kuriame yra stulpelis, nurodantis jų klasę iš šių ['verslo klasė', 'ekonominė klasė', 'pirma klasė']. Jei būtų atliktas etikečių kodavimas, tai būtų paversta į [0,1,2]. Pažiūrėkime pavyzdį per kodą. Kadangi artimiausiuose užrašuose mokysimės apie `scikit-learn`, čia jo nenaudosime.\n" ] }, { @@ -2984,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Norėdami atlikti etikečių kodavimą pirmoje stulpelyje, pirmiausia turime aprašyti kiekvienos klasės susiejimą su skaičiumi, prieš pakeičiant.\n" + "Norėdami atlikti etikečių kodavimą pirmoje stulpelyje, pirmiausia turime aprašyti kiekvienos klasės atvaizdavimą į skaičių, prieš pakeičiant.\n" ] }, { @@ -3097,11 +3105,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**VIENKARTINIS KODAVIMAS**\n", + "**VIENOS KARŠTOS KODAVIMAS**\n", "\n", - "Kitas kodavimo tipas yra vienkartinis kodavimas (One Hot Encoding). Šio tipo kodavime kiekviena stulpelio kategorija pridedama kaip atskiras stulpelis, o kiekvienam duomenų taškui priskiriama 0 arba 1, priklausomai nuo to, ar jis priklauso tai kategorijai. Taigi, jei yra n skirtingų kategorijų, prie duomenų rėmelio bus pridėti n stulpeliai.\n", + "Kitas kodavimo tipas yra Vienos Karštos Kodavimas (One Hot Encoding). Šio tipo kodavime kiekviena stulpelio kategorija pridedama kaip atskiras stulpelis, o kiekvienas duomenų taškas gauna 0 arba 1, priklausomai nuo to, ar jis atitinka tą kategoriją. Taigi, jei yra n skirtingų kategorijų, į duomenų rinkinį bus pridėti n stulpeliai.\n", "\n", - "Pavyzdžiui, paimkime tą patį lėktuvo klasių pavyzdį. Kategorijos buvo: ['verslo klasė', 'ekonominė klasė', 'pirmoji klasė']. Taigi, jei atliksime vienkartinį kodavimą, į duomenų rinkinį bus pridėti šie trys stulpeliai: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Pavyzdžiui, paimkime tą patį lėktuvo klasių pavyzdį. Kategorijos buvo: ['verslo klasė', 'ekonominė klasė', 'pirma klasė']. Taigi, jei atliksime vienos karštos kodavimą, į duomenų rinkinį bus pridėti šie trys stulpeliai: ['class_verslo klasė', 'class_ekonominė klasė', 'class_pirma klasė'].\n" ] }, { @@ -3355,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Pagrindinės mintys: \n", - "1. Kodavimas atliekamas siekiant konvertuoti ne skaitinius duomenis į skaitinius. \n", - "2. Yra du kodavimo tipai: žymų kodavimas ir vieno karštojo kodavimas, abu gali būti atliekami atsižvelgiant į duomenų rinkinio poreikius. \n" + "> Pagrindinės mintys:\n", + "1. Kodavimas atliekamas siekiant konvertuoti ne skaitinius duomenis į skaitinius.\n", + "2. Yra du kodavimo tipai: žymų kodavimas ir vieno karšto kodavimas, kurie gali būti atliekami atsižvelgiant į duomenų rinkinio poreikius.\n" ] }, { @@ -3366,9 +3374,9 @@ "id": "K8UXOJYRgRsJ" }, "source": [ - "## Pašalinimas pasikartojančių duomenų\n", + "## Duomenų dubliavimo pašalinimas\n", "\n", - "> **Mokymosi tikslas:** Šio poskyrio pabaigoje turėtumėte jaustis užtikrintai atpažindami ir pašalindami pasikartojančias reikšmes iš DataFrame lentelių.\n", + "> **Mokymosi tikslas:** Šio poskyrio pabaigoje turėtumėte jaustis užtikrintai identifikuodami ir pašalindami pasikartojančias reikšmes iš DataFrame.\n", "\n", "Be trūkstamų duomenų, realiuose duomenų rinkiniuose dažnai susidursite su pasikartojančiais duomenimis. Laimei, pandas suteikia paprastą būdą aptikti ir pašalinti pasikartojančius įrašus.\n" ] @@ -3379,9 +3387,9 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### Identifikavimas pasikartojančių reikšmių: `duplicated`\n", + "### Dubliu atpažinimas: `duplicated`\n", "\n", - "Pasikartojančias reikšmes galite lengvai nustatyti naudodami pandas metodą `duplicated`, kuris grąžina Boole'o kaukę, nurodančią, ar įrašas `DataFrame` yra ankstesnio įrašo dublikatas. Sukurkime dar vieną pavyzdinį `DataFrame`, kad pamatytume, kaip tai veikia.\n" + "Naudodami pandas metodą `duplicated`, galite lengvai nustatyti pasikartojančias reikšmes. Šis metodas grąžina Boole'o kaukę, nurodančią, ar įrašas `DataFrame` yra ankstesnio įrašo dublikatas. Sukurkime dar vieną pavyzdinį `DataFrame`, kad pamatytume, kaip tai veikia.\n" ] }, { @@ -3670,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Svarbiausia:** Pašalinti pasikartojančius duomenis yra būtina beveik kiekvieno duomenų mokslo projekto dalis. Pasikartojantys duomenys gali pakeisti jūsų analizės rezultatus ir pateikti netikslius rezultatus!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tikrinimas duomenų kokybės realiame pasaulyje\n", + "\n", + "> **Mokymosi tikslas:** Šio skyriaus pabaigoje turėtumėte jaustis užtikrintai aptikdami ir taisydami dažniausiai pasitaikančias duomenų kokybės problemas, tokias kaip nenuoseklūs kategoriniai reikšmės, nenormalios skaitinės reikšmės (išskirtiniai atvejai) ir pasikartojančios esybės su variacijomis.\n", + "\n", + "Nors trūkstamos reikšmės ir tikslūs dublikatai yra dažnos problemos, realaus pasaulio duomenų rinkiniuose dažnai pasitaiko subtilesnių problemų:\n", + "\n", + "1. **Nenuoseklūs kategoriniai reikšmės**: Ta pati kategorija užrašyta skirtingai (pvz., \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Nenormalios skaitinės reikšmės**: Ekstremalūs išskirtiniai atvejai, rodantys klaidas duomenų įvedime (pvz., amžius = 999)\n", + "3. **Beveik pasikartojančios eilutės**: Įrašai, kurie atspindi tą pačią esybę su nedideliais skirtumais\n", + "\n", + "Pažvelkime į metodus, kaip aptikti ir spręsti šias problemas.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Sukurkime pavyzdinį „nešvarų“ duomenų rinkinį\n", + "\n", + "Pirmiausia sukurkime pavyzdinį duomenų rinkinį, kuriame būtų problemų, su kuriomis dažnai susiduriame realiuose duomenyse:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Nenuoseklių kategorinių reikšmių aptikimas\n", + "\n", + "Atkreipkite dėmesį, kad `country` stulpelyje yra kelios to paties šalies reprezentacijos. Išsiaiškinkime šiuos neatitikimus:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Kategorinių reikšmių standartizavimas\n", + "\n", + "Galime sukurti žemėlapį, kad standartizuotume šias reikšmes. Paprastas būdas yra konvertuoti į mažąsias raides ir sukurti žemėlapio žodyną:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternatyva: Naudojant neaiškų atitikimą**\n", + "\n", + "Sudėtingesniais atvejais galime naudoti neaiškų teksto atitikimą su `rapidfuzz` biblioteka, kad automatiškai aptiktume panašius tekstus:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Aptikti neįprastas skaitines reikšmes (išskirtis)\n", + "\n", + "Žvelgiant į `age` stulpelį, pastebime keletą įtartinų reikšmių, tokių kaip 199 ir -5. Pasitelkime statistinius metodus, kad aptiktume šias išskirtis.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Naudojant IQR (Tarpkvartilinis diapazonas) metodą\n", + "\n", + "IQR metodas yra patikimas statistinis būdas aptikti išskirtines reikšmes, kuris yra mažiau jautrus ekstremalioms reikšmėms:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Naudojant Z-reitingo metodą\n", + "\n", + "Z-reitingo metodas nustato išskirtis pagal standartinius nuokrypius nuo vidurkio:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Darbas su išskirtimis\n", + "\n", + "Aptikus išskirtis, jas galima tvarkyti keliais būdais:\n", + "1. **Pašalinti**: Ištrinti eilutes su išskirtimis (jei tai klaidos)\n", + "2. **Apriboti**: Pakeisti ribinėmis reikšmėmis\n", + "3. **Pakeisti į NaN**: Traktuoti kaip trūkstamus duomenis ir taikyti imputacijos metodus\n", + "4. **Palikti**: Jei tai teisėtos ekstremalios reikšmės\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Aptikti beveik pasikartojančias eilutes\n", + "\n", + "Pastebėkite, kad mūsų duomenų rinkinyje yra kelios „John Smith“ įrašų versijos su šiek tiek skirtingomis reikšmėmis. Pabandykime nustatyti galimus pasikartojimus pagal vardų panašumą.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Artimų dublikatų paieška naudojant neaiškų atitikimą\n", + "\n", + "Norint atlikti sudėtingesnį dublikatų aptikimą, galime naudoti neaiškų atitikimą, kad rastume panašius vardus:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Tvarkymas su pasikartojančiais duomenimis\n", + "\n", + "Kai pasikartojimai yra nustatyti, reikia nuspręsti, kaip juos tvarkyti:\n", + "1. **Palikti pirmą pasikartojimą**: Naudokite `drop_duplicates(keep='first')`\n", + "2. **Palikti paskutinį pasikartojimą**: Naudokite `drop_duplicates(keep='last')`\n", + "3. **Apjungti informaciją**: Sujungti informaciją iš pasikartojančių eilučių\n", + "4. **Rankinis peržiūrėjimas**: Pažymėti peržiūrai žmogui\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Santrauka: Pilnas duomenų valymo procesas\n", + "\n", + "Sujunkime viską į išsamų valymo procesą:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Iššūkio užduotis\n", + "\n", + "Dabar tavo eilė! Žemiau pateikta nauja duomenų eilutė su daugybe kokybės problemų. Ar gali:\n", + "\n", + "1. Nustatyti visas problemas šioje eilutėje\n", + "2. Parašyti kodą, kuris išsprendžia kiekvieną problemą\n", + "3. Pridėti išvalytą eilutę prie duomenų rinkinio\n", + "\n", + "Štai probleminiai duomenys:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Pagrindinės įžvalgos\n", + "\n", + "1. **Nesuderintos kategorijos** yra dažnas reiškinys realiuose duomenyse. Visada patikrinkite unikalius reikšmių sąrašus ir standartizuokite jas naudodami žemėlapius arba neaiškų atitikimą.\n", + "\n", + "2. **Išskirtinės reikšmės** gali stipriai paveikti jūsų analizę. Naudokite srities žinias kartu su statistiniais metodais (IQR, Z-score), kad jas aptiktumėte.\n", + "\n", + "3. **Beveik pasikartojančias reikšmes** sunkiau aptikti nei tikslius pasikartojimus. Apsvarstykite galimybę naudoti neaiškų atitikimą ir normalizuoti duomenis (mažosios raidės, tarpų pašalinimas), kad jas identifikuotumėte.\n", + "\n", + "4. **Duomenų valymas yra iteratyvus procesas**. Gali tekti taikyti kelis metodus ir peržiūrėti rezultatus prieš galutinai išvalant duomenų rinkinį.\n", + "\n", + "5. **Dokumentuokite savo sprendimus**. Sekite, kokius valymo veiksmus taikėte ir kodėl, nes tai svarbu atkuriamumui ir skaidrumui.\n", + "\n", + "> **Geriausia praktika:** Visada išsaugokite originalius „nešvarius“ duomenis. Niekada neperrašykite pirminių duomenų failų – sukurkite išvalytas versijas su aiškiais pavadinimais, pvz., `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Atsakomybės apribojimas**: \nŠis dokumentas buvo išverstas naudojant AI vertimo paslaugą [Co-op Translator](https://github.com/Azure/co-op-translator). Nors siekiame tikslumo, prašome atkreipti dėmesį, kad automatiniai vertimai gali turėti klaidų ar netikslumų. Originalus dokumentas jo gimtąja kalba turėtų būti laikomas autoritetingu šaltiniu. Kritinei informacijai rekomenduojama profesionali žmogaus vertimo paslauga. Mes neprisiimame atsakomybės už nesusipratimus ar klaidingus interpretavimus, atsiradusius naudojant šį vertimą.\n" + "\n---\n\n**Atsakomybės apribojimas**: \nŠis dokumentas buvo išverstas naudojant AI vertimo paslaugą [Co-op Translator](https://github.com/Azure/co-op-translator). Nors stengiamės užtikrinti tikslumą, prašome atkreipti dėmesį, kad automatiniai vertimai gali turėti klaidų ar netikslumų. Originalus dokumentas jo gimtąja kalba turėtų būti laikomas autoritetingu šaltiniu. Kritinei informacijai rekomenduojama naudoti profesionalų žmogaus vertimą. Mes neprisiimame atsakomybės už nesusipratimus ar neteisingą interpretaciją, atsiradusią dėl šio vertimo naudojimo.\n" ] } ], @@ -3704,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T22:11:11+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T21:27:21+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "lt" } diff --git a/translations/mo/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/mo/2-Working-With-Data/08-data-preparation/notebook.ipynb index e347224e..3a8c1517 100644 --- a/translations/mo/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/mo/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -6,17 +6,17 @@ "id": "rQ8UhzFpgRra" }, "source": [ - "# 數據準備\n", + "# 資料準備\n", "\n", - "[原始筆記本來源:*數據科學:Python 和機器學習工作室的數據科學機器學習入門,作者 Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[原始筆記本來源:*Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## 探索 `DataFrame` 資訊\n", "\n", - "> **學習目標:** 在完成本小節後,您應該能夠熟練地查找 pandas DataFrame 中存儲的數據的一般資訊。\n", + "> **學習目標:** 完成本小節後,您應該能夠熟練地找到存儲在 pandas DataFrame 中的資料的一般資訊。\n", "\n", - "當您將數據加載到 pandas 中後,數據很可能會以 `DataFrame` 的形式存在。然而,如果您的 `DataFrame` 中的數據集有 60,000 行和 400 列,您該如何開始了解自己正在處理的內容呢?幸運的是,pandas 提供了一些方便的工具,可以快速查看 `DataFrame` 的整體資訊,以及前幾行和後幾行的內容。\n", + "當您將資料載入 pandas 後,資料通常會以 `DataFrame` 的形式存在。然而,如果您的 `DataFrame` 中的資料集有 60,000 行和 400 列,您該如何開始了解自己正在處理的內容呢?幸運的是,pandas 提供了一些方便的工具,可以快速查看 `DataFrame` 的整體資訊,以及前幾行和後幾行的內容。\n", "\n", - "為了探索這些功能,我們將導入 Python 的 scikit-learn 庫,並使用一個每位數據科學家都見過數百次的經典數據集:英國生物學家 Ronald Fisher 在他 1936 年的論文《多重測量在分類學問題中的應用》中使用的 *Iris* 數據集:\n" + "為了探索這些功能,我們將匯入 Python 的 scikit-learn 庫,並使用一個每位資料科學家都看過數百次的經典資料集:英國生物學家 Ronald Fisher 在他1936年的論文《多重測量在分類問題中的應用》中使用的 *Iris* 資料集:\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "我們已將 Iris 數據集載入到變數 `iris_df` 中。在深入分析數據之前,了解我們擁有的數據點數量以及整個數據集的大小是很有價值的。檢視我們正在處理的數據量是很有幫助的。\n" + "我們已將鳶尾花數據集載入到變數 `iris_df` 中。在深入分析數據之前,了解我們擁有的數據點數量以及整個數據集的大小是很有價值的。查看我們正在處理的數據量是很有幫助的。\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "所以,我們正在處理150行和4列的數據。每一行代表一個數據點,每一列代表與數據框相關的一個特徵。基本上,這裡有150個數據點,每個數據點包含4個特徵。\n", + "我們正在處理150行4列的數據。每一行代表一個數據點,每一列代表與數據框相關的一個特徵。基本上,這裡有150個數據點,每個數據點包含4個特徵。\n", "\n", - "`shape` 在這裡是數據框的一個屬性,而不是一個函數,這就是為什麼它的結尾沒有一對括號。\n" + "`shape`在這裡是數據框的一個屬性,而不是一個函數,所以它的後面沒有一對括號。\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "現在讓我們來看看這四個數據欄位。每個欄位究竟代表什麼?`columns` 屬性會提供我們數據框中欄位的名稱。\n" + "現在讓我們來看看這個數據的四個欄位。每個欄位究竟代表什麼?`columns` 屬性會提供我們數據框中欄位的名稱。\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "如我們所見,有四(4)列。`columns`屬性告訴我們列的名稱,基本上沒有其他內容。當我們想要識別數據集包含的特徵時,這個屬性就顯得重要。\n" + "如我們所見,有四(4)列。`columns`屬性告訴我們列的名稱,基本上沒有其他內容。當我們想要識別數據集包含的特徵時,這個屬性就顯得重要了。\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "透過 `shape` 屬性提供的數據量,以及透過 `columns` 屬性提供的特徵或欄位名稱,可以讓我們對數據集有初步的了解。現在,我們希望更深入地探索這個數據集。`DataFrame.info()` 函數在這方面非常有用。\n" + "透過 `shape` 屬性提供的數據量以及透過 `columns` 屬性提供的特徵或欄位名稱,可以讓我們對數據集有一些初步了解。現在,我們希望更深入地探索數據集。`DataFrame.info()` 函數在這方面非常有用。\n" ] }, { @@ -180,7 +180,7 @@ "id": "1XgVMpvigRru" }, "source": [ - "從這裡,我們可以做出一些觀察:\n", + "從這裡,我們可以做出以下幾點觀察:\n", "1. 每個欄位的資料類型:在這個資料集中,所有的資料都以64位元浮點數形式儲存。\n", "2. 非空值的數量:處理空值是資料準備中的重要步驟,稍後會在筆記本中進行處理。\n" ] @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "假設我們的數據集中有許多數值型資料。像平均值、中位數、四分位數等單變量統計計算可以針對每個欄位單獨進行。`DataFrame.describe()` 函數為我們提供了數據集中數值欄位的統計摘要。\n" + "假設我們的資料集中有大量的數值資料。像平均值、中位數、四分位數等單變量統計計算可以針對每個欄位單獨進行。`DataFrame.describe()` 函數可以為我們提供資料集中數值欄位的統計摘要。\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "上述輸出顯示了每列的數據點總數、平均值、標準差、最小值、下四分位數(25%)、中位數(50%)、上四分位數(75%)和最大值。\n" + "上面的輸出顯示了每列的數據點總數、平均值、標準差、最小值、下四分位數(25%)、中位數(50%)、上四分位數(75%)和最大值。\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "透過以上所有的函數和屬性,我們已經對數據集有了一個高層次的概覽。我們知道數據集中有多少數據點,有多少特徵,每個特徵的數據類型,以及每個特徵中非空值的數量。\n", + "透過上述所有函數和屬性,我們已經對數據集有了一個高層次的概覽。我們知道有多少數據點、多少特徵、每個特徵的數據類型,以及每個特徵的非空值數量。\n", "\n", - "現在是時候來看看數據本身了。讓我們來看看我們的 `DataFrame` 的前幾行(前幾個數據點)是什麼樣子的:\n" + "現在是時候查看數據本身了。讓我們看看我們的 `DataFrame` 的前幾行(前幾個數據點)是什麼樣子:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "作為輸出,我們可以看到數據集的五(5)個條目。如果我們查看左側的索引,我們會發現這是前五行。\n" + "在此輸出中,我們可以看到數據集的五(5)個條目。如果查看左側的索引,我們會發現這是前五行。\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### 練習:\n", "\n", - "從上述範例可以看出,預設情況下,`DataFrame.head` 會返回 `DataFrame` 的前五行。在下面的程式碼區塊中,你能找到一種方法來顯示超過五行的內容嗎?\n" + "從上面的例子可以看出,預設情況下,`DataFrame.head` 會返回 `DataFrame` 的前五行。在下面的程式碼單元中,你能找到一種方法來顯示超過五行嗎?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "另一種查看數據的方法是從結尾開始(而不是從開頭)。`DataFrame.head` 的相反方法是 `DataFrame.tail`,它會返回 `DataFrame` 的最後五行:\n" + "另一種查看數據的方式是從結尾開始(而不是從開頭)。`DataFrame.head` 的反面是 `DataFrame.tail`,它會返回 `DataFrame` 的最後五行:\n" ] }, { @@ -584,9 +584,9 @@ "source": [ "在實際操作中,能夠輕鬆檢視 `DataFrame` 的前幾行或後幾行非常有用,特別是在檢查有序數據集中的異常值時。\n", "\n", - "上面透過程式碼範例展示的所有函數和屬性,幫助我們快速了解數據的外觀和感覺。\n", + "上述透過程式碼範例展示的所有函數和屬性,都能幫助我們快速了解數據的外觀和特性。\n", "\n", - "> **重點提示:** 即使僅僅透過查看 `DataFrame` 中的元數據或前幾個和後幾個值,也能立即對您正在處理的數據的大小、形狀和內容有一個初步的概念。\n" + "> **重點提示:** 僅僅透過查看 `DataFrame` 中的元數據或前幾個及後幾個值,就能立即對數據的大小、形狀以及內容有一個初步的概念。\n" ] }, { @@ -598,15 +598,15 @@ "### 缺失資料\n", "讓我們深入探討缺失資料。缺失資料是指某些欄位中沒有儲存任何值。\n", "\n", - "舉個例子:假設某人對自己的體重很在意,因此在問卷中沒有填寫體重欄位。那麼,這個人的體重值就會是缺失的。\n", + "舉個例子:假設某人對自己的體重非常在意,因此在調查中不填寫體重欄位。那麼,該人的體重值就會是缺失的。\n", "\n", - "在現實世界的數據集中,缺失值是非常常見的。\n", + "在現實世界的資料集中,缺失值是非常常見的。\n", "\n", "**Pandas 如何處理缺失資料**\n", "\n", - "Pandas 有兩種方式來處理缺失值。第一種方式你可能在之前的章節中已經見過:`NaN`,即「非數值」(Not a Number)。這其實是一個特殊的值,屬於 IEEE 浮點數規範的一部分,專門用來表示缺失的浮點數值。\n", + "Pandas 以兩種方式處理缺失值。第一種方式是你在之前的章節中已經見過的:`NaN`,即「非數值」(Not a Number)。這其實是一個特殊的值,是 IEEE 浮點規範的一部分,僅用於表示缺失的浮點值。\n", "\n", - "對於非浮點數的缺失值,Pandas 使用 Python 的 `None` 物件。雖然遇到兩種不同的值來表示相同的概念可能會讓人感到困惑,但這種設計選擇有其合理的程式邏輯原因。在實際應用中,這樣的設計能夠在絕大多數情況下提供良好的平衡。不過,無論是 `None` 還是 `NaN`,它們都帶有一些限制,必須注意它們在使用上的差異。\n" + "對於非浮點型的缺失值,Pandas 使用 Python 的 `None` 物件。雖然遇到兩種不同的值來表示相同的概念可能會讓人感到困惑,但這種設計選擇有其合理的程式設計原因。實際上,這樣的方式使得 Pandas 能夠在絕大多數情況下提供良好的平衡。不過,無論是 `None` 還是 `NaN`,它們都帶有一些限制,必須注意它們在使用上的差異。\n" ] }, { @@ -615,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: 非浮點型缺失資料\n", - "由於 `None` 來自 Python,它無法用於非 `'object'` 資料類型的 NumPy 和 pandas 陣列。請記住,NumPy 陣列(以及 pandas 中的資料結構)只能包含一種資料類型。這正是它們在大規模資料和計算工作中展現強大效能的原因,但同時也限制了它們的靈活性。這類陣列必須提升為「最低共同分母」,即能包含陣列中所有內容的資料類型。當陣列中包含 `None` 時,表示您正在處理 Python 物件。\n", + "### `None`:非浮點型缺失數據\n", + "由於 `None` 來自 Python,它無法用於數據類型非 `'object'` 的 NumPy 和 pandas 陣列。請記住,NumPy 陣列(以及 pandas 中的數據結構)只能包含一種類型的數據。這正是它們在大規模數據和計算工作中展現強大能力的原因,但也限制了它們的靈活性。這類陣列必須提升為“最低共同分母”,即能包含陣列中所有內容的數據類型。當陣列中包含 `None` 時,意味著您正在處理 Python 對象。\n", "\n", - "以下範例陣列可以幫助您理解這一點(注意它的 `dtype`):\n" + "以下示例陣列可以幫助您理解這一點(注意它的 `dtype`):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "上升數據類型的現實情況帶來了兩個副作用。首先,操作將在解釋執行的 Python 代碼層面進行,而不是在編譯執行的 NumPy 代碼層面進行。基本上,這意味著任何涉及包含 `None` 的 `Series` 或 `DataFrame` 的操作都會變得較慢。雖然你可能不會注意到這種性能下降,但對於大型數據集來說,這可能會成為一個問題。\n", + "上升型資料類型的現實情況帶來了兩個副作用。首先,操作將在解釋型 Python 代碼層面執行,而不是編譯型 NumPy 代碼層面。基本上,這意味著任何涉及包含 `None` 的 `Series` 或 `DataFrame` 的操作都會變得較慢。雖然你可能不會注意到這種性能影響,但對於大型數據集來說,這可能會成為一個問題。\n", "\n", - "第二個副作用源於第一個副作用。由於 `None` 本質上將 `Series` 或 `DataFrame` 拉回到原生 Python 的世界中,因此對包含 `None` 值的數組使用 NumPy/pandas 的聚合函數(例如 `sum()` 或 `min()`)通常會產生錯誤:\n" + "第二個副作用源於第一個副作用。由於 `None` 本質上將 `Series` 或 `DataFrame` 拉回到原生 Python 的世界,因此在包含 ``None`` 值的陣列上使用像 `sum()` 或 `min()` 這樣的 NumPy/pandas 聚合函數通常會產生錯誤:\n" ] }, { @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**關鍵要點**:整數與 `None` 值之間的加法(以及其他操作)是未定義的,這可能會限制您對包含這些值的數據集所能執行的操作。\n" + ] }, { "cell_type": "markdown", @@ -707,7 +709,7 @@ "source": [ "### `NaN`:缺失的浮點值\n", "\n", - "與 `None` 不同,NumPy(因此也包括 pandas)支援 `NaN`,以便進行快速的向量化操作和通用函數(ufuncs)。壞消息是,任何對 `NaN` 進行的算術運算結果都會是 `NaN`。例如:\n" + "與 `None` 不同,NumPy(因此也包括 pandas)支援 `NaN`,以進行快速的向量化操作和 ufuncs。壞消息是,任何對 `NaN` 進行的算術運算都會產生 `NaN`。例如:\n" ] }, { @@ -770,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "好消息:在包含 `NaN` 的數組上運行的聚合不會出現錯誤。壞消息:結果並非一律有用:\n" + "好消息:在包含 `NaN` 的數組上運行的聚合不會出現錯誤。壞消息:結果並不總是有用:\n" ] }, { @@ -806,7 +808,9 @@ "metadata": { "id": "nhlnNJT7gRr_" }, - "source": [] + "source": [ + "### 運動:\n" + ] }, { "cell_type": "code", @@ -826,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "記住:`NaN` 只是用於表示缺失的浮點值;整數、字符串或布爾值沒有 `NaN` 的對應。\n" + ] }, { "cell_type": "markdown", @@ -836,7 +842,7 @@ "source": [ "### `NaN` 和 `None`:pandas 中的空值\n", "\n", - "儘管 `NaN` 和 `None` 的行為可能略有不同,但 pandas 仍然設計成可以互換處理它們。為了說明這一點,請考慮一個整數的 `Series`:\n" + "儘管 `NaN` 和 `None` 的行為可能略有不同,但 pandas 仍然設計成可以互換處理它們。為了更清楚地了解這一點,請看以下一個整數的 `Series`:\n" ] }, { @@ -875,7 +881,9 @@ "metadata": { "id": "WklCzqb8gRsB" }, - "source": [] + "source": [ + "### 運動:\n" + ] }, { "cell_type": "code", @@ -898,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "在將資料類型向上轉型以建立 `Series` 和 `DataFrame` 的資料一致性時,pandas 會自動在 `None` 和 `NaN` 之間切換缺失值。由於這種設計特性,將 `None` 和 `NaN` 視為 pandas 中兩種不同形式的「空值」是很有幫助的。事實上,pandas 中一些處理缺失值的核心方法名稱就反映了這一點:\n", + "在將資料型別向上轉型以建立 `Series` 和 `DataFrame` 的資料一致性過程中,pandas 會自動在 `None` 和 `NaN` 之間切換缺失值。由於這種設計特性,將 `None` 和 `NaN` 視為 pandas 中兩種不同形式的「空值」是很有幫助的。事實上,pandas 中一些處理缺失值的核心方法名稱也反映了這個概念:\n", "\n", - "- `isnull()`: 生成一個布林遮罩,指示缺失值的位置\n", - "- `notnull()`: 與 `isnull()` 相反\n", - "- `dropna()`: 返回一個過濾後的資料版本\n", - "- `fillna()`: 返回一個填補或推補缺失值後的資料副本\n", + "- `isnull()`:生成一個布林遮罩以指示缺失值\n", + "- `notnull()`:與 `isnull()` 相反\n", + "- `dropna()`:返回過濾後的資料版本\n", + "- `fillna()`:返回填充或推算缺失值後的資料副本\n", "\n", - "這些方法非常重要,值得熟練掌握。因此,接下來我們將深入探討每一個方法。\n" + "這些方法非常重要,熟練掌握它們是必要的,因此我們將深入探討每一個方法。\n" ] }, { @@ -914,10 +922,10 @@ "id": "Yh5ifd9FgRsB" }, "source": [ - "### 偵測空值\n", + "### 檢測空值\n", "\n", - "現在我們已經了解缺失值的重要性,在處理它們之前,我們需要在資料集中偵測它們。\n", - "`isnull()` 和 `notnull()` 是偵測空值的主要方法。這兩個方法都會在資料上返回布林遮罩。\n" + "既然我們已經了解了缺失值的重要性,在處理它們之前,我們需要在數據集中檢測它們。\n", + "`isnull()` 和 `notnull()` 是檢測空值的主要方法。這兩個方法都會返回布林遮罩,覆蓋你的數據。\n" ] }, { @@ -970,9 +978,9 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "仔細看看輸出結果,有沒有什麼讓你感到驚訝的地方?雖然 `0` 是一個算術上的「空值」,但它仍然是一個完全有效的整數,pandas 也將其視為如此。而 `''` 則稍微微妙一些。雖然我們在第 1 節中使用它來表示空字串值,但對 pandas 而言,它仍然是一個字串物件,而不是空值的表示。\n", + "仔細看看輸出的結果,有沒有讓你感到驚訝的地方?雖然 `0` 是算術上的空值,但它仍然是一個完全有效的整數,pandas 也將其視為如此。而 `''` 則稍微微妙一些。雖然我們在第 1 節中使用它來表示空字串值,但它仍然是一個字串物件,並非 pandas 所認為的空值表示。\n", "\n", - "現在,讓我們換個角度,將這些方法以更接近實際使用的方式來應用。你可以直接將布林遮罩作為 ``Series`` 或 ``DataFrame`` 的索引,這在處理孤立的缺失值(或存在值)時非常有用。\n", + "現在,讓我們換個角度,使用這些方法更接近實際應用的方式。你可以直接使用布林遮罩作為 ``Series`` 或 ``DataFrame`` 的索引,這在處理孤立的缺失值(或存在值)時非常有用。\n", "\n", "如果我們想要計算缺失值的總數,只需對 `isnull()` 方法生成的遮罩進行一次加總即可。\n" ] @@ -1008,7 +1016,9 @@ "metadata": { "id": "PlBqEo3mgRsC" }, - "source": [] + "source": [ + "### 運動:\n" + ] }, { "cell_type": "code", @@ -1030,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**關鍵要點**:當您在 DataFrame 中使用 `isnull()` 和 `notnull()` 方法時,兩者會產生類似的結果:它們顯示結果及其索引,這將在您處理數據時對您有極大的幫助。\n" + "**主要收穫**:當您在資料框中使用 `isnull()` 和 `notnull()` 方法時,兩者會產生類似的結果:它們顯示結果以及這些結果的索引,這將在您處理數據時提供極大的幫助。\n" ] }, { @@ -1039,15 +1049,15 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### 處理遺漏數據\n", + "### 處理遺漏資料\n", "\n", "> **學習目標:** 在本小節結束時,您應該了解如何以及何時替換或移除 DataFrame 中的空值。\n", "\n", - "機器學習模型無法直接處理遺漏數據。因此,在將數據傳入模型之前,我們需要先處理這些遺漏值。\n", + "機器學習模型無法直接處理遺漏資料。因此,在將資料傳入模型之前,我們需要先處理這些遺漏值。\n", "\n", - "如何處理遺漏數據涉及微妙的取捨,可能會影響您的最終分析結果以及實際應用的效果。\n", + "如何處理遺漏資料涉及微妙的取捨,可能會影響您的最終分析結果以及實際應用的效果。\n", "\n", - "主要有兩種處理遺漏數據的方法:\n", + "主要有兩種處理遺漏資料的方法:\n", "\n", "1. 移除包含遺漏值的行\n", "2. 用其他值替換遺漏值\n", @@ -1061,13 +1071,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### 刪除空值\n", + "### 移除空值\n", "\n", - "我們傳遞給模型的數據量會直接影響其性能。刪除空值意味著我們減少了數據點的數量,從而縮小了數據集的規模。因此,當數據集相當大時,建議刪除包含空值的行。\n", + "我們傳遞給模型的數據量會直接影響其性能。移除空值意味著減少數據點的數量,因此也減少了數據集的大小。因此,當數據集相當大時,建議移除包含空值的行。\n", "\n", - "另一種情況可能是某一行或列有大量缺失值。在這種情況下,這些行或列可能會被刪除,因為它們對我們的分析幾乎沒有幫助,因為該行/列的大部分數據都是缺失的。\n", + "另一種情況可能是某一行或列有大量缺失值。在這種情況下,可以考慮移除它們,因為該行/列的大部分數據都缺失,對分析的價值不大。\n", "\n", - "除了識別缺失值之外,pandas 還提供了一種方便的方法來從 `Series` 和 `DataFrame` 中移除空值。為了實際了解這一點,我們可以回到 `example3`。`DataFrame.dropna()` 函數可以幫助刪除包含空值的行。\n" + "除了識別缺失值之外,pandas 還提供了一種方便的方法來從 `Series` 和 `DataFrame` 中移除空值。為了更直觀地了解這一點,我們可以回到 `example3`。`DataFrame.dropna()` 函數可以幫助移除包含空值的行。\n" ] }, { @@ -1106,7 +1116,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "請注意,這應該看起來像是您從 `example3[example3.notnull()]` 的輸出。這裡的不同之處在於,`dropna` 並非僅僅基於遮罩值進行索引,而是從 `Series` 的 `example3` 中移除了那些缺失值。\n", + "請注意,這應該看起來像您從 `example3[example3.notnull()]` 的輸出。這裡的不同之處在於,`dropna` 不僅僅是基於遮罩值進行索引,而是已經從 `Series` `example3` 中移除了那些缺失值。\n", "\n", "由於 DataFrame 是二維的,因此在刪除數據時提供了更多選擇。\n" ] @@ -1198,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(你是否注意到 pandas 將其中兩列提升為浮點型,以容納 `NaN`?)\n", + "(你是否注意到 pandas 將其中兩列提升為浮點型,以容納 `NaN` 值?)\n", "\n", - "你無法從 `DataFrame` 中刪除單一值,因此你必須刪除整行或整列。根據你的需求,你可能會選擇其中一種方式,因此 pandas 提供了兩種選項。由於在數據科學中,列通常代表變數,行則代表觀測值,因此你更可能刪除數據的行;`dropna()` 的預設設定是刪除所有包含任何空值的行:\n" + "你無法從 `DataFrame` 中刪除單個值,因此必須刪除整行或整列。根據你的需求,你可能會選擇其中一種方式,因此 pandas 提供了兩種選項。在數據科學中,列通常代表變量,行則代表觀測值,因此你更可能刪除包含數據的行;`dropna()` 的預設設定是刪除所有包含任何空值的行:\n" ] }, { @@ -1273,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "如果需要,您可以從列中刪除 NA 值。使用 `axis=1` 來執行:\n" + "如果需要,您可以從列中刪除 NA 值。使用 `axis=1` 來完成:\n" ] }, { @@ -1352,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "注意,這可能會丟失許多您可能想保留的數據,特別是在較小的數據集中。如果您只想刪除包含幾個甚至全部空值的行或列該怎麼辦?您可以在 `dropna` 中使用 `how` 和 `thresh` 參數來指定這些設置。\n", + "請注意,這可能會刪除許多您可能希望保留的數據,特別是在較小的數據集中。如果您只想刪除包含多個甚至全部空值的行或列該怎麼辦?您可以在 `dropna` 中使用 `how` 和 `thresh` 參數來指定這些設置。\n", "\n", - "預設情況下,`how='any'`(如果您想自行檢查或查看該方法的其他參數,可以在程式碼單元中執行 `example4.dropna?`)。您也可以選擇指定 `how='all'`,這樣只會刪除包含所有空值的行或列。我們來擴展我們的範例 `DataFrame`,在下一個練習中看看這是如何運作的。\n" + "預設情況下,`how='any'`(如果您想自行檢查或查看該方法的其他參數,可以在程式碼單元中執行 `example4.dropna?`)。您也可以選擇指定 `how='all'`,以便僅刪除包含所有空值的行或列。讓我們擴展範例 `DataFrame`,在下一個練習中看看這是如何運作的。\n" ] }, { @@ -1446,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> 關鍵重點:\n", - "1. 僅在資料集足夠大的情況下,刪除空值才是個好主意。\n", - "2. 如果整行或整列的大部分資料都缺失,可以考慮刪除這些行或列。\n", - "3. `DataFrame.dropna(axis=)` 方法可用於刪除空值。`axis` 參數用於指定是刪除行還是列。\n", - "4. `how` 參數也可以使用。預設值為 `any`,因此它只會刪除包含任意空值的行或列。可以將其設置為 `all`,以指定僅刪除所有值皆為空的行或列。\n" + "> 關鍵要點:\n", + "1. 只有在資料集足夠大的情況下,刪除空值才是明智的選擇。\n", + "2. 如果整行或整列的大部分資料都缺失,可以考慮刪除。\n", + "3. `DataFrame.dropna(axis=)` 方法可用於刪除空值。`axis` 參數表示是要刪除行還是列。\n", + "4. 也可以使用 `how` 參數。預設值為 `any`,因此它只會刪除包含任何空值的行或列。可以將其設置為 `all`,以指定僅刪除所有值均為空的行或列。\n" ] }, { @@ -1458,7 +1468,9 @@ "metadata": { "id": "oXXSfQFHgRsF" }, - "source": [] + "source": [ + "### 運動:\n" + ] }, { "cell_type": "code", @@ -1480,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "`thresh` 參數為您提供更細緻的控制:您可以設定一行或一列需要具有的*非空*值的數量,以便保留:\n" + "`thresh` 參數提供更細緻的控制:您設定一行或一列需要具有的*非空*值的數量,以便保留該行或列:\n" ] }, { @@ -1566,9 +1578,9 @@ "source": [ "### 填補空值\n", "\n", - "有時候,用一些可能合理的值來填補缺失值是有意義的。填補空值有幾種技術。第一種方法是利用領域知識(即對數據集所基於主題的了解)來大致估算缺失值。\n", + "有時候填補缺失值為可能有效的值是合理的。有幾種方法可以用來填補空值。第一種方法是使用領域知識(即對數據集所基於的主題的了解)來近似缺失值。\n", "\n", - "你可以使用 `isnull` 來直接進行填補,但這可能會很繁瑣,特別是當你需要填補大量值時。由於這在數據科學中是一個非常常見的任務,pandas 提供了 `fillna` 方法,該方法會返回一個 `Series` 或 `DataFrame` 的副本,並將缺失值替換為你選擇的值。我們來創建另一個 `Series` 的例子,看看這在實際操作中是如何運作的。\n" + "你可以使用 `isnull` 直接進行操作,但這可能會很繁瑣,特別是當你有很多值需要填補時。由於這在數據科學中是一個非常常見的任務,pandas 提供了 `fillna`,它會返回一個 `Series` 或 `DataFrame` 的副本,其中的缺失值被替換為你選擇的值。讓我們創建另一個示例 `Series`,來看看這在實際操作中是如何工作的。\n" ] }, { @@ -1578,11 +1590,11 @@ }, "source": [ "### 類別型資料(非數值型)\n", - "首先,我們來討論非數值型資料。在數據集中,我們有一些包含類別型資料的欄位。例如:性別、True 或 False 等。\n", + "首先讓我們來看非數值型資料。在資料集中,我們有一些包含類別型資料的欄位,例如性別、True 或 False 等。\n", "\n", - "在大多數情況下,我們會用該欄位的「眾數」來替換缺失值。假設我們有 100 筆數據,其中 90 筆是 True,8 筆是 False,還有 2 筆未填寫。那麼,我們可以將這 2 筆未填寫的數據填為 True,基於整個欄位的情況來考量。\n", + "在大多數情況下,我們會用該欄位的 `眾數` 來替換缺失值。假設我們有 100 筆資料,其中 90 筆是 True,8 筆是 False,還有 2 筆未填寫。那麼,我們可以用 True 填補這 2 筆缺失值,基於整個欄位的情況來考量。\n", "\n", - "此外,我們也可以在這裡運用領域知識。讓我們來看一個使用眾數填補的例子。\n" + "此外,我們也可以在這裡運用領域知識。以下是一個使用眾數填補的例子。\n" ] }, { @@ -1687,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "現在,讓我們先找到眾數,再用眾數填充 `None` 值。\n" + ] }, { "cell_type": "code", @@ -1722,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "所以,我們將用 True 替換 None\n" + ] }, { "cell_type": "code", @@ -1832,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "正如我們所見,空值已被替換。毋庸置疑,我們本可以在 `'True'` 的位置寫任何內容,它都會被替換。\n" + "如我們所見,空值已被替換。不用說,我們可以在 `'True'` 的位置寫任何內容,它都會被替代。\n" ] }, { @@ -1844,14 +1860,14 @@ "### 數值資料\n", "現在來談談數值資料。在這裡,我們有兩種常見的方法來替換缺失值:\n", "\n", - "1. 用該行的中位數替換 \n", - "2. 用該行的平均值替換 \n", + "1. 用行的中位數替換\n", + "2. 用行的平均值替換\n", "\n", - "當資料有偏態且存在異常值時,我們會選擇用中位數替換。這是因為中位數對異常值具有穩健性。\n", + "如果資料有偏態且存在異常值,我們會選擇用中位數替換。這是因為中位數對異常值具有穩健性。\n", "\n", "當資料已經正規化時,我們可以使用平均值,因為在這種情況下,平均值和中位數會非常接近。\n", "\n", - "首先,我們來選擇一個呈正態分佈的欄位,並用該欄的平均值填補缺失值。\n" + "首先,我們選擇一個呈正態分佈的列,並用該列的平均值填補缺失值。\n" ] }, { @@ -1991,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "用平均值填充\n" + ] }, { "cell_type": "code", @@ -2091,7 +2109,7 @@ "id": "CwpVFCrPTC5z" }, "source": [ - "正如我們所見,缺失值已被其平均值取代。\n" + "正如我們所見,缺失值已被其平均值替換。\n" ] }, { @@ -2240,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "填充中位數\n" + ] }, { "cell_type": "code", @@ -2340,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "正如我們所見,NaN 值已被該列的中位數取代\n" + "如我們所見,NaN 值已被該列的中位數替換\n" ] }, { @@ -2423,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> 關鍵重點:\n", - "1. 當數據較少或有策略填補缺失數據時,應進行缺失值填補。\n", + "> 關鍵要點:\n", + "1. 填補缺失值應在數據較少或有填補缺失值的策略時進行。\n", "2. 可以利用領域知識來估算並填補缺失值。\n", "3. 對於分類數據,通常使用該列的眾數來替代缺失值。\n", - "4. 對於數值型數據,缺失值通常使用平均值(針對正規化數據集)或該列的中位數來填補。\n" + "4. 對於數值型數據,缺失值通常以平均值(針對正規化數據集)或該列的中位數來填補。\n" ] }, { @@ -2435,7 +2455,9 @@ "metadata": { "id": "FI9MmqFJgRsH" }, - "source": [] + "source": [ + "### 運動:\n" + ] }, { "cell_type": "code", @@ -2455,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "您可以使用**前向填充**空值,即使用最後一個有效值來填充空值:\n" + ] }, { "cell_type": "code", @@ -2495,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "您也可以使用**回填**將下一個有效值向後傳播以填補空值:\n" + "您也可以使用 **回填** 將下一個有效值向後傳播以填補空值:\n" ] }, { @@ -2537,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "正如你可能猜到的,這與 DataFrames 的操作方式相同,但你也可以指定一個 `axis` 來填充空值:\n" + "正如您可能猜到的,這與 DataFrames 的操作方式相同,但您也可以指定一個 `axis` 來填充空值:\n" ] }, { @@ -2710,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "請注意,當先前的值無法用於向前填充時,空值將保留。\n" + "請注意,當前一個值無法用於向前填充時,空值將保持不變。\n" ] }, { @@ -2718,7 +2742,9 @@ "metadata": { "id": "eeAoOU0RgRsJ" }, - "source": [] + "source": [ + "### 運動:\n" + ] }, { "cell_type": "code", @@ -2741,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "您可以創意地使用 `fillna`。例如,我們再來看看 `example4`,但這次我們用 `DataFrame` 中所有值的平均值來填補缺失值:\n" + "您可以創造性地使用 `fillna`。例如,讓我們再次查看 `example4`,但這次我們將缺失值填充為 `DataFrame` 中所有值的平均值:\n" ] }, { @@ -2832,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "注意,第 3 欄仍然是空的:預設的方向是按行填充數值。\n", + "注意,第 3 欄仍然是空的:預設方向是按行填充值。\n", "\n", - "> **重點提示:** 處理數據集中缺失值的方法有很多種。具體採用哪種策略(刪除、替換,甚至是如何替換)應該根據該數據的具體情況來決定。隨著你處理和分析更多數據集,你將對如何處理缺失值有更好的理解和感覺。\n" + "> **重點提示:** 處理數據集中缺失值的方法有很多。具體採用的策略(刪除、替換,甚至替換的方式)應根據該數據的具體情況來決定。隨著你處理和接觸更多的數據集,你將更能掌握如何應對缺失值的技巧。\n" ] }, { @@ -2843,11 +2869,11 @@ "id": "bauDnESIl9FH" }, "source": [ - "### 編碼分類資料\n", + "### 編碼分類數據\n", "\n", - "機器學習模型只能處理數字以及任何形式的數值資料。它無法分辨「是」和「否」,但能區分 0 和 1。因此,在填補缺失值之後,我們需要將分類資料編碼成某種數值形式,讓模型能夠理解。\n", + "機器學習模型只能處理數字和任何形式的數值數據。它無法分辨「是」和「否」,但能區分 0 和 1。因此,在填補缺失值之後,我們需要將分類數據編碼成某種數字形式,讓模型能夠理解。\n", "\n", - "編碼可以透過兩種方式完成。我們接下來會討論這些方法。\n" + "編碼可以通過兩種方式完成。我們接下來將討論這些方法。\n" ] }, { @@ -2858,7 +2884,7 @@ "source": [ "**標籤編碼**\n", "\n", - "標籤編碼基本上是將每個類別轉換為一個數字。例如,假設我們有一個航空乘客的數據集,其中有一列包含他們的艙等,艙等包括以下類別:['商務艙', '經濟艙', '頭等艙']。如果對這些類別進行標籤編碼,則會被轉換為 [0,1,2]。讓我們通過程式碼來看一個例子。由於我們會在接下來的筆記本中學習 `scikit-learn`,所以這裡不使用它。\n" + "標籤編碼基本上是將每個類別轉換為一個數字。例如,假設我們有一個航空乘客的數據集,其中有一列包含以下類別:['商務艙', '經濟艙', '頭等艙']。如果對其進行標籤編碼,則會被轉換為 [0,1,2]。讓我們通過程式碼來看一個例子。由於我們會在接下來的筆記本中學習 `scikit-learn`,這裡不會使用它。\n" ] }, { @@ -2966,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "要對第一列執行標籤編碼,我們必須先描述每個類別到數字的映射,然後再進行替換\n" + "要對第一列進行標籤編碼,我們必須首先描述每個類別到數字的映射,然後進行替換\n" ] }, { @@ -3068,10 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "正如我們所見,輸出結果與我們預期的一致。那麼,我們什麼時候應該使用標籤編碼呢?標籤編碼適用於以下一種或兩種情況:\n", - "\n", - "1. 當類別數量很大時 \n", - "2. 當類別具有順序性時 \n" + "如我們所見,輸出結果與我們預期的一致。那麼,我們什麼時候使用標籤編碼呢?標籤編碼通常在以下情況之一或兩者中使用:\n", + "1. 當類別數量很多時\n", + "2. 當類別具有順序性時。\n" ] }, { @@ -3080,11 +3105,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**獨熱編碼**\n", + "**單一熱編碼**\n", "\n", - "另一種編碼方式是獨熱編碼(One Hot Encoding)。在這種編碼方式中,每個欄位的類別會被新增為一個獨立的欄位,而每個數據點會根據是否包含該類別被賦予 0 或 1 的值。因此,如果有 n 種不同的類別,則會在資料框中新增 n 個欄位。\n", + "另一種編碼方式是單一熱編碼。在這種編碼方式中,欄位中的每個類別都會被新增為一個獨立的欄位,而每個數據點會根據是否包含該類別被賦予 0 或 1 的值。因此,如果有 n 個不同的類別,則會向資料框中新增 n 個欄位。\n", "\n", - "例如,我們以相同的飛機艙等為例。類別為:['business class', 'economy class', 'first class']。那麼,如果我們執行獨熱編碼,以下三個欄位將被新增到資料集中:['class_business class', 'class_economy class', 'class_first class']。\n" + "例如,讓我們以相同的飛機艙等例子來說。類別為:['商務艙', '經濟艙', '頭等艙']。如果我們執行單一熱編碼,以下三個欄位將被新增到資料集中:['class_business class', 'class_economy class', 'class_first class']。\n" ] }, { @@ -3192,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "讓我們對第一列執行獨熱編碼\n" + "讓我們對第一列進行獨熱編碼\n" ] }, { @@ -3317,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "每個獨熱編碼欄位包含 0 或 1,指定該數據點是否存在該類別。\n" + "每個獨熱編碼的列包含 0 或 1,指定該數據點是否存在該類別。\n" ] }, { @@ -3328,8 +3353,8 @@ "source": [ "什麼時候使用獨熱編碼?獨熱編碼通常在以下情況之一或兩者中使用:\n", "\n", - "1. 當類別數量和數據集的大小較小時。\n", - "2. 當類別沒有特定的順序時。\n" + "1. 當分類數量和數據集的大小較小時。\n", + "2. 當分類沒有特定的順序時。\n" ] }, { @@ -3338,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> 關鍵重點:\n", - "1. 編碼是將非數值型資料轉換為數值型資料的過程。\n", - "2. 編碼分為兩種類型:標籤編碼和獨熱編碼,可以根據資料集的需求進行選擇。\n" + "> 關鍵要點:\n", + "1. 編碼是將非數字型資料轉換為數字型資料的過程。\n", + "2. 編碼有兩種類型:標籤編碼和獨熱編碼,可以根據資料集的需求進行選擇。\n" ] }, { @@ -3351,9 +3376,9 @@ "source": [ "## 移除重複資料\n", "\n", - "> **學習目標:** 在本小節結束時,您應該能夠輕鬆識別並移除 DataFrame 中的重複值。\n", + "> **學習目標:** 完成本小節後,您應該能夠熟練地識別並移除 DataFrame 中的重複值。\n", "\n", - "除了遺漏資料之外,您在處理真實世界的數據集時,經常會遇到重複的資料。幸運的是,pandas 提供了一種簡單的方法來檢測和移除重複的條目。\n" + "除了缺失資料外,您在真實世界的數據集中經常會遇到重複的資料。幸運的是,pandas 提供了一個簡便的方法來檢測和移除重複的項目。\n" ] }, { @@ -3362,9 +3387,9 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### 識別重複值:`duplicated`\n", + "### 識別重複項目:`duplicated`\n", "\n", - "你可以使用 pandas 的 `duplicated` 方法輕鬆找出重複值。該方法會返回一個布林遮罩,指示 `DataFrame` 中某個條目是否與之前的條目重複。我們來建立另一個範例 `DataFrame`,看看這個方法的實際應用。\n" + "您可以使用 pandas 中的 `duplicated` 方法輕鬆找出重複的值。該方法會返回一個布林遮罩,指示 `DataFrame` 中的某個項目是否與之前的項目重複。讓我們建立另一個範例 `DataFrame` 來看看這個方法的運作方式。\n" ] }, { @@ -3493,7 +3518,7 @@ "id": "0eDRJD4SgRsK" }, "source": [ - "### 刪除重複值:`drop_duplicates`\n", + "### 刪除重複項:`drop_duplicates`\n", "`drop_duplicates` 會返回一份數據的副本,其中所有 `duplicated` 值均為 `False`:\n" ] }, @@ -3653,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **重點:** 移除重複數據是幾乎每個數據科學項目中不可或缺的一部分。重複數據可能會改變分析結果並導致不準確的結論!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 真實世界的資料品質檢查\n", + "\n", + "> **學習目標:** 完成本節後,您應該能夠熟練地檢測並修正常見的真實世界資料品質問題,包括不一致的分類值、異常的數值(離群值)以及具有變化的重複實體。\n", + "\n", + "雖然遺漏值和完全重複是常見問題,但真實世界的資料集通常包含更微妙的問題:\n", + "\n", + "1. **不一致的分類值**:同一分類以不同方式拼寫(例如:\"USA\"、\"U.S.A\"、\"United States\")\n", + "2. **異常的數值**:極端的離群值可能表示資料輸入錯誤(例如,年齡 = 999)\n", + "3. **近似重複的行**:表示同一實體但有些微差異的記錄\n", + "\n", + "讓我們來探討檢測和處理這些問題的技巧。\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 建立範例「髒」資料集\n", + "\n", + "首先,讓我們建立一個包含常見於真實世界數據問題的範例資料集:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. 偵測不一致的分類值\n", + "\n", + "注意到 `country` 欄位中,同一個國家有多種表示方式。讓我們來識別這些不一致之處:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 標準化分類值\n", + "\n", + "我們可以建立一個映射來標準化這些值。一個簡單的方法是將值轉換為小寫並建立一個映射字典:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**替代方法:使用模糊匹配**\n", + "\n", + "對於更複雜的情況,我們可以使用 `rapidfuzz` 庫進行模糊字符串匹配,自動檢測相似的字符串:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. 偵測異常數值(離群值)\n", + "\n", + "查看 `age` 欄位時,我們發現一些可疑的數值,例如 199 和 -5。讓我們使用統計方法來偵測這些離群值。\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 使用 IQR(四分位距)方法\n", + "\n", + "IQR 方法是一種穩健的統計技術,用於檢測異常值,且對極端值的敏感度較低:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 使用 Z 分數方法\n", + "\n", + "Z 分數方法根據與平均值的標準差來識別異常值:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 處理異常值\n", + "\n", + "一旦檢測到異常值,可以用以下幾種方式處理:\n", + "1. **移除**:刪除包含異常值的行(如果它們是錯誤)\n", + "2. **限制**:用邊界值替換\n", + "3. **替換為 NaN**:視為缺失數據並使用插補技術\n", + "4. **保留**:如果它們是合法的極端值\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. 偵測近似重複的行\n", + "\n", + "注意,我們的數據集中有多個 \"John Smith\" 的條目,但其值略有不同。我們來根據名稱相似性識別潛在的重複項。\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 使用模糊匹配尋找近似重複項\n", + "\n", + "為了進行更高級的重複檢測,我們可以使用模糊匹配來尋找相似的名稱:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 處理重複項\n", + "\n", + "一旦識別出來後,您需要決定如何處理重複項:\n", + "1. **保留第一次出現**:使用 `drop_duplicates(keep='first')`\n", + "2. **保留最後一次出現**:使用 `drop_duplicates(keep='last')`\n", + "3. **聚合資訊**:合併重複行中的資訊\n", + "4. **人工審查**:標記以供人工審查\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 摘要:完整的數據清理流程\n", + "\n", + "讓我們將所有內容整合成一個全面的清理流程:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 挑戰練習\n", + "\n", + "現在輪到你了!以下是一行包含多個品質問題的新數據。你能否:\n", + "\n", + "1. 找出這行數據中的所有問題\n", + "2. 撰寫程式碼來清理每個問題\n", + "3. 將清理後的數據行添加到數據集\n", + "\n", + "以下是有問題的數據:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 關鍵重點\n", + "\n", + "1. **分類不一致**在真實世界的數據中很常見。務必檢查唯一值,並使用映射或模糊匹配來標準化它們。\n", + "\n", + "2. **異常值**可能會對分析產生重大影響。結合領域知識與統計方法(如 IQR、Z-score)來檢測它們。\n", + "\n", + "3. **近似重複項**比完全重複項更難檢測。考慮使用模糊匹配並對數據進行標準化(如轉小寫、去除空白)來識別它們。\n", + "\n", + "4. **數據清理是反覆進行的**。可能需要應用多種技術並檢查結果,才能最終完成清理後的數據集。\n", + "\n", + "5. **記錄你的決策**。追蹤你所採用的清理步驟及其原因,這對於可重現性和透明度非常重要。\n", + "\n", + "> **最佳實踐:**務必保留原始的「髒」數據副本。切勿覆蓋原始數據文件,應創建清理後的版本,並使用清晰的命名規則,例如 `data_cleaned.csv`。\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**免責聲明**: \n本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對於因使用此翻譯而引起的任何誤解或錯誤解讀概不負責。 \n" + "\n---\n\n**免責聲明**: \n本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。\n" ] } ], @@ -3687,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:08:15+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:19:07+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "mo" } diff --git a/translations/mr/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/mr/2-Working-With-Data/08-data-preparation/notebook.ipynb index 7917014c..5ff09e6f 100644 --- a/translations/mr/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/mr/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# डेटा तयारी\n", "\n", - "[मूळ नोटबुक स्रोत *डेटा सायन्स: डेटा सायन्ससाठी मशीन लर्निंगची ओळख - पायथॉन आणि मशीन लर्निंग स्टुडिओ बाय ली स्टॉट*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[मूळ नोटबुक स्रोत *डेटा सायन्स: डेटासायन्ससाठी मशीन लर्निंगसाठी परिचय - पायथन आणि मशीन लर्निंग स्टुडिओ बाय ली स्टॉट*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## `DataFrame` माहिती शोधणे\n", "\n", - "> **शिकण्याचे उद्दिष्ट:** या उपविभागाच्या शेवटी, तुम्हाला pandas DataFrames मध्ये संग्रहित डेटाबद्दल सामान्य माहिती शोधण्यात सोय होईल.\n", + "> **शिकण्याचे उद्दिष्ट:** या उपविभागाच्या शेवटी, तुम्हाला pandas DataFrames मध्ये संग्रहित डेटा बद्दल सामान्य माहिती शोधण्यात सोय होईल.\n", "\n", - "जेव्हा तुम्ही तुमचा डेटा pandas मध्ये लोड करता, तेव्हा तो बहुधा `DataFrame` स्वरूपात असेल. परंतु, जर तुमच्या `DataFrame` मध्ये 60,000 ओळी आणि 400 स्तंभ असतील, तर तुम्ही सुरुवात कशी कराल? सुदैवाने, pandas काही सोयीस्कर साधने प्रदान करते ज्यामुळे `DataFrame` बद्दलची एकूण माहिती तसेच सुरुवातीच्या आणि शेवटच्या काही ओळी पटकन पाहता येतात.\n", + "तुम्ही तुमचा डेटा pandas मध्ये लोड केल्यानंतर, तो बहुधा `DataFrame` स्वरूपात असेल. परंतु, जर तुमच्या `DataFrame` मध्ये 60,000 ओळी आणि 400 स्तंभ असतील, तर तुम्ही काय काम करत आहात याची कल्पना कशी कराल? सुदैवाने, pandas काही सोयीस्कर साधने प्रदान करते ज्यामुळे `DataFrame` बद्दल एकूण माहिती तसेच सुरुवातीच्या काही आणि शेवटच्या काही ओळी पटकन पाहता येतात.\n", "\n", - "ही कार्यक्षमता शोधण्यासाठी, आपण Python scikit-learn लायब्ररी आयात करू आणि एक प्रसिद्ध डेटासेट वापरू, जो प्रत्येक डेटा सायंटिस्टने शेकडो वेळा पाहिला आहे: ब्रिटिश जीवशास्त्रज्ञ रोनाल्ड फिशर यांचा *Iris* डेटासेट, जो त्यांनी 1936 च्या त्यांच्या \"The use of multiple measurements in taxonomic problems\" या पेपरमध्ये वापरला होता:\n" + "या कार्यक्षमतेचा अभ्यास करण्यासाठी, आपण Python scikit-learn लायब्ररी आयात करू आणि एक प्रसिद्ध डेटासेट वापरू जो प्रत्येक डेटा सायंटिस्टने शेकडो वेळा पाहिला आहे: ब्रिटिश जीवशास्त्रज्ञ रोनाल्ड फिशर यांचा *Iris* डेटा सेट, जो त्यांच्या 1936 च्या \"The use of multiple measurements in taxonomic problems\" या पेपरमध्ये वापरला होता:\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "आम्ही 150 ओळी आणि 4 स्तंभांच्या डेटासह काम करत आहोत. प्रत्येक ओळ एक डेटा पॉइंट दर्शवते आणि प्रत्येक स्तंभ डेटा फ्रेमशी संबंधित एक वैशिष्ट्य दर्शवतो. त्यामुळे मूलतः, 150 डेटा पॉइंट्स आहेत ज्यामध्ये प्रत्येकामध्ये 4 वैशिष्ट्ये आहेत.\n", + "म्हणजे, आपल्याकडे 150 ओळी आणि 4 स्तंभांचा डेटा आहे. प्रत्येक ओळ एक डेटा पॉइंट दर्शवते आणि प्रत्येक स्तंभ डेटा फ्रेमशी संबंधित एक वैशिष्ट्य दर्शवतो. तर मूलतः, 150 डेटा पॉइंट्स आहेत ज्यामध्ये प्रत्येकामध्ये 4 वैशिष्ट्ये आहेत.\n", "\n", - "`shape` येथे डेटा फ्रेमचे एक गुणधर्म आहे आणि एक फंक्शन नाही, म्हणूनच ते कंसांच्या जोडीत संपत नाही.\n" + "`shape` येथे डेटा फ्रेमचे एक गुणधर्म आहे आणि एक फंक्शन नाही, म्हणूनच ते जोडलेल्या कंसांनी संपत नाही.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "आता आपण डेटा फ्रेममधील ४ स्तंभांकडे वळूया. प्रत्येक स्तंभ नेमके काय दर्शवतो? `columns` गुणधर्म आपल्याला डेटा फ्रेममधील स्तंभांची नावे देईल.\n" + "आता आपण डेटा फ्रेममधील 4 स्तंभांकडे जाऊया. प्रत्येक स्तंभ नेमके काय दर्शवतो? `columns` गुणधर्म आपल्याला डेटा फ्रेममधील स्तंभांची नावे देईल.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "जसे आपण पाहू शकतो, येथे चार(4) स्तंभ आहेत. `columns` गुणधर्म आपल्याला स्तंभांची नावे सांगतो आणि मुळात इतर काहीही नाही. जेव्हा आपल्याला डेटासेटमध्ये असलेल्या वैशिष्ट्यांची ओळख पटवायची असते तेव्हा हा गुणधर्म महत्त्वाचा ठरतो.\n" + "जसे आपण पाहू शकतो, येथे चार(4) स्तंभ आहेत. `columns` गुणधर्म आपल्याला स्तंभांची नावे सांगतो आणि मूलत: त्यापेक्षा काहीही नाही. जेव्हा आपल्याला डेटासेटमध्ये असलेल्या वैशिष्ट्यांची ओळख पटवायची असते तेव्हा हा गुणधर्म महत्त्वाचा ठरतो.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "डेटामधील माहिती (`shape` attribute द्वारे दिलेली) आणि वैशिष्ट्ये किंवा स्तंभांची नावे (`columns` attribute द्वारे दिलेली) आपल्याला डेटासेटबद्दल काहीतरी सांगतात. आता, आपल्याला डेटासेटमध्ये अधिक सखोल जाणून घ्यायचे आहे. `DataFrame.info()` फंक्शन यासाठी खूप उपयुक्त आहे.\n" + "डेटामधील माहिती (`shape` गुणधर्माने दिलेली) आणि वैशिष्ट्ये किंवा स्तंभांची नावे (`columns` गुणधर्माने दिलेली) आपल्याला डेटासेटबद्दल काहीतरी सांगतात. आता, आपल्याला डेटासेटमध्ये अधिक सखोल जाणून घ्यायचे आहे. `DataFrame.info()` फंक्शन यासाठी खूप उपयुक्त आहे.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "येथून, आपण काही निरीक्षणे करू शकतो: \n", - "1. प्रत्येक स्तंभाचा डेटा प्रकार: या डेटासेटमध्ये, सर्व डेटा 64-बिट फ्लोटिंग-पॉइंट संख्यांमध्ये संग्रहित आहे. \n", - "2. नॉन-नल मूल्यांची संख्या: नल मूल्यांशी व्यवहार करणे हा डेटा तयारीतील एक महत्त्वाचा टप्पा आहे. यावर पुढे नोटबुकमध्ये प्रक्रिया केली जाईल. \n" + "येथून, आपण काही निरीक्षणे करू शकतो:\n", + "1. प्रत्येक स्तंभाचा डेटा प्रकार: या डेटासेटमध्ये, सर्व डेटा 64-बिट फ्लोटिंग-पॉइंट संख्यांमध्ये संग्रहित केला आहे.\n", + "2. नॉन-नल मूल्यांची संख्या: नल मूल्यांशी व्यवहार करणे हा डेटा तयारीतील महत्त्वाचा टप्पा आहे. यावर नंतर नोटबुकमध्ये विचार केला जाईल.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "समजा आपल्या डेटासेटमध्ये बरीच संख्यात्मक माहिती आहे. प्रत्येक कॉलमवर स्वतंत्रपणे सरासरी, मध्यक, चतुर्थांश इत्यादी एकसमान सांख्यिकीय गणना करता येऊ शकते. `DataFrame.describe()` फंक्शन आपल्याला डेटासेटमधील संख्यात्मक कॉलम्सचा सांख्यिकीय सारांश प्रदान करते.\n" + "म्हणून समजा आपल्या डेटासेटमध्ये बरीच संख्यात्मक माहिती आहे. प्रत्येक स्तंभावर स्वतंत्रपणे सरासरी, मध्यक, चतुर्थांश इत्यादीसारख्या एकच चल सांख्यिकी गणना करता येतात. `DataFrame.describe()` फंक्शन आपल्याला डेटासेटमधील संख्यात्मक स्तंभांचे सांख्यिकी सारांश प्रदान करते.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "वरील आउटपुट प्रत्येक स्तंभातील डेटा पॉइंट्सची एकूण संख्या, सरासरी, मानक विचलन, किमान मूल्य, खालचा चतुर्थांश (25%), मध्य (50%), वरचा चतुर्थांश (75%) आणि जास्तीत जास्त मूल्य दर्शवतो.\n" + "वरील आउटपुट प्रत्येक स्तंभाचा डेटा पॉइंट्सची एकूण संख्या, सरासरी, मानक विचलन, किमान, खालचा चतुर्थांश (25%), मध्यम (50%), वरचा चतुर्थांश (75%) आणि जास्तीत जास्त मूल्य दर्शवतो.\n" ] }, { @@ -334,7 +334,7 @@ "### `DataFrame.head`\n", "वरील सर्व फंक्शन्स आणि गुणधर्मांसह, आपल्याला डेटासेटचा एक उच्चस्तरीय आढावा मिळाला आहे. आपल्याला माहित आहे की किती डेटा पॉइंट्स आहेत, किती वैशिष्ट्ये आहेत, प्रत्येक वैशिष्ट्याचा डेटा प्रकार काय आहे आणि प्रत्येक वैशिष्ट्यासाठी किती नॉन-नल मूल्ये आहेत.\n", "\n", - "आता प्रत्यक्ष डेटाकडे पाहण्याची वेळ आली आहे. आपल्या `DataFrame` मधील पहिल्या काही ओळी (पहिले काही डेटा पॉइंट्स) कशा दिसतात ते पाहूया:\n" + "आता प्रत्यक्ष डेटाकडे पाहण्याची वेळ आली आहे. आपल्या `DataFrame` च्या पहिल्या काही ओळी (पहिले काही डेटा पॉइंट्स) कशा दिसतात ते पाहूया:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "आउटपुटमध्ये, आपण डेटासेटच्या पाच(5) नोंदी पाहू शकतो. जर आपण डावीकडील अनुक्रमांक पाहिला, तर आपल्याला कळते की या पहिल्या पाच ओळी आहेत.\n" + "आउटपुटमध्ये, आपण डेटासेटच्या पाच(5) नोंदी पाहू शकतो. जर आपण डाव्या बाजूला असलेल्या अनुक्रमणिका पाहिल्या, तर आपल्याला कळते की या पहिल्या पाच ओळी आहेत.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### व्यायाम:\n", "\n", - "वरील उदाहरणावरून स्पष्ट होते की, डीफॉल्टनुसार, `DataFrame.head` `DataFrame` च्या पहिल्या पाच ओळी परत करते. खालील कोड सेलमध्ये, तुम्ही पाचपेक्षा जास्त ओळी कशा प्रदर्शित करायच्या याचा मार्ग शोधू शकता का?\n" + "वरील उदाहरणावरून स्पष्ट होते की, `DataFrame.head` डिफॉल्टनुसार `DataFrame` च्या पहिल्या पाच ओळी परत करते. खालील कोड सेलमध्ये, तुम्ही पाचपेक्षा जास्त ओळी दाखवण्याचा मार्ग शोधू शकता का?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "डेटा पाहण्याचा आणखी एक मार्ग म्हणजे शेवटापासून (सुरुवातीऐवजी). `DataFrame.head` च्या उलट, `DataFrame.tail` `DataFrame` च्या शेवटच्या पाच ओळी परत करते:\n" + "डेटा पाहण्याचा आणखी एक मार्ग म्हणजे शेवटापासून (सुरुवातीऐवजी). `DataFrame.head` च्या उलट म्हणजे `DataFrame.tail`, जे `DataFrame` च्या शेवटच्या पाच ओळी परत करते:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "व्यवहारात, `DataFrame` च्या पहिल्या काही ओळी किंवा शेवटच्या काही ओळी सहजपणे तपासणे उपयुक्त ठरते, विशेषतः जेव्हा तुम्ही क्रमबद्ध डेटासेटमधील अपवाद शोधत असता.\n", + "प्रत्यक्षात, `DataFrame` मधील पहिल्या काही ओळी किंवा शेवटच्या काही ओळी सहजपणे तपासणे उपयुक्त ठरते, विशेषतः जेव्हा तुम्ही क्रमबद्ध डेटासेटमध्ये अपवाद शोधत असता.\n", "\n", - "वरील कोड उदाहरणांच्या मदतीने दाखवलेल्या सर्व फंक्शन्स आणि अॅट्रिब्युट्स आपल्याला डेटाचा लुक आणि फील समजून घेण्यास मदत करतात.\n", + "वरील कोड उदाहरणांच्या मदतीने दाखवलेल्या सर्व फंक्शन्स आणि गुणधर्म आपल्याला डेटाचा लुक आणि फील मिळविण्यास मदत करतात.\n", "\n", - "> **महत्त्वाचे:** फक्त `DataFrame` मधील माहितीबद्दलची मेटाडेटा किंवा त्यातील पहिल्या आणि शेवटच्या काही मूल्यांकडे पाहूनही, तुम्ही डेटाचा आकार, स्वरूप, आणि सामग्री याबद्दल त्वरित कल्पना करू शकता.\n" + "> **महत्त्वाचे:** फक्त `DataFrame` मधील माहितीबद्दलची मेटाडेटा किंवा त्यातील पहिल्या आणि शेवटच्या काही मूल्यांकडे पाहूनही, तुम्ही डेटाचा आकार, स्वरूप आणि सामग्रीबद्दल त्वरित कल्पना करू शकता.\n" ] }, { @@ -595,18 +595,18 @@ "id": "TvurZyLSDxq_" }, "source": [ - "### हरवलेली डेटा\n", - "चला हरवलेल्या डेटावर चर्चा करूया. हरवलेली डेटा म्हणजे, जेव्हा काही स्तंभांमध्ये कोणतीही मूल्ये संग्रहित केलेली नसतात.\n", + "### हरवलेला डेटा\n", + "चला हरवलेल्या डेटामध्ये खोलवर जाऊया. हरवलेला डेटा तेव्हा होतो, जेव्हा काही स्तंभांमध्ये कोणतीही मूल्ये संग्रहित केलेली नसतात.\n", "\n", - "उदाहरण घेऊया: समजा, एखादी व्यक्ती त्याच्या/तिच्या वजनाबद्दल जागरूक आहे आणि सर्वेक्षणामध्ये वजनाचा भाग भरत नाही. अशा परिस्थितीत, त्या व्यक्तीसाठी वजनाचे मूल्य हरवलेले असेल.\n", + "उदाहरण घेऊया: एखादी व्यक्ती त्याच्या/तिच्या वजनाबद्दल जागरूक आहे आणि सर्वेक्षणामध्ये वजनाचा फील्ड भरत नाही. अशा परिस्थितीत त्या व्यक्तीसाठी वजनाचे मूल्य हरवलेले असेल.\n", "\n", "बहुतेक वेळा, वास्तविक जगातील डेटासेट्समध्ये हरवलेली मूल्ये आढळतात.\n", "\n", - "**Pandas कसे हरवलेल्या डेटाचा सामना करते**\n", + "**पांडास हरवलेल्या डेटाचा कसा सामना करतो**\n", "\n", - "Pandas हरवलेल्या मूल्यांचा सामना दोन प्रकारे करते. पहिला प्रकार तुम्ही याआधीच्या विभागांमध्ये पाहिला असेल: `NaN`, म्हणजेच Not a Number. हे प्रत्यक्षात IEEE फ्लोटिंग-पॉइंट स्पेसिफिकेशनचा एक विशेष मूल्य आहे आणि ते केवळ हरवलेल्या फ्लोटिंग-पॉइंट मूल्ये दर्शवण्यासाठी वापरले जाते.\n", + "पांडास हरवलेल्या मूल्यांचा दोन प्रकारे सामना करतो. पहिला प्रकार तुम्ही याआधीच्या विभागांमध्ये पाहिला आहे: `NaN`, म्हणजेच Not a Number. हे प्रत्यक्षात IEEE फ्लोटिंग-पॉइंट स्पेसिफिकेशनचा एक विशेष मूल्य आहे आणि ते फक्त हरवलेल्या फ्लोटिंग-पॉइंट मूल्ये दर्शवण्यासाठी वापरले जाते.\n", "\n", - "फ्लोट्सव्यतिरिक्त इतर हरवलेल्या मूल्यांसाठी, pandas Python च्या `None` ऑब्जेक्टचा वापर करते. तुम्हाला असे वाटू शकते की दोन वेगवेगळ्या प्रकारची मूल्ये दिसतात जी मूलत: एकच गोष्ट सांगतात, परंतु या डिझाइन निवडीसाठी ठोस प्रोग्रामिंग कारणे आहेत. प्रत्यक्षात, या मार्गाने जाणे pandas ला बहुतेक प्रकरणांमध्ये चांगला तोल साधण्यास सक्षम करते. तरीही, `None` आणि `NaN` या दोन्हीमध्ये काही मर्यादा आहेत ज्या त्यांच्या वापराबाबत तुम्हाला लक्षात ठेवाव्या लागतील.\n" + "फ्लोट्स व्यतिरिक्त हरवलेल्या मूल्यांसाठी, पांडास Python चा `None` ऑब्जेक्ट वापरतो. दोन वेगवेगळ्या प्रकारच्या मूल्यांचा सामना करावा लागतो हे गोंधळात टाकणारे वाटू शकते, परंतु या डिझाइन निवडीसाठी ठोस प्रोग्रामिंग कारणे आहेत आणि प्रत्यक्षात, या मार्गाने जाणे पांडासला बहुतेक प्रकरणांमध्ये चांगला तडजोड देण्यास सक्षम करते. तरीही, `None` आणि `NaN` दोन्हीवर काही मर्यादा आहेत ज्यांचा वापर करताना तुम्हाला लक्षात ठेवणे आवश्यक आहे.\n" ] }, { @@ -616,9 +616,9 @@ }, "source": [ "### `None`: नॉन-फ्लोट गहाळ डेटा\n", - "`None` हा Python मधून येतो, त्यामुळे तो NumPy आणि pandas च्या अशा arrays मध्ये वापरता येत नाही ज्यांचा डेटा प्रकार `'object'` नाही. लक्षात ठेवा, NumPy arrays (आणि pandas मधील डेटा संरचना) फक्त एकाच प्रकारचा डेटा ठेवू शकतात. यामुळेच ते मोठ्या प्रमाणावर डेटा आणि computational कामासाठी जबरदस्त शक्तिशाली ठरतात, पण त्याच वेळी त्यांची लवचिकता मर्यादित होते. अशा arrays ला “सर्वात सामान्य प्रकार” मध्ये बदलावे लागते, म्हणजेच त्या array मधील सर्व गोष्टींना सामावून घेणारा डेटा प्रकार. जेव्हा `None` array मध्ये असतो, तेव्हा याचा अर्थ तुम्ही Python objects सोबत काम करत आहात.\n", + "`None` हा Python मधून येतो, त्यामुळे तो NumPy आणि pandas च्या अशा arrays मध्ये वापरता येत नाही ज्यांचा डेटा प्रकार `'object'` नाही. लक्षात ठेवा, NumPy arrays (आणि pandas मधील डेटा संरचना) फक्त एकाच प्रकारचा डेटा ठेवू शकतात. यामुळेच ते मोठ्या प्रमाणावर डेटा आणि computational कामासाठी जबरदस्त शक्तिशाली ठरतात, पण त्याच वेळी त्यांची लवचिकता मर्यादित होते. अशा arrays ला “lowest common denominator” मध्ये बदलावे लागते, म्हणजेच त्या array मधील सर्व गोष्टींना सामावून घेणारा डेटा प्रकार. जेव्हा `None` array मध्ये असतो, तेव्हा तुम्ही Python objects सोबत काम करत आहात असे मानले जाते.\n", "\n", - "हे कृतीत पाहण्यासाठी, खालील उदाहरण array विचार करा (त्याचा `dtype` लक्षात घ्या):\n" + "हे कृतीत पाहण्यासाठी, खालील उदाहरण array विचारात घ्या (त्याचा `dtype` लक्षात घ्या):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "अपकास्ट डेटा प्रकारांच्या वास्तवतेसह दोन साइड इफेक्ट्स येतात. पहिले, ऑपरेशन्स इंटरप्रेटेड Python कोडच्या पातळीवर चालवले जातात, संकलित NumPy कोडच्या पातळीवर नाहीत. याचा अर्थ असा की, `Series` किंवा `DataFrames` मध्ये `None` असलेल्या कोणत्याही ऑपरेशन्ससाठी प्रक्रिया हळू होईल. तुम्हाला कदाचित हा कार्यक्षमता घटक जाणवणार नाही, परंतु मोठ्या डेटासेटसाठी हे एक समस्या बनू शकते.\n", + "अपकास्ट डेटा प्रकारांची वास्तविकता दोन साइड इफेक्ट्ससह येते. पहिले, ऑपरेशन्स संकलित NumPy कोडऐवजी इंटरप्रेटेड Python कोडच्या स्तरावर चालवले जातील. याचा अर्थ असा की `Series` किंवा `DataFrames` मध्ये `None` असलेल्या कोणत्याही ऑपरेशन्ससाठी गती कमी होईल. तुम्हाला कदाचित ही कार्यक्षमता कमी झाल्याची जाणीव होणार नाही, परंतु मोठ्या डेटासेटसाठी हे एक समस्या बनू शकते.\n", "\n", - "दुसरा साइड इफेक्ट पहिल्यापासून उद्भवतो. कारण `None` मुळात `Series` किंवा `DataFrame`s ला पारंपरिक Python च्या जगात परत खेचतो, त्यामुळे `sum()` किंवा `min()` सारख्या NumPy/pandas ऍग्रीगेशन्सचा वापर `None` मूल्य असलेल्या ऍरेवर केल्यास सामान्यतः एक त्रुटी निर्माण होईल:\n" + "दुसरा साइड इफेक्ट पहिल्यापासून उद्भवतो. कारण `None` मुळात `Series` किंवा `DataFrame`s ला व्हॅनिला Python च्या जगात परत आणते, त्यामुळे NumPy/pandas चे `sum()` किंवा `min()` सारखे ऍग्रीगेशन फंक्शन्स अशा ऍरेवर वापरणे ज्यामध्ये ``None`` मूल्य आहे, सामान्यतः एक त्रुटी निर्माण करेल:\n" ] }, { @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**महत्त्वाचा मुद्दा**: पूर्णांक आणि `None` मूल्यांमधील बेरीज (आणि इतर क्रिया) अनिर्दिष्ट आहे, ज्यामुळे अशा डेटासेट्ससह काय करता येईल यावर मर्यादा येऊ शकते.\n" + ] }, { "cell_type": "markdown", @@ -707,7 +709,7 @@ "source": [ "### `NaN`: गहाळ फ्लोट मूल्ये\n", "\n", - "`None` च्या विपरीत, NumPy (आणि त्यामुळे pandas) त्याच्या जलद, व्हेक्टराइज्ड ऑपरेशन्स आणि ufuncs साठी `NaN` ला समर्थन देते. वाईट बातमी अशी आहे की `NaN` वर कोणतीही अंकगणितीय क्रिया केली तरी ती नेहमी `NaN` देते. उदाहरणार्थ:\n" + "`None` च्या विरोधात, NumPy (आणि त्यामुळे pandas) त्याच्या जलद, व्हेक्टराइज्ड ऑपरेशन्स आणि ufuncs साठी `NaN` ला समर्थन देते. वाईट बातमी म्हणजे `NaN` वर केलेली कोणतीही अंकगणितीय क्रिया नेहमी `NaN` देते. उदाहरणार्थ:\n" ] }, { @@ -770,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "चांगली बातमी: `NaN` असलेल्या arrays वर चालणाऱ्या aggregations त्रुटी दाखवत नाहीत. वाईट बातमी: परिणाम सर्वत्र उपयुक्त नसतात:\n" + "चांगली बातमी: `NaN` असलेल्या arrays वर चालणाऱ्या aggregations त्रुटी निर्माण करत नाहीत. वाईट बातमी: परिणाम सर्वत्र उपयुक्त नसतात:\n" ] }, { @@ -806,7 +808,9 @@ "metadata": { "id": "nhlnNJT7gRr_" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -826,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "लक्षात ठेवा: `NaN` फक्त गहाळ फ्लोटिंग-पॉइंट मूल्यांसाठी आहे; पूर्णांक, स्ट्रिंग्स किंवा बूलियनसाठी `NaN` समानार्थी नाही.\n" + ] }, { "cell_type": "markdown", @@ -836,7 +842,7 @@ "source": [ "### `NaN` आणि `None`: pandas मधील null मूल्ये\n", "\n", - "जरी `NaN` आणि `None` थोडे वेगळे वागू शकतात, तरीही pandas त्यांना एकमेकांच्या जागी हाताळण्यासाठी तयार केले आहे. याचा अर्थ काय आहे ते पाहण्यासाठी, integers च्या `Series` वर विचार करा:\n" + "जरी `NaN` आणि `None` काही प्रमाणात वेगळ्या प्रकारे वागू शकतात, तरीही pandas त्यांना एकसारखे हाताळण्यासाठी तयार केले आहे. याचा अर्थ काय आहे हे पाहण्यासाठी, integers चा एक `Series` विचार करा:\n" ] }, { @@ -875,7 +881,9 @@ "metadata": { "id": "WklCzqb8gRsB" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -898,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "डेटा प्रकारांमध्ये एकसंधता निर्माण करण्यासाठी `Series` आणि `DataFrame`s मध्ये डेटा अपकास्ट करताना, pandas सहजपणे गहाळ मूल्ये `None` आणि `NaN` यांच्यात बदलू शकतो. या डिझाइन वैशिष्ट्यामुळे, pandas मध्ये `None` आणि `NaN` यांना \"null\" च्या दोन वेगळ्या प्रकारांप्रमाणे विचार करणे उपयुक्त ठरते. खरं तर, pandas मध्ये गहाळ मूल्यांशी व्यवहार करण्यासाठी वापरल्या जाणाऱ्या काही मुख्य पद्धती त्यांच्या नावांमध्येही या कल्पनेला प्रतिबिंबित करतात:\n", + "`Series` आणि `DataFrame` मध्ये डेटा प्रकारांची एकसंधता स्थापित करण्यासाठी डेटा अपकास्ट करताना, pandas सहजपणे `None` आणि `NaN` दरम्यान गहाळ मूल्ये बदलतो. या डिझाइन वैशिष्ट्यामुळे, pandas मध्ये `None` आणि `NaN` हे \"null\" चे दोन वेगळे प्रकार म्हणून विचार करणे उपयुक्त ठरू शकते. खरंच, pandas मध्ये गहाळ मूल्यांशी व्यवहार करण्यासाठी तुम्ही वापरणाऱ्या काही मुख्य पद्धती त्यांच्या नावांमध्ये या कल्पनेचे प्रतिबिंब दाखवतात:\n", "\n", - "- `isnull()`: गहाळ मूल्ये दर्शवणारा Boolean मास्क तयार करते\n", - "- `notnull()`: `isnull()` च्या उलट कार्य करते\n", + "- `isnull()`: गहाळ मूल्ये दर्शविणारा Boolean मास्क तयार करते\n", + "- `notnull()`: `isnull()` चा उलट\n", "- `dropna()`: डेटा फिल्टर केलेला आवृत्ती परत करते\n", "- `fillna()`: गहाळ मूल्ये भरून किंवा अंदाज लावून डेटा कॉपी परत करते\n", "\n", - "या पद्धतींचे चांगले ज्ञान मिळवणे आणि त्यांचा सराव करणे महत्त्वाचे आहे, त्यामुळे चला प्रत्येक पद्धतीचा सविस्तर आढावा घेऊया.\n" + "या पद्धतींवर प्रभुत्व मिळवणे आणि त्यांचा आत्मविश्वासाने वापर करणे महत्त्वाचे आहे, त्यामुळे चला प्रत्येकावर सविस्तरपणे चर्चा करूया.\n" ] }, { @@ -916,8 +924,8 @@ "source": [ "### शून्य मूल्य शोधणे\n", "\n", - "आता आपण गहाळ मूल्यांचे महत्त्व समजून घेतले आहे, त्यामुळे त्यांचा सामना करण्यापूर्वी आपल्याला आपल्या डेटासेटमध्ये त्यांना शोधणे आवश्यक आहे. \n", - "`isnull()` आणि `notnull()` ही शून्य डेटा शोधण्यासाठीची तुमची प्राथमिक पद्धती आहेत. दोन्ही तुमच्या डेटावर Boolean मास्क परत करतात.\n" + "आता आपल्याला गहाळ मूल्यांचे महत्त्व समजले आहे, त्यामुळे त्यांच्याशी व्यवहार करण्यापूर्वी आपल्याला आपल्या डेटासेटमध्ये त्यांना शोधणे आवश्यक आहे. \n", + "`isnull()` आणि `notnull()` हे शून्य डेटा शोधण्यासाठी तुमचे प्राथमिक पद्धती आहेत. दोन्ही तुमच्या डेटावर Boolean मास्क परत करतात.\n" ] }, { @@ -970,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "आश्चर्य वाटतंय का? जरी `0` अंकगणितीय शून्य असला तरी तो एक पूर्णांक आहे आणि pandas त्याला तसाच मानतो. `''` थोडं अधिक सूक्ष्म आहे. जरी आपण ते विभाग 1 मध्ये रिक्त स्ट्रिंग मूल्य म्हणून वापरले असले तरी, ते एक स्ट्रिंग ऑब्जेक्ट आहे आणि pandas च्या दृष्टीने null चे प्रतिनिधित्व नाही.\n", + "आउटपुटकडे बारकाईने पाहा. त्यात काही आश्चर्य वाटतंय का? जरी `0` हे अंकगणितीय शून्य असले तरी, ते एक पूर्णांक आहे आणि pandas त्याला तसंच मानतो. `''` थोडं अधिक सूक्ष्म आहे. जरी आपण ते विभाग 1 मध्ये रिक्त स्ट्रिंग मूल्य दर्शवण्यासाठी वापरले असले तरी, ते एक स्ट्रिंग ऑब्जेक्ट आहे आणि pandas च्या दृष्टीने null चे प्रतिनिधित्व नाही.\n", "\n", - "आता, हे उलट करून पाहूया आणि या पद्धती अधिक व्यावहारिक पद्धतीने वापरूया. Boolean मास्कचा वापर थेट ``Series`` किंवा ``DataFrame`` इंडेक्स म्हणून करता येतो, जे गहाळ (किंवा उपस्थित) मूल्यांसोबत काम करताना उपयुक्त ठरू शकते.\n", + "आता, हे उलटं करून पाहूया आणि या पद्धतींचा वापर जसा तुम्ही प्रत्यक्षात कराल तसा करूया. Boolean मास्कचा वापर थेट ``Series`` किंवा ``DataFrame`` इंडेक्स म्हणून करता येतो, जे गहाळ (किंवा विद्यमान) मूल्यांसोबत काम करताना उपयुक्त ठरू शकते.\n", "\n", - "जर आपल्याला गहाळ मूल्यांची एकूण संख्या हवी असेल, तर आपण `isnull()` पद्धतीने तयार केलेल्या मास्कवर फक्त एक sum करू शकतो.\n" + "जर आपल्याला गहाळ मूल्यांची एकूण संख्या हवी असेल, तर आपण `isnull()` पद्धतीने तयार केलेल्या मास्कवर फक्त sum करू शकतो.\n" ] }, { @@ -1008,7 +1016,9 @@ "metadata": { "id": "PlBqEo3mgRsC" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -1029,7 +1039,9 @@ "metadata": { "id": "D_jWN7mHgRsD" }, - "source": [] + "source": [ + "**महत्त्वाचा मुद्दा**: `isnull()` आणि `notnull()` या दोन्ही पद्धती DataFrames मध्ये वापरल्यास समान परिणाम देतात: त्या परिणाम आणि त्या परिणामांचे निर्देशांक दाखवतात, जे तुम्हाला तुमच्या डेटासह काम करताना खूप मदत करतील.\n" + ] }, { "cell_type": "markdown", @@ -1039,18 +1051,18 @@ "source": [ "### हरवलेल्या डेटाशी सामना करणे\n", "\n", - "> **शिकण्याचे उद्दिष्ट:** या उपविभागाच्या शेवटी, तुम्हाला DataFrames मधून null मूल्ये कधी आणि कशा प्रकारे बदलायच्या किंवा काढून टाकायच्या हे माहित असावे.\n", + "> **शिकण्याचे उद्दिष्ट:** या उपविभागाच्या शेवटी, तुम्हाला DataFrames मधून null मूल्ये कधी आणि कशी बदलायची किंवा काढायची हे माहित असावे.\n", "\n", - "मशीन लर्निंग मॉडेल्स स्वतः हरवलेल्या डेटाशी सामना करू शकत नाहीत. त्यामुळे, डेटाला मॉडेलमध्ये पाठवण्यापूर्वी, आपल्याला या हरवलेल्या मूल्यांशी सामना करावा लागतो.\n", + "मशीन लर्निंग मॉडेल्स स्वतः हरवलेल्या डेटाशी सामना करू शकत नाहीत. त्यामुळे, डेटा मॉडेलमध्ये पाठवण्यापूर्वी, आपल्याला या हरवलेल्या मूल्यांशी सामना करावा लागतो.\n", "\n", - "हरवलेल्या डेटाशी कसे व्यवहार करायचे यामध्ये सूक्ष्म समतोल असतो, जो तुमच्या अंतिम विश्लेषणावर आणि प्रत्यक्ष परिणामांवर प्रभाव टाकू शकतो.\n", + "हरवलेल्या डेटाशी कसे व्यवहार करायचे यामध्ये सूक्ष्म तडजोडी असतात, ज्याचा तुमच्या अंतिम विश्लेषणावर आणि वास्तविक जगातील परिणामांवर प्रभाव पडू शकतो.\n", "\n", - "हरवलेल्या डेटाशी व्यवहार करण्याचे मुख्यतः दोन मार्ग आहेत:\n", + "हरवलेल्या डेटाशी सामना करण्याचे मुख्यतः दोन मार्ग आहेत:\n", "\n", "1. हरवलेल्या मूल्य असलेली पंक्ती काढून टाका\n", "2. हरवलेल्या मूल्याला दुसऱ्या काही मूल्याने बदला\n", "\n", - "आपण या दोन्ही पद्धती आणि त्यांचे फायदे व तोटे सविस्तरपणे चर्चा करू.\n" + "आम्ही या दोन्ही पद्धती आणि त्यांचे फायदे व तोटे सविस्तरपणे चर्चा करू.\n" ] }, { @@ -1059,13 +1071,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### शून्य मूल्ये काढून टाकणे\n", + "### शून्य मूल्य काढून टाकणे\n", "\n", - "आपल्या मॉडेलला दिलेल्या डेटाचा प्रमाण त्याच्या कार्यक्षमतेवर थेट परिणाम करतो. शून्य मूल्ये काढून टाकणे म्हणजे आपण डेटापॉइंट्सची संख्या कमी करत आहोत, आणि त्यामुळे डेटासेटचा आकार कमी होत आहे. त्यामुळे, जेव्हा डेटासेट खूप मोठा असेल तेव्हा शून्य मूल्य असलेल्या रांगा काढून टाकणे योग्य ठरते.\n", + "आपण आपल्या मॉडेलला जितका डेटा पुरवतो, त्याचा त्याच्या कार्यक्षमतेवर थेट परिणाम होतो. शून्य मूल्ये काढून टाकणे म्हणजे आपण डेटापॉइंट्सची संख्या कमी करत आहोत आणि त्यामुळे डेटासेटचा आकारही कमी होत आहे. त्यामुळे, जेव्हा डेटासेट खूप मोठा असेल, तेव्हा शून्य मूल्य असलेल्या रकाने काढून टाकणे योग्य ठरते.\n", "\n", - "आणखी एक उदाहरण म्हणजे एखाद्या विशिष्ट रांगेत किंवा स्तंभात खूपच गहाळ मूल्ये असतील. अशा वेळी ती रांगा किंवा स्तंभ काढून टाकले जाऊ शकतात कारण त्या विशिष्ट रांगेतील/स्तंभातील बहुतेक डेटा गहाळ असल्यामुळे त्याचा आपल्या विश्लेषणात फारसा उपयोग होणार नाही.\n", + "आणखी एक उदाहरण म्हणजे एखाद्या विशिष्ट रकान्यात किंवा स्तंभात खूप शून्य मूल्ये असणे. अशावेळी, ती रकाने किंवा स्तंभ काढून टाकले जाऊ शकतात कारण त्या रकान्यात/स्तंभात बहुतेक डेटा गहाळ असल्यामुळे ते आपल्या विश्लेषणात फारसा उपयोगी ठरणार नाहीत.\n", "\n", - "गहाळ मूल्ये ओळखण्याच्या पलीकडे, pandas शून्य मूल्ये `Series` आणि `DataFrame`s मधून काढून टाकण्यासाठी सोयीस्कर साधन उपलब्ध करून देते. हे प्रत्यक्षात कसे कार्य करते ते पाहण्यासाठी आपण `example3` कडे परत जाऊ. `DataFrame.dropna()` फंक्शन शून्य मूल्य असलेल्या रांगा काढून टाकण्यासाठी मदत करते.\n" + "गहाळ मूल्ये ओळखण्यापलीकडे, pandas `Series` आणि `DataFrame`s मधून शून्य मूल्ये काढून टाकण्यासाठी सोयीस्कर साधन उपलब्ध करून देते. हे प्रत्यक्षात कसे कार्य करते ते पाहण्यासाठी, आपण `example3` कडे परत जाऊ. `DataFrame.dropna()` फंक्शन शून्य मूल्य असलेल्या रकाने काढून टाकण्यासाठी मदत करते.\n" ] }, { @@ -1104,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "लक्षात ठेवा की हे तुमच्या `example3[example3.notnull()]` च्या आउटपुटसारखे दिसले पाहिजे. येथे फरक असा आहे की, फक्त मास्क केलेल्या मूल्यांवर इंडेक्सिंग करण्याऐवजी, `dropna` ने `Series` `example3` मधून ती गहाळ मूल्ये काढून टाकली आहेत.\n", + "लक्षात घ्या की हे तुमच्या `example3[example3.notnull()]` च्या आउटपुटसारखे दिसले पाहिजे. येथे फरक असा आहे की, फक्त मास्क केलेल्या मूल्यांवर इंडेक्सिंग करण्याऐवजी, `dropna` ने `Series` `example3` मधील ती गहाळ मूल्ये काढून टाकली आहेत.\n", "\n", - "कारण DataFrames दोन परिमाण असतात, ते डेटा काढण्यासाठी अधिक पर्याय उपलब्ध करून देतात.\n" + "कारण DataFrames दोन परिमाण असतात, त्यामुळे डेटा काढून टाकण्यासाठी अधिक पर्याय उपलब्ध होतात.\n" ] }, { @@ -1196,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(तुम्ही लक्षात घेतले का की pandas ने `NaN`s समाविष्ट करण्यासाठी दोन स्तंभांना floats मध्ये बदलले?)\n", + "(आपण लक्षात घेतले का की pandas ने `NaN`s accommodate करण्यासाठी दोन स्तंभ float मध्ये बदलले?)\n", "\n", - "तुम्ही `DataFrame` मधून एकच मूल्य काढून टाकू शकत नाही, त्यामुळे तुम्हाला पूर्ण रांगा किंवा स्तंभ काढून टाकावे लागतील. तुम्ही काय करत आहात यावर अवलंबून, तुम्हाला एक पर्याय निवडायचा असेल, आणि म्हणूनच pandas तुम्हाला दोन्ही पर्याय उपलब्ध करून देते. कारण डेटा सायन्समध्ये, स्तंभ सामान्यतः variables चे प्रतिनिधित्व करतात आणि रांगा observations चे प्रतिनिधित्व करतात, त्यामुळे तुम्ही डेटा रांगा काढून टाकण्याची अधिक शक्यता असते; `dropna()` साठी डिफॉल्ट सेटिंग म्हणजे ज्या रांगांमध्ये कोणतीही null values असतील त्या सर्व रांगा काढून टाकणे:\n" + "आपण `DataFrame` मधून एकच मूल्य काढून टाकू शकत नाही, त्यामुळे आपल्याला संपूर्ण पंक्ती किंवा स्तंभ काढून टाकावे लागतील. आपण काय करत आहात यावर अवलंबून, आपल्याला एक किंवा दुसरे करायचे असू शकते, आणि म्हणून pandas आपल्याला दोन्ही पर्याय देतो. कारण डेटा सायन्समध्ये, स्तंभ सामान्यतः बदल दर्शवतात आणि पंक्ती निरीक्षणे दर्शवतात, आपण डेटा पंक्ती काढून टाकण्याची अधिक शक्यता असते; `dropna()` साठी डिफॉल्ट सेटिंग म्हणजे अशा सर्व पंक्ती काढून टाकणे ज्यामध्ये कोणतीही null मूल्ये असतात:\n" ] }, { @@ -1350,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "लक्षात ठेवा की हे लहान डेटासेट्समध्ये विशेषतः तुम्हाला ठेवायची असलेली बरीच डेटा गमावू शकते. जर तुम्हाला फक्त अशा पंक्ती किंवा स्तंभ काढून टाकायचे असतील ज्यामध्ये अनेक किंवा अगदी सर्व null मूल्ये असतील तर काय कराल? तुम्ही `dropna` मध्ये `how` आणि `thresh` पॅरामीटर्स वापरून ती सेटिंग्ज निर्दिष्ट करू शकता.\n", + "लक्षात घ्या की यामुळे तुम्हाला ठेवायचा असलेला डेटा, विशेषतः लहान डेटासेटमध्ये, मोठ्या प्रमाणात गमवावा लागू शकतो. जर तुम्हाला फक्त अशा पंक्ती किंवा स्तंभ काढून टाकायचे असतील ज्यामध्ये अनेक किंवा अगदी सर्व null मूल्ये असतील, तर तुम्ही `dropna` मध्ये `how` आणि `thresh` पॅरामीटर्स सेट करू शकता.\n", "\n", - "डिफॉल्टनुसार, `how='any'` असते (जर तुम्हाला स्वतः तपासायचे असेल किंवा या पद्धतीमध्ये इतर कोणते पॅरामीटर्स आहेत ते पाहायचे असेल, तर कोड सेलमध्ये `example4.dropna?` चालवा). पर्यायाने, तुम्ही `how='all'` निर्दिष्ट करू शकता, ज्यामुळे फक्त अशा पंक्ती किंवा स्तंभ काढून टाकले जातील ज्यामध्ये सर्व null मूल्ये असतील. पुढील व्यायामामध्ये हे कृतीत पाहण्यासाठी आपण आपले उदाहरण `DataFrame` विस्तृत करूया.\n" + "डिफॉल्टनुसार, `how='any'` असते (जर तुम्हाला स्वतः तपासायचे असेल किंवा या मेथडमध्ये कोणते इतर पॅरामीटर्स आहेत ते पाहायचे असेल, तर कोड सेलमध्ये `example4.dropna?` चालवा). पर्यायाने, तुम्ही `how='all'` असे सेट करू शकता, ज्यामुळे फक्त अशा पंक्ती किंवा स्तंभ काढून टाकले जातील ज्यामध्ये सर्व null मूल्ये असतील. पुढील व्यायामात हे प्रत्यक्षात कसे कार्य करते ते पाहण्यासाठी आपण आपले उदाहरण `DataFrame` विस्तृत करूया.\n" ] }, { @@ -1444,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "महत्त्वाचे मुद्दे: \n", - "1. फक्त डेटासेट पुरेसा मोठा असेल तेव्हाच null मूल्ये काढून टाकणे चांगला पर्याय आहे. \n", - "2. पूर्ण रांगा किंवा स्तंभ काढून टाकता येतात जर त्यामध्ये बहुतेक डेटा गायब असेल. \n", - "3. `DataFrame.dropna(axis=)` पद्धत null मूल्ये काढून टाकण्यासाठी मदत करते. `axis` युक्तिवाद सूचित करतो की रांगा काढून टाकायच्या आहेत की स्तंभ. \n", - "4. `how` युक्तिवाद देखील वापरता येतो. डीफॉल्टनुसार ते `any` वर सेट केलेले असते. त्यामुळे, फक्त त्या रांगा/स्तंभ काढून टाकले जातात ज्यामध्ये कोणतेही null मूल्य असते. ते `all` वर सेट करता येते ज्यामुळे आपण फक्त त्या रांगा/स्तंभ काढून टाकतो जिथे सर्व मूल्ये null असतात. \n" + "> मुख्य मुद्दे:\n", + "1. डेटासेट पुरेसा मोठा असेल तेव्हाच null मूल्ये काढून टाकणे योग्य ठरते.\n", + "2. पूर्ण रांगा किंवा स्तंभ काढून टाकता येतात जर त्यामध्ये बहुतेक डेटा गायब असेल.\n", + "3. `DataFrame.dropna(axis=)` पद्धत null मूल्ये काढून टाकण्यासाठी मदत करते. `axis` युक्तिवाद सूचित करतो की रांगा काढून टाकायच्या आहेत की स्तंभ.\n", + "4. `how` युक्तिवाद देखील वापरता येतो. डीफॉल्टनुसार ते `any` वर सेट केलेले असते. त्यामुळे, फक्त त्या रांगा/स्तंभ काढून टाकले जातात ज्यामध्ये कोणतेही null मूल्ये असतात. ते `all` वर सेट करून आपण फक्त त्या रांगा/स्तंभ काढून टाकू शकतो जिथे सर्व मूल्ये null आहेत.\n" ] }, { @@ -1456,7 +1468,9 @@ "metadata": { "id": "oXXSfQFHgRsF" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -1478,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "`thresh` पॅरामीटर तुम्हाला अधिक सूक्ष्म नियंत्रण देते: तुम्ही सेट करता की एखाद्या पंक्ती किंवा स्तंभामध्ये टिकून राहण्यासाठी किती *नॉन-नल* मूल्ये असावीत:\n" + "`thresh` पॅरामीटर तुम्हाला अधिक सूक्ष्म नियंत्रण देते: तुम्ही सेट करता की एखाद्या पंक्ती किंवा स्तंभामध्ये ठेवण्यासाठी किती *नॉन-नल* मूल्ये असणे आवश्यक आहे:\n" ] }, { @@ -1552,7 +1566,9 @@ "metadata": { "id": "fmSFnzZegRsG" }, - "source": [] + "source": [ + "येथे, पहिली आणि शेवटची ओळ वगळली गेली आहे, कारण त्यामध्ये फक्त दोन नॉन-नल मूल्ये आहेत.\n" + ] }, { "cell_type": "markdown", @@ -1560,11 +1576,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### शून्य मूल्ये भरणे\n", + "### रिक्त मूल्ये भरणे\n", "\n", - "कधी कधी हरवलेली मूल्ये अशा मूल्यांनी भरल्याने अर्थपूर्ण होऊ शकते जी वैध असू शकतात. शून्य मूल्ये भरण्यासाठी काही तंत्रे आहेत. पहिले तंत्र म्हणजे डोमेन ज्ञानाचा (डेटासेट ज्या विषयावर आधारित आहे त्या विषयाचे ज्ञान) वापर करून हरवलेल्या मूल्यांचा अंदाज लावणे.\n", + "कधी कधी हरवलेल्या मूल्यांना अशा मूल्यांनी भरणे योग्य ठरते जे वैध असू शकतात. रिक्त मूल्ये भरण्यासाठी काही तंत्रे आहेत. पहिले तंत्र म्हणजे डोमेन ज्ञान (डेटासेट ज्या विषयावर आधारित आहे त्याचे ज्ञान) वापरून हरवलेल्या मूल्यांचा अंदाज लावणे.\n", "\n", - "तुम्ही `isnull` वापरून हे थेट करू शकता, परंतु जर तुम्हाला भरायची बरीच मूल्ये असतील तर ते श्रमदायक ठरू शकते. कारण डेटा सायन्समध्ये हे एक सामान्य कार्य आहे, pandas `fillna` प्रदान करते, जे `Series` किंवा `DataFrame` ची एक प्रत परत करते, ज्यामध्ये हरवलेली मूल्ये तुमच्या निवडीच्या मूल्यांनी बदललेली असतात. हे प्रत्यक्षात कसे कार्य करते हे पाहण्यासाठी आणखी एक उदाहरण `Series` तयार करूया.\n" + "तुम्ही `isnull` वापरून हे थेट करू शकता, परंतु जर तुम्हाला भरायची अनेक मूल्ये असतील तर ते श्रमसाध्य होऊ शकते. कारण डेटा सायन्समध्ये ही एक सामान्य प्रक्रिया आहे, pandas `fillna` प्रदान करते, जे `Series` किंवा `DataFrame` ची एक प्रत परत करते ज्यामध्ये हरवलेली मूल्ये तुमच्या निवडीच्या मूल्यांनी बदललेली असतात. हे प्रत्यक्षात कसे कार्य करते हे पाहण्यासाठी आणखी एक उदाहरण `Series` तयार करूया.\n" ] }, { @@ -1574,11 +1590,11 @@ }, "source": [ "### श्रेणीसंबंधी डेटा (असंख्यात्मक)\n", - "सुरुवातीला आपण असंख्यात्मक डेटाचा विचार करूया. डेटासेट्समध्ये, आपल्याकडे श्रेणीसंबंधी डेटासह स्तंभ असतात. उदा. लिंग, True किंवा False इत्यादी.\n", + "सुरुवातीला आपण असंख्यात्मक डेटा विचारात घेऊ. डेटासेटमध्ये, आपल्याकडे श्रेणीसंबंधी डेटा असलेले स्तंभ असतात. उदा. लिंग, खरे किंवा खोटे इत्यादी.\n", "\n", - "बहुतेक या प्रकरणांमध्ये, आपण गहाळ मूल्ये त्या स्तंभाच्या `mode` ने बदलतो. समजा, आपल्याकडे 100 डेटा पॉइंट्स आहेत आणि त्यापैकी 90 जणांनी True म्हटले आहे, 8 जणांनी False म्हटले आहे आणि 2 जणांनी काहीही भरलेले नाही. तर, आपण त्या 2 गहाळ मूल्यांना True ने भरू शकतो, पूर्ण स्तंभाचा विचार करून.\n", + "बहुतेक वेळा, अशा परिस्थितीत, आम्ही गहाळ मूल्ये त्या स्तंभाच्या `mode` ने बदलतो. उदाहरणार्थ, आपल्याकडे 100 डेटा पॉइंट्स आहेत आणि त्यापैकी 90 जणांनी खरे म्हटले आहे, 8 जणांनी खोटे म्हटले आहे आणि 2 जणांनी काहीही भरलेले नाही. अशा वेळी, आपण त्या 2 गहाळ मूल्यांना खरेने भरू शकतो, संपूर्ण स्तंभ विचारात घेऊन.\n", "\n", - "पुन्हा, येथे आपण डोमेन ज्ञानाचा उपयोग करू शकतो. `mode` ने भरल्याचा एक उदाहरण विचार करूया.\n" + "पुन्हा, येथे आपण डोमेन ज्ञानाचा उपयोग करू शकतो. `mode` ने भरल्याचा एक उदाहरण विचार करू.\n" ] }, { @@ -1683,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "आता, प्रथम `None` मूल्य मोडने भरून टाकण्यापूर्वी मोड शोधूया.\n" + ] }, { "cell_type": "code", @@ -1718,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "म्हणून, आम्ही None च्या जागी True ठेवू.\n" + ] }, { "cell_type": "code", @@ -1827,7 +1847,9 @@ "metadata": { "id": "SktitLxxOR16" }, - "source": [] + "source": [ + "जसे आपण पाहू शकतो, null मूल्य बदलले गेले आहे. निःसंशयपणे, आपण `'True'` च्या जागी काहीही लिहू शकतो आणि ते बदलले जाईल.\n" + ] }, { "cell_type": "markdown", @@ -1836,16 +1858,16 @@ }, "source": [ "### संख्यात्मक डेटा\n", - "आता, संख्यात्मक डेटाकडे वळूया. येथे, गहाळ मूल्ये भरण्यासाठी दोन सामान्य पद्धती आहेत:\n", + "आता, संख्यात्मक डेटाकडे वळूया. येथे, गहाळ मूल्ये बदलण्यासाठी दोन सामान्य पद्धती आहेत:\n", "\n", - "1. पंक्तीच्या माध्यिका (Median) ने भरणे \n", - "2. पंक्तीच्या सरासरी (Mean) ने भरणे \n", + "1. पंक्तीच्या माध्याने बदलणे \n", + "2. पंक्तीच्या सरासरीने बदलणे \n", "\n", - "जर डेटा विसंगत (skewed) असेल आणि त्यात बाहेरच्या मूल्यांचा (outliers) समावेश असेल, तर आपण माध्यिका वापरतो. कारण माध्यिका बाहेरच्या मूल्यांमुळे प्रभावित होत नाही.\n", + "आम्ही माध्याने बदलतो, जेव्हा डेटा आउटलायर्ससह तिर्यक असतो. कारण माध्य आउटलायर्ससाठी मजबूत असते.\n", "\n", - "जेव्हा डेटा सामान्यीकृत (normalized) असतो, तेव्हा आपण सरासरी वापरू शकतो, कारण अशा परिस्थितीत सरासरी आणि माध्यिका जवळजवळ सारखीच असते.\n", + "जेव्हा डेटा सामान्यीकृत (normalized) असतो, तेव्हा आपण सरासरी वापरू शकतो, कारण अशा परिस्थितीत सरासरी आणि माध्य जवळजवळ समान असतात.\n", "\n", - "सुरुवातीला, आपण एक स्तंभ घेऊ जो सामान्य वितरणात (normally distributed) आहे आणि त्या स्तंभातील गहाळ मूल्य सरासरीने भरूया.\n" + "सर्वप्रथम, आपण एक स्तंभ घेऊ जो सामान्य वितरणात आहे आणि त्या स्तंभाच्या सरासरीने गहाळ मूल्य भरूया.\n" ] }, { @@ -1985,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "मध्यमाने भरत आहे\n" + ] }, { "cell_type": "code", @@ -2084,7 +2108,9 @@ "metadata": { "id": "CwpVFCrPTC5z" }, - "source": [] + "source": [ + "जसे आपण पाहू शकतो, गहाळ मूल्य त्याच्या सरासरीने बदलले गेले आहे.\n" + ] }, { "cell_type": "markdown", @@ -2092,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "आता आपण दुसरा डेटा फ्रेम वापरूया, आणि यावेळी आपण None मूल्ये स्तंभाच्या मध्यमानाने बदलू.\n" + "आता आपण दुसरा डेटा फ्रेम वापरूया, आणि यावेळी आम्ही None मूल्ये स्तंभाच्या मध्यमानाने बदलू.\n" ] }, { @@ -2232,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "मध्यक मूल्याने भरत आहे\n" + ] }, { "cell_type": "code", @@ -2332,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "जसे आपण पाहू शकतो, NaN मूल्य स्तंभाच्या मध्यमाने बदलले गेले आहे\n" + "जसे आपण पाहू शकतो, NaN मूल्य स्तंभाच्या मध्यमाने बदलले गेले आहे.\n" ] }, { @@ -2374,7 +2402,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "तुम्ही सर्व रिक्त नोंदी एका मूल्याने भरू शकता, जसे की `0`:\n" + "आपण सर्व रिक्त नोंदी एका मूल्याने भरू शकता, जसे की `0`:\n" ] }, { @@ -2416,10 +2444,10 @@ }, "source": [ "> मुख्य मुद्दे:\n", - "1. हरवलेली मूल्ये भरून काढणे तेव्हाच करावे जेव्हा डेटा कमी असेल किंवा हरवलेल्या डेटासाठी एखादी ठराविक पद्धत असेल.\n", - "2. हरवलेली मूल्ये अंदाजाने भरून काढण्यासाठी डोमेन ज्ञानाचा उपयोग केला जाऊ शकतो.\n", - "3. श्रेणीसंबंधित (Categorical) डेटासाठी, प्रामुख्याने, हरवलेली मूल्ये त्या स्तंभाच्या मोडने (mode) भरली जातात.\n", - "4. संख्यात्मक (Numeric) डेटासाठी, हरवलेली मूल्ये सहसा स्तंभाच्या सरासरीने (mean - जर डेटासेट सामान्यीकृत असेल) किंवा मध्यकाने (median) भरली जातात.\n" + "1. गहाळ मूल्ये भरताना तेव्हा करावे जेव्हा डेटा कमी असेल किंवा गहाळ डेटा भरण्याची काही रणनीती असेल.\n", + "2. गहाळ मूल्ये अंदाजे भरण्यासाठी डोमेन ज्ञानाचा उपयोग केला जाऊ शकतो.\n", + "3. श्रेणीबद्ध डेटासाठी, प्रामुख्याने, गहाळ मूल्ये स्तंभाच्या मोडने बदलली जातात.\n", + "4. संख्यात्मक डेटासाठी, गहाळ मूल्ये सामान्यतः स्तंभांच्या सरासरी (सामान्यीकृत डेटासेटसाठी) किंवा माध्याने भरली जातात.\n" ] }, { @@ -2427,7 +2455,9 @@ "metadata": { "id": "FI9MmqFJgRsH" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -2447,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "आपण **फॉरवर्ड-फिल** शून्य मूल्ये करू शकता, म्हणजेच शेवटच्या वैध मूल्याचा वापर करून शून्य भरू शकता:\n" + ] }, { "cell_type": "code", @@ -2487,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "तुम्ही पुढील वैध मूल्य मागे नेऊन रिक्त जागा भरू शकता:\n" + "तुम्ही null भरण्यासाठी पुढील वैध मूल्य मागे नेऊन **back-fill** देखील करू शकता:\n" ] }, { @@ -2529,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "तुम्ही अंदाज लावू शकता, हे DataFrames सोबत देखील तसेच कार्य करते, परंतु तुम्ही null मूल्ये भरण्यासाठी कोणता `axis` निवडायचा आहे ते देखील निर्दिष्ट करू शकता:\n" + "जसे तुम्ही अंदाज लावू शकता, हे DataFrames सोबत देखील तसेच कार्य करते, परंतु तुम्ही null मूल्ये भरण्यासाठी `axis` देखील निर्दिष्ट करू शकता:\n" ] }, { @@ -2701,14 +2733,18 @@ "metadata": { "id": "ZeMc-I1EgRsI" }, - "source": [] + "source": [ + "लक्षात घ्या की जेव्हा पूर्वीचे मूल्य पुढे भरण्यासाठी उपलब्ध नसते, तेव्हा रिक्त मूल्य तसेच राहते.\n" + ] }, { "cell_type": "markdown", "metadata": { "id": "eeAoOU0RgRsJ" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -2731,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "आपण `fillna` कसा वापरता याबद्दल सर्जनशील होऊ शकता. उदाहरणार्थ, पुन्हा `example4` पाहूया, पण यावेळी `DataFrame` मधील सर्व मूल्यांचा सरासरी वापरून गहाळ मूल्ये भरूया:\n" + "आपण `fillna` कसे वापरता याबद्दल सर्जनशील होऊ शकता. उदाहरणार्थ, पुन्हा `example4` पाहूया, पण यावेळी `DataFrame` मधील सर्व मूल्यांचा सरासरी वापरून गहाळ मूल्ये भरूया:\n" ] }, { @@ -2822,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "लक्षात घ्या की स्तंभ 3 अजूनही रिक्त आहे: डीफॉल्ट दिशा म्हणजे मूल्ये पंक्तीनुसार भरणे.\n", + "लक्षात घ्या की स्तंभ 3 अजूनही रिक्त आहे: डीफॉल्ट दिशा म्हणजे मूल्ये पंक्तीवार भरणे.\n", "\n", - "> **महत्त्वाचा मुद्दा:** तुमच्या डेटासेटमधील हरवलेल्या मूल्यांशी व्यवहार करण्याचे अनेक मार्ग आहेत. तुम्ही वापरलेली विशिष्ट रणनीती (त्यांना काढून टाकणे, त्यांची जागा घेणे, किंवा त्यांना कसे बदलायचे) त्या डेटाच्या विशिष्ट तपशीलांवर अवलंबून असावी. तुम्ही जितके अधिक डेटासेट हाताळाल आणि त्यांच्याशी संवाद साधाल तितके हरवलेल्या मूल्यांशी व्यवहार करण्याची चांगली समज विकसित होईल.\n" + "> **महत्त्वाचे:** तुमच्या डेटासेटमधील हरवलेल्या मूल्यांशी व्यवहार करण्याचे अनेक मार्ग आहेत. तुम्ही वापरलेली विशिष्ट रणनीती (त्यांना काढून टाकणे, त्यांची जागा घेणे, किंवा त्यांना कसे बदलायचे) त्या डेटाच्या विशिष्टतेनुसार ठरवली पाहिजे. तुम्ही जितके अधिक डेटासेट हाताळाल आणि त्यांच्याशी संवाद साधाल तितके हरवलेल्या मूल्यांशी व्यवहार करण्याची चांगली समज विकसित होईल.\n" ] }, { @@ -2835,9 +2871,9 @@ "source": [ "### श्रेणीसंबंधी डेटा एन्कोड करणे\n", "\n", - "मशीन लर्निंग मॉडेल्स केवळ संख्यात्मक डेटा आणि कोणत्याही स्वरूपातील संख्यांशीच व्यवहार करू शकतात. ते \"हो\" आणि \"नाही\" यामधील फरक ओळखू शकत नाहीत, परंतु 0 आणि 1 यामधील फरक ओळखू शकतात. त्यामुळे, गहाळ मूल्ये भरल्यानंतर, आपल्याला श्रेणीसंबंधी डेटाचे एन्कोडिंग करून ते संख्यात्मक स्वरूपात रूपांतरित करावे लागते, जेणेकरून मॉडेलला ते समजू शकेल.\n", + "मशीन लर्निंग मॉडेल्स फक्त संख्यात्मक डेटा आणि कोणत्याही प्रकारच्या संख्यात्मक माहितीशी व्यवहार करतात. ते \"होय\" आणि \"नाही\" यामधील फरक ओळखू शकत नाहीत, परंतु ते 0 आणि 1 मधील फरक ओळखू शकतील. त्यामुळे, गहाळ मूल्ये भरल्यानंतर, आपल्याला श्रेणीसंबंधी डेटा काही संख्यात्मक स्वरूपात एन्कोड करणे आवश्यक आहे जेणेकरून मॉडेलला ते समजेल.\n", "\n", - "एन्कोडिंग दोन प्रकारे करता येते. पुढील भागात आपण त्याबद्दल चर्चा करू.\n" + "एन्कोडिंग दोन प्रकारे करता येते. पुढे आपण त्याबद्दल चर्चा करू.\n" ] }, { @@ -2848,7 +2884,7 @@ "source": [ "**लेबल एन्कोडिंग**\n", "\n", - "लेबल एन्कोडिंग म्हणजे प्रत्येक श्रेणीला एका क्रमांकात रूपांतरित करणे. उदाहरणार्थ, समजा आपल्याकडे विमान प्रवाशांचा डेटासेट आहे आणि त्यामध्ये त्यांच्या वर्गाबद्दलची ['बिझनेस क्लास', 'इकॉनॉमी क्लास', 'फर्स्ट क्लास'] अशी माहिती असलेली एक स्तंभ आहे. जर यावर लेबल एन्कोडिंग केले, तर हे [0, 1, 2] मध्ये रूपांतरित होईल. चला, कोडच्या माध्यमातून एक उदाहरण पाहूया. पुढील नोटबुक्समध्ये आपण `scikit-learn` शिकणार असल्याने, येथे आपण ते वापरणार नाही.\n" + "लेबल एन्कोडिंग म्हणजे प्रत्येक श्रेणीला एका संख्येमध्ये रूपांतरित करणे. उदाहरणार्थ, समजा आपल्याकडे विमान प्रवाशांचा डेटासेट आहे आणि त्यामध्ये त्यांच्या वर्गाची माहिती असलेला एक स्तंभ आहे ['बिझनेस क्लास', 'इकॉनॉमी क्लास', 'फर्स्ट क्लास']. जर लेबल एन्कोडिंग केले गेले, तर हे [0,1,2] मध्ये रूपांतरित होईल. चला कोडच्या माध्यमातून एक उदाहरण पाहूया. कारण आपण पुढील नोटबुक्समध्ये `scikit-learn` शिकणार आहोत, त्यामुळे येथे आपण ते वापरणार नाही.\n" ] }, { @@ -2956,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "पहिल्या स्तंभावर लेबल एन्कोडिंग करण्यासाठी, प्रत्येक वर्गासाठी एका क्रमांकाचा नकाशा प्रथम तयार करावा लागतो, त्यानंतर बदल करावा लागतो.\n" + "पहिल्या स्तंभावर लेबल एन्कोडिंग करण्यासाठी, प्रत्येक वर्गासाठी एका संख्येची मॅपिंग तयार करावी लागते, त्यानंतर बदल करावा लागतो.\n" ] }, { @@ -3058,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "जसे आपण पाहतो, आउटपुट आपल्या अपेक्षेनुसार आहे. तर, लेबल एन्कोडिंग कधी वापरावे? लेबल एन्कोडिंग खालीलपैकी एक किंवा दोन्ही परिस्थितींमध्ये वापरले जाते:\n", - "1. जेव्हा श्रेणींची संख्या मोठी असते\n", - "2. जेव्हा श्रेणी क्रमाने असतात.\n" + "जसे आपण पाहतो, आउटपुट आपल्या अपेक्षेनुसार आहे. तर, लेबल एन्कोडिंग कधी वापरावे? लेबल एन्कोडिंग खालीलपैकी एक किंवा दोन्ही परिस्थितींमध्ये वापरले जाते: \n", + "1. जेव्हा श्रेणींची संख्या मोठी असते \n", + "2. जेव्हा श्रेण्या क्रमाने असतात. \n" ] }, { @@ -3069,11 +3105,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**वन हॉट एन्कोडिंग**\n", + "**वन हॉट एनकोडिंग**\n", "\n", - "वन हॉट एन्कोडिंग हा एन्कोडिंगचा आणखी एक प्रकार आहे. या प्रकारात, कॉलममधील प्रत्येक श्रेणीसाठी स्वतंत्र कॉलम तयार केला जातो आणि प्रत्येक डेटापॉईंटला त्या श्रेणीमध्ये आहे की नाही यावर आधारित 0 किंवा 1 दिले जाते. त्यामुळे, जर n वेगवेगळ्या श्रेण्या असतील, तर n कॉलम डेटा फ्रेममध्ये जोडले जातील.\n", + "एनकोडिंगचा आणखी एक प्रकार म्हणजे वन हॉट एनकोडिंग. या प्रकारात, कॉलममधील प्रत्येक श्रेणीसाठी स्वतंत्र कॉलम जोडला जातो आणि प्रत्येक डेटा पॉइंटमध्ये त्या श्रेणीचा समावेश आहे की नाही यावर आधारित 0 किंवा 1 दिला जातो. त्यामुळे, जर n वेगवेगळ्या श्रेण्या असतील, तर n कॉलम डेटा फ्रेममध्ये जोडले जातील.\n", "\n", - "उदाहरणार्थ, आपण पुन्हा विमानाच्या वर्गाचे उदाहरण घेऊ. श्रेण्या होत्या: ['बिझनेस क्लास', 'इकॉनॉमी क्लास', 'फर्स्ट क्लास']. त्यामुळे, जर आपण वन हॉट एन्कोडिंग केले, तर खालील तीन कॉलम डेटासेटमध्ये जोडले जातील: ['class_business class', 'class_economy class', 'class_first class'].\n" + "उदाहरणार्थ, आपण पुन्हा विमानाच्या वर्गाचे उदाहरण घेऊ. श्रेण्या होत्या: ['बिझनेस क्लास', 'इकॉनॉमी क्लास', 'फर्स्ट क्लास']. त्यामुळे, जर आपण वन हॉट एनकोडिंग केले, तर खालील तीन कॉलम डेटासेटमध्ये जोडले जातील: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3306,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "प्रत्येक वन-हॉट एन्कोडेड स्तंभामध्ये 0 किंवा 1 असतो, जो दर्शवतो की त्या डेटापॉइंटसाठी ती श्रेणी अस्तित्वात आहे का.\n" + "प्रत्येक वन हॉट एन्कोड केलेल्या स्तंभामध्ये 0 किंवा 1 असते, जे त्या डेटापॉइंटसाठी ती श्रेणी अस्तित्वात आहे की नाही हे निर्दिष्ट करते.\n" ] }, { @@ -3315,7 +3351,7 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "वन हॉट एन्कोडिंग कधी वापरतो? वन हॉट एन्कोडिंग खालीलपैकी एक किंवा दोन्ही परिस्थितींमध्ये वापरले जाते :\n", + "आपण वन हॉट एन्कोडिंग कधी वापरतो? वन हॉट एन्कोडिंग खालीलपैकी एक किंवा दोन्ही परिस्थितींमध्ये वापरले जाते:\n", "\n", "1. जेव्हा श्रेणींची संख्या आणि डेटासेटचा आकार लहान असतो.\n", "2. जेव्हा श्रेणी कोणत्याही विशिष्ट क्रमाचे पालन करत नाहीत.\n" @@ -3328,8 +3364,8 @@ }, "source": [ "> मुख्य मुद्दे:\n", - "1. एनकोडिंगचा उपयोग संख्यात्मक नसलेल्या डेटाला संख्यात्मक डेटामध्ये रूपांतरित करण्यासाठी केला जातो.\n", - "2. एनकोडिंगचे दोन प्रकार आहेत: लेबल एनकोडिंग आणि वन हॉट एनकोडिंग, जे डेटासेटच्या गरजेनुसार केले जाऊ शकते.\n" + "1. संख्यात्मक नसलेल्या डेटाला संख्यात्मक डेटामध्ये रूपांतरित करण्यासाठी एन्कोडिंग केले जाते.\n", + "2. एन्कोडिंगचे दोन प्रकार आहेत: लेबल एन्कोडिंग आणि वन हॉट एन्कोडिंग, जे डेटासेटच्या गरजेनुसार केले जाऊ शकते.\n" ] }, { @@ -3342,7 +3378,7 @@ "\n", "> **शिकण्याचे उद्दिष्ट:** या उपविभागाच्या शेवटी, तुम्ही DataFrames मधून डुप्लिकेट मूल्ये ओळखण्यात आणि काढण्यात सहजतेने सक्षम असाल.\n", "\n", - "गहाळ डेटाच्या व्यतिरिक्त, तुम्हाला वास्तविक-जगातील डेटासेटमध्ये अनेकदा डुप्लिकेट डेटा देखील सापडतो. सुदैवाने, pandas डुप्लिकेट नोंदी शोधण्यासाठी आणि काढण्यासाठी सोपी पद्धत प्रदान करते.\n" + "गहाळ डेटाशिवाय, तुम्हाला वास्तविक जगातील डेटासेटमध्ये अनेकदा डुप्लिकेट डेटा सापडतो. सुदैवाने, pandas डुप्लिकेट नोंदी शोधण्यासाठी आणि काढण्यासाठी सोपी पद्धत प्रदान करते.\n" ] }, { @@ -3353,7 +3389,7 @@ "source": [ "### डुप्लिकेट ओळखणे: `duplicated`\n", "\n", - "तुम्ही pandas मधील `duplicated` पद्धतीचा वापर करून डुप्लिकेट मूल्ये सहज ओळखू शकता, जी Boolean मास्क परत करते, ज्यामध्ये `DataFrame` मधील एखादी नोंद यापूर्वीच्या नोंदीची डुप्लिकेट आहे का हे दर्शवले जाते. चला, हे कृतीत पाहण्यासाठी आणखी एक उदाहरण `DataFrame` तयार करूया.\n" + "तुम्ही pandas मधील `duplicated` पद्धतीचा वापर करून सहजपणे डुप्लिकेट मूल्ये ओळखू शकता, जी Boolean मास्क परत करते ज्यामध्ये एखादी नोंद `DataFrame` मध्ये आधीच्या नोंदीची डुप्लिकेट आहे का हे दर्शवले जाते. चला याचा उपयोग करून एक उदाहरण `DataFrame` तयार करूया.\n" ] }, { @@ -3483,7 +3519,7 @@ }, "source": [ "### डुप्लिकेट्स काढणे: `drop_duplicates`\n", - "`drop_duplicates` फक्त त्या डेटाची एक प्रत परत करते ज्यासाठी सर्व `duplicated` मूल्ये `False` असतात:\n" + "`drop_duplicates` फक्त अशा डेटाची प्रत परत करते ज्यासाठी सर्व `duplicated` मूल्ये `False` आहेत:\n" ] }, { @@ -3566,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "`duplicated` आणि `drop_duplicates` दोन्ही डीफॉल्टने सर्व स्तंभ विचारात घेतात, परंतु तुम्ही निर्दिष्ट करू शकता की ते तुमच्या `DataFrame` मधील केवळ एका उपसंच स्तंभांचा विचार करतील:\n" + "`duplicated` आणि `drop_duplicates` डिफॉल्टनं सर्व स्तंभ विचारात घेतात, पण तुम्ही तुमच्या `DataFrame` मधील स्तंभांचा उपसंच तपासण्यासाठी त्यांना निर्दिष्ट करू शकता:\n" ] }, { @@ -3642,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **महत्त्वाचे:** डुप्लिकेट डेटा काढून टाकणे हे जवळजवळ प्रत्येक डेटा-सायन्स प्रकल्पाचा महत्त्वाचा भाग आहे. डुप्लिकेट डेटा तुमच्या विश्लेषणाचे परिणाम बदलू शकतो आणि तुम्हाला चुकीचे परिणाम देऊ शकतो!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## वास्तविक-जगातील डेटा गुणवत्ता तपासणी\n", + "\n", + "> **शिकण्याचे उद्दिष्ट:** या विभागाच्या शेवटी, तुम्हाला असंगत श्रेणीमूल्ये, असामान्य संख्यात्मक मूल्ये (अत्युच्च मूल्ये), आणि थोड्या फरकांसह पुनरावृत्ती असलेल्या घटकांसह सामान्य डेटा गुणवत्ता समस्यांचे शोध आणि सुधार करण्याची सवय होईल.\n", + "\n", + "जरी गहाळ मूल्ये आणि अचूक पुनरावृत्ती सामान्य समस्या असल्या तरी, वास्तविक-जगातील डेटासेटमध्ये अधिक सूक्ष्म समस्या असतात:\n", + "\n", + "1. **असंगत श्रेणीमूल्ये**: समान श्रेणी वेगवेगळ्या प्रकारे लिहिलेली (उदा., \"USA\", \"U.S.A\", \"United States\")\n", + "2. **असामान्य संख्यात्मक मूल्ये**: डेटा नोंदवण्याच्या त्रुटी सूचित करणारी अत्युच्च मूल्ये (उदा., वय = 999)\n", + "3. **जवळपास पुनरावृत्ती असलेल्या ओळी**: थोड्या फरकांसह समान घटकाचे प्रतिनिधित्व करणारे नोंद\n", + "\n", + "या समस्यांचे शोध आणि हाताळण्यासाठी तंत्रे शोधूया.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### \"डर्टी\" डेटासेट तयार करणे\n", + "\n", + "सुरुवातीला, आपण एक नमुना डेटासेट तयार करूया ज्यामध्ये वास्तविक जगातील डेटामध्ये सामान्यतः आढळणाऱ्या समस्या असतील:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. असंगत श्रेणीमूल्य शोधणे\n", + "\n", + "`country` स्तंभामध्ये समान देशांसाठी अनेक प्रकार दिसून येतात. चला या असंगती ओळखूया:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### श्रेणीबद्ध मूल्यांचे मानकीकरण\n", + "\n", + "आपण या मूल्यांचे मानकीकरण करण्यासाठी एक मॅपिंग तयार करू शकतो. एक सोपी पद्धत म्हणजे लहान अक्षरात रूपांतर करणे आणि मॅपिंग डिक्शनरी तयार करणे:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**पर्याय: अस्पष्ट जुळणीचा वापर**\n", + "\n", + "अधिक जटिल प्रकरणांसाठी, आपण `rapidfuzz` लायब्ररीसह अस्पष्ट स्ट्रिंग जुळणी वापरू शकतो जेणेकरून समान स्ट्रिंग्स आपोआप ओळखता येतील:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. असामान्य संख्यात्मक मूल्य (आउटलायर्स) शोधणे\n", + "\n", + "`age` स्तंभाकडे पाहताना, आपल्याला 199 आणि -5 सारखे काही संशयास्पद मूल्ये दिसतात. चल statistical पद्धतींचा वापर करून या आउटलाईर्स शोधूया.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### IQR (इंटरक्वार्टाइल रेंज) पद्धत वापरणे\n", + "\n", + "IQR पद्धत ही बाह्य मूल्य शोधण्यासाठी एक मजबूत सांख्यिकीय तंत्र आहे जी अत्यंत मूल्यांबद्दल कमी संवेदनशील आहे:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Z-स्कोर पद्धत वापरणे\n", + "\n", + "Z-स्कोर पद्धत सरासरीपासून मानक विचलनांवर आधारित अपवाद ओळखते:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### अपवाद हाताळणे\n", + "\n", + "एकदा ओळखल्यानंतर, अपवाद अनेक प्रकारे हाताळले जाऊ शकतात:\n", + "1. **काढून टाका**: अपवाद असलेल्या पंक्ती हटवा (जर त्या चुका असतील)\n", + "2. **मर्यादा ठेवा**: सीमा मूल्यांसह बदल करा\n", + "3. **NaN ने बदला**: हरवलेला डेटा म्हणून विचार करा आणि भरपाई तंत्र वापरा\n", + "4. **ठेवा**: जर ते वैध अत्यंत मूल्ये असतील\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. जवळजवळ जुळणाऱ्या ओळी शोधणे\n", + "\n", + "लक्षात घ्या की आपल्या डेटासेटमध्ये \"John Smith\" साठी थोड्या वेगळ्या मूल्यांसह अनेक नोंदी आहेत. नावाच्या साम्याच्या आधारे संभाव्य डुप्लिकेट्स ओळखूया.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### फझी मॅचिंगसह जवळपास डुप्लिकेट शोधणे\n", + "\n", + "अधिक प्रगत डुप्लिकेट शोधण्यासाठी, आपण फझी मॅचिंग वापरून समान नाव शोधू शकतो:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### डुप्लिकेट्स हाताळणे\n", + "\n", + "ओळखल्यानंतर, तुम्हाला डुप्लिकेट्स कसे हाताळायचे ते ठरवावे लागेल:\n", + "1. **पहिली नोंद ठेवा**: `drop_duplicates(keep='first')` वापरा\n", + "2. **शेवटची नोंद ठेवा**: `drop_duplicates(keep='last')` वापरा\n", + "3. **माहिती एकत्र करा**: डुप्लिकेट रकान्यांमधील माहिती एकत्र करा\n", + "4. **हस्तलिखित पुनरावलोकन**: मानवी पुनरावलोकनासाठी चिन्हांकित करा\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### सारांश: संपूर्ण डेटा स्वच्छता प्रक्रिया\n", + "\n", + "चला सर्वकाही एकत्र करून एक व्यापक स्वच्छता प्रक्रिया तयार करूया:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 आव्हान व्यायाम\n", + "\n", + "आता तुमची पाळी! खाली दिलेली डेटा पंक्ती अनेक गुणवत्तेच्या समस्यांसह आहे. तुम्ही करू शकता का:\n", + "\n", + "1. या पंक्तीतील सर्व समस्या ओळखणे\n", + "2. प्रत्येक समस्येचे निराकरण करण्यासाठी कोड लिहिणे\n", + "3. स्वच्छ केलेली पंक्ती डेटासेटमध्ये जोडणे\n", + "\n", + "येथे समस्याग्रस्त डेटा आहे:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### मुख्य मुद्दे\n", + "\n", + "1. **असंगत श्रेणी** वास्तव जगातील डेटामध्ये सामान्य आहेत. नेहमी अद्वितीय मूल्ये तपासा आणि त्यांना मॅपिंग किंवा फझी मॅचिंगद्वारे प्रमाणित करा.\n", + "\n", + "2. **आउटलायर्स** तुमच्या विश्लेषणावर मोठा परिणाम करू शकतात. त्यांचा शोध घेण्यासाठी डोमेन ज्ञानासह सांख्यिकीय पद्धती (IQR, Z-score) वापरा.\n", + "\n", + "3. **जवळपासचे डुप्लिकेट** अचूक डुप्लिकेटपेक्षा शोधणे कठीण असते. त्यांना ओळखण्यासाठी फझी मॅचिंग आणि डेटा सामान्यीकरण (लोअरकेसिंग, व्हाइटस्पेस काढणे) विचारात घ्या.\n", + "\n", + "4. **डेटा स्वच्छ करणे पुनरावृत्तीशील आहे**. स्वच्छ डेटा अंतिम करण्यापूर्वी तुम्हाला अनेक तंत्रे लागू करावी लागतील आणि परिणाम पुनरावलोकन करावे लागतील.\n", + "\n", + "5. **तुमचे निर्णय दस्तऐवजीकरण करा**. तुम्ही कोणते स्वच्छता चरण लागू केले आणि का, याचा मागोवा ठेवा, कारण पुनरुत्पादकता आणि पारदर्शकतेसाठी हे महत्त्वाचे आहे.\n", + "\n", + "> **सर्वोत्तम पद्धत:** तुमचा मूळ \"अस्वच्छ\" डेटा नेहमी जतन करा. तुमच्या स्रोत डेटा फाइल्स कधीही अधिलिखित करू नका - `data_cleaned.csv` सारख्या स्पष्ट नावाच्या पद्धतींसह स्वच्छ आवृत्त्या तयार करा.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**अस्वीकरण**: \nहा दस्तऐवज AI भाषांतर सेवा [Co-op Translator](https://github.com/Azure/co-op-translator) चा वापर करून भाषांतरित करण्यात आला आहे. आम्ही अचूकतेसाठी प्रयत्नशील असलो तरी, कृपया लक्षात घ्या की स्वयंचलित भाषांतरांमध्ये त्रुटी किंवा अचूकतेचा अभाव असू शकतो. मूळ भाषेतील दस्तऐवज हा अधिकृत स्रोत मानला जावा. महत्त्वाच्या माहितीसाठी व्यावसायिक मानवी भाषांतराची शिफारस केली जाते. या भाषांतराचा वापर करून उद्भवलेल्या कोणत्याही गैरसमज किंवा चुकीच्या अर्थासाठी आम्ही जबाबदार राहणार नाही.\n" + "\n---\n\n**अस्वीकरण**: \nहा दस्तऐवज AI भाषांतर सेवा [Co-op Translator](https://github.com/Azure/co-op-translator) चा वापर करून भाषांतरित करण्यात आला आहे. आम्ही अचूकतेसाठी प्रयत्नशील असलो तरी कृपया लक्षात ठेवा की स्वयंचलित भाषांतरांमध्ये त्रुटी किंवा अचूकतेचा अभाव असू शकतो. मूळ भाषेतील दस्तऐवज हा अधिकृत स्रोत मानला जावा. महत्त्वाच्या माहितीसाठी व्यावसायिक मानवी भाषांतराची शिफारस केली जाते. या भाषांतराचा वापर करून उद्भवलेल्या कोणत्याही गैरसमज किंवा चुकीच्या अर्थासाठी आम्ही जबाबदार राहणार नाही.\n" ] } ], @@ -3676,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:14:58+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:42:34+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "mr" } diff --git a/translations/ms/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/ms/2-Working-With-Data/08-data-preparation/notebook.ipynb index 8838bdad..fdd04dcc 100644 --- a/translations/ms/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/ms/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# Penyediaan Data\n", "\n", - "[Notebook asal daripada *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio oleh Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Sumber Notebook asal daripada *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio oleh Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## Meneroka maklumat `DataFrame`\n", "\n", "> **Matlamat pembelajaran:** Pada akhir subseksyen ini, anda seharusnya selesa mencari maklumat umum tentang data yang disimpan dalam pandas DataFrames.\n", "\n", - "Setelah anda memuatkan data anda ke dalam pandas, kemungkinan besar ia akan berada dalam bentuk `DataFrame`. Namun, jika set data dalam `DataFrame` anda mempunyai 60,000 baris dan 400 lajur, bagaimana anda boleh mula memahami apa yang sedang anda kerjakan? Nasib baik, pandas menyediakan beberapa alat yang mudah untuk melihat maklumat keseluruhan tentang `DataFrame` dengan cepat, selain daripada beberapa baris pertama dan terakhir.\n", + "Setelah anda memuatkan data ke dalam pandas, kemungkinan besar data tersebut akan berada dalam bentuk `DataFrame`. Namun, jika set data dalam `DataFrame` anda mempunyai 60,000 baris dan 400 lajur, bagaimana anda mula memahami apa yang sedang anda kerjakan? Nasib baik, pandas menyediakan beberapa alat yang mudah untuk melihat maklumat keseluruhan tentang `DataFrame` dengan cepat, selain daripada beberapa baris pertama dan terakhir.\n", "\n", - "Untuk meneroka fungsi ini, kita akan mengimport pustaka Python scikit-learn dan menggunakan satu set data ikonik yang setiap saintis data pasti pernah lihat beratus-ratus kali: set data *Iris* oleh ahli biologi British Ronald Fisher yang digunakan dalam kertas kerjanya pada tahun 1936, \"The use of multiple measurements in taxonomic problems\":\n" + "Untuk meneroka fungsi ini, kita akan mengimport pustaka Python scikit-learn dan menggunakan satu set data ikonik yang telah dilihat oleh setiap saintis data beratus-ratus kali: set data *Iris* oleh ahli biologi British Ronald Fisher yang digunakan dalam kertas kerjanya pada tahun 1936 \"The use of multiple measurements in taxonomic problems\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Kami telah memuatkan Dataset Iris ke dalam pemboleh ubah `iris_df`. Sebelum mendalami data, adalah berguna untuk mengetahui bilangan titik data yang kita ada dan saiz keseluruhan dataset. Ia membantu untuk melihat jumlah data yang sedang kita uruskan.\n" + "Kami telah memuatkan Dataset Iris ke dalam pemboleh ubah `iris_df`. Sebelum mendalami data, adalah berguna untuk mengetahui bilangan titik data yang kita ada dan saiz keseluruhan dataset. Ia berguna untuk melihat jumlah data yang kita sedang uruskan.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Jadi, kita sedang berurusan dengan 150 baris dan 4 lajur data. Setiap baris mewakili satu titik data dan setiap lajur mewakili satu ciri yang berkaitan dengan rangka data. Jadi secara asasnya, terdapat 150 titik data yang mengandungi 4 ciri setiap satu.\n", + "Jadi, kita sedang menguruskan 150 baris dan 4 lajur data. Setiap baris mewakili satu titik data dan setiap lajur mewakili satu ciri yang berkaitan dengan rangka data. Jadi secara asasnya, terdapat 150 titik data yang mengandungi 4 ciri setiap satu.\n", "\n", - "`shape` di sini adalah atribut rangka data dan bukan fungsi, sebab itu ia tidak diakhiri dengan sepasang tanda kurung.\n" + "`shape` di sini adalah atribut rangka data dan bukan fungsi, sebab itulah ia tidak diakhiri dengan sepasang kurungan.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Mari kita lihat 4 lajur data. Apa sebenarnya yang diwakili oleh setiap lajur? Atribut `columns` akan memberikan kita nama-nama lajur dalam dataframe.\n" + "Sekarang mari kita lihat 4 lajur data. Apakah yang sebenarnya diwakili oleh setiap lajur ini? Atribut `columns` akan memberikan kita nama-nama lajur dalam dataframe.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Seperti yang kita dapat lihat, terdapat empat(4) lajur. Atribut `columns` memberitahu kita nama lajur dan secara asasnya tiada yang lain. Atribut ini menjadi penting apabila kita ingin mengenal pasti ciri-ciri yang terdapat dalam set data.\n" + "Seperti yang kita dapat lihat, terdapat empat(4) lajur. Atribut `columns` memberitahu kita nama lajur dan pada dasarnya tiada apa-apa lagi. Atribut ini menjadi penting apabila kita ingin mengenal pasti ciri-ciri yang terdapat dalam set data.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Jumlah data (diberikan oleh atribut `shape`) dan nama ciri atau lajur (diberikan oleh atribut `columns`) memberikan kita sedikit maklumat tentang set data. Sekarang, kita ingin menyelami lebih dalam ke dalam set data. Fungsi `DataFrame.info()` sangat berguna untuk tujuan ini.\n" + "Jumlah data (diberikan oleh atribut `shape`) dan nama ciri atau lajur (diberikan oleh atribut `columns`) memberikan kita sedikit maklumat tentang dataset. Sekarang, kita ingin menyelami dataset dengan lebih mendalam. Fungsi `DataFrame.info()` sangat berguna untuk tujuan ini.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Dari sini, kita boleh membuat beberapa pemerhatian: \n", - "1. Jenis Data bagi setiap lajur: Dalam set data ini, semua data disimpan sebagai nombor titik terapung 64-bit. \n", - "2. Bilangan nilai bukan null: Menangani nilai null adalah langkah penting dalam penyediaan data. Ia akan ditangani kemudian dalam buku nota. \n" + "Dari sini, kita boleh membuat beberapa pemerhatian:\n", + "1. Jenis Data bagi setiap lajur: Dalam set data ini, semua data disimpan sebagai nombor titik terapung 64-bit.\n", + "2. Bilangan nilai bukan null: Menangani nilai null adalah langkah penting dalam penyediaan data. Ia akan ditangani kemudian dalam buku nota.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Katakan kita mempunyai banyak data numerik dalam set data kita. Pengiraan statistik univariat seperti min, median, kuartil dan sebagainya boleh dilakukan pada setiap lajur secara individu. Fungsi `DataFrame.describe()` memberikan kita ringkasan statistik bagi lajur-lajur numerik dalam set data.\n" + "Katakan kita mempunyai banyak data berangka dalam set data kita. Pengiraan statistik univariat seperti purata, median, kuartil dan sebagainya boleh dilakukan pada setiap lajur secara individu. Fungsi `DataFrame.describe()` memberikan kita ringkasan statistik bagi lajur berangka dalam set data.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "Output di atas menunjukkan jumlah keseluruhan titik data, min, sisihan piawai, minimum, kuartil bawah (25%), median (50%), kuartil atas (75%) dan nilai maksimum bagi setiap lajur.\n" + "Output di atas menunjukkan jumlah keseluruhan titik data, min, sisihan piawai, nilai minimum, kuartil bawah (25%), median (50%), kuartil atas (75%) dan nilai maksimum bagi setiap lajur.\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "Dengan semua fungsi dan atribut yang disebutkan di atas, kita telah mendapat gambaran keseluruhan tentang dataset. Kita tahu berapa banyak titik data yang ada, berapa banyak ciri yang ada, jenis data bagi setiap ciri, dan bilangan nilai bukan null untuk setiap ciri.\n", + "Dengan semua fungsi dan atribut di atas, kita telah mendapat gambaran keseluruhan tentang dataset. Kita tahu berapa banyak titik data yang ada, berapa banyak ciri yang ada, jenis data bagi setiap ciri, dan bilangan nilai bukan null bagi setiap ciri.\n", "\n", - "Sekarang tiba masanya untuk melihat data itu sendiri. Mari kita lihat bagaimana rupa beberapa baris pertama (beberapa titik data pertama) dalam `DataFrame` kita:\n" + "Sekarang tiba masanya untuk melihat data itu sendiri. Mari kita lihat beberapa baris pertama (beberapa titik data pertama) dalam `DataFrame` kita:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Sebagai output di sini, kita dapat melihat lima(5) entri daripada set data. Jika kita melihat pada indeks di sebelah kiri, kita mendapati bahawa ini adalah lima baris pertama.\n" + "Sebagai output di sini, kita dapat melihat lima(5) entri dataset. Jika kita melihat indeks di sebelah kiri, kita mendapati bahawa ini adalah lima baris pertama.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Latihan:\n", "\n", - "Daripada contoh yang diberikan di atas, jelas bahawa, secara lalai, `DataFrame.head` mengembalikan lima baris pertama daripada `DataFrame`. Dalam sel kod di bawah, bolehkah anda mencari cara untuk memaparkan lebih daripada lima baris?\n" + "Daripada contoh yang diberikan di atas, jelas bahawa secara lalai, `DataFrame.head` mengembalikan lima baris pertama daripada `DataFrame`. Dalam sel kod di bawah, bolehkah anda mencari cara untuk memaparkan lebih daripada lima baris?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Satu lagi cara untuk melihat data adalah dari penghujung (bukannya dari permulaan). Lawan kepada `DataFrame.head` ialah `DataFrame.tail`, yang mengembalikan lima baris terakhir daripada `DataFrame`:\n" + "Satu lagi cara untuk melihat data adalah dari hujung (bukannya dari permulaan). Lawan kepada `DataFrame.head` ialah `DataFrame.tail`, yang mengembalikan lima baris terakhir dari `DataFrame`:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "Dalam praktiknya, adalah berguna untuk dapat memeriksa beberapa baris pertama atau beberapa baris terakhir `DataFrame` dengan mudah, terutamanya apabila anda mencari nilai luar dalam dataset yang teratur.\n", + "Dalam amalan, adalah berguna untuk dapat memeriksa beberapa baris pertama atau beberapa baris terakhir `DataFrame` dengan mudah, terutamanya apabila anda mencari nilai luar dalam dataset yang diatur.\n", "\n", - "Semua fungsi dan atribut yang ditunjukkan di atas dengan bantuan contoh kod membantu kita mendapatkan gambaran dan rasa tentang data tersebut.\n", + "Semua fungsi dan atribut yang ditunjukkan di atas dengan bantuan contoh kod membantu kita mendapatkan gambaran dan rasa tentang data.\n", "\n", - "> **Kesimpulan:** Walaupun hanya dengan melihat metadata tentang maklumat dalam `DataFrame` atau beberapa nilai pertama dan terakhir di dalamnya, anda boleh mendapatkan idea segera tentang saiz, bentuk, dan kandungan data yang sedang anda hadapi.\n" + "> **Kesimpulan:** Walaupun hanya dengan melihat metadata tentang maklumat dalam DataFrame atau beberapa nilai pertama dan terakhir, anda boleh mendapatkan idea segera tentang saiz, bentuk, dan kandungan data yang sedang anda hadapi.\n" ] }, { @@ -596,17 +596,17 @@ }, "source": [ "### Data Hilang\n", - "Mari kita selami data yang hilang. Data hilang berlaku apabila tiada nilai disimpan dalam beberapa kolum.\n", + "Mari kita selami data yang hilang. Data hilang berlaku apabila tiada nilai yang disimpan dalam beberapa lajur.\n", "\n", - "Mari kita ambil contoh: katakan seseorang yang sangat mementingkan berat badannya tidak mengisi ruangan berat dalam satu tinjauan. Maka, nilai berat bagi orang tersebut akan hilang.\n", + "Mari kita ambil satu contoh: katakan seseorang sangat mementingkan berat badannya dan tidak mengisi ruangan berat dalam satu tinjauan. Maka, nilai berat untuk orang tersebut akan hilang.\n", "\n", - "Kebanyakan masa, dalam dataset dunia sebenar, nilai yang hilang sering berlaku.\n", + "Kebanyakan masa, dalam set data dunia sebenar, nilai yang hilang memang berlaku.\n", "\n", "**Bagaimana Pandas Mengendalikan Data Hilang**\n", "\n", - "Pandas mengendalikan nilai yang hilang dengan dua cara. Cara pertama yang telah anda lihat dalam bahagian sebelumnya ialah `NaN`, atau Not a Number. Ini sebenarnya adalah nilai khas yang merupakan sebahagian daripada spesifikasi titik terapung IEEE dan ia hanya digunakan untuk menunjukkan nilai titik terapung yang hilang.\n", + "Pandas mengendalikan nilai yang hilang dengan dua cara. Cara pertama yang telah anda lihat sebelum ini dalam bahagian sebelumnya ialah `NaN`, atau Not a Number. Ini sebenarnya adalah nilai khas yang merupakan sebahagian daripada spesifikasi titik terapung IEEE dan ia hanya digunakan untuk menunjukkan nilai titik terapung yang hilang.\n", "\n", - "Untuk nilai yang hilang selain daripada titik terapung, pandas menggunakan objek Python `None`. Walaupun mungkin kelihatan mengelirukan bahawa anda akan menemui dua jenis nilai yang pada dasarnya menyatakan perkara yang sama, terdapat alasan programatik yang kukuh untuk pilihan reka bentuk ini dan, dalam praktiknya, pendekatan ini membolehkan pandas memberikan kompromi yang baik untuk kebanyakan kes. Walaupun begitu, kedua-dua `None` dan `NaN` mempunyai batasan yang perlu anda ambil perhatian berkaitan dengan cara ia boleh digunakan.\n" + "Untuk nilai yang hilang selain daripada jenis float, pandas menggunakan objek Python `None`. Walaupun mungkin kelihatan mengelirukan bahawa anda akan menemui dua jenis nilai yang pada dasarnya menyatakan perkara yang sama, terdapat sebab programatik yang kukuh untuk pilihan reka bentuk ini dan, dalam praktiknya, pendekatan ini membolehkan pandas memberikan kompromi yang baik untuk kebanyakan kes. Walau bagaimanapun, kedua-dua `None` dan `NaN` mempunyai batasan yang perlu anda ambil perhatian berkaitan dengan cara ia boleh digunakan.\n" ] }, { @@ -615,8 +615,8 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: data hilang bukan float\n", - "Oleh kerana `None` berasal dari Python, ia tidak boleh digunakan dalam array NumPy dan pandas yang bukan jenis data `'object'`. Ingat, array NumPy (dan struktur data dalam pandas) hanya boleh mengandungi satu jenis data. Inilah yang memberikan mereka kuasa besar untuk kerja data dan pengiraan berskala besar, tetapi ia juga menghadkan fleksibiliti mereka. Array seperti ini perlu dinaikkan kepada \"denominator paling rendah,\" iaitu jenis data yang akan merangkumi segala-galanya dalam array. Apabila `None` berada dalam array, ini bermakna anda sedang bekerja dengan objek Python.\n", + "### `None`: data hilang bukan jenis float\n", + "Oleh kerana `None` berasal dari Python, ia tidak boleh digunakan dalam array NumPy dan pandas yang bukan daripada jenis data `'object'`. Ingat, array NumPy (dan struktur data dalam pandas) hanya boleh mengandungi satu jenis data sahaja. Inilah yang memberikan mereka kuasa besar untuk kerja data berskala besar dan pengiraan, tetapi ia juga menghadkan fleksibiliti mereka. Array seperti ini perlu dinaikkan kepada “penyebut bersama terendah,” iaitu jenis data yang dapat merangkumi semua elemen dalam array. Apabila `None` berada dalam array, ini bermakna anda sedang bekerja dengan objek Python.\n", "\n", "Untuk melihat ini dalam tindakan, pertimbangkan contoh array berikut (perhatikan `dtype` untuknya):\n" ] @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Realiti jenis data yang dinaikkan (upcast) membawa dua kesan sampingan bersamanya. Pertama, operasi akan dijalankan pada tahap kod Python yang ditafsirkan dan bukannya kod NumPy yang telah disusun. Secara asasnya, ini bermakna sebarang operasi yang melibatkan `Series` atau `DataFrames` dengan `None` di dalamnya akan menjadi lebih perlahan. Walaupun anda mungkin tidak menyedari kesan prestasi ini, untuk set data yang besar ia mungkin menjadi isu.\n", + "Realiti jenis data yang dinaikkan membawa dua kesan sampingan bersamanya. Pertama, operasi akan dijalankan pada tahap kod Python yang ditafsirkan dan bukannya kod NumPy yang telah disusun. Secara asasnya, ini bermakna sebarang operasi yang melibatkan `Series` atau `DataFrames` dengan `None` di dalamnya akan menjadi lebih perlahan. Walaupun anda mungkin tidak menyedari kesan prestasi ini, untuk set data yang besar ia mungkin menjadi isu.\n", "\n", - "Kesan sampingan kedua berpunca daripada yang pertama. Oleh kerana `None` pada dasarnya menarik `Series` atau `DataFrame` kembali ke dunia Python biasa, menggunakan pengagregatan NumPy/pandas seperti `sum()` atau `min()` pada array yang mengandungi nilai ``None`` secara amnya akan menghasilkan ralat:\n" + "Kesan sampingan kedua berpunca daripada yang pertama. Oleh kerana `None` pada dasarnya membawa `Series` atau `DataFrame` kembali ke dunia Python biasa, menggunakan pengagregatan NumPy/pandas seperti `sum()` atau `min()` pada array yang mengandungi nilai ``None`` secara amnya akan menghasilkan ralat:\n" ] }, { @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Perkara utama**: Penambahan (dan operasi lain) antara integer dan nilai `None` adalah tidak ditakrifkan, yang boleh mengehadkan apa yang boleh anda lakukan dengan set data yang mengandungi nilai tersebut.\n" + "**Kesimpulan utama**: Penambahan (dan operasi lain) antara integer dan nilai `None` adalah tidak ditakrifkan, yang boleh mengehadkan apa yang boleh dilakukan dengan set data yang mengandungi nilai tersebut.\n" ] }, { @@ -709,7 +709,7 @@ "source": [ "### `NaN`: nilai terapung yang hilang\n", "\n", - "Berbeza dengan `None`, NumPy (dan oleh itu pandas) menyokong `NaN` untuk operasi vektorisasi dan ufuncs yang pantas. Berita buruknya ialah sebarang operasi aritmetik yang dilakukan pada `NaN` sentiasa menghasilkan `NaN`. Sebagai contoh:\n" + "Berbeza dengan `None`, NumPy (dan oleh itu pandas) menyokong `NaN` untuk operasi vektorisasi yang pantas dan ufuncs. Berita buruknya ialah sebarang operasi aritmetik yang dilakukan pada `NaN` sentiasa menghasilkan `NaN`. Sebagai contoh:\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Berita baik: pengagregatan yang dijalankan pada array dengan `NaN` di dalamnya tidak menghasilkan ralat. Berita buruk: hasilnya tidak seragam berguna:\n" + "Berita baik: pengagregatan yang dijalankan pada array dengan `NaN` di dalamnya tidak menghasilkan ralat. Berita buruk: hasilnya tidak sentiasa berguna:\n" ] }, { @@ -809,7 +809,7 @@ "id": "nhlnNJT7gRr_" }, "source": [ - "### Senaman:\n" + "### Latihan:\n" ] }, { @@ -831,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "Ingat: `NaN` hanyalah untuk nilai titik terapung yang hilang; tiada `NaN` yang setara untuk integer, string, atau Boolean.\n" + "Ingat: `NaN` hanya untuk nilai titik terapung yang hilang; tiada `NaN` yang setara untuk integer, string, atau Boolean.\n" ] }, { @@ -842,7 +842,7 @@ "source": [ "### `NaN` dan `None`: nilai null dalam pandas\n", "\n", - "Walaupun `NaN` dan `None` boleh berkelakuan sedikit berbeza, pandas tetap dibina untuk mengendalikannya secara bergantian. Untuk memahami maksud ini, pertimbangkan satu `Series` integer:\n" + "Walaupun `NaN` dan `None` boleh berkelakuan sedikit berbeza, pandas tetap dibina untuk mengendalikannya secara bergantian. Untuk memahami maksudnya, pertimbangkan `Series` integer:\n" ] }, { @@ -906,12 +906,12 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Dalam proses menaikkan jenis data untuk mewujudkan keseragaman data dalam `Series` dan `DataFrame`, pandas dengan mudah akan menukar nilai yang hilang antara `None` dan `NaN`. Disebabkan ciri reka bentuk ini, adalah berguna untuk menganggap `None` dan `NaN` sebagai dua jenis \"null\" yang berbeza dalam pandas. Malah, beberapa kaedah teras yang akan anda gunakan untuk menangani nilai yang hilang dalam pandas mencerminkan idea ini dalam nama mereka:\n", + "Dalam proses menaikkan jenis data untuk mewujudkan keseragaman data dalam `Series` dan `DataFrame`, pandas dengan mudah menukar nilai yang hilang antara `None` dan `NaN`. Disebabkan ciri reka bentuk ini, adalah berguna untuk menganggap `None` dan `NaN` sebagai dua jenis \"null\" yang berbeza dalam pandas. Malah, beberapa kaedah teras yang anda akan gunakan untuk menangani nilai yang hilang dalam pandas mencerminkan idea ini dalam nama mereka:\n", "\n", - "- `isnull()`: Menghasilkan topeng Boolean yang menunjukkan nilai yang hilang\n", + "- `isnull()`: Menjana topeng Boolean yang menunjukkan nilai yang hilang\n", "- `notnull()`: Bertentangan dengan `isnull()`\n", - "- `dropna()`: Mengembalikan versi data yang ditapis\n", - "- `fillna()`: Mengembalikan salinan data dengan nilai yang hilang diisi atau dianggar\n", + "- `dropna()`: Mengembalikan versi data yang telah ditapis\n", + "- `fillna()`: Mengembalikan salinan data dengan nilai yang hilang diisi atau dianggarkan\n", "\n", "Kaedah-kaedah ini adalah penting untuk dikuasai dan dibiasakan, jadi mari kita teliti setiap satu dengan lebih mendalam.\n" ] @@ -924,7 +924,7 @@ "source": [ "### Mengesan nilai null\n", "\n", - "Sekarang setelah kita memahami kepentingan nilai yang hilang, kita perlu mengesannya dalam set data kita sebelum menanganinya. \n", + "Setelah kita memahami kepentingan nilai yang hilang, kita perlu mengesannya dalam dataset kita sebelum menanganinya. \n", "Kedua-dua `isnull()` dan `notnull()` adalah kaedah utama anda untuk mengesan data null. Kedua-duanya mengembalikan topeng Boolean ke atas data anda.\n" ] }, @@ -978,7 +978,7 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Lihat dengan teliti pada output. Adakah ada yang mengejutkan anda? Walaupun `0` adalah nilai sifar aritmetik, ia tetap merupakan integer yang sah dan pandas menganggapnya sedemikian. `''` pula sedikit lebih halus. Walaupun kita menggunakannya dalam Bahagian 1 untuk mewakili nilai rentetan kosong, ia tetap merupakan objek rentetan dan bukan representasi nilai null menurut pandas.\n", + "Perhatikan dengan teliti pada output. Adakah terdapat sesuatu yang mengejutkan anda? Walaupun `0` adalah null aritmetik, ia tetap merupakan integer yang sah dan pandas menganggapnya sedemikian. `''` pula sedikit lebih halus. Walaupun kita menggunakannya dalam Seksyen 1 untuk mewakili nilai string kosong, ia tetap merupakan objek string dan bukan representasi null menurut pandas.\n", "\n", "Sekarang, mari kita ubah pendekatan ini dan gunakan kaedah-kaedah ini dengan cara yang lebih menyerupai penggunaan sebenar. Anda boleh menggunakan topeng Boolean secara langsung sebagai indeks ``Series`` atau ``DataFrame``, yang boleh berguna apabila cuba bekerja dengan nilai yang hilang (atau ada) secara terasing.\n", "\n", @@ -1040,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Pengajaran utama**: Kedua-dua kaedah `isnull()` dan `notnull()` menghasilkan keputusan yang serupa apabila anda menggunakannya dalam DataFrame: ia menunjukkan keputusan dan indeks keputusan tersebut, yang akan sangat membantu anda semasa anda mengendalikan data anda.\n" + "**Pengajaran utama**: Kedua-dua kaedah `isnull()` dan `notnull()` menghasilkan keputusan yang serupa apabila anda menggunakannya dalam DataFrame: mereka menunjukkan keputusan dan indeks keputusan tersebut, yang akan sangat membantu anda semasa anda menguruskan data anda.\n" ] }, { @@ -1049,13 +1049,13 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### Menangani data yang hilang\n", + "### Menangani Data yang Hilang\n", "\n", "> **Matlamat pembelajaran:** Pada akhir subseksyen ini, anda sepatutnya tahu bagaimana dan bila untuk menggantikan atau membuang nilai null daripada DataFrames.\n", "\n", "Model Pembelajaran Mesin tidak dapat menangani data yang hilang secara langsung. Oleh itu, sebelum data dimasukkan ke dalam model, kita perlu menangani nilai-nilai yang hilang ini.\n", "\n", - "Cara menangani data yang hilang membawa kompromi yang halus, boleh mempengaruhi analisis akhir anda dan hasil dunia sebenar.\n", + "Cara menangani data yang hilang mempunyai kompromi yang halus, boleh mempengaruhi analisis akhir anda dan hasil dunia sebenar.\n", "\n", "Terdapat dua cara utama untuk menangani data yang hilang:\n", "\n", @@ -1073,9 +1073,9 @@ "source": [ "### Menyingkirkan nilai null\n", "\n", - "Jumlah data yang kita serahkan kepada model kita mempunyai kesan langsung terhadap prestasinya. Menyingkirkan nilai null bermaksud kita mengurangkan bilangan titik data, dan seterusnya mengurangkan saiz set data. Oleh itu, adalah disarankan untuk menyingkirkan baris dengan nilai null apabila set data agak besar.\n", + "Jumlah data yang kita berikan kepada model kita mempunyai kesan langsung terhadap prestasinya. Menyingkirkan nilai null bermaksud kita mengurangkan bilangan titik data, dan seterusnya mengurangkan saiz dataset. Oleh itu, adalah disarankan untuk menyingkirkan baris dengan nilai null apabila dataset cukup besar.\n", "\n", - "Satu lagi situasi mungkin berlaku apabila baris atau lajur tertentu mempunyai banyak nilai yang hilang. Dalam kes ini, ia mungkin disingkirkan kerana ia tidak akan memberikan banyak nilai kepada analisis kita memandangkan kebanyakan data untuk baris/lajur tersebut hilang.\n", + "Contoh lain mungkin berlaku apabila baris atau lajur tertentu mempunyai banyak nilai yang hilang. Dalam kes ini, ia mungkin disingkirkan kerana tidak akan memberikan banyak nilai kepada analisis kita memandangkan kebanyakan data untuk baris/lajur tersebut hilang.\n", "\n", "Selain mengenal pasti nilai yang hilang, pandas menyediakan cara yang mudah untuk menyingkirkan nilai null daripada `Series` dan `DataFrame`. Untuk melihat ini dalam tindakan, mari kita kembali kepada `example3`. Fungsi `DataFrame.dropna()` membantu dalam menyingkirkan baris dengan nilai null.\n" ] @@ -1116,7 +1116,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "Perhatikan bahawa ini sepatutnya kelihatan seperti output anda daripada `example3[example3.notnull()]`. Perbezaannya di sini ialah, bukannya hanya mengindeks pada nilai yang bertopeng, `dropna` telah membuang nilai yang hilang daripada `Series` `example3`.\n", + "Perhatikan bahawa ini sepatutnya kelihatan seperti output anda daripada `example3[example3.notnull()]`. Perbezaannya di sini ialah, bukannya hanya mengindeks pada nilai yang bertopeng, `dropna` telah membuang nilai-nilai yang hilang daripada `Series` `example3`.\n", "\n", "Oleh kerana DataFrame mempunyai dua dimensi, ia memberikan lebih banyak pilihan untuk membuang data.\n" ] @@ -1208,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Adakah anda perasan bahawa pandas telah menaikkan dua daripada lajur kepada jenis float untuk menyesuaikan `NaN`?)\n", + "(Adakah anda perasan bahawa pandas menaikkan dua daripada lajur kepada jenis float untuk menyesuaikan `NaN`?)\n", "\n", - "Anda tidak boleh membuang satu nilai sahaja daripada `DataFrame`, jadi anda perlu membuang keseluruhan baris atau lajur. Bergantung pada apa yang anda lakukan, anda mungkin ingin memilih salah satu daripadanya, dan oleh itu pandas memberikan anda pilihan untuk kedua-duanya. Oleh kerana dalam sains data, lajur biasanya mewakili pemboleh ubah dan baris mewakili pemerhatian, anda lebih cenderung untuk membuang baris data; tetapan lalai untuk `dropna()` adalah untuk membuang semua baris yang mengandungi sebarang nilai null:\n" + "Anda tidak boleh membuang satu nilai sahaja daripada `DataFrame`, jadi anda perlu membuang keseluruhan baris atau lajur. Bergantung pada apa yang anda lakukan, anda mungkin ingin memilih salah satu, dan oleh itu pandas memberikan anda pilihan untuk kedua-duanya. Oleh kerana dalam sains data, lajur biasanya mewakili pemboleh ubah dan baris mewakili pemerhatian, anda lebih cenderung untuk membuang baris data; tetapan lalai untuk `dropna()` adalah untuk membuang semua baris yang mengandungi sebarang nilai null:\n" ] }, { @@ -1283,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "Jika perlu, anda boleh membuang nilai NA daripada lajur. Gunakan `axis=1` untuk melakukannya:\n" + "Jika perlu, anda boleh membuang nilai NA dari lajur. Gunakan `axis=1` untuk melakukannya:\n" ] }, { @@ -1362,7 +1362,7 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Perhatikan bahawa ini boleh membuang banyak data yang mungkin anda ingin simpan, terutamanya dalam dataset yang lebih kecil. Bagaimana jika anda hanya ingin membuang baris atau lajur yang mengandungi beberapa atau bahkan semua nilai null? Anda boleh menetapkan pilihan tersebut dalam `dropna` dengan parameter `how` dan `thresh`.\n", + "Perhatikan bahawa ini boleh menyebabkan kehilangan banyak data yang mungkin anda ingin simpan, terutamanya dalam dataset yang lebih kecil. Bagaimana jika anda hanya ingin membuang baris atau lajur yang mengandungi beberapa atau bahkan semua nilai null? Anda boleh menetapkan pilihan tersebut dalam `dropna` dengan parameter `how` dan `thresh`.\n", "\n", "Secara lalai, `how='any'` (jika anda ingin memeriksa sendiri atau melihat parameter lain yang dimiliki oleh kaedah ini, jalankan `example4.dropna?` dalam sel kod). Sebagai alternatif, anda boleh menetapkan `how='all'` untuk hanya membuang baris atau lajur yang mengandungi semua nilai null. Mari kita kembangkan contoh `DataFrame` kita untuk melihat ini berfungsi dalam latihan seterusnya.\n" ] @@ -1456,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> Perkara penting yang perlu diambil perhatian:\n", - "1. Menghapuskan nilai null adalah idea yang baik hanya jika dataset cukup besar.\n", - "2. Baris atau lajur penuh boleh dihapuskan jika kebanyakan datanya hilang.\n", - "3. Kaedah `DataFrame.dropna(axis=)` membantu dalam menghapuskan nilai null. Argumen `axis` menunjukkan sama ada baris atau lajur yang akan dihapuskan.\n", - "4. Argumen `how` juga boleh digunakan. Secara lalai ia ditetapkan kepada `any`. Jadi, ia hanya menghapuskan baris/lajur yang mengandungi sebarang nilai null. Ia boleh ditetapkan kepada `all` untuk menentukan bahawa kita hanya akan menghapuskan baris/lajur di mana semua nilainya adalah null.\n" + "> Perkara penting: \n", + "1. Menghapuskan nilai null adalah idea yang baik hanya jika dataset cukup besar. \n", + "2. Baris atau lajur penuh boleh dihapuskan jika kebanyakan datanya hilang. \n", + "3. Kaedah `DataFrame.dropna(axis=)` membantu dalam menghapuskan nilai null. Argumen `axis` menunjukkan sama ada baris atau lajur yang akan dihapuskan. \n", + "4. Argumen `how` juga boleh digunakan. Secara lalai ia ditetapkan kepada `any`. Jadi, ia hanya menghapuskan baris/lajur yang mengandungi sebarang nilai null. Ia boleh ditetapkan kepada `all` untuk menentukan bahawa kita hanya akan menghapuskan baris/lajur di mana semua nilainya adalah null. \n" ] }, { @@ -1469,7 +1469,7 @@ "id": "oXXSfQFHgRsF" }, "source": [ - "### Senaman:\n" + "### Latihan:\n" ] }, { @@ -1492,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "Parameter `thresh` memberikan anda kawalan yang lebih terperinci: anda menetapkan bilangan nilai *bukan null* yang perlu ada pada satu baris atau lajur untuk disimpan:\n" + "Parameter `thresh` memberikan kawalan yang lebih terperinci: anda menetapkan bilangan nilai *bukan null* yang diperlukan oleh baris atau lajur untuk dikekalkan:\n" ] }, { @@ -1576,11 +1576,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### Mengisi nilai null\n", + "### Mengisi Nilai Null\n", "\n", "Kadang-kadang masuk akal untuk mengisi nilai yang hilang dengan nilai yang mungkin sah. Terdapat beberapa teknik untuk mengisi nilai null. Yang pertama adalah menggunakan Pengetahuan Domain (pengetahuan tentang subjek yang menjadi asas dataset) untuk menganggarkan nilai yang hilang.\n", "\n", - "Anda boleh menggunakan `isnull` untuk melakukan ini secara langsung, tetapi ia boleh menjadi memakan masa, terutamanya jika anda mempunyai banyak nilai untuk diisi. Oleh kerana ini adalah tugas yang biasa dalam sains data, pandas menyediakan `fillna`, yang mengembalikan salinan `Series` atau `DataFrame` dengan nilai yang hilang digantikan dengan pilihan anda. Mari kita buat satu lagi contoh `Series` untuk melihat bagaimana ini berfungsi dalam amalan.\n" + "Anda boleh menggunakan `isnull` untuk melakukan ini secara langsung, tetapi ia boleh menjadi memakan masa, terutamanya jika anda mempunyai banyak nilai untuk diisi. Oleh kerana ini adalah tugas yang biasa dalam sains data, pandas menyediakan `fillna`, yang mengembalikan salinan `Series` atau `DataFrame` dengan nilai yang hilang digantikan dengan pilihan anda. Mari kita buat satu lagi contoh `Series` untuk melihat bagaimana ini berfungsi dalam praktik.\n" ] }, { @@ -1590,11 +1590,11 @@ }, "source": [ "### Data Kategori (Bukan Numerik)\n", - "Pertama, mari kita pertimbangkan data bukan numerik. Dalam set data, terdapat lajur dengan data kategori. Contohnya, Jantina, Benar atau Palsu, dan sebagainya.\n", + "Pertama sekali, mari kita pertimbangkan data bukan numerik. Dalam set data, kita mempunyai lajur dengan data kategori. Contohnya, Jantina, Benar atau Salah, dan sebagainya.\n", "\n", - "Dalam kebanyakan kes ini, kita menggantikan nilai yang hilang dengan `mod` bagi lajur tersebut. Sebagai contoh, jika kita mempunyai 100 titik data dan 90 daripadanya mengatakan Benar, 8 mengatakan Palsu, dan 2 tidak diisi. Maka, kita boleh mengisi 2 yang kosong dengan Benar, dengan mengambil kira keseluruhan lajur.\n", + "Dalam kebanyakan kes ini, kita menggantikan nilai yang hilang dengan `mod` bagi lajur tersebut. Sebagai contoh, katakan kita mempunyai 100 titik data, di mana 90 mengatakan Benar, 8 mengatakan Salah, dan 2 tidak diisi. Maka, kita boleh mengisi 2 yang kosong dengan Benar, dengan mengambil kira keseluruhan lajur.\n", "\n", - "Sekali lagi, di sini kita boleh menggunakan pengetahuan domain. Mari kita pertimbangkan contoh pengisian dengan mod.\n" + "Sekali lagi, di sini kita boleh menggunakan pengetahuan domain. Mari kita pertimbangkan contoh pengisian menggunakan mod.\n" ] }, { @@ -1699,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Sekarang, mari kita cari mod terlebih dahulu sebelum mengisi nilai `None` dengan mod.\n" + ] }, { "cell_type": "code", @@ -1734,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Jadi, kita akan menggantikan None dengan True\n" + ] }, { "cell_type": "code", @@ -1844,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Seperti yang kita dapat lihat, nilai null telah digantikan. Tidak perlu dikatakan, kita boleh menulis apa sahaja sebagai ganti `'True'` dan ia akan digantikan.\n" + "Seperti yang kita lihat, nilai null telah digantikan. Tidak perlu dikatakan, kita boleh menulis apa sahaja sebagai ganti atau `'True'` dan ia akan digantikan.\n" ] }, { @@ -1853,13 +1857,13 @@ "id": "heYe1I0dOmQ_" }, "source": [ - "### Data Berangka\n", - "Sekarang, mari kita bincangkan tentang data berangka. Di sini, terdapat dua cara biasa untuk menggantikan nilai yang hilang:\n", + "### Data Nombor\n", + "Sekarang, beralih kepada data nombor. Di sini, terdapat dua cara biasa untuk menggantikan nilai yang hilang:\n", "\n", - "1. Gantikan dengan Median bagi baris tersebut\n", - "2. Gantikan dengan Purata bagi baris tersebut\n", + "1. Gantikan dengan Median baris\n", + "2. Gantikan dengan Purata baris\n", "\n", - "Kita menggantikan dengan Median apabila data mempunyai taburan yang tidak seimbang dengan kehadiran outlier. Ini kerana median adalah lebih tahan terhadap outlier.\n", + "Kita menggantikan dengan Median apabila data mempunyai pencilan yang menyebabkan data menjadi tidak seimbang. Ini kerana median adalah lebih tahan terhadap pencilan.\n", "\n", "Apabila data telah dinormalisasi, kita boleh menggunakan purata, kerana dalam kes ini, purata dan median akan hampir sama.\n", "\n", @@ -2003,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Mengisi dengan purata\n" + ] }, { "cell_type": "code", @@ -2103,7 +2109,7 @@ "id": "CwpVFCrPTC5z" }, "source": [ - "Seperti yang kita dapat lihat, nilai yang hilang telah digantikan dengan puratanya.\n" + "Seperti yang kita dapat lihat, nilai yang hilang telah digantikan dengan minnya.\n" ] }, { @@ -2112,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Sekarang mari kita cuba dataframe lain, dan kali ini kita akan menggantikan nilai None dengan median lajur.\n" + "Sekarang mari kita cuba dataframe yang lain, dan kali ini kita akan menggantikan nilai None dengan median lajur tersebut.\n" ] }, { @@ -2218,7 +2224,7 @@ "id": "mM1GpXYmjHnc" }, "source": [ - "Median bagi lajur kedua ialah\n" + "Median lajur kedua ialah\n" ] }, { @@ -2354,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Seperti yang kita dapat lihat, nilai NaN telah digantikan dengan median lajur tersebut\n" + "Seperti yang kita lihat, nilai NaN telah digantikan dengan median bagi lajur tersebut\n" ] }, { @@ -2437,8 +2443,8 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Perkara utama yang perlu diambil perhatian:\n", - "1. Mengisi nilai yang hilang perlu dilakukan sama ada apabila terdapat sedikit data atau terdapat strategi untuk mengisi data yang hilang.\n", + "> Perkara penting yang perlu diambil perhatian:\n", + "1. Pengisian nilai yang hilang perlu dilakukan sama ada apabila terdapat sedikit data atau terdapat strategi untuk mengisi data yang hilang.\n", "2. Pengetahuan domain boleh digunakan untuk mengisi nilai yang hilang dengan menganggarkannya.\n", "3. Untuk data Kategori, kebiasaannya, nilai yang hilang digantikan dengan mod bagi lajur tersebut.\n", "4. Untuk data numerik, nilai yang hilang biasanya diisi dengan purata (untuk set data yang dinormalisasi) atau median bagi lajur tersebut.\n" @@ -2472,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "Anda boleh **isi hadapan** nilai null, iaitu menggunakan nilai sah terakhir untuk mengisi null:\n" + "Anda boleh **isi ke depan** nilai null, iaitu menggunakan nilai sah terakhir untuk mengisi null:\n" ] }, { @@ -2513,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Anda juga boleh **mengisi semula** untuk menyebarkan nilai sah seterusnya ke belakang bagi mengisi null:\n" + "Anda juga boleh **isi semula** untuk menyebarkan nilai sah seterusnya ke belakang bagi mengisi null:\n" ] }, { @@ -2728,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Perhatikan bahawa apabila nilai sebelumnya tidak tersedia untuk pengisian ke hadapan, nilai null akan kekal.\n" + "Perhatikan bahawa apabila nilai sebelumnya tidak tersedia untuk pengisian ke hadapan, nilai null tetap ada.\n" ] }, { @@ -2737,7 +2743,7 @@ "id": "eeAoOU0RgRsJ" }, "source": [ - "### Senaman:\n" + "### Latihan:\n" ] }, { @@ -2854,7 +2860,7 @@ "source": [ "Perhatikan bahawa lajur 3 masih tidak mempunyai nilai: arah lalai adalah untuk mengisi nilai secara baris demi baris.\n", "\n", - "> **Kesimpulan:** Terdapat pelbagai cara untuk menangani nilai yang hilang dalam dataset anda. Strategi khusus yang anda gunakan (menghapusnya, menggantikannya, atau bahkan cara anda menggantikannya) harus ditentukan oleh keunikan data tersebut. Anda akan mengembangkan pemahaman yang lebih baik tentang cara menangani nilai yang hilang semakin banyak anda berurusan dan berinteraksi dengan dataset.\n" + "> **Kesimpulan:** Terdapat pelbagai cara untuk menangani nilai yang hilang dalam set data anda. Strategi khusus yang anda gunakan (menghapusnya, menggantikannya, atau bahkan cara anda menggantikannya) harus ditentukan oleh keunikan data tersebut. Anda akan mengembangkan pemahaman yang lebih baik tentang cara menangani nilai yang hilang semakin banyak anda mengurus dan berinteraksi dengan set data.\n" ] }, { @@ -2865,7 +2871,7 @@ "source": [ "### Pengekodan Data Kategori\n", "\n", - "Model pembelajaran mesin hanya berfungsi dengan nombor dan sebarang bentuk data berangka. Ia tidak dapat membezakan antara Ya dan Tidak, tetapi ia dapat membezakan antara 0 dan 1. Jadi, selepas mengisi nilai yang hilang, kita perlu mengekod data kategori kepada bentuk berangka supaya model dapat memahaminya.\n", + "Model pembelajaran mesin hanya berurusan dengan nombor dan sebarang bentuk data berangka. Ia tidak dapat membezakan antara Ya dan Tidak, tetapi ia boleh membezakan antara 0 dan 1. Jadi, selepas mengisi nilai yang hilang, kita perlu mengekod data kategori kepada bentuk berangka supaya model dapat memahaminya.\n", "\n", "Pengekodan boleh dilakukan dengan dua cara. Kita akan membincangkannya seterusnya.\n" ] @@ -2876,9 +2882,9 @@ "id": "uDq9SxB7mu5i" }, "source": [ - "**PENYANDIAN LABEL**\n", + "**PENKODAN LABEL**\n", "\n", - "Penyandian label pada dasarnya adalah menukar setiap kategori kepada nombor. Sebagai contoh, katakan kita mempunyai set data penumpang kapal terbang dan terdapat satu lajur yang mengandungi kelas mereka di antara ['kelas perniagaan', 'kelas ekonomi', 'kelas pertama']. Jika penyandian label dilakukan pada ini, ia akan ditukar kepada [0,1,2]. Mari kita lihat satu contoh melalui kod. Oleh kerana kita akan mempelajari `scikit-learn` dalam buku nota yang akan datang, kita tidak akan menggunakannya di sini.\n" + "Penkodan label pada dasarnya adalah menukar setiap kategori kepada nombor. Sebagai contoh, katakan kita mempunyai dataset penumpang penerbangan dan terdapat satu lajur yang mengandungi kelas mereka di antara ['kelas perniagaan', 'kelas ekonomi', 'kelas pertama']. Jika penkodan label dilakukan pada ini, ia akan ditukar kepada [0,1,2]. Mari kita lihat contoh melalui kod. Oleh kerana kita akan mempelajari `scikit-learn` dalam notebook yang akan datang, kita tidak akan menggunakannya di sini.\n" ] }, { @@ -3088,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Seperti yang kita lihat, hasilnya sepadan dengan apa yang kita jangkakan. Jadi, bila kita menggunakan label encoding? Label encoding digunakan dalam salah satu atau kedua-dua situasi berikut: \n", - "1. Apabila bilangan kategori adalah besar \n", - "2. Apabila kategori mempunyai susunan tertentu. \n" + "Seperti yang kita lihat, outputnya sepadan dengan apa yang kita jangkakan akan berlaku. Jadi, bila kita menggunakan pengekodan label? Pengekodan label digunakan dalam salah satu atau kedua-dua kes berikut:\n", + "1. Apabila bilangan kategori adalah besar\n", + "2. Apabila kategori mempunyai susunan.\n" ] }, { @@ -3101,9 +3107,9 @@ "source": [ "**PENKODAN SATU PANAS**\n", "\n", - "Satu lagi jenis penkodan ialah Penkodan Satu Panas. Dalam jenis penkodan ini, setiap kategori dalam lajur akan ditambah sebagai lajur berasingan dan setiap titik data akan mendapat nilai 0 atau 1 berdasarkan sama ada ia mengandungi kategori tersebut. Jadi, jika terdapat n kategori yang berbeza, n lajur akan ditambahkan ke dalam dataframe.\n", + "Satu lagi jenis penkodan ialah Penkodan Satu Panas (One Hot Encoding). Dalam jenis penkodan ini, setiap kategori dalam lajur akan ditambah sebagai lajur berasingan, dan setiap titik data akan mendapat nilai 0 atau 1 berdasarkan sama ada ia mengandungi kategori tersebut. Jadi, jika terdapat n kategori yang berbeza, n lajur akan ditambahkan ke dalam dataframe.\n", "\n", - "Sebagai contoh, mari kita ambil contoh kelas kapal terbang yang sama. Kategorinya adalah: ['business class', 'economy class', 'first class']. Jadi, jika kita melakukan penkodan satu panas, tiga lajur berikut akan ditambahkan ke dalam dataset: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Sebagai contoh, mari kita ambil contoh kelas kapal terbang yang sama. Kategorinya adalah: ['kelas perniagaan', 'kelas ekonomi', 'kelas pertama']. Jadi, jika kita melakukan penkodan satu panas, tiga lajur berikut akan ditambahkan ke dataset: ['class_kelas perniagaan', 'class_kelas ekonomi', 'class_kelas pertama'].\n" ] }, { @@ -3336,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Setiap lajur pengekodan panas mengandungi 0 atau 1, yang menentukan sama ada kategori itu wujud untuk titik data tersebut.\n" + "Setiap satu lajur yang dikodkan secara one-hot mengandungi 0 atau 1, yang menentukan sama ada kategori tersebut wujud untuk titik data itu.\n" ] }, { @@ -3345,9 +3351,9 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "Bilakah kita menggunakan pengekodan one hot? Pengekodan one hot digunakan dalam salah satu atau kedua-dua situasi berikut:\n", + "Bilakah kita menggunakan pengekodan satu panas? Pengekodan satu panas digunakan dalam salah satu atau kedua-dua kes berikut:\n", "\n", - "1. Apabila bilangan kategori dan saiz set data adalah kecil.\n", + "1. Apabila bilangan kategori dan saiz dataset adalah kecil.\n", "2. Apabila kategori tidak mengikut sebarang susunan tertentu.\n" ] }, @@ -3357,7 +3363,7 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Perkara Penting yang Perlu Diambil:\n", + "> Perkara Utama:\n", "1. Pengekodan dilakukan untuk menukar data bukan numerik kepada data numerik.\n", "2. Terdapat dua jenis pengekodan: Label encoding dan One Hot encoding, kedua-duanya boleh dilakukan berdasarkan keperluan dataset.\n" ] @@ -3372,7 +3378,7 @@ "\n", "> **Matlamat pembelajaran:** Pada akhir subseksyen ini, anda seharusnya berasa selesa mengenal pasti dan menghapuskan nilai pendua daripada DataFrames.\n", "\n", - "Selain daripada data yang hilang, anda juga akan sering menemui data pendua dalam set data dunia sebenar. Nasib baik, pandas menyediakan cara yang mudah untuk mengesan dan menghapuskan entri pendua.\n" + "Selain daripada data yang hilang, anda sering akan menemui data pendua dalam set data dunia sebenar. Nasib baik, pandas menyediakan cara yang mudah untuk mengesan dan menghapuskan entri pendua.\n" ] }, { @@ -3383,7 +3389,7 @@ "source": [ "### Mengenal pasti pendua: `duplicated`\n", "\n", - "Anda boleh mengenal pasti nilai pendua dengan mudah menggunakan kaedah `duplicated` dalam pandas, yang mengembalikan topeng Boolean yang menunjukkan sama ada entri dalam `DataFrame` adalah pendua daripada entri sebelumnya. Mari kita cipta satu lagi contoh `DataFrame` untuk melihat cara ini berfungsi.\n" + "Anda boleh dengan mudah mengenal pasti nilai pendua menggunakan kaedah `duplicated` dalam pandas, yang mengembalikan topeng Boolean yang menunjukkan sama ada entri dalam `DataFrame` adalah pendua daripada entri sebelumnya. Mari kita cipta satu lagi contoh `DataFrame` untuk melihat ini berfungsi.\n" ] }, { @@ -3596,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Kedua-dua `duplicated` dan `drop_duplicates` secara lalai mempertimbangkan semua lajur tetapi anda boleh menentukan bahawa ia hanya memeriksa subset lajur dalam `DataFrame` anda:\n" + "Kedua-dua `duplicated` dan `drop_duplicates` secara lalai mempertimbangkan semua lajur tetapi anda boleh menentukan bahawa mereka hanya memeriksa subset lajur dalam `DataFrame` anda:\n" ] }, { @@ -3672,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Pengajaran:** Menghapuskan data pendua adalah bahagian penting dalam hampir setiap projek sains data. Data pendua boleh mengubah hasil analisis anda dan memberikan keputusan yang tidak tepat!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pemeriksaan Kualiti Data Dunia Sebenar\n", + "\n", + "> **Matlamat pembelajaran:** Pada akhir bahagian ini, anda seharusnya berasa yakin untuk mengesan dan membetulkan isu kualiti data dunia sebenar yang biasa termasuk nilai kategori yang tidak konsisten, nilai numerik yang tidak normal (outlier), dan entiti pendua dengan variasi.\n", + "\n", + "Walaupun nilai yang hilang dan pendua yang tepat adalah masalah biasa, set data dunia sebenar sering mengandungi masalah yang lebih halus:\n", + "\n", + "1. **Nilai kategori yang tidak konsisten**: Kategori yang sama dieja dengan cara berbeza (contohnya, \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Nilai numerik yang tidak normal**: Outlier ekstrem yang menunjukkan kesilapan kemasukan data (contohnya, umur = 999)\n", + "3. **Baris hampir pendua**: Rekod yang mewakili entiti yang sama dengan sedikit variasi\n", + "\n", + "Mari kita terokai teknik untuk mengesan dan menangani isu-isu ini.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Membuat Dataset \"Kotor\" Contoh\n", + "\n", + "Pertama, mari kita buat dataset contoh yang mengandungi jenis masalah yang sering kita temui dalam data dunia sebenar:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Mengesan Nilai Kategori yang Tidak Konsisten\n", + "\n", + "Perhatikan bahawa lajur `country` mempunyai pelbagai representasi untuk negara yang sama. Mari kita kenal pasti ketidakkonsistenan ini:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Menyeragamkan Nilai Kategori\n", + "\n", + "Kita boleh membuat pemetaan untuk menyeragamkan nilai-nilai ini. Pendekatan mudah adalah dengan menukar kepada huruf kecil dan membuat kamus pemetaan:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternatif: Menggunakan Pencocokan Kabur**\n", + "\n", + "Untuk kes-kes yang lebih kompleks, kita boleh menggunakan pencocokan rentetan kabur dengan pustaka `rapidfuzz` untuk mengesan rentetan yang serupa secara automatik:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Mengesan Nilai Berangka Tidak Normal (Outliers)\n", + "\n", + "Melihat pada lajur `age`, terdapat beberapa nilai yang mencurigakan seperti 199 dan -5. Mari gunakan kaedah statistik untuk mengesan outlier ini.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Menggunakan Kaedah IQR (Interquartile Range)\n", + "\n", + "Kaedah IQR adalah teknik statistik yang kukuh untuk pengesanan nilai luar yang kurang sensitif terhadap nilai ekstrem:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Menggunakan Kaedah Z-Score\n", + "\n", + "Kaedah Z-score mengenal pasti nilai luar biasa berdasarkan sisihan piawai dari purata:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Mengendalikan Nilai Luar Biasa\n", + "\n", + "Setelah dikesan, nilai luar biasa boleh dikendalikan dengan beberapa cara:\n", + "1. **Buang**: Hapuskan baris dengan nilai luar biasa (jika ia adalah kesilapan)\n", + "2. **Hadkan**: Gantikan dengan nilai sempadan\n", + "3. **Gantikan dengan NaN**: Anggap sebagai data yang hilang dan gunakan teknik imputasi\n", + "4. **Simpan**: Jika ia adalah nilai ekstrem yang sah\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Mengesan Baris Hampir Serupa\n", + "\n", + "Perhatikan bahawa dataset kita mempunyai beberapa entri untuk \"John Smith\" dengan nilai yang sedikit berbeza. Mari kita kenal pasti kemungkinan pendua berdasarkan kesamaan nama.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Mencari Pendua Hampir Sama dengan Pencocokan Kabur\n", + "\n", + "Untuk pengesanan pendua yang lebih canggih, kita boleh menggunakan pencocokan kabur untuk mencari nama yang serupa:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Mengendalikan Pendua\n", + "\n", + "Setelah dikenal pasti, anda perlu memutuskan cara untuk mengendalikan pendua:\n", + "1. **Simpan kejadian pertama**: Gunakan `drop_duplicates(keep='first')`\n", + "2. **Simpan kejadian terakhir**: Gunakan `drop_duplicates(keep='last')`\n", + "3. **Gabungkan maklumat**: Satukan maklumat daripada baris pendua\n", + "4. **Semakan manual**: Tandakan untuk semakan manusia\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Ringkasan: Saluran Pembersihan Data Lengkap\n", + "\n", + "Mari kita gabungkan semuanya ke dalam saluran pembersihan yang menyeluruh:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Latihan Cabaran\n", + "\n", + "Sekarang giliran anda! Di bawah ini terdapat satu baris data baru dengan pelbagai isu kualiti. Bolehkah anda:\n", + "\n", + "1. Kenal pasti semua isu dalam baris ini\n", + "2. Tulis kod untuk membersihkan setiap isu\n", + "3. Tambahkan baris yang telah dibersihkan ke dalam set data\n", + "\n", + "Berikut adalah data yang bermasalah:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Perkara Penting\n", + "\n", + "1. **Kategori tidak konsisten** adalah perkara biasa dalam data dunia sebenar. Sentiasa periksa nilai unik dan standardkan menggunakan pemetaan atau padanan kabur.\n", + "\n", + "2. **Nilai luar biasa** boleh memberi kesan besar kepada analisis anda. Gunakan pengetahuan domain bersama kaedah statistik (IQR, Z-score) untuk mengesannya.\n", + "\n", + "3. **Hampir serupa** lebih sukar dikesan berbanding duplikasi tepat. Pertimbangkan menggunakan padanan kabur dan normalisasi data (huruf kecil, buang ruang kosong) untuk mengenal pasti mereka.\n", + "\n", + "4. **Pembersihan data adalah proses berulang**. Anda mungkin perlu menggunakan pelbagai teknik dan menyemak hasilnya sebelum memuktamadkan set data yang telah dibersihkan.\n", + "\n", + "5. **Dokumentasikan keputusan anda**. Simpan rekod langkah pembersihan yang telah anda gunakan dan sebabnya, kerana ini penting untuk kebolehulangan dan ketelusan.\n", + "\n", + "> **Amalan Terbaik:** Sentiasa simpan salinan data \"kotor\" asal anda. Jangan sesekali menulis ganti fail data sumber anda - buat versi yang telah dibersihkan dengan konvensyen penamaan yang jelas seperti `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Penafian**: \nDokumen ini telah diterjemahkan menggunakan perkhidmatan terjemahan AI [Co-op Translator](https://github.com/Azure/co-op-translator). Walaupun kami berusaha untuk memastikan ketepatan, sila ambil perhatian bahawa terjemahan automatik mungkin mengandungi kesilapan atau ketidaktepatan. Dokumen asal dalam bahasa asalnya harus dianggap sebagai sumber yang berwibawa. Untuk maklumat penting, terjemahan manusia profesional adalah disyorkan. Kami tidak bertanggungjawab atas sebarang salah faham atau salah tafsir yang timbul daripada penggunaan terjemahan ini.\n" + "\n---\n\n**Penafian**: \nDokumen ini telah diterjemahkan menggunakan perkhidmatan terjemahan AI [Co-op Translator](https://github.com/Azure/co-op-translator). Walaupun kami berusaha untuk memastikan ketepatan, sila ambil perhatian bahawa terjemahan automatik mungkin mengandungi kesilapan atau ketidaktepatan. Dokumen asal dalam bahasa asalnya harus dianggap sebagai sumber yang berwibawa. Untuk maklumat yang kritikal, terjemahan manusia profesional adalah disyorkan. Kami tidak bertanggungjawab atas sebarang salah faham atau salah tafsir yang timbul daripada penggunaan terjemahan ini.\n" ] } ], @@ -3706,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:11:22+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:42:33+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "ms" } diff --git a/translations/my/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/my/2-Working-With-Data/08-data-preparation/notebook.ipynb index 26af09fd..de27abc0 100644 --- a/translations/my/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/my/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -6,17 +6,17 @@ "id": "rQ8UhzFpgRra" }, "source": [ - "# ဒေတာ ပြင်ဆင်ခြင်း\n", + "# ဒေတာပြင်ဆင်ခြင်း\n", "\n", "[မူရင်း Notebook အရင်းအမြစ် *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", - "## `DataFrame` အချက်အလက်များ စူးစမ်းခြင်း\n", + "## `DataFrame` အချက်အလက်များကို စူးစမ်းခြင်း\n", "\n", - "> **သင်ယူရမည့် ရည်မှန်းချက်:** ဒီအပိုင်းလေးအဆုံးသတ်ချိန်မှာ pandas DataFrames ထဲမှာ သိမ်းဆည်းထားတဲ့ ဒေတာအကြောင်း အထွေထွေ အချက်အလက်တွေကို ရှာဖွေတတ်ဖို့ ရည်ရွယ်ပါတယ်။\n", + "> **သင်ယူရည်မှန်းချက်:** ဒီအခန်းငယ်ကို ပြီးဆုံးသွားတဲ့အခါမှာ pandas DataFrames ထဲမှာ သိမ်းဆည်းထားတဲ့ ဒေတာအကြောင်းကို အထွေထွေရှာဖွေတတ်ဖို့ သင်အဆင်ပြေဖြစ်နေပါလိမ့်မယ်။\n", "\n", - "သင့်ဒေတာကို pandas ထဲသို့ load လုပ်ပြီးတာနဲ့, ဒေတာဟာ `DataFrame` အနေနဲ့ ရှိနေမှာ သေချာပါတယ်။ ဒါပေမယ့် သင့် `DataFrame` ထဲမှာ အတန်း 60,000 ရှိပြီး ကော်လံ 400 ရှိနေခဲ့ရင်, သင်လုပ်နေတဲ့အရာကို ဘယ်လို စတင်နားလည်ရမလဲ? ကံကောင်းစွာ, pandas ဟာ `DataFrame` တစ်ခုရဲ့ အထွေထွေ အချက်အလက်တွေကို အလျင်အမြန် ကြည့်ရှုနိုင်ဖို့ အဆင်ပြေတဲ့ ကိရိယာတွေကို ပံ့ပိုးပေးထားပါတယ်။ ဒါ့အပြင်, ရှေ့ဆုံးအတန်းအချို့နဲ့ နောက်ဆုံးအတန်းအချို့ကိုလည်း မြင်နိုင်ပါတယ်။\n", + "သင့်ဒေတာကို pandas ထဲသို့ load လုပ်ပြီးတာနဲ့, ဒါဟာ `DataFrame` အနေနဲ့ရှိနေမှာ မလွဲမသွေပါဘူး။ သို့သော်, သင့် `DataFrame` ထဲမှာ အတန်း 60,000 ရှိပြီး ကော်လံ 400 ရှိတဲ့ ဒေတာ set ရှိရင်, သင်ဘာတွေနဲ့လုပ်ဆောင်နေတယ်ဆိုတာကို ဘယ်လိုစတင်နားလည်ရမလဲ? ကံကောင်းစွာ, pandas က `DataFrame` အကြောင်းအရာကို အမြန်ကြည့်ရှုနိုင်ဖို့အတွက် အဆင်ပြေတဲ့ tools တွေကို ပေးထားပါတယ်၊ ဒါ့အပြင် ပထမအတန်းအချို့နဲ့ နောက်ဆုံးအတန်းအချို့ကိုလည်း ကြည့်ရှုနိုင်ပါတယ်။\n", "\n", - "ဒီလုပ်ဆောင်ချက်ကို စူးစမ်းဖို့အတွက်, Python scikit-learn library ကို import လုပ်ပြီး, ဒေတာသိပ္ပံပညာရှင်တိုင်း သိပြီးသား dataset တစ်ခုကို အသုံးပြုပါမယ်။ ဒါကတော့ 1936 ခုနှစ်မှာ ဗြိတိသျှ ဇီဝဗေဒပညာရှင် Ronald Fisher ရေးသားခဲ့တဲ့ \"The use of multiple measurements in taxonomic problems\" စာတမ်းမှာ အသုံးပြုခဲ့တဲ့ *Iris* ဒေတာစနစ် ဖြစ်ပါတယ်။\n" + "ဒီလုပ်ဆောင်ချက်ကို စူးစမ်းဖို့အတွက်, Python scikit-learn library ကို import လုပ်ပြီး ဒေတာသိပ္ပံပညာရှင်တိုင်းကြုံတွေ့ဖူးတဲ့ dataset တစ်ခုကို အသုံးပြုပါမယ်။ ဒါကတော့ 1936 ခုနှစ်မှာ ဗြိတိသျှဇီဝဗေဒပညာရှင် Ronald Fisher ရဲ့ *Iris* ဒေတာ set ဖြစ်ပြီး, သူ့ရဲ့စာတမ်း \"The use of multiple measurements in taxonomic problems\" မှာ အသုံးပြုခဲ့တာဖြစ်ပါတယ်။\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "ကျွန်ုပ်တို့သည် Iris Dataset ကို `iris_df` ဟူသော variable အတွင်း load လုပ်ထားပါသည်။ ဒေတာများကို စတင်ကြည့်ရှုမည့်အချိန်တွင်၊ ကျွန်ုပ်တို့တွင် ရရှိထားသော datapoints အရေအတွက်နှင့် dataset ၏ စုစုပေါင်းအရွယ်အစားကို သိထားခြင်းမှာ အထောက်အကူဖြစ်ပါသည်။ ကျွန်ုပ်တို့ လက်ရှိ handling လုပ်နေသော ဒေတာ၏ ပမာဏကို ကြည့်ရှုခြင်းမှာ အရေးကြီးပါသည်။\n" + "ကျွန်ုပ်တို့သည် Iris Dataset ကို `iris_df` အမည်ရှိ variable ထဲသို့ load လုပ်ထားပါသည်။ ဒေတာကို စတင်လေ့လာမည့်အခါ၊ ကျွန်ုပ်တို့တွင်ရှိသော datapoints အရေအတွက်နှင့် dataset ၏ စုစုပေါင်းအရွယ်အစားကို သိထားခြင်းသည် အရေးကြီးပါသည်။ ကျွန်ုပ်တို့ကိုယ်တိုင် handling လုပ်နေသော ဒေတာပမာဏကို ကြည့်ရှုခြင်းသည် အကျိုးရှိစေပါသည်။\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "ဒီမှာ ၁၅၀ အတန်းနဲ့ ၄ ကော်လံရှိတဲ့ ဒေတာကို ကိုင်တွယ်နေရပါတယ်။ အတန်းတစ်ခုစီဟာ ဒေတာပွိုင့်တစ်ခုကို ကိုယ်စားပြုပြီး ကော်လံတစ်ခုစီဟာ ဒေတာဖရိမ်းနဲ့ ဆက်စပ်နေတဲ့ အင်္ဂါရပ်တစ်ခုစီကို ကိုယ်စားပြုပါတယ်။ အခြေခံအားဖြင့် ၁၅၀ ဒေတာပွိုင့်ရှိပြီး တစ်ခုစီမှာ ၄ အင်္ဂါရပ်ပါဝင်ပါတယ်။\n", + "ဒါဆိုရင် ကျွန်တော်တို့ ၁၅၀ ရိုးနှင့် ၄ ကော်လံပါသော ဒေတာကို ကိုင်တွယ်နေရပါတယ်။ ရိုးတစ်ရိုးစီဟာ ဒေတာပွင့်တစ်ခုကို ကိုယ်စားပြုပြီး ကော်လံတစ်ခုစီဟာ ဒေတာဖရိမ်းနဲ့ဆက်စပ်နေတဲ့ အင်္ဂါရပ်တစ်ခုကို ကိုယ်စားပြုပါတယ်။ ဒါကြောင့် အခြေခံအားဖြင့် ၁၅၀ ဒေတာပွင့်ရှိပြီး တစ်ခုစီမှာ အင်္ဂါရပ် ၄ ခုပါဝင်ပါတယ်။\n", "\n", - "`shape` ဟာ ဒီမှာ ဒေတာဖရိမ်းရဲ့ attribute ဖြစ်ပြီး function မဟုတ်တဲ့အတွက် parentheses တစ်စုံနဲ့ မဆုံးသွားပါဘူး။\n" + "`shape` ဟာ ဒီမှာ ဒေတာဖရိမ်းရဲ့ attribute ဖြစ်ပြီး function မဟုတ်ပါဘူး၊ ဒါကြောင့် parentheses တစ်စုံနဲ့ မဆုံးသွားတာပါ။\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "အခုတော့ ဒေတာရဲ့ ကော်လံ ၄ ခုကို ဆက်လက်လေ့လာကြမယ်။ အဲဒီကော်လံတစ်ခုချင်းစီက ဘာကို ကိုယ်စားပြုနေတာလဲဆိုတာ သိရအောင်။ `columns` attribute က dataframe ထဲမှာရှိတဲ့ ကော်လံနာမည်တွေကို ပြသပေးမှာ ဖြစ်ပါတယ်။\n" + "အခုတော့ ဒေတာရဲ့ ကော်လံ ၄ ခုဆီကို ရောက်ပါမယ်။ အဲဒီကော်လံတစ်ခုချင်းစီက တိတိကျကျ ဘာကို ကိုယ်စားပြုနေလဲဆိုတာကို ကြည့်ပါမယ်။ `columns` attribute က dataframe ထဲမှာရှိတဲ့ ကော်လံနာမည်တွေကို ပြပါလိမ့်မယ်။\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "ကျွန်တော်တို့မြင်နိုင်သည့်အတိုင်း၊ ကော်လံလေး(၄)ခုရှိပါတယ်။ `columns` attribute က ကော်လံတွေရဲ့အမည်ကိုပြောပြပေးပြီး အခြားဘာမှမပြောပြပါဘူး။ ဒီ attribute က ဒေတာစုပေါင်းတစ်ခုမှာပါဝင်တဲ့ features တွေကိုဖော်ထုတ်ချင်တဲ့အခါမှာ အရေးကြီးလာပါတယ်။\n" + "ကျွန်တော်တို့မြင်နိုင်သည့်အတိုင်း၊ ကော်လံလေး(၄)ခုရှိပါတယ်။ `columns` attribute က ကော်လံများ၏နာမည်ကိုပြောပြပေးပြီး အခြားအချက်အလက်မပါဝင်ပါဘူး။ ဒီ attribute က dataset တစ်ခုမှာပါဝင်တဲ့ features တွေကိုဖော်ထုတ်ချင်တဲ့အခါမှာ အရေးပါလာပါတယ်။\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "ဒေတာပမာဏ (`shape` attribute မှပေးထားသည်) နှင့် feature များ သို့မဟုတ် column များ၏အမည်များ (`columns` attribute မှပေးထားသည်) သည် dataset အကြောင်းအချို့ကို ပြောပြပေးသည်။ အခုတော့ dataset ကို ပိုမိုနက်နက်ရှိုင်းရှိုင်း လေ့လာလိုပါသည်။ `DataFrame.info()` function သည် အလွန်အသုံးဝင်သော function တစ်ခုဖြစ်သည်။\n" + "`shape` attribute ကပေးတဲ့ ဒေတာပမာဏနဲ့ `columns` attribute ကပေးတဲ့ feature တွေ၊ column အမည်တွေက dataset အကြောင်းအချို့ကို ပြောပြပေးပါတယ်။ အခုတော့ dataset ကို ပိုမိုနက်နက်ရှိုင်းရှိုင်း လေ့လာချင်ပါတယ်။ `DataFrame.info()` function က အရမ်းအသုံးဝင်ပါတယ်။\n" ] }, { @@ -180,10 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "ဒီနေရာကနေ အချို့အချက်အလက်တွေကို သတိပြုနိုင်ပါတယ် -\n", - "\n", - "1. ကော်လံတစ်ခုချင်းစီရဲ့ DataType: ဒီဒေတာအစုအဝေးမှာ ဒေတာအားလုံးကို 64-bit floating-point နံပါတ်အနေနဲ့ သိမ်းဆည်းထားပါတယ်။\n", - "2. Non-Null အတန်းအရေအတွက်: Null တန်ဖိုးတွေကို ကိုင်တွယ်ဖို့က ဒေတာပြင်ဆင်မှုအဆင့်မှာ အရေးကြီးတဲ့အဆင့်တစ်ခုဖြစ်ပါတယ်။ ဒါကို နောက်ပိုင်း notebook မှာ ကိုင်တွယ်သွားမှာဖြစ်ပါတယ်။\n" + "ဒီနေရာကနေ အချို့အချက်အလက်တွေကို သတိပြုနိုင်ပါတယ်။\n", + "1. တစ်ခုချင်းကော်လံရဲ့ DataType: ဒီ dataset မှာ အချက်အလက်အားလုံးကို 64-bit floating-point နံပါတ်အနေနဲ့ သိမ်းဆည်းထားပါတယ်။\n", + "2. Non-Null အတန်းအရေအတွက်: Null values ကို ကိုင်တွယ်ဖို့က Data preparation အဆင့်မှာ အရေးကြီးတဲ့အဆင့်တစ်ခုဖြစ်ပါတယ်။ ဒါကို notebook ရဲ့ နောက်ပိုင်းမှာ ကိုင်တွယ်သွားမှာဖြစ်ပါတယ်။\n" ] }, { @@ -193,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "ကျွန်တော်တို့ dataset မှာ ကိန်းဂဏန်းအချက်အလက်များ များစွာရှိတယ်လို့ ဆိုပါစို့။ mean, median, quartiles စတဲ့ တစ်ခုချင်းစီ column တွေမှာ univariate စာရင်းဇယားတွက်ချက်မှုတွေကို ပြုလုပ်နိုင်ပါတယ်။ `DataFrame.describe()` function က dataset ရဲ့ ကိန်းဂဏန်း column တွေကို စာရင်းဇယားအကျဉ်းချုပ်ပေးပါတယ်။\n" + "ကျွန်တော်တို့ dataset မှာ အရေအတွက်ဆိုင်ရာ ဒေတာများ များစွာရှိတယ်လို့ ဆိုပါစို့။ mean, median, quartiles စတဲ့ တစ်ခုချင်းစီ column တွေမှာ သီးသန့် အဆင့်တစ်ခုချင်းစီ ရှိတဲ့ စာရင်းဇယားဆိုင်ရာ တွက်ချက်မှုတွေကို ပြုလုပ်နိုင်ပါတယ်။ `DataFrame.describe()` function က dataset ရဲ့ အရေအတွက်ဆိုင်ရာ column တွေကို စာရင်းဇယားဆိုင်ရာ အကျဉ်းချုပ်ပေးပါတယ်။\n" ] }, { @@ -323,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "အထက်ပါအထွက်သည် ကော်လံတစ်ခုချင်းစီ၏ စုစုပေါင်းဒေတာအချက်အလက်အရေအတွက်၊ ပျမ်းမျှတန်ဖိုး၊ စံအရွေ့၊ အနည်းဆုံးတန်ဖိုး၊ အောက်ပိုင်းလေးပုံတစ်ပုံ (25%)၊ အလယ်တန်းတန်ဖိုး (50%)၊ အထက်ပိုင်းလေးပုံတစ်ပုံ (75%) နှင့် အများဆုံးတန်ဖိုးကို ပြသထားသည်။\n" + "အထက်တွင် ဖော်ပြထားသော အထွက်သည် ကော်လံတစ်ခုချင်းစီ၏ ဒေတာအချက်အလက်စုစုပေါင်းအရေအတွက်၊ ပျမ်းမျှတန်ဖိုး၊ စံအလျားချုပ်၊ အနည်းဆုံးတန်ဖိုး၊ အောက်ပိုင်းတစ်စိတ် ၄ ပုံ ၁ (25%)၊ အလယ်တန်းတန်ဖိုး (50%)၊ အပေါ်ပိုင်းတစ်စိတ် ၄ ပုံ ၃ (75%) နှင့် အများဆုံးတန်ဖိုးတို့ကို ဖော်ပြထားသည်။\n" ] }, { @@ -333,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "အထက်ပါ function နှင့် attribute အားလုံးကို အသုံးပြုပြီးနောက်၊ dataset ရဲ့ အထက်ဆုံးအခြေအနေကို ကြည့်ရှုနိုင်ပါပြီ။ ဒေတာအချက်အလက်များ ဘယ်လောက်ရှိသလဲ၊ feature များ ဘယ်နှစ်ခုရှိသလဲ၊ feature တစ်ခုချင်းစီရဲ့ data type ဘယ်လိုလဲ၊ feature တစ်ခုချင်းစီမှာ null မဟုတ်တဲ့ အချက်အလက်အရေအတွက် ဘယ်လောက်ရှိသလဲဆိုတာကို သိရှိနိုင်ပါပြီ။\n", + "အထက်ပါ function တွေ၊ attribute တွေကို အသုံးပြုပြီးနောက်မှာ dataset ရဲ့ အထက်လွှာအမြင်ကို ရရှိခဲ့ပါပြီ။ အဲဒီ dataset မှာ data point အရေအတွက်ဘယ်လောက်ရှိသလဲ၊ feature အရေအတွက်ဘယ်လောက်ရှိသလဲ၊ feature တစ်ခုချင်းစီရဲ့ data type ဘယ်လိုလဲ၊ feature တစ်ခုချင်းစီမှာ non-null value အရေအတွက်ဘယ်လောက်ရှိသလဲဆိုတာကို သိရှိခဲ့ပါပြီ။\n", "\n", - "အခုတော့ ဒေတာကို ကိုယ်တိုင်ကြည့်မယ့်အချိန်ရောက်ပါပြီ။ `DataFrame` ရဲ့ ပထမဆုံးတန်းများ (ပထမဆုံး data point များ) ဘယ်လိုပုံစံရှိလဲဆိုတာ ကြည့်ကြရအောင်:\n" + "အခုတော့ data ကို ကိုယ်တိုင်ကြည့်ဖို့အချိန်ရောက်ပါပြီ။ `DataFrame` ရဲ့ ပထမဆုံးအတန်းတွေ (ပထမဆုံး data point တွေ) ဘယ်လိုပုံစံရှိလဲဆိုတာ ကြည့်လိုက်ရအောင်:\n" ] }, { @@ -442,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "ဒီအထွက်မှာ ကျွန်တော်တို့ ဒေတာဆက်တင်ရဲ့ အချက်အလက်ငါး(၅) ခုကို မြင်နိုင်ပါတယ်။ ဘယ်ဘက်မှာရှိတဲ့ အညွှန်းကိုကြည့်မယ်ဆိုရင်၊ ဒါတွေက ပထမငါးတန်းအတန်းဖြစ်တယ်ဆိုတာ သိနိုင်ပါတယ်။\n" + "ဒီအထွက်မှာ၊ ဒေတာစနစ်ရဲ့ အချက်အလက်ငါး(၅) ခုကို မြင်နိုင်ပါတယ်။ ဘယ်ဘက်မှာရှိတဲ့ အညွှန်းကိုကြည့်မယ်ဆိုရင်၊ ဒါတွေဟာ ပထမ ငါးတန်းအတန်းတွေဖြစ်တယ်ဆိုတာ သိနိုင်ပါတယ်။\n" ] }, { @@ -453,7 +452,7 @@ "source": [ "### လေ့ကျင့်ခန်း:\n", "\n", - "အထက်မှာပေးထားတဲ့ ဥပမာအရ `DataFrame.head` က ပုံမှန်အားဖြင့် `DataFrame` ရဲ့ ပထမဆုံးအတန်း ၅ ခုကို ပြန်ပေးတယ်ဆိုတာ ရှင်းလင်းပါတယ်။ အောက်မှာရှိတဲ့ ကုဒ်ဆဲလ်မှာ၊ အတန်း ၅ ခုထက် ပိုမိုပြသနိုင်တဲ့ နည်းလမ်းကို ရှာဖွေနိုင်မလား?\n" + "အထက်မှာပေးထားတဲ့ ဥပမာအရ `DataFrame.head` က `DataFrame` ရဲ့ ပထမဆုံးအတန်း ၅ ခုကို ပုံမှန်အတိုင်း ပြန်ပေးတယ်ဆိုတာ သိရပါတယ်။ အောက်မှာရှိတဲ့ code cell မှာ အတန်း ၅ ခုထက်ပိုပြီး ပြသနိုင်တဲ့ နည်းလမ်းကို ရှာဖွေနိုင်မလား?\n" ] }, { @@ -476,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "ဒေတာကိုကြည့်ရှုရန် နောက်ဆုံးပိုင်းမှစ၍လည်း ကြည့်နိုင်ပါတယ် (အစမှမဟုတ်ပါဘူး)။ `DataFrame.head` ၏ တစ်ဖက်ခြမ်းအနေနှင့် `DataFrame.tail` သည် `DataFrame` ၏ နောက်ဆုံးအတန်း ၅ ခုကို ပြန်ပေးပါသည်။\n" + "ဒေတာကိုကြည့်ရှုခြင်းအခြားနည်းလမ်းတစ်ခုမှာ အစမဟုတ်ဘဲ အဆုံးမှစပြီးကြည့်ရှုခြင်းဖြစ်နိုင်ပါတယ်။ `DataFrame.head` ရဲ့ အတိမ်းအနောက်မှာ `DataFrame.tail` ရှိပြီး၊ ဒါဟာ `DataFrame` ရဲ့ နောက်ဆုံးအတန်း ၅ ခုကို ပြန်ပေးပါသည်။\n" ] }, { @@ -583,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "အလေ့အထ၏အရ၊ အစီအစဉ်တစ်ခုတွင် အစောပိုင်းအတန်းများ သို့မဟုတ် နောက်ဆုံးအတန်းများကို လွယ်ကူစွာ ကြည့်ရှုနိုင်ခြင်းသည် အထူးသဖြင့် အစီအစဉ်တစ်ခုတွင် အစီအစဉ်ထားသော ဒေတာများတွင် အထူးသဖြင့် အထူးအချက်အလက်များ (outliers) ကို ရှာဖွေလိုသောအခါ အထောက်အကူဖြစ်သည်။\n", + "အလေ့အကျင့်အရ၊ အစီအစဉ်တကျထားရှိသော ဒေတာများတွင် အထူးသဖြင့် အထူးအချက်အလက်များကို ရှာဖွေနေစဉ် `DataFrame` ၏ အစပိုင်းအတန်းများ သို့မဟုတ် အဆုံးပိုင်းအတန်းများကို လွယ်ကူစွာ ကြည့်ရှုနိုင်ခြင်းသည် အကျိုးရှိစေပါသည်။\n", "\n", - "အထက်တွင် ဖော်ပြထားသည့် function များနှင့် attribute များအားလုံးကို ကုဒ်ဥပမာများဖြင့် ဖော်ပြထားပြီး၊ ဒေတာ၏ ပုံစံနှင့် အကြောင်းအရာကို နားလည်ရန် ကူညီပေးသည်။\n", + "ကုဒ်နမူနာများ၏ အကူအညီဖြင့် ပြသထားသော အထက်ပါ လုပ်ဆောင်ချက်များနှင့် အင်္ဂါရပ်များသည် ဒေတာ၏ ပုံစံနှင့် ခံစားမှုကို ရရှိစေပါသည်။\n", "\n", - "> **အဓိကအချက်:** `DataFrame` တစ်ခုအတွင်းရှိ အချက်အလက်များနှင့် ပတ်သက်သော metadata ကို ကြည့်ရှုခြင်းဖြစ်စေ၊ ဒါမှမဟုတ် အစောပိုင်းနှင့် နောက်ဆုံးတန်းများကိုသာ ကြည့်ရှုခြင်းဖြစ်စေ၊ သင်ကြည့်ရှုနေသော ဒေတာ၏ အရွယ်အစား၊ ပုံစံနှင့် အကြောင်းအရာကို ချက်ချင်းနားလည်နိုင်သည်။\n" + "> **အရေးကြီးသောအချက်:** `DataFrame` တစ်ခု၏ အချက်အလက်များနှင့် ပတ်သက်သော metadata သို့မဟုတ် အစပိုင်းနှင့် အဆုံးပိုင်းတန်ဖိုးများကို ကြည့်ရှုခြင်းဖြင့် သင်လုပ်ဆောင်နေသော ဒေတာ၏ အရွယ်အစား၊ ပုံစံနှင့် အကြောင်းအရာကို ချက်ချင်းနားလည်နိုင်စေပါသည်။\n" ] }, { @@ -597,17 +596,17 @@ }, "source": [ "### မရှိသော ဒေတာ\n", - "မရှိသော ဒေတာအကြောင်းကို ဆွေးနွေးကြမယ်။ မရှိသော ဒေတာဆိုတာ အတန်းတစ်ချို့မှာ တန်ဖိုးမရှိတဲ့အခါ ဖြစ်ပေါ်လာတာပါ။\n", + "မရှိသော ဒေတာအကြောင်းကို ဆွေးနွေးကြမယ်။ ဒေတာမရှိတာဆိုတာ အချို့ကော်လံတွေမှာ တန်ဖိုးမရှိတဲ့အခါ ဖြစ်ပေါ်လာတာပါ။\n", "\n", - "ဥပမာတစ်ခုကို ယူကြည့်ရအောင်။ တစ်ဦးတစ်ယောက်ဟာ သူ့ရဲ့ ကိုယ်အလေးချိန်ကို စိတ်ဝင်စားပြီး စစ်တမ်းမှာ ကိုယ်အလေးချိန်ကွက်လပ်ကို မဖြည့်ဘူးလို့ ဆိုရင်၊ အဲ့ဒီလူရဲ့ ကိုယ်အလေးချိန်တန်ဖိုးဟာ မရှိတော့ပါဘူး။\n", + "ဥပမာတစ်ခုကို ယူကြည့်ရအောင်။ တစ်ဦးတစ်ယောက်ဟာ သူ့ရဲ့အလေးချိန်ကို အလွန်ဂရုစိုက်ပြီး စစ်တမ်းမှာ အလေးချိန်ကွက်လပ်ကို မဖြည့်ဘူးဆိုပါစို့။ ဒီလိုဆိုရင် အဲ့ဒီလူရဲ့ အလေးချိန်တန်ဖိုးက မရှိတော့ပါဘူး။\n", "\n", - "အများအားဖြင့်၊ အမှန်တကယ်ရှိတဲ့ ဒေတာအစုအဝေးတွေမှာ မရှိသော တန်ဖိုးတွေ ဖြစ်ပေါ်လေ့ရှိပါတယ်။\n", + "အများအားဖြင့် အမှန်တကယ်ကမ္ဘာ့ဒေတာအစုအဝေးတွေမှာ တန်ဖိုးမရှိတာတွေ ဖြစ်ပေါ်လေ့ရှိပါတယ်။\n", "\n", - "**Pandas က မရှိသော ဒေတာကို ဘယ်လို ကိုင်တွယ်သလဲ**\n", + "**Pandas က မရှိသော ဒေတာကို ဘယ်လိုကိုင်တွယ်သလဲ**\n", "\n", - "Pandas က မရှိသော တန်ဖိုးတွေကို နှစ်မျိုးနည်းလမ်းနဲ့ ကိုင်တွယ်ပါတယ်။ ပထမနည်းလမ်းကို မိမိဟာ အရင်ပိုင်းက အပိုင်းတွေမှာ တွေ့ဖူးပြီးသားဖြစ်ပါတယ်။ အဲ့ဒါက `NaN` (Not a Number) ပါ။ ဒါဟာ IEEE floating-point specification ရဲ့ အထူးတန်ဖိုးတစ်ခုဖြစ်ပြီး၊ မရှိသော floating-point တန်ဖိုးတွေကို ဖော်ပြဖို့ သီးသန့်အသုံးပြုပါတယ်။\n", + "Pandas က မရှိသော တန်ဖိုးတွေကို နှစ်မျိုးနည်းနဲ့ ကိုင်တွယ်ပါတယ်။ ပထမနည်းကတော့ အရင်ပိုင်းက အပိုင်းတွေမှာ တွေ့ဖူးတဲ့ `NaN` (Not a Number) ပါ။ ဒါဟာ IEEE floating-point specification ရဲ့ အထူးတန်ဖိုးတစ်ခုဖြစ်ပြီး floating-point တန်ဖိုးမရှိတဲ့အခါကို ဖော်ပြဖို့ သီးသန့်အသုံးပြုပါတယ်။\n", "\n", - "Floating-point မဟုတ်တဲ့ မရှိသော တန်ဖိုးတွေကို pandas က Python ရဲ့ `None` object ကို အသုံးပြုပါတယ်။ `None` နဲ့ `NaN` ဟာ အဓိပ္ပါယ်တူတူပုံရပေမယ့်၊ ဒီဒီဇိုင်းရွေးချယ်မှုဟာ အစီအစဉ်ရေးသားမှုအရ သင့်တော်တဲ့အကြောင်းရင်းတွေရှိပြီး၊ အများဆုံးအခြေအနေတွေမှာ pandas ကို သင့်တော်တဲ့နည်းလမ်းတစ်ခုအဖြစ် ပေးစွမ်းနိုင်စေပါတယ်။ ဒါပေမယ့် `None` နဲ့ `NaN` နှစ်ခုလုံးမှာ သုံးစွဲပုံနဲ့ ပတ်သက်ပြီး သတိထားရမယ့် ကန့်သတ်ချက်တွေ ရှိပါတယ်။\n" + "Floating-point တန်ဖိုးတွေမရှိတဲ့အခြေအနေအပြင် အခြားတန်ဖိုးမရှိတဲ့အခါမှာတော့ pandas က Python ရဲ့ `None` object ကို အသုံးပြုပါတယ်။ `None` နဲ့ `NaN` ဟာ အဓိပ္ပါယ်တူတူပေမယ့် နှစ်မျိုးနည်းနဲ့ ကိုင်တွယ်ရတာဟာ အစီအစဉ်ရေးသားမှုအရ အကြောင်းပြချက်ရှိပြီး၊ အများဆုံးအခြေအနေတွေမှာ pandas က အကောင်းဆုံးဖြေရှင်းနည်းကို ပေးနိုင်ဖို့ ဒီနည်းလမ်းကို သုံးတာပါ။ ဒါပေမယ့် `None` နဲ့ `NaN` နှစ်ခုလုံးမှာ သတ်မှတ်ချက်တွေရှိပြီး၊ အဲ့ဒီအရာတွေကို ဘယ်လိုအသုံးပြုရမလဲဆိုတာ သတိထားဖို့ လိုအပ်ပါတယ်။\n" ] }, { @@ -617,9 +616,9 @@ }, "source": [ "### `None`: non-float missing data\n", - "`None` သည် Python မှလာသောကြောင့်၊ ဒါကို NumPy နှင့် pandas ၏ `'object'` data type မဟုတ်သော arrays တွင် အသုံးမပြုနိုင်ပါ။ သတိပြုပါ၊ NumPy arrays (နှင့် pandas ၏ data structures) တွင် တစ်မျိုးတည်းသော data type ကိုသာ ပါဝင်နိုင်သည်။ ဒါက သူတို့ကို အကြီးစား data နှင့် ကွန်ပျူတာဆိုင်ရာ အလုပ်များအတွက် အလွန်အစွမ်းထက်စေသော်လည်း၊ flexibility ကို ကန့်သတ်စေသည်။ အဲဒီလို arrays တွေဟာ “အနိမ့်ဆုံး ပေါင်းစည်းနိုင်သော အမျိုးအစား” (lowest common denominator) သို့ အမျိုးအစားကို အလိုအလျောက် ပြောင်းလဲရမည်ဖြစ်သည်၊ ဒါကတော့ array ထဲမှာရှိသမျှကို အုပ်စည်းနိုင်မည့် data type ဖြစ်သည်။ `None` ကို array ထဲမှာ ထည့်လိုက်တဲ့အခါ၊ Python objects တွေနဲ့ အလုပ်လုပ်နေရတယ်ဆိုတာကို ဆိုလိုပါတယ်။\n", + "`None` သည် Python မှလာသောကြောင့် `'object'` data type မဟုတ်သော NumPy နှင့် pandas arrays တွင် အသုံးမပြုနိုင်ပါ။ NumPy arrays (နှင့် pandas တွင်ပါဝင်သော data structures) သည် data အမျိုးအစားတစ်မျိုးသာ ပါဝင်နိုင်သည်ကို မှတ်ထားပါ။ ၎င်းသည် အကြီးစား data နှင့် တွက်ချက်မှုလုပ်ငန်းများအတွက် အလွန်အစွမ်းထက်သောစွမ်းရည်ကို ပေးစွမ်းနိုင်သော်လည်း, flexibility ကို ကန့်သတ်ထားသည်။ ထို arrays များသည် array အတွင်းရှိ အရာအားလုံးကို အကျုံးဝင်စေမည့် “lowest common denominator” data type သို့ အလိုအလျောက်ပြောင်းလဲရမည်ဖြစ်သည်။ `None` သည် array အတွင်းရှိနေသည်ဆိုပါက, သင်သည် Python objects များနှင့်အလုပ်လုပ်နေသည်ကို ဆိုလိုသည်။\n", "\n", - "ဒီအရာကို လက်တွေ့ကြည့်ရှုရန် အောက်ပါ ဥပမာ array ကို သုံးပါ (ဒီမှာ `dtype` ကို သတိပြုကြည့်ပါ):\n" + "ဤအရာကို လက်တွေ့ကြည့်ရှုရန်, အောက်ပါ ဥပမာ array ကို စဉ်းစားပါ (၎င်း၏ `dtype` ကို သတိပြုပါ):\n" ] }, { @@ -658,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "အချက်အလက်အမျိုးအစားများကို အထက်တင်သုံးစွဲခြင်း၏ အကျိုးဆက်နှစ်ခုရှိပါသည်။ ပထမအနေနှင့် လုပ်ဆောင်မှုများကို NumPy ကုဒ်ကို ကုန်သွင်းထားသောအစား Python အဓိပ္ပါယ်ဖော်ပြထားသောကုဒ်အဆင့်တွင် ဆောင်ရွက်မည်ဖြစ်သည်။ အဓိကအားဖြင့်၊ ၎င်းသည် `Series` သို့မဟုတ် `DataFrames` တွင် `None` ပါဝင်နေသော လုပ်ဆောင်မှုများသည် ပိုမိုနှေးကွေးလာမည်ဖြစ်ကြောင်းကို ဆိုလိုသည်။ သင်သည် ယင်းဆောင်ရွက်မှုအရှိန်ကျဆင်းမှုကို မသိသာနိုင်ပေမယ့်၊ ဒေတာအစုအဝေးများအတွက်တော့ ပြဿနာတစ်ခုဖြစ်လာနိုင်ပါသည်။\n", + "အမြင့်တင်ထားသော ဒေတာအမျိုးအစားများ၏ အမှန်တရားသည် အကျိုးသက်ရောက်မှုနှစ်ခုကို လိုက်ပါလာသည်။ ပထမတစ်ခုမှာ လုပ်ဆောင်မှုများကို NumPy ကုဒ်ကို စုစည်းထားသောအဆင့်မဟုတ်ဘဲ Python ကုဒ်ကို အဓိကထားသောအဆင့်တွင် ဆောင်ရွက်မည်ဖြစ်သည်။ အဓိကအားဖြင့် ဒါက `Series` သို့မဟုတ် `DataFrames` တွင် `None` ပါဝင်သော လုပ်ဆောင်မှုများသည် ပိုနှေးကွေးမည်ဖြစ်သည်ဟု ဆိုလိုသည်။ သင်သည် ဒီစွမ်းဆောင်ရည်ကျဆင်းမှုကို မသိသာနိုင်လောက်ပေမယ့်၊ ဒေတာအစုအဝေးများအတွက်တော့ ဒါဟာ ပြဿနာတစ်ခုဖြစ်လာနိုင်သည်။\n", "\n", - "ဒုတိယအကျိုးဆက်သည် ပထမအကျိုးဆက်မှ ဆင်းသက်လာသည်။ `None` သည် `Series` သို့မဟုတ် `DataFrame`s များကို သာမာန် Python ကမ္ဘာသို့ ပြန်ဆွဲဆောင်သည့်အတွက်၊ `sum()` သို့မဟုတ် `min()` ကဲ့သို့သော NumPy/pandas အစုစုပေါင်းလုပ်ဆောင်မှုများကို `None` တန်ဖိုးပါဝင်သော အစုအဝေးများတွင် အသုံးပြုပါက ပုံမှန်အားဖြင့် အမှားတစ်ခုကို ဖြစ်ပေါ်စေမည်ဖြစ်သည်-\n" + "ဒုတိယအကျိုးသက်ရောက်မှုသည် ပထမအကျိုးသက်ရောက်မှုမှ ဆင်းသက်လာသည်။ `None` သည် `Series` သို့မဟုတ် `DataFrame`s ကို သာမန် Python ကမ္ဘာသို့ ပြန်ဆွဲခေါ်သည့်အတွက်၊ `sum()` သို့မဟုတ် `min()` ကဲ့သို့သော NumPy/pandas အစုချုပ်မှုများကို `None` တန်ဖိုးပါဝင်သော array များပေါ်တွင် အသုံးပြုပါက အများအားဖြင့် အမှားတစ်ခုကို ဖြစ်ပေါ်စေမည်ဖြစ်သည်။\n" ] }, { @@ -698,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**အဓိကအချက်**: အင်တဂါများနှင့် `None` အတန်ဖိုးများအကြား တွက်ချက်မှု (နှင့်အခြားလုပ်ဆောင်မှုများ) သတ်မှတ်ထားခြင်းမရှိပါ၊ ဒါကြောင့် ၎င်းတို့ပါဝင်သော ဒေတာစုများနှင့်လုပ်ဆောင်နိုင်သည့်အရာများကို ကန့်သတ်နိုင်ပါသည်။\n" + ] }, { "cell_type": "markdown", @@ -708,7 +709,7 @@ "source": [ "### `NaN`: မရှိသော float တန်ဖိုးများ\n", "\n", - "`None` နှင့်မတူဘဲ၊ NumPy (နှင့် pandas) သည် ၎င်း၏ အမြန်နှုန်းမြင့်သော၊ ဗက်တာအခြေပြု လုပ်ဆောင်မှုများနှင့် ufuncs များအတွက် `NaN` ကို ပံ့ပိုးပေးပါသည်။ သတင်းမကောင်းကတော့ `NaN` ပေါ်တွင် အာရုံစိုက်သော သင်္ချာဆိုင်ရာ လုပ်ဆောင်မှုများကို ပြုလုပ်သည့်အခါ အမြဲတမ်း `NaN` ကိုသာ ရလဒ်အဖြစ် ရရှိမည်ဖြစ်သည်။ ဥပမာအားဖြင့် - \n" + "`None` နှင့်မတူဘဲ NumPy (အထူးသဖြင့် pandas) သည် `NaN` ကို ၎င်း၏ အမြန်နှုန်းမြင့်သော vectorized လုပ်ဆောင်မှုများနှင့် ufuncs များအတွက် ပံ့ပိုးပေးသည်။ သို့သော် မကောင်းသောအချက်မှာ `NaN` ပေါ်တွင် အရေအတွက်ဆိုင်ရာ လုပ်ဆောင်မှုများကို ပြုလုပ်သည့်အခါ အမြဲတမ်း `NaN` ဖြစ်သွားမည်ဖြစ်သည်။ ဥပမာ:\n" ] }, { @@ -771,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "သတင်းကောင်းတစ်ခုကတော့ `NaN` ပါဝင်တဲ့ အရေအတွက်များပေါ်မှာ aggregation များကို လုပ်ဆောင်တဲ့အခါ အမှားများ မပေါက်ဖွားပါဘူး။ သတင်းဆိုးကတော့ ရလဒ်များသည် တစ်သမတ်တည်း အသုံးဝင်မှု မရှိကြောင်း ဖြစ်ပါတယ်။\n" + "အကြောင်းကောင်းတစ်ခုကတော့ `NaN` ပါဝင်တဲ့ array တွေမှာ aggregation တွေ run လုပ်တဲ့အခါ error မပေါက်ပါဘူး။ အကြောင်းမကောင်းတစ်ခုကတော့ ရလဒ်တွေဟာ အတူတူအသုံးဝင်တဲ့အရာမဟုတ်ပါဘူး။\n" ] }, { @@ -807,7 +808,9 @@ "metadata": { "id": "nhlnNJT7gRr_" }, - "source": [] + "source": [ + "### လေ့ကျင့်မှု:\n" + ] }, { "cell_type": "code", @@ -827,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "မှတ်ထားပါ။ `NaN` သည် မရှိသော floating-point အတန်းများအတွက်သာ ဖြစ်ပြီး၊ integers, strings, သို့မဟုတ် Booleans အတွက် `NaN` နှင့် ညီမျှသော အရာမရှိပါ။\n" + ] }, { "cell_type": "markdown", @@ -837,7 +842,7 @@ "source": [ "### `NaN` နှင့် `None`: pandas တွင် null အတန်တန်များ\n", "\n", - "`NaN` နှင့် `None` တို့သည် အချို့ကွဲပြားမှုများရှိနိုင်သော်လည်း pandas သည် အတူတူအသုံးပြုနိုင်ရန် အဆင်ပြေစွာ ဖန်တီးထားသည်။ ဥပမာအားဖြင့် အောက်ပါ `Series` အတွက် စဉ်းစားကြည့်ပါ:\n" + "`NaN` နှင့် `None` တို့သည် အချို့အခါ အပြုအမူကွဲပြားနိုင်သော်လည်း pandas သည် အတူတူအသုံးပြုနိုင်ရန် ဖန်တီးထားသည်။ ဥပမာအားဖြင့် အောက်ပါ `Series` အတွက် ကြည့်ပါ:\n" ] }, { @@ -876,7 +881,9 @@ "metadata": { "id": "WklCzqb8gRsB" }, - "source": [] + "source": [ + "### လေ့ကျင့်မှု:\n" + ] }, { "cell_type": "code", @@ -899,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "ဒေတာအမျိုးအစားများကို `Series` နှင့် `DataFrame` များတွင် တူညီမှုရှိစေရန် အဆင့်မြှင့်တင်ရာတွင် pandas သည် `None` နှင့် `NaN` အကြား မရှိမဖြစ်တန်ဖိုးများကို အလွယ်တကူ ပြောင်းလဲပေးနိုင်သည်။ ဒီဒီဇိုင်းအင်္ဂါရပ်ကြောင့် pandas တွင် `None` နှင့် `NaN` ကို \"null\" အမျိုးအစားနှစ်မျိုးအဖြစ် သတ်မှတ်စဉ်းစားနိုင်သည်။ တကယ်တော့, pandas တွင် မရှိမဖြစ်တန်ဖိုးများကို ကိုင်တွယ်ရန် အသုံးပြုသော အခြေခံနည်းလမ်းများသည် ဒီအယူအဆကို သူတို့၏အမည်များတွင်ပါ ထင်ဟပ်ပြသထားသည်။\n", + "`Series` နှင့် `DataFrame` များတွင် ဒေတာအမျိုးအစားများကို တူညီမှုရှိစေရန်အတွက် အမျိုးအစားမြှင့်တင်ခြင်းလုပ်ငန်းစဉ်တွင် pandas သည် `None` နှင့် `NaN` အကြား ပျောက်ဆုံးနေသောတန်ဖိုးများကို အလွယ်တကူ ပြောင်းလဲပေးပါသည်။ ဒီဒီဇိုင်းအင်္ဂါရပ်ကြောင့် pandas တွင် `None` နှင့် `NaN` ကို \"null\" အမျိုးအစားနှစ်မျိုးအဖြစ် စဉ်းစားရတာ အကျိုးရှိနိုင်ပါတယ်။ အမှန်တကယ်တော့ pandas တွင် ပျောက်ဆုံးနေသောတန်ဖိုးများကို ကိုင်တွယ်ရန် သုံးသော အခြေခံနည်းလမ်းများသည် ဒီအယူအဆကို သူတို့နာမည်များတွင် ထင်ဟပ်စေပါသည်။\n", "\n", - "- `isnull()`: မရှိမဖြစ်တန်ဖိုးများကို ပြသသော Boolean mask တစ်ခု ဖန်တီးသည် \n", - "- `notnull()`: `isnull()` ၏ ဆန့်ကျင်ဘက် \n", - "- `dropna()`: ဒေတာကို စစ်ထုတ်ပြီး ပြန်ပေးသည် \n", - "- `fillna()`: မရှိမဖြစ်တန်ဖိုးများကို ဖြည့်စွက်ထားသည့် ဒေတာ၏ မိတ္တူတစ်ခု ပြန်ပေးသည် \n", + "- `isnull()`: ပျောက်ဆုံးနေသောတန်ဖိုးများကို ဖော်ပြသော Boolean mask တစ်ခုကို ဖန်တီးသည်\n", + "- `notnull()`: `isnull()` ၏ ဆန့်ကျင်ဘက်\n", + "- `dropna()`: ဒေတာကို စစ်ထုတ်ထားသော ဗားရှင်းတစ်ခု ပြန်ပေးသည်\n", + "- `fillna()`: ပျောက်ဆုံးနေသောတန်ဖိုးများကို ဖြည့်စွက်ထားသော ဒေတာ၏ မိတ္တူတစ်ခု ပြန်ပေးသည်\n", "\n", - "ဒီနည်းလမ်းများသည် အလွန်အရေးကြီးပြီး ကျွမ်းကျင်စွာ အသုံးပြုနိုင်ရန် လေ့လာသင့်သည်။ ထို့ကြောင့်, အခုတစ်ခါမှာ တစ်ခုချင်းစီကို နက်နက်ရှိုင်းရှိုင်း လေ့လာကြမည်။\n" + "ဒီနည်းလမ်းများသည် အရေးကြီးပြီး ကျွမ်းကျင်စွာ အသုံးပြုနိုင်ရန် လေ့လာသင့်သော နည်းလမ်းများဖြစ်သည်။ အခုတော့ တစ်ခုချင်းစီကို အသေးစိတ် သွားလေ့လာကြမယ်။\n" ] }, { @@ -915,11 +922,10 @@ "id": "Yh5ifd9FgRsB" }, "source": [ - "### မရှိသောတန်ဖိုးများကို ရှာဖွေခြင်း\n", + "### Null တန်ဖိုးများကို ရှာဖွေခြင်း\n", "\n", - "မရှိသောတန်ဖိုးများ၏ အရေးပါမှုကို နားလည်ပြီးနောက်၊ အရင်ဆုံး မရှိသောတန်ဖိုးများကို ကျွန်ုပ်တို့၏ဒေတာအစုတွင် ရှာဖွေဖို့ လိုအပ်ပါသည်။ \n", - "`isnull()` နှင့် `notnull()` နှစ်ခုစလုံးသည် မရှိသောဒေတာကို ရှာဖွေဖို့ အဓိကနည်းလမ်းများဖြစ်သည်။ \n", - "နှစ်ခုစလုံးသည် သင့်ဒေတာအပေါ် Boolean mask များကို ပြန်ပေးသည်။ \n" + "အခု Missing Values ရဲ့ အရေးကြီးမှုကို နားလည်ပြီးတဲ့အခါမှာ Missing Values တွေကို ကိုင်တွယ်ဖို့မတိုင်ခင် Dataset ထဲမှာ ရှာဖွေဖို့လိုအပ်ပါတယ်။\n", + "`isnull()` နဲ့ `notnull()` နှစ်ခုလုံးဟာ Null Data ကို ရှာဖွေဖို့အတွက် အဓိက Method တွေဖြစ်ပါတယ်။ Method နှစ်ခုလုံးဟာ သင့် Data အပေါ် Boolean Mask တွေကို ပြန်ပေးပါမယ်။\n" ] }, { @@ -972,13 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "အောက်ပါအကြောင်းအရာကို မြန်မာဘာသာဖြင့် ဘာသာပြန်ထားသည် -\n", + "အထွေထွေကြည့်လိုက်ပါ။ အဲဒီအထဲမှာ အံ့ဩစရာတစ်ခုခုရှိပါသလား။ `0` ဟာ သင်္ချာအရ null ဖြစ်ပေမယ့်၊ ဒါဟာ ကောင်းမွန်တဲ့ integer တစ်ခုဖြစ်ပြီး pandas က အဲဒီအတိုင်းကို လက်ခံပါတယ်။ `''` ကတော့ နည်းနည်းပိုမရှင်းလင်းပါ။ ဒါကို Section 1 မှာ အလွတ် string တန်ဖိုးကို ကိုယ်စားပြုဖို့ အသုံးပြုခဲ့ပေမယ့်၊ pandas အရတော့ ဒါဟာ null ကို ကိုယ်စားပြုတာမဟုတ်ဘဲ string object တစ်ခုဖြစ်ပါတယ်။\n", "\n", - "အထက်ပါအချက်များကို သေချာစွာကြည့်ပါ။ `0` သည် သင်္ချာဆိုင်ရာ null ဖြစ်သော်လည်း၊ ၎င်းသည် ကောင်းမွန်သော အပြည့်အဝ integer တစ်ခုဖြစ်ပြီး pandas က ၎င်းကို ထိုသို့ပင် သတ်မှတ်သည်။ `''` သည် နည်းနည်းပိုမိုနက်နဲသည်။ ကျွန်ုပ်တို့သည် ၎င်းကို အပိုင်း ၁ တွင် အလွတ်စကားကြောင်းတန်ဖိုးကို ကိုယ်စားပြုရန် အသုံးပြုခဲ့သော်လည်း၊ ၎င်းသည် string object တစ်ခုဖြစ်ပြီး pandas အရ null ကို ကိုယ်စားပြုသောအရာမဟုတ်ပါ။\n", + "အခုတော့ ဒီအရာတွေကို ပြန်လှည့်ပြီး သင်အမှန်တကယ် အသုံးပြုမယ့်ပုံစံနဲ့ ပိုဆင်တူတဲ့နည်းလမ်းတွေကို အသုံးပြုကြည့်ရအောင်။ Boolean masks ကို တိုက်ရိုက် ``Series`` ဒါမှမဟုတ် ``DataFrame`` index အနေနဲ့ အသုံးပြုနိုင်ပြီး၊ အဲဒါက အလွတ် (ဒါမှမဟုတ် ရှိနေတဲ့) တန်ဖိုးတွေကို သီးသန့်လုပ်ဆောင်ဖို့ အသုံးဝင်ပါတယ်။\n", "\n", - "ယခု၊ ဤအရာကို ပြောင်းလဲပြီး သင်အလေ့အကျင့်အဖြစ် အသုံးပြုမည့် နည်းလမ်းများဖြင့် အသုံးပြုကြည့်ပါ။ သင်သည် Boolean masks ကို တိုက်ရိုက် ``Series`` သို့မဟုတ် ``DataFrame`` index အဖြစ် အသုံးပြုနိုင်ပြီး၊ ၎င်းသည် အထီးကျန်နေသော (သို့မဟုတ် ရှိနေသော) တန်ဖိုးများနှင့် အလုပ်လုပ်ရန် အသုံးဝင်နိုင်သည်။\n", - "\n", - "ကျွန်ုပ်တို့ Missing Values အရေအတွက်စုစုပေါင်းကို သိလိုပါက၊ `isnull()` method မှ ထုတ်လုပ်သော mask အပေါ်တွင် sum တစ်ခု ပြုလုပ်ရုံဖြင့် ရနိုင်သည်။\n" + "မရှိတဲ့တန်ဖိုးတွေ စုစုပေါင်းကို သိချင်ရင် `isnull()` method က ထုတ်ပေးတဲ့ mask ကို အပေါ်မှာ sum လုပ်လိုက်ရုံနဲ့ ရနိုင်ပါတယ်။\n" ] }, { @@ -1012,7 +1016,9 @@ "metadata": { "id": "PlBqEo3mgRsC" }, - "source": [] + "source": [ + "### လေ့ကျင့်မှု:\n" + ] }, { "cell_type": "code", @@ -1033,7 +1039,9 @@ "metadata": { "id": "D_jWN7mHgRsD" }, - "source": [] + "source": [ + "**အဓိကအချက်**: `isnull()` နှင့် `notnull()` နည်းလမ်းများကို DataFrames တွင် အသုံးပြုသောအခါ၊ ၎င်းတို့သည် ရလဒ်များနှင့် ၎င်းရလဒ်များ၏ အညွှန်းကို ပြသပေးပါသည်။ ၎င်းသည် သင့်ဒေတာနှင့် အလုပ်လုပ်နေစဉ်တွင် အလွန်အကျိုးရှိစေပါမည်။\n" + ] }, { "cell_type": "markdown", @@ -1041,20 +1049,20 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### မရှိသည့် ဒေတာများကို ကိုင်တွယ်ခြင်း\n", + "### မရှိသောဒေတာကို ကိုင်တွယ်ခြင်း\n", "\n", - "> **သင်ယူရမည့် ရည်မှန်းချက်:** ဒီအပိုင်းလေးအဆုံးသတ်ချိန်မှာ DataFrames ထဲက null values တွေကို ဘယ်အချိန်မှာ၊ ဘယ်လို အစားထိုးရမလဲ၊ ဖယ်ရှားရမလဲ ဆိုတာကို သိရှိနားလည်ထားနိုင်ပါမယ်။\n", + "> **သင်ယူရန်ရည်မှန်းချက်:** ဒီအပိုင်းလေးအဆုံးသတ်ချိန်မှာ DataFrames ထဲက null values တွေကို ဘယ်အချိန်မှာ ဘယ်လိုအစားထိုးမလဲ၊ ဖယ်ရှားမလဲဆိုတာကို သိရှိနားလည်နိုင်ပါမည်။\n", "\n", - "Machine Learning မော်ဒယ်တွေဟာ မရှိသည့် ဒေတာတွေကို ကိုယ်တိုင် ကိုင်တွယ်နိုင်တာ မဟုတ်ပါဘူး။ ဒါကြောင့် မော်ဒယ်ထဲကို ဒေတာတွေ ထည့်ပို့မယ့်အချိန်မှာ မရှိသည့် ဒေတာတွေကို ကိုင်တွယ်ဖို့ လိုအပ်ပါတယ်။\n", + "Machine Learning မော်ဒယ်တွေဟာ မရှိတဲ့ဒေတာတွေကို ကိုယ်တိုင်ကိုင်တွယ်နိုင်တာမဟုတ်ပါဘူး။ ဒါကြောင့် မော်ဒယ်ထဲကို ဒေတာတွေကို ထည့်မယ့်အခါမှာ ဒီမရှိတဲ့တန်ဖိုးတွေကို ကိုင်တွယ်ဖို့လိုအပ်ပါတယ်။\n", "\n", - "မရှိသည့် ဒေတာတွေကို ကိုင်တွယ်ပုံဟာ သွယ်ဝိုက်တဲ့ အကျိုးဆက်တွေကို ဖြစ်ပေါ်စေနိုင်ပြီး၊ သင့် Analysis နဲ့ အမှန်တကယ် အကျိုးရလဒ်တွေကိုပါ သက်ရောက်စေနိုင်ပါတယ်။\n", + "မရှိတဲ့ဒေတာကို ကိုင်တွယ်ပုံဟာ သေးငယ်တဲ့ အကျိုးဆက်တွေကိုပါ ပါဝင်စေပြီး၊ သင့်ရဲ့ analysis နောက်ဆုံးရလဒ်နဲ့ အမှန်တကယ်ဖြစ်ပျက်မယ့်အခြေအနေတွေကိုလည်း သက်ရောက်စေပါတယ်။\n", "\n", - "မရှိသည့် ဒေတာတွေကို ကိုင်တွယ်ဖို့ အဓိကနည်းလမ်းနှစ်မျိုးရှိပါတယ် -\n", + "မရှိတဲ့ဒေတာကို ကိုင်တွယ်ဖို့နည်းလမ်းတွေမှာ အဓိကအားဖြင့် နှစ်မျိုးရှိပါတယ် -\n", "\n", - "1. မရှိသည့် ဒေတာပါဝင်တဲ့ row ကို ဖယ်ရှားပစ်ခြင်း\n", - "2. မရှိသည့် ဒေတာကို အခြားတစ်ခုခုနဲ့ အစားထိုးခြင်း\n", + "1. မရှိတဲ့တန်ဖိုးပါဝင်တဲ့ row ကို ဖျက်ပစ်ခြင်း\n", + "2. မရှိတဲ့တန်ဖိုးကို တခြားတန်ဖိုးတစ်ခုနဲ့ အစားထိုးခြင်း\n", "\n", - "ဒီနည်းလမ်းနှစ်မျိုးကို အသေးစိတ် ဆွေးနွေးပြီး၊ အကျိုးကျေးဇူးနဲ့ အားနည်းချက်တွေကိုလည်း ပြောပြသွားပါမယ်။\n" + "ဒီနည်းလမ်းနှစ်ခုကို အကျိုးကျိုးနဲ့ အနုတ်ကျိုးတွေကို အသေးစိတ်ဆွေးနွေးသွားပါမယ်။\n" ] }, { @@ -1063,13 +1071,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### Null တန်ဖိုးများကို ဖယ်ရှားခြင်း\n", + "### Null အချက်အလက်များကို ဖယ်ရှားခြင်း\n", "\n", - "ကျွန်တော်တို့ရဲ့ မော်ဒယ်ကို ပေးပို့တဲ့ ဒေတာပမာဏက မော်ဒယ်ရဲ့ လုပ်ဆောင်မှုအပေါ် တိုက်ရိုက်သက်ရောက်မှုရှိပါတယ်။ Null တန်ဖိုးများကို ဖယ်ရှားခြင်းက ဒေတာပွင့်များအရေအတွက်ကို လျှော့ချတာဖြစ်ပြီး ဒေတာအစုအဝေးရဲ့ အရွယ်အစားကိုလည်း လျှော့ချတာဖြစ်ပါတယ်။ ဒါကြောင့် ဒေတာအစုအဝေးက အလွန်ကြီးမားတဲ့အခါ Null တန်ဖိုးများပါဝင်တဲ့ အတန်းများကို ဖယ်ရှားဖို့ အကြံပေးပါတယ်။\n", + "ကျွန်ုပ်တို့၏မော်ဒယ်သို့ ပေးပို့သောအချက်အလက်ပမာဏသည် ၎င်း၏စွမ်းဆောင်ရည်ကို တိုက်ရိုက်သက်ရောက်စေပါသည်။ Null အချက်အလက်များကို ဖယ်ရှားခြင်းသည် အချက်အလက်အချက်ပြများ၏အရေအတွက်ကို လျှော့ချခြင်းဖြစ်ပြီး၊ dataset ၏အရွယ်အစားကိုလည်း လျှော့ချခြင်းဖြစ်သည်။ ထို့ကြောင့် dataset ကြီးမားလွန်းသောအခါတွင် Null အချက်အလက်များပါဝင်သော အတန်းများကို ဖယ်ရှားရန် အကြံပြုပါသည်။\n", "\n", - "တစ်ခြားအခြေအနေတစ်ခုကတော့ အတန်းတစ်ခု သို့မဟုတ် ကော်လံတစ်ခုမှာ မရှိတဲ့တန်ဖိုးများ အလွန်များနေတဲ့အခါ ဖြစ်နိုင်ပါတယ်။ ဒီလိုဆိုရင် အတန်း/ကော်လံကို ဖယ်ရှားနိုင်ပါတယ်၊ အကြောင်းကတော့ အတန်း/ကော်လံရဲ့ ဒေတာအများစုက မရှိတဲ့အတွက် ကျွန်တော်တို့ရဲ့ ခွဲခြမ်းစိတ်ဖြာမှုအတွက် တန်ဖိုးမရှိလောက်ပါဘူး။\n", + "တစ်ခြားအခြေအနေတစ်ခုမှာ အတန်းတစ်ခု သို့မဟုတ် ကော်လံတစ်ခုတွင် အချက်အလက်ပျောက်ဆုံးမှုများစွာရှိနေသည်။ ထိုအခါ၎င်းတို့ကို ဖယ်ရှားနိုင်ပါသည်၊ အကြောင်းကတော့ အတန်း/ကော်လံအတွက် အချက်အလက်များအများစုပျောက်ဆုံးနေသောကြောင့် ကျွန်ုပ်တို့၏ခွဲခြမ်းစိတ်ဖြာမှုတွင် တန်ဖိုးများမပေးနိုင်ပါ။\n", "\n", - "Missing values တွေကို ရှာဖွေဖော်ထုတ်တာအပြင် pandas က `Series` နဲ့ `DataFrame` တွေထဲက Null တန်ဖိုးများကို ဖယ်ရှားဖို့ အဆင်ပြေတဲ့ နည်းလမ်းတစ်ခုကို ပေးထားပါတယ်။ ဒီကို လက်တွေ့အသုံးပြုတာကို ကြည့်ဖို့ `example3` ကို ပြန်သွားကြရအောင်။ `DataFrame.dropna()` function က Null တန်ဖိုးများပါဝင်တဲ့ အတန်းများကို ဖယ်ရှားဖို့ အထောက်အကူပြုပါတယ်။\n" + "Missing values ကို ရှာဖွေခြင်းအပြင် pandas သည် `Series` နှင့် `DataFrame` များမှ Null အချက်အလက်များကို ဖယ်ရှားရန် အဆင်ပြေသောနည်းလမ်းကို ပေးသည်။ ၎င်းကို လက်တွေ့အသုံးပြုမှုအနေဖြင့် `example3` သို့ ပြန်သွားကြည့်ပါ။ `DataFrame.dropna()` function သည် Null အချက်အလက်များပါဝင်သော အတန်းများကို ဖယ်ရှားရန် အထောက်အကူပြုပါသည်။\n" ] }, { @@ -1108,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "ဤအရာသည် `example3[example3.notnull()]` မှ ထွက်ရှိသည့် output နှင့် တူရိုက်ပါမည်။ ဒီမှာ ကွဲပြားချက်ကတော့ masked values များကို indexing လုပ်တာအစား၊ `dropna` က `Series` `example3` ထဲမှ ပျောက်ဆုံးနေသော အချက်အလက်များကို ဖယ်ရှားလိုက်ခြင်းဖြစ်သည်။\n", + "ဤအရာသည် `example3[example3.notnull()]` မှ သင့်ရဲ့ output နမူနာလိုပဲ ဖြစ်ရမည်ကို မှတ်ထားပါ။ ဒီမှာ ကွာခြားချက်ကတော့ masked values တွေကို index လုပ်တာမဟုတ်ဘဲ `dropna` က `Series` `example3` မှ ပျောက်ဆုံးနေတဲ့ values တွေကို ဖယ်ရှားလိုက်တာဖြစ်ပါတယ်။\n", "\n", - "DataFrames တွင် အတိုင်းအတာနှစ်ခုရှိသောကြောင့်၊ အချက်အလက်များကို ဖယ်ရှားရန် အခြားရွေးချယ်စရာများ ပိုမိုရရှိနိုင်ပါသည်။\n" + "DataFrames တွေမှာ dimension နှစ်ခုရှိတဲ့အတွက် ဒေတာတွေကို ဖယ်ရှားဖို့ အခြားရွေးချယ်မှုများကို ပေးစွမ်းနိုင်ပါတယ်။\n" ] }, { @@ -1200,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(သင် pandas က `NaN` တွေကို accommodate လုပ်ဖို့အတွက် ကော်လံနှစ်ခုကို float အဖြစ် upcast လုပ်ထားတာကို သတိထားမိပါသလား?)\n", + "(သင် pandas က `NaN` တွေကို accommodate လုပ်ဖို့အတွက် ကော်လံနှစ်ခုကို float အဖြစ် upcast လုပ်ထားတာသတိထားမိပါသလား?)\n", "\n", - "သင် `DataFrame` မှတစ်ခုတည်းသောတန်ဖိုးကို drop လုပ်လို့မရပါဘူး၊ ဒါကြောင့် အတန်းတစ်ခုလုံး သို့မဟုတ် ကော်လံတစ်ခုလုံးကို drop လုပ်ရမည်ဖြစ်သည်။ သင်လုပ်ဆောင်လိုသောအရာပေါ်မူတည်ပြီး၊ တစ်ခု သို့မဟုတ် တစ်ခုကိုရွေးချယ်နိုင်ပြီး pandas က နှစ်မျိုးလုံးအတွက် ရွေးချယ်စရာများပေးထားသည်။ ဒေတာသိပ္ပံတွင် ကော်လံများသည် အများအားဖြင့် variable များကို ကိုယ်စားပြုပြီး အတန်းများသည် observation များကို ကိုယ်စားပြုသောကြောင့်၊ သင်အတန်းများကို ပိုမိုများစွာ drop လုပ်နိုင်သည်။ `dropna()` ၏ default setting သည် null value များပါဝင်သော အတန်းအားလုံးကို drop လုပ်ရန်ဖြစ်သည်။\n" + "သင် `DataFrame` ထဲကတစ်ခုတည်းသောတန်ဖိုးကို drop လုပ်လို့မရပါဘူး၊ ဒါကြောင့် အပြည့်အစုံသော row သို့မဟုတ် column ကို drop လုပ်ရပါမယ်။ သင်လုပ်ဆောင်နေတဲ့အရာပေါ်မူတည်ပြီး၊ တစ်ခုခုကိုရွေးချယ်နိုင်ဖို့လိုအပ်နိုင်ပြီး၊ pandas က နှစ်မျိုးလုံးအတွက်ရွေးချယ်စရာပေးထားပါတယ်။ ဒေတာသိပ္ပံမှာ column တွေက variables ကိုယ်စားပြုပြီး row တွေက observations ကိုယ်စားပြုတာကြောင့်၊ row တွေကို drop လုပ်ဖို့ပိုမိုဖြစ်နိုင်ပါတယ်။ `dropna()` ရဲ့ default setting က null values ပါဝင်တဲ့ row တွေကိုအားလုံး drop လုပ်ဖို့ဖြစ်ပါတယ်:\n" ] }, { @@ -1275,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "အကယ်၍ လိုအပ်ပါက၊ ကော်လံများမှ NA အတန်းများကို ဖယ်ရှားနိုင်ပါသည်။ ထိုအတွက် `axis=1` ကို အသုံးပြုပါ:\n" + "လိုအပ်ပါက၊ ကော်လံများမှ NA အချက်အလက်များကို ဖယ်ရှားနိုင်ပါသည်။ `axis=1` ကို အသုံးပြုပါ:\n" ] }, { @@ -1354,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "ဤသည် သင့်ရဲ့ dataset တွေထဲမှာ အချက်အလက်များကို အများကြီးပျောက်ဆုံးစေနိုင်ပါတယ်၊ အထူးသဖြင့် dataset သေးငယ်တဲ့အခါမှာ။ ဒါပေမယ့် သင့်ရဲ့ dataset ထဲမှာ null value အများကြီးပါဝင်တဲ့ rows သို့မဟုတ် columns တွေကိုပဲ drop လုပ်ချင်ရင်ရော ဘာလုပ်မလဲ? `dropna` function ရဲ့ `how` နဲ့ `thresh` parameters တွေကို သတ်မှတ်နိုင်ပါတယ်။\n", + "ဤအချက်ကို သတိပြုပါ၊ သင်ထိန်းသိမ်းလိုသော ဒေတာများစွာကို အထူးသဖြင့် သေးငယ်သော ဒေတာအစုများတွင် ပျောက်ဆုံးစေနိုင်သည်။ သင်သည် null တန်ဖိုးများစွာပါဝင်သော (သို့မဟုတ်) null တန်ဖိုးများအားလုံးပါဝင်သော အတန်းများ သို့မဟုတ် ကော်လံများကိုသာ ဖယ်ရှားလိုပါက အဘယ်သို့လုပ်မည်နည်း? `dropna` တွင် `how` နှင့် `thresh` parameters များကို သတ်မှတ်ခြင်းဖြင့် သင်လိုအပ်သော အဆင့်ဆင့်များကို ပြုလုပ်နိုင်သည်။\n", "\n", - "ပုံမှန်အားဖြင့် `how='any'` သတ်မှတ်ထားပါတယ် (သင့်ကိုယ်တိုင်စစ်ဆေးချင်ရင် သို့မဟုတ် method ရဲ့ အခြား parameters တွေကိုကြည့်ချင်ရင် `example4.dropna?` ကို code cell မှာ run လုပ်ပါ။) အခြားနည်းလမ်းတစ်ခုအနေနဲ့ `how='all'` ကို သတ်မှတ်နိုင်ပါတယ်၊ ဒါက null value အားလုံးပါဝင်တဲ့ rows သို့မဟုတ် columns တွေကိုပဲ drop လုပ်မှာဖြစ်ပါတယ်။ အောက်ပါ exercise မှာ ဤအရာကို လက်တွေ့အသုံးပြုဖို့ `DataFrame` ကို ကျယ်ပြန့်အောင်ပြင်ဆင်ကြည့်ရအောင်။\n" + "ပုံမှန်အားဖြင့် `how='any'` သတ်မှတ်ထားသည် (သင်ကိုယ်တိုင်စစ်ဆေးလိုပါက သို့မဟုတ် method တွင်ရှိသော အခြား parameters များကို ကြည့်လိုပါက `example4.dropna?` ကို code cell တစ်ခုတွင် run လိုက်ပါ။) အခြားနည်းလမ်းတစ်ခုအနေဖြင့် `how='all'` ကို သတ်မှတ်နိုင်ပြီး null တန်ဖိုးများအားလုံးပါဝင်သော အတန်းများ သို့မဟုတ် ကော်လံများကိုသာ ဖယ်ရှားနိုင်သည်။ နောက် exercise တွင် ဤအရာကို လက်တွေ့ကျကျကြည့်ရှုနိုင်ရန် `DataFrame` ကို ကျယ်ပြန့်စေကြမည်။\n" ] }, { @@ -1448,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> အရေးကြီးသော အချက်များ:\n", - "1. Null အချက်အလက်များကို ဖယ်ရှားခြင်းသည် dataset ကြီးလုံလောက်မှသာ ကောင်းမွန်သော အကြံဉာဏ်ဖြစ်သည်။\n", - "2. အချက်အလက်များ မရှိသည့် အတန်းများ သို့မဟုတ် ကော်လံများကို အပြည့်အဝ ဖယ်ရှားနိုင်သည်။\n", - "3. `DataFrame.dropna(axis=)` method သည် Null အချက်အလက်များကို ဖယ်ရှားရန် အထောက်အကူပြုသည်။ `axis` argument သည် အတန်းများကို ဖယ်ရှားမည်လား၊ ကော်လံများကို ဖယ်ရှားမည်လား ဆိုသည်ကို ဖော်ပြသည်။\n", - "4. `how` argument ကိုလည်း အသုံးပြုနိုင်သည်။ ပုံမှန်အားဖြင့် ၎င်းကို `any` အဖြစ် သတ်မှတ်ထားသည်။ ထို့ကြောင့် Null အချက်အလက်များ ပါဝင်သော အတန်း/ကော်လံများကိုသာ ဖယ်ရှားသည်။ ၎င်းကို `all` အဖြစ် သတ်မှတ်နိုင်ပြီး Null အချက်အလက်များသာ ပါဝင်သော အတန်း/ကော်လံများကိုသာ ဖယ်ရှားမည်ဟု သတ်မှတ်နိုင်သည်။\n" + "> အဓိကအချက်များ:\n", + "1. Null တန်ဖိုးများကို ဖယ်ရှားခြင်းသည် dataset ကြီးလုံလောက်မှသာ ကောင်းမွန်သော အကြံဉာဏ်ဖြစ်သည်။\n", + "2. အချက်အလက်များအများစုပျောက်ဆုံးနေသော အတန်းများ သို့မဟုတ် ကော်လံများကို အပြည့်အဝ ဖယ်ရှားနိုင်သည်။\n", + "3. Null တန်ဖိုးများကို ဖယ်ရှားရန် `DataFrame.dropna(axis=)` method ကို အသုံးပြုနိုင်သည်။ `axis` argument သည် အတန်းများကို ဖယ်ရှားမည်လား၊ ကော်လံများကို ဖယ်ရှားမည်လား ဆိုတာကို ဖော်ပြသည်။\n", + "4. `how` argument ကိုလည်း အသုံးပြုနိုင်သည်။ ပုံမှန်အားဖြင့် `any` အဖြစ် သတ်မှတ်ထားသည်။ ထို့ကြောင့် Null တန်ဖိုးများ ပါဝင်သော အတန်း/ကော်လံများကိုသာ ဖယ်ရှားသည်။ Null တန်ဖိုးများအားလုံးပါဝင်သော အတန်း/ကော်လံများကိုသာ ဖယ်ရှားရန် `all` အဖြစ် သတ်မှတ်နိုင်သည်။\n" ] }, { @@ -1460,7 +1468,9 @@ "metadata": { "id": "oXXSfQFHgRsF" }, - "source": [] + "source": [ + "### လေ့ကျင့်မှု:\n" + ] }, { "cell_type": "code", @@ -1482,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "`thresh` ပါရာမီတာသည် သင့်အား ပိုမိုသေးငယ်သည့် ထိန်းချုပ်မှုကို ပေးသည်။ အတန်း သို့မဟုတ် ကော်လံတစ်ခုကို ထိန်းသိမ်းထားရန် လိုအပ်သည့် *null မဟုတ်သော* အတန်းအရေအတွက်ကို သင် သတ်မှတ်နိုင်သည်။\n" + "`thresh` ပရမီတာသည် သင့်အား ပိုမိုသေးငယ်သော ထိန်းချုပ်မှုကို ပေးသည်။ အတန်းတစ်ခု သို့မဟုတ် ကော်လံတစ်ခုကို ထိန်းသိမ်းထားရန် လိုအပ်သော *null မဟုတ်သော* အချက်အလက်အရေအတွက်ကို သင် သတ်မှတ်နိုင်သည်။\n" ] }, { @@ -1556,7 +1566,9 @@ "metadata": { "id": "fmSFnzZegRsG" }, - "source": [] + "source": [ + "ဒီမှာ ပထမတန်းနှင့် နောက်ဆုံးတန်းကို ဖယ်ရှားထားပြီးဖြစ်သည်၊ အကြောင်းမှာ ၎င်းတို့တွင် null မဟုတ်သောတန်ဖိုးနှစ်ခုသာပါဝင်သောကြောင့်ဖြစ်သည်။\n" + ] }, { "cell_type": "markdown", @@ -1564,11 +1576,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### အချိုးအစားမရှိသော တန်ဖိုးများ ဖြည့်ခြင်း\n", + "### Null Value များကို ဖြည့်ခြင်း\n", "\n", - "တစ်ခါတစ်ရံမှာ အချိုးအစားမရှိတဲ့ တန်ဖိုးတွေကို သင့်တော်တဲ့ တန်ဖိုးတွေနဲ့ ဖြည့်သွင်းတာဟာ make sense ဖြစ်တတ်ပါတယ်။ အချိုးအစားမရှိတဲ့ တန်ဖိုးတွေကို ဖြည့်သွင်းဖို့ နည်းလမ်းအချို့ ရှိပါတယ်။ ပထမနည်းလမ်းကတော့ Domain Knowledge (ဒေတာဆက်စပ်တဲ့ အကြောင်းအရာပေါ်မှာ အခြေခံထားတဲ့ အသိပညာ) ကို အသုံးပြုပြီး အချိုးအစားမရှိတဲ့ တန်ဖိုးတွေကို ခန့်မှန်းဖြည့်သွင်းတာ ဖြစ်ပါတယ်။\n", + "တစ်ခါတစ်ရံတွင် မရှိသည့်တန်ဖိုးများကို သက်ဆိုင်ရာတန်ဖိုးများဖြင့် ဖြည့်သွင်းခြင်းသည် သင့်လျော်နိုင်ပါသည်။ Null Value များကို ဖြည့်သွင်းရန် နည်းလမ်းအချို့ရှိပါသည်။ ပထမနည်းလမ်းမှာ Domain Knowledge (အချက်အလက်များအပေါ် အခြေခံထားသော အကြောင်းအရာ၏ အသိပညာ) ကို အသုံးပြု၍ မရှိသည့်တန်ဖိုးများကို ခန့်မှန်းဖြည့်သွင်းခြင်းဖြစ်သည်။\n", "\n", - "ဒီလိုလုပ်ဖို့ `isnull` ကို သုံးနိုင်ပေမယ့် ဒါဟာ အလုပ်ရှုပ်တတ်ပါတယ်၊ အထူးသဖြင့် ဖြည့်ရမယ့် တန်ဖိုးတွေ များများရှိရင် ပိုပြီး အလုပ်ရှုပ်နိုင်ပါတယ်။ ဒေတာသိပ္ပံမှာ ဒီလိုအလုပ်ဟာ အလွန်ရိုးရိုးရှင်းရှင်း ဖြစ်တဲ့အတွက် pandas က `fillna` ကို ပံ့ပိုးပေးထားပါတယ်။ ဒါကတော့ သင့်ရဲ့ `Series` သို့မဟုတ် `DataFrame` ကို ကူးယူပြီး အချိုးအစားမရှိတဲ့ တန်ဖိုးတွေကို သင့်စိတ်ကြိုက် တန်ဖိုးတွေနဲ့ အစားထိုးပေးတဲ့ function တစ်ခု ဖြစ်ပါတယ်။ ဒီလိုလုပ်ပုံကို လက်တွေ့ကြည့်ရှုနိုင်ဖို့ အခြား `Series` တစ်ခုကို ဖန်တီးကြည့်ရအောင်။\n" + "သင်သည် `isnull` ကို အသုံးပြု၍ Null Value များကို တိုက်ရိုက်ဖြည့်နိုင်ပါသည်၊ သို့သော် အတော်လေး အလုပ်ရှုပ်နိုင်ပါသည်၊ အထူးသဖြင့် ဖြည့်ရန်တန်ဖိုးများ များစွာရှိပါက။ ဒါကြောင့် Data Science တွင် အလွန်ရိုးရှင်းသော အလုပ်တစ်ခုဖြစ်သောကြောင့် pandas သည် `fillna` ကို ပံ့ပိုးပေးပါသည်၊ ၎င်းသည် သင့်ရွေးချယ်မှုတစ်ခုဖြင့် မရှိသည့်တန်ဖိုးများကို အစားထိုးထားသော `Series` သို့မဟုတ် `DataFrame` ၏ မိတ္တူတစ်ခုကို ပြန်ပေးပါသည်။ ၎င်းကို လက်တွေ့အသုံးပြုပုံကို ကြည့်ရန် နောက်ထပ် `Series` ကို ဖန်တီးကြည့်ပါ။\n" ] }, { @@ -1578,11 +1590,11 @@ }, "source": [ "### အမျိုးအစားအချက်အလက် (Non-numeric)\n", - "ပထမဆုံး Non-numeric အချက်အလက်ကို စဉ်းစားကြည့်ပါ။ ဒေတာစုများတွင် အမျိုးအစားအချက်အလက်ပါသော ကော်လံများရှိပါသည်။ ဥပမာ - ကျား/မ၊ True သို့မဟုတ် False စသည်တို့။\n", + "ပထမဆုံး Non-numeric အချက်အလက်ကို စဉ်းစားကြည့်ရအောင်။ ဒေတာစုပေါင်းများတွင် အမျိုးအစားအချက်အလက်ပါသော ကော်လံများရှိပါသည်။ ဥပမာ - ကျား/မ၊ True or False စသည်တို့။\n", "\n", - "ဤအခြေအနေများအများစုတွင် ကော်လံ၏ `mode` ကို အသုံးပြု၍ မရှိသည့်တန်ဖိုးများကို အစားထိုးပါသည်။ ဥပမာအားဖြင့် 100 ဒေတာပွင့်များရှိပြီး 90 ခုက True ဟုဆိုထားသည်၊ 8 ခုက False ဟုဆိုထားပြီး 2 ခုက မဖြည့်ထားပါ။ ထို့နောက် ကော်လံတစ်ခုလုံးကို စဉ်းစားပြီး 2 ခုကို True ဖြင့် ဖြည့်နိုင်ပါသည်။\n", + "ဤအခြေအနေများအများစုတွင် ကော်လံ၏ `mode` ဖြင့် ပျောက်ဆုံးနေသောတန်ဖိုးများကို အစားထိုးလေ့ရှိသည်။ ဥပမာအားဖြင့် 100 ဒေတာပွင့်များရှိပြီး 90 ခုက True ဟုဆိုထားသည်၊ 8 ခုက False ဟုဆိုထားပြီး 2 ခုက မဖြည့်ထားပါ။ ထို့ကြောင့် ကော်လံတစ်ခုလုံးကို စဉ်းစားပြီး 2 ခုကို True ဖြင့် ဖြည့်နိုင်ပါသည်။\n", "\n", - "ထပ်ပြီးတော့ ဒီမှာ domain knowledge ကိုလည်း အသုံးပြုနိုင်ပါတယ်။ Mode ဖြင့် ဖြည့်သည့် ဥပမာတစ်ခုကို စဉ်းစားကြည့်ပါ။\n" + "ထပ်ပြီးတော့ ဒီမှာ domain knowledge ကိုလည်း အသုံးပြုနိုင်ပါတယ်။ Mode ဖြင့် ဖြည့်သည့် ဥပမာတစ်ခုကို စဉ်းစားကြည့်ရအောင်။\n" ] }, { @@ -1687,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "အခုတော့ `None` အဖြစ်တန်ဖိုးကို mode နဲ့ဖြည့်မည့်အခါ mode ကိုအရင်ရှာဖွေကြမယ်။\n" + ] }, { "cell_type": "code", @@ -1722,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "ဒါဆိုရင် None ကို True နဲ့အစားထိုးပါမယ်။\n" + ] }, { "cell_type": "code", @@ -1831,7 +1847,9 @@ "metadata": { "id": "SktitLxxOR16" }, - "source": [] + "source": [ + "ကျွန်တော်တို့မြင်နိုင်သည့်အတိုင်း null တန်ဖိုးကို အစားထိုးပြီးဖြစ်ပါသည်။ ပြောစရာမလိုအပ်ပါဘူး၊ `'True'` အစားထိုးနေရာတွင် အခြားတစ်ခုခုရေးနိုင်ပြီး အစားထိုးခံရနိုင်ပါသည်။\n" + ] }, { "cell_type": "markdown", @@ -1840,16 +1858,16 @@ }, "source": [ "### ကိန်းဂဏန်းဆိုင်ရာ ဒေတာ\n", - "အခု ကိန်းဂဏန်းဆိုင်ရာ ဒေတာကို ဆွေးနွေးကြမယ်။ ဒီမှာ မရှိတဲ့တန်ဖိုးတွေကို အစားထိုးဖို့အတွက် အများဆုံးအသုံးပြုတဲ့ နည်းလမ်းနှစ်ခုရှိတယ်။\n", + "အခုတော့ ကိန်းဂဏန်းဆိုင်ရာ ဒေတာကို ဆွေးနွေးကြမယ်။ ဒီမှာ မရှိတဲ့တန်ဖိုးတွေကို အစားထိုးဖို့အတွက် အများဆုံးအသုံးပြုတဲ့နည်းလမ်းနှစ်ခုရှိပါတယ်။\n", "\n", - "1. အတန်းရဲ့ အလယ်တန်းတန်ဖိုး (Median) နဲ့ အစားထိုးခြင်း \n", - "2. အတန်းရဲ့ ပျမ်းမျှတန်ဖိုး (Mean) နဲ့ အစားထိုးခြင်း \n", + "1. အတန်းရဲ့ အလယ်တန်းတန်ဖိုး (Median) နဲ့ အစားထိုးခြင်း\n", + "2. အတန်းရဲ့ ပျမ်းမျှတန်ဖိုး (Mean) နဲ့ အစားထိုးခြင်း\n", "\n", - "အလယ်တန်းတန်ဖိုး (Median) နဲ့ အစားထိုးတာက အလွန်အမင်းတန်ဖိုးတွေ (outliers) ပါဝင်တဲ့ skewed data တွေမှာ အသုံးပြုတယ်။ ဒါကတော့ အလယ်တန်းတန်ဖိုးဟာ အလွန်အမင်းတန်ဖိုးတွေကို သက်ရောက်မှုမရှိစေတဲ့ အကြောင်းကြောင့် ဖြစ်တယ်။\n", + "အလယ်တန်းတန်ဖိုး (Median) နဲ့ အစားထိုးတာက အချက်အလက်တွေ skewed ဖြစ်ပြီး outliers ရှိတဲ့အခါမှာ အသုံးပြုပါတယ်။ အကြောင်းကတော့ အလယ်တန်းတန်ဖိုးက outliers တွေကို သက်သာစေတဲ့ အကျိုးရှိလို့ပါ။\n", "\n", - "ဒေတာကို ပုံမှန်အတိုင်း (normalized) ပြုလုပ်ထားတဲ့အခါမှာတော့ ပျမ်းမျှတန်ဖိုး (Mean) ကို အသုံးပြုနိုင်တယ်။ အဲဒီအချိန်မှာ Mean နဲ့ Median ဟာ တစ်ခွင်တည်းနီးနီး ဖြစ်နေမယ်။\n", + "ဒေတာကို အဆင်ပြေစွာ ချိန်ညှိထားတဲ့အခါမှာတော့ ပျမ်းမျှတန်ဖိုး (Mean) ကို အသုံးပြုနိုင်ပါတယ်။ အဲဒီအချိန်မှာတော့ ပျမ်းမျှတန်ဖိုးနဲ့ အလယ်တန်းတန်ဖိုးဟာ အတော်နီးစပ်နေမှာပါ။\n", "\n", - "ပထမဆုံး၊ ပုံမှန်ဖြန့်ဖြူးမှုရှိတဲ့ ကော်လံတစ်ခုကို ယူပြီး အဲဒီကော်လံရဲ့ ပျမ်းမျှတန်ဖိုးနဲ့ မရှိတဲ့တန်ဖိုးတွေကို ဖြည့်စွက်ကြမယ်။\n" + "ပထမဆုံး အတန်းတစ်ခုကို ယူပြီး အဲဒီအတန်းဟာ သာမန်ဖြန့်ဝေမှုရှိနေတဲ့အခြေအနေမှာ မရှိတဲ့တန်ဖိုးတွေကို အတန်းရဲ့ ပျမ်းမျှတန်ဖိုးနဲ့ ဖြည့်စွက်ကြည့်ရအောင်။ \n" ] }, { @@ -1989,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "အလယ်တန်းတန်ဖိုးဖြင့် ဖြည့်ခြင်း\n" + ] }, { "cell_type": "code", @@ -2088,7 +2108,9 @@ "metadata": { "id": "CwpVFCrPTC5z" }, - "source": [] + "source": [ + "ကျွန်တော်တို့မြင်နိုင်သည့်အတိုင်း၊ ပျောက်ဆုံးနေသောတန်ဖိုးကို ၎င်း၏ပျမ်းမျှတန်ဖိုးဖြင့် အစားထိုးထားပါသည်။\n" + ] }, { "cell_type": "markdown", @@ -2096,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "ယခုတစ်ခါမှာ တစ်ခြား dataframe တစ်ခုကို စမ်းကြည့်ရအောင်၊ ဒီတစ်ခါမှာတော့ None အတန်းများကို ကော်လံ၏ အလယ်တန်းတန်ဖိုးဖြင့် အစားထိုးပါမည်။\n" + "အခုတော့ နောက်ထပ် dataframe တစ်ခုကို စမ်းကြည့်ရအောင်၊ ဒီတစ်ခါမှာတော့ None အဖြစ်တန်ဖိုးတွေကို ကော်လံရဲ့ အလယ်တန်းတန်ဖိုးနဲ့ အစားထိုးပါမယ်။\n" ] }, { @@ -2236,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "မီဒီယန်းဖြင့်ဖြည့်ခြင်း\n" + ] }, { "cell_type": "code", @@ -2336,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "ကျွန်တော်တို့မြင်နိုင်သည့်အတိုင်း NaN တန်ဖိုးကို ကော်လံ၏အလယ်တန်းတန်ဖိုးဖြင့် အစားထိုးထားပါသည်\n" + "ကျွန်တော်တို့မြင်နိုင်သည့်အတိုင်း NaN တန်ဖိုးကို ကော်လံ၏အလယ်တန်းတန်ဖိုးဖြင့် အစားထိုးထားပါသည်။\n" ] }, { @@ -2419,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "အဓိကအချက်များ:\n", - "1. အချက်အလက်နည်းပါးသောအခါ သို့မဟုတ် မရှိသည့်အချက်အလက်များကို ဖြည့်စွက်ရန် မူဝါဒတစ်ခုရှိသောအခါ မရှိသည့်အချက်အလက်များကို ဖြည့်စွက်သင့်သည်။\n", - "2. မရှိသည့်အချက်အလက်များကို ခန့်မှန်း၍ ဖြည့်စွက်ရန် အထူးကျွမ်းကျင်မှုကို အသုံးပြုနိုင်သည်။\n", - "3. Categorized အချက်အလက်များအတွက် မရှိသည့်အချက်အလက်များကို အများအားဖြင့် ကော်လံ၏ mode ဖြင့် အစားထိုးသည်။\n", - "4. နံပါတ်ဆိုင်ရာအချက်အလက်များအတွက် မရှိသည့်အချက်အလက်များကို အများအားဖြင့် mean (normalized datasets များအတွက်) သို့မဟုတ် ကော်လံ၏ median ဖြင့် ဖြည့်စွက်သည်။\n" + "> အဓိကအချက်များ:\n", + "1. အချက်အလက်နည်းပါးသောအခါ သို့မဟုတ် မရှိသည့်အချက်အလက်များကို ဖြည့်စွက်ရန် မဟာဗျူဟာတစ်ခုရှိသောအခါ မရှိသည့်တန်ဖိုးများကို ဖြည့်စွက်သင့်သည်။\n", + "2. မရှိသည့်တန်ဖိုးများကို ခန့်မှန်းဖြည့်စွက်ရန် အကျိုးအမြတ်ဆိုင်ရာ အသိပညာကို အသုံးပြုနိုင်သည်။\n", + "3. အမျိုးအစားဆိုင်ရာ အချက်အလက်များအတွက် မရှိသည့်တန်ဖိုးများကို အများအားဖြင့် ကော်လံ၏ mode ဖြင့် အစားထိုးသည်။\n", + "4. ကိန်းဂဏန်းဆိုင်ရာ အချက်အလက်များအတွက် မရှိသည့်တန်ဖိုးများကို အများအားဖြင့် mean (normalized datasets များအတွက်) သို့မဟုတ် ကော်လံ၏ median ဖြင့် ဖြည့်စွက်သည်။\n" ] }, { @@ -2431,7 +2455,9 @@ "metadata": { "id": "FI9MmqFJgRsH" }, - "source": [] + "source": [ + "### လေ့ကျင့်မှု:\n" + ] }, { "cell_type": "code", @@ -2451,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "သင်သည် null တန်ဖိုးများကို **forward-fill** လုပ်နိုင်ပြီး၊ ၎င်းသည် နောက်ဆုံးတရားဝင်တန်ဖိုးကို null ဖြည့်ရန် အသုံးပြုခြင်းဖြစ်သည်။\n" + ] }, { "cell_type": "code", @@ -2491,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "သင်သည် **back-fill** ကိုလည်း အသုံးပြု၍ null ကို ဖြည့်ရန် နောက်ထပ်တရားဝင်တန်ဖိုးကို နောက်ဆုတ်၍ ဖြည့်နိုင်သည်။\n" + "သင်သည် null ကို ဖြည့်ရန် နောက်ဆုံးမှန်ကန်သောတန်ဖိုးကို နောက်သို့ပြန်လည်ဖြည့်ရန် **back-fill** ကိုလည်း အသုံးပြုနိုင်သည်။\n" ] }, { @@ -2533,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "သင်ခန့်မှန်းနိုင်သလို၊ ဒါကို DataFrames တွေနဲ့လည်း အတူတူအလုပ်လုပ်ပေမယ့်၊ null တန်ဖိုးတွေကို ဖြည့်ရန် `axis` တစ်ခုကိုလည်း သတ်မှတ်နိုင်ပါတယ်။\n" + "သင်ခန့်မှန်းနိုင်သလို၊ ဒါဟာ DataFrames တွေနဲ့လည်း အတူတူအလုပ်လုပ်ပါတယ်၊ ဒါပေမယ့် null values တွေကို ဖြည့်စွက်ဖို့ `axis` ကိုလည်း သတ်မှတ်နိုင်ပါတယ်။\n" ] }, { @@ -2705,14 +2733,18 @@ "metadata": { "id": "ZeMc-I1EgRsI" }, - "source": [] + "source": [ + "သတိပြုပါ၊ ယခင်တန်ဖိုးကို ရှေ့သို့ဖြည့်စွက်ရန် မရရှိနိုင်သောအခါတွင် null တန်ဖိုးသည် ကျန်ရှိနေသည်။\n" + ] }, { "cell_type": "markdown", "metadata": { "id": "eeAoOU0RgRsJ" }, - "source": [] + "source": [ + "### လေ့ကျင့်မှု:\n" + ] }, { "cell_type": "code", @@ -2735,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "သင်သည် `fillna` ကို အသုံးပြုရန် အကြောင်းအရာမရွေး ဖန်တီးနိုင်ပါသည်။ ဥပမာအားဖြင့်၊ `example4` ကို နောက်တစ်ကြိမ် ပြန်လည်ကြည့်ရှုကြမည်၊ ဒါပေမယ့် ဒီတစ်ခါမှာတော့ `DataFrame` ထဲရှိ တန်ဖိုးအားလုံး၏ ပျမ်းမျှတန်ဖိုးဖြင့် ပျောက်ဆုံးနေသော တန်ဖိုးများကို ဖြည့်စွက်ကြည့်မည်။\n" + "သင်သည် `fillna` ကို အသုံးပြုပုံအပေါ်တွင် ဖန်တီးမှုရှိနိုင်သည်။ ဥပမာအားဖြင့်၊ `example4` ကို ထပ်မံကြည့်ရှုကြမည်၊ သို့သော် ဒီတစ်ခါမှာတော့ `DataFrame` ထဲရှိ တန်ဖိုးအားလုံး၏ ပျမ်းမျှတန်ဖိုးဖြင့် မရှိသည့်တန်ဖိုးများကို ဖြည့်စွက်ကြည့်ပါမည်။\n" ] }, { @@ -2826,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "အမှတ်တရ ၃ ကတော့ တန်ဖိုးမရှိသေးပါဘူး။ ပုံမှန်အတိုင်း တန်ဖိုးတွေကို အတန်းလိုက်ဖြည့်သွင်းမှာဖြစ်ပါတယ်။\n", + "သတိပြုပါ၊ အတန်း ၃ သည် အတန်တန်ဖွယ်မရှိသေးပါ။ ပုံမှန်အတိုင်း တန်ဖိုးများကို အတန်းလိုက်ဖြည့်သွင်းသည်။\n", "\n", - "> **အရေးကြီးသောအချက်:** သင့်ဒေတာများတွင် ပျောက်ဆုံးနေသောတန်ဖိုးများကို ကိုင်တွယ်ရန် နည်းလမ်းများစွာရှိပါတယ်။ သင့်အသုံးပြုမည့်နည်းလမ်း (ပျောက်ဆုံးနေသောတန်ဖိုးများကို ဖယ်ရှားခြင်း၊ အစားထိုးခြင်း၊ ဒါမှမဟုတ် အစားထိုးပုံစံကို ရွေးချယ်ခြင်း) သည် အဆိုပါဒေတာ၏ အထူးသက်ဆိုင်မှုများအပေါ် မူတည်သင့်ပါတယ်။ ဒေတာများကို ပိုမိုကိုင်တွယ်ပြီး အလုပ်လုပ်သည့်အခါ ပျောက်ဆုံးနေသောတန်ဖိုးများကို ဘယ်လိုကိုင်တွယ်ရမလဲဆိုတာ ပိုမိုနားလည်လာမည်ဖြစ်သည်။\n" + "> **သင်ခန်းစာ:** သင့်ဒေတာများတွင် ပျောက်ဆုံးနေသောတန်ဖိုးများကို ကိုင်တွယ်ရန် နည်းလမ်းများစွာရှိသည်။ သင့်အသုံးပြုမည့်နည်းလမ်း (ဖယ်ရှားခြင်း၊ အစားထိုးခြင်း၊ သို့မဟုတ် အစားထိုးပုံစံ) သည် အဆိုပါဒေတာ၏အသေးစိတ်အချက်အလက်များအပေါ်မူတည်သင့်သည်။ ဒေတာများကို ပိုမိုကိုင်တွယ်ပြီး အလုပ်လုပ်သည့်အခါ ပျောက်ဆုံးနေသောတန်ဖိုးများကို ဘယ်လိုကိုင်တွယ်ရမည်ဆိုသည်ကို ပိုမိုနားလည်လာမည်ဖြစ်သည်။\n" ] }, { @@ -2837,11 +2869,11 @@ "id": "bauDnESIl9FH" }, "source": [ - "### ကဏ္ဍအချက်အလက်များကို Encode လုပ်ခြင်း\n", + "### ကဏ္ဍအချက်အလက်များကို Encoding လုပ်ခြင်း\n", "\n", - "Machine learning မော်ဒယ်များသည် ကိန်းဂဏန်းများနှင့် ကိန်းဂဏန်းပုံစံအချက်အလက်များကိုသာ ကိုင်တွယ်နိုင်သည်။ မော်ဒယ်သည် Yes နှင့် No အကြားကွာခြားမှုကို မသိနိုင်ပေမယ့် 0 နှင့် 1 အကြားကွာခြားမှုကို သိနိုင်ပါမည်။ ထို့ကြောင့် ပျောက်ဆုံးနေသော အချက်အလက်များကို ဖြည့်ပြီးနောက်၊ ကဏ္ဍအချက်အလက်များကို မော်ဒယ်နားလည်နိုင်ရန်အတွက် ကိန်းဂဏန်းပုံစံတစ်ခုအဖြစ် encode လုပ်ရန် လိုအပ်ပါသည်။\n", + "Machine learning မော်ဒယ်များသည် ကိန်းဂဏန်းများနှင့် ကိန်းဂဏန်းပုံစံအချက်အလက်များကိုသာ ကိုင်တွယ်နိုင်သည်။ မော်ဒယ်သည် Yes နှင့် No အကြားကွာခြားမှုကို မသိနိုင်ပေမယ့် 0 နှင့် 1 အကြားကွာခြားမှုကို သိနိုင်ပါမည်။ ထို့ကြောင့် အချက်အလက်များတွင် ပျောက်နေသောတန်ဖိုးများကို ဖြည့်ပြီးနောက် မော်ဒယ်အနားမှာ နားလည်နိုင်ရန် ကဏ္ဍအချက်အလက်များကို ကိန်းဂဏန်းပုံစံတစ်ခုခုအဖြစ် encode လုပ်ရန် လိုအပ်ပါသည်။\n", "\n", - "Encoding ကို နည်းလမ်းနှစ်မျိုးဖြင့် ပြုလုပ်နိုင်ပါသည်။ အောက်တွင် အဆိုပါနည်းလမ်းများကို ဆွေးနွေးသွားမည်ဖြစ်သည်။\n" + "Encoding ကို လုပ်နိုင်သောနည်းလမ်းနှစ်မျိုးရှိပြီး၊ အောက်တွင် ဆွေးနွေးသွားမည်ဖြစ်သည်။\n" ] }, { @@ -2850,9 +2882,9 @@ "id": "uDq9SxB7mu5i" }, "source": [ - "**တံဆိပ်ကုဒ်ဖြင့်အမှတ်အသားပေးခြင်း**\n", + "**LABEL ENCODING**\n", "\n", - "တံဆိပ်ကုဒ်ဖြင့်အမှတ်အသားပေးခြင်းသည် အမျိုးအစားတစ်ခုချင်းစီကို နံပါတ်တစ်ခုအဖြစ် ပြောင်းလဲခြင်းဖြစ်သည်။ ဥပမာအားဖြင့်၊ လေကြောင်းခရီးသည်များ၏ ဒေတာစုတစ်ခုရှိပြီး၊ ၎င်းတွင် ['business class', 'economy class', 'first class'] စသည်ဖြင့် ခရီးသည်အတန်းအစားကို ဖော်ပြထားသော ကော်လံတစ်ခုရှိသည်ဟု ဆိုပါစို့။ တံဆိပ်ကုဒ်ဖြင့်အမှတ်အသားပေးခြင်းကို ပြုလုပ်ပါက၊ ၎င်းသည် [0,1,2] အဖြစ် ပြောင်းလဲသွားမည်ဖြစ်သည်။ ဥပမာကို ကုဒ်ဖြင့် ကြည့်ရှုကြမည်။ ကျွန်ုပ်တို့သည် နောက်ထပ် notebook များတွင် `scikit-learn` ကို သင်ယူမည်ဖြစ်သော်လည်း၊ ဒီနေရာတွင်တော့ ၎င်းကို အသုံးမပြုပါ။\n" + "Label encoding သည် အမျိုးအစားတစ်ခုချင်းစီကို နံပါတ်တစ်ခုအဖြစ် ပြောင်းလဲခြင်းဖြစ်သည်။ ဥပမာအားဖြင့်၊ ကျွန်ုပ်တို့တွင် လေကြောင်းခရီးသည်များ၏ dataset ရှိပြီး ['business class', 'economy class', 'first class'] အမျိုးအစားများပါဝင်သော column တစ်ခုရှိသည်ဟု ဆိုပါစို့။ Label encoding ပြုလုပ်ပါက၊ ၎င်းသည် [0,1,2] အဖြစ် ပြောင်းလဲသွားမည်ဖြစ်သည်။ Code ဖြင့် ဥပမာကို ကြည့်ကြမည်။ ကျွန်ုပ်တို့သည် နောက်ထပ် notebooks များတွင် `scikit-learn` ကို သင်ယူမည်ဖြစ်သဖြင့်၊ ဒီနေရာတွင် မသုံးပါ။\n" ] }, { @@ -2960,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "ပထမဆုံးကော်လံတွင် label encoding ပြုလုပ်ရန်အတွက်၊ အတန်းတစ်ခုချင်းစီကို နံပါတ်တစ်ခုနှင့်ဆက်စပ်ထားသော မြေပုံဖော်ပြချက်ကို အရင်ဆုံးဖော်ပြရမည်၊ ထို့နောက် အစားထိုးရန်\n" + "ပထမတန်းကော်လံတွင် label encoding ပြုလုပ်ရန်၊ အရင်ဆုံး တစ်ခုချင်းစီ၏အတန်းကို နံပါတ်တစ်ခုနှင့်ဆက်စပ်ထားသော mapping ကို ဖော်ပြရမည်၊ ထို့နောက် အစားထိုးရန်။\n" ] }, { @@ -3062,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "ကျွန်တော်တို့မြင်နိုင်သည့်အတိုင်း၊ အထွေထွေထင်မြင်ထားသည့်အတိုင်းရလဒ်များကိုတွေ့ရှိနိုင်ပါသည်။ ဒါဆိုရင် label encoding ကိုဘယ်အချိန်မှာအသုံးပြုသင့်သလဲ? Label encoding ကိုအောက်ပါအခြေအနေများတွင် အသုံးပြုပါသည်။\n", - "1. အမျိုးအစားများ၏အရေအတွက်များသောအခါ\n", - "2. အမျိုးအစားများသည်အစီအစဉ်ရှိသောအခါ\n" + "ကျွန်တော်တို့မြင်နိုင်သည့်အတိုင်း၊ အထွက်သည် ကျွန်တော်တို့ထင်ထားသည့်အတိုင်းကိုက်ညီနေသည်။ ဒါဆိုရင် label encoding ကို ဘယ်အချိန်မှာသုံးမလဲ? Label encoding ကို အောက်ပါအခြေအနေများအနက် တစ်ခုသို့မဟုတ် နှစ်ခုလုံးတွင်သုံးပါသည်။\n", + "1. အမျိုးအစားများရဲ့ အရေအတွက်များသောအခါ\n", + "2. အမျိုးအစားများသည် အစီအစဉ်အတိုင်းရှိသောအခါ\n" ] }, { @@ -3073,11 +3105,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**One Hot Encoding**\n", + "**ONE HOT ENCODING**\n", "\n", - "အခြားသော Encoding အမျိုးအစားတစ်ခုမှာ One Hot Encoding ဖြစ်ပါတယ်။ ဒီ Encoding အမျိုးအစားမှာ Column ရဲ့ Category တစ်ခုစီကို သီးသန့် Column အဖြစ် ထည့်သွင်းပြီး၊ Data Point တစ်ခုစီမှာ အဲဒီ Category ပါဝင်မပါဝင်ပေါ်မူတည်ပြီး 0 သို့မဟုတ် 1 ကို ထည့်သွင်းပေးပါမယ်။ ဒါကြောင့် Category မျိုးစုံ n ခုရှိရင် Dataframe မှာ Column n ခုကို ထပ်ထည့်ပေးပါမယ်။\n", + "One Hot Encoding ဆိုတာ Encoding အမျိုးအစားတစ်ခုဖြစ်ပါတယ်။ ဒီ Encoding အမျိုးအစားမှာ Column ရဲ့ Category တစ်ခုချင်းစီကို သီးသန့် Column အဖြစ် ထည့်ပေးပြီး၊ Data Point တစ်ခုချင်းစီမှာ အဲဒီ Category ပါဝင်မပါဝင်ပေါ်မူတည်ပြီး 0 သို့မဟုတ် 1 ကို ထည့်ပေးပါတယ်။ ဒါကြောင့် Category မျိုးစုံ n ခုရှိရင် Dataframe မှာ Column n ခုကို ထပ်ထည့်ပေးရပါမယ်။\n", "\n", - "ဥပမာအားဖြင့် အရင်က သုံးခဲ့တဲ့ လေယာဉ်အတန်းပုံစံကို ပြန်ယူကြည့်ရအောင်။ Categories တွေက ['business class', 'economy class', 'first class'] ဖြစ်ပါတယ်။ ဒါကြောင့် One Hot Encoding ကို လုပ်ဆောင်မယ်ဆိုရင် Dataset မှာ အောက်ပါ Column သုံးခုကို ထည့်သွင်းပေးပါမယ်။ ['class_business class', 'class_economy class', 'class_first class']\n" + "ဥပမာအနေနဲ့ အရင်က သုံးခဲ့တဲ့ လေယာဉ်အတန်း (Aeroplane Class) ဥပမာကို ပြန်ယူကြည့်ရအောင်။ Categories တွေက ['business class', 'economy class', 'first class'] ဖြစ်ပါတယ်။ ဒါကြောင့် One Hot Encoding လုပ်မယ်ဆိုရင် Dataset မှာ ['class_business class', 'class_economy class', 'class_first class'] ဆိုတဲ့ Column သုံးခုကို ထည့်ပေးရပါမယ်။\n" ] }, { @@ -3184,7 +3216,9 @@ "metadata": { "id": "aVnZ7paDrWmb" }, - "source": [] + "source": [ + "အရင်ကော်လံကို One Hot Encoding ပြုလုပ်ကြပါစို့\n" + ] }, { "cell_type": "code", @@ -3308,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "တစ်ခုချင်းစီ hot encoded ကော်လံတွင် 0 သို့မဟုတ် 1 ပါဝင်ပြီး၊ အဲဒီအမျိုးအစားသည် အဲဒီဒေတာပွိုင့်အတွက် ရှိမရှိကို ဖော်ပြသည်။\n" + "တစ်ခုချင်းစီသော hot encoded ကော်လံတွင် 0 သို့မဟုတ် 1 ပါဝင်ပြီး၊ အဲဒီအမျိုးအစားသည် အဲဒီဒေတာပွိုင့်အတွက် ရှိမရှိကို သတ်မှတ်ပေးသည်။\n" ] }, { @@ -3317,10 +3351,10 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "တစ်ခုချင်းစီကို One Hot Encoding ဘယ်အချိန်မှာသုံးမလဲ? One Hot Encoding ကို အောက်ပါအခြေအနေများထဲမှ တစ်ခု သို့မဟုတ် နှစ်ခုလုံးတွင် အသုံးပြုကြသည် -\n", + "One hot encoding ကို ဘယ်အချိန်မှာ အသုံးပြုသင့်သလဲ? One hot encoding ကို အောက်ပါအခြေအနေများတွင် အသုံးပြုနိုင်သည် -\n", "\n", - "1. အမျိုးအစားများရဲ့ အရေအတွက်နဲ့ ဒေတာစနစ်ရဲ့ အရွယ်အစားက သေးငယ်တဲ့အခါ။\n", - "2. အမျိုးအစားများမှာ သတ်မှတ်ထားတဲ့ အစီအစဉ်မရှိတဲ့အခါ။\n" + "1. အမျိုးအစားများရဲ့ အရေအတွက်နဲ့ dataset ရဲ့ အရွယ်အစားက သေးငယ်တဲ့အခါ။\n", + "2. အမျိုးအစားများမှာ အထူးအစီအစဉ်မရှိတဲ့အခါ။\n" ] }, { @@ -3329,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "အဓိကအချက်များ: \n", - "1. Encoding သည် အနက်မပါသော ဒေတာများကို အနက်ပါသော ဒေတာများအဖြစ် ပြောင်းလဲရန်အတွက် ပြုလုပ်သည်။ \n", - "2. Encoding အမျိုးအစားနှစ်မျိုးရှိသည် - Label encoding နှင့် One Hot encoding၊ ဒါတွေကို dataset ရဲ့ လိုအပ်ချက်အပေါ်မူတည်ပြီး ပြုလုပ်နိုင်သည်။ \n" + "> အဓိကအချက်များ:\n", + "1. အနက်ရှိုင်းမဟုတ်သောဒေတာများကို နံပါတ်ပုံစံဒေတာများအဖြစ် ပြောင်းလဲရန် Encoding ကို အသုံးပြုသည်။\n", + "2. Encoding အမျိုးအစားနှစ်မျိုးရှိသည် - Label encoding နှင့် One Hot encoding ဖြစ်ပြီး၊ ဒေတာစနစ်၏လိုအပ်ချက်များအပေါ်မူတည်၍ အဆိုပါ encoding များကို ပြုလုပ်နိုင်သည်။\n" ] }, { @@ -3340,11 +3374,11 @@ "id": "K8UXOJYRgRsJ" }, "source": [ - "## အချက်အလက်အတူတူများကို ဖယ်ရှားခြင်း\n", + "## အချက်အလက်ထပ်နေမှုများကို ဖယ်ရှားခြင်း\n", "\n", - "> **သင်ယူရည်မှန်းချက်:** ဤအပိုင်းလေးအဆုံးသတ်ချိန်တွင် DataFrames မှ အချက်အလက်အတူတူများကို ဖော်ထုတ်ပြီး ဖယ်ရှားနိုင်ရန် ကျွမ်းကျင်မှုရှိလာမည်။\n", + "> **သင်ယူရမည့်ရည်ရွယ်ချက်:** ဒီအခန်းခွဲအဆုံးတွင် DataFrames မှ ထပ်နေသောတန်ဖိုးများကို ရှာဖွေပြီး ဖယ်ရှားနိုင်ရန် သင်ကျွမ်းကျင်လာရမည်။\n", "\n", - "ပျက်ကွက်နေသော အချက်အလက်များအပြင်၊ အမှန်တကယ်ရှိသော dataset များတွင် အချက်အလက်အတူတူများနှင့်လည်း ကြုံတွေ့ရလေ့ရှိသည်။ ကံကောင်းစွာဖြင့် pandas သည် အချက်အလက်အတူတူများကို ရှာဖွေဖော်ထုတ်ရန်နှင့် ဖယ်ရှားရန် လွယ်ကူသော နည်းလမ်းတစ်ခုကို ပံ့ပိုးပေးထားသည်။\n" + "ပျောက်နေသောအချက်အလက်များအပြင်၊ အမှန်တကယ်ရှိသောဒေတာများတွင် အချက်အလက်ထပ်နေမှုများကိုလည်း မကြာခဏတွေ့ရပါမည်။ ကံကောင်းစွာ pandas သည် ထပ်နေသောအချက်အလက်များကို ရှာဖွေပြီး ဖယ်ရှားရန် လွယ်ကူသောနည်းလမ်းကို ပံ့ပိုးပေးထားပါသည်။\n" ] }, { @@ -3353,9 +3387,9 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### အတူတူဖြစ်နေသောတန်ဖိုးများကို ရှာဖွေခြင်း: `duplicated`\n", + "### အတူတူဖြစ်သောတန်ဖိုးများကိုရှာဖွေခြင်း: `duplicated`\n", "\n", - "သင်သည် pandas ရဲ့ `duplicated` method ကို အသုံးပြု၍ အတူတူဖြစ်နေသောတန်ဖိုးများကို လွယ်ကူစွာ ရှာဖွေနိုင်ပါသည်။ ဤ method သည် `DataFrame` အတွင်းရှိ တစ်ခုတည်းသော အချက်အလက်သည် ယခင်တစ်ခုနှင့် အတူတူဖြစ်ကြောင်း ပြသသော Boolean mask ကို ပြန်ပေးပါသည်။ ဤကို လက်တွေ့အသုံးပြုရန်အတွက် နောက်ထပ် `DataFrame` တစ်ခုကို ဖန်တီးကြည့်ရအောင်။\n" + "pandas မှာ `duplicated` method ကိုအသုံးပြုပြီး အတူတူဖြစ်သောတန်ဖိုးများကို လွယ်ကူစွာရှာဖွေနိုင်ပါတယ်။ ဒီ method က Boolean mask ကိုပြန်ပေးပြီး `DataFrame` ထဲမှာ ရှိနေတဲ့ entry တစ်ခုဟာ အရင်တစ်ခုနဲ့ အတူတူဖြစ်ကြောင်းကို ဖော်ပြပေးပါတယ်။ ဒီကို လက်တွေ့အသုံးပြုကြည့်ဖို့ `DataFrame` တစ်ခုကို ပြန်ဖန်တီးကြည့်ရအောင်။\n" ] }, { @@ -3485,7 +3519,7 @@ }, "source": [ "### အတူတူထပ်နေသောအချက်အလက်များကို ဖယ်ရှားခြင်း: `drop_duplicates`\n", - "`drop_duplicates` သည် `duplicated` အဖြေများအားလုံးမှာ `False` ဖြစ်နေသော အချက်အလက်များကို ကူးယူပြီး ပြန်ပေးသည်။\n" + "`drop_duplicates` သည် `duplicated` အဖြစ် `False` ဖြစ်နေသော အချက်အလက်များကိုသာ ထုတ်ပေးသော copy ကို ပြန်ပေးသည်။\n" ] }, { @@ -3568,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "`duplicated` နှင့် `drop_duplicates` နှစ်ခုစလုံးသည် အကုန်လုံးသော ကော်လံများကို စဉ်းစားရန် ပုံမှန်ထားရှိထားပြီး သို့သော် သင့် `DataFrame` တွင် ကော်လံအချို့ကိုသာ စစ်ဆေးရန် သတ်မှတ်နိုင်ပါသည်။\n" + "`duplicated` နှင့် `drop_duplicates` နှစ်ခုစလုံးသည် အကုန်လုံးကို default အနေနဲ့ စဉ်းစားပေးသော်လည်း သင့် `DataFrame` မှာ column အချို့ကိုသာ စစ်ဆေးစေလိုပါက သတ်မှတ်ပေးနိုင်သည်။\n" ] }, { @@ -3644,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **အဓိကအချက်:** အတူတူထပ်နေသောဒေတာများကိုဖယ်ရှားခြင်းသည် ဒေတာသိပ္ပံပညာစီမံကိန်းများ၏ အရေးကြီးသောအပိုင်းတစ်ခုဖြစ်သည်။ အတူတူထပ်နေသောဒေတာများသည် သင့်၏ခန့်မှန်းချက်ရလဒ်များကို ပြောင်းလဲစေပြီး မမှန်ကန်သောရလဒ်များကိုရရှိစေနိုင်ပါသည်!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## အမှန်တကယ်ရှိသော ဒေတာအရည်အသွေး စစ်ဆေးမှုများ\n", + "\n", + "> **သင်ယူရည်မှန်းချက်:** ဒီအပိုင်းအဆုံးသတ်ချိန်မှာ အမျိုးအစားတူတူမညီညွတ်သောတန်ဖိုးများ၊ အဆမတန်နံပါတ်တန်ဖိုးများ (outliers)၊ နည်းနည်းကွဲပြားမှုရှိသော အတူတူသောအရာများကို ရှာဖွေပြီး ပြင်ဆင်နိုင်ရန် သင်အဆင်ပြေဖြစ်ရမည်။\n", + "\n", + "ပျောက်ဆုံးနေသောတန်ဖိုးများနှင့် တိကျသောအတူတူမှုများသည် အများအားဖြင့်တွေ့ရသောပြဿနာများဖြစ်သော်လည်း အမှန်တကယ်ရှိသောဒေတာများတွင် ပိုမိုသိသာသောပြဿနာများပါဝင်နိုင်သည်။\n", + "\n", + "1. **အမျိုးအစားတူတူမညီညွတ်သောတန်ဖိုးများ**: တူညီသောအမျိုးအစားကို အခြားအခြားပုံစံဖြင့် ရေးသားထားခြင်း (ဥပမာ - \"USA\", \"U.S.A\", \"United States\")\n", + "2. **အဆမတန်နံပါတ်တန်ဖိုးများ**: ဒေတာထည့်သွင်းမှုမှားယွင်းမှုများကို ဖော်ပြသော အလွန်အမင်းသော outliers (ဥပမာ - အသက် = 999)\n", + "3. **နီးကပ်သောအတူတူသောအတန်းများ**: နည်းနည်းကွဲပြားမှုရှိသော်လည်း တူညီသော entity ကို ကိုယ်စားပြုသော မှတ်တမ်းများ\n", + "\n", + "ဒီပြဿနာများကို ရှာဖွေပြီး ကိုင်တွယ်နိုင်ရန် နည်းလမ်းများကို လေ့လာကြမည်။\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### \"ညစ်ပတ်\" ဒေတာစနစ်တစ်ခုကို စမ်းသပ်ဖန်တီးခြင်း\n", + "\n", + "ပထမဦးဆုံး၊ အမှန်တကယ်ဒေတာများတွင် မကြုံရခဲသော ပြဿနာအမျိုးမျိုးပါဝင်သော စမ်းသပ်ဒေတာစနစ်တစ်ခုကို ဖန်တီးကြမယ်:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. မတူညီသော အမျိုးအစားတန်ဖိုးများကို ရှာဖွေခြင်း\n", + "\n", + "`country` ကော်လံတွင် တစ်နိုင်ငံတည်းအတွက် အမျိုးမျိုးသော ကိုယ်စားပြုမှုများရှိနေသည်ကို သတိပြုပါ။ အဆိုပါ မတူညီမှုများကို ရှာဖွေကြမည်:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Categorized Values များကို စံပြုခြင်း\n", + "\n", + "ဤတန်ဖိုးများကို စံပြုရန်အတွက် mapping တစ်ခုကို ဖန်တီးနိုင်ပါသည်။ ရိုးရှင်းသောနည်းလမ်းတစ်ခုမှာ lowercase သို့ ပြောင်းပြီး mapping dictionary တစ်ခုကို ဖန်တီးခြင်းဖြစ်သည်။\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**အခြားနည်းလမ်း: Fuzzy Matching ကို အသုံးပြုခြင်း**\n", + "\n", + "ပိုမိုရှုပ်ထွေးသောအခြေအနေများအတွက် `rapidfuzz` စာကြောင်းကိုက်ညီမှု စနစ်ကို အသုံးပြု၍ တူညီသော စာကြောင်းများကို အလိုအလျောက် ရှာဖွေနိုင်ပါသည်။\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. အဆင့်မမှန်သော ကိန်းဂဏန်းတန်ဖိုးများ (Outliers) ကို ရှာဖွေခြင်း\n", + "\n", + "`age` ကော်လံကိုကြည့်လိုက်ရင် 199 နဲ့ -5 လို သံသယရှိတဲ့တန်ဖိုးတွေရှိပါတယ်။ ဒီ outliers တွေကို ရှာဖွေဖို့ စာရင်းကိုင်နည်းလမ်းတွေကို အသုံးပြုကြမယ်။\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### IQR (အလယ်တန်းအကွာအဝေး) နည်းလမ်းကို အသုံးပြုခြင်း\n", + "\n", + "IQR နည်းလမ်းသည် အလွန်အမင်းတန်ဖိုးများအပေါ် အထူးမထိခိုက်သော အလွန်အမင်းတန်ဖိုးများကို ရှာဖွေဖို့ အသုံးပြုနိုင်သော အဆင့်မြင့် စက်မှုစဉ်နည်းလမ်းတစ်ခုဖြစ်သည်။\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Z-Score နည်းလမ်းကို အသုံးပြုခြင်း\n", + "\n", + "Z-score နည်းလမ်းသည် အလယ်တန်းတန်ဖိုးမှ စံအလျားချိုးများအပေါ် အခြေခံ၍ ထူးခြားသောတန်ဖိုးများကို ဖော်ထုတ်သည်။\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### အထူးအချက်များကို ကိုင်တွယ်ခြင်း\n", + "\n", + "အထူးအချက်များကို ရှာဖွေတွေ့ရှိပြီးနောက်၊ အောက်ပါနည်းလမ်းများဖြင့် ကိုင်တွယ်နိုင်ပါသည်။\n", + "1. **ဖယ်ရှား**: အမှားဖြစ်သော အထူးအချက်များပါဝင်သော အတန်းများကို ဖယ်ရှားပါ။\n", + "2. **အကန့်အသတ်ထား**: အကန့်အသတ်တန်ဖိုးများဖြင့် အစားထိုးပါ။\n", + "3. **NaN ဖြင့် အစားထိုး**: မရှိသော ဒေတာအဖြစ် ဆက်ဆံပြီး အစားထိုးနည်းလမ်းများကို အသုံးပြုပါ။\n", + "4. **ထားရှိထား**: အထူးအချက်များသည် တရားဝင်သော extrême တန်ဖိုးများဖြစ်ပါက ထားရှိပါ။\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. နီးကပ်သော အတူတူသော အတန်းများကို ရှာဖွေခြင်း\n", + "\n", + "ကျွန်ုပ်တို့၏ ဒေတာစနစ်တွင် \"John Smith\" အတွက် အနည်းငယ်ကွဲပြားသော တန်ဖိုးများနှင့်အတူ အများအပြား အဝင်များရှိသည်ကို သတိပြုပါ။ နာမည်တူညီမှုအပေါ် အခြေခံပြီး များစွာသော အတူတူသော အတန်းများကို ရှာဖွေကြမည်။\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### နီးစပ်သော အတူတူသောအရာများကို Fuzzy Matching ဖြင့် ရှာဖွေခြင်း\n", + "\n", + "ပိုမိုတိုးတက်သော အတူတူသောအရာများကို ရှာဖွေရန်အတွက် Fuzzy Matching ကို အသုံးပြု၍ နီးစပ်သော နာမည်များကို ရှာဖွေနိုင်ပါသည်။\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### အတူတူဖြစ်သောအရာများကို ကိုင်တွယ်ခြင်း\n", + "\n", + "အတူတူဖြစ်သောအရာများကို ရှာဖွေတွေ့ရှိပြီးနောက်၊ အောက်ပါနည်းလမ်းများဖြင့် ကိုင်တွယ်ရန် ဆုံးဖြတ်ရမည်။\n", + "1. **ပထမဆုံးတွေ့ရှိမှုကို ထားရှိရန်**: `drop_duplicates(keep='first')` ကို အသုံးပြုပါ\n", + "2. **နောက်ဆုံးတွေ့ရှိမှုကို ထားရှိရန်**: `drop_duplicates(keep='last')` ကို အသုံးပြုပါ\n", + "3. **အချက်အလက်များကို စုပေါင်းရန်**: အတူတူဖြစ်သော အတန်းများမှ အချက်အလက်များကို ပေါင်းစည်းပါ\n", + "4. **လူ့အကဲဖြတ်မှု**: လူ့အကဲဖြတ်မှုအတွက် အမှတ်အသားပြုထားပါ\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### အကျဉ်းချုပ် - အပြည့်အစုံသော ဒေတာသန့်စင်ရေးပိုင်းဆိုင်ရာလုပ်ငန်းစဉ်\n", + "\n", + "အခုတော့ ဒေတာသန့်စင်ရေးလုပ်ငန်းစဉ်ကို အပြည့်အစုံအဖြစ် စုပေါင်းပြီး တစ်ခုတည်းအဖြစ် ဖော်ဆောင်ကြမယ်:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 စိန်ခေါ်မှုလေ့ကျင့်ခန်း\n", + "\n", + "အခုတော့ သင့်အလှည့်ပါ! အောက်မှာ အရည်အသွေးပြဿနာများစွာပါဝင်တဲ့ ဒေတာတစ်တန်းအသစ်ရှိပါတယ်။ သင်လုပ်နိုင်မလား:\n", + "\n", + "1. ဒီတန်းမှာရှိတဲ့ ပြဿနာအားလုံးကို ဖော်ထုတ်ပါ\n", + "2. ပြဿနာတစ်ခုချင်းစီကို သန့်ရှင်းစေရန် ကုဒ်ရေးပါ\n", + "3. သန့်ရှင်းပြီးတဲ့ ဒေတာတန်းကို dataset ထဲမှာ ထည့်ပါ\n", + "\n", + "ဒီမှာ ပြဿနာရှိတဲ့ ဒေတာတွေရှိပါတယ်:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### အဓိကအချက်များ\n", + "\n", + "1. **အမျိုးအစားများ မညီညွတ်မှု** သည် အမှန်တကယ်ရှိသော ဒေတာများတွင် မကြာခဏတွေ့ရသည်။ တန်ဖိုးများကို ထူးခြားစွာ စစ်ဆေးပြီး မျှတစွာ စနစ်တကျပြင်ဆင်ရန် mapping သို့မဟုတ် fuzzy matching ကို အသုံးပြုပါ။\n", + "\n", + "2. **Outliers** သည် သင့်အနုစိတ်ခွဲခြမ်းစိတ်ဖြာမှုကို အလွန်အကျွံ သက်ရောက်စေနိုင်သည်။ အထူးကျွမ်းကျင်မှုနှင့် စာရင်းအင်းနည်းလမ်းများ (IQR, Z-score) ကို ပေါင်းစပ်အသုံးပြု၍ Outliers ကို ရှာဖွေပါ။\n", + "\n", + "3. **နီးကပ်သော အတူတူများ** ကို တိကျသော အတူတူများထက် ရှာဖွေဖို့ ပိုခက်သည်။ Fuzzy matching နှင့် ဒေတာကို အဆင်ပြေစွာ ပြင်ဆင်ခြင်း (lowercasing, whitespace ဖယ်ရှားခြင်း) ကို အသုံးပြု၍ ရှာဖွေပါ။\n", + "\n", + "4. **ဒေတာသန့်စင်ခြင်းသည် အဆင့်ဆင့်ဖြစ်သည်**။ သင့်ဒေတာသန့်စင်ပြီးဆုံးရန် မတူညီသောနည်းလမ်းများကို အသုံးပြုပြီး ရလဒ်များကို ပြန်လည်သုံးသပ်ရန် လိုအပ်နိုင်သည်။\n", + "\n", + "5. **သင့်ဆုံးဖြတ်ချက်များကို မှတ်တမ်းတင်ပါ**။ သင့်သန့်စင်ခြင်းအဆင့်များကို ဘာကြောင့်အသုံးပြုခဲ့သည်ဆိုတာ အလင်းပြထားရန်၊ ပြန်လုပ်နိုင်မှုနှင့် ထင်ရှားမှုအတွက် အရေးကြီးသည်။\n", + "\n", + "> **အကောင်းဆုံးအလေ့အကျင့်:** သင့်ရဲ့ မူရင်း \"ညစ်ပတ်နေသော\" ဒေတာကို အမြဲတမ်း မိတိတက်ထားပါ။ မူရင်းဒေတာဖိုင်များကို မဖျက်ပါနှင့် - `data_cleaned.csv` ကဲ့သို့သော အမည်ပေးနည်းလမ်းများဖြင့် သန့်စင်ထားသောဗားရှင်းများကို ဖန်တီးပါ။\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**ဝက်ဘ်ဆိုက်မှတ်ချက်**: \nဤစာရွက်စာတမ်းကို AI ဘာသာပြန်ဝန်ဆောင်မှု [Co-op Translator](https://github.com/Azure/co-op-translator) ကို အသုံးပြု၍ ဘာသာပြန်ထားပါသည်။ ကျွန်ုပ်တို့သည် တိကျမှန်ကန်မှုအတွက် ကြိုးစားနေပါသော်လည်း၊ အလိုအလျောက်ဘာသာပြန်ဆိုမှုများတွင် အမှားများ သို့မဟုတ် မတိကျမှုများ ပါဝင်နိုင်သည်ကို ကျေးဇူးပြု၍ သတိပြုပါ။ မူရင်းစာရွက်စာတမ်းကို ၎င်း၏ မူလဘာသာစကားဖြင့် အာဏာတည်သောရင်းမြစ်အဖြစ် သတ်မှတ်သင့်ပါသည်။ အရေးကြီးသော အချက်အလက်များအတွက် လူ့ဘာသာပြန်ပညာရှင်များမှ ပြန်ဆိုမှုကို အကြံပြုပါသည်။ ဤဘာသာပြန်ကို အသုံးပြုခြင်းမှ ဖြစ်ပေါ်လာသော နားလည်မှုမှားမှုများ သို့မဟုတ် အဓိပ္ပါယ်မှားမှုများအတွက် ကျွန်ုပ်တို့သည် တာဝန်မယူပါ။\n" + "\n---\n\n**အကြောင်းကြားချက်**: \nဤစာရွက်စာတမ်းကို AI ဘာသာပြန်ဝန်ဆောင်မှု [Co-op Translator](https://github.com/Azure/co-op-translator) ကို အသုံးပြု၍ ဘာသာပြန်ထားပါသည်။ ကျွန်ုပ်တို့သည် တိကျမှုအတွက် ကြိုးစားနေသော်လည်း အလိုအလျောက် ဘာသာပြန်မှုများတွင် အမှားများ သို့မဟုတ် မမှန်ကန်မှုများ ပါဝင်နိုင်သည်ကို သတိပြုပါ။ မူရင်းဘာသာစကားဖြင့် ရေးသားထားသော စာရွက်စာတမ်းကို အာဏာတရ အရင်းအမြစ်အဖြစ် သတ်မှတ်သင့်ပါသည်။ အရေးကြီးသော အချက်အလက်များအတွက် လူက ဘာသာပြန်မှုကို အကြံပြုပါသည်။ ဤဘာသာပြန်မှုကို အသုံးပြုခြင်းမှ ဖြစ်ပေါ်လာသော အလွဲအမှားများ သို့မဟုတ် အနားလွဲမှုများအတွက် ကျွန်ုပ်တို့သည် တာဝန်မယူပါ။\n" ] } ], @@ -3678,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:19:05+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T21:20:19+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "my" } diff --git a/translations/ne/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/ne/2-Working-With-Data/08-data-preparation/notebook.ipynb index 6b66721d..6cfd8e5f 100644 --- a/translations/ne/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/ne/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# डेटा तयारी\n", "\n", - "[मूल नोटबुक स्रोत *डेटा साइन्स: डाटा साइन्सका लागि मेसिन लर्निङको परिचय, पायथन र मेसिन लर्निङ स्टुडियो द्वारा ली स्टट*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[मूल नोटबुक स्रोत *डेटा साइन्स: डाटा साइन्सका लागि मेसिन लर्निङको परिचय, पायथन र मेसिन लर्निङ स्टुडियो, ली स्टटद्वारा*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## `DataFrame` जानकारी अन्वेषण गर्दै\n", "\n", - "> **शिक्षण लक्ष्य:** यस उपविभागको अन्त्यसम्म, तपाईं pandas DataFrames मा भण्डारण गरिएको डाटाको सामान्य जानकारी पत्ता लगाउन सहज महसुस गर्नुहुनेछ।\n", + "> **शिक्षण लक्ष्य:** यो उपविभागको अन्त्यसम्ममा, तपाईं pandas DataFrames मा संग्रहित डाटाको सामान्य जानकारी पत्ता लगाउन सहज हुनु पर्नेछ।\n", "\n", - "जब तपाईंले आफ्नो डाटा pandas मा लोड गर्नुहुन्छ, यो सम्भवतः `DataFrame` मा हुनेछ। तर, यदि तपाईंको `DataFrame` मा ६०,००० पङ्क्तिहरू र ४०० स्तम्भहरू छन् भने, तपाईंले काम गर्न लागेको डाटाको बारेमा कसरी थाहा पाउनुहुन्छ? सौभाग्यवश, pandas ले `DataFrame` को समग्र जानकारी हेर्नका लागि साथै पहिलो केही र अन्तिम केही पङ्क्तिहरू हेर्नका लागि केही सुविधाजनक उपकरणहरू प्रदान गर्दछ।\n", + "जब तपाईंले आफ्नो डेटा pandas मा लोड गर्नुहुन्छ, यो सम्भवतः `DataFrame` मा हुनेछ। तर, यदि तपाईंको `DataFrame` मा ६०,००० पङ्क्ति र ४०० स्तम्भ छन् भने, तपाईंले काम गरिरहेको डाटाको बारेमा कसरी थाहा पाउनुहुन्छ? सौभाग्यवश, pandas ले `DataFrame` को समग्र जानकारी छिटो हेर्नका लागि केही सुविधाजनक उपकरणहरू प्रदान गर्दछ, साथै पहिलो केही र अन्तिम केही पङ्क्तिहरू पनि।\n", "\n", - "यस कार्यक्षमता अन्वेषण गर्नका लागि, हामी Python को scikit-learn लाइब्रेरी आयात गर्नेछौं र एउटा प्रसिद्ध डाटासेट प्रयोग गर्नेछौं जुन हरेक डेटा वैज्ञानिकले सयौं पटक देखेका छन्: बेलायती जीवविज्ञानी रोनाल्ड फिशरको *Iris* डाटासेट, जुन उनले १९३६ मा \"The use of multiple measurements in taxonomic problems\" शीर्षकको आफ्नो पेपरमा प्रयोग गरेका थिए:\n" + "यस कार्यक्षमता अन्वेषण गर्नका लागि, हामी Python को scikit-learn लाइब्रेरी आयात गर्नेछौं र एक प्रसिद्ध डाटासेट प्रयोग गर्नेछौं जुन प्रत्येक डेटा वैज्ञानिकले सयौं पटक देखेका छन्: ब्रिटिश जीवविज्ञानी रोनाल्ड फिशरको *Iris* डाटासेट, जुन उनले १९३६ मा \"The use of multiple measurements in taxonomic problems\" नामक कागजमा प्रयोग गरेका थिए:\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "हामीले Iris Dataset लाई `iris_df` नामको भेरिएबलमा लोड गरेका छौं। डाटामा प्रवेश गर्नु अघि, हामीसँग कति डाटापोइन्टहरू छन् र डाटासेटको कुल आकार कस्तो छ भन्ने जान्न महत्त्वपूर्ण हुनेछ। हामीले सामना गरिरहेको डाटाको मात्रा हेर्न उपयोगी हुन्छ।\n" + "हामीले Iris Dataset लाई `iris_df` भेरिएबलमा लोड गरेका छौं। डाटामा गहिराइमा जानु अघि, हामीसँग कति डाटापोइन्टहरू छन् र डाटासेटको कुल आकार कति छ भन्ने जान्नु महत्त्वपूर्ण हुनेछ। हामीले सामना गरिरहेको डाटाको परिमाण हेर्नु उपयोगी हुन्छ।\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "त्यसैले, हामीसँग १५० पङ्क्ति र ४ स्तम्भको डाटा छ। प्रत्येक पङ्क्तिले एउटा डाटापोइन्टलाई प्रतिनिधित्व गर्छ र प्रत्येक स्तम्भले डाटा फ्रेमसँग सम्बन्धित एउटा विशेषता देखाउँछ। त्यसैले आधारभूत रूपमा, त्यहाँ १५० डाटापोइन्टहरू छन्, जसमा प्रत्येकमा ४ विशेषताहरू छन्।\n", + "त्यसैले, हामी १५० पंक्ति र ४ स्तम्भको डेटा संग काम गरिरहेका छौं। प्रत्येक पंक्ति एक डेटा बिन्दुलाई प्रतिनिधित्व गर्दछ र प्रत्येक स्तम्भ डेटा फ्रेमसँग सम्बन्धित एकल विशेषता प्रतिनिधित्व गर्दछ। त्यसैले आधारभूत रूपमा, त्यहाँ १५० डेटा बिन्दुहरू छन् जसमा प्रत्येकमा ४ विशेषताहरू छन्।\n", "\n", - "`shape` यहाँ डाटा फ्रेमको एउटा गुण हो, कार्य (function) होइन, त्यसैले यसले जोडी कोष्ठकहरूमा अन्त्य गर्दैन।\n" + "`shape` यहाँ डेटा फ्रेमको एक गुण हो र कुनै फङ्सन होइन, यही कारणले यसले जोडी कोष्ठकमा अन्त्य गर्दैन।\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "अब हामी डाटाका ४ स्तम्भहरूतर्फ जाऔं। यी प्रत्येकले के प्रतिनिधित्व गर्छन्? `columns` एट्रिब्युटले हामीलाई डेटा फ्रेममा रहेका स्तम्भहरूको नाम दिन्छ।\n" + "अब हामी डाटाका ४ स्तम्भहरूमा प्रवेश गरौं। ती प्रत्येकले वास्तवमा के प्रतिनिधित्व गर्छन्? `columns` गुणले हामीलाई डाटाफ्रेममा स्तम्भहरूको नाम दिन्छ।\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "जसरी हामी देख्न सक्छौं, त्यहाँ चार(४) वटा स्तम्भहरू छन्। `columns` विशेषताले हामीलाई स्तम्भहरूको नाम बताउँछ र मूलतः अरू केही होइन। यो विशेषता महत्त्वपूर्ण हुन्छ जब हामी कुनै डेटासेटमा भएका विशेषताहरू पहिचान गर्न चाहन्छौं।\n" + "जस्तो कि हामी देख्न सक्छौं, त्यहाँ चार(४) स्तम्भहरू छन्। `columns` विशेषताले हामीलाई स्तम्भहरूको नाम बताउँछ र आधारभूत रूपमा अरू केही बताउँदैन। यो विशेषता महत्वपूर्ण हुन्छ जब हामी कुनै डेटासेटले समावेश गर्ने विशेषताहरू पहिचान गर्न चाहन्छौं।\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "डाटाको मात्रा (`shape` attribute ले दिएको) र विशेषता वा स्तम्भहरूको नाम (`columns` attribute ले दिएको) ले हामीलाई डेटासेटको बारेमा केही जानकारी दिन्छ। अब, हामी डेटासेटमा अझ गहिरो रूपमा जान चाहन्छौं। `DataFrame.info()` function यसका लागि निकै उपयोगी छ।\n" + "डाटाको मात्रा (`shape` attribute ले दिएको) र विशेषता वा स्तम्भहरूको नाम (`columns` attribute ले दिएको) ले हामीलाई डेटासेटको बारेमा केही जानकारी दिन्छ। अब, हामी डेटासेटमा अझ गहिरो रूपमा जान चाहन्छौं। `DataFrame.info()` फंक्शन यसका लागि निकै उपयोगी छ।\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "यहाँबाट, हामी केही अवलोकनहरू गर्न सक्छौं: \n", - "1. प्रत्येक स्तम्भको डेटा प्रकार: यस डेटासेटमा, सबै डेटा 64-बिट फ्लोटिङ-पोइन्ट संख्याको रूपमा संग्रह गरिएको छ। \n", - "2. गैर-नल मानहरूको संख्या: नल मानहरूलाई व्यवस्थापन गर्नु डेटा तयारीको महत्त्वपूर्ण चरण हो। यसलाई पछि नोटबुकमा सम्बोधन गरिनेछ। \n" + "यहाँबाट, हामी केही अवलोकनहरू गर्न सक्छौं:\n", + "1. प्रत्येक स्तम्भको डेटा प्रकार: यस डेटासेटमा, सबै डेटा 64-बिट फ्लोटिङ-पोइन्ट संख्याहरूको रूपमा संग्रहित गरिएको छ।\n", + "2. गैर-नल मानहरूको संख्या: नल मानहरूलाई व्यवस्थापन गर्नु डेटा तयारीको महत्त्वपूर्ण चरण हो। यसलाई पछि नोटबुकमा सम्बोधन गरिनेछ।\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "मानौं हाम्रो डेटासेटमा धेरै संख्यात्मक डाटा छ। जस्तै औसत, माध्यिका, चतुर्थांशहरू आदि जस्ता एकपक्षीय सांख्यिकीय गणनाहरू प्रत्येक स्तम्भमा अलग-अलग गर्न सकिन्छ। `DataFrame.describe()` फंक्शनले डेटासेटका संख्यात्मक स्तम्भहरूको सांख्यिकीय सारांश प्रदान गर्दछ।\n" + "मानौं हाम्रो डेटासेटमा धेरै संख्यात्मक डाटा छ। प्रत्येक स्तम्भमा अलग-अलग रूपमा औसत, माध्यिका, चौथाई भागहरू जस्ता एकपक्षीय सांख्यिकीय गणनाहरू गर्न सकिन्छ। `DataFrame.describe()` फङ्सनले हामीलाई डेटासेटका संख्यात्मक स्तम्भहरूको सांख्यिकीय सारांश प्रदान गर्दछ।\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "उपरोक्त परिणामले प्रत्येक स्तम्भको कुल डाटा बिन्दुहरूको संख्या, औसत, मानक विचलन, न्यूनतम, तल्लो चतुर्थांश (२५%), माध्यिका (५०%), माथिल्लो चतुर्थांश (७५%) र अधिकतम मान देखाउँछ।\n" + "माथिको आउटपुटले प्रत्येक स्तम्भको कुल डेटा बिन्दुहरूको संख्या, औसत, मानक विचलन, न्यूनतम, तल्लो क्वार्टाइल (२५%), माध्य (५०%), माथिल्लो क्वार्टाइल (७५%) र अधिकतम मान देखाउँछ।\n" ] }, { @@ -332,7 +332,7 @@ }, "source": [ "### `DataFrame.head`\n", - "माथिका सबै फंक्शनहरू र विशेषताहरूको साथमा, हामीले डेटासेटको उच्च स्तरको दृष्टिकोण प्राप्त गरेका छौं। हामीलाई थाहा छ कति डेटा पोइन्टहरू छन्, कति विशेषताहरू छन्, प्रत्येक विशेषताको डेटा प्रकार के हो र प्रत्येक विशेषताका लागि कति गैर-शून्य मानहरू छन्।\n", + "माथिका सबै फंक्शनहरू र एट्रिब्युटहरू प्रयोग गरेर, हामीले डेटासेटको उच्च स्तरको दृष्टिकोण प्राप्त गरेका छौं। हामीलाई थाहा छ कति डेटा पोइन्टहरू छन्, कति विशेषताहरू छन्, प्रत्येक विशेषताको डेटा प्रकार के हो, र प्रत्येक विशेषताका लागि कति गैर-शून्य मानहरू छन्।\n", "\n", "अब डेटा आफैं हेर्ने समय आएको छ। हाम्रो `DataFrame` का पहिलो केही पङ्क्तिहरू (पहिलो केही डेटा पोइन्टहरू) कस्तो देखिन्छन् हेर्नुहोस्:\n" ] @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "आउटपुटमा, हामीले डेटासेटका पाँच(५) इन्ट्रीहरू देख्न सक्छौं। यदि हामी बायाँतिरको इन्डेक्स हेर्छौं भने, यी पहिलो पाँच पंक्तिहरू हुन् भन्ने पत्ता लगाउन सक्छौं।\n" + "यहाँको नतिजामा, हामीले डेटासेटका पाँच(५) इन्ट्रीहरू देख्न सक्छौं। यदि हामी बायाँतिरको इन्डेक्स हेर्छौं भने, हामी पत्ता लगाउँछौं कि यी पहिलो पाँच पंक्तिहरू हुन्।\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### अभ्यास:\n", "\n", - "माथि दिइएको उदाहरणबाट स्पष्ट छ कि, डिफल्ट रूपमा, `DataFrame.head` ले `DataFrame` का पहिलो पाँच पङ्क्तिहरू फिर्ता गर्छ। तलको कोड सेलमा, के तपाईं पाँचभन्दा बढी पङ्क्तिहरू देखाउने तरिका पत्ता लगाउन सक्नुहुन्छ?\n" + "माथि दिइएको उदाहरणबाट स्पष्ट छ कि, डिफल्ट रूपमा, `DataFrame.head` ले `DataFrame` का पहिलो पाँच पङ्क्तिहरू फिर्ता गर्छ। तलको कोड सेलमा, के तपाईं पाँचभन्दा बढी पङ्क्तिहरू प्रदर्शन गर्ने तरिका पत्ता लगाउन सक्नुहुन्छ?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "डाटा हेर्ने अर्को तरिका अन्त्यबाट (सुरुवातको सट्टा) हुन सक्छ। `DataFrame.head` को उल्टो पक्ष `DataFrame.tail` हो, जसले `DataFrame` का अन्तिम पाँच पंक्तिहरू फिर्ता गर्छ:\n" + "डेटा हेर्ने अर्को तरिका अन्त्यबाट (सुरुवातको सट्टा) हुन सक्छ। `DataFrame.head` को उल्टो पक्ष `DataFrame.tail` हो, जसले `DataFrame` का अन्तिम पाँच पंक्तिहरू फिर्ता गर्छ:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "व्यवहारमा, विशेष गरी जब तपाईं क्रमबद्ध डेटासेटहरूमा बाहिरिने मानहरू खोज्दै हुनुहुन्छ, `DataFrame` का पहिलो केही पङ्क्तिहरू वा अन्तिम केही पङ्क्तिहरू सजिलैसँग जाँच गर्न सक्षम हुनु उपयोगी हुन्छ।\n", + "व्यवहारमा, `DataFrame` का पहिलो केही पङ्क्तिहरू वा अन्तिम केही पङ्क्तिहरू सजिलैसँग जाँच गर्न सक्षम हुनु उपयोगी हुन्छ, विशेष गरी जब तपाईं क्रमबद्ध डेटासेटहरूमा असामान्य मानहरू खोज्दै हुनुहुन्छ। \n", "\n", - "माथि कोड उदाहरणहरूको मद्दतले देखाइएका सबै functions र attributes ले हामीलाई डेटा हेर्न र महसुस गर्न मद्दत गर्छ।\n", + "माथि कोड उदाहरणहरूको मद्दतले देखाइएका सबै कार्यहरू र विशेषताहरूले हामीलाई डेटा हेर्न र बुझ्न मद्दत गर्छ। \n", "\n", - "> **मुख्य कुरा:** केवल `DataFrame` मा भएको जानकारीको metadata हेरेर वा यसको पहिलो र अन्तिम केही मानहरू हेरेर पनि, तपाईंले तपाईंले काम गरिरहेको डेटा कस्तो आकार, आकार, र सामग्रीको हो भन्ने बारे तुरुन्तै धारणा बनाउन सक्नुहुन्छ।\n" + "> **मुख्य कुरा:** केवल `DataFrame` मा भएको जानकारीको मेटाडेटा हेरेर वा यसको पहिलो र अन्तिम केही मानहरू हेरेर पनि, तपाईंले आफूले काम गरिरहेको डेटाको आकार, संरचना, र सामग्रीको बारेमा तुरुन्तै धारणा बनाउन सक्नुहुन्छ।\n" ] }, { @@ -595,18 +595,18 @@ "id": "TvurZyLSDxq_" }, "source": [ - "### हराएको डाटा\n", - "आउनुहोस्, हराएको डाटाबारे छलफल गरौं। हराएको डाटा तब हुन्छ, जब केही स्तम्भहरूमा कुनै मान राखिएको हुँदैन।\n", + "### हराएको डेटा\n", + "आउनुहोस्, हराएको डेटा बारे छलफल गरौं। हराएको डेटा तब हुन्छ जब केही स्तम्भहरूमा कुनै मान राखिएको हुँदैन।\n", "\n", - "उदाहरण लिऔं: मानौं कसैलाई आफ्नो तौलको बारेमा धेरै चिन्ता छ र उसले सर्वेक्षणमा तौलको क्षेत्र खाली छोड्छ। त्यस अवस्थामा, उक्त व्यक्तिको तौलको मान हराएको हुनेछ।\n", + "उदाहरण लिऔं: मानौं कसैलाई आफ्नो तौलको बारेमा धेरै चिन्ता छ र उसले सर्वेक्षणमा तौलको क्षेत्र भर्दैन। त्यस अवस्थामा, उक्त व्यक्तिको तौलको मान हराएको हुनेछ।\n", "\n", - "धेरैजसो समय, वास्तविक संसारका डेटासेटहरूमा हराएका मानहरू देखिन्छन्।\n", + "अधिकांश समय, वास्तविक संसारका डेटासेटहरूमा हराएका मानहरू देखिन्छन्।\n", "\n", - "**Pandas ले हराएको डाटालाई कसरी व्यवस्थापन गर्छ**\n", + "**Pandas ले हराएको डेटा कसरी व्यवस्थापन गर्छ**\n", "\n", - "Pandas ले हराएका मानहरूलाई दुई तरिकाले व्यवस्थापन गर्छ। पहिलो तरिका तपाईंले पहिलेका खण्डहरूमा देखिसक्नुभएको छ: `NaN`, वा Not a Number। यो वास्तवमा IEEE फ्लोटिङ-पोइन्ट स्पेसिफिकेसनको एक विशेष मान हो र यो केवल हराएको फ्लोटिङ-पोइन्ट मानहरूलाई जनाउन प्रयोग गरिन्छ।\n", + "Pandas ले हराएका मानहरूलाई दुई तरिकाले व्यवस्थापन गर्छ। पहिलो तरिका तपाईंले पहिलेका खण्डहरूमा देख्नुभएको छ: `NaN`, अर्थात् Not a Number। यो वास्तवमा IEEE floating-point विशिष्टताको एक विशेष मान हो र यो केवल हराएका floating-point मानहरूलाई संकेत गर्न प्रयोग गरिन्छ।\n", "\n", - "फ्लोट बाहेकका हराएका मानहरूको लागि, pandas ले Python को `None` वस्तु प्रयोग गर्छ। यद्यपि यो अलि भ्रमित लाग्न सक्छ कि तपाईंले दुई फरक प्रकारका मानहरू सामना गर्नुहुनेछ जसले मूलतः एउटै कुरा जनाउँछन्, यस डिजाइन छनोटको लागि ठोस प्रोग्रामेटिक कारणहरू छन्। व्यवहारमा, यस मार्गमा जानुले pandas लाई धेरैजसो केसहरूको लागि राम्रो सन्तुलन प्रदान गर्न सक्षम बनाउँछ। यद्यपि, `None` र `NaN` दुबैसँग केही सीमाहरू छन् जसलाई तपाईंले ध्यानमा राख्नुपर्छ, विशेष गरी तिनीहरूलाई कसरी प्रयोग गर्न सकिन्छ भन्ने सन्दर्भमा।\n" + "Floating-point बाहेकका हराएका मानहरूको लागि, pandas ले Python को `None` वस्तु प्रयोग गर्छ। दुई फरक प्रकारका मानहरू देख्नुपर्दा अलि भ्रमित लाग्न सक्छ, तर यो डिजाइन विकल्पका लागि ठोस प्रोग्रामिङ कारणहरू छन्। व्यवहारमा, यसले pandas लाई अधिकांश केसहरूका लागि राम्रो सन्तुलन प्रदान गर्न सक्षम बनाउँछ। यद्यपि, `None` र `NaN` दुवैसँग केही सीमाहरू छन् जसको बारेमा तपाईं सचेत हुनुपर्छ कि तिनीहरूलाई कसरी प्रयोग गर्न सकिन्छ।\n" ] }, { @@ -615,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: गैर-फ्लोट हराएको डाटा\n", - "किनभने `None` Python बाट आउँछ, यसलाई NumPy र pandas का arrays मा प्रयोग गर्न सकिँदैन जुन डाटा प्रकार `'object'` को होइन। सम्झनुहोस्, NumPy arrays (र pandas का डाटा संरचनाहरू) मा एउटै प्रकारको डाटा मात्र समावेश गर्न सकिन्छ। यही कारणले गर्दा तिनीहरूले ठूलो मात्रामा डाटा र गणनात्मक कामका लागि अपार शक्ति प्रदान गर्छन्, तर यसले तिनीहरूको लचिलोपनलाई सीमित पनि गर्छ। यस्ता arrays ले \"सबैभन्दा कम साझा गुणक\" मा अपकास्ट गर्नुपर्छ, जुन डाटा प्रकारले array मा सबै कुरा समेट्न सक्छ। जब array मा `None` हुन्छ, यसको मतलब तपाईं Python objects सँग काम गर्दै हुनुहुन्छ।\n", + "### `None`: गैर-फ्लोट हराएको डेटा\n", + "किनभने `None` Python बाट आउँछ, यसलाई NumPy र pandas का arrays मा प्रयोग गर्न सकिँदैन जुन डेटा प्रकार `'object'` होइन। सम्झनुहोस्, NumPy arrays (र pandas मा रहेका डेटा संरचनाहरू) मा केवल एक प्रकारको डेटा मात्र समावेश गर्न सकिन्छ। यही कारणले तिनीहरूलाई ठूलो-स्तरको डेटा र गणनात्मक कामको लागि अत्यधिक शक्ति दिन्छ, तर यसले तिनीहरूको लचिलोपनलाई सीमित पनि गर्छ। यस्ता arrays ले \"सबभन्दा सामान्य डिनोमिनेटर,\" अर्थात् डेटा प्रकार जसले array मा सबै कुरा समेट्न सक्छ, मा अपकास्ट गर्नुपर्छ। जब `None` array मा हुन्छ, यसको मतलब तपाईं Python objects सँग काम गरिरहनुभएको छ।\n", "\n", - "यसलाई व्यवहारमा हेर्नको लागि, निम्न उदाहरण array लाई विचार गर्नुहोस् (यसको `dtype` मा ध्यान दिनुहोस्):\n" + "यसलाई व्यवहारमा देख्नको लागि, निम्न उदाहरण array विचार गर्नुहोस् (यसको `dtype` मा ध्यान दिनुहोस्):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "अपकास्ट डाटा प्रकारहरूको वास्तविकताले दुई प्रकारका प्रभावहरू ल्याउँछ। पहिलो, अपरेसनहरू व्याख्या गरिएको Python कोडको स्तरमा गरिन्छ, कम्पाइल गरिएको NumPy कोडको स्तरमा होइन। यसको मतलब, `Series` वा `DataFrames` मा `None` समावेश भएका अपरेसनहरू सामान्यतया ढिलो हुनेछन्। यद्यपि तपाईंले यो प्रदर्शनमा आएको असर सायद महसुस गर्नुहुने छैन, ठूला डाटासेटहरूमा यो समस्या बन्न सक्छ।\n", + "अपकास्ट डाटा प्रकारहरूको वास्तविकताले दुई प्रकारका प्रभावहरू ल्याउँछ। पहिलो, अपरेशनहरू व्याख्या गरिएको Python कोडको स्तरमा गरिन्छ, कम्पाइल गरिएको NumPy कोडको स्तरमा होइन। यसको मतलब, `Series` वा `DataFrames` मा `None` समावेश भएका अपरेशनहरू सुस्त हुनेछन्। यद्यपि तपाईंले यो प्रदर्शनमा आएको असरलाई सायद महसुस गर्नुहुने छैन, ठूला डाटासेटहरूमा यो समस्या हुन सक्छ।\n", "\n", - "दोस्रो प्रभाव पहिलोबाट उत्पन्न हुन्छ। किनभने `None` ले `Series` वा `DataFrame`s लाई सामान्य Python को दुनियाँमा फर्काउँछ, NumPy/pandas को `sum()` वा `min()` जस्ता समग्र गणनाहरू प्रयोग गर्दा, यदि array मा ``None`` मान छ भने सामान्यतया त्रुटि उत्पन्न हुन्छ:\n" + "दोस्रो प्रभाव पहिलोबाट उत्पन्न हुन्छ। किनभने `None` ले `Series` वा `DataFrame`s लाई सामान्य Python को दुनियाँमा फर्काउँछ, त्यसैले NumPy/pandas को `sum()` वा `min()` जस्ता समग्र गणनाहरू प्रयोग गर्दा, यदि array मा ``None`` मान हुन्छ भने सामान्यतया त्रुटि उत्पन्न हुन्छ:\n" ] }, { @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**मुख्य कुरा**: पूर्णांक र `None` मानहरू बीचको थप (र अन्य अपरेशनहरू) अपरिभाषित हुन्छ, जसले ती समावेश गर्ने डाटासेटहरूसँग के गर्न सकिन्छ भन्ने सीमित गर्न सक्छ।\n" + ] }, { "cell_type": "markdown", @@ -707,7 +709,7 @@ "source": [ "### `NaN`: हराएको फ्लोट मानहरू\n", "\n", - "`None` को विपरीत, NumPy (र त्यसैले pandas) ले यसको छिटो, भेक्टराइज्ड अपरेसनहरू र ufuncs का लागि `NaN` समर्थन गर्दछ। नराम्रो खबर यो हो कि `NaN` मा गरिने कुनै पनि अंकगणितीय कार्यले सधैं `NaN` नै परिणाम दिन्छ। उदाहरणका लागि:\n" + "`None` को विपरीत, NumPy (र त्यसैले pandas) ले यसको छिटो, भेक्टराइज्ड अपरेशनहरू र ufuncs को लागि `NaN` समर्थन गर्दछ। नराम्रो समाचार भनेको `NaN` मा गरिने कुनै पनि अंकगणितीय कार्यले सधैं `NaN` नै परिणाम दिन्छ। उदाहरणका लागि:\n" ] }, { @@ -770,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "खुसीको खबर: `NaN` भएका एरेहरूमा चल्ने एग्रिगेसनहरूले त्रुटिहरू उत्पन्न गर्दैनन्। नराम्रो खबर: परिणामहरू समान रूपमा उपयोगी हुँदैनन्:\n" + "राम्रो खबर: `NaN` भएको एरेहरूमा चल्ने समग्रहरू त्रुटिहरू देखाउँदैनन्। नराम्रो खबर: परिणामहरू समान रूपमा उपयोगी हुँदैनन्:\n" ] }, { @@ -806,7 +808,9 @@ "metadata": { "id": "nhlnNJT7gRr_" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -826,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "सम्झनुहोस्: `NaN` केवल हराइरहेका फ्लोटिङ-पोइन्ट मानहरूको लागि हो; पूर्णांक, स्ट्रिङ, वा बूलियनहरूको लागि `NaN` बराबर केही छैन।\n" + ] }, { "cell_type": "markdown", @@ -836,7 +842,7 @@ "source": [ "### `NaN` र `None`: pandas मा null मानहरू\n", "\n", - "यद्यपि `NaN` र `None` केही हदसम्म फरक व्यवहार गर्न सक्छन्, pandas लाई यी दुबैलाई परस्पर विनिमेय रूपमा व्यवस्थापन गर्न बनाइएको छ। हामी के भन्न खोजिरहेका छौं बुझ्नको लागि, एउटा पूर्णांकहरूको `Series` लाई विचार गर्नुहोस्:\n" + "यद्यपि `NaN` र `None` केही हदसम्म फरक व्यवहार गर्न सक्छन्, pandas तिनीहरूलाई परस्पर रूपमा व्यवस्थापन गर्न बनाइएको छ। हामीले के भन्न खोजेका छौं बुझ्नको लागि, एक `Series` को पूर्णांकहरूको उदाहरण हेर्नुहोस्:\n" ] }, { @@ -875,7 +881,9 @@ "metadata": { "id": "WklCzqb8gRsB" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -898,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "पाण्डासमा `Series` र `DataFrame` हरूमा डेटा प्रकारहरूको समानता कायम गर्न अपकास्टिङ गर्दा, पाण्डासले हराएका मानहरूलाई `None` र `NaN` बीच सजिलै परिवर्तन गर्न सक्छ। यस डिजाइन सुविधाका कारण, पाण्डासमा `None` र `NaN` लाई \"null\" का दुई फरक प्रकारका रूपमा सोच्नु उपयोगी हुन सक्छ। वास्तवमा, पाण्डासमा हराएका मानहरूलाई व्यवस्थापन गर्न प्रयोग गरिने केही मुख्य विधिहरूले यो विचारलाई आफ्ना नामहरूमा झल्काउँछन्:\n", + "`Series` र `DataFrame` मा डाटा समानता कायम गर्न डाटा प्रकारलाई अपकास्ट गर्ने प्रक्रियामा, pandas ले हराएका मानहरूलाई `None` र `NaN` बीच सजिलै परिवर्तन गर्न सक्छ। यस डिजाइन सुविधाका कारण, pandas मा `None` र `NaN` लाई \"null\" का दुई फरक प्रकारका रूपमा सोच्नु उपयोगी हुन सक्छ। वास्तवमा, pandas मा हराएका मानहरूलाई व्यवस्थापन गर्न प्रयोग गरिने केही मुख्य विधिहरूले यस विचारलाई आफ्नो नाममा प्रतिबिम्बित गर्छन्:\n", "\n", - "- `isnull()`: हराएका मानहरूलाई जनाउने बूलियन मास्क उत्पन्न गर्छ\n", + "- `isnull()`: हराएका मानहरूलाई संकेत गर्ने बूलियन मास्क उत्पन्न गर्छ\n", "- `notnull()`: `isnull()` को विपरीत\n", - "- `dropna()`: डेटा को फिल्टर गरिएको संस्करण फिर्ता दिन्छ\n", - "- `fillna()`: हराएका मानहरू भरेर वा अनुमान गरेर डेटा को प्रतिलिपि फिर्ता दिन्छ\n", + "- `dropna()`: डाटाको फिल्टर गरिएको संस्करण फर्काउँछ\n", + "- `fillna()`: हराएका मानहरू भरेर वा अनुमान गरेर डाटाको प्रतिलिपि फर्काउँछ\n", "\n", - "यी विधिहरूलाई राम्रोसँग बुझ्न र सहज हुन सिक्नु महत्त्वपूर्ण छ, त्यसैले हामी यी प्रत्येकलाई विस्तारमा बुझ्ने प्रयास गरौं।\n" + "यी विधिहरूलाई राम्रोसँग बुझ्न र प्रयोग गर्न सिक्नु महत्त्वपूर्ण छ, त्यसैले अब हामी यी प्रत्येकलाई विस्तारमा बुझ्ने प्रयास गरौं।\n" ] }, { @@ -914,10 +922,10 @@ "id": "Yh5ifd9FgRsB" }, "source": [ - "### नल मानहरू पत्ता लगाउँदै\n", + "### शून्य मानहरू पत्ता लगाउँदै\n", "\n", - "अब हामीले हराएका मानहरूको महत्त्व बुझेका छौं, तिनीहरूलाई व्यवस्थापन गर्नुअघि हाम्रो डेटासेटमा तिनीहरू पत्ता लगाउन आवश्यक छ। \n", - "`isnull()` र `notnull()` दुबै नल डाटालाई पत्ता लगाउनका लागि तपाईंका मुख्य विधिहरू हुन्। यी दुबैले तपाईंको डाटामा बूलियन मास्कहरू फिर्ता गर्छन्।\n" + "अब हामीले हराएका मानहरूको महत्त्व बुझिसकेपछि, तिनीहरूलाई व्यवस्थापन गर्नुअघि हाम्रो डेटासेटमा तिनीहरूलाई पत्ता लगाउन आवश्यक छ। \n", + "`isnull()` र `notnull()` दुबै शून्य डाटा पत्ता लगाउनका लागि मुख्य विधिहरू हुन्। दुबैले तपाईंको डाटामा Boolean मास्कहरू फर्काउँछन्।\n" ] }, { @@ -970,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "ध्यानपूर्वक हेर्नुहोस्। के यसमा केही कुरा तपाईंलाई अचम्म लाग्छ? जबकि `0` एक अंकगणितीय शून्य हो, यो अझै पनि एकदम राम्रो पूर्णांक हो र pandas ले यसलाई त्यस्तै व्यवहार गर्छ। `''` अलि बढी सूक्ष्म छ। जबकि हामीले यसलाई खण्ड १ मा खाली स्ट्रिङ मानको रूपमा प्रयोग गरेका थियौं, यो अझै पनि स्ट्रिङ वस्तु हो र pandas को दृष्टिकोणले यो null को प्रतिनिधित्व होइन।\n", + "आउटपुटलाई ध्यानपूर्वक हेर्नुहोस्। के यसमा कुनै कुरा तपाईंलाई अचम्म लाग्छ? जबकि `0` एक गणितीय शून्य हो, यो अझै पनि एक राम्रो पूर्णांक हो र pandas ले यसलाई त्यस्तै व्यवहार गर्छ। `''` भने अलि सूक्ष्म छ। हामीले यसलाई खण्ड १ मा खाली स्ट्रिङ मानको रूपमा प्रयोग गरेका थियौं, तर pandas को दृष्टिकोणले यो खालीको प्रतिनिधित्व होइन, यो स्ट्रिङ वस्तु हो।\n", "\n", - "अब, यसलाई उल्ट्याएर यी विधिहरूलाई व्यवहारमा जस्तै प्रयोग गरौं। तपाईं Boolean मास्कहरूलाई सिधै ``Series`` वा ``DataFrame`` को इन्डेक्सको रूपमा प्रयोग गर्न सक्नुहुन्छ, जुन छुट्टै हराएका (वा उपस्थित) मानहरूसँग काम गर्दा उपयोगी हुन सक्छ।\n", + "अब, यसलाई उल्ट्याएर यी विधिहरूलाई व्यवहारमा जस्तै प्रयोग गरिन्छ त्यसरी प्रयोग गरौं। तपाईं Boolean मास्कहरूलाई सिधै ``Series`` वा ``DataFrame`` को इन्डेक्सको रूपमा प्रयोग गर्न सक्नुहुन्छ, जुन छुट्टै हराएका (वा उपस्थित) मानहरूसँग काम गर्दा उपयोगी हुन सक्छ।\n", "\n", - "यदि हामीलाई हराएका मानहरूको कुल संख्या चाहिन्छ भने, हामी `isnull()` विधिले उत्पादन गरेको मास्कमा sum गर्न सक्छौं।\n" + "यदि हामीलाई हराएका मानहरूको कुल संख्या चाहिन्छ भने, हामी `isnull()` विधिले उत्पादन गरेको मास्कमा सिधै sum गर्न सक्छौं।\n" ] }, { @@ -1008,7 +1016,9 @@ "metadata": { "id": "PlBqEo3mgRsC" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -1030,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**मुख्य कुरा**: दुवै `isnull()` र `notnull()` विधिहरूले समान परिणाम उत्पादन गर्छन् जब तपाईं तिनीहरूलाई DataFrames मा प्रयोग गर्नुहुन्छ: तिनीहरूले परिणामहरू र ती परिणामहरूको सूचकांक देखाउँछन्, जसले तपाईंलाई तपाईंको डाटासँग संघर्ष गर्दा अत्यधिक मद्दत गर्नेछ।\n" + "**मुख्य कुरा**: दुवै `isnull()` र `notnull()` विधिहरूले DataFrames मा प्रयोग गर्दा समान परिणामहरू उत्पादन गर्छन्: तिनीहरूले परिणामहरू र ती परिणामहरूको सूचकांक देखाउँछन्, जसले तपाईंलाई तपाईंको डाटासँग संघर्ष गर्दा अत्यधिक मद्दत गर्नेछ।\n" ] }, { @@ -1041,18 +1051,18 @@ "source": [ "### हराएको डाटासँग व्यवहार गर्ने\n", "\n", - "> **शिक्षण लक्ष्य:** यो उपविभागको अन्त्यसम्ममा, तपाईंले DataFrames बाट null मानहरू कहिले र कसरी प्रतिस्थापन गर्ने वा हटाउने भन्ने जान्नुहुनेछ।\n", + "> **अध्ययनको लक्ष्य:** यो उपविभागको अन्त्यसम्ममा, तपाईंले DataFrames बाट null मानहरू कहिले र कसरी प्रतिस्थापन गर्ने वा हटाउने भन्ने कुरा जान्नुपर्नेछ।\n", "\n", - "Machine Learning मोडेलहरूले आफैंले हराएको डाटासँग व्यवहार गर्न सक्दैनन्। त्यसैले, डाटालाई मोडेलमा पठाउनु अघि, हामीले यी हराएका मानहरूसँग व्यवहार गर्नुपर्छ।\n", + "मेसिन लर्निङ मोडेलहरूले आफैं हराएको डाटासँग व्यवहार गर्न सक्दैनन्। त्यसैले, मोडेलमा डाटा पठाउनु अघि, हामीले यी हराएका मानहरूलाई व्यवस्थापन गर्नुपर्छ।\n", "\n", - "हराएको डाटालाई कसरी व्यवस्थापन गरिन्छ भन्ने कुराले सूक्ष्म सम्झौता (tradeoffs) ल्याउँछ, जसले तपाईंको अन्तिम विश्लेषण र वास्तविक संसारको नतिजामा प्रभाव पार्न सक्छ।\n", + "हराएको डाटालाई कसरी व्यवस्थापन गरिन्छ भन्ने कुराले सानो तर महत्वपूर्ण प्रभाव पार्छ, जसले तपाईंको अन्तिम विश्लेषण र वास्तविक संसारको परिणामलाई असर गर्न सक्छ।\n", "\n", - "हराएको डाटासँग व्यवहार गर्ने मुख्यतः दुई तरिकाहरू छन्:\n", + "हराएको डाटासँग व्यवहार गर्ने मुख्यत: दुई तरिका छन्:\n", "\n", - "1. हराएको मान भएको पङ्क्ति (row) हटाउनुहोस् \n", - "2. हराएको मानलाई कुनै अन्य मानले प्रतिस्थापन गर्नुहोस् \n", + "1. हराएको मान भएको पङ्क्ति हटाउनुहोस्\n", + "2. हराएको मानलाई कुनै अन्य मानले प्रतिस्थापन गर्नुहोस्\n", "\n", - "हामी यी दुवै विधिहरू र तिनका फाइदा र बेफाइदाहरू विस्तारमा छलफल गर्नेछौं। \n" + "हामी यी दुवै विधिहरू र तिनका फाइदा र बेफाइदाको विस्तृत रूपमा चर्चा गर्नेछौं।\n" ] }, { @@ -1061,13 +1071,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### नल मानहरू हटाउने\n", + "### खाली मानहरू हटाउने\n", "\n", - "हामीले हाम्रो मोडेललाई दिने डाटाको परिमाणले यसको प्रदर्शनमा प्रत्यक्ष प्रभाव पार्छ। नल मानहरू हटाउनुको अर्थ हो कि हामी डाटापोइन्टहरूको संख्या घटाउँदैछौं, जसले गर्दा डेटासेटको आकार पनि घट्छ। त्यसैले, जब डेटासेट धेरै ठूलो हुन्छ, नल मान भएका पङ्क्तिहरू हटाउनु सल्लाहयोग्य हुन्छ।\n", + "हामीले हाम्रो मोडेललाई दिने डाटाको मात्रा यसको प्रदर्शनमा सीधा प्रभाव पार्छ। खाली मानहरू हटाउनु भनेको हामीले डाटापोइन्टहरूको संख्या घटाउनु हो, जसले गर्दा डेटासेटको आकार पनि घट्छ। त्यसैले, जब डेटासेट धेरै ठूलो हुन्छ, खाली मान भएका पङ्क्तिहरू हटाउनु सल्लाहयोग्य हुन्छ।\n", "\n", - "अर्को उदाहरण हुन सक्छ कि कुनै निश्चित पङ्क्ति वा स्तम्भमा धेरै हराएका मानहरू छन्। त्यस अवस्थामा, ती पङ्क्ति वा स्तम्भलाई हटाउन सकिन्छ किनभने ती हाम्रो विश्लेषणमा धेरै मूल्य थप्दैनन्, किनभने अधिकांश डाटा हराएको हुन्छ।\n", + "अर्को उदाहरण हुन सक्छ कि कुनै निश्चित पङ्क्ति वा स्तम्भमा धेरै हराएका मानहरू छन्। त्यस अवस्थामा, ती हटाउन सकिन्छ किनभने ती पङ्क्ति/स्तम्भको अधिकांश डाटा हराएको हुँदा हाम्रो विश्लेषणमा धेरै मूल्य थप्दैन।\n", "\n", - "हराएका मानहरू पहिचान गर्न बाहेक, pandas ले `Series` र `DataFrame`s बाट नल मानहरू हटाउनको लागि सुविधाजनक उपाय प्रदान गर्दछ। यसलाई व्यवहारमा हेर्नको लागि, हामी `example3` मा फर्कौं। `DataFrame.dropna()` function ले नल मान भएका पङ्क्तिहरू हटाउन मद्दत गर्दछ।\n" + "हराएका मानहरू पहिचान गर्न बाहेक, pandas ले `Series` र `DataFrame`s बाट खाली मानहरू हटाउनको लागि सुविधाजनक उपाय प्रदान गर्दछ। यसलाई व्यवहारमा देख्नको लागि, हामी `example3` मा फर्कौं। `DataFrame.dropna()` फङ्क्सनले खाली मान भएका पङ्क्तिहरू हटाउन मद्दत गर्दछ।\n" ] }, { @@ -1106,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "ध्यान दिनुहोस् कि यो तपाईंको `example3[example3.notnull()]` बाट प्राप्त हुने परिणाम जस्तै देखिनुपर्छ। यहाँ फरक यति मात्र छ कि, मास्क गरिएका मानहरूमा मात्र इन्डेक्सिङ गर्ने सट्टा, `dropna` ले `Series` `example3` बाट ती हराएका मानहरू हटाएको छ।\n", + "ध्यान दिनुहोस् कि यो `example3[example3.notnull()]` को नतिजा जस्तै देखिनु पर्छ। यहाँको फरक के छ भने, केवल मास्क गरिएको मानहरूमा इन्डेक्सिङ गर्ने सट्टा, `dropna` ले `Series` `example3` बाट ती हराएका मानहरू हटाएको छ।\n", "\n", - "किनभने DataFrames दुई आयामहरूमा हुन्छन्, तिनीहरूले डाटा हटाउनका लागि थप विकल्पहरू प्रदान गर्छन्।\n" + "किनभने DataFrames दुई आयामहरूमा हुन्छन्, तिनीहरूले डेटा हटाउनका लागि थप विकल्पहरू प्रदान गर्छन्।\n" ] }, { @@ -1200,7 +1210,7 @@ "source": [ "(के तपाईंले ध्यान दिनुभयो कि pandas ले `NaN`s समायोजन गर्न दुई स्तम्भहरूलाई floats मा परिवर्तन गर्यो?)\n", "\n", - "तपाईं `DataFrame` बाट एकल मान हटाउन सक्नुहुन्न, त्यसैले तपाईंले पूर्ण पङ्क्ति वा स्तम्भहरू हटाउनुपर्छ। तपाईंले के गर्दै हुनुहुन्छ भन्ने आधारमा, तपाईंले यीमध्ये कुनै एक गर्न चाहनुहुन्छ, र त्यसैले pandas ले तपाईंलाई दुवैका लागि विकल्पहरू दिन्छ। किनभने डेटा विज्ञानमा, स्तम्भहरूले सामान्यतया भेरिएबलहरू प्रतिनिधित्व गर्छन् र पङ्क्तिहरूले अवलोकनहरू प्रतिनिधित्व गर्छन्, तपाईंले प्रायः डेटा पङ्क्तिहरू हटाउन चाहनुहुन्छ; `dropna()` को डिफल्ट सेटिङ भनेको कुनै पनि null मानहरू समावेश गर्ने सबै पङ्क्तिहरू हटाउनु हो:\n" + "तपाईं `DataFrame` बाट एकल मान हटाउन सक्नुहुन्न, त्यसैले तपाईंले पूर्ण पंक्ति वा स्तम्भहरू हटाउनुपर्छ। तपाईंले के गर्दै हुनुहुन्छ भन्ने आधारमा, तपाईंले एउटा वा अर्को गर्न चाहनुहुन्छ, र त्यसैले pandas ले तपाईंलाई दुवैको विकल्प दिन्छ। किनभने डेटा विज्ञानमा, स्तम्भहरूले सामान्यतया चरहरू प्रतिनिधित्व गर्छन् र पंक्तिहरूले अवलोकनहरू प्रतिनिधित्व गर्छन्, तपाईं डेटा पंक्तिहरू हटाउन बढी सम्भावना राख्नुहुन्छ; `dropna()` को डिफल्ट सेटिङले कुनै पनि null मानहरू समावेश गर्ने सबै पंक्तिहरू हटाउँछ:\n" ] }, { @@ -1273,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "यदि आवश्यक भएमा, तपाईं स्तम्भहरूबाट NA मानहरू हटाउन सक्नुहुन्छ। त्यसो गर्न `axis=1` प्रयोग गर्नुहोस्:\n" + "यदि आवश्यक छ भने, तपाईं स्तम्भहरूबाट NA मानहरू हटाउन सक्नुहुन्छ। त्यसका लागि `axis=1` प्रयोग गर्नुहोस्:\n" ] }, { @@ -1352,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "ध्यान दिनुहोस् कि यसले धेरै डाटा हटाउन सक्छ जुन तपाईंले राख्न चाहनुहुन्छ, विशेष गरी साना डेटासेटहरूमा। यदि तपाईं केवल केही वा सबै null मानहरू भएका पङ्क्ति वा स्तम्भहरू हटाउन चाहनुहुन्छ भने के गर्ने? तपाईंले `dropna` मा `how` र `thresh` प्यारामिटरहरू प्रयोग गरेर ती सेटिङहरू निर्दिष्ट गर्न सक्नुहुन्छ।\n", + "ध्यान दिनुहोस् कि यसले धेरै डाटा हटाउन सक्छ जुन तपाईं राख्न चाहनुहुन्छ, विशेष गरी साना डेटासेटहरूमा। यदि तपाईं केवल ती पङ्क्ति वा स्तम्भहरू हटाउन चाहनुहुन्छ जसमा धेरै वा सबै null मानहरू छन् भने के गर्ने? तपाईंले `dropna` मा `how` र `thresh` प्यारामिटरहरू सेट गरेर यो निर्दिष्ट गर्न सक्नुहुन्छ।\n", "\n", - "डिफल्ट रूपमा, `how='any'` हुन्छ (यदि तपाईं आफैं जाँच गर्न चाहनुहुन्छ वा यो विधिमा अरू के-के प्यारामिटरहरू छन् भनेर हेर्न चाहनुहुन्छ भने, कोड सेलमा `example4.dropna?` चलाउनुहोस्)। वैकल्पिक रूपमा, तपाईंले `how='all'` निर्दिष्ट गर्न सक्नुहुन्छ ताकि केवल ती पङ्क्ति वा स्तम्भहरू हटाउन सकियोस् जसमा सबै null मानहरू छन्। आउनुहोस्, हाम्रो उदाहरण `DataFrame` लाई विस्तार गरौं र यो कसरी काम गर्छ भन्ने कुरा अर्को अभ्यासमा हेर्छौं।\n" + "डिफल्ट रूपमा, `how='any'` हुन्छ (यदि तपाईं आफैं जाँच गर्न चाहनुहुन्छ वा यो विधिमा अन्य प्यारामिटरहरू के छन् हेर्न चाहनुहुन्छ भने, कोड सेलमा `example4.dropna?` चलाउनुहोस्)। वैकल्पिक रूपमा, तपाईं `how='all'` निर्दिष्ट गर्न सक्नुहुन्छ ताकि केवल ती पङ्क्ति वा स्तम्भहरू हटाउन सकियोस् जसमा सबै null मानहरू छन्। आउँदो अभ्यासमा यो कसरी काम गर्छ भनेर हेर्नको लागि हामी हाम्रो उदाहरण `DataFrame` विस्तार गर्नेछौं।\n" ] }, { @@ -1447,10 +1457,10 @@ }, "source": [ "> मुख्य बुँदाहरू: \n", - "1. null मानहरू हटाउनु राम्रो विचार हो, तर मात्र तब जब dataset पर्याप्त ठूलो छ। \n", - "2. यदि पंक्ति वा स्तम्भमा अधिकांश डाटा हराइरहेको छ भने, ती पूर्ण रूपमा हटाउन सकिन्छ। \n", - "3. `DataFrame.dropna(axis=)` विधिले null मानहरू हटाउन मद्दत गर्छ। `axis` तर्कले पंक्ति हटाउने हो वा स्तम्भ भन्ने जनाउँछ। \n", - "4. `how` तर्क पनि प्रयोग गर्न सकिन्छ। यो डिफल्ट रूपमा `any` मा सेट गरिएको हुन्छ। त्यसैले, यसले त्यस्ता पंक्ति/स्तम्भ मात्र हटाउँछ जसमा कुनै पनि null मानहरू हुन्छन्। यसलाई `all` मा सेट गर्न सकिन्छ, जसले गर्दा हामी त्यस्ता पंक्ति/स्तम्भ मात्र हटाउँछौं जहाँ सबै मानहरू null छन्। \n" + "1. खाली मानहरू हटाउनु राम्रो विचार हो केवल डेटा सेट पर्याप्त ठूलो भएमा। \n", + "2. पूर्ण पङ्क्ति वा स्तम्भहरू हटाउन सकिन्छ यदि तिनीहरूको अधिकांश डेटा हराएको छ भने। \n", + "3. `DataFrame.dropna(axis=)` विधिले खाली मानहरू हटाउन मद्दत गर्दछ। `axis` तर्कले पङ्क्ति हटाउने वा स्तम्भ हटाउने कुरा जनाउँछ। \n", + "4. `how` तर्क पनि प्रयोग गर्न सकिन्छ। डिफल्टमा यो `any` मा सेट गरिएको हुन्छ। त्यसैले, यो केवल ती पङ्क्ति/स्तम्भहरू हटाउँछ जसमा कुनै पनि खाली मानहरू छन्। यसलाई `all` मा सेट गर्न सकिन्छ जसले हामी केवल ती पङ्क्ति/स्तम्भहरू हटाउँछौं जहाँ सबै मानहरू खाली छन्। \n" ] }, { @@ -1458,7 +1468,9 @@ "metadata": { "id": "oXXSfQFHgRsF" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -1480,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "`thresh` प्यारामिटरले तपाईंलाई अझ सूक्ष्म नियन्त्रण दिन्छ: तपाईंले पङ्क्ति वा स्तम्भलाई कायम राख्न आवश्यक पर्ने *गैर-शून्य* मानहरूको संख्या सेट गर्नुहुन्छ:\n" + "`thresh` प्यारामिटरले तपाईंलाई सूक्ष्म नियन्त्रण दिन्छ: तपाईंले पंक्ति वा स्तम्भलाई राख्नको लागि आवश्यक *गैर-शून्य* मानहरूको संख्या सेट गर्नुहुन्छ:\n" ] }, { @@ -1554,7 +1566,9 @@ "metadata": { "id": "fmSFnzZegRsG" }, - "source": [] + "source": [ + "यहाँ, पहिलो र अन्तिम पंक्ति हटाइएको छ, किनभने तिनीहरूमा मात्र दुई गैर-शून्य मानहरू छन्।\n" + ] }, { "cell_type": "markdown", @@ -1562,11 +1576,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### नल मानहरू भर्नु\n", + "### खाली मानहरू भर्ने\n", "\n", - "कहिलेकाहीँ हराएका मानहरूलाई यस्ता मानहरूसँग भर्नु उपयुक्त हुन्छ जुन वैध हुन सक्छन्। नल मानहरू भर्ने केही प्रविधिहरू छन्। पहिलो हो डोमेन ज्ञान (डाटासेट आधारित विषयको ज्ञान) प्रयोग गरेर हराएका मानहरूको अनुमान लगाउने प्रयास गर्नु। \n", + "कहिलेकाहीँ हराएका मानहरूलाई यस्ता मानहरूद्वारा भर्नु उपयुक्त हुन्छ जुन वैध हुन सक्छ। खाली मानहरू भर्ने केही प्रविधिहरू छन्। पहिलो हो डोमेन ज्ञान (डाटासेट आधारित विषयको ज्ञान) प्रयोग गरेर हराएका मानहरूलाई कुनै प्रकारले अनुमान गर्नु।\n", "\n", - "तपाईंले `isnull` प्रयोग गरेर यो काम गर्न सक्नुहुन्छ, तर यो धेरै श्रमसाध्य हुन सक्छ, विशेष गरी यदि तपाईंले धेरै मानहरू भर्नुपर्ने छ भने। किनभने यो डाटा विज्ञानमा धेरै सामान्य कार्य हो, pandas ले `fillna` प्रदान गर्दछ, जसले `Series` वा `DataFrame` को प्रतिलिपि फिर्ता गर्छ, जहाँ हराएका मानहरू तपाईंले रोजेको मानले प्रतिस्थापन गरिएका हुन्छन्। यो व्यवहारमा कसरी काम गर्छ भनेर हेर्न अर्को उदाहरण `Series` बनाऔं।\n" + "तपाईंले `isnull` प्रयोग गरेर यो काम गर्न सक्नुहुन्छ, तर यो धेरै श्रमसाध्य हुन सक्छ, विशेष गरी यदि तपाईंले धेरै मानहरू भर्नुपर्ने छ भने। किनकि यो डाटा विज्ञानमा धेरै सामान्य कार्य हो, pandas ले `fillna` प्रदान गर्दछ, जसले `Series` वा `DataFrame` को प्रतिलिपि फर्काउँछ जहाँ हराएका मानहरू तपाईंले रोजेको मानले प्रतिस्थापन गरिएका हुन्छन्। यसलाई व्यवहारमा कसरी काम गर्छ भनेर हेर्न अर्को उदाहरण `Series` सिर्जना गरौं।\n" ] }, { @@ -1578,7 +1592,7 @@ "### श्रेणीगत डेटा (गैर-संख्यात्मक)\n", "पहिले गैर-संख्यात्मक डेटा विचार गरौं। डेटासेटहरूमा, हामीसँग श्रेणीगत डेटा भएका स्तम्भहरू हुन्छन्। जस्तै, लिङ्ग, सत्य वा असत्य आदि।\n", "\n", - "यस्ता धेरै अवस्थामा, हामी हराएका मानहरूलाई स्तम्भको `mode` द्वारा प्रतिस्थापन गर्छौं। मानौं, हामीसँग १०० डेटा बिन्दुहरू छन् र ९० ले सत्य भनेका छन्, ८ ले असत्य भनेका छन् र २ ले भरेका छैनन्। त्यसो भए, हामी ती २ लाई सत्यले भरिदिन सक्छौं, सम्पूर्ण स्तम्भलाई विचार गर्दै।\n", + "यस्ता धेरै अवस्थामा, हामी हराएका मानहरूलाई स्तम्भको `mode` (सबभन्दा धेरै दोहोरिएको मान) द्वारा प्रतिस्थापन गर्छौं। मानौं, हामीसँग १०० डेटा बिन्दुहरू छन् र ९० जनाले सत्य भनेका छन्, ८ जनाले असत्य भनेका छन् र २ जनाले भरेका छैनन्। त्यस अवस्थामा, हामी ती २ लाई सत्यले भरिदिन सक्छौं, सम्पूर्ण स्तम्भलाई विचार गर्दै।\n", "\n", "फेरि, यहाँ हामी डोमेन ज्ञान प्रयोग गर्न सक्छौं। अब, `mode` द्वारा भरिदिने उदाहरणलाई विचार गरौं।\n" ] @@ -1685,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "अब, पहिलोमा मोड पत्ता लगाऔं त्यसपछि `None` मानलाई मोडले भरौं।\n" + ] }, { "cell_type": "code", @@ -1720,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "त्यसैले, हामी None लाई True संग बदल्नेछौं\n" + ] }, { "cell_type": "code", @@ -1829,7 +1847,9 @@ "metadata": { "id": "SktitLxxOR16" }, - "source": [] + "source": [ + "जस्तो कि हामी देख्न सक्छौं, null मानलाई प्रतिस्थापन गरिएको छ। भन्नु नपर्ने कुरा हो, हामीले `'True'` को सट्टामा केही पनि लेख्न सक्थ्यौं र यो प्रतिस्थापित हुने थियो।\n" + ] }, { "cell_type": "markdown", @@ -1838,16 +1858,16 @@ }, "source": [ "### संख्यात्मक डेटा\n", - "अब, संख्यात्मक डेटा तर्फ जाऔं। यहाँ, हराएको मानहरूलाई प्रतिस्थापन गर्ने दुई सामान्य तरिका छन्:\n", + "अब, संख्यात्मक डेटाको कुरा गरौं। यहाँ, हराएको मानहरूलाई प्रतिस्थापन गर्ने दुई सामान्य तरिका छन्:\n", "\n", "1. पंक्तिको माध्यक (Median) प्रयोग गरेर प्रतिस्थापन गर्नुहोस् \n", "2. पंक्तिको औसत (Mean) प्रयोग गरेर प्रतिस्थापन गर्नुहोस् \n", "\n", "यदि डेटा असमान छ र बाहिरका मानहरू (outliers) छन् भने, हामी माध्यक प्रयोग गरेर प्रतिस्थापन गर्छौं। यसको कारण, माध्यक बाहिरका मानहरू प्रति संवेदनशील हुँदैन।\n", "\n", - "जब डेटा सामान्यीकृत (normalized) हुन्छ, हामी औसत प्रयोग गर्न सक्छौं, किनकि त्यस अवस्थामा औसत र माध्यक एक-अर्कासँग नजिक हुन्छन्।\n", + "जब डेटा सामान्यीकृत (normalized) हुन्छ, हामी औसत प्रयोग गर्न सक्छौं, किनकि त्यस अवस्थामा औसत र माध्यक एकदमै नजिक हुनेछन्।\n", "\n", - "पहिला, एउटा स्तम्भ लिऔं जुन सामान्य वितरणमा छ, र त्यस स्तम्भको हराएको मानलाई औसत प्रयोग गरेर भर्नुहोस्।\n" + "पहिला, हामी एउटा स्तम्भ लिऔं जुन सामान्य रूपमा वितरण गरिएको छ र त्यस स्तम्भको हराएको मानलाई औसत प्रयोग गरेर भर्ने प्रयास गरौं।\n" ] }, { @@ -1987,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "माध्यमसँग भरिरहेको।\n" + ] }, { "cell_type": "code", @@ -2086,7 +2108,9 @@ "metadata": { "id": "CwpVFCrPTC5z" }, - "source": [] + "source": [ + "जस्तो कि हामी देख्न सक्छौं, हराएको मानलाई यसको औसतले प्रतिस्थापन गरिएको छ।\n" + ] }, { "cell_type": "markdown", @@ -2094,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "अब हामी अर्को डाटाफ्रेम प्रयास गरौं, र यस पटक हामी None मानहरूलाई स्तम्भको माध्यिका संग प्रतिस्थापन गर्नेछौं।\n" + "अब हामी अर्को डेटा फ्रेम प्रयास गरौं, र यस पटक हामी None मानहरूलाई स्तम्भको माध्यिका संग प्रतिस्थापन गर्नेछौं।\n" ] }, { @@ -2234,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "मध्य मानले भरिरहेको।\n" + ] }, { "cell_type": "code", @@ -2334,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "जसरी हामी देख्न सक्छौं, NaN मानलाई स्तम्भको माध्यिका द्वारा प्रतिस्थापन गरिएको छ\n" + "जस्तो कि हामी देख्न सक्छौं, NaN मानलाई स्तम्भको माध्यिका द्वारा प्रतिस्थापन गरिएको छ।\n" ] }, { @@ -2376,7 +2402,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "तपाईंले सबै खाली प्रविष्टिहरूलाई `0` जस्तो एकल मानले भर्न सक्नुहुन्छ:\n" + "तपाईंले सबै खाली प्रविष्टिहरूलाई एउटा मात्र मान, जस्तै `0` ले भर्न सक्नुहुन्छ:\n" ] }, { @@ -2418,10 +2444,10 @@ }, "source": [ "> मुख्य बुँदाहरू:\n", - "1. हराएका मानहरू भर्नु तब मात्र गर्नुपर्छ जब डाटा कम छ वा हराएको डाटा भर्ने कुनै रणनीति छ। \n", - "2. डोमेन ज्ञानको प्रयोग गरेर हराएका मानहरूलाई अनुमान गरेर भर्न सकिन्छ। \n", - "3. श्रेणीगत (Categorical) डाटाका लागि, प्रायः हराएका मानहरू स्तम्भको मोड (mode) ले प्रतिस्थापन गरिन्छ। \n", - "4. संख्यात्मक (Numeric) डाटाका लागि, हराएका मानहरू सामान्यतया स्तम्भहरूको औसत (normalized datasets का लागि) वा माध्यिका (median) ले भर्ने गरिन्छ। \n" + "1. हराएका मानहरू भर्ने काम तब मात्र गर्नुपर्छ जब डाटा कम छ वा हराएका डाटा भर्ने कुनै रणनीति छ। \n", + "2. डोमेन ज्ञान प्रयोग गरेर हराएका मानहरूलाई अनुमान गरेर भर्न सकिन्छ। \n", + "3. श्रेणीगत डाटाका लागि प्रायः हराएका मानहरू स्तम्भको मोडले प्रतिस्थापन गरिन्छ। \n", + "4. संख्यात्मक डाटाका लागि, हराएका मानहरू सामान्यत: औसत (सामान्यीकृत डाटासेटहरूका लागि) वा स्तम्भहरूको माध्यकले भर्ने गरिन्छ। \n" ] }, { @@ -2429,7 +2455,9 @@ "metadata": { "id": "FI9MmqFJgRsH" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -2449,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "तपाईंले शून्य मानहरूलाई **फर्वार्ड-फिल** गर्न सक्नुहुन्छ, जसले अन्तिम मान्य मानलाई शून्य भर्न प्रयोग गर्दछ:\n" + ] }, { "cell_type": "code", @@ -2489,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "तपाईंले अर्को मान्य मानलाई पछाडि फैलाउनको लागि **पछाडि भर्नुहोस्** गर्न सक्नुहुन्छ ताकि खाली ठाउँ भर्न सकियोस्:\n" + "तपाईंले पनि **पछाडि-भर्न** गर्न सक्नुहुन्छ ताकि अर्को मान्य मानलाई पछाडि फैलाएर खाली स्थान भर्न सकिन्छ:\n" ] }, { @@ -2531,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "जसरी तपाईंले अनुमान गर्न सक्नुहुन्छ, यो DataFrames सँग पनि उस्तै काम गर्छ, तर तपाईंले null मानहरू भर्नको लागि `axis` पनि निर्दिष्ट गर्न सक्नुहुन्छ:\n" + "जस्तो तपाईंले अनुमान गर्न सक्नुहुन्छ, यो DataFrames सँग पनि उस्तै काम गर्दछ, तर तपाईंले null मानहरू भर गर्नको लागि `axis` पनि निर्दिष्ट गर्न सक्नुहुन्छ:\n" ] }, { @@ -2703,14 +2733,18 @@ "metadata": { "id": "ZeMc-I1EgRsI" }, - "source": [] + "source": [ + "ध्यान दिनुहोस् कि जब अगाडिको-भराइको लागि अघिल्लो मान उपलब्ध छैन, खाली मान यथावत रहन्छ।\n" + ] }, { "cell_type": "markdown", "metadata": { "id": "eeAoOU0RgRsJ" }, - "source": [] + "source": [ + "### व्यायाम:\n" + ] }, { "cell_type": "code", @@ -2733,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "तपाईंले `fillna` प्रयोग गर्ने तरिकामा सिर्जनात्मक हुन सक्नुहुन्छ। उदाहरणका लागि, फेरि `example4` लाई हेरौं, तर यस पटक `DataFrame` मा भएका सबै मानहरूको औसतले हराएका मानहरू भर्न प्रयास गरौं:\n" + "तपाईं `fillna` प्रयोग गर्ने तरिकामा सिर्जनशील हुन सक्नुहुन्छ। उदाहरणका लागि, फेरि `example4` हेर्नुहोस्, तर यस पटक `DataFrame` मा रहेका सबै मानहरूको औसतले हराएका मानहरू भर्न प्रयास गरौं:\n" ] }, { @@ -2824,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "ध्यान दिनुहोस् कि स्तम्भ ३ अझै खाली छ: डिफल्ट दिशा पङ्क्ति अनुसार मानहरू भर्नु हो।\n", + "ध्यान दिनुहोस् कि स्तम्भ ३ अझै पनि खाली छ: डिफल्ट दिशा पङ्क्ति अनुसार मानहरू भर्ने हो।\n", "\n", - "> **मुख्य कुरा:** तपाईंसँगको डाटासेटमा हराइरहेका मानहरूलाई व्यवस्थापन गर्न धेरै तरिकाहरू छन्। तपाईले कुन विशेष रणनीति प्रयोग गर्नुहुन्छ (तिनीहरूलाई हटाउने, प्रतिस्थापन गर्ने, वा कसरी प्रतिस्थापन गर्ने) त्यो डाटाको विशेषताहरूले निर्धारण गर्नुपर्छ। जति धेरै तपाई डाटासेटहरूलाई व्यवस्थापन र अन्तरक्रिया गर्नुहुन्छ, हराइरहेका मानहरूलाई कसरी व्यवस्थापन गर्ने भन्ने राम्रो ज्ञान विकास हुनेछ।\n" + "> **मुख्य कुरा:** तपाईंको डाटासेटमा हराएका मानहरूलाई व्यवस्थापन गर्न धेरै तरिकाहरू छन्। तपाईंले प्रयोग गर्ने विशेष रणनीति (तिनीहरू हटाउने, तिनीहरूलाई प्रतिस्थापन गर्ने, वा कसरी प्रतिस्थापन गर्ने) उक्त डाटाको विशेषताहरूले निर्धारण गर्नुपर्छ। तपाईंले जति धेरै डाटासेटहरूलाई व्यवस्थापन र अन्तरक्रिया गर्नुहुन्छ, हराएका मानहरूलाई कसरी व्यवस्थापन गर्ने भन्ने राम्रो ज्ञान विकास हुनेछ।\n" ] }, { @@ -2835,11 +2869,11 @@ "id": "bauDnESIl9FH" }, "source": [ - "### श्रेणीगत डाटा एनकोडिङ\n", + "### श्रेणीगत डाटा को एन्कोडिङ\n", "\n", - "मेसिन लर्निङ मोडेलहरूले मात्र संख्यात्मक डाटासँग काम गर्छन्। यसले \"हो\" र \"होइन\" बीचको भिन्नता बुझ्न सक्दैन, तर यसले 0 र 1 बीचको भिन्नता छुट्याउन सक्छ। त्यसैले, हराएका मानहरू भरेपछि, मोडेलले बुझ्न सक्ने संख्यात्मक रूपमा श्रेणीगत डाटालाई एनकोड गर्न आवश्यक छ।\n", + "मेसिन लर्निङ मोडेलहरूले मात्र संख्यात्मक डाटासँग काम गर्छन्। यसले \"हो\" र \"होइन\" बीचको भिन्नता बुझ्न सक्दैन, तर यसले 0 र 1 बीचको भिन्नता छुट्याउन सक्छ। त्यसैले, हराएका मानहरू भरेपछि, मोडेलले बुझ्न सक्ने संख्यात्मक रूपमा श्रेणीगत डाटालाई एन्कोड गर्न आवश्यक छ।\n", "\n", - "एनकोडिङ दुई तरिकाले गर्न सकिन्छ। हामी अगाडि ती तरिकाहरूको चर्चा गर्नेछौं।\n" + "एन्कोडिङ दुई तरिकामा गर्न सकिन्छ। हामी अब ती तरिकाहरूको चर्चा गर्नेछौं।\n" ] }, { @@ -2848,9 +2882,9 @@ "id": "uDq9SxB7mu5i" }, "source": [ - "**लेबल इनकोडिङ**\n", + "**लेबल एनकोडिङ**\n", "\n", - "लेबल इनकोडिङ भनेको प्रत्येक श्रेणीलाई एउटा नम्बरमा परिवर्तन गर्ने प्रक्रिया हो। उदाहरणका लागि, मानौं हामीसँग एयरलाइन यात्रुहरूको डाटासेट छ र त्यहाँ एउटा स्तम्भ छ जसमा उनीहरूको वर्ग ['बिजनेस क्लास', 'इकोनोमी क्लास', 'फर्स्ट क्लास'] मध्ये एक छ। यदि यसमा लेबल इनकोडिङ गरिन्छ भने, यो [0,1,2] मा परिवर्तन हुनेछ। अब हामी कोडको माध्यमबाट एउटा उदाहरण हेर्नेछौं। किनकि हामी आगामी नोटबुकहरूमा `scikit-learn` सिक्दैछौं, हामी यसलाई यहाँ प्रयोग गर्नेछैनौं।\n" + "लेबल एनकोडिङ भनेको प्रत्येक श्रेणीलाई एउटा नम्बरमा परिवर्तन गर्नु हो। उदाहरणका लागि, मानौं हामीसँग एयरलाइन यात्रुहरूको डाटासेट छ र त्यहाँ एउटा स्तम्भ छ जसमा उनीहरूको वर्ग ['बिजनेस क्लास', 'इकोनोमी क्लास', 'फर्स्ट क्लास'] मध्ये छ। यदि यसमा लेबल एनकोडिङ गरिन्छ भने, यो [0,1,2] मा परिवर्तन हुनेछ। अब हामी कोडको माध्यमबाट एउटा उदाहरण हेर्छौं। किनकि हामी आगामी नोटबुकहरूमा `scikit-learn` सिक्दैछौं, हामी यसलाई यहाँ प्रयोग गर्नेछैनौं।\n" ] }, { @@ -2958,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "पहिलो स्तम्भमा लेबल इन्कोडिङ गर्न, प्रत्येक वर्गलाई एउटा नम्बरमा म्याप गर्ने विवरण दिनुपर्छ, त्यसपछि प्रतिस्थापन गर्नु अघि।\n" + "पहिलो स्तम्भमा लेबल इन्कोडिङ गर्न, प्रत्येक वर्गलाई नम्बरमा म्यापिङ गर्ने विवरण दिनुपर्छ, त्यसपछि प्रतिस्थापन गर्नुपर्छ।\n" ] }, { @@ -3060,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "जसरी हामीले देख्यौं, नतिजा हाम्रो अपेक्षासँग मेल खान्छ। त्यसोभए, हामीले लेबल इन्कोडिङ कहिले प्रयोग गर्ने? लेबल इन्कोडिङ निम्नमध्ये कुनै एक वा दुबै अवस्थामा प्रयोग गरिन्छ: \n", - "1. जब श्रेणीहरूको संख्या धेरै हुन्छ \n", - "2. जब श्रेणीहरू क्रमबद्ध हुन्छन्। \n" + "जस्तो कि हामीले देख्न सक्छौं, नतिजा हाम्रो अपेक्षासँग मेल खान्छ। त्यसो भए, लेबल इन्कोडिङ कहिले प्रयोग गर्ने? लेबल इन्कोडिङ निम्नमध्ये कुनै एक वा दुवै अवस्थामा प्रयोग गरिन्छ:\n", + "1. जब श्रेणीहरूको संख्या धेरै हुन्छ\n", + "2. जब श्रेणीहरू क्रमबद्ध हुन्छन्।\n" ] }, { @@ -3071,11 +3105,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**वन हट इन्कोडिङ**\n", + "**वन हट इनकोडिङ**\n", "\n", - "अर्को प्रकारको इन्कोडिङ वन हट इन्कोडिङ हो। यस प्रकारको इन्कोडिङमा, स्तम्भका प्रत्येक श्रेणीहरूलाई छुट्टाछुट्टै स्तम्भको रूपमा थपिन्छ, र प्रत्येक डाटापोइन्टले 0 वा 1 पाउँछ, यो निर्भर गर्दछ कि त्यसमा त्यो श्रेणी समावेश छ कि छैन। त्यसैले, यदि n फरक श्रेणीहरू छन् भने, n स्तम्भहरू डाटाफ्रेममा थपिन्छन्।\n", + "अर्को प्रकारको इनकोडिङ वन हट इनकोडिङ हो। यस प्रकारको इनकोडिङमा, स्तम्भको प्रत्येक श्रेणीलाई छुट्टै स्तम्भको रूपमा थपिन्छ र प्रत्येक डाटापोइन्टले ० वा १ प्राप्त गर्दछ, यो श्रेणी समावेश छ कि छैन भन्ने आधारमा। त्यसैले, यदि n विभिन्न श्रेणीहरू छन् भने, n स्तम्भहरू डाटाफ्रेममा थपिनेछन्।\n", "\n", - "उदाहरणका लागि, हामी उही हवाईजहाजको श्रेणीको उदाहरण लिऔं। श्रेणीहरू थिए: ['business class', 'economy class', 'first class']। त्यसैले, यदि हामी वन हट इन्कोडिङ गर्छौं भने, निम्न तीन स्तम्भहरू डाटासेटमा थपिनेछन्: ['class_business class', 'class_economy class', 'class_first class']।\n" + "उदाहरणका लागि, उही विमानको श्रेणीको उदाहरण लिऔं। श्रेणीहरू थिए: ['बिजनेस क्लास', 'इकोनोमी क्लास', 'फर्स्ट क्लास']। त्यसैले, यदि हामी वन हट इनकोडिङ गर्छौं भने, निम्न तीन स्तम्भहरू डेटासेटमा थपिनेछन्: ['class_business class', 'class_economy class', 'class_first class']।\n" ] }, { @@ -3183,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "पहिलो स्तम्भमा वन हट इनकोडिङ गरौं\n" + "हामी पहिलो स्तम्भमा वन हट इनकोडिङ गर्नेछौं।\n" ] }, { @@ -3308,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "प्रत्येक वन-हट एन्कोड गरिएको स्तम्भमा 0 वा 1 हुन्छ, जसले सो डाटापोइन्टका लागि त्यो श्रेणी अस्तित्वमा छ कि छैन भनेर निर्दिष्ट गर्दछ।\n" + "प्रत्येक वन हट एन्कोड गरिएको स्तम्भमा 0 वा 1 हुन्छ, जसले सो डाटापोइन्टको लागि त्यो श्रेणी रहेको छ कि छैन भन्ने निर्दिष्ट गर्दछ।\n" ] }, { @@ -3317,10 +3351,10 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "हामीले वन हट इनकोडिङ कहिले प्रयोग गर्ने? वन हट इनकोडिङ निम्नमध्ये कुनै एक वा दुबै अवस्थामा प्रयोग गरिन्छ :\n", + "हामी कहिले वन हट इनकोडिङ प्रयोग गर्छौं? वन हट इनकोडिङ निम्नमध्ये कुनै एक वा दुवै अवस्थामा प्रयोग गरिन्छ :\n", "\n", - "1. जब श्रेणीहरूको संख्या र डाटासेटको आकार सानो हुन्छ।\n", - "2. जब श्रेणीहरूले कुनै विशेष क्रम पालना गर्दैनन्।\n" + "1. जब श्रेणीहरूको संख्या र डेटासेटको आकार सानो हुन्छ।\n", + "2. जब श्रेणीहरूले कुनै विशेष क्रम अनुसरण गर्दैनन्।\n" ] }, { @@ -3329,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> मुख्य बुँदाहरू: \n", - "1. एनकोडिङ गैर-संख्यात्मक डाटालाई संख्यात्मक डाटामा रूपान्तरण गर्न गरिन्छ। \n", - "2. एनकोडिङका दुई प्रकारहरू छन्: लेबल एनकोडिङ र वन हट एनकोडिङ, जसलाई डाटासेटको आवश्यकताका आधारमा प्रयोग गर्न सकिन्छ। \n" + "> मुख्य बुँदाहरू:\n", + "1. एनकोडिङ गैर-संख्यात्मक डाटालाई संख्यात्मक डाटामा रूपान्तरण गर्न गरिन्छ।\n", + "2. एनकोडिङका दुई प्रकार छन्: लेबल एनकोडिङ र वन हट एनकोडिङ, जसलाई डाटासेटको आवश्यकताका आधारमा प्रयोग गर्न सकिन्छ।\n" ] }, { @@ -3340,11 +3374,11 @@ "id": "K8UXOJYRgRsJ" }, "source": [ - "## नक्कल डेटा हटाउने\n", + "## डुप्लिकेट डेटा हटाउने\n", "\n", - "> **अध्ययनको लक्ष्य:** यस उपविभागको अन्त्यसम्ममा, तपाईं DataFrames बाट नक्कल मानहरू पहिचान गर्न र हटाउन सहज हुनुहुनेछ।\n", + "> **अध्ययनको लक्ष्य:** यस उपविभागको अन्त्यसम्ममा, तपाईं DataFrames बाट डुप्लिकेट मानहरू पहिचान गर्न र हटाउन सहज हुनुहुनेछ।\n", "\n", - "हराएको डेटाका अतिरिक्त, तपाईं वास्तविक संसारका डेटासेटहरूमा प्रायः नक्कल डेटा भेट्टाउनुहुनेछ। सौभाग्यवश, pandas ले नक्कल प्रविष्टिहरू पत्ता लगाउन र हटाउन सजिलो उपाय प्रदान गर्दछ।\n" + "हराएको डेटाको अतिरिक्त, तपाईं वास्तविक-विश्वको डेटासेटहरूमा प्रायः डुप्लिकेट डेटा भेट्नुहुनेछ। सौभाग्यवश, pandas ले डुप्लिकेट प्रविष्टिहरू पत्ता लगाउन र हटाउन सजिलो उपाय प्रदान गर्दछ।\n" ] }, { @@ -3355,7 +3389,7 @@ "source": [ "### डुप्लिकेटहरू पहिचान गर्ने: `duplicated`\n", "\n", - "तपाईंले pandas को `duplicated` विधि प्रयोग गरेर सजिलै डुप्लिकेट मानहरू पत्ता लगाउन सक्नुहुन्छ, जसले `DataFrame` मा कुनै इन्ट्री पहिलेको इन्ट्रीको डुप्लिकेट हो कि होइन भनेर जनाउने Boolean मास्क फिर्ता गर्छ। यसलाई व्यवहारमा हेर्नको लागि अर्को उदाहरण `DataFrame` बनाउँ।\n" + "तपाईंले pandas को `duplicated` विधि प्रयोग गरेर सजिलै डुप्लिकेट मानहरू पत्ता लगाउन सक्नुहुन्छ, जसले Boolean मास्क फर्काउँछ जसले देखाउँछ कि `DataFrame` मा कुनै प्रविष्टि पहिलेको प्रविष्टिको डुप्लिकेट हो कि होइन। यसलाई व्यवहारमा देख्नको लागि अर्को उदाहरण `DataFrame` बनाउँ।\n" ] }, { @@ -3484,8 +3518,8 @@ "id": "0eDRJD4SgRsK" }, "source": [ - "### डुप्लिकेटहरू हटाउँदै: `drop_duplicates`\n", - "`drop_duplicates` ले केवल ती डाटाको प्रतिलिपि फिर्ता गर्छ जसका लागि सबै `duplicated` मानहरू `False` हुन्छन्:\n" + "### डुप्लिकेट हटाउने: `drop_duplicates`\n", + "`drop_duplicates` ले केवल ती डाटाको प्रतिलिपि फर्काउँछ जसका लागि सबै `duplicated` मानहरू `False` छन्:\n" ] }, { @@ -3644,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **मुख्य कुरा:** नक्कल डेटा हटाउनु लगभग प्रत्येक डेटा-विज्ञान परियोजनाको महत्वपूर्ण भाग हो। नक्कल डेटा तपाईंको विश्लेषणको परिणाम परिवर्तन गर्न सक्छ र तपाईंलाई गलत परिणाम दिन सक्छ!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## वास्तविक-विश्व डेटा गुणस्तर जाँच\n", + "\n", + "> **शिक्षण लक्ष्य:** यस खण्डको अन्त्यसम्ममा, तपाईं असंगत श्रेणीगत मानहरू, असामान्य संख्यात्मक मानहरू (अत्यधिक मानहरू), र भिन्नतासहितको दोहोरिएका इकाइहरू पत्ता लगाउन र सुधार गर्न सहज हुनुहुनेछ।\n", + "\n", + "यद्यपि हराएका मानहरू र ठ्याक्कै दोहोरिएका डेटा सामान्य समस्या हुन्, वास्तविक-विश्व डेटासेटहरूमा प्रायः थप सूक्ष्म समस्याहरू हुन्छन्:\n", + "\n", + "1. **असंगत श्रेणीगत मानहरू**: एउटै श्रेणी फरक-फरक तरिकाले लेखिएको (जस्तै, \"USA\", \"U.S.A\", \"United States\")\n", + "2. **असामान्य संख्यात्मक मानहरू**: डेटा प्रविष्टि त्रुटिहरूलाई जनाउने अत्यधिक मानहरू (जस्तै, उमेर = 999)\n", + "3. **निकट-दोहोरिएका पङ्क्तिहरू**: थोरै भिन्नतासहित एउटै इकाइलाई प्रतिनिधित्व गर्ने रेकर्डहरू\n", + "\n", + "यी समस्याहरू पत्ता लगाउन र समाधान गर्नका लागि प्रविधिहरू अन्वेषण गरौं।\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### \"फोहोर\" डाटासेट सिर्जना गर्दै\n", + "\n", + "पहिले, एउटा नमूना डाटासेट सिर्जना गरौं जसमा हामीले वास्तविक संसारको डाटामा सामान्यत: सामना गर्ने समस्याहरू समावेश छन्:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### १. असंगत श्रेणीगत मानहरू पत्ता लगाउने\n", + "\n", + "`country` स्तम्भमा एउटै देशको लागि विभिन्न प्रतिनिधित्वहरू छन्। आउनुहोस् यी असंगतताहरू पहिचान गरौं:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### श्रेणीगत मानहरूलाई मानकीकरण गर्दै\n", + "\n", + "हामी यी मानहरूलाई मानकीकरण गर्न एक म्यापिङ बनाउन सक्छौं। एउटा सरल तरिका भनेको तिनीहरूलाई सानो अक्षरमा परिवर्तन गर्नु र म्यापिङ डिक्सनरी बनाउनु हो:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**वैकल्पिक: फजी म्याचिङ प्रयोग गर्दै**\n", + "\n", + "अझ जटिल अवस्थामा, हामी `rapidfuzz` लाइब्रेरी प्रयोग गरेर फजी स्ट्रिङ म्याचिङको माध्यमबाट समान स्ट्रिङहरू स्वतः पत्ता लगाउन सक्छौं:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. असामान्य संख्यात्मक मानहरू (आउटलायर्स) पत्ता लगाउने\n", + "\n", + "`age` स्तम्भलाई हेर्दा, हामीसँग १९९ र -५ जस्ता शंकास्पद मानहरू छन्। आउटलायर्स पत्ता लगाउन सांख्यिकीय विधिहरू प्रयोग गरौं।\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### IQR (इन्टरक्वार्टाइल रेन्ज) विधि प्रयोग गर्दै\n", + "\n", + "IQR विधि एक बलियो सांख्यिकीय प्रविधि हो जुन बाहिरिने मानहरू पत्ता लगाउन प्रयोग गरिन्छ र यो अत्यधिक मानहरू प्रति कम संवेदनशील हुन्छ:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Z-स्कोर विधि प्रयोग गर्दै\n", + "\n", + "Z-स्कोर विधिले औसतबाट मानक विचलनको आधारमा बाहिरिएका मानहरू पहिचान गर्दछ:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### बाहिरिएका डाटा (आउटलायर्स) को व्यवस्थापन\n", + "\n", + "पत्ता लागेपछि, बाहिरिएका डाटालाई विभिन्न तरिकाले व्यवस्थापन गर्न सकिन्छ:\n", + "1. **हटाउनुहोस्**: बाहिरिएका डाटासहितका पङ्क्तिहरू हटाउनुहोस् (यदि ती त्रुटिहरू हुन् भने)\n", + "2. **सीमा तोक्नुहोस्**: सीमा मानहरूद्वारा प्रतिस्थापन गर्नुहोस्\n", + "3. **NaN द्वारा प्रतिस्थापन गर्नुहोस्**: हराएको डाटा रूपमा व्यवहार गर्नुहोस् र इम्पुटेसन प्रविधिहरू प्रयोग गर्नुहोस्\n", + "4. **राख्नुहोस्**: यदि ती वैध अत्यधिक मानहरू हुन् भने\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ३. नजिकका नक्कल पङ्क्तिहरू पत्ता लगाउँदै\n", + "\n", + "ध्यान दिनुहोस् कि हाम्रो डेटासेटमा \"John Smith\" का लागि थोरै फरक मानहरू सहित धेरै प्रविष्टिहरू छन्। नामको समानताका आधारमा सम्भावित नक्कलहरू पहिचान गरौं।\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### फजी म्याचिङको प्रयोग गरेर नजिकका डुप्लिकेटहरू पत्ता लगाउने\n", + "\n", + "अधिक परिष्कृत डुप्लिकेट पहिचानको लागि, हामी फजी म्याचिङ प्रयोग गरेर मिल्दोजुल्दो नामहरू पत्ता लगाउन सक्छौं:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### डुप्लिकेटहरूलाई व्यवस्थापन गर्ने\n", + "\n", + "पहिचान गरेपछि, डुप्लिकेटहरूलाई कसरी व्यवस्थापन गर्ने भन्ने निर्णय गर्नुपर्छ:\n", + "1. **पहिलो पटकको उपस्थितिलाई राख्ने**: `drop_duplicates(keep='first')` प्रयोग गर्नुहोस्\n", + "2. **अन्तिम उपस्थितिलाई राख्ने**: `drop_duplicates(keep='last')` प्रयोग गर्नुहोस्\n", + "3. **जानकारीलाई समग्र बनाउने**: डुप्लिकेट पंक्तिहरूबाट जानकारीलाई संयोजन गर्नुहोस्\n", + "4. **म्यानुअल समीक्षा**: मानव समीक्षा गर्नको लागि झण्डा लगाउनुहोस्\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### सारांश: पूर्ण डेटा सफाई पाइपलाइन\n", + "\n", + "अब सबैलाई एकसाथ राखेर एक व्यापक सफाई पाइपलाइन बनाउँ।\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 चुनौती अभ्यास\n", + "\n", + "अब तपाईंको पालो! तलको नयाँ पङ्क्तिमा धेरै गुणस्तर समस्याहरू छन्। के तपाईं:\n", + "\n", + "1. यस पङ्क्तिमा भएका सबै समस्याहरू पहिचान गर्न सक्नुहुन्छ\n", + "2. प्रत्येक समस्यालाई सफा गर्न कोड लेख्न सक्नुहुन्छ\n", + "3. सफा गरिएको पङ्क्तिलाई डेटासेटमा थप्न सक्नुहुन्छ\n", + "\n", + "यहाँ समस्याग्रस्त डेटा छ:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### मुख्य बुँदाहरू\n", + "\n", + "1. **असंगत श्रेणीहरू** वास्तविक संसारको डाटामा सामान्य हुन्छन्। सधैं अनौठो मानहरू जाँच गर्नुहोस् र तिनीहरूलाई म्यापिङ वा फजी म्याचिङ प्रयोग गरेर मानकीकरण गर्नुहोस्।\n", + "\n", + "2. **आउटलायर्स**ले तपाईंको विश्लेषणमा ठूलो प्रभाव पार्न सक्छ। तिनीहरू पत्ता लगाउन डोमेन ज्ञानलाई सांख्यिकीय विधिहरू (IQR, Z-score) सँग मिलाएर प्रयोग गर्नुहोस्।\n", + "\n", + "3. **नजिकका डुप्लिकेटहरू** ठ्याक्कै मिल्ने डुप्लिकेटहरूभन्दा पत्ता लगाउन गाह्रो हुन्छ। तिनीहरूलाई पहिचान गर्न फजी म्याचिङ र डाटा सामान्यीकरण (लोअरकेसिङ, ह्वाइटस्पेस हटाउने) विचार गर्नुहोस्।\n", + "\n", + "4. **डाटा सफा गर्ने प्रक्रिया दोहोरिने हुन्छ।** तपाईंले धेरै प्रविधिहरू लागू गर्न र अन्तिम सफा गरिएको डाटासेट तयार गर्नु अघि नतिजाहरू समीक्षा गर्न आवश्यक हुन सक्छ।\n", + "\n", + "5. **आफ्नो निर्णयहरू दस्तावेज गर्नुहोस्।** तपाईंले कुन सफा गर्ने चरणहरू लागू गर्नुभयो र किन, त्यसलाई ट्र्याक गर्नुहोस् किनभने यो पुनरुत्पादनशीलता र पारदर्शिताका लागि महत्त्वपूर्ण छ।\n", + "\n", + "> **सर्वोत्तम अभ्यास:** सधैं आफ्नो मूल \"फोहोर\" डाटाको प्रतिलिपि राख्नुहोस्। कहिल्यै आफ्नो स्रोत डाटा फाइलहरू ओभरराइट नगर्नुहोस् - `data_cleaned.csv` जस्ता स्पष्ट नामकरण कन्वेन्सनसहित सफा गरिएको संस्करणहरू सिर्जना गर्नुहोस्।\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**अस्वीकरण**: \nयो दस्तावेज़ AI अनुवाद सेवा [Co-op Translator](https://github.com/Azure/co-op-translator) प्रयोग गरी अनुवाद गरिएको हो। हामी यथासम्भव सटीकता सुनिश्चित गर्न प्रयास गर्छौं, तर कृपया ध्यान दिनुहोस् कि स्वचालित अनुवादहरूमा त्रुटि वा अशुद्धता हुन सक्छ। यसको मूल भाषामा रहेको मूल दस्तावेज़लाई आधिकारिक स्रोत मानिनुपर्छ। महत्त्वपूर्ण जानकारीका लागि, व्यावसायिक मानव अनुवाद सिफारिस गरिन्छ। यस अनुवादको प्रयोगबाट उत्पन्न कुनै पनि गलतफहमी वा गलत व्याख्याका लागि हामी जिम्मेवार हुने छैनौं। \n" + "\n---\n\n**अस्वीकरण**: \nयो दस्तावेज [Co-op Translator](https://github.com/Azure/co-op-translator) नामक एआई अनुवाद सेवा प्रयोग गरी अनुवाद गरिएको हो। हामी यथासम्भव सही अनुवाद प्रदान गर्न प्रयास गर्छौं, तर कृपया ध्यान दिनुहोस् कि स्वचालित अनुवादमा त्रुटिहरू वा अशुद्धताहरू हुन सक्छन्। मूल भाषामा रहेको मूल दस्तावेजलाई आधिकारिक स्रोत मानिनुपर्छ। महत्वपूर्ण जानकारीका लागि, व्यावसायिक मानव अनुवाद सिफारिस गरिन्छ। यस अनुवादको प्रयोगबाट उत्पन्न हुने कुनै पनि गलतफहमी वा गलत व्याख्याका लागि हामी जिम्मेवार हुने छैनौं।\n" ] } ], @@ -3678,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:22:18+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:46:02+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "ne" } diff --git a/translations/nl/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/nl/2-Working-With-Data/08-data-preparation/notebook.ipynb index 654cb5e7..1d41f916 100644 --- a/translations/nl/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/nl/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,13 +8,13 @@ "source": [ "# Gegevensvoorbereiding\n", "\n", - "[Originele Notebook-bron uit *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio door Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Originele Notebook-bron van *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio door Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## Verkennen van `DataFrame`-informatie\n", "\n", - "> **Leerdoel:** Aan het einde van deze subsectie moet je in staat zijn om algemene informatie over de gegevens in pandas DataFrames te vinden.\n", + "> **Leerdoel:** Aan het einde van deze subsectie moet je in staat zijn om algemene informatie over de gegevens die zijn opgeslagen in pandas DataFrames te vinden.\n", "\n", - "Zodra je je gegevens in pandas hebt geladen, zullen ze hoogstwaarschijnlijk in een `DataFrame` staan. Maar als de dataset in je `DataFrame` 60.000 rijen en 400 kolommen bevat, hoe begin je dan überhaupt een idee te krijgen van waar je mee werkt? Gelukkig biedt pandas enkele handige tools om snel algemene informatie over een `DataFrame` te bekijken, naast de eerste en laatste paar rijen.\n", + "Zodra je je gegevens in pandas hebt geladen, zullen ze hoogstwaarschijnlijk in een `DataFrame` staan. Maar als de dataset in je `DataFrame` 60.000 rijen en 400 kolommen bevat, hoe begin je dan überhaupt een idee te krijgen van waar je mee werkt? Gelukkig biedt pandas enkele handige tools om snel algemene informatie over een `DataFrame` te bekijken, naast de eerste paar en laatste paar rijen.\n", "\n", "Om deze functionaliteit te verkennen, importeren we de Python scikit-learn bibliotheek en gebruiken we een iconische dataset die elke datawetenschapper honderden keren heeft gezien: de *Iris*-dataset van de Britse bioloog Ronald Fisher, gebruikt in zijn paper uit 1936 \"The use of multiple measurements in taxonomic problems\":\n" ] @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "We hebben de Iris Dataset geladen in de variabele `iris_df`. Voordat we de data verder onderzoeken, is het handig om te weten hoeveel datapunten we hebben en wat de totale omvang van de dataset is. Het is nuttig om een idee te krijgen van de hoeveelheid data waarmee we werken.\n" + "We hebben de Iris Dataset geladen in de variabele `iris_df`. Voordat we de data gaan verkennen, is het handig om te weten hoeveel datapunten we hebben en wat de totale omvang van de dataset is. Het is nuttig om een idee te krijgen van de hoeveelheid data waarmee we werken.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "We hebben te maken met 150 rijen en 4 kolommen aan gegevens. Elke rij vertegenwoordigt één datapunt en elke kolom vertegenwoordigt een enkele eigenschap die aan het data frame is gekoppeld. Kortom, er zijn 150 datapunten met elk 4 eigenschappen.\n", + "We hebben hier te maken met 150 rijen en 4 kolommen aan data. Elke rij vertegenwoordigt één datapunt en elke kolom staat voor een enkele eigenschap die bij het data frame hoort. Kortom, er zijn 150 datapunten met elk 4 eigenschappen.\n", "\n", - "`shape` is hier een attribuut van het dataframe en geen functie, wat de reden is dat het niet eindigt met een paar haakjes.\n" + "`shape` is hier een attribuut van het data frame en geen functie, daarom eindigt het niet met een paar haakjes.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Laten we nu de 4 kolommen met gegevens bekijken. Wat stelt elk van deze kolommen precies voor? Het attribuut `columns` geeft ons de namen van de kolommen in de dataframe.\n" + "Laten we nu de 4 kolommen van gegevens bekijken. Wat vertegenwoordigt elk van hen precies? De `columns`-eigenschap geeft ons de namen van de kolommen in de dataframe.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Zoals we kunnen zien, zijn er vier (4) kolommen. De `columns`-attribuut vertelt ons de namen van de kolommen en verder eigenlijk niets. Dit attribuut wordt belangrijk wanneer we de kenmerken van een dataset willen identificeren.\n" + "Zoals we kunnen zien, zijn er vier(4) kolommen. Het `columns`-attribuut vertelt ons de namen van de kolommen en verder eigenlijk niets. Dit attribuut wordt belangrijk wanneer we de kenmerken van een dataset willen identificeren.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "De hoeveelheid data (gegeven door het `shape` attribuut) en de namen van de kenmerken of kolommen (gegeven door het `columns` attribuut) vertellen ons iets over de dataset. Nu willen we dieper in de dataset duiken. De functie `DataFrame.info()` is hier erg handig voor.\n" + "De hoeveelheid data (gegeven door het attribuut `shape`) en de namen van de kenmerken of kolommen (gegeven door het attribuut `columns`) vertellen ons iets over de dataset. Nu willen we dieper in de dataset duiken. De functie `DataFrame.info()` is hier erg handig voor.\n" ] }, { @@ -181,8 +181,8 @@ }, "source": [ "Van hieruit kunnen we een paar observaties maken:\n", - "1. Het datatype van elke kolom: In deze dataset worden alle gegevens opgeslagen als 64-bit drijvende-komma getallen.\n", - "2. Aantal niet-nul waarden: Het omgaan met null-waarden is een belangrijke stap in de voorbereiding van gegevens. Dit zal later in het notebook worden behandeld.\n" + "1. Het datatype van elke kolom: In deze dataset worden alle gegevens opgeslagen als 64-bit floating-point getallen.\n", + "2. Aantal niet-nulwaarden: Het omgaan met nullwaarden is een belangrijke stap in de voorbereiding van gegevens. Dit zal later in het notebook worden behandeld.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Stel dat we veel numerieke gegevens in onze dataset hebben. Univariate statistische berekeningen zoals het gemiddelde, de mediaan, kwartielen, enzovoort, kunnen afzonderlijk op elke kolom worden uitgevoerd. De functie `DataFrame.describe()` geeft ons een statistisch overzicht van de numerieke kolommen in een dataset.\n" + "Stel dat we veel numerieke gegevens in onze dataset hebben. Univariate statistische berekeningen zoals het gemiddelde, de mediaan, kwartielen, enzovoort, kunnen afzonderlijk op elke kolom worden uitgevoerd. De functie `DataFrame.describe()` geeft ons een statistisch overzicht van de numerieke kolommen van een dataset.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "De bovenstaande output toont het totale aantal datapunten, het gemiddelde, de standaarddeviatie, het minimum, het onderste kwartiel (25%), de mediaan (50%), het bovenste kwartiel (75%) en de maximale waarde van elke kolom.\n" + "De bovenstaande output toont het totale aantal datapunten, gemiddelde, standaarddeviatie, minimum, onderste kwartiel (25%), mediaan (50%), bovenste kwartiel (75%) en de maximale waarde van elke kolom.\n" ] }, { @@ -332,7 +332,7 @@ }, "source": [ "### `DataFrame.head`\n", - "Met alle bovenstaande functies en attributen hebben we een overzicht op hoog niveau van de dataset. We weten hoeveel datapunten er zijn, hoeveel kenmerken er zijn, het datatype van elk kenmerk en het aantal niet-nulwaarden voor elk kenmerk.\n", + "Met alle bovenstaande functies en attributen hebben we een overzicht op hoog niveau van de dataset gekregen. We weten hoeveel datapunten er zijn, hoeveel kenmerken er zijn, het datatype van elk kenmerk en het aantal niet-nulwaarden voor elk kenmerk.\n", "\n", "Nu is het tijd om naar de gegevens zelf te kijken. Laten we eens zien hoe de eerste paar rijen (de eerste paar datapunten) van onze `DataFrame` eruitzien:\n" ] @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Zoals we hier kunnen zien, zijn er vijf(5) vermeldingen van de dataset. Als we naar de index aan de linkerkant kijken, ontdekken we dat dit de eerste vijf rijen zijn.\n" + "Zoals we hier zien, zijn er vijf(5) vermeldingen van de dataset. Als we naar de index aan de linkerkant kijken, ontdekken we dat dit de eerste vijf rijen zijn.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Oefening:\n", "\n", - "Uit het bovenstaande voorbeeld blijkt duidelijk dat `DataFrame.head` standaard de eerste vijf rijen van een `DataFrame` retourneert. Kun je in de onderstaande codecel een manier bedenken om meer dan vijf rijen weer te geven?\n" + "Uit het bovenstaande voorbeeld blijkt dat `DataFrame.head` standaard de eerste vijf rijen van een `DataFrame` retourneert. Kun je in de onderstaande codecel een manier vinden om meer dan vijf rijen weer te geven?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Een andere manier om naar de gegevens te kijken is vanaf het einde (in plaats van het begin). Het tegenovergestelde van `DataFrame.head` is `DataFrame.tail`, die de laatste vijf rijen van een `DataFrame` retourneert:\n" + "Een andere manier om naar de gegevens te kijken is vanaf het einde (in plaats van het begin). De tegenhanger van `DataFrame.head` is `DataFrame.tail`, die de laatste vijf rijen van een `DataFrame` retourneert:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "In de praktijk is het handig om eenvoudig de eerste paar rijen of de laatste paar rijen van een `DataFrame` te kunnen bekijken, vooral wanneer je op zoek bent naar uitschieters in geordende datasets.\n", + "In de praktijk is het handig om eenvoudig de eerste paar rijen of de laatste paar rijen van een `DataFrame` te bekijken, vooral wanneer je op zoek bent naar uitschieters in geordende datasets.\n", "\n", - "Alle functies en attributen die hierboven met behulp van codevoorbeelden zijn getoond, helpen ons om een indruk te krijgen van de gegevens.\n", + "Alle functies en attributen die hierboven zijn getoond met behulp van codevoorbeelden, helpen ons om een indruk te krijgen van de data.\n", "\n", - "> **Belangrijk punt:** Alleen al door te kijken naar de metadata over de informatie in een DataFrame of naar de eerste en laatste paar waarden ervan, kun je direct een idee krijgen van de grootte, vorm en inhoud van de gegevens waarmee je werkt.\n" + "> **Belangrijk punt:** Alleen al door te kijken naar de metadata over de informatie in een DataFrame of naar de eerste en laatste paar waarden ervan, kun je direct een idee krijgen van de grootte, vorm en inhoud van de data waarmee je werkt.\n" ] }, { @@ -598,15 +598,15 @@ "### Ontbrekende Gegevens\n", "Laten we ons verdiepen in ontbrekende gegevens. Ontbrekende gegevens ontstaan wanneer er geen waarde is opgeslagen in sommige kolommen.\n", "\n", - "Laten we een voorbeeld nemen: stel dat iemand bewust bezig is met zijn/haar gewicht en het veld voor gewicht in een enquête niet invult. Dan zal de waarde voor gewicht van die persoon ontbreken.\n", + "Laten we een voorbeeld nemen: stel dat iemand bewust is over zijn/haar gewicht en het veld voor gewicht niet invult in een enquête. Dan zal de waarde voor gewicht van die persoon ontbreken.\n", "\n", "In de meeste gevallen komen ontbrekende waarden voor in datasets uit de echte wereld.\n", "\n", "**Hoe Pandas omgaat met ontbrekende gegevens**\n", "\n", - "Pandas gaat op twee manieren om met ontbrekende waarden. De eerste manier heb je al eerder gezien in vorige secties: `NaN`, of Not a Number. Dit is eigenlijk een speciale waarde die deel uitmaakt van de IEEE floating-point specificatie en wordt alleen gebruikt om ontbrekende waarden van het type floating-point aan te geven.\n", + "Pandas gaat op twee manieren om met ontbrekende waarden. De eerste manier heb je al eerder gezien in vorige secties: `NaN`, of Not a Number. Dit is eigenlijk een speciale waarde die deel uitmaakt van de IEEE floating-point specificatie en wordt alleen gebruikt om ontbrekende waarden van het type float aan te geven.\n", "\n", - "Voor ontbrekende waarden anders dan floats gebruikt pandas het Python-object `None`. Hoewel het misschien verwarrend lijkt dat je twee verschillende soorten waarden tegenkomt die in wezen hetzelfde aangeven, zijn er goede programmatische redenen voor deze ontwerpkeuze. In de praktijk stelt deze aanpak pandas in staat om een goed compromis te bieden voor de overgrote meerderheid van de gevallen. Desondanks hebben zowel `None` als `NaN` beperkingen waar je rekening mee moet houden met betrekking tot hoe ze kunnen worden gebruikt.\n" + "Voor ontbrekende waarden die geen floats zijn, gebruikt pandas het Python-object `None`. Hoewel het misschien verwarrend lijkt dat je twee verschillende soorten waarden tegenkomt die in essentie hetzelfde aangeven, zijn er goede programmatische redenen voor deze ontwerpkeuze. In de praktijk stelt deze aanpak pandas in staat om een goed compromis te bieden voor de overgrote meerderheid van de gevallen. Desondanks hebben zowel `None` als `NaN` beperkingen waar je rekening mee moet houden met betrekking tot hoe ze kunnen worden gebruikt.\n" ] }, { @@ -616,7 +616,7 @@ }, "source": [ "### `None`: niet-vloeiende ontbrekende gegevens\n", - "Omdat `None` afkomstig is uit Python, kan het niet worden gebruikt in NumPy- en pandas-arrays die geen gegevenstype `'object'` hebben. Onthoud dat NumPy-arrays (en de datastructuren in pandas) slechts één type gegevens kunnen bevatten. Dit is wat hen hun enorme kracht geeft voor grootschalige data- en rekenkundige taken, maar het beperkt ook hun flexibiliteit. Dergelijke arrays moeten worden \"geüpcast\" naar de \"kleinste gemene deler,\" het gegevenstype dat alles in de array kan omvatten. Wanneer `None` in de array voorkomt, betekent dit dat je werkt met Python-objecten.\n", + "Omdat `None` afkomstig is uit Python, kan het niet worden gebruikt in NumPy- en pandas-arrays die geen datatype `'object'` hebben. Onthoud dat NumPy-arrays (en de datastructuren in pandas) slechts één type gegevens kunnen bevatten. Dit is wat hen hun enorme kracht geeft voor grootschalige data- en rekentaken, maar het beperkt ook hun flexibiliteit. Dergelijke arrays moeten worden opgewaardeerd naar de \"laagste gemene deler,\" het datatype dat alles in de array kan omvatten. Wanneer `None` in de array voorkomt, betekent dit dat je werkt met Python-objecten.\n", "\n", "Om dit in de praktijk te zien, bekijk het volgende voorbeeld van een array (let op de `dtype` ervan):\n" ] @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "De realiteit van opgewaardeerde datatypes brengt twee bijwerkingen met zich mee. Ten eerste worden bewerkingen uitgevoerd op het niveau van geïnterpreteerde Python-code in plaats van gecompileerde NumPy-code. In essentie betekent dit dat alle bewerkingen die `Series` of `DataFrames` met `None` bevatten, langzamer zullen zijn. Hoewel je deze prestatievermindering waarschijnlijk niet zult opmerken, kan het bij grote datasets een probleem worden.\n", + "De realiteit van opgehoogde datatypes brengt twee bijwerkingen met zich mee. Ten eerste worden bewerkingen uitgevoerd op het niveau van geïnterpreteerde Python-code in plaats van gecompileerde NumPy-code. In essentie betekent dit dat alle bewerkingen met `Series` of `DataFrames` waarin `None` voorkomt, langzamer zullen zijn. Hoewel je deze prestatievermindering waarschijnlijk niet zult opmerken, kan het bij grote datasets een probleem worden.\n", "\n", - "De tweede bijwerking vloeit voort uit de eerste. Omdat `None` `Series` of `DataFrames` in feite terugbrengt naar de wereld van standaard Python, zal het gebruik van NumPy/pandas-aggregaties zoals `sum()` of `min()` op arrays die een `None`-waarde bevatten over het algemeen een fout veroorzaken:\n" + "De tweede bijwerking vloeit voort uit de eerste. Omdat `None` `Series` of `DataFrames` feitelijk terugbrengt naar de wereld van standaard Python, zal het gebruik van NumPy/pandas-aggregaties zoals `sum()` of `min()` op arrays die een ``None``-waarde bevatten, doorgaans een fout veroorzaken:\n" ] }, { @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Belangrijkste punt**: Optelling (en andere bewerkingen) tussen gehele getallen en `None`-waarden is ongedefinieerd, wat kan beperken wat je kunt doen met datasets die ze bevatten.\n" + "**Belangrijkste punt**: Optelling (en andere bewerkingen) tussen gehele getallen en `None`-waarden is ongedefinieerd, wat kan beperken wat je kunt doen met datasets die deze bevatten.\n" ] }, { @@ -709,7 +709,7 @@ "source": [ "### `NaN`: ontbrekende float-waarden\n", "\n", - "In tegenstelling tot `None` ondersteunt NumPy (en dus ook pandas) `NaN` voor zijn snelle, gevectoriseerde operaties en ufuncs. Het nadeel is dat elke rekenkundige bewerking met `NaN` altijd resulteert in `NaN`. Bijvoorbeeld:\n" + "In tegenstelling tot `None` ondersteunt NumPy (en dus ook pandas) `NaN` voor zijn snelle, gevectoriseerde bewerkingen en ufuncs. Het nadeel is dat elke rekenkundige bewerking met `NaN` altijd resulteert in `NaN`. Bijvoorbeeld:\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Het goede nieuws: aggregaties die worden uitgevoerd op arrays met `NaN` erin veroorzaken geen fouten. Het slechte nieuws: de resultaten zijn niet uniform bruikbaar:\n" + "Het goede nieuws: aggregaties uitgevoerd op arrays met `NaN` erin veroorzaken geen fouten. Het slechte nieuws: de resultaten zijn niet uniform bruikbaar:\n" ] }, { @@ -831,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "Onthoud: `NaN` is alleen voor ontbrekende drijvende-kommawaarden; er is geen `NaN`-equivalent voor gehele getallen, strings of Booleans.\n" + "Onthoud: `NaN` is alleen voor ontbrekende waarden met drijvende komma; er is geen `NaN`-equivalent voor gehele getallen, strings of Booleans.\n" ] }, { @@ -840,9 +840,9 @@ "id": "kj6EKdsAgRsA" }, "source": [ - "### `NaN` en `None`: null-waarden in pandas\n", + "### `NaN` en `None`: nullwaarden in pandas\n", "\n", - "Hoewel `NaN` en `None` zich enigszins anders kunnen gedragen, is pandas ontworpen om ze door elkaar te gebruiken. Om te begrijpen wat hiermee wordt bedoeld, bekijk een `Series` van gehele getallen:\n" + "Hoewel `NaN` en `None` zich enigszins anders kunnen gedragen, is pandas toch ontworpen om ze door elkaar te gebruiken. Om te begrijpen wat we bedoelen, bekijk een `Series` van gehele getallen:\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Bij het upcasten van datatypes om gegevenshomogeniteit te waarborgen in `Series` en `DataFrame`s, zal pandas zonder problemen ontbrekende waarden omzetten tussen `None` en `NaN`. Vanwege deze ontwerpkeuze kan het handig zijn om `None` en `NaN` te beschouwen als twee verschillende varianten van \"null\" in pandas. Sterker nog, sommige van de kernmethoden die je zult gebruiken om met ontbrekende waarden in pandas om te gaan, weerspiegelen dit idee in hun namen:\n", + "Bij het opwaarderen van gegevenstypen om gegevenshomogeniteit te bereiken in `Series` en `DataFrame`s, zal pandas zonder problemen ontbrekende waarden wisselen tussen `None` en `NaN`. Door deze ontwerpkeuze kan het nuttig zijn om `None` en `NaN` te beschouwen als twee verschillende varianten van \"null\" in pandas. Sterker nog, sommige van de kernmethoden die je zult gebruiken om met ontbrekende waarden in pandas om te gaan, weerspiegelen dit idee in hun namen:\n", "\n", "- `isnull()`: Genereert een Booleaanse maskering die ontbrekende waarden aangeeft\n", - "- `notnull()`: Het tegenovergestelde van `isnull()`\n", + "- `notnull()`: Tegenovergestelde van `isnull()`\n", "- `dropna()`: Geeft een gefilterde versie van de gegevens terug\n", "- `fillna()`: Geeft een kopie van de gegevens terug waarbij ontbrekende waarden zijn ingevuld of geïmputeerd\n", "\n", - "Dit zijn belangrijke methoden om onder de knie te krijgen en vertrouwd mee te raken, dus laten we ze stuk voor stuk wat uitgebreider bespreken.\n" + "Dit zijn belangrijke methoden om onder de knie te krijgen en vertrouwd mee te raken, dus laten we ze elk wat uitgebreider bespreken.\n" ] }, { @@ -924,8 +924,7 @@ "source": [ "### Nullwaarden detecteren\n", "\n", - "Nu we het belang van ontbrekende waarden hebben begrepen, moeten we ze in onze dataset detecteren voordat we ermee aan de slag gaan. \n", - "Zowel `isnull()` als `notnull()` zijn je belangrijkste methoden om nullwaarden te detecteren. Beide geven Booleaanse maskers over je data terug.\n" + "Nu we het belang van ontbrekende waarden hebben begrepen, moeten we ze in onze dataset opsporen voordat we ermee aan de slag gaan. Zowel `isnull()` als `notnull()` zijn je belangrijkste methoden om nullwaarden te detecteren. Beide geven Booleaanse maskers over je data terug.\n" ] }, { @@ -978,11 +977,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Kijk goed naar de output. Valt je iets op? Hoewel `0` een rekenkundige nul is, is het toch een volledig geldig geheel getal, en pandas behandelt het ook zo. `''` is iets subtieler. Hoewel we het in Sectie 1 gebruikten om een lege tekenreekswaarde weer te geven, is het toch een tekenreeksobject en geen representatie van null volgens pandas.\n", + "Kijk goed naar de output. Verrast iets je? Hoewel `0` een wiskundige nul is, is het toch een volwaardig geheel getal en pandas behandelt het ook zo. `''` is iets subtieler. Hoewel we het in Sectie 1 gebruikten om een lege tekenreekswaarde weer te geven, is het toch een tekenreeksobject en geen representatie van null volgens pandas.\n", "\n", - "Laten we dit nu omdraaien en deze methoden gebruiken op een manier die meer lijkt op hoe je ze in de praktijk zult toepassen. Je kunt Booleaanse maskers direct gebruiken als een ``Series``- of ``DataFrame``-index, wat handig kan zijn wanneer je wilt werken met geïsoleerde ontbrekende (of aanwezige) waarden.\n", + "Laten we dit nu omdraaien en deze methoden gebruiken op een manier zoals je ze in de praktijk zult toepassen. Je kunt Booleaanse maskers direct gebruiken als een ``Series``- of ``DataFrame``-index, wat handig kan zijn wanneer je wilt werken met geïsoleerde ontbrekende (of aanwezige) waarden.\n", "\n", - "Als we het totale aantal ontbrekende waarden willen weten, kunnen we eenvoudig een som uitvoeren over het masker dat wordt geproduceerd door de `isnull()`-methode.\n" + "Als we het totale aantal ontbrekende waarden willen weten, kunnen we gewoon een som nemen over het masker dat door de `isnull()`-methode wordt geproduceerd.\n" ] }, { @@ -1040,7 +1039,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Belangrijkste punt**: Zowel de methoden `isnull()` als `notnull()` leveren vergelijkbare resultaten op wanneer je ze in DataFrames gebruikt: ze tonen de resultaten en de index van die resultaten, wat je enorm zal helpen bij het werken met je gegevens.\n" + "**Belangrijkste inzicht**: Zowel de methoden `isnull()` als `notnull()` leveren vergelijkbare resultaten op wanneer je ze gebruikt in DataFrames: ze tonen de resultaten en de index van die resultaten, wat je enorm zal helpen bij het werken met je data.\n" ] }, { @@ -1053,7 +1052,7 @@ "\n", "> **Leerdoel:** Aan het einde van deze subsectie weet je hoe en wanneer je null-waarden in DataFrames kunt vervangen of verwijderen.\n", "\n", - "Machine Learning-modellen kunnen niet zelf omgaan met ontbrekende gegevens. Voordat we de gegevens aan het model doorgeven, moeten we deze ontbrekende waarden verwerken.\n", + "Machine Learning-modellen kunnen niet zelf omgaan met ontbrekende gegevens. Daarom moeten we, voordat we de gegevens aan het model doorgeven, deze ontbrekende waarden aanpakken.\n", "\n", "Hoe ontbrekende gegevens worden behandeld, brengt subtiele afwegingen met zich mee en kan invloed hebben op je uiteindelijke analyse en resultaten in de praktijk.\n", "\n", @@ -1062,7 +1061,7 @@ "1. De rij met de ontbrekende waarde verwijderen\n", "2. De ontbrekende waarde vervangen door een andere waarde\n", "\n", - "We zullen beide methoden en hun voor- en nadelen in detail bespreken.\n" + "We zullen beide methoden en hun voor- en nadelen uitgebreid bespreken.\n" ] }, { @@ -1073,11 +1072,11 @@ "source": [ "### Nullwaarden verwijderen\n", "\n", - "De hoeveelheid data die we aan ons model doorgeven heeft een directe invloed op de prestaties ervan. Nullwaarden verwijderen betekent dat we het aantal datapunten verminderen, en daarmee de grootte van de dataset verkleinen. Het is dus aan te raden om rijen met nullwaarden te verwijderen wanneer de dataset behoorlijk groot is.\n", + "De hoeveelheid data die we aan ons model doorgeven, heeft een directe invloed op de prestaties ervan. Nullwaarden verwijderen betekent dat we het aantal datapunten verminderen en daarmee de grootte van de dataset verkleinen. Het is daarom aan te raden om rijen met nullwaarden te verwijderen wanneer de dataset behoorlijk groot is.\n", "\n", - "Een andere situatie kan zijn dat een bepaalde rij of kolom veel ontbrekende waarden heeft. In dat geval kunnen ze worden verwijderd omdat ze weinig waarde toevoegen aan onze analyse, aangezien de meeste data voor die rij/kolom ontbreekt.\n", + "Een andere situatie kan zijn dat een bepaalde rij of kolom veel ontbrekende waarden heeft. In dat geval kunnen ze worden verwijderd, omdat ze weinig waarde toevoegen aan onze analyse, aangezien de meeste gegevens voor die rij/kolom ontbreken.\n", "\n", - "Naast het identificeren van ontbrekende waarden biedt pandas een handige manier om nullwaarden te verwijderen uit `Series` en `DataFrame`s. Om dit in actie te zien, laten we teruggaan naar `example3`. De functie `DataFrame.dropna()` helpt bij het verwijderen van rijen met nullwaarden.\n" + "Naast het identificeren van ontbrekende waarden biedt pandas een handige manier om nullwaarden te verwijderen uit `Series` en `DataFrame`s. Om dit in de praktijk te zien, laten we teruggaan naar `example3`. De functie `DataFrame.dropna()` helpt bij het verwijderen van rijen met nullwaarden.\n" ] }, { @@ -1118,7 +1117,7 @@ "source": [ "Merk op dat dit eruit zou moeten zien als je uitvoer van `example3[example3.notnull()]`. Het verschil hier is dat, in plaats van alleen te indexeren op de gemaskeerde waarden, `dropna` die ontbrekende waarden uit de `Series` `example3` heeft verwijderd.\n", "\n", - "Omdat DataFrames twee dimensies hebben, bieden ze meer mogelijkheden om gegevens te verwijderen.\n" + "Omdat DataFrames twee dimensies hebben, bieden ze meer opties om gegevens te verwijderen.\n" ] }, { @@ -1283,7 +1282,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "Als het nodig is, kun je NA-waarden uit kolommen verwijderen. Gebruik `axis=1` om dit te doen:\n" + "Indien nodig kun je NA-waarden uit kolommen verwijderen. Gebruik `axis=1` om dit te doen:\n" ] }, { @@ -1362,7 +1361,7 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Merk op dat dit veel gegevens kan verwijderen die je misschien wilt behouden, vooral in kleinere datasets. Wat als je alleen rijen of kolommen wilt verwijderen die meerdere of zelfs alle nullwaarden bevatten? Je stelt deze instellingen in met `dropna` door de parameters `how` en `thresh` te gebruiken.\n", + "Merk op dat dit veel gegevens kan verwijderen die je misschien wilt behouden, vooral bij kleinere datasets. Wat als je alleen rijen of kolommen wilt verwijderen die meerdere of zelfs alle nullwaarden bevatten? Je kunt deze instellingen specificeren in `dropna` met de parameters `how` en `thresh`.\n", "\n", "Standaard is `how='any'` (als je dit zelf wilt controleren of wilt zien welke andere parameters de methode heeft, voer dan `example4.dropna?` uit in een codecel). Je kunt ook `how='all'` specificeren om alleen rijen of kolommen te verwijderen die volledig uit nullwaarden bestaan. Laten we ons voorbeeld `DataFrame` uitbreiden om dit in actie te zien in de volgende oefening.\n" ] @@ -1460,7 +1459,7 @@ "1. Het verwijderen van null-waarden is alleen een goed idee als de dataset groot genoeg is. \n", "2. Volledige rijen of kolommen kunnen worden verwijderd als het merendeel van de gegevens ontbreekt. \n", "3. De methode `DataFrame.dropna(axis=)` helpt bij het verwijderen van null-waarden. Het argument `axis` geeft aan of rijen of kolommen moeten worden verwijderd. \n", - "4. Het argument `how` kan ook worden gebruikt. Standaard is dit ingesteld op `any`. Dit betekent dat alleen die rijen/kolommen worden verwijderd die een of meer null-waarden bevatten. Het kan worden ingesteld op `all` om aan te geven dat we alleen die rijen/kolommen verwijderen waar alle waarden null zijn. \n" + "4. Het argument `how` kan ook worden gebruikt. Standaard is het ingesteld op `any`. Dit betekent dat alleen die rijen/kolommen worden verwijderd die een null-waarde bevatten. Het kan worden ingesteld op `all` om aan te geven dat we alleen die rijen/kolommen verwijderen waar alle waarden null zijn. \n" ] }, { @@ -1492,7 +1491,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "De parameter `thresh` geeft je fijnmazigere controle: je stelt het aantal *niet-nul* waarden in dat een rij of kolom moet hebben om behouden te blijven:\n" + "De `thresh`-parameter geeft je meer gedetailleerde controle: je stelt het aantal *niet-nulle* waarden in dat een rij of kolom moet hebben om behouden te blijven:\n" ] }, { @@ -1576,11 +1575,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### Null-waarden invullen\n", + "### Nullwaarden invullen\n", "\n", - "Het kan soms logisch zijn om ontbrekende waarden in te vullen met waarden die geldig zouden kunnen zijn. Er zijn een paar technieken om null-waarden in te vullen. De eerste is het gebruik van Domeinkennis (kennis van het onderwerp waarop de dataset is gebaseerd) om de ontbrekende waarden op een of andere manier te benaderen.\n", + "Het kan soms logisch zijn om ontbrekende waarden in te vullen met waarden die geldig zouden kunnen zijn. Er zijn een paar technieken om nullwaarden in te vullen. De eerste is het gebruik van Domeinkennis (kennis van het onderwerp waarop de dataset is gebaseerd) om op een of andere manier de ontbrekende waarden te benaderen.\n", "\n", - "Je zou `isnull` kunnen gebruiken om dit direct te doen, maar dat kan tijdrovend zijn, vooral als je veel waarden moet invullen. Omdat dit een veelvoorkomende taak is in data science, biedt pandas `fillna`, wat een kopie van de `Series` of `DataFrame` retourneert met de ontbrekende waarden vervangen door een waarde naar keuze. Laten we een ander voorbeeld van een `Series` maken om te zien hoe dit in de praktijk werkt.\n" + "Je kunt `isnull` gebruiken om dit direct te doen, maar dat kan tijdrovend zijn, vooral als je veel waarden moet invullen. Omdat dit een veelvoorkomende taak is in data science, biedt pandas `fillna`, waarmee je een kopie van de `Series` of `DataFrame` krijgt waarin de ontbrekende waarden zijn vervangen door een waarde naar keuze. Laten we een ander voorbeeld van een `Series` maken om te zien hoe dit in de praktijk werkt.\n" ] }, { @@ -1699,7 +1698,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Laten we eerst de modus vinden voordat we de `None`-waarde vullen met de modus.\n" + ] }, { "cell_type": "code", @@ -1734,7 +1735,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Dus, we zullen None vervangen door True\n" + ] }, { "cell_type": "code", @@ -1844,7 +1847,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Zoals we kunnen zien, is de null-waarde vervangen. Het hoeft geen betoog dat we alles hadden kunnen schrijven in plaats van `'True'` en het zou zijn vervangen.\n" + "Zoals we kunnen zien, is de null-waarde vervangen. Het is vanzelfsprekend dat we alles hadden kunnen schrijven in plaats van `'True'` en het zou zijn vervangen.\n" ] }, { @@ -1854,7 +1857,7 @@ }, "source": [ "### Numerieke Gegevens\n", - "Nu gaan we naar numerieke gegevens. Hier zijn er twee veelvoorkomende manieren om ontbrekende waarden te vervangen:\n", + "Nu gaan we verder met numerieke gegevens. Hier zijn twee veelgebruikte methoden om ontbrekende waarden te vervangen:\n", "\n", "1. Vervangen door de mediaan van de rij\n", "2. Vervangen door het gemiddelde van de rij\n", @@ -2003,7 +2006,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Vullen met gemiddelde\n" + ] }, { "cell_type": "code", @@ -2252,7 +2257,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Vullen met mediaan\n" + ] }, { "cell_type": "code", @@ -2394,7 +2401,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "Je kunt alle lege invoervelden invullen met een enkele waarde, zoals `0`:\n" + "Je kunt alle lege invoervelden vullen met een enkele waarde, zoals `0`:\n" ] }, { @@ -2437,7 +2444,7 @@ "source": [ "> Belangrijke punten:\n", "1. Het invullen van ontbrekende waarden moet worden gedaan wanneer er weinig gegevens zijn of wanneer er een strategie is om de ontbrekende gegevens in te vullen.\n", - "2. Domeinkennis kan worden gebruikt om ontbrekende waarden in te vullen door ze te benaderen.\n", + "2. Domeinkennis kan worden gebruikt om ontbrekende waarden te benaderen en in te vullen.\n", "3. Voor categorische gegevens worden ontbrekende waarden meestal vervangen door de modus van de kolom.\n", "4. Voor numerieke gegevens worden ontbrekende waarden meestal ingevuld met het gemiddelde (voor genormaliseerde datasets) of de mediaan van de kolommen.\n" ] @@ -2470,7 +2477,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "Je kunt null-waarden **vooruit invullen**, wat betekent dat je de laatste geldige waarde gebruikt om een null in te vullen:\n" + "Je kunt **forward-fill** nullwaarden, wat betekent dat je de laatste geldige waarde gebruikt om een nullwaarde in te vullen:\n" ] }, { @@ -2511,7 +2518,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Je kunt ook **back-fillen** om de volgende geldige waarde terugwaarts te propaganderen om een null te vullen:\n" + "Je kunt ook **back-fill** gebruiken om de volgende geldige waarde achterwaarts te propageren om een null te vullen:\n" ] }, { @@ -2553,7 +2560,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "Zoals je misschien al raadt, werkt dit hetzelfde met DataFrames, maar je kunt ook een `as` specificeren waarlangs je null-waarden wilt invullen:\n" + "Zoals je misschien kunt raden, werkt dit hetzelfde met DataFrames, maar je kunt ook een `as` specificeren langs welke null-waarden moeten worden ingevuld:\n" ] }, { @@ -2850,9 +2857,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Merk op dat kolom 3 nog steeds geen waarde heeft: de standaardrichting is om waarden rij-voor-rij in te vullen.\n", + "Merk op dat kolom 3 nog steeds geen waarde heeft: de standaardrichting is om waarden rij per rij in te vullen.\n", "\n", - "> **Belangrijk punt:** Er zijn meerdere manieren om om te gaan met ontbrekende waarden in je datasets. De specifieke strategie die je kiest (verwijderen, vervangen, of zelfs hoe je ze vervangt) moet worden bepaald door de specifieke kenmerken van die data. Je zult een beter gevoel ontwikkelen voor hoe je met ontbrekende waarden omgaat naarmate je meer met datasets werkt en ermee omgaat.\n" + "> **Belangrijk punt:** Er zijn meerdere manieren om om te gaan met ontbrekende waarden in je datasets. De specifieke strategie die je kiest (verwijderen, vervangen, of zelfs hoe je ze vervangt) moet worden bepaald door de specifieke kenmerken van die data. Hoe meer je met datasets werkt en interactie hebt, hoe beter je gevoel wordt voor het omgaan met ontbrekende waarden.\n" ] }, { @@ -2861,9 +2868,9 @@ "id": "bauDnESIl9FH" }, "source": [ - "### Categoriale Gegevens Coderen\n", + "### Coderen van Categorische Gegevens\n", "\n", - "Machine learning-modellen werken alleen met getallen en elke vorm van numerieke gegevens. Ze kunnen geen onderscheid maken tussen een Ja en een Nee, maar wel tussen een 0 en een 1. Dus, nadat we de ontbrekende waarden hebben ingevuld, moeten we de categorische gegevens coderen naar een numerieke vorm zodat het model deze kan begrijpen.\n", + "Machine learning-modellen werken alleen met cijfers en elke vorm van numerieke data. Ze kunnen geen onderscheid maken tussen een Ja en een Nee, maar wel tussen 0 en 1. Dus, nadat we de ontbrekende waarden hebben ingevuld, moeten we de categorische gegevens coderen naar een numerieke vorm zodat het model ze kan begrijpen.\n", "\n", "Coderen kan op twee manieren worden gedaan. We zullen deze hierna bespreken.\n" ] @@ -2874,9 +2881,9 @@ "id": "uDq9SxB7mu5i" }, "source": [ - "**LABEL ENCODERING**\n", + "**LABELCODERING**\n", "\n", - "Label-encodering houdt in dat elke categorie wordt omgezet naar een nummer. Stel bijvoorbeeld dat we een dataset hebben van vliegtuigpassagiers en er is een kolom met hun klasse, zoals ['business class', 'economy class', 'first class']. Als we Label-encodering toepassen, wordt dit omgezet naar [0, 1, 2]. Laten we een voorbeeld bekijken via code. Aangezien we `scikit-learn` in de komende notebooks zullen leren, gebruiken we het hier niet.\n" + "Labelcodering houdt in dat elke categorie wordt omgezet in een nummer. Stel bijvoorbeeld dat we een dataset hebben van vliegtuigpassagiers en er is een kolom met hun klasse, zoals ['business class', 'economy class', 'first class']. Als hier labelcodering op wordt toegepast, wordt dit omgezet naar [0, 1, 2]. Laten we een voorbeeld bekijken via code. Omdat we `scikit-learn` in de komende notebooks gaan leren, gebruiken we het hier niet.\n" ] }, { @@ -2984,7 +2991,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Om labelcodering uit te voeren op de 1e kolom, moeten we eerst een mapping beschrijven van elke klasse naar een nummer, voordat we vervangen\n" + "Om label encoding uit te voeren op de 1e kolom, moeten we eerst een mapping beschrijven van elke klasse naar een nummer, voordat we vervangen.\n" ] }, { @@ -3086,7 +3093,7 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Zoals we kunnen zien, komt het resultaat overeen met wat we hadden verwacht. Dus, wanneer gebruiken we label encoding? Label encoding wordt gebruikt in een of beide van de volgende gevallen:\n", + "Zoals we kunnen zien, komt de output overeen met wat we hadden verwacht. Dus, wanneer gebruiken we label encoding? Label encoding wordt gebruikt in een of beide van de volgende gevallen:\n", "1. Wanneer het aantal categorieën groot is\n", "2. Wanneer de categorieën een volgorde hebben.\n" ] @@ -3209,7 +3216,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "Laten we one-hot encoding uitvoeren op de 1e kolom\n" + "Laten we one-hot encoding uitvoeren op de eerste kolom\n" ] }, { @@ -3345,7 +3352,7 @@ "source": [ "Wanneer gebruiken we one-hot encoding? One-hot encoding wordt gebruikt in een of beide van de volgende gevallen:\n", "\n", - "1. Wanneer het aantal categorieën en de grootte van de dataset klein is.\n", + "1. Wanneer het aantal categorieën en de grootte van de dataset klein zijn.\n", "2. Wanneer de categorieën geen specifieke volgorde hebben.\n" ] }, @@ -3355,9 +3362,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Belangrijke punten:\n", + "> Belangrijkste punten:\n", "1. Codering wordt gebruikt om niet-numerieke gegevens om te zetten in numerieke gegevens.\n", - "2. Er zijn twee soorten codering: Labelcodering en One Hot-codering, die beide kunnen worden uitgevoerd op basis van de eisen van de dataset.\n" + "2. Er zijn twee soorten codering: Labelcodering en One Hot-codering, die beide kunnen worden uitgevoerd afhankelijk van de eisen van de dataset.\n" ] }, { @@ -3366,11 +3373,11 @@ "id": "K8UXOJYRgRsJ" }, "source": [ - "## Dubbele gegevens verwijderen\n", + "## Duplicaatgegevens verwijderen\n", "\n", - "> **Leerdoel:** Aan het einde van deze subsectie moet je in staat zijn om dubbele waarden in DataFrames te herkennen en te verwijderen.\n", + "> **Leerdoel:** Aan het einde van deze subsectie moet je in staat zijn om duplicaatwaarden in DataFrames te identificeren en te verwijderen.\n", "\n", - "Naast ontbrekende gegevens kom je in datasets uit de praktijk vaak dubbele gegevens tegen. Gelukkig biedt pandas een eenvoudige manier om dubbele items te detecteren en te verwijderen.\n" + "Naast ontbrekende gegevens kom je vaak duplicaatgegevens tegen in datasets uit de praktijk. Gelukkig biedt pandas een eenvoudige manier om duplicaatvermeldingen te detecteren en te verwijderen.\n" ] }, { @@ -3381,7 +3388,7 @@ "source": [ "### Duplicaten identificeren: `duplicated`\n", "\n", - "Je kunt duplicaten eenvoudig opsporen met de `duplicated`-methode in pandas, die een Booleaanse maskering retourneert om aan te geven of een invoer in een `DataFrame` een duplicaat is van een eerdere. Laten we een ander voorbeeld `DataFrame` maken om dit in actie te zien.\n" + "Je kunt eenvoudig dubbele waarden opsporen met de `duplicated`-methode in pandas, die een Booleaanse maskering retourneert om aan te geven of een invoer in een `DataFrame` een duplicaat is van een eerdere. Laten we een ander voorbeeld `DataFrame` maken om dit in actie te zien.\n" ] }, { @@ -3511,7 +3518,7 @@ }, "source": [ "### Duplicaten verwijderen: `drop_duplicates`\n", - "`drop_duplicates` geeft simpelweg een kopie van de gegevens terug waarvoor alle `duplicated` waarden `False` zijn:\n" + "`drop_duplicates` geeft eenvoudigweg een kopie van de gegevens terug waarvoor alle `duplicated` waarden `False` zijn:\n" ] }, { @@ -3670,13 +3677,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Belangrijk:** Het verwijderen van dubbele gegevens is een essentieel onderdeel van bijna elk data-scienceproject. Dubbele gegevens kunnen de resultaten van je analyses veranderen en je onnauwkeurige resultaten geven!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Kwaliteitscontroles van gegevens uit de praktijk\n", + "\n", + "> **Leerdoel:** Aan het einde van deze sectie moet je in staat zijn om veelvoorkomende kwaliteitsproblemen in gegevens uit de praktijk te herkennen en te corrigeren, zoals inconsistente categoriewaarden, abnormale numerieke waarden (uitbijters) en dubbele entiteiten met variaties.\n", + "\n", + "Hoewel ontbrekende waarden en exacte duplicaten veelvoorkomende problemen zijn, bevatten datasets uit de praktijk vaak subtielere problemen:\n", + "\n", + "1. **Inconsistente categoriewaarden**: Dezelfde categorie anders gespeld (bijv. \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Abnormale numerieke waarden**: Extreme uitbijters die wijzen op invoerfouten (bijv. leeftijd = 999)\n", + "3. **Bijna-duplicaten**: Records die dezelfde entiteit vertegenwoordigen met kleine variaties\n", + "\n", + "Laten we technieken verkennen om deze problemen te detecteren en aan te pakken.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Een voorbeeld van een \"vuile\" dataset maken\n", + "\n", + "Laten we eerst een voorbeelddataset maken die de soorten problemen bevat die we vaak tegenkomen in echte data:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Detecteren van inconsistente categorische waarden\n", + "\n", + "Let op dat de `country`-kolom meerdere representaties heeft voor dezelfde landen. Laten we deze inconsistenties identificeren:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Standaardiseren van Categorische Waarden\n", + "\n", + "We kunnen een mapping maken om deze waarden te standaardiseren. Een eenvoudige aanpak is om ze om te zetten naar kleine letters en een mapping dictionary te maken:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternatief: Gebruik van fuzzy matching**\n", + "\n", + "Voor meer complexe gevallen kunnen we fuzzy string matching gebruiken met de `rapidfuzz`-bibliotheek om automatisch vergelijkbare strings te detecteren:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Detecteren van Abnormale Numerieke Waarden (Uitbijters)\n", + "\n", + "Als we naar de `age`-kolom kijken, zien we enkele verdachte waarden zoals 199 en -5. Laten we statistische methoden gebruiken om deze uitbijters te detecteren.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Gebruik van de IQR (Interkwartielafstand) Methode\n", + "\n", + "De IQR-methode is een robuuste statistische techniek voor het detecteren van uitschieters die minder gevoelig is voor extreme waarden:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Gebruik van de Z-Score Methode\n", + "\n", + "De Z-score methode identificeert uitschieters op basis van standaarddeviaties vanaf het gemiddelde:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Omgaan met uitschieters\n", + "\n", + "Zodra uitschieters zijn gedetecteerd, kunnen ze op verschillende manieren worden behandeld:\n", + "1. **Verwijderen**: Verwijder rijen met uitschieters (als het fouten zijn)\n", + "2. **Afschermen**: Vervang door grenswaarden\n", + "3. **Vervangen door NaN**: Behandel als ontbrekende gegevens en gebruik imputatietechnieken\n", + "4. **Behouden**: Als het legitieme extreme waarden zijn\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Detecteren van bijna-duplicaat rijen\n", + "\n", + "Merk op dat onze dataset meerdere vermeldingen heeft voor \"John Smith\" met licht verschillende waarden. Laten we potentiële duplicaten identificeren op basis van naamgelijkenis.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Nabijgelegen duplicaten vinden met fuzzy matching\n", + "\n", + "Voor meer geavanceerde duplicaatdetectie kunnen we fuzzy matching gebruiken om vergelijkbare namen te vinden:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Omgaan met duplicaten\n", + "\n", + "Zodra ze zijn geïdentificeerd, moet je beslissen hoe je met duplicaten omgaat:\n", + "1. **Behoud de eerste voorkoming**: Gebruik `drop_duplicates(keep='first')`\n", + "2. **Behoud de laatste voorkoming**: Gebruik `drop_duplicates(keep='last')`\n", + "3. **Informatie samenvoegen**: Combineer informatie uit dubbele rijen\n", + "4. **Handmatige controle**: Markeer voor menselijke beoordeling\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Samenvatting: Volledige Gegevensopschoonpipeline\n", + "\n", + "Laten we alles samenvoegen tot een uitgebreide opschoonpipeline:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Uitdagingsoefening\n", + "\n", + "Nu is het jouw beurt! Hieronder staat een nieuwe rij met gegevens die meerdere kwaliteitsproblemen bevat. Kun je:\n", + "\n", + "1. Alle problemen in deze rij identificeren\n", + "2. Code schrijven om elk probleem op te lossen\n", + "3. De schoongemaakte rij toevoegen aan de dataset\n", + "\n", + "Hier zijn de problematische gegevens:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Belangrijke punten\n", + "\n", + "1. **Inconsistente categorieën** komen vaak voor in echte datasets. Controleer altijd de unieke waarden en standaardiseer ze met behulp van mappings of fuzzy matching.\n", + "\n", + "2. **Uitschieters** kunnen je analyse aanzienlijk beïnvloeden. Gebruik domeinkennis in combinatie met statistische methoden (IQR, Z-score) om ze te detecteren.\n", + "\n", + "3. **Bijna-duplicaten** zijn moeilijker te herkennen dan exacte duplicaten. Overweeg het gebruik van fuzzy matching en het normaliseren van gegevens (kleine letters, spaties verwijderen) om ze te identificeren.\n", + "\n", + "4. **Gegevens opschonen is iteratief**. Je moet mogelijk meerdere technieken toepassen en de resultaten beoordelen voordat je je opgeschoonde dataset definitief maakt.\n", + "\n", + "5. **Documenteer je beslissingen**. Houd bij welke schoonmaakstappen je hebt toegepast en waarom, omdat dit belangrijk is voor reproduceerbaarheid en transparantie.\n", + "\n", + "> **Beste praktijk:** Bewaar altijd een kopie van je originele \"vuile\" data. Overschrijf nooit je bronbestanden - maak opgeschoonde versies met duidelijke naamconventies zoals `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Disclaimer**: \nDit document is vertaald met behulp van de AI-vertalingsservice [Co-op Translator](https://github.com/Azure/co-op-translator). Hoewel we streven naar nauwkeurigheid, dient u zich ervan bewust te zijn dat geautomatiseerde vertalingen fouten of onnauwkeurigheden kunnen bevatten. Het originele document in de oorspronkelijke taal moet worden beschouwd als de gezaghebbende bron. Voor kritieke informatie wordt professionele menselijke vertaling aanbevolen. Wij zijn niet aansprakelijk voor misverstanden of verkeerde interpretaties die voortvloeien uit het gebruik van deze vertaling.\n" + "\n---\n\n**Disclaimer**: \nDit document is vertaald met behulp van de AI-vertalingsservice [Co-op Translator](https://github.com/Azure/co-op-translator). Hoewel we streven naar nauwkeurigheid, dient u zich ervan bewust te zijn dat geautomatiseerde vertalingen fouten of onnauwkeurigheden kunnen bevatten. Het originele document in de oorspronkelijke taal moet worden beschouwd als de gezaghebbende bron. Voor cruciale informatie wordt professionele menselijke vertaling aanbevolen. Wij zijn niet aansprakelijk voor misverstanden of verkeerde interpretaties die voortvloeien uit het gebruik van deze vertaling.\n" ] } ], @@ -3704,8 +4229,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:25:32+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:29:48+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "nl" } diff --git a/translations/no/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/no/2-Working-With-Data/08-data-preparation/notebook.ipynb index e357101f..703ee0a0 100644 --- a/translations/no/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/no/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -6,15 +6,15 @@ "id": "rQ8UhzFpgRra" }, "source": [ - "# Datapreparering\n", + "# Dataklargjøring\n", "\n", - "[Original Notebook-kilde fra *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Original Notebook-kilde fra *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio av Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", - "## Utforske informasjon i `DataFrame`\n", + "## Utforske informasjon om `DataFrame`\n", "\n", - "> **Læringsmål:** Etter å ha fullført denne delen, bør du være komfortabel med å finne generell informasjon om dataene som er lagret i pandas DataFrames.\n", + "> **Læringsmål:** Etter denne delen bør du være komfortabel med å finne generell informasjon om dataene som er lagret i pandas DataFrames.\n", "\n", - "Når du har lastet inn dataene dine i pandas, vil de mest sannsynlig være i en `DataFrame`. Men hvis datasettet i din `DataFrame` har 60 000 rader og 400 kolonner, hvordan begynner du i det hele tatt å få en forståelse av hva du jobber med? Heldigvis tilbyr pandas noen praktiske verktøy for raskt å se overordnet informasjon om en `DataFrame` i tillegg til de første og siste radene.\n", + "Når du har lastet inn dataene dine i pandas, vil de mest sannsynlig være i en `DataFrame`. Men hvis datasettet i din `DataFrame` har 60,000 rader og 400 kolonner, hvordan begynner du i det hele tatt å få en forståelse av hva du jobber med? Heldigvis gir pandas noen praktiske verktøy for raskt å se overordnet informasjon om en `DataFrame` i tillegg til de første og siste radene.\n", "\n", "For å utforske denne funksjonaliteten, vil vi importere Python-biblioteket scikit-learn og bruke et ikonisk datasett som enhver dataforsker har sett hundrevis av ganger: Den britiske biologen Ronald Fishers *Iris*-datasett brukt i hans artikkel fra 1936 \"The use of multiple measurements in taxonomic problems\":\n" ] @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Vi har lastet inn Iris-datasettet i variabelen `iris_df`. Før vi dykker ned i dataene, kan det være nyttig å vite hvor mange datapunkter vi har og den totale størrelsen på datasettet. Det er verdifullt å få en oversikt over mengden data vi jobber med.\n" + "Vi har lastet inn Iris-datasettet i variabelen `iris_df`. Før vi går dypere inn i dataene, kan det være nyttig å vite antall datapunkter vi har og den totale størrelsen på datasettet. Det er nyttig å se på volumet av data vi jobber med.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Så, vi har 150 rader og 4 kolonner med data. Hver rad representerer ett datapunkt, og hver kolonne representerer en enkelt egenskap knyttet til datarammen. Så i bunn og grunn er det 150 datapunkter som inneholder 4 egenskaper hver.\n", + "Så, vi har med 150 rader og 4 kolonner med data å gjøre. Hver rad representerer ett datapunkt, og hver kolonne representerer en enkelt egenskap knyttet til datarammen. Så i bunn og grunn er det 150 datapunkter som inneholder 4 egenskaper hver.\n", "\n", - "`shape` her er en attributt til datarammen og ikke en funksjon, derfor slutter den ikke med et par parenteser.\n" + "`shape` her er en attributt til datarammen og ikke en funksjon, og derfor slutter den ikke med et par parenteser.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "La oss nå se nærmere på de 4 kolonnene med data. Hva representerer hver av dem egentlig? Attributtet `columns` gir oss navnene på kolonnene i dataframen.\n" + "La oss nå gå videre til de 4 kolonnene med data. Hva representerer hver av dem egentlig? Attributtet `columns` gir oss navnene på kolonnene i dataframet.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Som vi kan se, er det fire (4) kolonner. Attributtet `columns` forteller oss navnene på kolonnene og egentlig ingenting annet. Dette attributtet blir viktig når vi ønsker å identifisere hvilke funksjoner et datasett inneholder.\n" + "Som vi kan se, er det fire(4) kolonner. `columns`-attributtet forteller oss navnene på kolonnene og egentlig ingenting annet. Dette attributtet blir viktig når vi ønsker å identifisere hvilke funksjoner et datasett inneholder.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Mengden data (gitt av attributtet `shape`) og navnene på funksjonene eller kolonnene (gitt av attributtet `columns`) gir oss noe informasjon om datasettet. Nå ønsker vi å gå dypere inn i datasettet. Funksjonen `DataFrame.info()` er svært nyttig for dette.\n" + "Mengden data (gitt av attributtet `shape`) og navnene på egenskapene eller kolonnene (gitt av attributtet `columns`) gir oss noe informasjon om datasettet. Nå ønsker vi å gå dypere inn i datasettet. Funksjonen `DataFrame.info()` er svært nyttig for dette.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Fra dette kan vi gjøre noen observasjoner: \n", - "1. Datatypen for hver kolonne: I dette datasettet er alle data lagret som 64-biters flyttall. \n", - "2. Antall ikke-null verdier: Håndtering av nullverdier er et viktig steg i databehandling. Dette vil bli tatt hånd om senere i notatboken. \n" + "Fra dette kan vi gjøre noen observasjoner:\n", + "1. Datatypen for hver kolonne: I dette datasettet er alle data lagret som 64-biters flyttall.\n", + "2. Antall ikke-null verdier: Håndtering av nullverdier er et viktig steg i databehandling. Dette vil bli tatt hånd om senere i notatboken.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "La oss si at vi har mye numerisk data i datasettet vårt. Envariat statistiske beregninger som gjennomsnitt, median, kvartiler osv. kan utføres på hver av kolonnene individuelt. Funksjonen `DataFrame.describe()` gir oss en statistisk oppsummering av de numeriske kolonnene i et datasett.\n" + "La oss si at vi har mye numerisk data i datasettet vårt. Univariate statistiske beregninger som gjennomsnitt, median, kvartiler osv. kan utføres på hver av kolonnene individuelt. Funksjonen `DataFrame.describe()` gir oss en statistisk oppsummering av de numeriske kolonnene i et datasett.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "Utdataene ovenfor viser det totale antallet datapunkter, gjennomsnitt, standardavvik, minimum, nedre kvartil (25 %), median (50 %), øvre kvartil (75 %) og maksimumsverdien for hver kolonne.\n" + "Outputen ovenfor viser det totale antallet datapunkter, gjennomsnitt, standardavvik, minimum, nedre kvartil (25%), median (50%), øvre kvartil (75%) og maksimumsverdien for hver kolonne.\n" ] }, { @@ -332,7 +332,7 @@ }, "source": [ "### `DataFrame.head`\n", - "Med alle funksjonene og attributtene nevnt ovenfor, har vi fått et overordnet bilde av datasettet. Vi vet hvor mange datapunkter som finnes, hvor mange egenskaper det er, datatypen til hver egenskap og antall ikke-null verdier for hver egenskap.\n", + "Med alle de ovennevnte funksjonene og attributtene har vi fått et overordnet bilde av datasettet. Vi vet hvor mange datapunkter som finnes, hvor mange egenskaper som finnes, datatypen til hver egenskap og antall ikke-null verdier for hver egenskap.\n", "\n", "Nå er det på tide å se på selve dataene. La oss se hvordan de første radene (de første datapunktene) i vår `DataFrame` ser ut:\n" ] @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Som output her kan vi se fem(5) oppføringer av datasettet. Hvis vi ser på indeksen til venstre, finner vi ut at dette er de første fem radene.\n" + "Som output her kan vi se fem (5) oppføringer av datasettet. Hvis vi ser på indeksen til venstre, finner vi ut at dette er de første fem radene.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Øvelse:\n", "\n", - "Fra eksempelet ovenfor er det tydelig at `DataFrame.head` som standard returnerer de fem første radene i en `DataFrame`. I kodecellen nedenfor, kan du finne en måte å vise mer enn fem rader på?\n" + "Fra eksempelet gitt ovenfor, er det tydelig at `DataFrame.head` som standard returnerer de første fem radene i en `DataFrame`. I kodecellen nedenfor, kan du finne ut en måte å vise mer enn fem rader?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "En annen måte å se på dataene kan være fra slutten (i stedet for starten). Motstykket til `DataFrame.head` er `DataFrame.tail`, som returnerer de siste fem radene i en `DataFrame`:\n" + "En annen måte å se på dataene kan være fra slutten (i stedet for begynnelsen). Motstykket til `DataFrame.head` er `DataFrame.tail`, som returnerer de siste fem radene i en `DataFrame`:\n" ] }, { @@ -598,15 +598,15 @@ "### Manglende Data\n", "La oss dykke ned i manglende data. Manglende data oppstår når ingen verdi er lagret i noen av kolonnene.\n", "\n", - "La oss ta et eksempel: si at noen er bevisst på vekten sin og ikke fyller ut vektfeltet i en undersøkelse. Da vil vektverdien for denne personen være manglende.\n", + "La oss ta et eksempel: si at noen er opptatt av vekten sin og ikke fyller ut vektfeltet i en undersøkelse. Da vil vektverdien for denne personen mangle.\n", "\n", - "I de fleste tilfeller oppstår manglende verdier i datasett fra den virkelige verden.\n", + "I de fleste tilfeller oppstår manglende verdier i datasett fra virkeligheten.\n", "\n", "**Hvordan Pandas håndterer manglende data**\n", "\n", "Pandas håndterer manglende verdier på to måter. Den første har du sett tidligere i tidligere seksjoner: `NaN`, eller Not a Number. Dette er faktisk en spesiell verdi som er en del av IEEE-flyttallsstandarden, og den brukes kun til å indikere manglende flyttallsverdier.\n", "\n", - "For manglende verdier som ikke er flyttall, bruker pandas Python-objektet `None`. Selv om det kan virke forvirrende at du vil støte på to forskjellige typer verdier som i hovedsak sier det samme, finnes det gode programmatiske grunner for dette designvalget. I praksis gjør denne tilnærmingen det mulig for pandas å levere et godt kompromiss for de aller fleste tilfeller. Til tross for dette har både `None` og `NaN` begrensninger som du må være oppmerksom på med hensyn til hvordan de kan brukes.\n" + "For manglende verdier som ikke er flyttall, bruker pandas Python-objektet `None`. Selv om det kan virke forvirrende at du vil støte på to forskjellige typer verdier som i hovedsak betyr det samme, finnes det gode programmeringsmessige grunner til dette designvalget. I praksis gjør denne tilnærmingen det mulig for pandas å levere et godt kompromiss for de aller fleste tilfeller. Likevel har både `None` og `NaN` begrensninger som du må være oppmerksom på med hensyn til hvordan de kan brukes.\n" ] }, { @@ -616,7 +616,7 @@ }, "source": [ "### `None`: ikke-flyttende manglende data\n", - "Siden `None` kommer fra Python, kan det ikke brukes i NumPy- og pandas-arrays som ikke har datatypen `'object'`. Husk at NumPy-arrays (og datastrukturene i pandas) kun kan inneholde én type data. Dette er det som gir dem deres enorme kraft for storskala data- og beregningsarbeid, men det begrenser også fleksibiliteten deres. Slike arrays må oppgradere til den \"laveste fellesnevneren,\" datatypen som kan omfatte alt i arrayet. Når `None` er i arrayet, betyr det at du jobber med Python-objekter.\n", + "Siden `None` kommer fra Python, kan det ikke brukes i NumPy- og pandas-arrays som ikke har datatypen `'object'`. Husk at NumPy-arrays (og datastrukturene i pandas) kun kan inneholde én type data. Dette er det som gir dem deres enorme kraft for storskala data- og beregningsarbeid, men det begrenser også fleksibiliteten deres. Slike arrays må oppgradere til den \"laveste fellesnevneren,\" datatypen som kan omfatte alt i arrayet. Når `None` er i arrayet, betyr det at du arbeider med Python-objekter.\n", "\n", "For å se dette i praksis, vurder følgende eksempel-array (merk `dtype` for det):\n" ] @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Realiteten med opphevede datatyper fører med seg to bivirkninger. For det første vil operasjoner utføres på nivået av tolket Python-kode i stedet for kompilert NumPy-kode. I praksis betyr dette at alle operasjoner som involverer `Series` eller `DataFrames` med `None` i seg, vil være tregere. Selv om du sannsynligvis ikke vil merke dette ytelsestapet, kan det bli et problem for store datasett.\n", + "Realiteten med opphøyde datatyper medfører to bivirkninger. For det første vil operasjoner utføres på nivået av tolket Python-kode i stedet for kompilert NumPy-kode. I praksis betyr dette at alle operasjoner som involverer `Series` eller `DataFrames` med `None` i seg vil være tregere. Selv om du sannsynligvis ikke vil merke denne ytelsespåvirkningen, kan det bli et problem for store datasett.\n", "\n", - "Den andre bivirkningen stammer fra den første. Fordi `None` i hovedsak trekker `Series` eller `DataFrame`s tilbake til den grunnleggende Python-verdenen, vil bruk av NumPy/pandas-aggregasjoner som `sum()` eller `min()` på arrays som inneholder en ``None``-verdi generelt føre til en feil:\n" + "Den andre bivirkningen stammer fra den første. Fordi `None` i hovedsak trekker `Series` eller `DataFrames` tilbake til den vanlige Python-verdenen, vil bruk av NumPy/pandas-aggregeringer som `sum()` eller `min()` på arrays som inneholder en ``None``-verdi generelt føre til en feil:\n" ] }, { @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**Viktig poeng**: Addisjon (og andre operasjoner) mellom heltall og `None`-verdier er udefinert, noe som kan begrense hva du kan gjøre med datasett som inneholder dem.\n" + ] }, { "cell_type": "markdown", @@ -707,7 +709,7 @@ "source": [ "### `NaN`: manglende flyttallsverdier\n", "\n", - "I motsetning til `None` støtter NumPy (og dermed pandas) `NaN` for sine raske, vektoriserte operasjoner og ufuncs. Den dårlige nyheten er at enhver aritmetikk utført på `NaN` alltid resulterer i `NaN`. For eksempel:\n" + "I motsetning til `None` støtter NumPy (og dermed pandas) `NaN` for sine raske, vektoriserte operasjoner og ufuncs. Den dårlige nyheten er at enhver aritmetisk operasjon utført på `NaN` alltid resulterer i `NaN`. For eksempel:\n" ] }, { @@ -770,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Den gode nyheten: aggregeringer som kjøres på matriser med `NaN` i dem gir ikke feil. Den dårlige nyheten: resultatene er ikke alltid like nyttige:\n" + "Den gode nyheten: aggregeringer som kjøres på matriser med `NaN` i dem gir ikke feil. Den dårlige nyheten: resultatene er ikke jevnt nyttige:\n" ] }, { @@ -806,7 +808,9 @@ "metadata": { "id": "nhlnNJT7gRr_" }, - "source": [] + "source": [ + "### Øvelse:\n" + ] }, { "cell_type": "code", @@ -826,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "Husk: `NaN` er kun for manglende flyttallsverdier; det finnes ingen `NaN`-ekvivalent for heltall, strenger eller boolske verdier.\n" + ] }, { "cell_type": "markdown", @@ -875,7 +881,9 @@ "metadata": { "id": "WklCzqb8gRsB" }, - "source": [] + "source": [ + "### Øvelse:\n" + ] }, { "cell_type": "code", @@ -898,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "I prosessen med å oppgradere datatyper for å etablere datalikhet i `Series` og `DataFrame`s, vil pandas villig bytte mellom manglende verdier som `None` og `NaN`. På grunn av denne designfunksjonen kan det være nyttig å tenke på `None` og `NaN` som to forskjellige varianter av \"null\" i pandas. Faktisk reflekterer noen av de sentrale metodene du vil bruke for å håndtere manglende verdier i pandas denne ideen i navnene deres:\n", + "I prosessen med å oppgradere datatyper for å etablere datahomogenitet i `Series` og `DataFrame`s, vil pandas villig bytte manglende verdier mellom `None` og `NaN`. På grunn av denne designfunksjonen kan det være nyttig å tenke på `None` og `NaN` som to forskjellige varianter av \"null\" i pandas. Faktisk reflekterer noen av de grunnleggende metodene du vil bruke for å håndtere manglende verdier i pandas denne ideen i navnene sine:\n", "\n", "- `isnull()`: Genererer en boolsk maske som indikerer manglende verdier\n", "- `notnull()`: Motsatt av `isnull()`\n", "- `dropna()`: Returnerer en filtrert versjon av dataene\n", - "- `fillna()`: Returnerer en kopi av dataene med manglende verdier fylt inn eller estimert\n", + "- `fillna()`: Returnerer en kopi av dataene med manglende verdier fylt eller imputert\n", "\n", - "Disse er viktige metoder å mestre og bli komfortabel med, så la oss gå gjennom hver av dem i litt mer detalj.\n" + "Dette er viktige metoder å mestre og bli komfortabel med, så la oss gå gjennom dem hver for seg i litt mer detalj.\n" ] }, { @@ -916,8 +924,8 @@ "source": [ "### Oppdage nullverdier\n", "\n", - "Nå som vi har forstått viktigheten av manglende verdier, må vi oppdage dem i datasettet vårt før vi håndterer dem. \n", - "Både `isnull()` og `notnull()` er dine primære metoder for å oppdage nullverdier. Begge returnerer boolske masker over dataene dine.\n" + "Nå som vi har forstått viktigheten av manglende verdier, må vi oppdage dem i datasettet vårt før vi håndterer dem. \n", + "Både `isnull()` og `notnull()` er de primære metodene for å oppdage nullverdier. Begge returnerer Boolean-masker over dataene dine.\n" ] }, { @@ -970,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Se nøye på resultatet. Er det noe som overrasker deg? Selv om `0` er en aritmetisk null, er det likevel et fullverdig heltall, og pandas behandler det som sådan. `''` er litt mer subtilt. Selv om vi brukte det i Seksjon 1 for å representere en tom strengverdi, er det likevel et strengobjekt og ikke en representasjon av null slik pandas ser det.\n", + "Se nøye på resultatet. Er det noe som overrasker deg? Selv om `0` er en aritmetisk null, er det likevel et fullverdig heltall, og pandas behandler det som sådan. `''` er litt mer subtilt. Selv om vi brukte det i Seksjon 1 for å representere en tom strengverdi, er det fortsatt et strengobjekt og ikke en representasjon av null slik pandas ser det.\n", "\n", - "La oss nå snu dette rundt og bruke disse metodene på en måte som ligner mer på hvordan du vil bruke dem i praksis. Du kan bruke boolske masker direkte som en ``Series``- eller ``DataFrame``-indeks, noe som kan være nyttig når du prøver å jobbe med isolerte manglende (eller tilstedeværende) verdier.\n", + "La oss nå snu dette rundt og bruke disse metodene på en måte som ligner mer på hvordan du vil bruke dem i praksis. Du kan bruke boolske masker direkte som en ``Series``- eller ``DataFrame``-indeks, noe som kan være nyttig når du prøver å jobbe med isolerte manglende (eller eksisterende) verdier.\n", "\n", - "Hvis vi ønsker det totale antallet manglende verdier, kan vi bare summere masken som produseres av `isnull()`-metoden.\n" + "Hvis vi vil ha det totale antallet manglende verdier, kan vi bare gjøre en summering over masken som produseres av `isnull()`-metoden.\n" ] }, { @@ -1008,7 +1016,9 @@ "metadata": { "id": "PlBqEo3mgRsC" }, - "source": [] + "source": [ + "### Øvelse:\n" + ] }, { "cell_type": "code", @@ -1029,7 +1039,9 @@ "metadata": { "id": "D_jWN7mHgRsD" }, - "source": [] + "source": [ + "**Viktig poeng**: Både `isnull()`- og `notnull()`-metodene gir lignende resultater når du bruker dem i DataFrames: de viser resultatene og indeksen til disse resultatene, noe som vil hjelpe deg enormt når du jobber med dataene dine.\n" + ] }, { "cell_type": "markdown", @@ -1039,18 +1051,18 @@ "source": [ "### Håndtering av manglende data\n", "\n", - "> **Læringsmål:** Etter denne delen skal du vite hvordan og når du bør erstatte eller fjerne nullverdier fra DataFrames.\n", + "> **Læringsmål:** Etter denne delen bør du vite hvordan og når du skal erstatte eller fjerne nullverdier fra DataFrames.\n", "\n", - "Maskinlæringsmodeller kan ikke håndtere manglende data direkte. Derfor må vi ta hånd om disse manglende verdiene før vi sender dataene inn i modellen.\n", + "Maskinlæringsmodeller kan ikke håndtere manglende data på egen hånd. Derfor må vi ta oss av disse manglende verdiene før vi sender dataene inn i modellen.\n", "\n", - "Hvordan manglende data håndteres innebærer subtile avveininger, og kan påvirke både den endelige analysen og resultater i virkelige situasjoner.\n", + "Hvordan manglende data håndteres innebærer subtile avveininger, og kan påvirke din endelige analyse og resultater i virkeligheten.\n", "\n", "Det finnes hovedsakelig to måter å håndtere manglende data på:\n", "\n", "1. Slette raden som inneholder den manglende verdien\n", "2. Erstatte den manglende verdien med en annen verdi\n", "\n", - "Vi vil diskutere begge disse metodene og deres fordeler og ulemper i detalj.\n" + "Vi skal diskutere begge disse metodene og deres fordeler og ulemper i detalj.\n" ] }, { @@ -1061,9 +1073,9 @@ "source": [ "### Fjerne nullverdier\n", "\n", - "Mengden data vi gir til modellen vår har en direkte innvirkning på ytelsen. Å fjerne nullverdier betyr at vi reduserer antall datapunkter, og dermed reduserer størrelsen på datasettet. Derfor er det lurt å fjerne rader med nullverdier når datasettet er ganske stort.\n", + "Mengden data vi gir til modellen vår har direkte innvirkning på ytelsen. Å fjerne nullverdier betyr at vi reduserer antall datapunkter, og dermed reduserer størrelsen på datasettet. Derfor er det anbefalt å fjerne rader med nullverdier når datasettet er ganske stort.\n", "\n", - "En annen situasjon kan være at en bestemt rad eller kolonne har mange manglende verdier. Da kan de fjernes fordi de ikke vil tilføre særlig verdi til analysen vår, ettersom mesteparten av dataene mangler for den raden/kolonnen.\n", + "En annen situasjon kan være at en bestemt rad eller kolonne har mange manglende verdier. Da kan de fjernes fordi de ikke vil tilføre mye verdi til analysen vår, ettersom mesteparten av dataene mangler for den raden/kolonnen.\n", "\n", "I tillegg til å identifisere manglende verdier, gir pandas en praktisk måte å fjerne nullverdier fra `Series` og `DataFrame`s. For å se dette i praksis, la oss gå tilbake til `example3`. Funksjonen `DataFrame.dropna()` hjelper med å fjerne rader med nullverdier.\n" ] @@ -1104,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "Merk at dette skal se ut som resultatet fra `example3[example3.notnull()]`. Forskjellen her er at, i stedet for bare å indeksere på de maskerte verdiene, har `dropna` fjernet de manglende verdiene fra `Series`-objektet `example3`.\n", + "Merk at dette bør se ut som resultatet fra `example3[example3.notnull()]`. Forskjellen her er at, i stedet for bare å indeksere på de maskerte verdiene, har `dropna` fjernet de manglende verdiene fra `Series` `example3`.\n", "\n", - "Siden DataFrames har to dimensjoner, gir de flere muligheter for å fjerne data.\n" + "Siden DataFrames har to dimensjoner, gir de flere alternativer for å fjerne data.\n" ] }, { @@ -1198,7 +1210,7 @@ "source": [ "(La du merke til at pandas oppgraderte to av kolonnene til flyttall for å håndtere `NaN`-verdiene?)\n", "\n", - "Du kan ikke fjerne en enkelt verdi fra en `DataFrame`, så du må fjerne hele rader eller kolonner. Avhengig av hva du jobber med, kan det være at du ønsker å gjøre det ene eller det andre, og derfor gir pandas deg alternativer for begge deler. Fordi kolonner generelt representerer variabler og rader representerer observasjoner i dataanalyse, er det mer sannsynlig at du fjerner rader med data. Standardinnstillingen for `dropna()` er å fjerne alle rader som inneholder noen nullverdier:\n" + "Du kan ikke fjerne en enkelt verdi fra en `DataFrame`, så du må fjerne hele rader eller kolonner. Avhengig av hva du gjør, kan det være aktuelt å gjøre det ene eller det andre, og derfor gir pandas deg alternativer for begge. Siden kolonner vanligvis representerer variabler og rader representerer observasjoner innen dataanalyse, er det mer sannsynlig at du fjerner rader med data; standardinnstillingen for `dropna()` er å fjerne alle rader som inneholder noen nullverdier:\n" ] }, { @@ -1445,10 +1457,10 @@ }, "source": [ "> Viktige punkter: \n", - "1. Å fjerne null-verdier er en god idé bare hvis datasettet er stort nok. \n", + "1. Å fjerne nullverdier er en god idé bare hvis datasettet er stort nok. \n", "2. Hele rader eller kolonner kan fjernes hvis mesteparten av dataene mangler. \n", - "3. Metoden `DataFrame.dropna(axis=)` hjelper med å fjerne null-verdier. Argumentet `axis` angir om rader eller kolonner skal fjernes. \n", - "4. Argumentet `how` kan også brukes. Som standard er det satt til `any`. Det betyr at det kun fjerner de radene/kolonnene som inneholder noen null-verdier. Det kan settes til `all` for å spesifisere at vi kun fjerner de radene/kolonnene hvor alle verdier er null. \n" + "3. Metoden `DataFrame.dropna(axis=)` hjelper med å fjerne nullverdier. Argumentet `axis` angir om rader eller kolonner skal fjernes. \n", + "4. Argumentet `how` kan også brukes. Som standard er det satt til `any`. Det betyr at kun de radene/kolonnene som inneholder noen nullverdier fjernes. Det kan settes til `all` for å spesifisere at vi kun vil fjerne de radene/kolonnene der alle verdier er null. \n" ] }, { @@ -1456,7 +1468,9 @@ "metadata": { "id": "oXXSfQFHgRsF" }, - "source": [] + "source": [ + "### Øvelse:\n" + ] }, { "cell_type": "code", @@ -1478,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "`thresh`-parameteren gir deg mer finjustert kontroll: du angir antall *ikke-null* verdier som en rad eller kolonne må ha for å beholdes:\n" + "`thresh`-parameteren gir deg mer detaljert kontroll: du angir antall *ikke-null* verdier som en rad eller kolonne må ha for å beholdes:\n" ] }, { @@ -1552,7 +1566,9 @@ "metadata": { "id": "fmSFnzZegRsG" }, - "source": [] + "source": [ + "Her er den første og siste raden fjernet, fordi de inneholder kun to ikke-null verdier.\n" + ] }, { "cell_type": "markdown", @@ -1562,9 +1578,9 @@ "source": [ "### Fylle inn nullverdier\n", "\n", - "Noen ganger gir det mening å fylle inn manglende verdier med verdier som kan være gyldige. Det finnes flere teknikker for å fylle inn nullverdier. Den første er å bruke domenekunnskap (kunnskap om emnet datasettet er basert på) for å på en eller annen måte anslå de manglende verdiene.\n", + "Noen ganger kan det være fornuftig å fylle inn manglende verdier med verdier som kan være gyldige. Det finnes flere teknikker for å fylle inn nullverdier. Den første er å bruke domenekunnskap (kunnskap om emnet som datasettet er basert på) for å på en eller annen måte anslå de manglende verdiene.\n", "\n", - "Du kan bruke `isnull` for å gjøre dette direkte, men det kan være tidkrevende, spesielt hvis du har mange verdier som må fylles inn. Siden dette er en så vanlig oppgave innen datavitenskap, tilbyr pandas `fillna`, som returnerer en kopi av `Series` eller `DataFrame` der de manglende verdiene er erstattet med en verdi du velger. La oss lage et annet eksempel på en `Series` for å se hvordan dette fungerer i praksis.\n" + "Du kan bruke `isnull` for å gjøre dette direkte, men det kan være tidkrevende, spesielt hvis du har mange verdier å fylle inn. Siden dette er en så vanlig oppgave innen datavitenskap, tilbyr pandas `fillna`, som returnerer en kopi av `Series` eller `DataFrame` der de manglende verdiene er erstattet med en verdi du velger. La oss lage et annet eksempel på `Series` for å se hvordan dette fungerer i praksis.\n" ] }, { @@ -1573,12 +1589,12 @@ "id": "CE8S7louLezV" }, "source": [ - "### Kategoriske data (ikke-numeriske)\n", - "La oss først se på ikke-numeriske data. I datasett har vi kolonner med kategoriske data, f.eks. Kjønn, Sant eller Usant osv.\n", + "### Kategoriske data (Ikke-numeriske)\n", + "La oss først se på ikke-numeriske data. I datasett har vi kolonner med kategoriske data, for eksempel Kjønn, Sant eller Usant osv.\n", "\n", - "I de fleste av disse tilfellene erstatter vi manglende verdier med `modus` for kolonnen. Si at vi har 100 datapunkter, og 90 har sagt Sant, 8 har sagt Usant, og 2 har ikke fylt ut. Da kan vi fylle de 2 med Sant, med tanke på hele kolonnen.\n", + "I de fleste tilfeller erstatter vi manglende verdier med `modus` for kolonnen. Si at vi har 100 datapunkter, hvor 90 har sagt Sant, 8 har sagt Usant, og 2 har ikke fylt ut. Da kan vi fylle de 2 med Sant, basert på hele kolonnen.\n", "\n", - "Igjen, her kan vi bruke domenekunnskap. La oss se på et eksempel på utfylling med modus.\n" + "Igjen kan vi bruke domenekunnskap her. La oss se på et eksempel der vi fyller med modus.\n" ] }, { @@ -1683,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "La oss først finne modus før vi fyller inn `None`-verdien med modus.\n" + ] }, { "cell_type": "code", @@ -1718,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Så, vi vil erstatte None med True\n" + ] }, { "cell_type": "code", @@ -1827,7 +1847,9 @@ "metadata": { "id": "SktitLxxOR16" }, - "source": [] + "source": [ + "Som vi kan se, har nullverdien blitt erstattet. Det er unødvendig å si at vi kunne ha skrevet hva som helst i stedet for `'True'`, og det ville ha blitt substituert.\n" + ] }, { "cell_type": "markdown", @@ -1836,16 +1858,16 @@ }, "source": [ "### Numeriske Data\n", - "La oss nå se på numeriske data. Her har vi to vanlige metoder for å erstatte manglende verdier:\n", + "Nå, når det gjelder numeriske data. Her har vi to vanlige måter å erstatte manglende verdier på:\n", "\n", - "1. Erstatte med medianen av raden \n", - "2. Erstatte med gjennomsnittet av raden \n", + "1. Erstatte med medianen av raden\n", + "2. Erstatte med gjennomsnittet av raden\n", "\n", - "Vi erstatter med medianen i tilfeller med skjev data som inneholder uteliggere. Dette er fordi medianen er robust mot uteliggere.\n", + "Vi erstatter med medianen i tilfelle skjev data med uteliggere. Dette er fordi medianen er robust mot uteliggere.\n", "\n", - "Når dataene er normaliserte, kan vi bruke gjennomsnittet, ettersom gjennomsnitt og median i slike tilfeller vil være ganske like.\n", + "Når dataene er normalisert, kan vi bruke gjennomsnittet, siden gjennomsnittet og medianen i så fall vil være ganske like.\n", "\n", - "Først, la oss ta en kolonne som er normalfordelt og fylle inn de manglende verdiene med gjennomsnittet av kolonnen.\n" + "La oss først ta en kolonne som er normalt fordelt og fylle den manglende verdien med gjennomsnittet av kolonnen.\n" ] }, { @@ -1985,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Fyller med gjennomsnitt\n" + ] }, { "cell_type": "code", @@ -2084,7 +2108,9 @@ "metadata": { "id": "CwpVFCrPTC5z" }, - "source": [] + "source": [ + "Som vi kan se, har den manglende verdien blitt erstattet med gjennomsnittet.\n" + ] }, { "cell_type": "markdown", @@ -2092,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "La oss nå prøve en annen dataframe, og denne gangen vil vi erstatte None-verdiene med medianen av kolonnen.\n" + "La oss prøve en annen dataframe, og denne gangen vil vi erstatte None-verdiene med medianen av kolonnen.\n" ] }, { @@ -2232,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Fylling med median\n" + ] }, { "cell_type": "code", @@ -2374,7 +2402,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "Du kan fylle alle nulloppføringer med en enkelt verdi, som `0`:\n" + "Du kan fylle alle nullverdiene med en enkelt verdi, som `0`:\n" ] }, { @@ -2416,10 +2444,10 @@ }, "source": [ "> Viktige punkter:\n", - "1. Å fylle inn manglende verdier bør gjøres enten når det er lite data eller når det finnes en strategi for å fylle inn de manglende verdiene. \n", - "2. Domenekunnskap kan brukes til å fylle inn manglende verdier ved å anslå dem. \n", - "3. For kategoriske data blir manglende verdier som oftest erstattet med modus for kolonnen. \n", - "4. For numeriske data blir manglende verdier vanligvis fylt inn med gjennomsnittet (for normaliserte datasett) eller medianen for kolonnene. \n" + "1. Å fylle inn manglende verdier bør gjøres enten når det er lite data eller når det finnes en strategi for å fylle inn de manglende verdiene.\n", + "2. Domenekunnskap kan brukes til å fylle inn manglende verdier ved å anslå dem.\n", + "3. For kategoriske data blir manglende verdier ofte erstattet med modus for kolonnen.\n", + "4. For numeriske data blir manglende verdier vanligvis fylt inn med gjennomsnittet (for normaliserte datasett) eller medianen for kolonnene.\n" ] }, { @@ -2427,7 +2455,9 @@ "metadata": { "id": "FI9MmqFJgRsH" }, - "source": [] + "source": [ + "### Øvelse:\n" + ] }, { "cell_type": "code", @@ -2447,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "Du kan **fremfylle** nullverdier, som vil si å bruke den siste gyldige verdien til å fylle en null:\n" + ] }, { "cell_type": "code", @@ -2487,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Du kan også **back-fylle** for å propagere den neste gyldige verdien bakover for å fylle en null:\n" + "Du kan også **bakfylle** for å propagere den neste gyldige verdien bakover for å fylle en null:\n" ] }, { @@ -2701,14 +2733,18 @@ "metadata": { "id": "ZeMc-I1EgRsI" }, - "source": [] + "source": [ + "Legg merke til at når en tidligere verdi ikke er tilgjengelig for fremfylling, forblir nullverdien.\n" + ] }, { "cell_type": "markdown", "metadata": { "id": "eeAoOU0RgRsJ" }, - "source": [] + "source": [ + "### Øvelse:\n" + ] }, { "cell_type": "code", @@ -2731,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Du kan være kreativ med hvordan du bruker `fillna`. For eksempel, la oss se på `example4` igjen, men denne gangen fyller vi de manglende verdiene med gjennomsnittet av alle verdiene i `DataFrame`:\n" + "Du kan være kreativ med hvordan du bruker `fillna`. For eksempel, la oss se på `example4` igjen, men denne gangen la oss fylle de manglende verdiene med gjennomsnittet av alle verdiene i `DataFrame`:\n" ] }, { @@ -2822,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Merk at kolonne 3 fortsatt mangler verdier: standardretningen er å fylle verdier radvis.\n", + "Legg merke til at kolonne 3 fortsatt mangler verdier: standardretningen er å fylle verdier radvis.\n", "\n", - "> **Hovedpoeng:** Det finnes flere måter å håndtere manglende verdier i datasettene dine på. Den spesifikke strategien du velger (å fjerne dem, erstatte dem, eller hvordan du erstatter dem) bør styres av de spesifikke egenskapene til dataene. Du vil utvikle en bedre forståelse for hvordan du håndterer manglende verdier jo mer du jobber med og analyserer datasett.\n" + "> **Hovedpoeng:** Det finnes flere måter å håndtere manglende verdier i datasettene dine. Den spesifikke strategien du velger (fjerne dem, erstatte dem, eller hvordan du erstatter dem) bør styres av detaljene i det aktuelle datasettet. Du vil utvikle en bedre forståelse for hvordan du håndterer manglende verdier jo mer du arbeider med og interagerer med datasett.\n" ] }, { @@ -2835,7 +2871,7 @@ "source": [ "### Koding av kategoriske data\n", "\n", - "Maskinlæringsmodeller håndterer kun tall og enhver form for numeriske data. De kan ikke skille mellom Ja og Nei, men de kan skille mellom 0 og 1. Så, etter at vi har fylt inn de manglende verdiene, må vi kode de kategoriske dataene til en numerisk form som modellen kan forstå.\n", + "Maskinlæringsmodeller håndterer kun tall og enhver form for numerisk data. De kan ikke skille mellom et Ja og et Nei, men de kan skille mellom 0 og 1. Så, etter at vi har fylt inn de manglende verdiene, må vi kode de kategoriske dataene til en numerisk form slik at modellen kan forstå dem.\n", "\n", "Koding kan gjøres på to måter. Vi skal diskutere dem videre.\n" ] @@ -2848,7 +2884,7 @@ "source": [ "**ETIKETTKODING**\n", "\n", - "Etikettkoding innebærer i hovedsak å konvertere hver kategori til et tall. For eksempel, si at vi har et datasett med flypassasjerer, og det finnes en kolonne som inneholder deres klasse blant følgende ['business class', 'economy class', 'first class']. Hvis etikettkoding utføres på dette, vil det bli transformert til [0,1,2]. La oss se et eksempel via kode. Siden vi skal lære `scikit-learn` i de kommende notatbøkene, vil vi ikke bruke det her.\n" + "Etikettkoding innebærer å konvertere hver kategori til et tall. For eksempel, si at vi har et datasett med flypassasjerer, og det finnes en kolonne som inneholder deres klasse blant følgende ['business class', 'economy class', 'first class']. Hvis etikettkoding utføres på dette, vil det bli transformert til [0,1,2]. La oss se et eksempel via kode. Siden vi skal lære `scikit-learn` i de kommende notatbøkene, vil vi ikke bruke det her.\n" ] }, { @@ -2956,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "For å utføre etikettkoding på den første kolonnen, må vi først beskrive en mapping fra hver klasse til et tall, før vi erstatter\n" + "For å utføre etikettkoding på den første kolonnen, må vi først beskrive en mapping fra hver klasse til et nummer, før vi erstatter.\n" ] }, { @@ -3058,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Som vi kan se, stemmer resultatet med det vi forventet. Så, når bruker vi etikettkoding? Etikettkoding brukes i ett eller begge av følgende tilfeller:\n", + "Som vi kan se, samsvarer resultatet med det vi trodde ville skje. Så, når bruker vi etikettkoding? Etikettkoding brukes i ett eller begge av følgende tilfeller:\n", "1. Når antallet kategorier er stort\n", - "2. Når kategoriene har en rekkefølge.\n" + "2. Når kategoriene er i rekkefølge.\n" ] }, { @@ -3071,9 +3107,9 @@ "source": [ "**ONE HOT ENCODING**\n", "\n", - "En annen type koding er One Hot Encoding. I denne typen koding blir hver kategori i kolonnen lagt til som en separat kolonne, og hver datapunkt får enten 0 eller 1 basert på om det inneholder den kategorien. Så, hvis det er n forskjellige kategorier, vil n kolonner bli lagt til i datasettet.\n", + "En annen type koding er One Hot Encoding. I denne typen koding blir hver kategori i kolonnen lagt til som en egen kolonne, og hver datapunkt får enten 0 eller 1 avhengig av om det inneholder den kategorien. Så hvis det finnes n forskjellige kategorier, vil n kolonner bli lagt til i datasettet.\n", "\n", - "For eksempel, la oss ta det samme eksempelet med flyklasser. Kategoriene var: ['business class', 'economy class', 'first class']. Så, hvis vi utfører one hot encoding, vil følgende tre kolonner bli lagt til i datasettet: ['class_business class', 'class_economy class', 'class_first class'].\n" + "For eksempel, la oss ta det samme eksempelet med flyklasser. Kategoriene var: ['business class', 'economy class', 'first class']. Hvis vi utfører One Hot Encoding, vil følgende tre kolonner bli lagt til i datasettet: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3306,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Hver én-kodet kolonne inneholder 0 eller 1, som angir om den kategorien eksisterer for det datapunktet.\n" + "Hver én-hot kodet kolonne inneholder 0 eller 1, som angir om den kategorien eksisterer for det datapunktet.\n" ] }, { @@ -3328,8 +3364,8 @@ }, "source": [ "> Viktige punkter:\n", - "1. Koding brukes for å konvertere ikke-numeriske data til numeriske data.\n", - "2. Det finnes to typer koding: Etikettkoding og One Hot-koding, som begge kan utføres basert på datasetets behov.\n" + "1. Koding gjøres for å konvertere ikke-numeriske data til numeriske data.\n", + "2. Det finnes to typer koding: Label-koding og One Hot-koding, som begge kan utføres basert på kravene til datasettet.\n" ] }, { @@ -3340,7 +3376,7 @@ "source": [ "## Fjerne dupliserte data\n", "\n", - "> **Læringsmål:** Etter å ha fullført denne underseksjonen, bør du være komfortabel med å identifisere og fjerne dupliserte verdier fra DataFrames.\n", + "> **Læringsmål:** Etter denne delen bør du være komfortabel med å identifisere og fjerne dupliserte verdier fra DataFrames.\n", "\n", "I tillegg til manglende data, vil du ofte støte på dupliserte data i virkelige datasett. Heldigvis tilbyr pandas en enkel måte å oppdage og fjerne dupliserte oppføringer på.\n" ] @@ -3353,7 +3389,7 @@ "source": [ "### Identifisere duplikater: `duplicated`\n", "\n", - "Du kan enkelt finne dupliserte verdier ved å bruke metoden `duplicated` i pandas, som returnerer en boolsk maske som indikerer om en oppføring i en `DataFrame` er en duplikat av en tidligere oppføring. La oss lage et annet eksempel på en `DataFrame` for å se dette i praksis.\n" + "Du kan enkelt finne duplikatverdier ved å bruke `duplicated`-metoden i pandas, som returnerer en boolsk maske som indikerer om en oppføring i en `DataFrame` er en duplikat av en tidligere. La oss lage et annet eksempel på en `DataFrame` for å se dette i praksis.\n" ] }, { @@ -3566,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Både `duplicated` og `drop_duplicates` vurderer som standard alle kolonner, men du kan spesifisere at de kun skal undersøke en delmengde av kolonnene i din `DataFrame`:\n" + "Både `duplicated` og `drop_duplicates` vurderer som standard alle kolonner, men du kan spesifisere at de kun skal undersøke et delsett av kolonner i din `DataFrame`:\n" ] }, { @@ -3642,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Hovedpoeng:** Fjerning av dupliserte data er en essensiell del av nesten alle datavitenskapsprosjekter. Dupliserte data kan endre resultatene av analysene dine og gi deg unøyaktige resultater!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Kvalitetssjekk av data fra virkeligheten\n", + "\n", + "> **Læringsmål:** Etter denne delen bør du være komfortabel med å oppdage og korrigere vanlige kvalitetsproblemer i data fra virkeligheten, inkludert inkonsistente kategoriske verdier, unormale numeriske verdier (uteliggere) og dupliserte enheter med variasjoner.\n", + "\n", + "Selv om manglende verdier og eksakte duplikater er vanlige problemer, inneholder datasett fra virkeligheten ofte mer subtile utfordringer:\n", + "\n", + "1. **Inkonsistente kategoriske verdier**: Den samme kategorien stavet forskjellig (f.eks. \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Unormale numeriske verdier**: Ekstreme uteliggere som indikerer feil ved dataregistrering (f.eks. alder = 999)\n", + "3. **Nesten-dupliserte rader**: Poster som representerer den samme enheten med små variasjoner\n", + "\n", + "La oss utforske teknikker for å oppdage og håndtere disse problemene.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Lage et eksempel på et \"skittent\" datasett\n", + "\n", + "Først, la oss lage et eksempel på et datasett som inneholder de typene problemer vi ofte møter i virkelige data:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Oppdage inkonsekvente kategoriske verdier\n", + "\n", + "Legg merke til at `country`-kolonnen har flere representasjoner for de samme landene. La oss identifisere disse inkonsekvensene:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Standardisering av kategoriske verdier\n", + "\n", + "Vi kan lage en mapping for å standardisere disse verdiene. En enkel metode er å konvertere til små bokstaver og lage en mapping-dictionary:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternativ: Bruke Fuzzy Matching**\n", + "\n", + "For mer komplekse tilfeller kan vi bruke fuzzy strengmatching med `rapidfuzz`-biblioteket for automatisk å oppdage lignende strenger:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Oppdage unormale numeriske verdier (uteliggere)\n", + "\n", + "Når vi ser på `age`-kolonnen, har vi noen mistenkelige verdier som 199 og -5. La oss bruke statistiske metoder for å oppdage disse uteliggerne.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Bruk av IQR (Interkvartilavstand) Metoden\n", + "\n", + "IQR-metoden er en robust statistisk teknikk for å oppdage avvik som er mindre følsom for ekstreme verdier:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Bruke Z-score-metoden\n", + "\n", + "Z-score-metoden identifiserer avvik basert på standardavvik fra gjennomsnittet:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Håndtering av avvik\n", + "\n", + "Når avvik er oppdaget, kan de håndteres på flere måter:\n", + "1. **Fjern**: Slett rader med avvik (hvis de er feil)\n", + "2. **Begrens**: Erstatt med grenseverdier\n", + "3. **Erstatt med NaN**: Behandle som manglende data og bruk imputeringsteknikker\n", + "4. **Behold**: Hvis de er legitime ekstreme verdier\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Oppdage nesten-identiske rader\n", + "\n", + "Legg merke til at datasettet vårt har flere oppføringer for \"John Smith\" med litt forskjellige verdier. La oss identifisere potensielle duplikater basert på navnelikhet.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Finne nesten-duplikater med uskarp matching\n", + "\n", + "For mer avansert duplikatdeteksjon kan vi bruke uskarp matching for å finne lignende navn:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Håndtering av duplikater\n", + "\n", + "Når du har identifisert dem, må du bestemme hvordan du skal håndtere duplikater:\n", + "1. **Behold den første forekomsten**: Bruk `drop_duplicates(keep='first')`\n", + "2. **Behold den siste forekomsten**: Bruk `drop_duplicates(keep='last')`\n", + "3. **Aggregere informasjon**: Kombiner informasjon fra dupliserte rader\n", + "4. **Manuell gjennomgang**: Merk for menneskelig gjennomgang\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Sammendrag: Fullstendig Datavaskingsprosess\n", + "\n", + "La oss sette alt sammen til en omfattende prosess for datarensing:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Utfordringsøvelse\n", + "\n", + "Nå er det din tur! Nedenfor er en ny rad med data som har flere kvalitetsproblemer. Kan du:\n", + "\n", + "1. Identifisere alle problemene i denne raden\n", + "2. Skrive kode for å rydde opp i hvert problem\n", + "3. Legge til den ryddede raden i datasettet\n", + "\n", + "Her er de problematiske dataene:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Viktige punkter\n", + "\n", + "1. **Ulike kategorier** er vanlig i virkelige data. Sjekk alltid unike verdier og standardiser dem ved hjelp av kartlegging eller uskarp matching.\n", + "\n", + "2. **Avvik** kan ha stor innvirkning på analysen din. Bruk domenekunnskap kombinert med statistiske metoder (IQR, Z-score) for å oppdage dem.\n", + "\n", + "3. **Nesten-duplikater** er vanskeligere å oppdage enn eksakte duplikater. Vurder å bruke uskarp matching og normalisere data (små bokstaver, fjerne mellomrom) for å identifisere dem.\n", + "\n", + "4. **Datavask er en iterativ prosess**. Du må kanskje bruke flere teknikker og gjennomgå resultatene før du ferdigstiller det rensede datasettet.\n", + "\n", + "5. **Dokumenter beslutningene dine**. Hold oversikt over hvilke rengjøringstrinn du har brukt og hvorfor, da dette er viktig for reproduksjon og åpenhet.\n", + "\n", + "> **Beste praksis:** Behold alltid en kopi av de originale \"skitne\" dataene. Aldri overskriv kildefilene dine - lag rensede versjoner med tydelige navnekonvensjoner som `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Ansvarsfraskrivelse**: \nDette dokumentet er oversatt ved hjelp av AI-oversettelsestjenesten [Co-op Translator](https://github.com/Azure/co-op-translator). Selv om vi tilstreber nøyaktighet, vennligst vær oppmerksom på at automatiske oversettelser kan inneholde feil eller unøyaktigheter. Det originale dokumentet på sitt opprinnelige språk bør anses som den autoritative kilden. For kritisk informasjon anbefales profesjonell menneskelig oversettelse. Vi er ikke ansvarlige for eventuelle misforståelser eller feiltolkninger som oppstår ved bruk av denne oversettelsen.\n" + "\n---\n\n**Ansvarsfraskrivelse**: \nDette dokumentet er oversatt ved hjelp av AI-oversettelsestjenesten [Co-op Translator](https://github.com/Azure/co-op-translator). Selv om vi tilstreber nøyaktighet, vær oppmerksom på at automatiserte oversettelser kan inneholde feil eller unøyaktigheter. Det originale dokumentet på sitt opprinnelige språk bør anses som den autoritative kilden. For kritisk informasjon anbefales profesjonell menneskelig oversettelse. Vi er ikke ansvarlige for misforståelser eller feiltolkninger som oppstår ved bruk av denne oversettelsen.\n" ] } ], @@ -3676,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:28:27+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:23:06+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "no" } diff --git a/translations/pa/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/pa/2-Working-With-Data/08-data-preparation/notebook.ipynb index ac84b3cb..58bc0486 100644 --- a/translations/pa/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/pa/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -10,13 +10,13 @@ "\n", "[ਅਸਲ ਨੋਟਬੁੱਕ ਸਰੋਤ *ਡਾਟਾ ਸਾਇੰਸ: ਪਾਇਥਨ ਅਤੇ ਮਸ਼ੀਨ ਲਰਨਿੰਗ ਸਟੂਡੀਓ ਲਈ ਮਸ਼ੀਨ ਲਰਨਿੰਗ ਦਾ ਪਰਿਚਯ ਲੀ ਸਟੌਟ ਦੁਆਰਾ*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", - "## `DataFrame` ਜਾਣਕਾਰੀ ਦੀ ਪੜਚੋਲ\n", + "## `DataFrame` ਜਾਣਕਾਰੀ ਦੀ ਖੋਜ\n", "\n", - "> **ਸਿੱਖਣ ਦਾ ਲਕਸ਼:** ਇਸ ਉਪਵਿਭਾਗ ਦੇ ਅੰਤ ਤੱਕ, ਤੁਸੀਂ pandas DataFrames ਵਿੱਚ ਸਟੋਰ ਕੀਤੇ ਡਾਟੇ ਬਾਰੇ ਆਮ ਜਾਣਕਾਰੀ ਲੱਭਣ ਵਿੱਚ ਸਹੂਲਤ ਮਹਿਸੂਸ ਕਰੋਗੇ।\n", + "> **ਸਿੱਖਣ ਦਾ ਉਦੇਸ਼:** ਇਸ ਉਪਵਿਭਾਗ ਦੇ ਅੰਤ ਤੱਕ, ਤੁਸੀਂ pandas DataFrames ਵਿੱਚ ਸਟੋਰ ਕੀਤੇ ਡਾਟਾ ਬਾਰੇ ਆਮ ਜਾਣਕਾਰੀ ਲੱਭਣ ਵਿੱਚ ਸਹੂਲਤ ਮਹਿਸੂਸ ਕਰੋਗੇ।\n", "\n", - "ਜਦੋਂ ਤੁਸੀਂ pandas ਵਿੱਚ ਆਪਣਾ ਡਾਟਾ ਲੋਡ ਕਰ ਲੈਂਦੇ ਹੋ, ਤਾਂ ਇਹ ਜ਼ਿਆਦਾਤਰ ਸੰਭਾਵਨਾ ਹੈ ਕਿ ਇਹ ਇੱਕ `DataFrame` ਵਿੱਚ ਹੋਵੇਗਾ। ਪਰ, ਜੇ ਤੁਹਾਡੇ `DataFrame` ਵਿੱਚ 60,000 ਕਤਾਰਾਂ ਅਤੇ 400 ਕਾਲਮ ਹਨ, ਤਾਂ ਤੁਸੀਂ ਇਹ ਸਮਝਣਾ ਕਿਵੇਂ ਸ਼ੁਰੂ ਕਰੋਗੇ ਕਿ ਤੁਸੀਂ ਕਿਸ ਨਾਲ ਕੰਮ ਕਰ ਰਹੇ ਹੋ? ਖੁਸ਼ਕਿਸਮਤੀ ਨਾਲ, pandas ਕੁਝ ਸੁਵਿਧਾਜਨਕ ਟੂਲ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ ਜੋ ਇੱਕ `DataFrame` ਬਾਰੇ ਕੁੱਲ ਜਾਣਕਾਰੀ ਦੇਖਣ ਦੇ ਨਾਲ ਨਾਲ ਪਹਿਲੀਆਂ ਕੁਝ ਅਤੇ ਆਖਰੀ ਕੁਝ ਕਤਾਰਾਂ ਨੂੰ ਤੇਜ਼ੀ ਨਾਲ ਦੇਖਣ ਦੀ ਸਹੂਲਤ ਦਿੰਦੇ ਹਨ।\n", + "ਜਦੋਂ ਤੁਸੀਂ pandas ਵਿੱਚ ਆਪਣਾ ਡਾਟਾ ਲੋਡ ਕਰ ਲੈਂਦੇ ਹੋ, ਤਾਂ ਇਹ ਜ਼ਿਆਦਾਤਰ `DataFrame` ਵਿੱਚ ਹੋਵੇਗਾ। ਹਾਲਾਂਕਿ, ਜੇ ਤੁਹਾਡੇ `DataFrame` ਵਿੱਚ 60,000 ਪੰਕਤਾਂ ਅਤੇ 400 ਕਾਲਮ ਹਨ, ਤਾਂ ਤੁਸੀਂ ਇਸ ਨਾਲ ਕੰਮ ਕਰਨ ਦੀ ਸ਼ੁਰੂਆਤ ਕਿਵੇਂ ਕਰਦੇ ਹੋ? ਖੁਸ਼ਕਿਸਮਤੀ ਨਾਲ, pandas ਕੁਝ ਸਹੂਲਤਮੰਦ ਟੂਲ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ ਜੋ `DataFrame` ਬਾਰੇ ਕੁੱਲ ਜਾਣਕਾਰੀ ਦੇਖਣ ਦੇ ਨਾਲ-साथ ਪਹਿਲੀਆਂ ਕੁਝ ਅਤੇ ਆਖਰੀ ਕੁਝ ਪੰਕਤਾਂ ਨੂੰ ਤੇਜ਼ੀ ਨਾਲ ਦੇਖਣ ਦੀ ਸਹੂਲਤ ਦਿੰਦੇ ਹਨ।\n", "\n", - "ਇਸ ਫੰਕਸ਼ਨਾਲਿਟੀ ਦੀ ਪੜਚੋਲ ਕਰਨ ਲਈ, ਅਸੀਂ Python ਦੀ scikit-learn ਲਾਇਬ੍ਰੇਰੀ ਨੂੰ ਇੰਪੋਰਟ ਕਰਾਂਗੇ ਅਤੇ ਇੱਕ ਪ੍ਰਸਿੱਧ ਡਾਟਾਸੈਟ ਦੀ ਵਰਤੋਂ ਕਰਾਂਗੇ ਜੋ ਹਰ ਡਾਟਾ ਸਾਇੰਟਿਸਟ ਸੈਂਕੜੇ ਵਾਰ ਦੇਖ ਚੁੱਕਾ ਹੈ: ਬ੍ਰਿਟਿਸ਼ ਜੀਵ ਵਿਗਿਆਨੀ ਰੋਨਾਲਡ ਫਿਸ਼ਰ ਦਾ *Iris* ਡਾਟਾਸੈਟ, ਜੋ ਉਸਦੇ 1936 ਦੇ ਪੇਪਰ \"ਟੈਕਸੋਨੋਮਿਕ ਸਮੱਸਿਆਵਾਂ ਵਿੱਚ ਕਈ ਮਾਪਦੰਡਾਂ ਦੇ ਉਪਯੋਗ\" ਵਿੱਚ ਵਰਤਿਆ ਗਿਆ ਸੀ:\n" + "ਇਸ ਫੰਕਸ਼ਨਲਿਟੀ ਦੀ ਖੋਜ ਕਰਨ ਲਈ, ਅਸੀਂ ਪਾਇਥਨ scikit-learn ਲਾਇਬ੍ਰੇਰੀ ਨੂੰ ਇੰਪੋਰਟ ਕਰਾਂਗੇ ਅਤੇ ਇੱਕ ਪ੍ਰਸਿੱਧ ਡਾਟਾਸੈਟ ਦੀ ਵਰਤੋਂ ਕਰਾਂਗੇ ਜੋ ਹਰ ਡਾਟਾ ਸਾਇੰਟਿਸਟ ਨੇ ਸੈਂਕੜੇ ਵਾਰ ਦੇਖਿਆ ਹੈ: ਬ੍ਰਿਟਿਸ਼ ਜੀਵ ਵਿਗਿਆਨੀ ਰੋਨਾਲਡ ਫਿਸ਼ਰ ਦਾ *Iris* ਡਾਟਾ ਸੈੱਟ ਜੋ ਉਸਦੇ 1936 ਦੇ ਪੇਪਰ \"The use of multiple measurements in taxonomic problems\" ਵਿੱਚ ਵਰਤਿਆ ਗਿਆ ਸੀ:\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "ਅਸੀਂ `iris_df` ਵੈਰੀਏਬਲ ਵਿੱਚ Iris Dataset ਲੋਡ ਕੀਤਾ ਹੈ। ਡਾਟਾ ਵਿੱਚ ਘੁਸਣ ਤੋਂ ਪਹਿਲਾਂ, ਇਹ ਜਾਣਨਾ ਮਹੱਤਵਪੂਰਨ ਹੋਵੇਗਾ ਕਿ ਸਾਡੇ ਕੋਲ ਕਿੰਨੇ ਡਾਟਾਪੌਇੰਟ ਹਨ ਅਤੇ ਡਾਟਾਸੈੱਟ ਦਾ ਕੁੱਲ ਆਕਾਰ ਕੀ ਹੈ। ਇਹ ਜਾਣਨਾ ਲਾਭਦਾਇਕ ਹੈ ਕਿ ਅਸੀਂ ਕਿੰਨੀ ਮਾਤਰਾ ਦੇ ਡਾਟਾ ਨਾਲ ਨਿਪਟ ਰਹੇ ਹਾਂ।\n" + "ਅਸੀਂ `iris_df` ਵਿੱਚ ਆਇਰਿਸ ਡੇਟਾਸੈੱਟ ਲੋਡ ਕੀਤਾ ਹੈ। ਡੇਟਾ ਵਿੱਚ ਡੁੱਬਣ ਤੋਂ ਪਹਿਲਾਂ, ਇਹ ਜਾਣਨਾ ਮੁਲਵਾਨ ਹੋਵੇਗਾ ਕਿ ਸਾਡੇ ਕੋਲ ਕਿੰਨੇ ਡੇਟਾਪੋਇੰਟ ਹਨ ਅਤੇ ਡੇਟਾਸੈੱਟ ਦਾ ਕੁੱਲ ਆਕਾਰ ਕੀ ਹੈ। ਇਹ ਦੇਖਣਾ ਲਾਭਦਾਇਕ ਹੈ ਕਿ ਅਸੀਂ ਕਿੰਨੇ ਡੇਟਾ ਦੀ ਮਾਤਰਾ ਨਾਲ ਨਿਪਟ ਰਹੇ ਹਾਂ।\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "ਅਸੀਂ 150 ਕਤਾਰਾਂ ਅਤੇ 4 ਕਾਲਮਾਂ ਦੇ ਡਾਟਾ ਨਾਲ ਨਿਪਟ ਰਹੇ ਹਾਂ। ਹਰ ਕਤਾਰ ਇੱਕ ਡਾਟਾਪੌਇੰਟ ਨੂੰ ਦਰਸਾਉਂਦੀ ਹੈ ਅਤੇ ਹਰ ਕਾਲਮ ਡਾਟਾ ਫਰੇਮ ਨਾਲ ਜੁੜੀ ਇੱਕ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਦਰਸਾਉਂਦਾ ਹੈ। ਇਸ ਲਈ, ਮੁਲ਼ ਤੌਰ 'ਤੇ, ਇੱਥੇ 150 ਡਾਟਾਪੌਇੰਟ ਹਨ, ਜਿਨ੍ਹਾਂ ਵਿੱਚੋਂ ਹਰ ਇੱਕ ਵਿੱਚ 4 ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਹਨ।\n", + "ਅਸੀਂ 150 ਪੰਗਤਾਂ ਅਤੇ 4 ਕਤਾਰਾਂ ਦੇ ਡਾਟਾ ਨਾਲ ਨਿਪਟ ਰਹੇ ਹਾਂ। ਹਰ ਪੰਗਤੀ ਇੱਕ ਡਾਟਾਪੌਇੰਟ ਨੂੰ ਦਰਸਾਉਂਦੀ ਹੈ ਅਤੇ ਹਰ ਕਤਾਰ ਡਾਟਾ ਫਰੇਮ ਨਾਲ ਜੁੜੀ ਇੱਕ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਦਰਸਾਉਂਦੀ ਹੈ। ਇਸ ਲਈ, ਮੁਢਲੇ ਤੌਰ 'ਤੇ 150 ਡਾਟਾਪੌਇੰਟ ਹਨ, ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਹਰ ਇੱਕ ਵਿੱਚ 4 ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਹਨ।\n", "\n", - "`shape` ਇੱਥੇ ਡਾਟਾ ਫਰੇਮ ਦੀ ਇੱਕ ਗੁਣਵੱਤਾ ਹੈ, ਨਾ ਕਿ ਇੱਕ ਫੰਕਸ਼ਨ, ਇਸ ਲਈ ਇਹ ਦੇ ਅੰਤ ਵਿੱਚ ਗੋਲ ਬ੍ਰੈਕਟਸ ਨਹੀਂ ਹਨ।\n" + "`shape` ਇੱਥੇ ਡਾਟਾ ਫਰੇਮ ਦਾ ਇੱਕ ਗੁਣ ਹੈ ਅਤੇ ਇੱਕ ਫੰਕਸ਼ਨ ਨਹੀਂ ਹੈ, ਇਸ ਲਈ ਇਹ ਇੱਕ ਜੋੜੇ ਕੋਠੇ ਨਾਲ ਖਤਮ ਨਹੀਂ ਹੁੰਦਾ।\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "ਹੁਣ ਆਓ ਡਾਟਾ ਦੀਆਂ 4 ਕਾਲਮਾਂ ਵੱਲ ਜਾਈਏ। ਹਰ ਇੱਕ ਕਾਲਮ ਦਾ ਅਰਥ ਕੀ ਹੈ? `columns` ਐਟ੍ਰਿਬਿਊਟ ਸਾਨੂੰ ਡਾਟਾਫ੍ਰੇਮ ਵਿੱਚ ਕਾਲਮਾਂ ਦੇ ਨਾਮ ਦੱਸੇਗਾ।\n" + "ਹੁਣ ਆਓ ਡਾਟਾ ਦੀਆਂ 4 ਕਾਲਮਾਂ ਵੱਲ ਧਿਆਨ ਦਈਏ। ਇਹਨਾਂ ਵਿੱਚੋਂ ਹਰ ਇੱਕ ਕਾਲਮ ਕੀ ਦਰਸਾਉਂਦੀ ਹੈ? `columns` ਐਟ੍ਰਿਬਿਊਟ ਸਾਨੂੰ ਡਾਟਾਫ੍ਰੇਮ ਵਿੱਚ ਕਾਲਮਾਂ ਦੇ ਨਾਮ ਦਿਖਾਏਗੀ।\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "ਜਿਵੇਂ ਕਿ ਅਸੀਂ ਦੇਖ ਸਕਦੇ ਹਾਂ, ਇੱਥੇ ਚਾਰ (4) ਕਾਲਮ ਹਨ। `columns` ਗੁਣ ਧਰਮ ਸਾਨੂੰ ਕਾਲਮਾਂ ਦੇ ਨਾਮ ਦੱਸਦਾ ਹੈ ਅਤੇ ਮੁੱਢਲੇ ਤੌਰ 'ਤੇ ਹੋਰ ਕੁਝ ਨਹੀਂ। ਇਹ ਗੁਣ ਧਰਮ ਮਹੱਤਵਪੂਰਨ ਹੋ ਜਾਂਦਾ ਹੈ ਜਦੋਂ ਅਸੀਂ ਇਹ ਪਛਾਣਣਾ ਚਾਹੁੰਦੇ ਹਾਂ ਕਿ ਇੱਕ ਡੇਟਾਸੈੱਟ ਵਿੱਚ ਕਿਹੜੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਸ਼ਾਮਲ ਹਨ।\n" + "ਜਿਵੇਂ ਕਿ ਅਸੀਂ ਦੇਖ ਸਕਦੇ ਹਾਂ, ਇੱਥੇ ਚਾਰ (4) ਕਾਲਮ ਹਨ। `columns` ਗੁਣਵੱਤਾ ਸਾਨੂੰ ਕਾਲਮਾਂ ਦੇ ਨਾਮ ਦੱਸਦੀ ਹੈ ਅਤੇ ਮੁਢਲੀ ਤੌਰ 'ਤੇ ਹੋਰ ਕੁਝ ਨਹੀਂ। ਇਹ ਗੁਣਵੱਤਾ ਉਸ ਸਮੇਂ ਮਹੱਤਵਪੂਰਨ ਹੋ ਜਾਂਦੀ ਹੈ ਜਦੋਂ ਅਸੀਂ ਪਤਾ ਲਗਾਉਣਾ ਚਾਹੁੰਦੇ ਹਾਂ ਕਿ ਇੱਕ ਡਾਟਾਸੈੱਟ ਵਿੱਚ ਕਿਹੜੇ ਫੀਚਰ ਹਨ।\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "ਡਾਟਾ ਦੀ ਮਾਤਰਾ (`shape` ਗੁਣ) ਅਤੇ ਫੀਚਰਾਂ ਜਾਂ ਕਾਲਮਾਂ ਦੇ ਨਾਮ (`columns` ਗੁਣ) ਸਾਨੂੰ ਡਾਟਾਸੈੱਟ ਬਾਰੇ ਕੁਝ ਦੱਸਦੇ ਹਨ। ਹੁਣ, ਅਸੀਂ ਡਾਟਾਸੈੱਟ ਵਿੱਚ ਹੋਰ ਗਹਿਰਾਈ ਨਾਲ ਜਾਣਾ ਚਾਹਾਂਗੇ। `DataFrame.info()` ਫੰਕਸ਼ਨ ਇਸ ਲਈ ਕਾਫ਼ੀ ਲਾਭਦਾਇਕ ਹੈ।\n" + "ਡਾਟਾ ਦੀ ਮਾਤਰਾ (`shape` ਗੁਣ) ਅਤੇ ਫੀਚਰਾਂ ਜਾਂ ਕਾਲਮਾਂ ਦੇ ਨਾਮ (`columns` ਗੁਣ) ਸਾਨੂੰ ਡਾਟਾਸੈੱਟ ਬਾਰੇ ਕੁਝ ਦੱਸਦੇ ਹਨ। ਹੁਣ, ਅਸੀਂ ਡਾਟਾਸੈੱਟ ਵਿੱਚ ਹੋਰ ਗਹਿਰਾਈ ਨਾਲ ਜਾਣਾ ਚਾਹੁੰਦੇ ਹਾਂ। `DataFrame.info()` ਫੰਕਸ਼ਨ ਇਸ ਲਈ ਕਾਫੀ ਲਾਭਦਾਇਕ ਹੈ।\n" ] }, { @@ -180,10 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "ਇਥੋਂ, ਅਸੀਂ ਕੁਝ ਨਿਰੀਖਣ ਕਰ ਸਕਦੇ ਹਾਂ:\n", - "\n", - "1. ਹਰ ਕਾਲਮ ਦੀ ਡੇਟਾ ਕਿਸਮ: ਇਸ ਡੇਟਾਸੈੱਟ ਵਿੱਚ, ਸਾਰਾ ਡੇਟਾ 64-ਬਿਟ ਫਲੋਟਿੰਗ-ਪੌਇੰਟ ਨੰਬਰਾਂ ਦੇ ਰੂਪ ਵਿੱਚ ਸਟੋਰ ਕੀਤਾ ਗਿਆ ਹੈ। \n", - "2. ਨਾਨ-ਨੱਲ ਮੁੱਲਾਂ ਦੀ ਗਿਣਤੀ: ਨੱਲ ਮੁੱਲਾਂ ਨਾਲ ਨਿਪਟਣਾ ਡੇਟਾ ਤਿਆਰੀ ਵਿੱਚ ਇੱਕ ਮਹੱਤਵਪੂਰਨ ਕਦਮ ਹੈ। ਇਸਨੂੰ ਨੋਟਬੁੱਕ ਵਿੱਚ ਬਾਅਦ ਵਿੱਚ ਹੱਲ ਕੀਤਾ ਜਾਵੇਗਾ। \n" + "ਇਥੋਂ, ਅਸੀਂ ਕੁਝ ਨਿਰੀਖਣ ਕਰ ਸਕਦੇ ਹਾਂ: \n", + "1. ਹਰ ਕਾਲਮ ਦਾ ਡਾਟਾ ਟਾਈਪ: ਇਸ ਡਾਟਾਸੈੱਟ ਵਿੱਚ, ਸਾਰਾ ਡਾਟਾ 64-ਬਿਟ ਫਲੋਟਿੰਗ-ਪੌਇੰਟ ਨੰਬਰਾਂ ਦੇ ਰੂਪ ਵਿੱਚ ਸਟੋਰ ਕੀਤਾ ਗਿਆ ਹੈ। \n", + "2. ਨਾਨ-ਨੱਲ ਮੁੱਲਾਂ ਦੀ ਗਿਣਤੀ: ਨੱਲ ਮੁੱਲਾਂ ਨਾਲ ਨਜਿੱਠਣਾ ਡਾਟਾ ਤਿਆਰੀ ਵਿੱਚ ਇੱਕ ਮਹੱਤਵਪੂਰਨ ਕਦਮ ਹੈ। ਇਸ ਨਾਲ ਨੋਟਬੁੱਕ ਵਿੱਚ ਬਾਅਦ ਵਿੱਚ ਨਜਿੱਠਿਆ ਜਾਵੇਗਾ। \n" ] }, { @@ -193,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "ਮੰਨੋ ਸਾਡੇ ਡਾਟਾਸੈੱਟ ਵਿੱਚ ਬਹੁਤ ਸਾਰਾ ਸੰਖਿਆਤਮਕ ਡਾਟਾ ਹੈ। ਇੱਕ-ਵਿਚਲਨ ਅੰਕੜੇ ਗਣਨਾਵਾਂ, ਜਿਵੇਂ ਕਿ ਔਸਤ, ਮੱਧਿਕ, ਚੌਥਾਈਕ ਆਦਿ, ਹਰ ਕਾਲਮ 'ਤੇ ਅਲੱਗ-ਅਲੱਗ ਕੀਤੀਆਂ ਜਾ ਸਕਦੀਆਂ ਹਨ। `DataFrame.describe()` ਫੰਕਸ਼ਨ ਸਾਨੂੰ ਡਾਟਾਸੈੱਟ ਦੇ ਸੰਖਿਆਤਮਕ ਕਾਲਮਾਂ ਦੀ ਅੰਕੜੇਵਾਰ ਸੰਖੇਪ ਜਾਣਕਾਰੀ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ।\n" + "ਮੰਨ ਲਓ ਕਿ ਸਾਡੇ ਡਾਟਾਸੈਟ ਵਿੱਚ ਬਹੁਤ ਸਾਰੇ ਸੰਖਿਆਤਮਕ ਡਾਟਾ ਹੈ। ਹਰ ਕਾਲਮ 'ਤੇ ਵੱਖ-ਵੱਖ ਤਰ੍ਹਾਂ ਦੇ ਅੰਕਗਣਿਤ ਗਣਨਾ ਜਿਵੇਂ ਕਿ ਔਸਤ, ਮੱਧਕ, ਚੌਥਾਈ ਆਦਿ ਕੀਤੇ ਜਾ ਸਕਦੇ ਹਨ। `DataFrame.describe()` ਫੰਕਸ਼ਨ ਸਾਨੂੰ ਡਾਟਾਸੈਟ ਦੇ ਸੰਖਿਆਤਮਕ ਕਾਲਮਾਂ ਦੀ ਅੰਕਗਣਿਤ ਸੰਖੇਪ ਜਾਣਕਾਰੀ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ।\n" ] }, { @@ -323,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "ਉਪਰੋਕਤ ਆਉਟਪੁੱਟ ਹਰ ਕਾਲਮ ਦੇ ਕੁੱਲ ਡਾਟਾ ਪੌਇੰਟਸ ਦੀ ਗਿਣਤੀ, ਔਸਤ, ਮਿਆਰੀ ਵਿਸ਼ਮ, ਘੱਟੋ-ਘੱਟ, ਹੇਠਲਾ ਚੌਥਾਈ (25%), ਮੱਧ (50%), ਉੱਪਰਲਾ ਚੌਥਾਈ (75%) ਅਤੇ ਵੱਧ ਤੋਂ ਵੱਧ ਮੁੱਲ ਦਿਖਾਉਂਦਾ ਹੈ।\n" + "ਉਪਰੋਕਤ ਆਉਟਪੁੱਟ ਹਰ ਕਾਲਮ ਦੇ ਕੁੱਲ ਡਾਟਾ ਪੌਇੰਟਸ, ਔਸਤ, ਮਿਆਰੀ ਵਿਸਥਾਪਨ, ਘੱਟੋ-ਘੱਟ, ਹੇਠਲਾ ਚੌਥਾਈ (25%), ਮੱਧ (50%), ਉੱਪਰਲਾ ਚੌਥਾਈ (75%) ਅਤੇ ਵੱਧ ਤੋਂ ਵੱਧ ਮੁੱਲ ਦਿਖਾਉਂਦਾ ਹੈ।\n" ] }, { @@ -333,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "ਉਪਰ ਦਿੱਤੀਆਂ ਸਾਰੀਆਂ ਫੰਕਸ਼ਨਾਂ ਅਤੇ ਗੁਣਾਂ ਨਾਲ, ਸਾਨੂੰ ਡਾਟਾਸੈਟ ਦੀ ਇੱਕ ਉੱਚ ਪੱਧਰੀ ਝਲਕ ਮਿਲ ਗਈ ਹੈ। ਸਾਨੂੰ ਪਤਾ ਹੈ ਕਿ ਕਿੰਨੇ ਡਾਟਾ ਪੌਇੰਟ ਹਨ, ਕਿੰਨੇ ਫੀਚਰ ਹਨ, ਹਰ ਫੀਚਰ ਦਾ ਡਾਟਾ ਟਾਈਪ ਕੀ ਹੈ ਅਤੇ ਹਰ ਫੀਚਰ ਲਈ ਕਿੰਨੇ non-null ਮੁੱਲ ਹਨ।\n", + "ਉਪਰੋਕਤ ਸਾਰੇ ਫੰਕਸ਼ਨ ਅਤੇ ਗੁਣਾਂ ਨਾਲ, ਸਾਨੂੰ ਡਾਟਾਸੈਟ ਦੀ ਇੱਕ ਉੱਚ ਪੱਧਰੀ ਝਲਕ ਮਿਲ ਗਈ ਹੈ। ਸਾਨੂੰ ਪਤਾ ਹੈ ਕਿ ਕਿੰਨੇ ਡਾਟਾ ਪੌਇੰਟ ਹਨ, ਕਿੰਨੀ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਹਨ, ਹਰ ਵਿਸ਼ੇਸ਼ਤਾ ਦਾ ਡਾਟਾ ਟਾਈਪ ਕੀ ਹੈ ਅਤੇ ਹਰ ਵਿਸ਼ੇਸ਼ਤਾ ਲਈ ਗੈਰ-ਨੱਲ ਮੁੱਲਾਂ ਦੀ ਗਿਣਤੀ ਕੀ ਹੈ।\n", "\n", - "ਹੁਣ ਸਮਾਂ ਹੈ ਡਾਟਾ ਨੂੰ ਖੁਦ ਦੇਖਣ ਦਾ। ਆਓ ਵੇਖੀਏ ਕਿ ਸਾਡੇ `DataFrame` ਦੀਆਂ ਪਹਿਲੀਆਂ ਕੁਝ ਪੰਗਤਾਂ (ਪਹਿਲੇ ਕੁਝ ਡਾਟਾ ਪੌਇੰਟ) ਕਿਵੇਂ ਦਿਖਦੇ ਹਨ:\n" + "ਹੁਣ ਸਮਾਂ ਹੈ ਕਿ ਅਸਲ ਡਾਟਾ ਨੂੰ ਦੇਖਣ ਦਾ। ਆਓ ਵੇਖੀਏ ਕਿ ਸਾਡੇ `DataFrame` ਦੀਆਂ ਪਹਿਲੀਆਂ ਕੁਝ ਪੰਗਤਾਂ (ਪਹਿਲੇ ਕੁਝ ਡਾਟਾ ਪੌਇੰਟ) ਕਿਵੇਂ ਦਿਖਦੀਆਂ ਹਨ:\n" ] }, { @@ -442,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "ਇੱਥੇ ਨਤੀਜੇ ਵਜੋਂ, ਅਸੀਂ ਡੇਟਾਸੈੱਟ ਦੀਆਂ ਪੰਜ (5) ਐਂਟਰੀਆਂ ਦੇਖ ਸਕਦੇ ਹਾਂ। ਜੇ ਅਸੀਂ ਖੱਬੇ ਪਾਸੇ ਇੰਡੈਕਸ ਨੂੰ ਵੇਖੀਏ, ਤਾਂ ਸਾਨੂੰ ਪਤਾ ਲੱਗਦਾ ਹੈ ਕਿ ਇਹ ਪਹਿਲੀਆਂ ਪੰਜ ਕਤਾਰਾਂ ਹਨ।\n" + "ਜਿਵੇਂ ਕਿ ਇੱਥੇ ਆਉਟਪੁੱਟ ਵਿੱਚ, ਅਸੀਂ ਡੇਟਾਸੈੱਟ ਦੇ ਪੰਜ (5) ਐਂਟਰੀਜ਼ ਦੇਖ ਸਕਦੇ ਹਾਂ। ਜੇ ਅਸੀਂ ਖੱਬੇ ਪਾਸੇ ਇੰਡੈਕਸ ਨੂੰ ਵੇਖੀਏ, ਤਾਂ ਪਤਾ ਲਗਦਾ ਹੈ ਕਿ ਇਹ ਪਹਿਲੀਆਂ ਪੰਜ ਪੰਗਤਾਂ ਹਨ।\n" ] }, { @@ -453,7 +452,7 @@ "source": [ "### ਕਸਰਤ:\n", "\n", - "ਉਪਰ ਦਿੱਤੇ ਉਦਾਹਰਨ ਤੋਂ ਸਪੱਸ਼ਟ ਹੈ ਕਿ ਮੂਲ ਰੂਪ ਵਿੱਚ, `DataFrame.head` ਇੱਕ `DataFrame` ਦੀ ਪਹਿਲੀਆਂ ਪੰਜ ਕਤਾਰਾਂ ਵਾਪਸ ਕਰਦਾ ਹੈ। ਹੇਠਾਂ ਦਿੱਤੇ ਕੋਡ ਸੈੱਲ ਵਿੱਚ, ਕੀ ਤੁਸੀਂ ਪੰਜ ਤੋਂ ਵੱਧ ਕਤਾਰਾਂ ਦਿਖਾਉਣ ਦਾ ਕੋਈ ਤਰੀਕਾ ਲੱਭ ਸਕਦੇ ਹੋ?\n" + "ਉਪਰ ਦਿੱਤੇ ਉਦਾਹਰਨ ਤੋਂ ਸਪਸ਼ਟ ਹੈ ਕਿ ਮੂਲ ਰੂਪ ਵਿੱਚ, `DataFrame.head` ਇੱਕ `DataFrame` ਦੇ ਪਹਿਲੇ ਪੰਜ ਪੰਨੇ ਵਾਪਸ ਕਰਦਾ ਹੈ। ਹੇਠਾਂ ਦਿੱਤੇ ਕੋਡ ਸੈਲ ਵਿੱਚ, ਕੀ ਤੁਸੀਂ ਪੰਜ ਤੋਂ ਵੱਧ ਪੰਨਿਆਂ ਨੂੰ ਦਿਖਾਉਣ ਦਾ ਕੋਈ ਤਰੀਕਾ ਲੱਭ ਸਕਦੇ ਹੋ?\n" ] }, { @@ -476,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "ਡਾਟਾ ਨੂੰ ਦੇਖਣ ਦਾ ਇੱਕ ਹੋਰ ਤਰੀਕਾ ਅੰਤ ਤੋਂ ਹੋ ਸਕਦਾ ਹੈ (ਸ਼ੁਰੂਆਤ ਦੀ ਬਜਾਏ)। `DataFrame.head` ਦਾ ਉਲਟ `DataFrame.tail` ਹੈ, ਜੋ ਕਿ `DataFrame` ਦੀਆਂ ਆਖਰੀ ਪੰਜ ਕਤਾਰਾਂ ਵਾਪਸ ਕਰਦਾ ਹੈ:\n" + "ਡਾਟਾ ਨੂੰ ਦੇਖਣ ਦਾ ਇੱਕ ਹੋਰ ਤਰੀਕਾ ਅੰਤ ਤੋਂ ਹੋ ਸਕਦਾ ਹੈ (ਸ਼ੁਰੂਆਤ ਦੀ ਬਜਾਏ)। `DataFrame.head` ਦਾ ਉਲਟ `DataFrame.tail` ਹੈ, ਜੋ ਕਿ `DataFrame` ਦੀਆਂ ਆਖਰੀ ਪੰਜ ਪੰਗਤਾਂ ਵਾਪਸ ਕਰਦਾ ਹੈ:\n" ] }, { @@ -583,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "ਅਮਲ ਵਿੱਚ, ਇਹ ਲਾਭਦਾਇਕ ਹੁੰਦਾ ਹੈ ਕਿ ਤੁਸੀਂ ਆਸਾਨੀ ਨਾਲ `DataFrame` ਦੀਆਂ ਪਹਿਲੀਆਂ ਕੁਝ ਕਤਾਰਾਂ ਜਾਂ ਆਖਰੀ ਕੁਝ ਕਤਾਰਾਂ ਦੀ ਜਾਂਚ ਕਰ ਸਕੋ, ਖਾਸ ਕਰਕੇ ਜਦੋਂ ਤੁਸੀਂ ਕ੍ਰਮਬੱਧ ਡੇਟਾਸੈਟਸ ਵਿੱਚ ਅਸਧਾਰਨ ਮੁੱਲਾਂ ਦੀ ਭਾਲ ਕਰ ਰਹੇ ਹੋ। \n", + "ਅਮਲ ਵਿੱਚ, ਇਹ ਲਾਭਦਾਇਕ ਹੁੰਦਾ ਹੈ ਕਿ `DataFrame` ਦੇ ਪਹਿਲੇ ਕੁ ਪੰਨਿਆਂ ਜਾਂ ਆਖਰੀ ਕੁ ਪੰਨਿਆਂ ਨੂੰ ਆਸਾਨੀ ਨਾਲ ਦੇਖਿਆ ਜਾ ਸਕੇ, ਖਾਸ ਕਰਕੇ ਜਦੋਂ ਤੁਸੀਂ ਕ੍ਰਮਬੱਧ ਡਾਟਾਸੈਟ ਵਿੱਚ ਅਸਧਾਰਨ ਮੁੱਲਾਂ ਦੀ ਭਾਲ ਕਰ ਰਹੇ ਹੋ। \n", "\n", - "ਉਪਰ ਦਿੱਤੇ ਸਾਰੇ ਫੰਕਸ਼ਨ ਅਤੇ ਗੁਣ, ਜੋ ਕੋਡ ਉਦਾਹਰਣਾਂ ਦੀ ਮਦਦ ਨਾਲ ਦਿਖਾਏ ਗਏ ਹਨ, ਸਾਨੂੰ ਡੇਟਾ ਦੀ ਇੱਕ ਝਲਕ ਅਤੇ ਅਹਿਸਾਸ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਮਦਦ ਕਰਦੇ ਹਨ। \n", + "ਉਪਰ ਦਿੱਤੇ ਸਾਰੇ ਫੰਕਸ਼ਨ ਅਤੇ ਗੁਣ, ਜਿਨ੍ਹਾਂ ਨੂੰ ਕੋਡ ਉਦਾਹਰਣਾਂ ਦੀ ਮਦਦ ਨਾਲ ਦਰਸਾਇਆ ਗਿਆ ਹੈ, ਸਾਨੂੰ ਡਾਟਾ ਦੇ ਦ੍ਰਿਸ਼ ਅਤੇ ਅਹਿਸਾਸ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਮਦਦ ਕਰਦੇ ਹਨ। \n", "\n", - "> **ਮੁੱਖ ਗੱਲ:** ਸਿਰਫ `DataFrame` ਵਿੱਚ ਮੌਜੂਦ ਜਾਣਕਾਰੀ ਬਾਰੇ ਮੈਟਾਡੇਟਾ ਜਾਂ ਉਸ ਦੀਆਂ ਪਹਿਲੀਆਂ ਅਤੇ ਆਖਰੀ ਕੁਝ ਕਦਰਾਂ ਨੂੰ ਦੇਖ ਕੇ ਵੀ, ਤੁਸੀਂ ਉਸ ਡੇਟਾ ਦੇ ਆਕਾਰ, ਰੂਪ ਅਤੇ ਸਮੱਗਰੀ ਬਾਰੇ ਤੁਰੰਤ ਇੱਕ ਵਿਚਾਰ ਪ੍ਰਾਪਤ ਕਰ ਸਕਦੇ ਹੋ, ਜਿਸ ਨਾਲ ਤੁਸੀਂ ਨਿਪਟ ਰਹੇ ਹੋ। \n" + "> **ਮੁੱਖ ਗੱਲ:** ਸਿਰਫ `DataFrame` ਵਿੱਚ ਮੌਜੂਦ ਜਾਣਕਾਰੀ ਬਾਰੇ ਮੈਟਾਡਾਟਾ ਜਾਂ ਪਹਿਲੇ ਅਤੇ ਆਖਰੀ ਕੁ ਮੁੱਲਾਂ ਨੂੰ ਦੇਖ ਕੇ ਹੀ, ਤੁਸੀਂ ਉਸ ਡਾਟਾ ਦੇ ਆਕਾਰ, ਰੂਪ ਅਤੇ ਸਮੱਗਰੀ ਬਾਰੇ ਤੁਰੰਤ ਧਾਰਨਾ ਲਗਾ ਸਕਦੇ ਹੋ ਜਿਸ ਨਾਲ ਤੁਸੀਂ ਨਿਪਟ ਰਹੇ ਹੋ।\n" ] }, { @@ -597,17 +596,17 @@ }, "source": [ "### ਗੁੰਮ ਡਾਟਾ\n", - "ਆਓ ਗੁੰਮ ਡਾਟਾ ਬਾਰੇ ਸਮਝੀਏ। ਗੁੰਮ ਡਾਟਾ ਉਸ ਸਮੇਂ ਹੁੰਦਾ ਹੈ, ਜਦੋਂ ਕੁਝ ਕਾਲਮਾਂ ਵਿੱਚ ਕੋਈ ਵੀ ਮੁੱਲ ਸਟੋਰ ਨਹੀਂ ਕੀਤਾ ਜਾਂਦਾ।\n", + "ਆਓ ਗੁੰਮ ਡਾਟਾ ਬਾਰੇ ਜਾਣਕਾਰੀ ਲਵਾਂ। ਗੁੰਮ ਡਾਟਾ ਉਹਨਾਂ ਹਾਲਾਤਾਂ ਵਿੱਚ ਹੁੰਦਾ ਹੈ ਜਦੋਂ ਕੁਝ ਕਾਲਮਾਂ ਵਿੱਚ ਕੋਈ ਵੀ ਮੁੱਲ ਸਟੋਰ ਨਹੀਂ ਕੀਤਾ ਜਾਂਦਾ।\n", "\n", - "ਚਲੋ ਇੱਕ ਉਦਾਹਰਨ ਲੈਂਦੇ ਹਾਂ: ਮੰਨੋ ਕਿ ਕੋਈ ਵਿਅਕਤੀ ਆਪਣੇ ਵਜ਼ਨ ਨੂੰ ਲੈ ਕੇ ਸਚੇਤ ਹੈ ਅਤੇ ਸਰਵੇ ਵਿੱਚ ਵਜ਼ਨ ਵਾਲਾ ਖੇਤਰ ਨਹੀਂ ਭਰਦਾ। ਫਿਰ, ਉਸ ਵਿਅਕਤੀ ਲਈ ਵਜ਼ਨ ਦਾ ਮੁੱਲ ਗੁੰਮ ਹੋਵੇਗਾ।\n", + "ਆਓ ਇੱਕ ਉਦਾਹਰਨ ਲਵਾਂ: ਮੰਨੋ ਕਿ ਕੋਈ ਵਿਅਕਤੀ ਆਪਣੇ ਵਜ਼ਨ ਨੂੰ ਲੈ ਕੇ ਚਿੰਤਤ ਹੈ ਅਤੇ ਸਰਵੇ ਵਿੱਚ ਵਜ਼ਨ ਵਾਲਾ ਖੇਤਰ ਨਹੀਂ ਭਰਦਾ। ਇਸ ਸਥਿਤੀ ਵਿੱਚ, ਉਸ ਵਿਅਕਤੀ ਲਈ ਵਜ਼ਨ ਦਾ ਮੁੱਲ ਗੁੰਮ ਹੋਵੇਗਾ।\n", "\n", - "ਅਕਸਰ, ਅਸਲ ਦੁਨੀਆ ਦੇ ਡਾਟਾਸੈਟਸ ਵਿੱਚ, ਗੁੰਮ ਮੁੱਲ ਮਿਲਦੇ ਹਨ।\n", + "ਅਕਸਰ, ਅਸਲ ਦੁਨੀਆ ਦੇ ਡਾਟਾਸੈਟਾਂ ਵਿੱਚ, ਗੁੰਮ ਮੁੱਲ ਮਿਲਦੇ ਹਨ।\n", "\n", - "**ਪੈਂਡਾਸ ਕਿਵੇਂ ਗੁੰਮ ਡਾਟਾ ਨੂੰ ਹੈਂਡਲ ਕਰਦਾ ਹੈ**\n", + "**Pandas ਗੁੰਮ ਡਾਟਾ ਨੂੰ ਕਿਵੇਂ ਸੰਭਾਲਦਾ ਹੈ**\n", "\n", - "ਪੈਂਡਾਸ ਗੁੰਮ ਮੁੱਲਾਂ ਨੂੰ ਦੋ ਤਰੀਕਿਆਂ ਨਾਲ ਹੈਂਡਲ ਕਰਦਾ ਹੈ। ਪਹਿਲਾ ਤਰੀਕਾ ਤੁਸੀਂ ਪਹਿਲੇ ਸੈਕਸ਼ਨਾਂ ਵਿੱਚ ਵੇਖ ਚੁੱਕੇ ਹੋ: `NaN`, ਜਾਂ Not a Number। ਇਹ ਦਰਅਸਲ ਇੱਕ ਖਾਸ ਮੁੱਲ ਹੈ ਜੋ IEEE ਫਲੋਟਿੰਗ-ਪੌਇੰਟ ਸਪੈਸਿਫਿਕੇਸ਼ਨ ਦਾ ਹਿੱਸਾ ਹੈ ਅਤੇ ਇਹ ਸਿਰਫ ਗੁੰਮ ਫਲੋਟਿੰਗ-ਪੌਇੰਟ ਮੁੱਲਾਂ ਨੂੰ ਦਰਸਾਉਣ ਲਈ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ।\n", + "Pandas ਗੁੰਮ ਮੁੱਲਾਂ ਨੂੰ ਦੋ ਤਰੀਕਿਆਂ ਨਾਲ ਸੰਭਾਲਦਾ ਹੈ। ਪਹਿਲਾ ਤਰੀਕਾ, ਜਿਸਨੂੰ ਤੁਸੀਂ ਪਹਿਲੇ ਸੈਕਸ਼ਨਾਂ ਵਿੱਚ ਦੇਖਿਆ ਹੈ: `NaN`, ਜਾਂ Not a Number। ਇਹ ਵਾਸਤਵ ਵਿੱਚ IEEE ਫਲੋਟਿੰਗ-ਪੌਇੰਟ ਸਪੈਸਿਫਿਕੇਸ਼ਨ ਦਾ ਇੱਕ ਵਿਸ਼ੇਸ਼ ਮੁੱਲ ਹੈ ਅਤੇ ਇਹ ਸਿਰਫ ਗੁੰਮ ਫਲੋਟਿੰਗ-ਪੌਇੰਟ ਮੁੱਲਾਂ ਨੂੰ ਦਰਸਾਉਣ ਲਈ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ।\n", "\n", - "ਫਲੋਟਸ ਤੋਂ ਇਲਾਵਾ ਹੋਰ ਕਿਸਮ ਦੇ ਗੁੰਮ ਮੁੱਲਾਂ ਲਈ, ਪੈਂਡਾਸ Python ਦੇ `None` ਆਬਜੈਕਟ ਦਾ ਇਸਤੇਮਾਲ ਕਰਦਾ ਹੈ। ਜਦੋਂ ਕਿ ਇਹ ਥੋੜ੍ਹਾ ਗੁੰਝਲਦਾਰ ਲੱਗ ਸਕਦਾ ਹੈ ਕਿ ਤੁਸੀਂ ਦੋ ਵੱਖ-ਵੱਖ ਕਿਸਮ ਦੇ ਮੁੱਲਾਂ ਨੂੰ ਦੇਖੋਗੇ ਜੋ ਅਸਲ ਵਿੱਚ ਇੱਕੋ ਗੱਲ ਕਹਿੰਦੇ ਹਨ, ਇਸ ਡਿਜ਼ਾਈਨ ਚੋਣ ਦੇ ਪਿੱਛੇ ਮਜ਼ਬੂਤ ਕਾਰਨ ਹਨ। ਅਮਲ ਵਿੱਚ, ਇਹ ਤਰੀਕਾ ਪੈਂਡਾਸ ਨੂੰ ਬਹੁਤ ਸਾਰੇ ਕੇਸਾਂ ਲਈ ਇੱਕ ਵਧੀਆ ਸਮਝੌਤਾ ਪੇਸ਼ ਕਰਨ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ। ਇਸਦੇ ਬਾਵਜੂਦ, `None` ਅਤੇ `NaN` ਦੋਵਾਂ ਵਿੱਚ ਕੁਝ ਪਾਬੰਦੀਆਂ ਹੁੰਦੀਆਂ ਹਨ ਜਿਨ੍ਹਾਂ ਬਾਰੇ ਤੁਹਾਨੂੰ ਸਾਵਧਾਨ ਰਹਿਣ ਦੀ ਲੋੜ ਹੈ ਕਿ ਇਹਨਾਂ ਨੂੰ ਕਿਵੇਂ ਵਰਤਿਆ ਜਾ ਸਕਦਾ ਹੈ।\n" + "ਫਲੋਟਾਂ ਤੋਂ ਇਲਾਵਾ ਗੁੰਮ ਮੁੱਲਾਂ ਲਈ, pandas Python ਦੇ `None` ਆਬਜੈਕਟ ਨੂੰ ਵਰਤਦਾ ਹੈ। ਜਦੋਂ ਕਿ ਇਹ ਥੋੜਾ ਜਿਹਾ ਗੁੰਝਲਦਾਰ ਲੱਗ ਸਕਦਾ ਹੈ ਕਿ ਤੁਹਾਨੂੰ ਦੋ ਵੱਖ-ਵੱਖ ਕਿਸਮ ਦੇ ਮੁੱਲ ਮਿਲਣਗੇ ਜੋ ਅਸਲ ਵਿੱਚ ਇੱਕੋ ਹੀ ਗੱਲ ਕਹਿੰਦੇ ਹਨ, ਇਸ ਡਿਜ਼ਾਈਨ ਚੋਣ ਦੇ ਪਿੱਛੇ ਵਾਜਬ ਕਾਰਨ ਹਨ। ਅਮਲ ਵਿੱਚ, ਇਸ ਤਰੀਕੇ ਨਾਲ pandas ਨੂੰ ਜ਼ਿਆਦਾਤਰ ਹਾਲਾਤਾਂ ਲਈ ਇੱਕ ਵਧੀਆ ਸਮਝੌਤਾ ਪੇਸ਼ ਕਰਨ ਦੀ ਯੋਗਤਾ ਮਿਲਦੀ ਹੈ। ਇਸਦੇ ਬਾਵਜੂਦ, `None` ਅਤੇ `NaN` ਦੋਵੇਂ ਵਿੱਚ ਕੁਝ ਪਾਬੰਦੀਆਂ ਹੁੰਦੀਆਂ ਹਨ ਜਿਨ੍ਹਾਂ ਨੂੰ ਤੁਹਾਨੂੰ ਇਹ ਸਮਝਣ ਦੀ ਲੋੜ ਹੈ ਕਿ ਇਹਨਾਂ ਨੂੰ ਕਿਵੇਂ ਵਰਤਿਆ ਜਾ ਸਕਦਾ ਹੈ।\n" ] }, { @@ -616,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: ਗੈਰ-ਫਲੋਟ ਗੁੰਮ ਡਾਟਾ \n", - "ਕਿਉਂਕਿ `None` ਪਾਇਥਨ ਤੋਂ ਆਉਂਦਾ ਹੈ, ਇਸਨੂੰ NumPy ਅਤੇ pandas ਐਰੇਜ਼ ਵਿੱਚ ਵਰਤਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ ਜਿਹਨਾਂ ਦਾ ਡਾਟਾ ਟਾਈਪ `'object'` ਨਹੀਂ ਹੈ। ਯਾਦ ਰੱਖੋ, NumPy ਐਰੇਜ਼ (ਅਤੇ pandas ਵਿੱਚ ਡਾਟਾ ਸਟ੍ਰਕਚਰ) ਸਿਰਫ ਇੱਕ ਹੀ ਕਿਸਮ ਦੇ ਡਾਟਾ ਨੂੰ ਰੱਖ ਸਕਦੇ ਹਨ। ਇਹੀ ਗੁਣ ਉਨ੍ਹਾਂ ਨੂੰ ਵੱਡੇ ਪੱਧਰ ਦੇ ਡਾਟਾ ਅਤੇ ਗਣਨਾ ਦੇ ਕੰਮ ਲਈ ਬੇਹੱਦ ਤਾਕਤਵਰ ਬਣਾਉਂਦਾ ਹੈ, ਪਰ ਇਹ ਉਨ੍ਹਾਂ ਦੀ ਲਚੀਲਤਾਵਾਂ ਨੂੰ ਵੀ ਸੀਮਿਤ ਕਰਦਾ ਹੈ। ਇਸ ਤਰ੍ਹਾਂ ਦੇ ਐਰੇਜ਼ ਨੂੰ \"ਸਭ ਤੋਂ ਘੱਟ ਸਾਂਝੇ ਗੁਣਕ\" ਵੱਲ ਅੱਪਕਾਸਟ ਕਰਨਾ ਪੈਂਦਾ ਹੈ, ਜੋ ਡਾਟਾ ਟਾਈਪ ਐਰੇ ਵਿੱਚ ਹਰ ਚੀਜ਼ ਨੂੰ ਸ਼ਾਮਲ ਕਰ ਸਕੇ। ਜਦੋਂ ਐਰੇ ਵਿੱਚ `None` ਹੁੰਦਾ ਹੈ, ਇਸਦਾ ਮਤਲਬ ਹੈ ਕਿ ਤੁਸੀਂ ਪਾਇਥਨ ਆਬਜੈਕਟਸ ਨਾਲ ਕੰਮ ਕਰ ਰਹੇ ਹੋ। \n", + "### `None`: ਗੈਰ-ਫਲੋਟ ਗੁੰਮ ਹੋਇਆ ਡਾਟਾ\n", + "ਕਿਉਂਕਿ `None` ਪਾਇਥਨ ਤੋਂ ਆਉਂਦਾ ਹੈ, ਇਸਨੂੰ NumPy ਅਤੇ pandas ਐਰੇਜ਼ ਵਿੱਚ ਵਰਤਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ ਜੋ ਡਾਟਾ ਟਾਈਪ `'object'` ਨਹੀਂ ਹਨ। ਯਾਦ ਰੱਖੋ, NumPy ਐਰੇਜ਼ (ਅਤੇ pandas ਵਿੱਚ ਡਾਟਾ ਸਟ੍ਰਕਚਰ) ਸਿਰਫ ਇੱਕ ਹੀ ਕਿਸਮ ਦੇ ਡਾਟਾ ਨੂੰ ਸ਼ਾਮਲ ਕਰ ਸਕਦੇ ਹਨ। ਇਹੀ ਗੁਣ ਉਨ੍ਹਾਂ ਨੂੰ ਵੱਡੇ ਪੱਧਰ ਦੇ ਡਾਟਾ ਅਤੇ ਗਣਨਾਤਮਕ ਕੰਮ ਲਈ ਬੇਹਤਰੀਨ ਤਾਕਤ ਦਿੰਦਾ ਹੈ, ਪਰ ਇਹ ਉਨ੍ਹਾਂ ਦੀ ਲਚਕਤਾ ਨੂੰ ਵੀ ਸੀਮਿਤ ਕਰਦਾ ਹੈ। ਇਸ ਤਰ੍ਹਾਂ ਦੇ ਐਰੇਜ਼ ਨੂੰ \"ਸਭ ਤੋਂ ਘੱਟ ਸਾਂਝੇ ਗੁਣਕ\" ਵੱਲ ਅਪਕਾਸਟ ਕਰਨਾ ਪੈਂਦਾ ਹੈ, ਜੋ ਡਾਟਾ ਟਾਈਪ ਐਰੇ ਵਿੱਚ ਹਰ ਚੀਜ਼ ਨੂੰ ਸ਼ਾਮਲ ਕਰ ਸਕੇ। ਜਦੋਂ `None` ਐਰੇ ਵਿੱਚ ਹੁੰਦਾ ਹੈ, ਇਸਦਾ ਮਤਲਬ ਹੈ ਕਿ ਤੁਸੀਂ ਪਾਇਥਨ ਆਬਜੈਕਟਸ ਨਾਲ ਕੰਮ ਕਰ ਰਹੇ ਹੋ।\n", "\n", - "ਇਸਨੂੰ ਕਿਰਿਆਸ਼ੀਲ ਰੂਪ ਵਿੱਚ ਵੇਖਣ ਲਈ, ਹੇਠਾਂ ਦਿੱਤੇ ਉਦਾਹਰਣ ਐਰੇ ਨੂੰ ਵੇਖੋ (ਇਸਦਾ `dtype` ਨੋਟ ਕਰੋ): \n" + "ਇਸਨੂੰ ਕਾਰਵਾਈ ਵਿੱਚ ਦੇਖਣ ਲਈ, ਹੇਠਾਂ ਦਿੱਤੇ ਉਦਾਹਰਨ ਐਰੇ ਨੂੰ ਵੇਖੋ (ਇਸਦਾ `dtype` ਨੋਟ ਕਰੋ):\n" ] }, { @@ -658,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "ਅੱਪਕਾਸਟ ਡਾਟਾ ਟਾਈਪਸ ਦੀ ਹਕੀਕਤ ਨਾਲ ਦੋ ਪਾਸੇ ਪ੍ਰਭਾਵ ਜੁੜੇ ਹੋਏ ਹਨ। ਪਹਿਲਾਂ, ਕਾਰਵਾਈਆਂ ਵਿਆਖਿਆ ਕੀਤੇ Python ਕੋਡ ਦੇ ਪੱਧਰ 'ਤੇ ਕੀਤੀਆਂ ਜਾਣਗੀਆਂ ਨਾ ਕਿ ਕੰਪਾਇਲ ਕੀਤੇ NumPy ਕੋਡ ਦੇ ਪੱਧਰ 'ਤੇ। ਅਸਲ ਵਿੱਚ, ਇਸਦਾ ਮਤਲਬ ਹੈ ਕਿ ਜੇਕਰ `Series` ਜਾਂ `DataFrames` ਵਿੱਚ `None` ਸ਼ਾਮਲ ਹੈ, ਤਾਂ ਉਨ੍ਹਾਂ ਨਾਲ ਜੁੜੀਆਂ ਕਾਰਵਾਈਆਂ ਹੌਲੀ ਹੋਣਗੀਆਂ। ਹਾਲਾਂਕਿ ਤੁਸੀਂ ਸ਼ਾਇਦ ਇਸ ਪ੍ਰਦਰਸ਼ਨ ਵਿੱਚ ਘਾਟ ਨੂੰ ਮਹਿਸੂ ਨਾ ਕਰੋ, ਵੱਡੇ ਡਾਟਾਸੈਟਸ ਲਈ ਇਹ ਸਮੱਸਿਆ ਬਣ ਸਕਦੀ ਹੈ।\n", + "ਅੱਪਕਾਸਟ ਡਾਟਾ ਟਾਈਪਸ ਦੀ ਹਕੀਕਤ ਨਾਲ ਦੋ ਪਾਸੇ ਪ੍ਰਭਾਵ ਜੁੜੇ ਹੋਏ ਹਨ। ਪਹਿਲਾਂ, ਕਾਰਵਾਈਆਂ ਵਿਆਖਿਆ ਕੀਤੇ ਗਏ Python ਕੋਡ ਦੇ ਪੱਧਰ 'ਤੇ ਕੀਤੀਆਂ ਜਾਣਗੀਆਂ, ਨਾ ਕਿ ਕੰਪਾਇਲ ਕੀਤੇ NumPy ਕੋਡ ਦੇ ਪੱਧਰ 'ਤੇ। ਅਸਲ ਵਿੱਚ, ਇਸਦਾ ਮਤਲਬ ਇਹ ਹੈ ਕਿ ਜੇ `Series` ਜਾਂ `DataFrames` ਵਿੱਚ `None` ਸ਼ਾਮਲ ਹੈ, ਤਾਂ ਉਨ੍ਹਾਂ ਨਾਲ ਜੁੜੀਆਂ ਕਾਰਵਾਈਆਂ ਹੌਲੀ ਹੋਣਗੀਆਂ। ਹਾਲਾਂਕਿ ਤੁਸੀਂ ਸ਼ਾਇਦ ਇਸ ਪ੍ਰਦਰਸ਼ਨ ਵਿੱਚ ਘਾਟ ਨੂੰ ਮਹਿਸੂ ਨਾ ਕਰੋ, ਵੱਡੇ ਡਾਟਾਸੈਟਸ ਲਈ ਇਹ ਇੱਕ ਸਮੱਸਿਆ ਬਣ ਸਕਦੀ ਹੈ।\n", "\n", - "ਦੂਜਾ ਪਾਸੇ ਪ੍ਰਭਾਵ ਪਹਿਲੇ ਤੋਂ ਉਤਪੰਨ ਹੁੰਦਾ ਹੈ। ਕਿਉਂਕਿ `None` ਅਸਲ ਵਿੱਚ `Series` ਜਾਂ `DataFrame`s ਨੂੰ ਵੈਨਿਲਾ Python ਦੀ ਦੁਨੀਆ ਵਿੱਚ ਵਾਪਸ ਖਿੱਚ ਲੈਂਦਾ ਹੈ, ਇਸ ਲਈ ਜੇਕਰ NumPy/pandas ਐਗਰੀਗੇਸ਼ਨ ਜਿਵੇਂ ਕਿ `sum()` ਜਾਂ `min()` ਨੂੰ ਉਹਨਾਂ ਐਰੇਜ਼ 'ਤੇ ਵਰਤਿਆ ਜਾਵੇ ਜਿਨ੍ਹਾਂ ਵਿੱਚ ``None`` ਮੁੱਲ ਸ਼ਾਮਲ ਹੈ, ਤਾਂ ਆਮ ਤੌਰ 'ਤੇ ਇੱਕ ਗਲਤੀ ਪੈਦਾ ਹੋਵੇਗੀ:\n" + "ਦੂਜਾ ਪਾਸਾ ਪ੍ਰਭਾਵ ਪਹਿਲੇ ਤੋਂ ਉਤਪੰਨ ਹੁੰਦਾ ਹੈ। ਕਿਉਂਕਿ `None` ਅਸਲ ਵਿੱਚ `Series` ਜਾਂ `DataFrame`s ਨੂੰ ਵੈਨਿਲਾ Python ਦੀ ਦੁਨੀਆ ਵਿੱਚ ਵਾਪਸ ਖਿੱਚ ਲੈਂਦਾ ਹੈ, ਇਸ ਲਈ ਜੇਕਰ NumPy/pandas ਐਗਰੀਗੇਸ਼ਨ ਜਿਵੇਂ ਕਿ `sum()` ਜਾਂ `min()` ਨੂੰ ਉਹਨਾਂ ਐਰੇਜ਼ 'ਤੇ ਲਾਗੂ ਕੀਤਾ ਜਾਵੇ ਜਿਨ੍ਹਾਂ ਵਿੱਚ ``None`` ਮੁੱਲ ਸ਼ਾਮਲ ਹੈ, ਤਾਂ ਆਮ ਤੌਰ 'ਤੇ ਇੱਕ ਗਲਤੀ ਪੈਦਾ ਹੋਵੇਗੀ:\n" ] }, { @@ -698,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**ਮੁੱਖ ਨਿਸ਼ਕਰਸ਼**: ਪੂਰਨ ਅੰਕਾਂ ਅਤੇ `None` ਮੁੱਲਾਂ ਦੇ ਵਿਚਕਾਰ ਜੋੜ (ਅਤੇ ਹੋਰ ਕਿਰਿਆਵਾਂ) ਅਨਿਰਧਾਰਿਤ ਹੈ, ਜੋ ਉਹਨਾਂ ਡੇਟਾਸੈਟਾਂ ਨਾਲ ਕੀਤੇ ਜਾਣ ਵਾਲੇ ਕੰਮਾਂ ਨੂੰ ਸੀਮਿਤ ਕਰ ਸਕਦਾ ਹੈ।\n" + ] }, { "cell_type": "markdown", @@ -706,9 +707,9 @@ "id": "pWvVHvETgRr9" }, "source": [ - "### `NaN`: ਗੁੰਮ ਸ਼ੂਨ ਭਿੰਨ ਮੁੱਲ\n", + "### `NaN`: ਗੁੰਮ ਹੋਏ ਫਲੋਟ ਮੁੱਲ\n", "\n", - "`None` ਦੇ ਵਿਰੋਧ ਵਿੱਚ, NumPy (ਅਤੇ ਇਸ ਲਈ pandas) ਆਪਣੇ ਤੇਜ਼, ਵੇਕਟਰਾਈਜ਼ਡ ਓਪਰੇਸ਼ਨ ਅਤੇ ufuncs ਲਈ `NaN` ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ। ਮੰਦੀ ਖ਼ਬਰ ਇਹ ਹੈ ਕਿ `NaN` 'ਤੇ ਕੀਤੇ ਗਏ ਕਿਸੇ ਵੀ ਗਣਿਤੀ ਪ੍ਰਕਿਰਿਆ ਦਾ ਨਤੀਜਾ ਹਮੇਸ਼ਾ `NaN` ਹੀ ਹੁੰਦਾ ਹੈ। ਉਦਾਹਰਣ ਵਜੋਂ:\n" + "`None` ਦੇ ਵਿਰੁੱਧ, NumPy (ਅਤੇ ਇਸ ਲਈ pandas) ਆਪਣੇ ਤੇਜ਼, ਵੇਕਟਰਾਈਜ਼ਡ ਓਪਰੇਸ਼ਨ ਅਤੇ ufuncs ਲਈ `NaN` ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ। ਖਰਾਬ ਖਬਰ ਇਹ ਹੈ ਕਿ `NaN` 'ਤੇ ਕੀਤੇ ਗਏ ਕਿਸੇ ਵੀ ਅੰਕਗਣਿਤ ਕਾਰਜ ਦਾ ਨਤੀਜਾ ਹਮੇਸ਼ਾ `NaN` ਹੀ ਹੁੰਦਾ ਹੈ। ਉਦਾਹਰਣ ਲਈ:\n" ] }, { @@ -771,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "ਚੰਗੀ ਖ਼ਬਰ: ਜਿਨ੍ਹਾਂ ਐਰੇਜ਼ ਵਿੱਚ `NaN` ਹੁੰਦੇ ਹਨ, ਉਨ੍ਹਾਂ 'ਤੇ ਚੱਲਣ ਵਾਲੀਆਂ ਐਗ੍ਰਿਗੇਸ਼ਨਜ਼ ਵਿੱਚ ਗਲਤੀਆਂ ਨਹੀਂ ਆਉਂਦੀਆਂ। ਮਾੜੀ ਖ਼ਬਰ: ਨਤੀਜੇ ਹਮੇਸ਼ਾ ਉਪਯੋਗੀ ਨਹੀਂ ਹੁੰਦੇ:\n" + "ਚੰਗੀ ਖਬਰ: ਜਿਨ੍ਹਾਂ ਐਰੇਜ਼ ਵਿੱਚ `NaN` ਹੁੰਦਾ ਹੈ, ਉਨ੍ਹਾਂ 'ਤੇ ਚਲਣ ਵਾਲੀਆਂ ਐਗਰੀਗੇਸ਼ਨਜ਼ ਵਿੱਚ ਗਲਤੀਆਂ ਨਹੀਂ ਆਉਂਦੀਆਂ। ਮੰਦੀ ਖਬਰ: ਨਤੀਜੇ ਸਾਰਿਆਂ ਲਈ ਇੱਕੋ ਜਿਹੇ ਲਾਭਦਾਇਕ ਨਹੀਂ ਹੁੰਦੇ:\n" ] }, { @@ -808,7 +809,7 @@ "id": "nhlnNJT7gRr_" }, "source": [ - "ਵਿਆਯਾਮ:\n" + "### ਕਸਰਤ:\n" ] }, { @@ -829,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "ਯਾਦ ਰੱਖੋ: `NaN` ਸਿਰਫ ਗੁੰਮ ਹੋਈਆਂ ਫਲੋਟਿੰਗ-ਪੌਇੰਟ ਮੁੱਲਾਂ ਲਈ ਹੈ; ਪੂਰਨਾਂ, ਸਤਰਾਂ ਜਾਂ ਬੂਲੀਅਨ ਲਈ ਕੋਈ `NaN` ਸਮਕਾਲੀ ਨਹੀਂ ਹੈ।\n" + ] }, { "cell_type": "markdown", @@ -839,7 +842,7 @@ "source": [ "### `NaN` ਅਤੇ `None`: pandas ਵਿੱਚ null ਮੁੱਲ\n", "\n", - "ਹਾਲਾਂਕਿ `NaN` ਅਤੇ `None` ਕੁਝ ਹੱਦ ਤੱਕ ਵੱਖਰੇ ਤਰੀਕੇ ਨਾਲ ਵਰਤਾਰਾ ਕਰ ਸਕਦੇ ਹਨ, pandas ਫਿਰ ਵੀ ਉਨ੍ਹਾਂ ਨੂੰ ਇੱਕੋ ਜਿਹਾ ਸੰਭਾਲਣ ਲਈ ਬਣਾਇਆ ਗਿਆ ਹੈ। ਇਸ ਗੱਲ ਨੂੰ ਸਮਝਣ ਲਈ, ਆਓ ਇੱਕ integers ਦੀ `Series` ਦੇਖੀਏ:\n" + "ਹਾਲਾਂਕਿ `NaN` ਅਤੇ `None` ਕੁਝ ਹੱਦ ਤੱਕ ਵੱਖਰੇ ਤਰੀਕੇ ਨਾਲ ਵਰਤਾਰਾ ਕਰ ਸਕਦੇ ਹਨ, pandas ਫਿਰ ਵੀ ਇਨ੍ਹਾਂ ਨੂੰ ਇੱਕੋ ਜਿਹਾ ਸੰਭਾਲਣ ਲਈ ਬਣਾਇਆ ਗਿਆ ਹੈ। ਇਸ ਗੱਲ ਨੂੰ ਸਮਝਣ ਲਈ, ਆਓ ਇੱਕ integers ਦੀ `Series` ਦੇਖੀਏ:\n" ] }, { @@ -879,7 +882,7 @@ "id": "WklCzqb8gRsB" }, "source": [ - "ਵਿਆਯਾਮ:\n" + "### ਕਸਰਤ:\n" ] }, { @@ -903,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "ਪਾਂਡਾਸ ਵਿੱਚ `Series` ਅਤੇ `DataFrame`s ਵਿੱਚ ਡਾਟਾ ਦੀ ਇੱਕਸਾਰਤਾ ਸਥਾਪਿਤ ਕਰਨ ਲਈ ਡਾਟਾ ਟਾਈਪਸ ਨੂੰ ਉੱਚੇ ਟਾਈਪਸ ਵਿੱਚ ਬਦਲਣ ਦੀ ਪ੍ਰਕਿਰਿਆ ਦੌਰਾਨ, ਪਾਂਡਾਸ ਆਸਾਨੀ ਨਾਲ ਗੁੰਮ ਹੋਈਆਂ ਕਦਰਾਂ ਨੂੰ `None` ਅਤੇ `NaN` ਦੇ ਵਿਚਕਾਰ ਬਦਲ ਸਕਦਾ ਹੈ। ਇਸ ਡਿਜ਼ਾਈਨ ਵਿਸ਼ੇਸ਼ਤਾ ਕਰਕੇ, ਪਾਂਡਾਸ ਵਿੱਚ `None` ਅਤੇ `NaN` ਨੂੰ \"null\" ਦੇ ਦੋ ਵੱਖ-ਵੱਖ ਰੂਪਾਂ ਵਜੋਂ ਸੋਚਣਾ ਲਾਭਦਾਇਕ ਹੋ ਸਕਦਾ ਹੈ। ਦਰਅਸਲ, ਕੁਝ ਮੁੱਖ ਤਰੀਕੇ ਜੋ ਤੁਸੀਂ ਪਾਂਡਾਸ ਵਿੱਚ ਗੁੰਮ ਹੋਈਆਂ ਕਦਰਾਂ ਨਾਲ ਨਜਿੱਠਣ ਲਈ ਵਰਤਦੇ ਹੋ, ਇਸ ਵਿਚਾਰ ਨੂੰ ਆਪਣੇ ਨਾਮਾਂ ਵਿੱਚ ਦਰਸਾਉਂਦੇ ਹਨ:\n", + "ਡਾਟਾ ਦੀ ਸਮਰੂਪਤਾ ਸਥਾਪਿਤ ਕਰਨ ਲਈ `Series` ਅਤੇ `DataFrame`s ਵਿੱਚ ਡਾਟਾ ਟਾਈਪਸ ਨੂੰ ਉੱਚੇ ਪੱਧਰ 'ਤੇ ਲਿਜਾਣ ਦੀ ਪ੍ਰਕਿਰਿਆ ਵਿੱਚ, pandas ਬਿਨਾਂ ਕਿਸੇ ਹਿਚਕਚਾਹਟ ਦੇ ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ `None` ਅਤੇ `NaN` ਦੇ ਵਿਚਕਾਰ ਬਦਲ ਸਕਦਾ ਹੈ। ਇਸ ਡਿਜ਼ਾਈਨ ਵਿਸ਼ੇਸ਼ਤਾ ਦੇ ਕਾਰਨ, pandas ਵਿੱਚ `None` ਅਤੇ `NaN` ਨੂੰ \"null\" ਦੇ ਦੋ ਵੱਖ-ਵੱਖ ਰੂਪਾਂ ਵਜੋਂ ਸੋਚਣਾ ਸਹੀ ਹੋ ਸਕਦਾ ਹੈ। ਦਰਅਸਲ, pandas ਵਿੱਚ ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨਾਲ ਨਿਪਟਣ ਲਈ ਤੁਸੀਂ ਵਰਤਦੇ ਕੁਝ ਮੁੱਖ ਤਰੀਕੇ ਇਸ ਵਿਚਾਰ ਨੂੰ ਆਪਣੇ ਨਾਮਾਂ ਵਿੱਚ ਦਰਸਾਉਂਦੇ ਹਨ:\n", "\n", - "- `isnull()`: ਗੁੰਮ ਹੋਈਆਂ ਕਦਰਾਂ ਨੂੰ ਦਰਸਾਉਣ ਵਾਲਾ ਬੂਲੀਅਨ ਮਾਸਕ ਤਿਆਰ ਕਰਦਾ ਹੈ\n", + "- `isnull()`: ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਦਰਸਾਉਣ ਵਾਲਾ ਬੂਲੀਅਨ ਮਾਸਕ ਬਣਾਉਂਦਾ ਹੈ\n", "- `notnull()`: `isnull()` ਦਾ ਉਲਟ\n", - "- `dropna()`: ਡਾਟੇ ਦਾ ਇੱਕ ਫਿਲਟਰ ਕੀਤਾ ਹੋਇਆ ਸੰਸਕਰਣ ਵਾਪਸ ਕਰਦਾ ਹੈ\n", - "- `fillna()`: ਗੁੰਮ ਹੋਈਆਂ ਕਦਰਾਂ ਨੂੰ ਭਰ ਕੇ ਜਾਂ ਅਨੁਮਾਨ ਲਗਾ ਕੇ ਡਾਟੇ ਦੀ ਇੱਕ ਕਾਪੀ ਵਾਪਸ ਕਰਦਾ ਹੈ\n", + "- `dropna()`: ਡਾਟਾ ਦਾ ਇੱਕ ਫਿਲਟਰ ਕੀਤਾ ਸੰਸਕਰਣ ਵਾਪਸ ਕਰਦਾ ਹੈ\n", + "- `fillna()`: ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਭਰ ਕੇ ਜਾਂ ਅਨੁਮਾਨ ਲਗਾ ਕੇ ਡਾਟਾ ਦੀ ਇੱਕ ਕਾਪੀ ਵਾਪਸ ਕਰਦਾ ਹੈ\n", "\n", - "ਇਹ ਤਰੀਕੇ ਸਿੱਖਣ ਅਤੇ ਇਨ੍ਹਾਂ ਨਾਲ ਆਰਾਮਦਾਇਕ ਹੋਣਾ ਬਹੁਤ ਜ਼ਰੂਰੀ ਹੈ, ਇਸ ਲਈ ਆਓ ਅਸੀਂ ਹਰ ਇੱਕ ਨੂੰ ਥੋੜ੍ਹੀ ਹੋਰ ਗਹਿਰਾਈ ਨਾਲ ਸਮਝੀਏ।\n" + "ਇਹ ਤਰੀਕੇ ਸਿੱਖਣ ਅਤੇ ਆਰਾਮਦਾਇਕ ਹੋਣ ਲਈ ਬਹੁਤ ਮਹੱਤਵਪੂਰਨ ਹਨ, ਇਸ ਲਈ ਆਓ ਇਨ੍ਹਾਂ ਨੂੰ ਵੱਖ-ਵੱਖ ਗਹਿਰਾਈ ਨਾਲ ਸਮਝੀਏ।\n" ] }, { @@ -919,10 +922,10 @@ "id": "Yh5ifd9FgRsB" }, "source": [ - "### ਨੱਲ ਮੁੱਲਾਂ ਦੀ ਪਛਾਣ ਕਰਨਾ\n", + "### ਨੱਲ ਮੁੱਲਾਂ ਦੀ ਪਹਿਚਾਣ ਕਰਨਾ\n", "\n", - "ਹੁਣ ਜਦੋਂ ਅਸੀਂ ਗੁੰਮਸ਼ੁਦਾ ਮੁੱਲਾਂ ਦੀ ਮਹੱਤਤਾ ਨੂੰ ਸਮਝ ਲਿਆ ਹੈ, ਤਾਂ ਸਾਨੂੰ ਉਹਨਾਂ ਨਾਲ ਨਿਪਟਣ ਤੋਂ ਪਹਿਲਾਂ ਆਪਣੇ ਡਾਟਾਸੈੱਟ ਵਿੱਚ ਉਹਨਾਂ ਦੀ ਪਛਾਣ ਕਰਨੀ ਚਾਹੀਦੀ ਹੈ। \n", - "`isnull()` ਅਤੇ `notnull()` ਦੋਵੇਂ ਹੀ ਨੱਲ ਡਾਟਾ ਦੀ ਪਛਾਣ ਕਰਨ ਲਈ ਤੁਹਾਡੇ ਮੁੱਖ ਤਰੀਕੇ ਹਨ। ਦੋਵੇਂ ਤੁਹਾਡੇ ਡਾਟਾ 'ਤੇ ਬੂਲੀਅਨ ਮਾਸਕ ਵਾਪਸ ਕਰਦੇ ਹਨ।\n" + "ਹੁਣ ਜਦੋਂ ਅਸੀਂ ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਦੀ ਮਹੱਤਤਾ ਨੂੰ ਸਮਝ ਲਿਆ ਹੈ, ਤਾਂ ਅਸੀਂ ਆਪਣੇ ਡਾਟਾਸੈਟ ਵਿੱਚ ਉਨ੍ਹਾਂ ਦੀ ਪਹਿਚਾਣ ਕਰਨੀ ਚਾਹੀਦੀ ਹੈ, ਇਸ ਨਾਲ ਨਜਿੱਠਣ ਤੋਂ ਪਹਿਲਾਂ। \n", + "`isnull()` ਅਤੇ `notnull()` ਦੋਵੇਂ ਨੱਲ ਡਾਟਾ ਦੀ ਪਹਿਚਾਣ ਕਰਨ ਲਈ ਤੁਹਾਡੇ ਮੁੱਖ ਤਰੀਕੇ ਹਨ। ਦੋਵੇਂ ਤੁਹਾਡੇ ਡਾਟੇ 'ਤੇ ਬੂਲੀਅਨ ਮਾਸਕ ਵਾਪਸ ਕਰਦੇ ਹਨ।\n" ] }, { @@ -975,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "ਆਪਣੇ ਆਉਟਪੁੱਟ ਨੂੰ ਧਿਆਨ ਨਾਲ ਦੇਖੋ। ਕੀ ਇਸ ਵਿੱਚੋਂ ਕੋਈ ਚੀਜ਼ ਤੁਹਾਨੂੰ ਹੈਰਾਨ ਕਰਦੀ ਹੈ? ਜਦੋਂ ਕਿ `0` ਇੱਕ ਗਣਿਤਕ ਨਲ ਹੈ, ਇਹ ਫਿਰ ਵੀ ਇੱਕ ਬਹੁਤ ਵਧੀਆ ਪੂਰਨ ਅੰਕ ਹੈ ਅਤੇ pandas ਇਸਨੂੰ ਇਸ ਤਰ੍ਹਾਂ ਹੀ ਮੰਨਦਾ ਹੈ। `''` ਕੁਝ ਹੱਦ ਤੱਕ ਹੋਰ ਸੁਖਮ ਹੈ। ਜਦੋਂ ਕਿ ਅਸੀਂ ਇਸਨੂੰ ਭਾਗ 1 ਵਿੱਚ ਖਾਲੀ ਸਤਰ ਦੀ ਮੁੱਲ ਦਰਸਾਉਣ ਲਈ ਵਰਤਿਆ ਸੀ, ਇਹ ਫਿਰ ਵੀ ਇੱਕ ਸਤਰ ਵਸਤੂ ਹੈ ਅਤੇ pandas ਦੇ ਹਿਸਾਬ ਨਾਲ ਨਲ ਦੀ ਪ੍ਰਤੀਨਿਧਤਾ ਨਹੀਂ ਹੈ।\n", + "ਧਿਆਨ ਨਾਲ ਨਤੀਜੇ ਨੂੰ ਦੇਖੋ। ਕੀ ਇਸ ਵਿੱਚੋਂ ਕੋਈ ਚੀਜ਼ ਤੁਹਾਨੂੰ ਹੈਰਾਨ ਕਰਦੀ ਹੈ? ਜਦੋਂ ਕਿ `0` ਇੱਕ ਗਣਿਤਕ null ਹੈ, ਇਹ ਫਿਰ ਵੀ ਇੱਕ ਬਹੁਤ ਵਧੀਆ ਪੂਰਨ ਅੰਕ ਹੈ ਅਤੇ pandas ਇਸਨੂੰ ਇਸੇ ਤਰ੍ਹਾਂ ਮੰਨਦਾ ਹੈ। `''` ਕੁਝ ਹੱਦ ਤੱਕ ਜ਼ਿਆਦਾ ਸੁਖਮ ਹੈ। ਜਦੋਂ ਕਿ ਅਸੀਂ ਇਸਨੂੰ ਭਾਗ 1 ਵਿੱਚ ਖਾਲੀ ਸਤਰ ਦੀ ਮੂਲਤਾ ਦਰਸਾਉਣ ਲਈ ਵਰਤਿਆ ਸੀ, ਇਹ ਫਿਰ ਵੀ ਇੱਕ ਸਤਰ ਵਸਤੂ ਹੈ ਅਤੇ pandas ਦੇ ਹਿਸਾਬ ਨਾਲ null ਦੀ ਨੁਮਾਇੰਦਗੀ ਨਹੀਂ ਹੈ।\n", "\n", - "ਹੁਣ, ਆਓ ਇਸਨੂੰ ਉਲਟਾ ਕਰੀਏ ਅਤੇ ਇਹਨਾਂ ਤਰੀਕਿਆਂ ਨੂੰ ਇਸ ਤਰ੍ਹਾਂ ਵਰਤਾਂ ਜਿਵੇਂ ਤੁਸੀਂ ਅਮਲ ਵਿੱਚ ਵਰਤੋਂਗੇ। ਤੁਸੀਂ Boolean masks ਨੂੰ ਸਿੱਧੇ ਤੌਰ 'ਤੇ ``Series`` ਜਾਂ ``DataFrame`` ਇੰਡੈਕਸ ਵਜੋਂ ਵਰਤ ਸਕਦੇ ਹੋ, ਜੋ ਕਿ ਅਲੱਗ-ਅਲੱਗ ਗੁੰਮ (ਜਾਂ ਮੌਜੂਦ) ਮੁੱਲਾਂ ਨਾਲ ਕੰਮ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਲਾਭਦਾਇਕ ਹੋ ਸਕਦਾ ਹੈ।\n", + "ਹੁਣ, ਆਓ ਇਸਨੂੰ ਵਿਰੋਧੀ ਦਿਸ਼ਾ ਵਿੱਚ ਮੋੜੀਏ ਅਤੇ ਇਹਨਾਂ ਤਰੀਕਿਆਂ ਨੂੰ ਇਸ ਤਰ੍ਹਾਂ ਵਰਤਾਂਗੇ ਜਿਵੇਂ ਤੁਸੀਂ ਅਮਲ ਵਿੱਚ ਇਹਨਾਂ ਨੂੰ ਵਰਤੋਂਗੇ। ਤੁਸੀਂ Boolean masks ਨੂੰ ਸਿੱਧੇ ਤੌਰ 'ਤੇ ``Series`` ਜਾਂ ``DataFrame`` ਇੰਡੈਕਸ ਵਜੋਂ ਵਰਤ ਸਕਦੇ ਹੋ, ਜੋ ਕਿ ਖਾਸ ਤੌਰ 'ਤੇ ਗੁੰਮ ਹੋਈਆਂ (ਜਾਂ ਮੌਜੂਦ) ਮੁੱਲਾਂ ਨਾਲ ਕੰਮ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਲਾਭਦਾਇਕ ਹੋ ਸਕਦਾ ਹੈ।\n", "\n", - "ਜੇਕਰ ਅਸੀਂ ਗੁੰਮ ਮੁੱਲਾਂ ਦੀ ਕੁੱਲ ਗਿਣਤੀ ਚਾਹੁੰਦੇ ਹਾਂ, ਤਾਂ ਅਸੀਂ ਸਿਰਫ `isnull()` ਤਰੀਕੇ ਦੁਆਰਾ ਬਣਾਈ ਗਈ mask 'ਤੇ ਇੱਕ ਜੋੜ ਕਰ ਸਕਦੇ ਹਾਂ।\n" + "ਜੇਕਰ ਅਸੀਂ ਗੁੰਮ ਹੋਈਆਂ ਮੁੱਲਾਂ ਦੀ ਕੁੱਲ ਗਿਣਤੀ ਚਾਹੁੰਦੇ ਹਾਂ, ਤਾਂ ਅਸੀਂ ਸਿਰਫ `isnull()` ਤਰੀਕੇ ਦੁਆਰਾ ਬਣਾਈ ਗਈ mask 'ਤੇ ਇੱਕ ਜੋੜ ਕਰ ਸਕਦੇ ਹਾਂ।\n" ] }, { @@ -1014,7 +1017,7 @@ "id": "PlBqEo3mgRsC" }, "source": [ - "ਵਿਆਯਾਮ:\n" + "### ਕਸਰਤ:\n" ] }, { @@ -1037,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**ਮੁੱਖ ਨਿਸ਼ਕਰਸ਼**: ਜਦੋਂ ਤੁਸੀਂ ਇਨ੍ਹਾਂ ਨੂੰ ਡਾਟਾਫ੍ਰੇਮਜ਼ ਵਿੱਚ ਵਰਤਦੇ ਹੋ, ਤਾਂ `isnull()` ਅਤੇ `notnull()` ਦੋਵੇਂ ਵਿਧੀਆਂ ਸਮਾਨ ਨਤੀਜੇ ਪੈਦਾ ਕਰਦੀਆਂ ਹਨ: ਇਹ ਨਤੀਜੇ ਅਤੇ ਉਨ੍ਹਾਂ ਦੇ ਸੂਚਕਾਂਕ ਦਿਖਾਉਂਦੀਆਂ ਹਨ, ਜੋ ਤੁਹਾਡੀ ਡਾਟਾ ਨਾਲ ਨਿਪਟਣ ਦੌਰਾਨ ਤੁਹਾਡੀ ਬਹੁਤ ਮਦਦ ਕਰਨਗੀਆਂ।\n" + "**ਮੁੱਖ ਨਿਸ਼ਕਰਸ਼**: ਦੋਵੇਂ `isnull()` ਅਤੇ `notnull()` ਵਿਧੀਆਂ ਸਮਾਨ ਨਤੀਜੇ ਪੈਦਾ ਕਰਦੀਆਂ ਹਨ ਜਦੋਂ ਤੁਸੀਂ ਉਨ੍ਹਾਂ ਨੂੰ ਡਾਟਾ ਫਰੇਮਜ਼ ਵਿੱਚ ਵਰਤਦੇ ਹੋ: ਇਹ ਨਤੀਜੇ ਅਤੇ ਉਨ੍ਹਾਂ ਦੇ ਇੰਡੈਕਸ ਦਿਖਾਉਂਦੀਆਂ ਹਨ, ਜੋ ਤੁਹਾਡੀ ਡਾਟਾ ਨਾਲ ਕੰਮ ਕਰਨ ਦੌਰਾਨ ਤੁਹਾਡੀ ਬਹੁਤ ਮਦਦ ਕਰਨਗੀਆਂ।\n" ] }, { @@ -1046,20 +1049,20 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### ਗੁੰਮ ਡਾਟਾ ਨਾਲ ਨਿਪਟਣਾ\n", + "### ਗੁੰਮ ਹੋਏ ਡਾਟਾ ਨਾਲ ਨਿਪਟਣਾ\n", "\n", - "> **ਸਿੱਖਣ ਦਾ ਮਕਸਦ:** ਇਸ ਉਪਵਿਭਾਗ ਦੇ ਅੰਤ ਤੱਕ, ਤੁਸੀਂ ਜਾਣ ਸਕੋਗੇ ਕਿ DataFrames ਵਿੱਚੋਂ null ਮੁੱਲਾਂ ਨੂੰ ਕਦੋਂ ਅਤੇ ਕਿਵੇਂ ਬਦਲਣਾ ਜਾਂ ਹਟਾਉਣਾ ਹੈ।\n", + "> **ਸਿੱਖਣ ਦਾ ਉਦੇਸ਼:** ਇਸ ਉਪਵਿਭਾਗ ਦੇ ਅੰਤ ਤੱਕ, ਤੁਸੀਂ ਜਾਣ ਸਕੋਗੇ ਕਿ DataFrames ਵਿੱਚ null ਮੁੱਲਾਂ ਨੂੰ ਕਿਵੇਂ ਅਤੇ ਕਦੋਂ ਬਦਲਣਾ ਜਾਂ ਹਟਾਉਣਾ ਹੈ।\n", "\n", - "Machine Learning ਮਾਡਲ ਖੁਦ ਗੁੰਮ ਡਾਟਾ ਨਾਲ ਨਿਪਟ ਨਹੀਂ ਕਰ ਸਕਦੇ। ਇਸ ਲਈ, ਡਾਟਾ ਨੂੰ ਮਾਡਲ ਵਿੱਚ ਪਾਸ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ, ਸਾਨੂੰ ਇਨ੍ਹਾਂ ਗੁੰਮ ਮੁੱਲਾਂ ਨਾਲ ਨਿਪਟਣਾ ਪਵੇਗਾ।\n", + "Machine Learning ਮਾਡਲ ਆਪਣੇ ਆਪ ਗੁੰਮ ਹੋਏ ਡਾਟਾ ਨਾਲ ਨਿਪਟ ਨਹੀਂ ਕਰ ਸਕਦੇ। ਇਸ ਲਈ, ਮਾਡਲ ਵਿੱਚ ਡਾਟਾ ਪਾਸ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ, ਸਾਨੂੰ ਇਨ੍ਹਾਂ ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨਾਲ ਨਿਪਟਣਾ ਪਵੇਗਾ।\n", "\n", - "ਗੁੰਮ ਡਾਟਾ ਨੂੰ ਕਿਵੇਂ ਹੱਲ ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਇਸ ਨਾਲ ਨਰਮ-ਨਰਮ ਤਰਾਜੂ ਜੁੜੇ ਹੋਏ ਹਨ, ਜੋ ਤੁਹਾਡੇ ਅੰਤਿਮ ਵਿਸ਼ਲੇਸ਼ਣ ਅਤੇ ਹਕੀਕਤੀ ਨਤੀਜਿਆਂ ਨੂੰ ਪ੍ਰਭਾਵਿਤ ਕਰ ਸਕਦੇ ਹਨ।\n", + "ਗੁੰਮ ਹੋਏ ਡਾਟਾ ਨੂੰ ਕਿਵੇਂ ਸੰਭਾਲਿਆ ਜਾਂਦਾ ਹੈ, ਇਸ ਨਾਲ ਨਰਮ-ਨਰਮ ਤਰੱਕੀਆਂ ਜੁੜੀਆਂ ਹੁੰਦੀਆਂ ਹਨ, ਜੋ ਤੁਹਾਡੇ ਅੰਤਿਮ ਵਿਸ਼ਲੇਸ਼ਣ ਅਤੇ ਹਕੀਕਤੀ-ਜਗਤ ਦੇ ਨਤੀਜਿਆਂ ਨੂੰ ਪ੍ਰਭਾਵਿਤ ਕਰ ਸਕਦੀਆਂ ਹਨ।\n", "\n", - "ਗੁੰਮ ਡਾਟਾ ਨਾਲ ਨਿਪਟਣ ਦੇ ਮੁੱਖ ਤੌਰ 'ਤੇ ਦੋ ਤਰੀਕੇ ਹਨ:\n", + "ਗੁੰਮ ਹੋਏ ਡਾਟਾ ਨਾਲ ਨਿਪਟਣ ਦੇ ਮੁੱਖ ਤੌਰ 'ਤੇ ਦੋ ਤਰੀਕੇ ਹਨ:\n", "\n", - "1. ਉਸ ਕਤਾਰ ਨੂੰ ਹਟਾਉਣਾ ਜਿਸ ਵਿੱਚ ਗੁੰਮ ਮੁੱਲ ਹੈ \n", - "2. ਗੁੰਮ ਮੁੱਲ ਨੂੰ ਕਿਸੇ ਹੋਰ ਮੁੱਲ ਨਾਲ ਬਦਲਣਾ \n", + "1. ਗੁੰਮ ਹੋਏ ਮੁੱਲ ਵਾਲੀ ਪੰਕਤੀ ਨੂੰ ਹਟਾਓ\n", + "2. ਗੁੰਮ ਹੋਏ ਮੁੱਲ ਨੂੰ ਕਿਸੇ ਹੋਰ ਮੁੱਲ ਨਾਲ ਬਦਲੋ\n", "\n", - "ਅਸੀਂ ਦੋਵੇਂ ਤਰੀਕਿਆਂ ਅਤੇ ਉਨ੍ਹਾਂ ਦੇ ਫਾਇਦੇ ਅਤੇ ਨੁਕਸਾਨਾਂ ਨੂੰ ਵਿਸਥਾਰ ਵਿੱਚ ਚਰਚਾ ਕਰਾਂਗੇ। \n" + "ਅਸੀਂ ਦੋਵੇਂ ਤਰੀਕਿਆਂ ਅਤੇ ਉਨ੍ਹਾਂ ਦੇ ਫਾਇਦੇ ਅਤੇ ਨੁਕਸਾਨਾਂ ਨੂੰ ਵਿਸਥਾਰ ਵਿੱਚ ਚਰਚਾ ਕਰਾਂਗੇ।\n" ] }, { @@ -1068,13 +1071,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### ਨੱਲ ਮੁੱਲਾਂ ਨੂੰ ਹਟਾਉਣਾ\n", + "### ਨਲ ਮੁੱਲਾਂ ਨੂੰ ਹਟਾਉਣਾ\n", "\n", - "ਜਿੰਨੀ ਡਾਟਾ ਅਸੀਂ ਆਪਣੇ ਮਾਡਲ ਨੂੰ ਦਿੰਦੇ ਹਾਂ, ਉਸਦਾ ਸਿੱਧਾ ਅਸਰ ਇਸਦੀ ਪ੍ਰਦਰਸ਼ਨਸ਼ੀਲਤਾ 'ਤੇ ਪੈਂਦਾ ਹੈ। ਨੱਲ ਮੁੱਲਾਂ ਨੂੰ ਹਟਾਉਣ ਦਾ ਮਤਲਬ ਹੈ ਕਿ ਅਸੀਂ ਡਾਟਾਪੌਇੰਟਸ ਦੀ ਗਿਣਤੀ ਘਟਾ ਰਹੇ ਹਾਂ, ਅਤੇ ਇਸ ਤਰ੍ਹਾਂ ਡਾਟਾਸੈੱਟ ਦਾ ਆਕਾਰ ਘਟਾ ਰਹੇ ਹਾਂ। ਇਸ ਲਈ, ਜਦੋਂ ਡਾਟਾਸੈੱਟ ਕਾਫ਼ੀ ਵੱਡਾ ਹੋਵੇ, ਤਾਂ ਨੱਲ ਮੁੱਲਾਂ ਵਾਲੀਆਂ ਕਤਾਰਾਂ ਨੂੰ ਹਟਾਉਣਾ ਸਲਾਹਯੋਗ ਹੈ।\n", + "ਜਿੰਨੀ ਡਾਟਾ ਅਸੀਂ ਆਪਣੇ ਮਾਡਲ ਨੂੰ ਪਾਸ ਕਰਦੇ ਹਾਂ, ਉਸਦਾ ਸਿੱਧਾ ਅਸਰ ਇਸਦੀ ਕਾਰਗੁਜ਼ਾਰੀ 'ਤੇ ਪੈਂਦਾ ਹੈ। ਨਲ ਮੁੱਲਾਂ ਨੂੰ ਹਟਾਉਣ ਦਾ ਮਤਲਬ ਹੈ ਕਿ ਅਸੀਂ ਡਾਟਾਪੌਇੰਟਸ ਦੀ ਗਿਣਤੀ ਘਟਾ ਰਹੇ ਹਾਂ, ਅਤੇ ਇਸ ਤਰ੍ਹਾਂ ਡਾਟਾਸੈਟ ਦਾ ਆਕਾਰ ਘਟਾ ਰਹੇ ਹਾਂ। ਇਸ ਲਈ, ਜਦੋਂ ਡਾਟਾਸੈਟ ਕਾਫੀ ਵੱਡਾ ਹੋਵੇ, ਤਾਂ ਨਲ ਮੁੱਲਾਂ ਵਾਲੀਆਂ ਪੰਗਤਾਂ ਨੂੰ ਹਟਾਉਣਾ ਸਲਾਹਯੋਗ ਹੈ।\n", "\n", - "ਇੱਕ ਹੋਰ ਹਾਲਤ ਇਹ ਹੋ ਸਕਦੀ ਹੈ ਕਿ ਕਿਸੇ ਖਾਸ ਕਤਾਰ ਜਾਂ ਕਾਲਮ ਵਿੱਚ ਬਹੁਤ ਸਾਰੇ ਗੁੰਮ ਮੁੱਲ ਹੋਣ। ਫਿਰ, ਉਹਨਾਂ ਨੂੰ ਹਟਾਇਆ ਜਾ ਸਕਦਾ ਹੈ ਕਿਉਂਕਿ ਉਹ ਸਾਡੇ ਵਿਸ਼ਲੇਸ਼ਣ ਵਿੱਚ ਜ਼ਿਆਦਾ ਮੂਲ ਭਾਗ ਨਹੀਂ ਜੋੜਣਗੇ, ਕਿਉਂਕਿ ਉਸ ਕਤਾਰ/ਕਾਲਮ ਲਈ ਜ਼ਿਆਦਾਤਰ ਡਾਟਾ ਗੁੰਮ ਹੈ।\n", + "ਇਕ ਹੋਰ ਹਾਲਾਤ ਇਹ ਹੋ ਸਕਦੀ ਹੈ ਕਿ ਕਿਸੇ ਖਾਸ ਪੰਗਤੀ ਜਾਂ ਕਾਲਮ ਵਿੱਚ ਬਹੁਤ ਸਾਰੇ ਮੁੱਲ ਗੁੰਮ ਹੋਣ। ਫਿਰ, ਉਹਨਾਂ ਨੂੰ ਹਟਾਇਆ ਜਾ ਸਕਦਾ ਹੈ ਕਿਉਂਕਿ ਉਹ ਸਾਡੇ ਵਿਸ਼ਲੇਸ਼ਣ ਵਿੱਚ ਜ਼ਿਆਦਾ ਮੂਲ ਨਹੀਂ ਜੋੜਦੇ, ਕਿਉਂਕਿ ਉਸ ਪੰਗਤੀ/ਕਾਲਮ ਲਈ ਜ਼ਿਆਦਾਤਰ ਡਾਟਾ ਗੁੰਮ ਹੈ।\n", "\n", - "ਗੁੰਮ ਮੁੱਲਾਂ ਦੀ ਪਛਾਣ ਕਰਨ ਤੋਂ ਇਲਾਵਾ, pandas `Series` ਅਤੇ `DataFrame`s ਤੋਂ ਨੱਲ ਮੁੱਲਾਂ ਨੂੰ ਹਟਾਉਣ ਦਾ ਇੱਕ ਆਸਾਨ ਤਰੀਕਾ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ। ਇਸਨੂੰ ਕਿਰਿਆਸ਼ੀਲਤਾ ਵਿੱਚ ਦੇਖਣ ਲਈ, ਆਓ `example3` ਵੱਲ ਮੁੜ ਚੱਲੀਏ। `DataFrame.dropna()` ਫੰਕਸ਼ਨ ਨੱਲ ਮੁੱਲਾਂ ਵਾਲੀਆਂ ਕਤਾਰਾਂ ਨੂੰ ਹਟਾਉਣ ਵਿੱਚ ਮਦਦ ਕਰਦਾ ਹੈ।\n" + "ਨਲ ਮੁੱਲਾਂ ਦੀ ਪਹਿਚਾਣ ਤੋਂ ਇਲਾਵਾ, pandas `Series` ਅਤੇ `DataFrame`s ਤੋਂ ਨਲ ਮੁੱਲਾਂ ਨੂੰ ਹਟਾਉਣ ਲਈ ਇੱਕ ਸੁਵਿਧਾਜਨਕ ਤਰੀਕਾ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ। ਇਸਨੂੰ ਕਾਰਵਾਈ ਵਿੱਚ ਦੇਖਣ ਲਈ, ਆਓ `example3` ਵੱਲ ਵਾਪਸ ਚਲਦੇ ਹਾਂ। `DataFrame.dropna()` ਫੰਕਸ਼ਨ ਨਲ ਮੁੱਲਾਂ ਵਾਲੀਆਂ ਪੰਗਤਾਂ ਨੂੰ ਹਟਾਉਣ ਵਿੱਚ ਮਦਦ ਕਰਦਾ ਹੈ।\n" ] }, { @@ -1113,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "ਨੋਟ ਕਰੋ ਕਿ ਇਹ ਤੁਹਾਡੇ `example3[example3.notnull()]` ਦੇ ਆਉਟਪੁੱਟ ਵਰਗਾ ਦਿਖਾਈ ਦੇਣਾ ਚਾਹੀਦਾ ਹੈ। ਇੱਥੇ ਫਰਕ ਇਹ ਹੈ ਕਿ, ਸਿਰਫ ਮਾਸਕ ਕੀਤੇ ਗਏ ਮੁੱਲਾਂ 'ਤੇ ਇੰਡੈਕਸ ਕਰਨ ਦੀ ਬਜਾਇ, `dropna` ਨੇ `Series` `example3` ਵਿੱਚੋਂ ਉਹ ਗੁੰਮ ਹੋਏ ਮੁੱਲ ਹਟਾ ਦਿੱਤੇ ਹਨ।\n", + "ਇਹ ਗੌਰ ਕਰੋ ਕਿ ਇਹ ਤੁਹਾਡੇ `example3[example3.notnull()]` ਦੇ ਆਉਟਪੁੱਟ ਵਰਗਾ ਹੀ ਦਿਖਾਈ ਦੇਣਾ ਚਾਹੀਦਾ ਹੈ। ਇੱਥੇ ਫਰਕ ਇਹ ਹੈ ਕਿ, ਸਿਰਫ ਮਾਸਕ ਕੀਤੇ ਗਏ ਮੁੱਲਾਂ 'ਤੇ ਇੰਡੈਕਸਿੰਗ ਕਰਨ ਦੀ ਬਜਾਇ, `dropna` ਨੇ `Series` `example3` ਤੋਂ ਉਹ ਗੁੰਮ ਹੋਏ ਮੁੱਲ ਹਟਾ ਦਿੱਤੇ ਹਨ।\n", "\n", - "ਕਿਉਂਕਿ DataFrames ਦੋ ਮਾਪਾਂ ਵਾਲੇ ਹੁੰਦੇ ਹਨ, ਇਹ ਡਾਟਾ ਹਟਾਉਣ ਲਈ ਹੋਰ ਵਿਕਲਪ ਪ੍ਰਦਾਨ ਕਰਦੇ ਹਨ।\n" + "ਕਿਉਂਕਿ DataFrames ਵਿੱਚ ਦੋ ਮਾਪ ਹੁੰਦੇ ਹਨ, ਇਹ ਡਾਟਾ ਹਟਾਉਣ ਲਈ ਹੋਰ ਵਿਕਲਪ ਪ੍ਰਦਾਨ ਕਰਦੇ ਹਨ।\n" ] }, { @@ -1205,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(ਕੀ ਤੁਸੀਂ ਧਿਆਨ ਦਿੱਤਾ ਕਿ pandas ਨੇ `NaN`s ਨੂੰ ਸਮਝਣ ਲਈ ਦੋ ਕਾਲਮਾਂ ਨੂੰ ਫਲੋਟ ਵਿੱਚ ਅਪਕਾਸਟ ਕੀਤਾ?)\n", + "(ਕੀ ਤੁਸੀਂ ਧਿਆਨ ਦਿੱਤਾ ਕਿ pandas ਨੇ `NaN`s ਨੂੰ ਸਮਝਣ ਲਈ ਦੋ ਕਾਲਮਾਂ ਨੂੰ floats ਵਿੱਚ ਬਦਲ ਦਿੱਤਾ?)\n", "\n", - "ਤੁਸੀਂ `DataFrame` ਤੋਂ ਇੱਕ ਹੀ ਮੁੱਲ ਨਹੀਂ ਹਟਾ ਸਕਦੇ, ਇਸ ਲਈ ਤੁਹਾਨੂੰ ਪੂਰੀਆਂ ਪੰਗਤਾਂ ਜਾਂ ਕਾਲਮਾਂ ਹਟਾਉਣੇ ਪੈਂਦੇ ਹਨ। ਜੋ ਕੁਝ ਤੁਸੀਂ ਕਰ ਰਹੇ ਹੋ, ਉਸ ਦੇ ਆਧਾਰ 'ਤੇ ਤੁਸੀਂ ਇੱਕ ਜਾਂ ਦੂਜਾ ਚੋਣ ਸਕਦੇ ਹੋ, ਅਤੇ ਇਸ ਲਈ pandas ਤੁਹਾਨੂੰ ਦੋਨੋਂ ਲਈ ਵਿਕਲਪ ਦਿੰਦਾ ਹੈ। ਕਿਉਂਕਿ ਡਾਟਾ ਸਾਇੰਸ ਵਿੱਚ, ਕਾਲਮ ਆਮ ਤੌਰ 'ਤੇ ਵੈਰੀਏਬਲ ਨੂੰ ਦਰਸਾਉਂਦੇ ਹਨ ਅਤੇ ਪੰਗਤਾਂ ਅਵਲੋਕਨ ਨੂੰ ਦਰਸਾਉਂਦੀਆਂ ਹਨ, ਤੁਸੀਂ ਡਾਟਾ ਦੀਆਂ ਪੰਗਤਾਂ ਨੂੰ ਹਟਾਉਣ ਦੀ ਸੰਭਾਵਨਾ ਵਧੇਰੇ ਰੱਖਦੇ ਹੋ; `dropna()` ਲਈ ਡਿਫਾਲਟ ਸੈਟਿੰਗ ਇਹ ਹੈ ਕਿ ਉਹ ਸਾਰੀਆਂ ਪੰਗਤਾਂ ਨੂੰ ਹਟਾ ਦਿੰਦਾ ਹੈ ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਕੋਈ ਵੀ null ਮੁੱਲ ਹੁੰਦਾ ਹੈ:\n" + "ਤੁਸੀਂ `DataFrame` ਵਿੱਚੋਂ ਇੱਕ ਹੀ ਮੁੱਲ ਨਹੀਂ ਹਟਾ ਸਕਦੇ, ਇਸ ਲਈ ਤੁਹਾਨੂੰ ਪੂਰੀਆਂ ਪੰਗਤਾਂ ਜਾਂ ਕਾਲਮਾਂ ਨੂੰ ਹਟਾਉਣਾ ਪਵੇਗਾ। ਜੋ ਕੁਝ ਤੁਸੀਂ ਕਰ ਰਹੇ ਹੋ, ਉਸ ਦੇ ਆਧਾਰ 'ਤੇ ਤੁਸੀਂ ਇੱਕ ਜਾਂ ਦੂਜਾ ਚੋਣ ਕਰ ਸਕਦੇ ਹੋ, ਅਤੇ ਇਸ ਲਈ pandas ਤੁਹਾਨੂੰ ਦੋਵੇਂ ਲਈ ਵਿਕਲਪ ਦਿੰਦਾ ਹੈ। ਕਿਉਂਕਿ ਡਾਟਾ ਸਾਇੰਸ ਵਿੱਚ, ਕਾਲਮ ਆਮ ਤੌਰ 'ਤੇ ਵੈਰੀਏਬਲਾਂ ਨੂੰ ਦਰਸਾਉਂਦੇ ਹਨ ਅਤੇ ਪੰਗਤਾਂ ਅਵਲੋਕਨ ਨੂੰ ਦਰਸਾਉਂਦੀਆਂ ਹਨ, ਤੁਸੀਂ ਡਾਟਾ ਦੀਆਂ ਪੰਗਤਾਂ ਨੂੰ ਹਟਾਉਣ ਦੀ ਸੰਭਾਵਨਾ ਵਧੇਰੇ ਰੱਖਦੇ ਹੋ; `dropna()` ਲਈ ਡਿਫਾਲਟ ਸੈਟਿੰਗ ਇਹ ਹੈ ਕਿ ਉਹ ਸਾਰੀਆਂ ਪੰਗਤਾਂ ਨੂੰ ਹਟਾ ਦਿੰਦਾ ਹੈ ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਕੋਈ ਵੀ null ਮੁੱਲ ਹੁੰਦਾ ਹੈ:\n" ] }, { @@ -1280,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "ਜੇ ਲੋੜੀਂਦਾ ਹੋਵੇ, ਤਾਂ ਤੁਸੀਂ ਕਾਲਮਾਂ ਤੋਂ NA ਮੁੱਲਾਂ ਨੂੰ ਹਟਾ ਸਕਦੇ ਹੋ। ਇਸ ਲਈ `axis=1` ਵਰਤੋ:\n" + "ਜੇ ਜ਼ਰੂਰੀ ਹੋਵੇ, ਤਾਂ ਤੁਸੀਂ ਕਾਲਮਾਂ ਤੋਂ NA ਮੁੱਲਾਂ ਨੂੰ ਹਟਾ ਸਕਦੇ ਹੋ। ਇਸ ਲਈ `axis=1` ਦੀ ਵਰਤੋਂ ਕਰੋ:\n" ] }, { @@ -1359,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "ਇਹ ਧਿਆਨ ਵਿੱਚ ਰੱਖੋ ਕਿ ਇਹ ਛੋਟੇ ਡਾਟਾਸੈਟ ਵਿੱਚ ਕਾਫ਼ੀ ਡਾਟਾ ਗੁਆ ਸਕਦਾ ਹੈ, ਜੋ ਤੁਸੀਂ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ। ਕੀ ਹੋਵੇ ਜੇ ਤੁਸੀਂ ਸਿਰਫ਼ ਉਹ ਪੰਗਤਾਂ ਜਾਂ ਕਾਲਮ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਕਈ ਜਾਂ ਸਾਰੇ null ਮੁੱਲ ਹਨ? ਤੁਸੀਂ ਇਹ ਸੈਟਿੰਗ `dropna` ਵਿੱਚ `how` ਅਤੇ `thresh` ਪੈਰਾਮੀਟਰਾਂ ਨਾਲ ਨਿਰਧਾਰਤ ਕਰਦੇ ਹੋ।\n", + "ਧਿਆਨ ਦਿਓ ਕਿ ਇਸ ਨਾਲ ਕਈ ਡਾਟਾ ਖਤਮ ਹੋ ਸਕਦਾ ਹੈ ਜੋ ਤੁਸੀਂ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ, ਖਾਸ ਕਰਕੇ ਛੋਟੇ ਡਾਟਾਸੈਟ ਵਿੱਚ। ਕੀ ਹੋਵੇ ਜੇ ਤੁਸੀਂ ਸਿਰਫ ਉਹ ਪੰਗਤਾਂ ਜਾਂ ਕਾਲਮ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਕਈ ਜਾਂ ਸਾਰੇ null ਮੁੱਲ ਹਨ? ਤੁਸੀਂ ਇਹ ਸੈਟਿੰਗ `dropna` ਵਿੱਚ `how` ਅਤੇ `thresh` ਪੈਰਾਮੀਟਰਾਂ ਨਾਲ ਨਿਰਧਾਰਤ ਕਰ ਸਕਦੇ ਹੋ।\n", "\n", - "ਡਿਫਾਲਟ ਤੌਰ 'ਤੇ, `how='any'` ਹੁੰਦਾ ਹੈ (ਜੇ ਤੁਸੀਂ ਖੁਦ ਜਾਂਚਣਾ ਚਾਹੁੰਦੇ ਹੋ ਜਾਂ ਵੇਖਣਾ ਚਾਹੁੰਦੇ ਹੋ ਕਿ ਇਸ ਮੈਥਡ ਦੇ ਹੋਰ ਪੈਰਾਮੀਟਰ ਕੀ ਹਨ, ਤਾਂ ਇੱਕ ਕੋਡ ਸੈਲ ਵਿੱਚ `example4.dropna?` ਚਲਾਓ)। ਤੁਸੀਂ ਵਿਕਲਪਕ ਤੌਰ 'ਤੇ `how='all'` ਨਿਰਧਾਰਤ ਕਰ ਸਕਦੇ ਹੋ ਤਾਂ ਜੋ ਸਿਰਫ਼ ਉਹ ਪੰਗਤਾਂ ਜਾਂ ਕਾਲਮ ਹਟਾਏ ਜਾਣ ਜੋ ਸਾਰੇ null ਮੁੱਲਾਂ ਨੂੰ ਸ਼ਾਮਲ ਕਰਦੇ ਹਨ। ਆਓ ਅਗਲੇ ਅਭਿਆਸ ਵਿੱਚ ਇਸ ਨੂੰ ਕਾਰਵਾਈ ਵਿੱਚ ਦੇਖਣ ਲਈ ਆਪਣੇ ਉਦਾਹਰਨ `DataFrame` ਨੂੰ ਵਧਾਉਣ।\n" + "ਡਿਫਾਲਟ ਰੂਪ ਵਿੱਚ, `how='any'` ਹੁੰਦਾ ਹੈ (ਜੇ ਤੁਸੀਂ ਖੁਦ ਜਾਂਚਣਾ ਚਾਹੁੰਦੇ ਹੋ ਜਾਂ ਵੇਖਣਾ ਚਾਹੁੰਦੇ ਹੋ ਕਿ ਇਸ ਮੈਥਡ ਵਿੱਚ ਹੋਰ ਕਿਹੜੇ ਪੈਰਾਮੀਟਰ ਹਨ, ਤਾਂ ਕੋਡ ਸੈਲ ਵਿੱਚ `example4.dropna?` ਚਲਾਓ)। ਤੁਸੀਂ ਵਿਕਲਪਕ ਤੌਰ 'ਤੇ `how='all'` ਨਿਰਧਾਰਤ ਕਰ ਸਕਦੇ ਹੋ ਤਾਂ ਜੋ ਸਿਰਫ ਉਹ ਪੰਗਤਾਂ ਜਾਂ ਕਾਲਮ ਹਟਾਏ ਜਾਣ ਜੋ ਸਾਰੇ null ਮੁੱਲ ਰੱਖਦੇ ਹਨ। ਆਓ ਅਗਲੇ ਅਭਿਆਸ ਵਿੱਚ ਇਸ ਨੂੰ ਕਾਰਵਾਈ ਵਿੱਚ ਦੇਖਣ ਲਈ ਆਪਣੇ ਉਦਾਹਰਨ `DataFrame` ਨੂੰ ਵਧਾਉਣ।\n" ] }, { @@ -1453,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "ਮੁੱਖ ਗੱਲਾਂ: \n", - "1. ਨੱਲ ਮੁੱਲਾਂ ਨੂੰ ਹਟਾਉਣਾ ਸਿਰਫ ਉਸ ਸਮੇਂ ਵਧੀਆ ਵਿਚਾਰ ਹੈ ਜੇ ਡਾਟਾਸੈੱਟ ਕਾਫੀ ਵੱਡਾ ਹੈ। \n", - "2. ਪੂਰੀਆਂ ਪੰਗਤਾਂ ਜਾਂ ਕਾਲਮ ਹਟਾਏ ਜਾ ਸਕਦੇ ਹਨ ਜੇ ਉਹਨਾਂ ਵਿੱਚ ਜ਼ਿਆਦਾਤਰ ਡਾਟਾ ਗੁੰਮ ਹੈ। \n", - "3. `DataFrame.dropna(axis=)` ਵਿਧੀ ਨੱਲ ਮੁੱਲਾਂ ਨੂੰ ਹਟਾਉਣ ਵਿੱਚ ਮਦਦ ਕਰਦੀ ਹੈ। `axis` ਦਲੀਲ ਦਰਸਾਉਂਦੀ ਹੈ ਕਿ ਪੰਗਤਾਂ ਹਟਾਈਆਂ ਜਾਣੀਆਂ ਹਨ ਜਾਂ ਕਾਲਮ। \n", - "4. `how` ਦਲੀਲ ਵੀ ਵਰਤੀ ਜਾ ਸਕਦੀ ਹੈ। ਮੂਲ ਰੂਪ ਵਿੱਚ ਇਹ `any` 'ਤੇ ਸੈਟ ਹੁੰਦੀ ਹੈ। ਇਸ ਲਈ, ਇਹ ਸਿਰਫ ਉਹਨਾਂ ਪੰਗਤਾਂ/ਕਾਲਮਾਂ ਨੂੰ ਹਟਾਉਂਦੀ ਹੈ ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਕੋਈ ਵੀ ਨੱਲ ਮੁੱਲ ਹੁੰਦਾ ਹੈ। ਇਸਨੂੰ `all` 'ਤੇ ਸੈਟ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ ਤਾਂ ਜੋ ਸਿਰਫ ਉਹਨਾਂ ਪੰਗਤਾਂ/ਕਾਲਮਾਂ ਨੂੰ ਹਟਾਇਆ ਜਾਵੇ ਜਿੱਥੇ ਸਾਰੇ ਮੁੱਲ ਨੱਲ ਹਨ। \n" + "> ਮੁੱਖ ਗੱਲਾਂ:\n", + "1. ਨੱਲ ਮੁੱਲਾਂ ਨੂੰ ਹਟਾਉਣਾ ਸਿਰਫ ਉਸੇ ਵੇਲੇ ਵਧੀਆ ਹੈ ਜਦੋਂ ਡੇਟਾਸੈੱਟ ਕਾਫੀ ਵੱਡਾ ਹੋਵੇ।\n", + "2. ਪੂਰੀਆਂ ਪੰਗਤਾਂ ਜਾਂ ਕਾਲਮ ਹਟਾਏ ਜਾ ਸਕਦੇ ਹਨ ਜੇ ਉਹਨਾਂ ਵਿੱਚ ਜ਼ਿਆਦਾਤਰ ਡੇਟਾ ਗੁੰਮ ਹੋਵੇ।\n", + "3. `DataFrame.dropna(axis=)` ਵਿਧੀ ਨੱਲ ਮੁੱਲਾਂ ਨੂੰ ਹਟਾਉਣ ਵਿੱਚ ਮਦਦ ਕਰਦੀ ਹੈ। `axis` ਦਲੀਲ ਦਰਸਾਉਂਦੀ ਹੈ ਕਿ ਪੰਗਤਾਂ ਹਟਾਈਆਂ ਜਾਣਗੀਆਂ ਜਾਂ ਕਾਲਮ।\n", + "4. `how` ਦਲੀਲ ਵੀ ਵਰਤੀ ਜਾ ਸਕਦੀ ਹੈ। ਮੂਲ ਰੂਪ ਵਿੱਚ ਇਹ `any` 'ਤੇ ਸੈਟ ਹੁੰਦੀ ਹੈ। ਇਸ ਲਈ, ਇਹ ਸਿਰਫ ਉਹਨਾਂ ਪੰਗਤਾਂ/ਕਾਲਮਾਂ ਨੂੰ ਹਟਾਉਂਦੀ ਹੈ ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਕੋਈ ਵੀ ਨੱਲ ਮੁੱਲ ਹੁੰਦਾ ਹੈ। ਇਸਨੂੰ `all` 'ਤੇ ਸੈਟ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ ਜਿਸ ਨਾਲ ਸਿਰਫ ਉਹਨਾਂ ਪੰਗਤਾਂ/ਕਾਲਮਾਂ ਨੂੰ ਹਟਾਇਆ ਜਾਵੇਗਾ ਜਿੱਥੇ ਸਾਰੇ ਮੁੱਲ ਨੱਲ ਹਨ।\n" ] }, { @@ -1489,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "`thresh` ਪੈਰਾਮੀਟਰ ਤੁਹਾਨੂੰ ਵਧੀਆ-ਦਰਜੇ ਦਾ ਨਿਯੰਤਰਣ ਦਿੰਦਾ ਹੈ: ਤੁਸੀਂ ਉਹ ਗਿਣਤੀ ਸੈਟ ਕਰਦੇ ਹੋ ਜਿੰਨੀ *ਗੈਰ-ਨੱਲ* ਮੁੱਲਾਂ ਦੀ ਲੋੜ ਹੈ ਤਾਂ ਜੋ ਇੱਕ ਕਤਾਰ ਜਾਂ ਕਾਲਮ ਨੂੰ ਰੱਖਿਆ ਜਾ ਸਕੇ:\n" + "`thresh` ਪੈਰਾਮੀਟਰ ਤੁਹਾਨੂੰ ਵਧੀਆ-ਦਰਜੇ ਦਾ ਕੰਟਰੋਲ ਦਿੰਦਾ ਹੈ: ਤੁਸੀਂ ਗੈਰ-ਨਲ ਮੁੱਲਾਂ ਦੀ ਗਿਣਤੀ ਸੈਟ ਕਰਦੇ ਹੋ ਜੋ ਇੱਕ ਪੰਕਤੀ ਜਾਂ ਕਾਲਮ ਨੂੰ ਰੱਖਣ ਲਈ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ:\n" ] }, { @@ -1563,7 +1566,9 @@ "metadata": { "id": "fmSFnzZegRsG" }, - "source": [] + "source": [ + "ਇੱਥੇ, ਪਹਿਲੀ ਅਤੇ ਆਖਰੀ ਪੰਗਤੀ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਗਿਆ ਹੈ, ਕਿਉਂਕਿ ਉਹਨਾਂ ਵਿੱਚ ਸਿਰਫ ਦੋ ਗੈਰ-ਨੱਲ ਮੁੱਲ ਹਨ।\n" + ] }, { "cell_type": "markdown", @@ -1571,11 +1576,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### ਖਾਲੀ ਮੁੱਲਾਂ ਨੂੰ ਭਰਨਾ\n", + "### ਨਲ ਮੁੱਲਾਂ ਨੂੰ ਭਰਨਾ\n", "\n", - "ਕਈ ਵਾਰ ਖਾਲੀ ਮੁੱਲਾਂ ਨੂੰ ਉਹਨਾਂ ਨਾਲ ਭਰਨਾ ਸਮਝਦਾਰੀ ਹੁੰਦੀ ਹੈ ਜੋ ਸਹੀ ਹੋ ਸਕਦੇ ਹਨ। ਖਾਲੀ ਮੁੱਲਾਂ ਨੂੰ ਭਰਨ ਲਈ ਕੁਝ ਤਕਨੀਕਾਂ ਹਨ। ਪਹਿਲੀ ਤਕਨੀਕ ਹੈ ਡੋਮੇਨ ਨੌਲਿਜ (ਉਸ ਵਿਸ਼ੇ ਦੀ ਜਾਣਕਾਰੀ ਜਿਸ 'ਤੇ ਡੇਟਾਸੈੱਟ ਆਧਾਰਿਤ ਹੈ) ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਕਿਸੇ ਤਰ੍ਹਾਂ ਖਾਲੀ ਮੁੱਲਾਂ ਦਾ ਅੰਦਾਜ਼ਾ ਲਗਾਉਣਾ। \n", + "ਕਈ ਵਾਰ ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਉਹਨਾਂ ਨਾਲ ਭਰਨਾ ਸਹੀ ਹੁੰਦਾ ਹੈ ਜੋ ਵੈਧ ਹੋ ਸਕਦੇ ਹਨ। ਨਲ ਮੁੱਲਾਂ ਨੂੰ ਭਰਨ ਦੇ ਕੁਝ ਤਰੀਕੇ ਹਨ। ਪਹਿਲਾ ਤਰੀਕਾ ਹੈ ਡੋਮੇਨ ਨੋਲਿਜ (ਜਿਸ ਵਿਸ਼ੇ 'ਤੇ ਡੇਟਾਸੈਟ ਆਧਾਰਿਤ ਹੈ ਉਸ ਦਾ ਗਿਆਨ) ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਦਾ ਅੰਦਾਜ਼ਾ ਲਗਾਉਣਾ। \n", "\n", - "ਤੁਸੀਂ ਇਸ ਕੰਮ ਨੂੰ ਕਰਨ ਲਈ `isnull` ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੇ ਹੋ, ਪਰ ਇਹ ਥੋੜ੍ਹਾ ਥਕਾਵਟ ਭਰਿਆ ਹੋ ਸਕਦਾ ਹੈ, ਖਾਸ ਕਰਕੇ ਜਦੋਂ ਤੁਹਾਡੇ ਕੋਲ ਭਰਨ ਲਈ ਬਹੁਤ ਸਾਰੇ ਮੁੱਲ ਹੋਣ। ਕਿਉਂਕਿ ਇਹ ਡੇਟਾ ਸਾਇੰਸ ਵਿੱਚ ਇੱਕ ਆਮ ਕੰਮ ਹੈ, pandas `fillna` ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ, ਜੋ `Series` ਜਾਂ `DataFrame` ਦੀ ਇੱਕ ਕਾਪੀ ਵਾਪਸ ਕਰਦਾ ਹੈ ਜਿਸ ਵਿੱਚ ਖਾਲੀ ਮੁੱਲ ਤੁਹਾਡੇ ਚੋਣੇ ਹੋਏ ਮੁੱਲ ਨਾਲ ਬਦਲੇ ਜਾਂਦੇ ਹਨ। ਆਓ ਇੱਕ ਹੋਰ ਉਦਾਹਰਨ ਲਈ `Series` ਬਣਾਈਏ ਤਾਂ ਜੋ ਵੇਖ ਸਕੀਏ ਕਿ ਇਹ ਅਸਲ ਵਿੱਚ ਕਿਵੇਂ ਕੰਮ ਕਰਦਾ ਹੈ।\n" + "ਤੁਸੀਂ ਇਸ ਨੂੰ `isnull` ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਸਿੱਧੇ ਹੀ ਕਰ ਸਕਦੇ ਹੋ, ਪਰ ਇਹ ਥੋੜਾ ਔਖਾ ਹੋ ਸਕਦਾ ਹੈ, ਖਾਸ ਕਰਕੇ ਜੇ ਤੁਹਾਡੇ ਕੋਲ ਭਰਨ ਲਈ ਕਾਫ਼ੀ ਸਾਰੇ ਮੁੱਲ ਹਨ। ਕਿਉਂਕਿ ਇਹ ਡੇਟਾ ਸਾਇੰਸ ਵਿੱਚ ਇੱਕ ਆਮ ਕੰਮ ਹੈ, pandas `fillna` ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ, ਜੋ `Series` ਜਾਂ `DataFrame` ਦੀ ਇੱਕ ਕਾਪੀ ਵਾਪਸ ਕਰਦਾ ਹੈ ਜਿਸ ਵਿੱਚ ਗੁੰਮ ਹੋਏ ਮੁੱਲ ਤੁਹਾਡੇ ਚੋਣੇ ਹੋਏ ਮੁੱਲਾਂ ਨਾਲ ਬਦਲੇ ਜਾਂਦੇ ਹਨ। ਆਓ ਇੱਕ ਹੋਰ ਉਦਾਹਰਨ `Series` ਬਣਾਈਏ ਤਾਂ ਜੋ ਦੇਖ ਸਕੀਏ ਕਿ ਇਹ ਅਮਲ ਵਿੱਚ ਕਿਵੇਂ ਕੰਮ ਕਰਦਾ ਹੈ।\n" ] }, { @@ -1584,13 +1589,12 @@ "id": "CE8S7louLezV" }, "source": [ - "### ਸ਼੍ਰੇਣੀਬੱਧ ਡਾਟਾ (ਗਿਣਤੀਯੋਗ ਨਹੀਂ)\n", + "### ਸ਼੍ਰੇਣੀਬੱਧ ਡਾਟਾ (ਗੈਰ-ਸੰਖਿਆਤਮਕ)\n", + "ਸਭ ਤੋਂ ਪਹਿਲਾਂ ਆਓ ਗੈਰ-ਸੰਖਿਆਤਮਕ ਡਾਟਾ ਦੇਖੀਏ। ਡਾਟਾਸੈਟ ਵਿੱਚ ਸਾਡੇ ਕੋਲ ਸ਼੍ਰੇਣੀਬੱਧ ਡਾਟਾ ਵਾਲੇ ਕਾਲਮ ਹੁੰਦੇ ਹਨ। ਉਦਾਹਰਣ ਲਈ, ਲਿੰਗ, ਸੱਚ ਜਾਂ ਝੂਠ ਆਦਿ।\n", "\n", - "ਸਭ ਤੋਂ ਪਹਿਲਾਂ ਆਓ ਗਿਣਤੀਯੋਗ ਨਹੀਂ ਡਾਟਾ ਬਾਰੇ ਸੋਚੀਏ। ਡਾਟਾਸੈਟ ਵਿੱਚ ਸਾਡੇ ਕੋਲ ਸ਼੍ਰੇਣੀਬੱਧ ਡਾਟਾ ਵਾਲੇ ਕਾਲਮ ਹੁੰਦੇ ਹਨ। ਉਦਾਹਰਣ ਲਈ, ਲਿੰਗ, ਸੱਚ ਜਾਂ ਝੂਠ ਆਦਿ।\n", + "ਇਨ੍ਹਾਂ ਵਿੱਚੋਂ ਜ਼ਿਆਦਾਤਰ ਮਾਮਲਿਆਂ ਵਿੱਚ, ਅਸੀਂ ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਕਾਲਮ ਦੇ `mode` ਨਾਲ ਬਦਲ ਦਿੰਦੇ ਹਾਂ। ਮੰਨੋ, ਸਾਡੇ ਕੋਲ 100 ਡਾਟਾ ਪੌਇੰਟ ਹਨ ਅਤੇ 90 ਨੇ ਸੱਚ ਕਿਹਾ ਹੈ, 8 ਨੇ ਝੂਠ ਕਿਹਾ ਹੈ ਅਤੇ 2 ਨੇ ਨਹੀਂ ਭਰਿਆ। ਫਿਰ, ਅਸੀਂ ਉਹ 2 ਨੂੰ ਸੱਚ ਨਾਲ ਭਰ ਸਕਦੇ ਹਾਂ, ਪੂਰੇ ਕਾਲਮ ਨੂੰ ਧਿਆਨ ਵਿੱਚ ਰੱਖਦੇ ਹੋਏ।\n", "\n", - "ਇਨ੍ਹਾਂ ਵਿੱਚੋਂ ਜ਼ਿਆਦਾਤਰ ਮਾਮਲਿਆਂ ਵਿੱਚ, ਅਸੀਂ ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਕਾਲਮ ਦੇ `ਮੋਡ` ਨਾਲ ਬਦਲ ਦਿੰਦੇ ਹਾਂ। ਮੰਨੋ, ਸਾਡੇ ਕੋਲ 100 ਡਾਟਾ ਪੌਇੰਟ ਹਨ, ਜਿਨ੍ਹਾਂ ਵਿੱਚੋਂ 90 ਨੇ ਸੱਚ ਕਿਹਾ ਹੈ, 8 ਨੇ ਝੂਠ ਕਿਹਾ ਹੈ ਅਤੇ 2 ਨੇ ਕੁਝ ਨਹੀਂ ਭਰਿਆ। ਫਿਰ, ਅਸੀਂ ਉਹ 2 ਸੱਚ ਨਾਲ ਭਰ ਸਕਦੇ ਹਾਂ, ਪੂਰੇ ਕਾਲਮ ਨੂੰ ਧਿਆਨ ਵਿੱਚ ਰੱਖਦੇ ਹੋਏ।\n", - "\n", - "ਇੱਥੇ ਵੀ ਅਸੀਂ ਖੇਤਰ ਵਿਸ਼ੇਸ਼ ਗਿਆਨ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੇ ਹਾਂ। ਆਓ ਮੋਡ ਨਾਲ ਭਰਨ ਦੇ ਇੱਕ ਉਦਾਹਰਣ ਨੂੰ ਸਮਝੀਏ।\n" + "ਇੱਥੇ ਵੀ ਅਸੀਂ ਡੋਮੇਨ ਗਿਆਨ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੇ ਹਾਂ। ਆਓ `mode` ਨਾਲ ਭਰਨ ਦਾ ਇੱਕ ਉਦਾਹਰਣ ਵੇਖੀਏ।\n" ] }, { @@ -1695,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "ਹੁਣ, ਪਹਿਲਾਂ ਮੋਡ ਲੱਭਦੇ ਹਾਂ ਜਦੋਂ ਕਿ `None` ਮੁੱਲ ਨੂੰ ਮੋਡ ਨਾਲ ਭਰਨਾ ਹੈ।\n" + ] }, { "cell_type": "code", @@ -1730,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "ਤਾਂਕਿ ਅਸੀਂ None ਨੂੰ True ਨਾਲ ਬਦਲਾਂਗੇ।\n" + ] }, { "cell_type": "code", @@ -1840,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "ਜਿਵੇਂ ਅਸੀਂ ਦੇਖ ਸਕਦੇ ਹਾਂ, ਨੱਲ ਮੁੱਲ ਦੀ ਥਾਂ ਲੈ ਲਈ ਗਈ ਹੈ। ਕਹਿਣ ਦੀ ਲੋੜ ਨਹੀਂ, ਅਸੀਂ `'True'` ਦੀ ਥਾਂ ਕੁਝ ਵੀ ਲਿਖ ਸਕਦੇ ਸੀ ਅਤੇ ਇਹ ਸਥਾਨਾਪਨ ਹੋ ਜਾਂਦਾ।\n" + "ਜਿਵੇਂ ਕਿ ਅਸੀਂ ਦੇਖ ਸਕਦੇ ਹਾਂ, ਨੱਲ ਮੁੱਲ ਦੀ ਜਗ੍ਹਾ ਲੈ ਲਈ ਗਈ ਹੈ। ਬੇਸ਼ੱਕ, ਅਸੀਂ `'True'` ਦੀ ਜਗ੍ਹਾ ਕੁਝ ਵੀ ਲਿਖ ਸਕਦੇ ਸੀ ਅਤੇ ਇਹ ਸਥਾਨਾਪਨ ਹੋ ਜਾਂਦਾ।\n" ] }, { @@ -1849,17 +1857,17 @@ "id": "heYe1I0dOmQ_" }, "source": [ - "### ਸੰਖਿਆਤਮਕ ਡਾਟਾ\n", - "ਹੁਣ, ਸੰਖਿਆਤਮਕ ਡਾਟਾ ਵੱਲ ਆਓ। ਇੱਥੇ, ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਭਰਨ ਦੇ ਦੋ ਆਮ ਤਰੀਕੇ ਹਨ:\n", + "### ਗਿਣਤੀ ਡਾਟਾ \n", + "ਹੁਣ, ਗਿਣਤੀ ਡਾਟਾ ਵੱਲ ਆਉਂਦੇ ਹਾਂ। ਇੱਥੇ, ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਭਰਣ ਦੇ ਦੋ ਆਮ ਤਰੀਕੇ ਹਨ: \n", "\n", - "1. ਕਤਾਰ ਦੇ ਮੱਧ (Median) ਨਾਲ ਭਰੋ \n", - "2. ਕਤਾਰ ਦੇ ਔਸਤ (Mean) ਨਾਲ ਭਰੋ \n", + "1. ਕਤਾਰ ਦੇ ਮੀਡੀਅਨ ਨਾਲ ਭਰੋ \n", + "2. ਕਤਾਰ ਦੇ ਮੀਨ ਨਾਲ ਭਰੋ \n", "\n", - "ਜੇ ਡਾਟਾ ਵਿੱਚ ਬਾਹਰਲੇ ਮੁੱਲ (outliers) ਨਾਲ ਝੁਕਾਅ ਹੋਵੇ, ਤਾਂ ਅਸੀਂ ਮੱਧ (Median) ਨਾਲ ਭਰਦੇ ਹਾਂ। ਇਹ ਇਸ ਲਈ ਕਿਉਂਕਿ ਮੱਧ ਬਾਹਰਲੇ ਮੁੱਲਾਂ ਲਈ ਸੰਵੇਦਨਸ਼ੀਲ ਨਹੀਂ ਹੁੰਦਾ।\n", + "ਅਸੀਂ ਮੀਡੀਅਨ ਨਾਲ ਭਰਦੇ ਹਾਂ, ਜੇ ਡਾਟਾ ਵਿੱਚ ਆਉਟਲਾਇਰਸ ਨਾਲ ਤਿਰਛਾ ਹੋਵੇ। ਇਹ ਇਸ ਲਈ ਕਿ ਮੀਡੀਅਨ ਆਉਟਲਾਇਰਸ ਲਈ ਮਜ਼ਬੂਤ ਹੁੰਦੀ ਹੈ। \n", "\n", - "ਜਦੋਂ ਡਾਟਾ ਸਧਾਰਨਕ੍ਰਿਤ (normalized) ਹੁੰਦਾ ਹੈ, ਅਸੀਂ ਔਸਤ (Mean) ਵਰਤ ਸਕਦੇ ਹਾਂ, ਕਿਉਂਕਿ ਉਸ ਸਥਿਤੀ ਵਿੱਚ ਔਸਤ ਅਤੇ ਮੱਧ ਕਾਫ਼ੀ ਨੇੜੇ ਹੁੰਦੇ ਹਨ।\n", + "ਜਦੋਂ ਡਾਟਾ ਨਾਰਮਲਾਈਜ਼ ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਅਸੀਂ ਮੀਨ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੇ ਹਾਂ, ਕਿਉਂਕਿ ਉਸ ਸਥਿਤੀ ਵਿੱਚ ਮੀਨ ਅਤੇ ਮੀਡੀਅਨ ਕਾਫ਼ੀ ਨੇੜੇ ਹੁੰਦੇ ਹਨ। \n", "\n", - "ਸਭ ਤੋਂ ਪਹਿਲਾਂ, ਆਓ ਇੱਕ ਕਾਲਮ ਲਵਾਂ ਜੋ ਆਮ ਤੌਰ 'ਤੇ ਵੰਡਿਆ ਹੋਇਆ ਹੈ ਅਤੇ ਉਸ ਵਿੱਚ ਗੁੰਮ ਹੋਏ ਮੁੱਲ ਨੂੰ ਕਾਲਮ ਦੇ ਔਸਤ ਨਾਲ ਭਰਦੇ ਹਾਂ।\n" + "ਸਭ ਤੋਂ ਪਹਿਲਾਂ, ਆਓ ਇੱਕ ਕਾਲਮ ਲਵਾਂ ਜੋ ਨਾਰਮਲ ਡਿਸਟ੍ਰਿਬਿਊਟ ਕੀਤਾ ਹੋਇਆ ਹੈ ਅਤੇ ਉਸ ਵਿੱਚ ਗੁੰਮ ਹੋਏ ਮੁੱਲ ਨੂੰ ਕਾਲਮ ਦੇ ਮੀਨ ਨਾਲ ਭਰਦੇ ਹਾਂ। \n" ] }, { @@ -1999,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "ਮਤਲਬ ਨਾਲ ਭਰਨਾ\n" + ] }, { "cell_type": "code", @@ -2099,7 +2109,7 @@ "id": "CwpVFCrPTC5z" }, "source": [ - "ਜਿਵੇਂ ਅਸੀਂ ਦੇਖ ਸਕਦੇ ਹਾਂ, ਗੁੰਮ ਹੋਈ ਮੁੱਲ ਨੂੰ ਇਸਦੇ ਔਸਤ ਨਾਲ ਬਦਲ ਦਿੱਤਾ ਗਿਆ ਹੈ।\n" + "ਜਿਵੇਂ ਕਿ ਅਸੀਂ ਦੇਖ ਸਕਦੇ ਹਾਂ, ਗੁੰਮ ਹੋਈ ਮੁੱਲ ਨੂੰ ਇਸਦੇ ਔਸਤ ਨਾਲ ਬਦਲ ਦਿੱਤਾ ਗਿਆ ਹੈ।\n" ] }, { @@ -2108,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "ਹੁਣ ਆਓ ਅਸੀਂ ਇੱਕ ਹੋਰ ਡਾਟਾਫ੍ਰੇਮ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੀਏ, ਅਤੇ ਇਸ ਵਾਰ ਅਸੀਂ None ਮੁੱਲਾਂ ਨੂੰ ਕਾਲਮ ਦੇ ਮੀਡੀਅਨ ਨਾਲ ਬਦਲਾਂਗੇ।\n" + "ਹੁਣ ਆਓ ਅਸੀਂ ਇੱਕ ਹੋਰ ਡਾਟਾਫਰੇਮ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੀਏ, ਅਤੇ ਇਸ ਵਾਰ ਅਸੀਂ None ਮੁੱਲਾਂ ਨੂੰ ਕਾਲਮ ਦੇ ਮੀਡੀਅਨ ਨਾਲ ਬਦਲਾਂਗੇ।\n" ] }, { @@ -2214,7 +2224,7 @@ "id": "mM1GpXYmjHnc" }, "source": [ - "ਦੂਜੇ ਕਤਾਰ ਦਾ ਮੱਧ ਹੈ\n" + "ਦੂਜੇ ਕਤਾਰ ਦਾ ਮੱਧਿਕ ਕੀ ਹੈ\n" ] }, { @@ -2248,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "ਮੱਧ ਨਾਲ ਭਰਨ\n" + ] }, { "cell_type": "code", @@ -2348,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "ਜਿਵੇਂ ਅਸੀਂ ਦੇਖ ਸਕਦੇ ਹਾਂ, NaN ਮੁੱਲ ਨੂੰ ਕਾਲਮ ਦੇ ਮੀਡੀਆਨ ਨਾਲ ਬਦਲ ਦਿੱਤਾ ਗਿਆ ਹੈ\n" + "ਜਿਵੇਂ ਕਿ ਅਸੀਂ ਦੇਖ ਸਕਦੇ ਹਾਂ, NaN ਮੁੱਲ ਨੂੰ ਕਾਲਮ ਦੇ ਮੀਡੀਆਨ ਨਾਲ ਬਦਲ ਦਿੱਤਾ ਗਿਆ ਹੈ।\n" ] }, { @@ -2390,7 +2402,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "ਤੁਸੀਂ ਸਾਰੇ ਖਾਲੀ ਐਂਟਰੀਜ਼ ਨੂੰ ਇੱਕ ਹੀ ਮੁੱਲ ਨਾਲ ਭਰ ਸਕਦੇ ਹੋ, ਜਿਵੇਂ ਕਿ `0`:\n" + "ਤੁਸੀਂ ਸਾਰੇ ਖਾਲੀ ਐਂਟਰੀਆਂ ਨੂੰ ਇੱਕ ਹੀ ਮੁੱਲ ਨਾਲ ਭਰ ਸਕਦੇ ਹੋ, ਜਿਵੇਂ ਕਿ `0`:\n" ] }, { @@ -2432,10 +2444,10 @@ }, "source": [ "> ਮੁੱਖ ਗੱਲਾਂ:\n", - "1. ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਭਰਨਾ ਉਸ ਸਮੇਂ ਕੀਤਾ ਜਾਣਾ ਚਾਹੀਦਾ ਹੈ ਜਦੋਂ ਡਾਟਾ ਘੱਟ ਹੋਵੇ ਜਾਂ ਗੁੰਮ ਹੋਏ ਡਾਟਾ ਨੂੰ ਭਰਨ ਲਈ ਕੋਈ ਰਣਨੀਤੀ ਹੋਵੇ। \n", - "2. ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਅਨੁਮਾਨ ਲਗਾ ਕੇ ਭਰਨ ਲਈ ਡੋਮੇਨ ਗਿਆਨ ਦੀ ਵਰਤੋਂ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ। \n", - "3. ਸ਼੍ਰੇਣੀਬੱਧ ਡਾਟਾ ਲਈ, ਜ਼ਿਆਦਾਤਰ ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਕਾਲਮ ਦੇ ਮੋਡ ਨਾਲ ਬਦਲਿਆ ਜਾਂਦਾ ਹੈ। \n", - "4. ਸੰਖਿਆਤਮਕ ਡਾਟਾ ਲਈ, ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਆਮ ਤੌਰ 'ਤੇ ਕਾਲਮ ਦੇ ਔਸਤ (ਨਾਰਮਲਾਈਜ਼ਡ ਡਾਟਾਸੈਟ ਲਈ) ਜਾਂ ਮੱਧਕ ਨਾਲ ਭਰਿਆ ਜਾਂਦਾ ਹੈ। \n" + "1. ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਭਰਨਾ ਉਸ ਸਮੇਂ ਕੀਤਾ ਜਾਣਾ ਚਾਹੀਦਾ ਹੈ ਜਦੋਂ ਡਾਟਾ ਘੱਟ ਹੋਵੇ ਜਾਂ ਗੁੰਮ ਹੋਏ ਡਾਟਾ ਨੂੰ ਭਰਨ ਲਈ ਕੋਈ ਰਣਨੀਤੀ ਹੋਵੇ।\n", + "2. ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਅਨੁਮਾਨ ਲਗਾ ਕੇ ਭਰਨ ਲਈ ਡੋਮੇਨ ਗਿਆਨ ਦੀ ਵਰਤੋਂ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ।\n", + "3. ਸ਼੍ਰੇਣੀਬੱਧ ਡਾਟਾ ਲਈ, ਜ਼ਿਆਦਾਤਰ ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਕਾਲਮ ਦੇ ਮੋਡ ਨਾਲ ਬਦਲਿਆ ਜਾਂਦਾ ਹੈ।\n", + "4. ਸੰਖਿਆਤਮਕ ਡਾਟਾ ਲਈ, ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਆਮ ਤੌਰ 'ਤੇ ਕਾਲਮ ਦੇ ਮੀਨ (ਸਧਾਰਨ ਡਾਟਾਸੈਟ ਲਈ) ਜਾਂ ਮੀਡਿਅਨ ਨਾਲ ਭਰਿਆ ਜਾਂਦਾ ਹੈ।\n" ] }, { @@ -2444,7 +2456,7 @@ "id": "FI9MmqFJgRsH" }, "source": [ - "ਵਿਆਯਾਮ:\n" + "### ਕਸਰਤ:\n" ] }, { @@ -2465,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "ਤੁਸੀਂ **ਫਾਰਵਰਡ-ਫਿਲ** ਨਲ ਮੁੱਲਾਂ ਨੂੰ ਭਰ ਸਕਦੇ ਹੋ, ਜਿਸਦਾ ਅਰਥ ਹੈ ਪਿਛਲੇ ਵੈਧ ਮੁੱਲ ਨੂੰ ਨਲ ਨੂੰ ਭਰਨ ਲਈ ਵਰਤਣਾ:\n" + ] }, { "cell_type": "code", @@ -2505,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "ਤੁਸੀਂ ਅਗਲੇ ਵੈਧ ਮੁੱਲ ਨੂੰ ਪਿੱਛੇ ਵੱਲ ਪ੍ਰਸਾਰਿਤ ਕਰਨ ਲਈ **ਬੈਕ-ਫਿਲ** ਵੀ ਕਰ ਸਕਦੇ ਹੋ ਤਾਂ ਜੋ ਇੱਕ ਨੱਲ ਨੂੰ ਭਰਿਆ ਜਾ ਸਕੇ:\n" + "ਤੁਸੀਂ ਅਗਲੇ ਵੈਧ ਮੁੱਲ ਨੂੰ ਪਿੱਛੇ ਵੱਲ ਫੈਲਾਉਣ ਲਈ **ਬੈਕ-ਫਿਲ** ਵੀ ਕਰ ਸਕਦੇ ਹੋ ਤਾਂ ਜੋ ਨੱਲ ਨੂੰ ਭਰਿਆ ਜਾ ਸਕੇ:\n" ] }, { @@ -2547,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "ਜਿਵੇਂ ਤੁਸੀਂ ਅਨੁਮਾਨ ਲਗਾ ਸਕਦੇ ਹੋ, ਇਹ DataFrames ਨਾਲ ਵੀ ਇੱਕੋ ਤਰ੍ਹਾਂ ਕੰਮ ਕਰਦਾ ਹੈ, ਪਰ ਤੁਸੀਂ ਉਸ `axis` ਨੂੰ ਵੀ ਨਿਰਧਾਰਤ ਕਰ ਸਕਦੇ ਹੋ ਜਿਸ ਨਾਲ ਖਾਲੀ ਮੁੱਲ ਭਰੇ ਜਾਣੇ ਹਨ:\n" + "ਜਿਵੇਂ ਤੁਸੀਂ ਅਨੁਮਾਨ ਲਗਾ ਸਕਦੇ ਹੋ, ਇਹ DataFrames ਨਾਲ ਵੀ ਇਸੇ ਤਰੀਕੇ ਨਾਲ ਕੰਮ ਕਰਦਾ ਹੈ, ਪਰ ਤੁਸੀਂ null ਮੁੱਲਾਂ ਨੂੰ ਭਰਣ ਲਈ ਇੱਕ `axis` ਵੀ ਨਿਰਧਾਰਤ ਕਰ ਸਕਦੇ ਹੋ:\n" ] }, { @@ -2719,7 +2733,9 @@ "metadata": { "id": "ZeMc-I1EgRsI" }, - "source": [] + "source": [ + "ਧਿਆਨ ਦਿਓ ਕਿ ਜਦੋਂ ਅੱਗੇ ਭਰਨ ਲਈ ਪਿਛਲਾ ਮੁੱਲ ਉਪਲਬਧ ਨਹੀਂ ਹੁੰਦਾ, ਤਾਂ ਨਲ ਮੁੱਲ ਜਿਵੇਂ ਦਾ ਤਿਵੇਂ ਰਹਿੰਦਾ ਹੈ।\n" + ] }, { "cell_type": "markdown", @@ -2727,7 +2743,7 @@ "id": "eeAoOU0RgRsJ" }, "source": [ - "ਵਿਆਯਾਮ:\n" + "### ਕਸਰਤ:\n" ] }, { @@ -2751,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "ਤੁਸੀਂ `fillna` ਨੂੰ ਵਰਤਣ ਦੇ ਤਰੀਕੇ ਬਾਰੇ ਰਚਨਾਤਮਕ ਹੋ ਸਕਦੇ ਹੋ। ਉਦਾਹਰਣ ਵਜੋਂ, ਆਓ `example4` ਨੂੰ ਫਿਰ ਤੋਂ ਵੇਖੀਏ, ਪਰ ਇਸ ਵਾਰ ਚਲੋ ਗੁੰਮ ਹੋਈਆਂ ਕੀਮਤਾਂ ਨੂੰ `DataFrame` ਵਿੱਚ ਸਾਰੀਆਂ ਕੀਮਤਾਂ ਦੇ ਔਸਤ ਨਾਲ ਭਰਦੇ ਹਾਂ:\n" + "ਤੁਸੀਂ `fillna` ਦੇ ਉਪਯੋਗ ਬਾਰੇ ਰਚਨਾਤਮਕ ਹੋ ਸਕਦੇ ਹੋ। ਉਦਾਹਰਣ ਲਈ, ਆਓ `example4` ਨੂੰ ਫਿਰ ਤੋਂ ਵੇਖੀਏ, ਪਰ ਇਸ ਵਾਰ ਚਲੋ ਗੁੰਮ ਹੋਈਆਂ ਮੁੱਲਾਂ ਨੂੰ `DataFrame` ਵਿੱਚ ਸਾਰੀਆਂ ਮੁੱਲਾਂ ਦੇ ਔਸਤ ਨਾਲ ਭਰਦੇ ਹਾਂ:\n" ] }, { @@ -2842,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "ਧਿਆਨ ਦਿਓ ਕਿ ਕਾਲਮ 3 ਅਜੇ ਵੀ ਖਾਲੀ ਹੈ: ਡਿਫਾਲਟ ਦਿਸ਼ਾ ਮੁਤਾਬਕ ਮੁੱਲਾਂ ਨੂੰ ਕਤਾਰਾਂ ਅਨੁਸਾਰ ਭਰਿਆ ਜਾਂਦਾ ਹੈ।\n", + "ਧਿਆਨ ਦਿਓ ਕਿ ਕਾਲਮ 3 ਅਜੇ ਵੀ ਖਾਲੀ ਹੈ: ਡਿਫਾਲਟ ਦਿਸ਼ਾ ਪੰਗਤਾਂ ਦੇ ਅਨੁਸਾਰ ਮੁੱਲ ਭਰਨ ਦੀ ਹੈ।\n", "\n", - "> **ਮੁੱਖ ਗੱਲ:** ਆਪਣੇ ਡਾਟਾਸੈਟ ਵਿੱਚ ਗੁੰਮ ਮੁੱਲਾਂ ਨਾਲ ਨਿਪਟਣ ਦੇ ਕਈ ਤਰੀਕੇ ਹਨ। ਤੁਸੀਂ ਜੋ ਖਾਸ ਰਣਨੀਤੀ ਵਰਤਦੇ ਹੋ (ਉਨ੍ਹਾਂ ਨੂੰ ਹਟਾਉਣਾ, ਬਦਲਣਾ, ਜਾਂ ਇੱਥੇ ਤੱਕ ਕਿ ਕਿਵੇਂ ਬਦਲਣਾ) ਉਹ ਡਾਟਾ ਦੀ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦੁਆਰਾ ਨਿਰਧਾਰਤ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ। ਜਿਵੇਂ ਜਿਵੇਂ ਤੁਸੀਂ ਡਾਟਾਸੈਟਸ ਨਾਲ ਵਧੇਰੇ ਕੰਮ ਕਰਦੇ ਹੋ ਅਤੇ ਉਨ੍ਹਾਂ ਨਾਲ ਸੰਚਾਰ ਕਰਦੇ ਹੋ, ਤੁਸੀਂ ਗੁੰਮ ਮੁੱਲਾਂ ਨਾਲ ਨਿਪਟਣ ਦਾ ਬਿਹਤਰ ਅਨੁਭਵ ਵਿਕਸਿਤ ਕਰੋਗੇ।\n" + "> **ਸਿੱਖਣ ਵਾਲੀ ਗੱਲ:** ਆਪਣੇ ਡਾਟਾਸੈਟ ਵਿੱਚ ਗੁੰਮ ਮੁੱਲਾਂ ਨਾਲ ਨਜਿੱਠਣ ਦੇ ਕਈ ਤਰੀਕੇ ਹਨ। ਤੁਸੀਂ ਜੋ ਖਾਸ ਰਣਨੀਤੀ ਵਰਤਦੇ ਹੋ (ਉਨ੍ਹਾਂ ਨੂੰ ਹਟਾਉਣਾ, ਬਦਲਣਾ, ਜਾਂ ਕਿਵੇਂ ਬਦਲਣਾ) ਉਹ ਡਾਟਾ ਦੀ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦੁਆਰਾ ਨਿਰਧਾਰਤ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ। ਜਿਵੇਂ ਜਿਵੇਂ ਤੁਸੀਂ ਡਾਟਾਸੈਟਸ ਨਾਲ ਵਧੇਰੇ ਕੰਮ ਕਰਦੇ ਹੋ ਅਤੇ ਉਨ੍ਹਾਂ ਨਾਲ ਸੰਚਾਰ ਕਰਦੇ ਹੋ, ਤੁਸੀਂ ਗੁੰਮ ਮੁੱਲਾਂ ਨਾਲ ਨਜਿੱਠਣ ਦਾ ਬਿਹਤਰ ਅਹਿਸਾਸ ਵਿਕਸਿਤ ਕਰੋਗੇ।\n" ] }, { @@ -2855,7 +2871,7 @@ "source": [ "### ਸ਼੍ਰੇਣੀਬੱਧ ਡਾਟਾ ਨੂੰ ਕੋਡ ਕਰਨਾ\n", "\n", - "ਮਸ਼ੀਨ ਲਰਨਿੰਗ ਮਾਡਲ ਸਿਰਫ਼ ਨੰਬਰਾਂ ਅਤੇ ਕਿਸੇ ਵੀ ਤਰ੍ਹਾਂ ਦੇ ਸੰਖਿਆਤਮਕ ਡਾਟਾ ਨਾਲ ਕੰਮ ਕਰਦੇ ਹਨ। ਇਹ \"ਹਾਂ\" ਅਤੇ \"ਨਹੀਂ\" ਵਿੱਚ ਫਰਕ ਨਹੀਂ ਕਰ ਸਕਦੇ, ਪਰ ਇਹ 0 ਅਤੇ 1 ਵਿੱਚ ਅੰਤਰ ਕਰ ਸਕਦੇ ਹਨ। ਇਸ ਲਈ, ਗੁੰਮ ਡਾਟਾ ਨੂੰ ਭਰਨ ਤੋਂ ਬਾਅਦ, ਸਾਨੂੰ ਮਾਡਲ ਨੂੰ ਸਮਝਣ ਲਈ ਸ਼੍ਰੇਣੀਬੱਧ ਡਾਟਾ ਨੂੰ ਕੁਝ ਸੰਖਿਆਤਮਕ ਰੂਪ ਵਿੱਚ ਕੋਡ ਕਰਨਾ ਪਵੇਗਾ।\n", + "ਮਸ਼ੀਨ ਲਰਨਿੰਗ ਮਾਡਲ ਸਿਰਫ਼ ਗਿਣਤੀ ਅਤੇ ਕਿਸੇ ਵੀ ਤਰ੍ਹਾਂ ਦੇ ਗਿਣਤੀ ਡਾਟਾ ਨਾਲ ਕੰਮ ਕਰਦੇ ਹਨ। ਇਹ \"ਹਾਂ\" ਅਤੇ \"ਨਹੀਂ\" ਵਿੱਚ ਫਰਕ ਨਹੀਂ ਕਰ ਸਕਦੇ, ਪਰ ਇਹ 0 ਅਤੇ 1 ਵਿੱਚ ਅੰਤਰ ਕਰ ਸਕਦੇ ਹਨ। ਇਸ ਲਈ, ਗੁੰਮ ਹੋਏ ਮੁੱਲਾਂ ਨੂੰ ਭਰਨ ਤੋਂ ਬਾਅਦ, ਸਾਨੂੰ ਮਾਡਲ ਨੂੰ ਸਮਝਣ ਲਈ ਸ਼੍ਰੇਣੀਬੱਧ ਡਾਟਾ ਨੂੰ ਕੁਝ ਗਿਣਤੀ ਰੂਪ ਵਿੱਚ ਕੋਡ ਕਰਨਾ ਪਵੇਗਾ।\n", "\n", "ਕੋਡਿੰਗ ਦੋ ਤਰੀਕਿਆਂ ਨਾਲ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ। ਅਸੀਂ ਅਗਲੇ ਹਿੱਸੇ ਵਿੱਚ ਇਹਨਾਂ ਬਾਰੇ ਚਰਚਾ ਕਰਾਂਗੇ।\n" ] @@ -2868,7 +2884,7 @@ "source": [ "**ਲੇਬਲ ਐਨਕੋਡਿੰਗ**\n", "\n", - "ਲੇਬਲ ਐਨਕੋਡਿੰਗ ਮੂਲ ਰੂਪ ਵਿੱਚ ਹਰ ਸ਼੍ਰੇਣੀ ਨੂੰ ਇੱਕ ਨੰਬਰ ਵਿੱਚ ਬਦਲਣ ਦੀ ਪ੍ਰਕਿਰਿਆ ਹੈ। ਉਦਾਹਰਣ ਲਈ, ਮੰਨੋ ਸਾਡੇ ਕੋਲ ਏਅਰਲਾਈਨ ਯਾਤਰੀਆਂ ਦਾ ਡਾਟਾਸੈਟ ਹੈ ਅਤੇ ਉਸ ਵਿੱਚ ਇੱਕ ਕਾਲਮ ਹੈ ਜੋ ਉਨ੍ਹਾਂ ਦੀ ਕਲਾਸ ਦੱਸਦਾ ਹੈ ['ਬਿਜ਼ਨਸ ਕਲਾਸ', 'ਇਕਨਾਮੀ ਕਲਾਸ', 'ਫਰਸਟ ਕਲਾਸ'] ਵਿੱਚੋਂ। ਜੇ ਇਸ 'ਤੇ ਲੇਬਲ ਐਨਕੋਡਿੰਗ ਕੀਤੀ ਜਾਵੇ, ਤਾਂ ਇਹ [0,1,2] ਵਿੱਚ ਬਦਲ ਜਾਵੇਗਾ। ਆਓ ਇਸ ਨੂੰ ਕੋਡ ਰਾਹੀਂ ਇੱਕ ਉਦਾਹਰਣ ਦੇ ਨਾਲ ਸਮਝੀਏ। ਕਿਉਂਕਿ ਅਸੀਂ ਅਗਲੇ ਨੋਟਬੁੱਕਸ ਵਿੱਚ `scikit-learn` ਸਿੱਖਣ ਵਾਲੇ ਹਾਂ, ਇਸ ਲਈ ਅਸੀਂ ਇਸਨੂੰ ਇੱਥੇ ਵਰਤਾਂਗੇ ਨਹੀਂ।\n" + "ਲੇਬਲ ਐਨਕੋਡਿੰਗ ਮੂਲ ਤੌਰ 'ਤੇ ਹਰ ਸ਼੍ਰੇਣੀ ਨੂੰ ਇੱਕ ਨੰਬਰ ਵਿੱਚ ਬਦਲਣ ਦੀ ਪ੍ਰਕਿਰਿਆ ਹੈ। ਉਦਾਹਰਨ ਵਜੋਂ, ਮੰਨ ਲਓ ਕਿ ਸਾਡੇ ਕੋਲ ਏਅਰਲਾਈਨ ਯਾਤਰੀਆਂ ਦਾ ਡਾਟਾਸੈਟ ਹੈ ਅਤੇ ਇਸ ਵਿੱਚ ਇੱਕ ਕਾਲਮ ਹੈ ਜੋ ਉਨ੍ਹਾਂ ਦੀ ਕਲਾਸ ਨੂੰ ਦਰਸਾਉਂਦਾ ਹੈ ['ਬਿਜ਼ਨਸ ਕਲਾਸ', 'ਇਕਨਾਮੀ ਕਲਾਸ', 'ਫਰਸਟ ਕਲਾਸ'] ਵਿੱਚੋਂ। ਜੇ ਇਸ 'ਤੇ ਲੇਬਲ ਐਨਕੋਡਿੰਗ ਕੀਤੀ ਜਾਂਦੀ ਹੈ, ਤਾਂ ਇਹ [0,1,2] ਵਿੱਚ ਬਦਲ ਜਾਵੇਗੀ। ਆਓ ਇਸ ਨੂੰ ਕੋਡ ਦੇ ਜਰੀਏ ਇੱਕ ਉਦਾਹਰਨ ਦੇ ਨਾਲ ਵੇਖੀਏ। ਕਿਉਂਕਿ ਅਸੀਂ ਅਗਲੇ ਨੋਟਬੁੱਕਸ ਵਿੱਚ `scikit-learn` ਸਿੱਖਣ ਜਾ ਰਹੇ ਹਾਂ, ਇਸ ਲਈ ਅਸੀਂ ਇਸਨੂੰ ਇੱਥੇ ਵਰਤਾਂਗੇ ਨਹੀਂ।\n" ] }, { @@ -2976,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "ਪਹਿਲੇ ਕਤਾਰ 'ਤੇ ਲੇਬਲ ਐਨਕੋਡਿੰਗ ਕਰਨ ਲਈ, ਸਾਨੂੰ ਪਹਿਲਾਂ ਹਰ ਵਰਗ ਤੋਂ ਇੱਕ ਨੰਬਰ ਤੱਕ ਦਾ ਨਕਸ਼ਾ ਬਣਾਉਣਾ ਪਵੇਗਾ, ਇਸ ਤੋਂ ਪਹਿਲਾਂ ਕਿ ਬਦਲਣਾ ਸ਼ੁਰੂ ਕਰੀਏ।\n" + "ਪਹਿਲੇ ਕਾਲਮ 'ਤੇ ਲੇਬਲ ਐਨਕੋਡਿੰਗ ਕਰਨ ਲਈ, ਸਾਨੂੰ ਪਹਿਲਾਂ ਹਰ ਕਲਾਸ ਤੋਂ ਇੱਕ ਨੰਬਰ ਤੱਕ ਮੈਪਿੰਗ ਦਾ ਵਰਣਨ ਕਰਨਾ ਪਵੇਗਾ, ਇਸ ਤੋਂ ਪਹਿਲਾਂ ਕਿ ਬਦਲਿਆ ਜਾਵੇ।\n" ] }, { @@ -3078,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "ਜਿਵੇਂ ਕਿ ਅਸੀਂ ਵੇਖ ਸਕਦੇ ਹਾਂ, ਨਤੀਜਾ ਉਹੀ ਹੈ ਜੋ ਅਸੀਂ ਸੋਚਿਆ ਸੀ। ਤਾਂ ਫਿਰ, ਅਸੀਂ ਲੇਬਲ ਐਨਕੋਡਿੰਗ ਕਦੋਂ ਵਰਤਦੇ ਹਾਂ? ਲੇਬਲ ਐਨਕੋਡਿੰਗ ਹੇਠਾਂ ਦਿੱਤੇ ਦੋਨੋਂ ਵਿੱਚੋਂ ਕਿਸੇ ਇੱਕ ਜਾਂ ਦੋਨੋਂ ਹਾਲਤਾਂ ਵਿੱਚ ਵਰਤੀ ਜਾਂਦੀ ਹੈ: \n", - "1. ਜਦੋਂ ਸ਼੍ਰੇਣੀਆਂ ਦੀ ਗਿਣਤੀ ਵੱਡੀ ਹੋਵੇ \n", - "2. ਜਦੋਂ ਸ਼੍ਰੇਣੀਆਂ ਵਿੱਚ ਕ੍ਰਮ ਹੋਵੇ। \n" + "ਜਿਵੇਂ ਕਿ ਅਸੀਂ ਦੇਖ ਸਕਦੇ ਹਾਂ, ਨਤੀਜਾ ਉਹੀ ਹੈ ਜੋ ਅਸੀਂ ਸੋਚਿਆ ਸੀ। ਤਾਂ, ਲੇਬਲ ਐਨਕੋਡਿੰਗ ਕਦੋਂ ਵਰਤੀ ਜਾਂਦੀ ਹੈ? ਲੇਬਲ ਐਨਕੋਡਿੰਗ ਹੇਠਾਂ ਦਿੱਤੇ ਦੋਨਾਂ ਵਿੱਚੋਂ ਕਿਸੇ ਇੱਕ ਜਾਂ ਦੋਨਾਂ ਹਾਲਤਾਂ ਵਿੱਚ ਵਰਤੀ ਜਾਂਦੀ ਹੈ:\n", + "1. ਜਦੋਂ ਸ਼੍ਰੇਣੀਆਂ ਦੀ ਗਿਣਤੀ ਵੱਡੀ ਹੁੰਦੀ ਹੈ\n", + "2. ਜਦੋਂ ਸ਼੍ਰੇਣੀਆਂ ਕ੍ਰਮ ਵਿੱਚ ਹੁੰਦੀਆਂ ਹਨ।\n" ] }, { @@ -3089,11 +3105,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**ਵਨ ਹਾਟ ਇਨਕੋਡਿੰਗ**\n", + "**ਵਨ ਹਾਟ ਐਨਕੋਡਿੰਗ**\n", "\n", - "ਇਕ ਹੋਰ ਤਰ੍ਹਾਂ ਦੀ ਇਨਕੋਡਿੰਗ ਵਨ ਹਾਟ ਇਨਕੋਡਿੰਗ ਹੈ। ਇਸ ਤਰ੍ਹਾਂ ਦੀ ਇਨਕੋਡਿੰਗ ਵਿੱਚ, ਕਾਲਮ ਦੀ ਹਰ ਸ਼੍ਰੇਣੀ ਨੂੰ ਇੱਕ ਵੱਖਰੇ ਕਾਲਮ ਵਜੋਂ ਸ਼ਾਮਲ ਕੀਤਾ ਜਾਂਦਾ ਹੈ ਅਤੇ ਹਰ ਡੇਟਾਪੌਇੰਟ ਨੂੰ 0 ਜਾਂ 1 ਮਿਲਦਾ ਹੈ, ਇਸ ਗੱਲ 'ਤੇ ਨਿਰਭਰ ਕਰਦਿਆਂ ਕਿ ਉਹ ਸ਼੍ਰੇਣੀ ਸ਼ਾਮਲ ਹੈ ਜਾਂ ਨਹੀਂ। ਇਸ ਲਈ, ਜੇ n ਵੱਖ-ਵੱਖ ਸ਼੍ਰੇਣੀਆਂ ਹਨ, ਤਾਂ n ਕਾਲਮ ਡੇਟਾਫਰੇਮ ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤੇ ਜਾਣਗੇ।\n", + "ਵਨ ਹਾਟ ਐਨਕੋਡਿੰਗ ਇੱਕ ਹੋਰ ਕਿਸਮ ਦੀ ਐਨਕੋਡਿੰਗ ਹੈ। ਇਸ ਤਰ੍ਹਾਂ ਦੀ ਐਨਕੋਡਿੰਗ ਵਿੱਚ, ਕਾਲਮ ਦੀ ਹਰ ਸ਼੍ਰੇਣੀ ਨੂੰ ਇੱਕ ਵੱਖਰੇ ਕਾਲਮ ਵਜੋਂ ਸ਼ਾਮਲ ਕੀਤਾ ਜਾਂਦਾ ਹੈ ਅਤੇ ਹਰ ਡੇਟਾਪੌਇੰਟ ਨੂੰ 0 ਜਾਂ 1 ਮਿਲਦਾ ਹੈ ਇਸ ਅਧਾਰ 'ਤੇ ਕਿ ਉਹ ਸ਼੍ਰੇਣੀ ਸ਼ਾਮਲ ਹੈ ਜਾਂ ਨਹੀਂ। ਇਸ ਲਈ, ਜੇ n ਵੱਖ-ਵੱਖ ਸ਼੍ਰੇਣੀਆਂ ਹਨ, ਤਾਂ n ਕਾਲਮ ਡੇਟਾਫਰੇਮ ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤੇ ਜਾਣਗੇ।\n", "\n", - "ਉਦਾਹਰਣ ਵਜੋਂ, ਆਓ ਉਹੀ ਜਹਾਜ਼ ਦੀ ਕਲਾਸ ਵਾਲਾ ਉਦਾਹਰਣ ਲਵਾਂ। ਸ਼੍ਰੇਣੀਆਂ ਸਨ: ['ਬਿਜ਼ਨਸ ਕਲਾਸ', 'ਇਕਨਾਮੀ ਕਲਾਸ', 'ਫਰਸਟ ਕਲਾਸ']। ਇਸ ਲਈ, ਜੇ ਅਸੀਂ ਵਨ ਹਾਟ ਇਨਕੋਡਿੰਗ ਕਰਦੇ ਹਾਂ, ਤਾਂ ਹੇਠ ਲਿਖੇ ਤਿੰਨ ਕਾਲਮ ਡੇਟਾਸੈੱਟ ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤੇ ਜਾਣਗੇ: ['class_business class', 'class_economy class', 'class_first class']।\n" + "ਉਦਾਹਰਨ ਵਜੋਂ, ਆਓ ਉਹੀ ਹਵਾਈ ਜਹਾਜ਼ ਕਲਾਸ ਦੀ ਉਦਾਹਰਨ ਲਵਾਂ। ਸ਼੍ਰੇਣੀਆਂ ਸਨ: ['ਬਿਜ਼ਨਸ ਕਲਾਸ', 'ਇਕਾਨਮੀ ਕਲਾਸ', 'ਫਰਸਟ ਕਲਾਸ']। ਇਸ ਲਈ, ਜੇ ਅਸੀਂ ਵਨ ਹਾਟ ਐਨਕੋਡਿੰਗ ਕਰਦੇ ਹਾਂ, ਤਾਂ ਡੇਟਾਸੈਟ ਵਿੱਚ ਹੇਠਾਂ ਦਿੱਤੇ ਤਿੰਨ ਕਾਲਮ ਸ਼ਾਮਲ ਕੀਤੇ ਜਾਣਗੇ: ['class_business class', 'class_economy class', 'class_first class']।\n" ] }, { @@ -3201,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "ਆਓ ਅਸੀਂ ਪਹਿਲੇ ਕਾਲਮ 'ਤੇ ਇੱਕ ਹੌਟ ਐਨਕੋਡਿੰਗ ਕਰੀਏ\n" + "ਆਓ ਪਹਿਲੇ ਕਾਲਮ 'ਤੇ ਇੱਕ ਹਾਟ ਕੋਡਿੰਗ ਕਰੀਏ।\n" ] }, { @@ -3326,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "ਹਰ ਇੱਕ ਹੌਟ ਐਨਕੋਡ ਕੀਤੀ ਕਾਲਮ ਵਿੱਚ 0 ਜਾਂ 1 ਹੁੰਦਾ ਹੈ, ਜੋ ਇਹ ਦਰਸਾਉਂਦਾ ਹੈ ਕਿ ਕੀ ਉਹ ਸ਼੍ਰੇਣੀ ਉਸ ਡੇਟਾਪੌਇੰਟ ਲਈ ਮੌਜੂਦ ਹੈ।\n" + "ਹਰ ਇੱਕ ਹੌਟ ਐਨਕੋਡ ਕੀਤੀ ਕਾਲਮ ਵਿੱਚ 0 ਜਾਂ 1 ਹੁੰਦਾ ਹੈ, ਜੋ ਦਰਸਾਉਂਦਾ ਹੈ ਕਿ ਕੀ ਉਹ ਸ਼੍ਰੇਣੀ ਉਸ ਡੇਟਾਪੌਇੰਟ ਲਈ ਮੌਜੂਦ ਹੈ।\n" ] }, { @@ -3335,9 +3351,9 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "ਅਸੀਂ ਇੱਕ ਹੌਟ ਇਨਕੋਡਿੰਗ ਕਦੋਂ ਵਰਤਦੇ ਹਾਂ? ਇੱਕ ਹੌਟ ਇਨਕੋਡਿੰਗ ਹੇਠਾਂ ਦਿੱਤੇ ਦੋਨੋਂ ਜਾਂ ਦੋਨੋਂ ਹੀ ਮਾਮਲਿਆਂ ਵਿੱਚ ਵਰਤੀ ਜਾਂਦੀ ਹੈ:\n", + "ਜਦੋਂ ਅਸੀਂ ਇੱਕ-ਹਾਟ ਐਨਕੋਡਿੰਗ ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਹਾਂ? ਇੱਕ-ਹਾਟ ਐਨਕੋਡਿੰਗ ਦੀ ਵਰਤੋਂ ਹੇਠਾਂ ਦਿੱਤੇ ਦੋਨਾਂ ਵਿੱਚੋਂ ਕਿਸੇ ਇੱਕ ਜਾਂ ਦੋਨਾਂ ਹਾਲਤਾਂ ਵਿੱਚ ਕੀਤੀ ਜਾਂਦੀ ਹੈ:\n", "\n", - "1. ਜਦੋਂ ਸ਼੍ਰੇਣੀਆਂ ਦੀ ਗਿਣਤੀ ਅਤੇ ਡਾਟਾਸੈਟ ਦਾ ਆਕਾਰ ਛੋਟਾ ਹੁੰਦਾ ਹੈ।\n", + "1. ਜਦੋਂ ਸ਼੍ਰੇਣੀਆਂ ਦੀ ਗਿਣਤੀ ਅਤੇ ਡਾਟਾਸੈੱਟ ਦਾ ਆਕਾਰ ਛੋਟਾ ਹੁੰਦਾ ਹੈ।\n", "2. ਜਦੋਂ ਸ਼੍ਰੇਣੀਆਂ ਕਿਸੇ ਖਾਸ ਕ੍ਰਮ ਦੀ ਪਾਲਣਾ ਨਹੀਂ ਕਰਦੀਆਂ।\n" ] }, @@ -3348,8 +3364,8 @@ }, "source": [ "> ਮੁੱਖ ਗੱਲਾਂ:\n", - "1. ਐਨਕੋਡਿੰਗ ਦਾ ਉਦੇਸ਼ ਗਿਣਤੀ ਨਾ ਹੋਣ ਵਾਲੇ ਡਾਟਾ ਨੂੰ ਗਿਣਤੀ ਵਾਲੇ ਡਾਟਾ ਵਿੱਚ ਬਦਲਣਾ ਹੈ। \n", - "2. ਐਨਕੋਡਿੰਗ ਦੇ ਦੋ ਪ੍ਰਕਾਰ ਹਨ: ਲੇਬਲ ਐਨਕੋਡਿੰਗ ਅਤੇ ਵਨ ਹਾਟ ਐਨਕੋਡਿੰਗ, ਜਿਨ੍ਹਾਂ ਨੂੰ ਡਾਟਾਸੈੱਟ ਦੀ ਲੋੜਾਂ ਦੇ ਅਧਾਰ 'ਤੇ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ। \n" + "1. ਐਨਕੋਡਿੰਗ ਗੈਰ-ਸੰਖਿਆਤਮਕ ਡਾਟਾ ਨੂੰ ਸੰਖਿਆਤਮਕ ਡਾਟਾ ਵਿੱਚ ਤਬਦੀਲ ਕਰਨ ਲਈ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।\n", + "2. ਐਨਕੋਡਿੰਗ ਦੇ ਦੋ ਪ੍ਰਕਾਰ ਹਨ: ਲੇਬਲ ਐਨਕੋਡਿੰਗ ਅਤੇ ਵਨ ਹਾਟ ਐਨਕੋਡਿੰਗ, ਜੋ ਡਾਟਾਸੈੱਟ ਦੀਆਂ ਜ਼ਰੂਰਤਾਂ ਦੇ ਅਧਾਰ 'ਤੇ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ।\n" ] }, { @@ -3360,9 +3376,9 @@ "source": [ "## ਡੁਪਲੀਕੇਟ ਡਾਟਾ ਹਟਾਉਣਾ\n", "\n", - "> **ਸਿੱਖਣ ਦਾ ਉਦੇਸ਼:** ਇਸ ਉਪਵਿਭਾਗ ਦੇ ਅੰਤ ਤੱਕ, ਤੁਸੀਂ DataFrames ਵਿੱਚ ਡੁਪਲੀਕੇਟ ਵੈਲਿਊਜ਼ ਦੀ ਪਹਿਚਾਣ ਅਤੇ ਹਟਾਉਣ ਵਿੱਚ ਸਹੂਲਤ ਮਹਿਸੂਸ ਕਰੋਗੇ।\n", + "> **ਸਿੱਖਣ ਦਾ ਉਦੇਸ਼:** ਇਸ ਉਪਵਿਭਾਗ ਦੇ ਅੰਤ ਤੱਕ, ਤੁਸੀਂ DataFrames ਵਿੱਚ ਡੁਪਲੀਕੇਟ ਮੁੱਲਾਂ ਦੀ ਪਹਿਚਾਣ ਅਤੇ ਹਟਾਉਣ ਵਿੱਚ ਸਹੀ ਹੋ ਜਾਣਗੇ।\n", "\n", - "ਗੁੰਮ ਹੋਈ ਡਾਟਾ ਤੋਂ ਇਲਾਵਾ, ਤੁਸੀਂ ਅਕਸਰ ਅਸਲ-ਜਗਤ ਦੇ ਡਾਟਾਸੈਟਸ ਵਿੱਚ ਡੁਪਲੀਕੇਟ ਡਾਟਾ ਦਾ ਸਾਹਮਣਾ ਕਰਦੇ ਹੋ। ਖੁਸ਼ਕਿਸਮਤੀ ਨਾਲ, pandas ਡੁਪਲੀਕੇਟ ਐਂਟਰੀਜ਼ ਦੀ ਪਹਿਚਾਣ ਅਤੇ ਹਟਾਉਣ ਦਾ ਆਸਾਨ ਤਰੀਕਾ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ।\n" + "ਗੁੰਮ ਹੋਏ ਡਾਟਾ ਤੋਂ ਇਲਾਵਾ, ਤੁਸੀਂ ਅਕਸਰ ਅਸਲ-ਜਗਤ ਦੇ ਡਾਟਾਸੈਟਸ ਵਿੱਚ ਡੁਪਲੀਕੇਟ ਡਾਟਾ ਦਾ ਸਾਹਮਣਾ ਕਰਦੇ ਹੋ। ਖੁਸ਼ਕਿਸਮਤੀ ਨਾਲ, pandas ਡੁਪਲੀਕੇਟ ਐਂਟਰੀਜ਼ ਦੀ ਪਹਿਚਾਣ ਅਤੇ ਹਟਾਉਣ ਦਾ ਇੱਕ ਆਸਾਨ ਤਰੀਕਾ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ।\n" ] }, { @@ -3373,7 +3389,7 @@ "source": [ "### ਨਕਲੀਆਂ ਪਛਾਣਣਾ: `duplicated`\n", "\n", - "ਤੁਸੀਂ pandas ਵਿੱਚ `duplicated` ਵਿਧੀ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਆਸਾਨੀ ਨਾਲ ਨਕਲੀਆਂ ਮੁੱਲਾਂ ਨੂੰ ਪਛਾਣ ਸਕਦੇ ਹੋ, ਜੋ ਇੱਕ ਬੂਲੀਅਨ ਮਾਸਕ ਵਾਪਸ ਕਰਦੀ ਹੈ ਜੋ ਦੱਸਦੀ ਹੈ ਕਿ `DataFrame` ਵਿੱਚ ਕੋਈ ਐਨਟਰੀ ਪਹਿਲਾਂ ਦੀ ਨਕਲ ਹੈ ਜਾਂ ਨਹੀਂ। ਆਓ ਇਸਨੂੰ ਕਾਰਵਾਈ ਵਿੱਚ ਦੇਖਣ ਲਈ ਇੱਕ ਹੋਰ ਉਦਾਹਰਣ `DataFrame` ਬਣਾਈਏ।\n" + "ਤੁਸੀਂ pandas ਵਿੱਚ `duplicated` ਵਿਧੀ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਆਸਾਨੀ ਨਾਲ ਨਕਲੀਆਂ ਮੁੱਲਾਂ ਨੂੰ ਪਛਾਣ ਸਕਦੇ ਹੋ, ਜੋ ਇੱਕ ਬੂਲੀਅਨ ਮਾਸਕ ਵਾਪਸ ਕਰਦੀ ਹੈ ਜੋ ਦੱਸਦੀ ਹੈ ਕਿ ਕੀ `DataFrame` ਵਿੱਚ ਕੋਈ ਐਨਟਰੀ ਪਹਿਲਾਂ ਦੀ ਨਕਲ ਹੈ। ਆਓ ਇਸਨੂੰ ਕਾਰਵਾਈ ਵਿੱਚ ਦੇਖਣ ਲਈ ਇੱਕ ਹੋਰ ਉਦਾਹਰਨ `DataFrame` ਬਣਾਈਏ।\n" ] }, { @@ -3586,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "ਦੋਵੇਂ `duplicated` ਅਤੇ `drop_duplicates` ਮੂਲ ਰੂਪ ਵਿੱਚ ਸਾਰੀਆਂ ਕਾਲਮਾਂ ਨੂੰ ਧਿਆਨ ਵਿੱਚ ਰੱਖਦੇ ਹਨ ਪਰ ਤੁਸੀਂ ਇਹ ਨਿਰਧਾਰਤ ਕਰ ਸਕਦੇ ਹੋ ਕਿ ਉਹ ਤੁਹਾਡੇ `DataFrame` ਵਿੱਚ ਸਿਰਫ਼ ਕੁਝ ਚੁਣੀ ਹੋਈਆਂ ਕਾਲਮਾਂ ਦੀ ਹੀ ਜਾਂਚ ਕਰਨ।\n" + "ਦੋਵੇਂ `duplicated` ਅਤੇ `drop_duplicates` ਮੂਲ ਰੂਪ ਵਿੱਚ ਸਾਰੇ ਕਾਲਮਾਂ ਨੂੰ ਧਿਆਨ ਵਿੱਚ ਰੱਖਦੇ ਹਨ ਪਰ ਤੁਸੀਂ ਨਿਰਧਾਰਿਤ ਕਰ ਸਕਦੇ ਹੋ ਕਿ ਉਹ ਤੁਹਾਡੇ `DataFrame` ਵਿੱਚ ਸਿਰਫ਼ ਕਾਲਮਾਂ ਦੇ ਇੱਕ ਉਪਸੈੱਟ ਦੀ ਜਾਂਚ ਕਰਨ:\n" ] }, { @@ -3662,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **ਮੁੱਖ ਗੱਲ:** ਡੁਪਲੀਕੇਟ ਡਾਟਾ ਨੂੰ ਹਟਾਉਣਾ ਲਗਭਗ ਹਰ ਡਾਟਾ-ਸਾਇੰਸ ਪ੍ਰੋਜੈਕਟ ਦਾ ਇੱਕ ਅਹਿਮ ਹਿੱਸਾ ਹੈ। ਡੁਪਲੀਕੇਟ ਡਾਟਾ ਤੁਹਾਡੇ ਵਿਸ਼ਲੇਸ਼ਣ ਦੇ ਨਤੀਜੇ ਬਦਲ ਸਕਦਾ ਹੈ ਅਤੇ ਤੁਹਾਨੂੰ ਗਲਤ ਨਤੀਜੇ ਦੇ ਸਕਦਾ ਹੈ!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ਅਸਲ-ਦੁਨੀਆ ਦੇ ਡਾਟਾ ਗੁਣਵੱਤਾ ਚੈੱਕ\n", + "\n", + "> **ਸਿੱਖਣ ਦਾ ਉਦੇਸ਼:** ਇਸ ਭਾਗ ਦੇ ਅੰਤ ਤੱਕ, ਤੁਸੀਂ ਅਸਲ-ਦੁਨੀਆ ਦੇ ਡਾਟਾ ਗੁਣਵੱਤਾ ਦੇ ਆਮ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਪਛਾਣਨ ਅਤੇ ਠੀਕ ਕਰਨ ਵਿੱਚ ਸਹੀ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ, ਜਿਸ ਵਿੱਚ ਅਸੰਗਤ ਸ਼੍ਰੇਣੀਮਾਨ ਮੁੱਲ, ਅਸਧਾਰਨ ਸੰਖਿਆਵਾਂ (ਆਊਟਲਾਇਰ), ਅਤੇ ਵੱਖ-ਵੱਖ ਤਰੀਕਿਆਂ ਨਾਲ ਦੁਹਰਾਏ ਗਏ ਇਕਾਈਆਂ ਸ਼ਾਮਲ ਹਨ।\n", + "\n", + "ਜਦੋਂ ਕਿ ਗੁੰਮ ਹੋਏ ਮੁੱਲ ਅਤੇ ਸਹੀ ਦੁਹਰਾਏ ਗਏ ਡਾਟਾ ਆਮ ਸਮੱਸਿਆਵਾਂ ਹਨ, ਅਸਲ-ਦੁਨੀਆ ਦੇ ਡਾਟਾਸੈਟ ਵਿੱਚ ਅਕਸਰ ਹੋਰ ਸੁਖਮ ਸਮੱਸਿਆਵਾਂ ਹੁੰਦੀਆਂ ਹਨ:\n", + "\n", + "1. **ਅਸੰਗਤ ਸ਼੍ਰੇਣੀਮਾਨ ਮੁੱਲ**: ਇੱਕੋ ਸ਼੍ਰੇਣੀ ਨੂੰ ਵੱਖ-ਵੱਖ ਤਰੀਕਿਆਂ ਨਾਲ ਲਿਖਿਆ ਗਿਆ (ਜਿਵੇਂ, \"USA\", \"U.S.A\", \"United States\")\n", + "2. **ਅਸਧਾਰਨ ਸੰਖਿਆਵਾਂ**: ਬਹੁਤ ਜ਼ਿਆਦਾ ਆਊਟਲਾਇਰ ਜੋ ਡਾਟਾ ਐਂਟਰੀ ਦੀ ਗਲਤੀ ਦਰਸਾਉਂਦੇ ਹਨ (ਜਿਵੇਂ, ਉਮਰ = 999)\n", + "3. **ਨਜ਼ਦੀਕੀ-ਦੁਹਰਾਏ ਗਏ ਪੰਨੇ**: ਰਿਕਾਰਡ ਜੋ ਇੱਕੋ ਹੀ ਇਕਾਈ ਨੂੰ ਦਰਸਾਉਂਦੇ ਹਨ ਪਰ ਥੋੜ੍ਹੇ ਬਦਲਾਅ ਨਾਲ\n", + "\n", + "ਆਓ, ਇਨ੍ਹਾਂ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਪਛਾਣਨ ਅਤੇ ਹੱਲ ਕਰਨ ਦੇ ਤਰੀਕਿਆਂ ਦੀ ਜਾਂਚ ਕਰੀਏ।\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### \"ਗੰਦੇ\" ਡਾਟਾਸੈੱਟ ਬਣਾਉਣਾ\n", + "\n", + "ਸਭ ਤੋਂ ਪਹਿਲਾਂ, ਆਓ ਇੱਕ ਨਮੂਨਾ ਡਾਟਾਸੈੱਟ ਬਣਾਈਏ ਜਿਸ ਵਿੱਚ ਉਹ ਸਮੱਸਿਆਵਾਂ ਸ਼ਾਮਲ ਹਨ ਜੋ ਅਸੀਂ ਅਕਸਰ ਅਸਲ-ਦੁਨੀਆ ਦੇ ਡਾਟਾ ਵਿੱਚ ਵੇਖਦੇ ਹਾਂ:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. ਅਸੰਗਤ ਸ਼੍ਰੇਣੀਮਾਨ ਮੁੱਲਾਂ ਦੀ ਪਹਿਚਾਣ\n", + "\n", + "ਧਿਆਨ ਦਿਓ ਕਿ `country` ਕਾਲਮ ਵਿੱਚ ਇੱਕੋ ਦੇਸ਼ਾਂ ਲਈ ਕਈ ਵੱਖ-ਵੱਖ ਪ੍ਰਸਤੁਤੀਆਂ ਹਨ। ਆਓ ਇਨ੍ਹਾਂ ਅਸੰਗਤਤਾਵਾਂ ਦੀ ਪਹਿਚਾਣ ਕਰੀਏ:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### ਸ਼੍ਰੇਣੀਬੱਧ ਮੁੱਲਾਂ ਨੂੰ ਮਿਆਰੀਕਰਣ\n", + "\n", + "ਅਸੀਂ ਇਨ੍ਹਾਂ ਮੁੱਲਾਂ ਨੂੰ ਮਿਆਰੀਕਰਣ ਲਈ ਇੱਕ ਮੈਪਿੰਗ ਬਣਾਉਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਸਕਦੇ ਹਾਂ। ਇੱਕ ਸਧਾਰਨ ਤਰੀਕਾ ਇਹ ਹੈ ਕਿ ਮੁੱਲਾਂ ਨੂੰ ਛੋਟੇ ਅੱਖਰਾਂ ਵਿੱਚ ਬਦਲਿਆ ਜਾਵੇ ਅਤੇ ਇੱਕ ਮੈਪਿੰਗ ਡਿਕਸ਼ਨਰੀ ਬਣਾਈ ਜਾਵੇ:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**ਵਿਕਲਪ: ਫਜ਼ੀ ਮੈਚਿੰਗ ਦੀ ਵਰਤੋਂ ਕਰਨਾ**\n", + "\n", + "ਜਟਿਲ ਮਾਮਲਿਆਂ ਲਈ, ਅਸੀਂ `rapidfuzz` ਲਾਇਬ੍ਰੇਰੀ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਫਜ਼ੀ ਸਟ੍ਰਿੰਗ ਮੈਚਿੰਗ ਕਰ ਸਕਦੇ ਹਾਂ, ਜੋ ਸਵੈਚਾਲਿਤ ਤੌਰ 'ਤੇ ਸਮਾਨ ਸਟ੍ਰਿੰਗਾਂ ਦੀ ਪਛਾਣ ਕਰਦੀ ਹੈ:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. ਅਸਧਾਰਨ ਗਿਣਤੀ ਮੁੱਲਾਂ (ਆਊਟਲਾਇਰ) ਦੀ ਪਹਿਚਾਣ\n", + "\n", + "`age` ਕਾਲਮ ਨੂੰ ਦੇਖਦੇ ਹੋਏ, ਸਾਡੇ ਕੋਲ ਕੁਝ ਸ਼ੱਕੀ ਮੁੱਲ ਹਨ ਜਿਵੇਂ 199 ਅਤੇ -5। ਆਓ, ਇਨ੍ਹਾਂ ਆਊਟਲਾਇਰਾਂ ਦੀ ਪਹਿਚਾਣ ਕਰਨ ਲਈ ਸਾਂਖਿਆਕੀ ਤਰੀਕੇ ਵਰਤਦੇ ਹਾਂ।\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### IQR (ਇੰਟਰਕਵਾਰਟਾਈਲ ਰੇਂਜ) ਵਿਧੀ ਦੀ ਵਰਤੋਂ\n", + "\n", + "IQR ਵਿਧੀ ਇੱਕ ਮਜ਼ਬੂਤ ਸਾਂਖਿਆਕੀ ਤਕਨੀਕ ਹੈ ਜੋ ਅਤਿ ਮੁੱਲਾਂ ਲਈ ਘੱਟ ਸੰਵੇਦਨਸ਼ੀਲ ਹੈ ਅਤੇ ਆਉਟਲਾਇਰ ਪਛਾਣ ਲਈ ਵਰਤੀ ਜਾਂਦੀ ਹੈ:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Z-ਸਕੋਰ ਵਿਧੀ ਦੀ ਵਰਤੋਂ\n", + "\n", + "Z-ਸਕੋਰ ਵਿਧੀ ਮੀਨ ਤੋਂ ਸਟੈਂਡਰਡ ਡਿਵਿਏਸ਼ਨ ਦੇ ਆਧਾਰ 'ਤੇ ਆਉਟਲਾਇਰਜ਼ ਦੀ ਪਹਿਚਾਣ ਕਰਦੀ ਹੈ:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### ਆਉਟਲਾਇਰਸ ਦਾ ਸੰਭਾਲ\n", + "\n", + "ਜਦੋਂ ਪਛਾਣ ਕੀਤੀ ਜਾਂਦੀ ਹੈ, ਆਉਟਲਾਇਰਸ ਨੂੰ ਕਈ ਤਰੀਕਿਆਂ ਨਾਲ ਸੰਭਾਲਿਆ ਜਾ ਸਕਦਾ ਹੈ:\n", + "1. **ਹਟਾਓ**: ਆਉਟਲਾਇਰਸ ਵਾਲੀਆਂ ਪੰਗਤਾਂ ਨੂੰ ਹਟਾਓ (ਜੇ ਇਹ ਗਲਤੀਆਂ ਹਨ)\n", + "2. **ਸੀਮਾ ਲਗਾਓ**: ਸੀਮਾਵੀ ਮੁੱਲਾਂ ਨਾਲ ਬਦਲੋ\n", + "3. **NaN ਨਾਲ ਬਦਲੋ**: ਇਸਨੂੰ ਗੁੰਮ ਹੋਏ ਡਾਟਾ ਵਜੋਂ ਮੰਨੋ ਅਤੇ ਭਰਨ ਦੀਆਂ ਤਕਨੀਕਾਂ ਵਰਤੋ\n", + "4. **ਰੱਖੋ**: ਜੇ ਇਹ ਵਾਸਤਵਿਕ ਤੌਰ 'ਤੇ ਅਤਿ ਮੁੱਲ ਹਨ\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. ਨਜ਼ਦੀਕੀ-ਡੁਪਲੀਕੇਟ ਪੰਗਤਾਂ ਦੀ ਪਹਿਚਾਣ\n", + "\n", + "ਧਿਆਨ ਦਿਓ ਕਿ ਸਾਡੇ ਡਾਟਾਸੈਟ ਵਿੱਚ \"John Smith\" ਲਈ ਕਈ ਐਂਟਰੀਆਂ ਹਨ ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਥੋੜ੍ਹਾ ਜਿਹਾ ਅੰਤਰ ਹੈ। ਆਓ ਨਾਮ ਦੀ ਸਮਾਨਤਾ ਦੇ ਆਧਾਰ 'ਤੇ ਸੰਭਾਵਿਤ ਡੁਪਲੀਕੇਟਾਂ ਦੀ ਪਹਿਚਾਣ ਕਰੀਏ।\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### ਫਜ਼ੀ ਮੈਚਿੰਗ ਨਾਲ ਨਜ਼ਦੀਕੀ ਡੁਪਲੀਕੇਟ ਲੱਭਣਾ\n", + "\n", + "ਜਿਆਦਾ ਉੱਚੇ ਪੱਧਰ ਦੇ ਡੁਪਲੀਕੇਟ ਪਛਾਣ ਲਈ, ਅਸੀਂ ਫਜ਼ੀ ਮੈਚਿੰਗ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੇ ਹਾਂ ਜੋ ਮਿਲਦੇ-ਜੁਲਦੇ ਨਾਮ ਲੱਭਣ ਵਿੱਚ ਮਦਦ ਕਰਦੀ ਹੈ:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### ਡੁਪਲੀਕੇਟਸ ਨੂੰ ਸੰਭਾਲਣਾ\n", + "\n", + "ਜਦੋਂ ਪਛਾਣ ਕੀਤੀ ਜਾਂਦੀ ਹੈ, ਤਾਂ ਤੁਹਾਨੂੰ ਫੈਸਲਾ ਕਰਨਾ ਪਵੇਗਾ ਕਿ ਡੁਪਲੀਕੇਟਸ ਨੂੰ ਕਿਵੇਂ ਸੰਭਾਲਣਾ ਹੈ:\n", + "1. **ਪਹਿਲੀ ਵਾਰ ਨੂੰ ਰੱਖੋ**: `drop_duplicates(keep='first')` ਵਰਤੋ\n", + "2. **ਆਖਰੀ ਵਾਰ ਨੂੰ ਰੱਖੋ**: `drop_duplicates(keep='last')` ਵਰਤੋ\n", + "3. **ਜਾਣਕਾਰੀ ਨੂੰ ਇਕੱਠਾ ਕਰੋ**: ਡੁਪਲੀਕੇਟ ਪੰਨਿਆਂ ਤੋਂ ਜਾਣਕਾਰੀ ਨੂੰ ਜੋੜੋ\n", + "4. **ਹੱਥੋਂ ਸਮੀਖਾ**: ਮਨੁੱਖੀ ਸਮੀਖਾ ਲਈ ਚਿੰਨ੍ਹਿਤ ਕਰੋ\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ਸਾਰ: ਪੂਰੀ ਡਾਟਾ ਕਲੀਨਿੰਗ ਪਾਈਪਲਾਈਨ\n", + "\n", + "ਆਓ ਇਸਨੂੰ ਇੱਕ ਸੰਪੂਰਨ ਕਲੀਨਿੰਗ ਪਾਈਪਲਾਈਨ ਵਿੱਚ ਇਕੱਠਾ ਕਰੀਏ:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 ਚੁਣੌਤੀ ਅਭਿਆਸ\n", + "\n", + "ਹੁਣ ਤੁਹਾਡੀ ਵਾਰੀ ਹੈ! ਹੇਠਾਂ ਦਿੱਤੇ ਡਾਟਾ ਦੀ ਇੱਕ ਨਵੀਂ ਪੰਗਤੀ ਹੈ ਜਿਸ ਵਿੱਚ ਕਈ ਗੁਣਵੱਤਾ ਸਮੱਸਿਆਵਾਂ ਹਨ। ਕੀ ਤੁਸੀਂ:\n", + "\n", + "1. ਇਸ ਪੰਗਤੀ ਵਿੱਚ ਸਾਰੀਆਂ ਸਮੱਸਿਆਵਾਂ ਦੀ ਪਛਾਣ ਕਰ ਸਕਦੇ ਹੋ\n", + "2. ਹਰ ਸਮੱਸਿਆ ਨੂੰ ਸਾਫ ਕਰਨ ਲਈ ਕੋਡ ਲਿਖ ਸਕਦੇ ਹੋ\n", + "3. ਸਾਫ ਕੀਤੀ ਪੰਗਤੀ ਨੂੰ ਡਾਟਾਸੈੱਟ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰ ਸਕਦੇ ਹੋ\n", + "\n", + "ਇਹ ਹੈ ਸਮੱਸਿਆਪੂਰਣ ਡਾਟਾ:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ਮੁੱਖ ਗੱਲਾਂ\n", + "\n", + "1. **ਅਸਥਿਰ ਸ਼੍ਰੇਣੀਆਂ** ਅਕਸਰ ਅਸਲ-ਜਗਤ ਦੇ ਡਾਟਾ ਵਿੱਚ ਮਿਲਦੀਆਂ ਹਨ। ਹਮੇਸ਼ਾ ਵਿਲੱਖਣ ਮੁੱਲਾਂ ਦੀ ਜਾਂਚ ਕਰੋ ਅਤੇ ਉਨ੍ਹਾਂ ਨੂੰ ਮੈਪਿੰਗ ਜਾਂ ਫਜ਼ੀ ਮੈਚਿੰਗ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਸਧਾਰਨ ਬਣਾਓ।\n", + "\n", + "2. **ਆਊਟਲਾਇਰਸ** ਤੁਹਾਡੇ ਵਿਸ਼ਲੇਸ਼ਣ 'ਤੇ ਗੰਭੀਰ ਪ੍ਰਭਾਵ ਪਾ ਸਕਦੇ ਹਨ। ਉਨ੍ਹਾਂ ਦੀ ਪਛਾਣ ਕਰਨ ਲਈ ਡੋਮੇਨ ਗਿਆਨ ਨੂੰ ਸਾਂਖਿਆਕੀ ਤਰੀਕਿਆਂ (IQR, Z-score) ਨਾਲ ਜੋੜੋ।\n", + "\n", + "3. **ਨਜ਼ਦੀਕੀ-ਡੁਪਲੀਕੇਟਸ** ਸਹੀ ਡੁਪਲੀਕੇਟਸ ਨਾਲੋਂ ਪਛਾਣ ਕਰਨਾ ਔਖਾ ਹੁੰਦਾ ਹੈ। ਫਜ਼ੀ ਮੈਚਿੰਗ ਅਤੇ ਡਾਟਾ ਨੂੰ ਨਾਰਮਲਾਈਜ਼ (ਲੋਅਰਕੇਸਿੰਗ, ਵ੍ਹਾਈਟਸਪੇਸ ਹਟਾਉਣਾ) ਕਰਨ ਦੀ ਵਿਚਾਰ ਕਰੋ।\n", + "\n", + "4. **ਡਾਟਾ ਸਾਫ਼ ਕਰਨਾ ਦੁਹਰਾਉਣਯੋਗ ਹੈ।** ਤੁਹਾਨੂੰ ਕਈ ਤਕਨੀਕਾਂ ਲਾਗੂ ਕਰਨੀਆਂ ਪੈ ਸਕਦੀਆਂ ਹਨ ਅਤੇ ਆਪਣੇ ਸਾਫ਼ ਕੀਤੇ ਡਾਟਾਸੈਟ ਨੂੰ ਅੰਤਮ ਰੂਪ ਦੇਣ ਤੋਂ ਪਹਿਲਾਂ ਨਤੀਜਿਆਂ ਦੀ ਸਮੀਖਿਆ ਕਰਨੀ ਪੈ ਸਕਦੀ ਹੈ।\n", + "\n", + "5. **ਆਪਣੇ ਫੈਸਲੇ ਦਸਤਾਵੇਜ਼ ਕਰੋ।** ਤੁਸੀਂ ਕਿਹੜੇ ਸਾਫ਼ ਕਰਨ ਦੇ ਕਦਮ ਲਾਗੂ ਕੀਤੇ ਅਤੇ ਕਿਉਂ, ਇਸ ਨੂੰ ਟਰੈਕ ਕਰਨਾ ਮੁਹੱਤਵਪੂਰਨ ਹੈ, ਤਾਂ ਜੋ ਦੁਬਾਰਾ ਬਣਾਉਣ ਅਤੇ ਪਾਰਦਰਸ਼ਤਾ ਨੂੰ ਯਕੀਨੀ ਬਣਾਇਆ ਜਾ ਸਕੇ।\n", + "\n", + "> **ਸਰਵੋਤਮ ਅਭਿਆਸ:** ਹਮੇਸ਼ਾ ਆਪਣੇ ਅਸਲ \"ਗੰਦੇ\" ਡਾਟਾ ਦੀ ਇੱਕ ਕਾਪੀ ਰੱਖੋ। ਆਪਣੇ ਸਰੋਤ ਡਾਟਾ ਫਾਈਲਾਂ ਨੂੰ ਕਦੇ ਵੀ ਓਵਰਰਾਈਟ ਨਾ ਕਰੋ - ਸਾਫ਼ ਕੀਤੇ ਵਰਜਨ ਬਣਾਓ ਜਿਨ੍ਹਾਂ ਦੇ ਸਪਸ਼ਟ ਨਾਮਕਰਨ ਜਿਵੇਂ `data_cleaned.csv` ਹੋਵੇ।\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**ਅਸਵੀਕਰਤੀ**: \nਇਹ ਦਸਤਾਵੇਜ਼ AI ਅਨੁਵਾਦ ਸੇਵਾ [Co-op Translator](https://github.com/Azure/co-op-translator) ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਅਨੁਵਾਦ ਕੀਤਾ ਗਿਆ ਹੈ। ਜਦੋਂ ਕਿ ਅਸੀਂ ਸਹੀ ਹੋਣ ਦਾ ਯਤਨ ਕਰਦੇ ਹਾਂ, ਕਿਰਪਾ ਕਰਕੇ ਧਿਆਨ ਦਿਓ ਕਿ ਸਵੈਚਾਲਿਤ ਅਨੁਵਾਦਾਂ ਵਿੱਚ ਗਲਤੀਆਂ ਜਾਂ ਅਸੁੱਚੀਤਤਾਵਾਂ ਹੋ ਸਕਦੀਆਂ ਹਨ। ਇਸ ਦੀ ਮੂਲ ਭਾਸ਼ਾ ਵਿੱਚ ਮੌਜੂਦ ਮੂਲ ਦਸਤਾਵੇਜ਼ ਨੂੰ ਪ੍ਰਮਾਣਿਕ ਸਰੋਤ ਮੰਨਿਆ ਜਾਣਾ ਚਾਹੀਦਾ ਹੈ। ਮਹੱਤਵਪੂਰਨ ਜਾਣਕਾਰੀ ਲਈ, ਪੇਸ਼ੇਵਰ ਮਨੁੱਖੀ ਅਨੁਵਾਦ ਦੀ ਸਿਫਾਰਸ਼ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਇਸ ਅਨੁਵਾਦ ਦੀ ਵਰਤੋਂ ਤੋਂ ਪੈਦਾ ਹੋਣ ਵਾਲੇ ਕਿਸੇ ਵੀ ਗਲਤਫਹਿਮੀ ਜਾਂ ਗਲਤ ਵਿਆਖਿਆ ਲਈ ਅਸੀਂ ਜ਼ਿੰਮੇਵਾਰ ਨਹੀਂ ਹਾਂ। \n" + "\n---\n\n**ਅਸਵੀਕਰਤਾ**: \nਇਹ ਦਸਤਾਵੇਜ਼ AI ਅਨੁਵਾਦ ਸੇਵਾ [Co-op Translator](https://github.com/Azure/co-op-translator) ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਅਨੁਵਾਦ ਕੀਤਾ ਗਿਆ ਹੈ। ਜਦੋਂ ਕਿ ਅਸੀਂ ਸਹੀ ਹੋਣ ਦਾ ਯਤਨ ਕਰਦੇ ਹਾਂ, ਕਿਰਪਾ ਕਰਕੇ ਧਿਆਨ ਦਿਓ ਕਿ ਸਵੈਚਾਲਿਤ ਅਨੁਵਾਦਾਂ ਵਿੱਚ ਗਲਤੀਆਂ ਜਾਂ ਅਸੁਚੱਜੇਪਣ ਹੋ ਸਕਦੇ ਹਨ। ਇਸ ਦੀ ਮੂਲ ਭਾਸ਼ਾ ਵਿੱਚ ਮੌਜੂਦ ਅਸਲ ਦਸਤਾਵੇਜ਼ ਨੂੰ ਅਧਿਕਾਰਤ ਸਰੋਤ ਮੰਨਿਆ ਜਾਣਾ ਚਾਹੀਦਾ ਹੈ। ਮਹੱਤਵਪੂਰਨ ਜਾਣਕਾਰੀ ਲਈ, ਪੇਸ਼ੇਵਰ ਮਨੁੱਖੀ ਅਨੁਵਾਦ ਦੀ ਸਿਫਾਰਸ਼ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਇਸ ਅਨੁਵਾਦ ਦੀ ਵਰਤੋਂ ਤੋਂ ਪੈਦਾ ਹੋਣ ਵਾਲੇ ਕਿਸੇ ਵੀ ਗਲਤਫਹਿਮੀ ਜਾਂ ਗਲਤ ਵਿਆਖਿਆ ਲਈ ਅਸੀਂ ਜ਼ਿੰਮੇਵਾਰ ਨਹੀਂ ਹਾਂ।\n" ] } ], @@ -3696,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:32:48+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:50:09+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "pa" } diff --git a/translations/pl/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/pl/2-Working-With-Data/08-data-preparation/notebook.ipynb index c56ebd52..b192111b 100644 --- a/translations/pl/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/pl/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# Przygotowanie danych\n", "\n", - "[Oryginalne źródło notatnika z *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Oryginalne źródło notebooka z *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio autorstwa Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", - "## Eksplorowanie informacji o `DataFrame`\n", + "## Eksploracja informacji o `DataFrame`\n", "\n", - "> **Cel nauki:** Po zakończeniu tej sekcji powinieneś swobodnie znajdować ogólne informacje o danych przechowywanych w pandas DataFrames.\n", + "> **Cel nauki:** Po zakończeniu tej części powinieneś swobodnie znajdować ogólne informacje o danych przechowywanych w pandas DataFrames.\n", "\n", - "Kiedy załadujesz swoje dane do pandas, najprawdopodobniej będą one znajdować się w obiekcie `DataFrame`. Jednak jeśli zbiór danych w Twoim `DataFrame` zawiera 60 000 wierszy i 400 kolumn, jak w ogóle zacząć orientować się, z czym masz do czynienia? Na szczęście pandas oferuje kilka wygodnych narzędzi, które pozwalają szybko uzyskać ogólne informacje o `DataFrame`, a także podejrzeć kilka pierwszych i ostatnich wierszy.\n", + "Gdy załadujesz swoje dane do pandas, najprawdopodobniej będą one w formacie `DataFrame`. Jednak jeśli zestaw danych w Twoim `DataFrame` zawiera 60 000 wierszy i 400 kolumn, od czego zacząć, aby zrozumieć, z czym pracujesz? Na szczęście pandas oferuje kilka wygodnych narzędzi, które pozwalają szybko uzyskać ogólne informacje o `DataFrame`, a także zobaczyć kilka pierwszych i ostatnich wierszy.\n", "\n", - "Aby zbadać tę funkcjonalność, zaimportujemy bibliotekę Python scikit-learn i użyjemy ikonicznego zbioru danych, który każdy data scientist widział setki razy: zbioru danych *Iris* brytyjskiego biologa Ronalda Fishera, użytego w jego pracy z 1936 roku \"The use of multiple measurements in taxonomic problems\":\n" + "Aby zbadać tę funkcjonalność, zaimportujemy bibliotekę Python scikit-learn i użyjemy ikonicznego zestawu danych, który każdy data scientist widział setki razy: zestawu danych *Iris* brytyjskiego biologa Ronalda Fishera, użytego w jego pracy z 1936 roku \"The use of multiple measurements in taxonomic problems\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Załadowaliśmy zbiór danych Iris do zmiennej `iris_df`. Zanim zagłębimy się w dane, warto wiedzieć, ile mamy punktów danych i jaki jest ogólny rozmiar zbioru danych. Dobrze jest przyjrzeć się, z jaką ilością danych mamy do czynienia.\n" + "Załadowaliśmy zbiór danych Iris do zmiennej `iris_df`. Zanim zagłębimy się w dane, warto wiedzieć, ile punktów danych posiadamy oraz jaki jest ogólny rozmiar zbioru danych. Przydatne jest spojrzenie na ilość danych, z którymi mamy do czynienia.\n" ] }, { @@ -78,7 +78,7 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Mamy do czynienia z 150 wierszami i 4 kolumnami danych. Każdy wiersz reprezentuje jeden punkt danych, a każda kolumna odpowiada pojedynczej cesze związanej z ramką danych. Innymi słowy, mamy 150 punktów danych, z których każdy zawiera 4 cechy.\n", + "Mamy do czynienia z 150 wierszami i 4 kolumnami danych. Każdy wiersz reprezentuje jeden punkt danych, a każda kolumna odpowiada pojedynczej cesze związanej z ramką danych. Czyli zasadniczo mamy 150 punktów danych, z których każdy zawiera 4 cechy.\n", "\n", "`shape` tutaj jest atrybutem ramki danych, a nie funkcją, dlatego nie kończy się parą nawiasów.\n" ] @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Przejdźmy teraz do 4 kolumn danych. Co dokładnie każda z nich reprezentuje? Atrybut `columns` pokaże nam nazwy kolumn w dataframe.\n" + "Przejdźmy teraz do 4 kolumn danych. Co dokładnie każda z nich reprezentuje? Atrybut `columns` pozwoli nam uzyskać nazwy kolumn w dataframe.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Ilość danych (podana przez atrybut `shape`) oraz nazwy cech lub kolumn (podane przez atrybut `columns`) dostarczają nam informacji o zbiorze danych. Teraz chcielibyśmy zagłębić się bardziej w ten zbiór danych. Funkcja `DataFrame.info()` jest bardzo przydatna w tym celu.\n" + "Ilość danych (podana przez atrybut `shape`) oraz nazwy cech lub kolumn (podane przez atrybut `columns`) mówią nam coś o zestawie danych. Teraz chcielibyśmy zagłębić się bardziej w zestaw danych. Funkcja `DataFrame.info()` jest bardzo przydatna w tym celu.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Z tego miejsca możemy wyciągnąć kilka obserwacji: \n", - "1. Typ danych każdej kolumny: W tym zbiorze danych wszystkie dane są przechowywane jako liczby zmiennoprzecinkowe 64-bitowe. \n", - "2. Liczba wartości niepustych: Radzenie sobie z brakującymi wartościami to ważny krok w przygotowaniu danych. Zostanie to omówione później w notebooku. \n" + "Na podstawie tego możemy poczynić kilka obserwacji:\n", + "1. Typ danych każdej kolumny: W tym zbiorze danych wszystkie dane są przechowywane jako 64-bitowe liczby zmiennoprzecinkowe.\n", + "2. Liczba wartości niepustych: Radzenie sobie z wartościami pustymi to ważny krok w przygotowaniu danych. Zostanie to omówione później w notatniku.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Załóżmy, że mamy dużo danych numerycznych w naszym zbiorze danych. Jednowymiarowe obliczenia statystyczne, takie jak średnia, mediana, kwartyle itp., mogą być wykonane dla każdej kolumny osobno. Funkcja `DataFrame.describe()` dostarcza nam statystyczne podsumowanie numerycznych kolumn w zbiorze danych.\n" + "Załóżmy, że mamy dużo danych numerycznych w naszym zbiorze danych. Jednowymiarowe obliczenia statystyczne, takie jak średnia, mediana, kwartyle itp., mogą być wykonywane na każdej kolumnie osobno. Funkcja `DataFrame.describe()` dostarcza nam statystyczne podsumowanie numerycznych kolumn w zbiorze danych.\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "Dzięki wszystkim powyższym funkcjom i atrybutom uzyskaliśmy ogólny obraz zbioru danych. Wiemy, ile jest punktów danych, ile jest cech, jaki jest typ danych każdej cechy oraz ile wartości niepustych przypada na każdą cechę.\n", + "Dzięki wszystkim powyższym funkcjom i atrybutom uzyskaliśmy ogólny obraz zestawu danych. Wiemy, ile jest punktów danych, ile jest cech, jaki jest typ danych każdej cechy oraz ile wartości niepustych przypada na każdą cechę.\n", "\n", - "Teraz nadszedł czas, aby przyjrzeć się samym danym. Zobaczmy, jak wyglądają pierwsze wiersze (pierwsze punkty danych) naszego `DataFrame`:\n" + "Teraz czas przyjrzeć się samym danym. Zobaczmy, jak wyglądają pierwsze kilka wierszy (pierwsze kilka punktów danych) naszego `DataFrame`:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "W wyniku tutaj widzimy pięć (5) wpisów zestawu danych. Jeśli spojrzymy na indeks po lewej stronie, dowiemy się, że są to pierwsze pięć wierszy.\n" + "Na podstawie wyników tutaj widzimy pięć (5) wpisów w zestawie danych. Jeśli spojrzymy na indeks po lewej stronie, dowiadujemy się, że są to pierwsze pięć wierszy.\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Inny sposób przeglądania danych to spojrzenie na ich koniec (zamiast na początek). Odpowiednikiem `DataFrame.head` jest `DataFrame.tail`, który zwraca ostatnie pięć wierszy `DataFrame`:\n" + "Innym sposobem przeglądania danych może być spojrzenie od końca (zamiast od początku). Odpowiednikiem `DataFrame.head` jest `DataFrame.tail`, który zwraca ostatnie pięć wierszy `DataFrame`:\n" ] }, { @@ -582,7 +582,7 @@ "id": "31kBWfyLgRr3" }, "source": [ - "W praktyce przydatne jest móc łatwo przejrzeć pierwsze kilka wierszy lub ostatnie kilka wierszy `DataFrame`, szczególnie gdy szukasz wartości odstających w uporządkowanych zbiorach danych.\n", + "W praktyce przydatne jest łatwe przeglądanie pierwszych kilku wierszy lub ostatnich kilku wierszy `DataFrame`, szczególnie gdy szukasz wartości odstających w uporządkowanych zbiorach danych.\n", "\n", "Wszystkie funkcje i atrybuty pokazane powyżej za pomocą przykładów kodu pomagają nam uzyskać wgląd w dane.\n", "\n", @@ -596,17 +596,17 @@ }, "source": [ "### Brakujące dane\n", - "Przyjrzyjmy się brakującym danym. Brakujące dane pojawiają się, gdy w niektórych kolumnach nie ma zapisanej wartości.\n", + "Przyjrzyjmy się brakującym danym. Brakujące dane pojawiają się, gdy w niektórych kolumnach nie jest zapisane żadne wartości.\n", "\n", - "Weźmy przykład: załóżmy, że ktoś jest świadomy swojej wagi i nie wypełnia pola dotyczącego wagi w ankiecie. Wtedy wartość wagi dla tej osoby będzie brakująca.\n", + "Weźmy przykład: załóżmy, że ktoś jest świadomy swojej wagi i nie wypełnia pola dotyczącego wagi w ankiecie. Wtedy wartość wagi dla tej osoby będzie brakować.\n", "\n", - "W większości przypadków, w rzeczywistych zbiorach danych, występują brakujące wartości.\n", + "W większości przypadków w rzeczywistych zbiorach danych występują brakujące wartości.\n", "\n", "**Jak Pandas radzi sobie z brakującymi danymi**\n", "\n", - "Pandas obsługuje brakujące wartości na dwa sposoby. Pierwszy z nich widziałeś już wcześniej w poprzednich sekcjach: `NaN`, czyli Not a Number. Jest to w rzeczywistości specjalna wartość będąca częścią specyfikacji IEEE dla liczb zmiennoprzecinkowych i jest używana wyłącznie do wskazywania brakujących wartości zmiennoprzecinkowych.\n", + "Pandas obsługuje brakujące wartości na dwa sposoby. Pierwszy sposób, który widziałeś wcześniej w poprzednich sekcjach, to `NaN`, czyli Not a Number. Jest to w rzeczywistości specjalna wartość będąca częścią specyfikacji IEEE dla liczb zmiennoprzecinkowych i jest używana wyłącznie do wskazywania brakujących wartości zmiennoprzecinkowych.\n", "\n", - "W przypadku brakujących wartości innych niż liczby zmiennoprzecinkowe, pandas używa obiektu `None` w Pythonie. Choć może wydawać się to mylące, że spotkasz dwa różne typy wartości oznaczające zasadniczo to samo, istnieją uzasadnione programistyczne powody dla takiego wyboru projektowego. W praktyce takie podejście pozwala pandas na osiągnięcie dobrego kompromisu w zdecydowanej większości przypadków. Niemniej jednak zarówno `None`, jak i `NaN` mają ograniczenia, o których należy pamiętać w kontekście ich użycia.\n" + "W przypadku brakujących wartości innych niż liczby zmiennoprzecinkowe, pandas używa obiektu `None` z Pythona. Chociaż może wydawać się to mylące, że spotkasz dwa różne rodzaje wartości oznaczające zasadniczo to samo, istnieją uzasadnione programistyczne powody dla takiego wyboru projektowego. W praktyce takie podejście pozwala pandas na osiągnięcie dobrego kompromisu w zdecydowanej większości przypadków. Niemniej jednak zarówno `None`, jak i `NaN` mają ograniczenia, o których należy pamiętać w kontekście ich użycia.\n" ] }, { @@ -659,7 +659,7 @@ "source": [ "Rzeczywistość związana z podnoszeniem typów danych niesie ze sobą dwa skutki uboczne. Po pierwsze, operacje będą wykonywane na poziomie interpretowanego kodu Python, a nie skompilowanego kodu NumPy. W praktyce oznacza to, że wszelkie operacje obejmujące `Series` lub `DataFrames` zawierające `None` będą wolniejsze. Chociaż prawdopodobnie nie zauważysz tego spadku wydajności, w przypadku dużych zbiorów danych może to stać się problemem.\n", "\n", - "Drugi skutek uboczny wynika z pierwszego. Ponieważ `None` zasadniczo sprowadza `Series` lub `DataFrame` z powrotem do świata czystego Pythona, użycie agregacji NumPy/pandas, takich jak `sum()` czy `min()` na tablicach zawierających wartość ``None`` zazwyczaj spowoduje błąd:\n" + "Drugi skutek uboczny wynika z pierwszego. Ponieważ `None` zasadniczo sprowadza `Series` lub `DataFrame` z powrotem do świata zwykłego Pythona, użycie agregacji NumPy/pandas, takich jak `sum()` czy `min()` na tablicach zawierających wartość ``None`` zazwyczaj spowoduje błąd:\n" ] }, { @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Kluczowa informacja**: Dodawanie (i inne operacje) między liczbami całkowitymi a wartościami `None` jest niezdefiniowane, co może ograniczać możliwości pracy z zestawami danych, które je zawierają.\n" + "**Kluczowa uwaga**: Dodawanie (i inne operacje) między liczbami całkowitymi a wartościami `None` jest niezdefiniowane, co może ograniczać możliwości pracy z zestawami danych, które je zawierają.\n" ] }, { @@ -709,7 +709,7 @@ "source": [ "### `NaN`: brakujące wartości zmiennoprzecinkowe\n", "\n", - "W przeciwieństwie do `None`, NumPy (a co za tym idzie pandas) obsługuje `NaN` dla swoich szybkich, wektorowych operacji i funkcji uniwersalnych (ufuncs). Złą wiadomością jest to, że każda operacja arytmetyczna wykonana na `NaN` zawsze daje w wyniku `NaN`. Na przykład:\n" + "W przeciwieństwie do `None`, NumPy (a co za tym idzie pandas) obsługuje `NaN` w swoich szybkich, wektorowych operacjach i funkcjach ufunc. Zła wiadomość jest taka, że każda operacja arytmetyczna wykonana na `NaN` zawsze daje wynik `NaN`. Na przykład:\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Dobra wiadomość: agregacje wykonywane na tablicach zawierających `NaN` nie generują błędów. Zła wiadomość: wyniki nie zawsze są użyteczne:\n" + "Dobra wiadomość: agregacje uruchamiane na tablicach zawierających `NaN` nie generują błędów. Zła wiadomość: wyniki nie są jednolicie użyteczne:\n" ] }, { @@ -830,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "Pamiętaj: `NaN` jest tylko dla brakujących wartości zmiennoprzecinkowych; nie ma odpowiednika `NaN` dla liczb całkowitych, ciągów znaków ani wartości logicznych.\n" + ] }, { "cell_type": "markdown", @@ -840,7 +842,7 @@ "source": [ "### `NaN` i `None`: wartości null w pandas\n", "\n", - "Chociaż `NaN` i `None` mogą zachowywać się nieco inaczej, pandas zostało zaprojektowane tak, aby obsługiwać je zamiennie. Aby zobaczyć, co mamy na myśli, rozważ `Series` liczb całkowitych:\n" + "Chociaż `NaN` i `None` mogą zachowywać się nieco inaczej, pandas zostało zaprojektowane tak, aby obsługiwać je zamiennie. Aby zobaczyć, o co chodzi, rozważ `Series` liczb całkowitych:\n" ] }, { @@ -904,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "W procesie podnoszenia typów danych w celu zapewnienia jednorodności danych w `Series` i `DataFrame`, pandas bez problemu zamienia brakujące wartości między `None` a `NaN`. Ze względu na tę cechę projektową, warto myśleć o `None` i `NaN` jako o dwóch różnych odmianach \"wartości pustych\" w pandas. W rzeczywistości, niektóre z podstawowych metod, które będziesz używać do obsługi brakujących wartości w pandas, odzwierciedlają tę ideę w swoich nazwach:\n", + "Podczas procesu podnoszenia typów danych w celu zapewnienia jednolitości danych w `Series` i `DataFrame`, pandas bez problemu zamienia brakujące wartości między `None` a `NaN`. Ze względu na tę cechę projektową warto myśleć o `None` i `NaN` jako o dwóch różnych odmianach \"null\" w pandas. W rzeczywistości niektóre z podstawowych metod, które będziesz używać do obsługi brakujących wartości w pandas, odzwierciedlają tę ideę w swoich nazwach:\n", "\n", "- `isnull()`: Tworzy maskę logiczną wskazującą brakujące wartości\n", "- `notnull()`: Przeciwieństwo `isnull()`\n", "- `dropna()`: Zwraca przefiltrowaną wersję danych\n", "- `fillna()`: Zwraca kopię danych z uzupełnionymi lub imputowanymi brakującymi wartościami\n", "\n", - "Te metody są kluczowe do opanowania i warto się z nimi dobrze zapoznać, więc omówmy je każdą z osobna bardziej szczegółowo.\n" + "To są kluczowe metody, które warto opanować i dobrze zrozumieć, więc omówmy je szczegółowo.\n" ] }, { @@ -922,8 +924,7 @@ "source": [ "### Wykrywanie wartości null\n", "\n", - "Teraz, gdy zrozumieliśmy znaczenie brakujących wartości, musimy je wykryć w naszym zbiorze danych, zanim zaczniemy je obsługiwać. \n", - "Zarówno `isnull()`, jak i `notnull()` to podstawowe metody do wykrywania danych null. Obie zwracają maski logiczne dla Twoich danych.\n" + "Teraz, gdy zrozumieliśmy znaczenie brakujących wartości, musimy je wykryć w naszym zbiorze danych, zanim zaczniemy je obsługiwać. Zarówno `isnull()`, jak i `notnull()` są podstawowymi metodami do wykrywania danych null. Obie zwracają maski logiczne dla Twoich danych.\n" ] }, { @@ -976,11 +977,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Przyjrzyj się uważnie wynikowi. Czy coś Cię w nim zaskakuje? Chociaż `0` jest arytmetycznym zerem, to mimo wszystko jest pełnoprawną liczbą całkowitą i pandas traktuje go właśnie w ten sposób. `''` jest nieco bardziej subtelne. Chociaż w Rozdziale 1 używaliśmy go do reprezentowania pustego ciągu znaków, to mimo wszystko jest to obiekt typu string, a nie reprezentacja wartości null w rozumieniu pandas.\n", + "Przyjrzyj się uważnie wynikom. Czy coś Cię zaskakuje? Chociaż `0` jest arytmetycznym zerem, to wciąż jest pełnoprawną liczbą całkowitą i pandas traktuje go właśnie w ten sposób. `''` jest nieco bardziej subtelne. Chociaż używaliśmy tego w Sekcji 1 do reprezentowania pustej wartości tekstowej, to nadal jest to obiekt typu string, a nie reprezentacja null w rozumieniu pandas.\n", "\n", "Teraz odwróćmy sytuację i użyjmy tych metod w sposób bardziej zbliżony do praktycznego zastosowania. Możesz używać masek logicznych bezpośrednio jako indeksu ``Series`` lub ``DataFrame``, co może być przydatne, gdy próbujesz pracować z izolowanymi brakującymi (lub obecnymi) wartościami.\n", "\n", - "Jeśli chcemy uzyskać całkowitą liczbę brakujących wartości, możemy po prostu wykonać sumowanie maski wygenerowanej przez metodę `isnull()`.\n" + "Jeśli chcemy uzyskać całkowitą liczbę brakujących wartości, możemy po prostu wykonać sumę na masce wygenerowanej przez metodę `isnull()`.\n" ] }, { @@ -1038,7 +1039,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Kluczowa informacja**: Zarówno metody `isnull()`, jak i `notnull()` dają podobne wyniki, gdy używasz ich w DataFrame'ach: pokazują wyniki oraz indeks tych wyników, co będzie ogromną pomocą podczas pracy z danymi.\n" + "**Kluczowa informacja**: Zarówno metody `isnull()` jak i `notnull()` dają podobne wyniki, gdy używasz ich w DataFrame'ach: pokazują wyniki oraz indeks tych wyników, co będzie niezwykle pomocne podczas pracy z danymi.\n" ] }, { @@ -1053,7 +1054,7 @@ "\n", "Modele uczenia maszynowego nie potrafią samodzielnie radzić sobie z brakującymi danymi. Dlatego przed przekazaniem danych do modelu musimy zająć się tymi brakującymi wartościami.\n", "\n", - "Sposób, w jaki radzimy sobie z brakującymi danymi, wiąże się z subtelnymi kompromisami i może wpłynąć na końcową analizę oraz wyniki w rzeczywistych zastosowaniach.\n", + "Sposób radzenia sobie z brakującymi danymi wiąże się z subtelnymi kompromisami, które mogą wpłynąć na ostateczną analizę i wyniki w rzeczywistych zastosowaniach.\n", "\n", "Istnieją głównie dwa sposoby radzenia sobie z brakującymi danymi:\n", "\n", @@ -1071,11 +1072,11 @@ "source": [ "### Usuwanie wartości null\n", "\n", - "Ilość danych, które przekazujemy do naszego modelu, ma bezpośredni wpływ na jego wydajność. Usuwanie wartości null oznacza zmniejszenie liczby punktów danych, a co za tym idzie, zmniejszenie rozmiaru zbioru danych. Dlatego zaleca się usuwanie wierszy z wartościami null, gdy zbiór danych jest dość duży.\n", + "Ilość danych, które przekazujemy do naszego modelu, ma bezpośredni wpływ na jego wydajność. Usuwanie wartości null oznacza, że zmniejszamy liczbę punktów danych, a tym samym rozmiar zbioru danych. Dlatego zaleca się usuwanie wierszy z wartościami null, gdy zbiór danych jest dość duży.\n", "\n", - "Innym przypadkiem może być sytuacja, gdy dany wiersz lub kolumna ma wiele brakujących wartości. W takim przypadku można je usunąć, ponieważ nie wniosą one zbyt wiele do naszej analizy, gdy większość danych dla tego wiersza/kolumny jest nieobecna.\n", + "Innym przypadkiem może być sytuacja, gdy określony wiersz lub kolumna ma wiele brakujących wartości. Wtedy można je usunąć, ponieważ nie wniosą one dużej wartości do naszej analizy, gdy większość danych dla tego wiersza/kolumny jest brakująca.\n", "\n", - "Oprócz identyfikowania brakujących wartości, pandas oferuje wygodne narzędzie do usuwania wartości null z `Series` i `DataFrame`. Aby zobaczyć to w praktyce, wróćmy do `example3`. Funkcja `DataFrame.dropna()` pomaga w usuwaniu wierszy z wartościami null.\n" + "Oprócz identyfikowania brakujących wartości, pandas oferuje wygodny sposób na usuwanie wartości null z `Series` i `DataFrame`. Aby zobaczyć to w praktyce, wróćmy do `example3`. Funkcja `DataFrame.dropna()` pomaga w usuwaniu wierszy z wartościami null.\n" ] }, { @@ -1114,7 +1115,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "Należy zauważyć, że wynik powinien wyglądać jak wynik z `example3[example3.notnull()]`. Różnica polega na tym, że zamiast indeksować na podstawie wartości maskowanych, `dropna` usunął te brakujące wartości z `Series` `example3`.\n", + "Zauważ, że powinno to wyglądać jak wynik z `example3[example3.notnull()]`. Różnica polega na tym, że zamiast indeksować tylko na podstawie zamaskowanych wartości, `dropna` usunął te brakujące wartości z `Series` `example3`.\n", "\n", "Ponieważ DataFrames mają dwa wymiary, oferują więcej opcji usuwania danych.\n" ] @@ -1206,9 +1207,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Czy zauważyłeś, że pandas przekonwertował dwie kolumny na typ float, aby uwzględnić `NaN`?)\n", + "(Czy zauważyłeś, że pandas zmienił typ dwóch kolumn na float, aby uwzględnić `NaN`?)\n", "\n", - "Nie możesz usunąć pojedynczej wartości z `DataFrame`, więc musisz usunąć całe wiersze lub kolumny. W zależności od tego, co chcesz osiągnąć, możesz wybrać jedną z tych opcji, a pandas daje możliwość wykonania obu. Ponieważ w nauce o danych kolumny zazwyczaj reprezentują zmienne, a wiersze reprezentują obserwacje, częściej usuwa się wiersze danych; domyślne ustawienie dla `dropna()` to usunięcie wszystkich wierszy zawierających jakiekolwiek wartości null:\n" + "Nie można usunąć pojedynczej wartości z `DataFrame`, więc trzeba usunąć całe wiersze lub kolumny. W zależności od tego, co robisz, możesz chcieć wybrać jedną z tych opcji, dlatego pandas daje możliwość obu. Ponieważ w nauce o danych kolumny zazwyczaj reprezentują zmienne, a wiersze obserwacje, częściej usuwa się wiersze danych; domyślne ustawienie dla `dropna()` polega na usunięciu wszystkich wierszy zawierających jakiekolwiek wartości null:\n" ] }, { @@ -1360,9 +1361,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Zauważ, że może to spowodować utratę dużej ilości danych, które mogą być dla Ciebie istotne, szczególnie w przypadku mniejszych zbiorów danych. Co zrobić, jeśli chcesz usunąć tylko te wiersze lub kolumny, które zawierają kilka lub nawet wszystkie wartości null? Możesz określić te ustawienia w `dropna` za pomocą parametrów `how` i `thresh`.\n", + "Zauważ, że może to spowodować usunięcie dużej ilości danych, które być może chciałbyś zachować, szczególnie w przypadku mniejszych zbiorów danych. Co jeśli chcesz usunąć tylko wiersze lub kolumny, które zawierają kilka lub nawet wszystkie wartości null? Możesz określić te ustawienia w `dropna` za pomocą parametrów `how` i `thresh`.\n", "\n", - "Domyślnie `how='any'` (jeśli chcesz to sprawdzić samodzielnie lub zobaczyć, jakie inne parametry ma ta metoda, uruchom `example4.dropna?` w komórce kodu). Alternatywnie możesz określić `how='all'`, aby usunąć tylko te wiersze lub kolumny, które zawierają wyłącznie wartości null. Rozszerzmy nasz przykład `DataFrame`, aby zobaczyć to w praktyce w następnym ćwiczeniu.\n" + "Domyślnie `how='any'` (jeśli chcesz sprawdzić samodzielnie lub zobaczyć, jakie inne parametry ma ta metoda, uruchom `example4.dropna?` w komórce kodu). Możesz alternatywnie określić `how='all'`, aby usunąć tylko wiersze lub kolumny, które zawierają wszystkie wartości null. Rozszerzmy nasz przykład `DataFrame`, aby zobaczyć to w działaniu w następnym ćwiczeniu.\n" ] }, { @@ -1490,7 +1491,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "Parametr `thresh` daje bardziej szczegółową kontrolę: ustawiasz liczbę wartości *niepustych*, które wiersz lub kolumna muszą mieć, aby zostały zachowane:\n" + "Parametr `thresh` daje bardziej szczegółową kontrolę: ustawiasz liczbę *niepustych* wartości, które wiersz lub kolumna musi mieć, aby zostać zachowanym:\n" ] }, { @@ -1565,7 +1566,7 @@ "id": "fmSFnzZegRsG" }, "source": [ - "Tutaj pierwszy i ostatni wiersz zostały usunięte, ponieważ zawierają tylko dwie niepuste wartości.\n" + "Tutaj pierwsza i ostatnia wiersz zostały usunięte, ponieważ zawierają tylko dwie niepuste wartości.\n" ] }, { @@ -1574,11 +1575,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### Wypełnianie brakujących wartości\n", + "### Wypełnianie wartości null\n", "\n", - "Czasami warto uzupełnić brakujące wartości takimi, które mogą być uznane za prawidłowe. Istnieje kilka technik wypełniania braków. Pierwszą z nich jest wykorzystanie wiedzy dziedzinowej (znajomości tematu, na którym opiera się zestaw danych), aby w przybliżeniu określić brakujące wartości.\n", + "Czasami warto wypełnić brakujące wartości takimi, które mogą być uznane za prawidłowe. Istnieje kilka technik wypełniania wartości null. Pierwszą z nich jest wykorzystanie wiedzy dziedzinowej (wiedzy na temat tematu, na którym opiera się zestaw danych), aby w pewien sposób oszacować brakujące wartości.\n", "\n", - "Możesz użyć `isnull`, aby zrobić to bezpośrednio, ale może to być czasochłonne, szczególnie jeśli masz wiele wartości do uzupełnienia. Ponieważ jest to tak częste zadanie w analizie danych, pandas oferuje funkcję `fillna`, która zwraca kopię `Series` lub `DataFrame` z brakującymi wartościami zastąpionymi wybranymi przez Ciebie. Stwórzmy kolejny przykład `Series`, aby zobaczyć, jak to działa w praktyce.\n" + "Możesz użyć `isnull`, aby zrobić to bezpośrednio, ale może to być czasochłonne, szczególnie jeśli masz wiele wartości do wypełnienia. Ponieważ jest to tak powszechne zadanie w analizie danych, pandas oferuje funkcję `fillna`, która zwraca kopię `Series` lub `DataFrame` z brakującymi wartościami zastąpionymi wybranymi przez Ciebie. Stwórzmy kolejny przykład `Series`, aby zobaczyć, jak to działa w praktyce.\n" ] }, { @@ -1588,9 +1589,9 @@ }, "source": [ "### Dane kategoryczne (nienumeryczne)\n", - "Najpierw rozważmy dane nienumeryczne. W zbiorach danych mamy kolumny zawierające dane kategoryczne, np. płeć, Prawda lub Fałsz itp.\n", + "Najpierw rozważmy dane nienumeryczne. W zestawach danych mamy kolumny zawierające dane kategoryczne, np. płeć, Prawda lub Fałsz itp.\n", "\n", - "W większości takich przypadków zastępujemy brakujące wartości `modą` kolumny. Załóżmy, że mamy 100 punktów danych, z czego 90 wskazało Prawda, 8 wskazało Fałsz, a 2 nie zostały wypełnione. Wtedy możemy uzupełnić te 2 brakujące wartości jako Prawda, biorąc pod uwagę całą kolumnę.\n", + "W większości takich przypadków zastępujemy brakujące wartości `modą` kolumny. Na przykład, mamy 100 punktów danych, z czego 90 wskazało Prawda, 8 wskazało Fałsz, a 2 nie wypełniły. Wówczas możemy uzupełnić te 2 brakujące wartości jako Prawda, biorąc pod uwagę całą kolumnę.\n", "\n", "Tutaj również możemy wykorzystać wiedzę dziedzinową. Rozważmy przykład uzupełniania braków za pomocą mody.\n" ] @@ -1697,7 +1698,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Teraz najpierw znajdźmy modę, zanim wypełnimy wartość `None` modą.\n" + ] }, { "cell_type": "code", @@ -1732,7 +1735,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Więc zastąpimy None wartością True\n" + ] }, { "cell_type": "code", @@ -1842,7 +1847,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Jak widzimy, wartość null została zastąpiona. Nie trzeba dodawać, że moglibyśmy wpisać cokolwiek zamiast `'True'` i zostałoby to podstawione.\n" + "Jak widzimy, wartość null została zastąpiona. Nie trzeba dodawać, że mogliśmy wpisać cokolwiek zamiast `'True'` i zostałoby to podstawione.\n" ] }, { @@ -1851,8 +1856,8 @@ "id": "heYe1I0dOmQ_" }, "source": [ - "### Dane Liczbowe\n", - "Przechodząc teraz do danych liczbowych. Tutaj mamy dwa powszechne sposoby zastępowania brakujących wartości:\n", + "### Dane numeryczne\n", + "Przejdźmy teraz do danych numerycznych. W tym przypadku mamy dwa popularne sposoby zastępowania brakujących wartości:\n", "\n", "1. Zastąpienie medianą wiersza \n", "2. Zastąpienie średnią wiersza \n", @@ -1861,7 +1866,7 @@ "\n", "Gdy dane są znormalizowane, możemy użyć średniej, ponieważ w takim przypadku średnia i mediana będą do siebie bardzo zbliżone.\n", "\n", - "Najpierw weźmy kolumnę, która ma rozkład normalny, i uzupełnijmy brakujące wartości średnią tej kolumny.\n" + "Najpierw weźmy kolumnę, która jest rozkładem normalnym, i uzupełnijmy brakujące wartości średnią z tej kolumny.\n" ] }, { @@ -2001,7 +2006,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Wypełnianie średnią\n" + ] }, { "cell_type": "code", @@ -2110,7 +2117,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Teraz spróbujmy innej ramki danych, a tym razem zastąpimy wartości None medianą kolumny.\n" + "Teraz spróbujmy innego dataframe, a tym razem zastąpimy wartości None medianą kolumny.\n" ] }, { @@ -2250,7 +2257,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Wypełnianie medianą\n" + ] }, { "cell_type": "code", @@ -2433,11 +2442,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Kluczowe wnioski: \n", - "1. Uzupełnianie brakujących wartości powinno być przeprowadzane, gdy danych jest niewiele lub istnieje strategia na ich uzupełnienie. \n", - "2. Wiedza domenowa może być wykorzystana do przybliżonego uzupełnienia brakujących wartości. \n", - "3. W przypadku danych kategorycznych brakujące wartości najczęściej zastępuje się modą kolumny. \n", - "4. W przypadku danych numerycznych brakujące wartości zazwyczaj uzupełnia się średnią (dla znormalizowanych zbiorów danych) lub medianą kolumn. \n" + "> Kluczowe wnioski:\n", + "1. Uzupełnianie brakujących wartości powinno być wykonywane, gdy danych jest niewiele lub istnieje strategia ich uzupełnienia.\n", + "2. Wiedza domenowa może być wykorzystana do przybliżonego uzupełnienia brakujących wartości.\n", + "3. W przypadku danych kategorycznych brakujące wartości najczęściej zastępuje się modą kolumny.\n", + "4. W przypadku danych numerycznych brakujące wartości zazwyczaj uzupełnia się średnią (dla znormalizowanych zbiorów danych) lub medianą kolumn.\n" ] }, { @@ -2446,7 +2455,7 @@ "id": "FI9MmqFJgRsH" }, "source": [ - "Ćwiczenie:\n" + "### Ćwiczenie:\n" ] }, { @@ -2509,7 +2518,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Możesz również **uzupełnić wstecz**, aby propagować następną prawidłową wartość wstecz w celu wypełnienia wartości null:\n" + "Możesz również **uzupełnić wstecz**, aby propagować następne prawidłowe wartości wstecz w celu wypełnienia null:\n" ] }, { @@ -2551,7 +2560,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "Jak możesz się domyślić, działa to tak samo z DataFrames, ale możesz również określić `axis`, wzdłuż którego wypełniane będą wartości null:\n" + "Jak możesz się domyślić, działa to tak samo z DataFrames, ale możesz również określić `axis`, wzdłuż którego wypełniane są wartości null:\n" ] }, { @@ -2757,7 +2766,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Możesz być kreatywny w używaniu `fillna`. Na przykład, spójrzmy ponownie na `example4`, ale tym razem wypełnijmy brakujące wartości średnią wszystkich wartości w `DataFrame`:\n" + "Możesz być kreatywny w użyciu `fillna`. Na przykład, spójrzmy ponownie na `example4`, ale tym razem wypełnijmy brakujące wartości średnią wszystkich wartości w `DataFrame`:\n" ] }, { @@ -2848,9 +2857,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Zauważ, że kolumna 3 nadal nie ma wartości: domyślny kierunek to wypełnianie wartości wierszami.\n", + "Zauważ, że kolumna 3 nadal nie ma wartości: domyślnym kierunkiem jest wypełnianie wartości wierszami.\n", "\n", - "> **Wniosek:** Istnieje wiele sposobów radzenia sobie z brakującymi wartościami w zbiorach danych. Konkretna strategia, którą zastosujesz (usuwanie, zastępowanie lub sposób zastępowania), powinna być uzależniona od specyfiki tych danych. Im więcej będziesz pracować z zestawami danych, tym lepiej zrozumiesz, jak radzić sobie z brakującymi wartościami.\n" + "> **Wniosek:** Istnieje wiele sposobów radzenia sobie z brakującymi wartościami w zbiorach danych. Konkretna strategia, którą zastosujesz (usuwanie, zastępowanie lub sposób zastępowania), powinna być uzależniona od specyfiki danych. Im więcej będziesz pracować z zestawami danych, tym lepiej zrozumiesz, jak radzić sobie z brakującymi wartościami.\n" ] }, { @@ -2872,9 +2881,9 @@ "id": "uDq9SxB7mu5i" }, "source": [ - "**KODOWANIE ETYKIET** \n", + "**KODOWANIE ETYKIET**\n", "\n", - "Kodowanie etykiet polega na zamianie każdej kategorii na liczbę. Na przykład, załóżmy, że mamy zbiór danych pasażerów linii lotniczych i znajduje się w nim kolumna zawierająca ich klasę spośród następujących ['klasa biznesowa', 'klasa ekonomiczna', 'klasa pierwsza']. Jeśli zastosujemy kodowanie etykiet, zostanie to przekształcone na [0,1,2]. Zobaczmy przykład w kodzie. Ponieważ będziemy uczyć się `scikit-learn` w kolejnych notatnikach, tutaj go nie użyjemy.\n" + "Kodowanie etykiet polega na zamianie każdej kategorii na liczbę. Na przykład, załóżmy, że mamy zbiór danych pasażerów linii lotniczych, a jedna z kolumn zawiera ich klasę spośród następujących ['klasa biznesowa', 'klasa ekonomiczna', 'pierwsza klasa']. Jeśli zastosujemy kodowanie etykiet, zostanie to przekształcone na [0,1,2]. Zobaczmy przykład w kodzie. Ponieważ będziemy uczyć się `scikit-learn` w nadchodzących notatnikach, tutaj go nie użyjemy.\n" ] }, { @@ -2982,7 +2991,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Aby wykonać kodowanie etykiet na pierwszej kolumnie, musimy najpierw opisać mapowanie każdej klasy na liczbę, zanim zastąpimy\n" + "Aby wykonać kodowanie etykiet w pierwszej kolumnie, musimy najpierw opisać mapowanie każdej klasy na liczbę, zanim dokonamy zamiany\n" ] }, { @@ -3084,9 +3093,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Jak widzimy, wynik jest zgodny z naszymi przewidywaniami. Kiedy więc stosujemy kodowanie etykiet? Kodowanie etykiet stosuje się w jednym lub obu z poniższych przypadków: \n", - "1. Gdy liczba kategorii jest duża \n", - "2. Gdy kategorie są uporządkowane. \n" + "Jak widzimy, wynik odpowiada temu, czego się spodziewaliśmy. Kiedy więc stosujemy kodowanie etykiet? Kodowanie etykiet stosuje się w jednym lub obu z poniższych przypadków:\n", + "1. Gdy liczba kategorii jest duża\n", + "2. Gdy kategorie są uporządkowane.\n" ] }, { @@ -3095,11 +3104,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**JEDNOZNACZNE KODOWANIE (ONE HOT ENCODING)**\n", + "**JEDNOZNACZNE KODOWANIE**\n", "\n", - "Innym rodzajem kodowania jest jednoznaczne kodowanie (One Hot Encoding). W tym typie kodowania każda kategoria z kolumny zostaje dodana jako osobna kolumna, a każdemu punktowi danych przypisywana jest wartość 0 lub 1 w zależności od tego, czy zawiera daną kategorię. Jeśli więc istnieje n różnych kategorii, do ramki danych zostanie dodanych n kolumn.\n", + "Innym rodzajem kodowania jest Jednoznaczne Kodowanie (One Hot Encoding). W tym typie kodowania każda kategoria z kolumny zostaje dodana jako osobna kolumna, a każdy punkt danych otrzymuje wartość 0 lub 1 w zależności od tego, czy zawiera daną kategorię. Jeśli więc istnieje n różnych kategorii, do ramki danych zostanie dodanych n kolumn.\n", "\n", - "Na przykład, weźmy ten sam przykład klas w samolocie. Kategorie to: ['business class', 'economy class', 'first class']. Jeśli zastosujemy jednoznaczne kodowanie, do zbioru danych zostaną dodane następujące trzy kolumny: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Na przykład, weźmy ten sam przykład klas w samolocie. Kategorie to: ['business class', 'economy class', 'first class']. Jeśli zastosujemy jednoznaczne kodowanie, do zestawu danych zostaną dodane następujące trzy kolumny: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3207,7 +3216,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "Wykonajmy one hot encoding na pierwszej kolumnie\n" + "Wykonajmy kodowanie one hot na pierwszej kolumnie\n" ] }, { @@ -3332,7 +3341,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Każda zakodowana kolumna one-hot zawiera 0 lub 1, co określa, czy dana kategoria istnieje dla tego punktu danych.\n" + "Każda zakodowana kolumna zawiera 0 lub 1, co określa, czy dana kategoria istnieje dla danego punktu danych.\n" ] }, { @@ -3353,9 +3362,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Kluczowe wnioski: \n", - "1. Kodowanie służy do przekształcania danych nienumerycznych na dane numeryczne. \n", - "2. Istnieją dwa rodzaje kodowania: kodowanie etykiet (Label encoding) i kodowanie One Hot, które można zastosować w zależności od wymagań zbioru danych. \n" + "> Najważniejsze informacje:\n", + "1. Kodowanie służy do przekształcania danych nienumerycznych na dane numeryczne.\n", + "2. Istnieją dwa rodzaje kodowania: kodowanie etykiet oraz kodowanie One Hot, które można zastosować w zależności od wymagań zestawu danych.\n" ] }, { @@ -3366,9 +3375,9 @@ "source": [ "## Usuwanie zduplikowanych danych\n", "\n", - "> **Cel nauki:** Po zakończeniu tej sekcji powinieneś swobodnie identyfikować i usuwać zduplikowane wartości z DataFrames.\n", + "> **Cel nauki:** Po zakończeniu tej części powinieneś swobodnie identyfikować i usuwać zduplikowane wartości z DataFrames.\n", "\n", - "Oprócz brakujących danych, w rzeczywistych zbiorach danych często napotkasz zduplikowane dane. Na szczęście pandas oferuje prosty sposób na wykrywanie i usuwanie zduplikowanych wpisów.\n" + "Oprócz brakujących danych, w rzeczywistych zestawach danych często napotkasz zduplikowane dane. Na szczęście pandas oferuje łatwy sposób wykrywania i usuwania zduplikowanych wpisów.\n" ] }, { @@ -3379,7 +3388,7 @@ "source": [ "### Identyfikacja duplikatów: `duplicated`\n", "\n", - "Możesz łatwo zidentyfikować duplikaty za pomocą metody `duplicated` w pandas. Zwraca ona maskę logiczną wskazującą, czy dany wpis w `DataFrame` jest duplikatem wcześniejszego. Stwórzmy kolejny przykład `DataFrame`, aby zobaczyć, jak to działa w praktyce.\n" + "Możesz łatwo wykryć zduplikowane wartości za pomocą metody `duplicated` w pandas, która zwraca maskę logiczną wskazującą, czy wpis w `DataFrame` jest duplikatem wcześniejszego. Stwórzmy kolejny przykład `DataFrame`, aby zobaczyć to w praktyce.\n" ] }, { @@ -3592,7 +3601,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Zarówno `duplicated`, jak i `drop_duplicates` domyślnie uwzględniają wszystkie kolumny, ale możesz określić, że mają sprawdzać tylko podzbiór kolumn w Twoim `DataFrame`:\n" + "Zarówno `duplicated`, jak i `drop_duplicates` domyślnie uwzględniają wszystkie kolumny, ale możesz określić, że mają analizować tylko podzbiór kolumn w Twoim `DataFrame`:\n" ] }, { @@ -3668,13 +3677,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Wniosek:** Usuwanie zduplikowanych danych jest kluczowym elementem niemal każdego projektu z zakresu nauki o danych. Zduplikowane dane mogą zmienić wyniki analiz i prowadzić do nieprawidłowych rezultatów!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Kontrole jakości danych w rzeczywistych zastosowaniach\n", + "\n", + "> **Cel nauki:** Po zakończeniu tej sekcji powinieneś swobodnie wykrywać i poprawiać typowe problemy z jakością danych w rzeczywistych zastosowaniach, takie jak niespójne wartości kategorii, nietypowe wartości numeryczne (wartości odstające) oraz duplikaty encji z wariacjami.\n", + "\n", + "Chociaż brakujące wartości i dokładne duplikaty są częstymi problemami, rzeczywiste zestawy danych często zawierają bardziej subtelne trudności:\n", + "\n", + "1. **Niespójne wartości kategorii**: Ta sama kategoria zapisana w różny sposób (np. \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Nietypowe wartości numeryczne**: Ekstremalne wartości odstające wskazujące na błędy wprowadzania danych (np. wiek = 999)\n", + "3. **Prawie identyczne wiersze**: Rekordy reprezentujące tę samą encję z drobnymi różnicami\n", + "\n", + "Przyjrzyjmy się technikom wykrywania i radzenia sobie z tymi problemami.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tworzenie przykładowego \"zanieczyszczonego\" zestawu danych\n", + "\n", + "Najpierw stwórzmy przykładowy zestaw danych, który zawiera typowe problemy, z jakimi często spotykamy się w danych rzeczywistych:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Wykrywanie niespójnych wartości kategorii\n", + "\n", + "Zauważ, że kolumna `country` zawiera różne reprezentacje tych samych krajów. Zidentyfikujmy te niespójności:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Standaryzacja wartości kategorycznych\n", + "\n", + "Możemy stworzyć mapowanie, aby ujednolicić te wartości. Prostym podejściem jest konwersja na małe litery i utworzenie słownika mapowania:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternatywa: Użycie dopasowania przybliżonego**\n", + "\n", + "W bardziej złożonych przypadkach możemy użyć dopasowania przybliżonego ciągów znaków za pomocą biblioteki `rapidfuzz`, aby automatycznie wykrywać podobne ciągi:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Wykrywanie nietypowych wartości liczbowych (odchylenia)\n", + "\n", + "Przyglądając się kolumnie `age`, zauważamy podejrzane wartości, takie jak 199 i -5. Skorzystajmy z metod statystycznych, aby wykryć te odchylenia.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Korzystanie z metody IQR (Interquartile Range)\n", + "\n", + "Metoda IQR to solidna technika statystyczna do wykrywania wartości odstających, która jest mniej wrażliwa na wartości skrajne:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Korzystanie z metody Z-score\n", + "\n", + "Metoda Z-score identyfikuje wartości odstające na podstawie odchyleń standardowych od średniej:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Obsługa wartości odstających\n", + "\n", + "Po ich wykryciu, wartości odstające można obsłużyć na kilka sposobów:\n", + "1. **Usuń**: Usuń wiersze zawierające wartości odstające (jeśli są błędami)\n", + "2. **Ogranicz**: Zastąp wartościami granicznymi\n", + "3. **Zastąp NaN**: Potraktuj jako brakujące dane i zastosuj techniki imputacji\n", + "4. **Zachowaj**: Jeśli są to uzasadnione wartości ekstremalne\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Wykrywanie prawie identycznych wierszy\n", + "\n", + "Zauważ, że nasz zestaw danych zawiera wiele wpisów dla \"John Smith\" z nieco różniącymi się wartościami. Zidentyfikujmy potencjalne duplikaty na podstawie podobieństwa nazw.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Znajdowanie prawie identycznych elementów za pomocą dopasowania rozmytego\n", + "\n", + "Do bardziej zaawansowanego wykrywania duplikatów możemy użyć dopasowania rozmytego, aby znaleźć podobne nazwy:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Obsługa duplikatów\n", + "\n", + "Po zidentyfikowaniu, musisz zdecydować, jak obsłużyć duplikaty:\n", + "1. **Zachowaj pierwsze wystąpienie**: Użyj `drop_duplicates(keep='first')`\n", + "2. **Zachowaj ostatnie wystąpienie**: Użyj `drop_duplicates(keep='last')`\n", + "3. **Agreguj informacje**: Połącz informacje z duplikowanych wierszy\n", + "4. **Ręczna weryfikacja**: Oznacz do przeglądu przez człowieka\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Podsumowanie: Kompletny Proces Czyszczenia Danych\n", + "\n", + "Połączmy wszystko w jeden kompleksowy proces czyszczenia danych:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Ćwiczenie Wyzwanie\n", + "\n", + "Teraz Twoja kolej! Poniżej znajduje się nowy wiersz danych z wieloma problemami jakościowymi. Czy potrafisz:\n", + "\n", + "1. Zidentyfikować wszystkie problemy w tym wierszu\n", + "2. Napisać kod, aby naprawić każdy problem\n", + "3. Dodać oczyszczony wiersz do zestawu danych\n", + "\n", + "Oto problematyczne dane:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Kluczowe Wnioski\n", + "\n", + "1. **Niespójne kategorie** są częstym problemem w danych rzeczywistych. Zawsze sprawdzaj unikalne wartości i standaryzuj je za pomocą mapowań lub dopasowania przybliżonego.\n", + "\n", + "2. **Wartości odstające** mogą znacząco wpłynąć na Twoją analizę. Wykorzystaj wiedzę domenową w połączeniu z metodami statystycznymi (IQR, Z-score), aby je wykryć.\n", + "\n", + "3. **Prawie duplikaty** są trudniejsze do wykrycia niż dokładne duplikaty. Rozważ użycie dopasowania przybliżonego oraz normalizację danych (zmiana na małe litery, usuwanie spacji), aby je zidentyfikować.\n", + "\n", + "4. **Czyszczenie danych jest procesem iteracyjnym**. Może być konieczne zastosowanie wielu technik i przegląd wyników przed ostatecznym zakończeniem procesu czyszczenia danych.\n", + "\n", + "5. **Dokumentuj swoje decyzje**. Zapisuj, jakie kroki czyszczenia danych zostały zastosowane i dlaczego, ponieważ jest to ważne dla odtwarzalności i przejrzystości.\n", + "\n", + "> **Najlepsza praktyka:** Zawsze zachowaj kopię swoich oryginalnych \"brudnych\" danych. Nigdy nie nadpisuj plików źródłowych - twórz oczyszczone wersje z jasnymi konwencjami nazewnictwa, np. `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Zastrzeżenie**: \nTen dokument został przetłumaczony za pomocą usługi tłumaczeniowej AI [Co-op Translator](https://github.com/Azure/co-op-translator). Chociaż dokładamy wszelkich starań, aby tłumaczenie było precyzyjne, prosimy pamiętać, że automatyczne tłumaczenia mogą zawierać błędy lub nieścisłości. Oryginalny dokument w jego rodzimym języku powinien być uznawany za wiarygodne źródło. W przypadku informacji krytycznych zaleca się skorzystanie z profesjonalnego tłumaczenia wykonanego przez człowieka. Nie ponosimy odpowiedzialności za jakiekolwiek nieporozumienia lub błędne interpretacje wynikające z korzystania z tego tłumaczenia.\n" + "\n---\n\n**Zastrzeżenie**: \nTen dokument został przetłumaczony za pomocą usługi tłumaczenia AI [Co-op Translator](https://github.com/Azure/co-op-translator). Chociaż staramy się zapewnić dokładność, prosimy pamiętać, że automatyczne tłumaczenia mogą zawierać błędy lub nieścisłości. Oryginalny dokument w jego języku źródłowym powinien być uznawany za autorytatywne źródło. W przypadku informacji krytycznych zaleca się skorzystanie z profesjonalnego tłumaczenia przez człowieka. Nie ponosimy odpowiedzialności za jakiekolwiek nieporozumienia lub błędne interpretacje wynikające z użycia tego tłumaczenia.\n" ] } ], @@ -3702,8 +4229,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:36:21+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:02:55+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "pl" } diff --git a/translations/pt/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/pt/2-Working-With-Data/08-data-preparation/notebook.ipynb index aadf55e7..ab3f49a2 100644 --- a/translations/pt/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/pt/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# Preparação de Dados\n", "\n", - "[Origem do Notebook original de *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Fonte original do Notebook de *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", - "## Explorando informações de um `DataFrame`\n", + "## Explorando informações do `DataFrame`\n", "\n", - "> **Objetivo de aprendizagem:** No final desta subseção, deverá sentir-se confortável em encontrar informações gerais sobre os dados armazenados em pandas DataFrames.\n", + "> **Objetivo de aprendizagem:** Ao final desta subseção, deverá sentir-se confortável em encontrar informações gerais sobre os dados armazenados em pandas DataFrames.\n", "\n", - "Depois de carregar os seus dados no pandas, é muito provável que estejam num `DataFrame`. No entanto, se o conjunto de dados no seu `DataFrame` tiver 60.000 linhas e 400 colunas, como começar a ter uma ideia do que está a trabalhar? Felizmente, o pandas fornece algumas ferramentas práticas para rapidamente obter informações gerais sobre um `DataFrame`, além de visualizar as primeiras e últimas linhas.\n", + "Depois de carregar os seus dados no pandas, é muito provável que estejam num `DataFrame`. No entanto, se o conjunto de dados no seu `DataFrame` tiver 60.000 linhas e 400 colunas, como começar a ter uma ideia do que está a trabalhar? Felizmente, o pandas oferece algumas ferramentas convenientes para rapidamente obter informações gerais sobre um `DataFrame`, além das primeiras e últimas linhas.\n", "\n", - "Para explorar esta funcionalidade, iremos importar a biblioteca Python scikit-learn e utilizar um conjunto de dados icónico que todos os cientistas de dados já viram centenas de vezes: o conjunto de dados *Iris* do biólogo britânico Ronald Fisher, usado no seu artigo de 1936 \"The use of multiple measurements in taxonomic problems\":\n" + "Para explorar esta funcionalidade, iremos importar a biblioteca Python scikit-learn e usar um conjunto de dados icónico que todos os cientistas de dados já viram centenas de vezes: o conjunto de dados *Iris* do biólogo britânico Ronald Fisher, utilizado no seu artigo de 1936 \"The use of multiple measurements in taxonomic problems\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Carregámos o Conjunto de Dados Iris na variável `iris_df`. Antes de explorarmos os dados, seria útil saber o número de pontos de dados que temos e o tamanho total do conjunto de dados. É importante ter uma ideia do volume de dados com que estamos a lidar.\n" + "Carregámos o conjunto de dados Iris na variável `iris_df`. Antes de explorar os dados, seria útil saber o número de pontos de dados que temos e o tamanho geral do conjunto de dados. É importante observar o volume de dados com que estamos a lidar.\n" ] }, { @@ -78,7 +78,7 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Portanto, estamos a lidar com 150 linhas e 4 colunas de dados. Cada linha representa um ponto de dados e cada coluna representa uma única característica associada ao quadro de dados. Basicamente, existem 150 pontos de dados, cada um contendo 4 características.\n", + "Portanto, estamos a lidar com 150 linhas e 4 colunas de dados. Cada linha representa um ponto de dados e cada coluna representa uma única característica associada ao quadro de dados. Basicamente, há 150 pontos de dados contendo 4 características cada.\n", "\n", "`shape` aqui é um atributo do quadro de dados e não uma função, razão pela qual não termina com um par de parênteses.\n" ] @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Vamos agora analisar as 4 colunas de dados. O que exatamente cada uma delas representa? O atributo `columns` fornece-nos o nome das colunas no dataframe.\n" + "Vamos agora analisar as 4 colunas de dados. O que cada uma delas representa exatamente? O atributo `columns` fornece-nos os nomes das colunas no dataframe.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Como podemos ver, existem quatro (4) colunas. O atributo `columns` indica-nos o nome das colunas e basicamente nada mais. Este atributo assume importância quando queremos identificar as características que um conjunto de dados contém.\n" + "Como podemos ver, existem quatro (4) colunas. O atributo `columns` indica-nos o nome das colunas e, basicamente, nada mais. Este atributo assume importância quando queremos identificar as características que um conjunto de dados contém.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "A quantidade de dados (dada pelo atributo `shape`) e o nome das características ou colunas (dado pelo atributo `columns`) dizem-nos algo sobre o conjunto de dados. Agora, queremos explorar o conjunto de dados mais a fundo. A função `DataFrame.info()` é bastante útil para isso.\n" + "A quantidade de dados (indicada pelo atributo `shape`) e o nome das características ou colunas (indicados pelo atributo `columns`) dão-nos algumas informações sobre o conjunto de dados. Agora, queremos explorar o conjunto de dados mais a fundo. A função `DataFrame.info()` é bastante útil para isso.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "A partir daqui, podemos fazer algumas observações: \n", - "1. O tipo de dados de cada coluna: Neste conjunto de dados, todos os dados estão armazenados como números de ponto flutuante de 64 bits. \n", - "2. Número de valores não nulos: Lidar com valores nulos é um passo importante na preparação de dados. Isso será tratado mais tarde no notebook. \n" + "A partir daqui, podemos fazer algumas observações:\n", + "1. O tipo de dados de cada coluna: Neste conjunto de dados, todos os dados estão armazenados como números de ponto flutuante de 64 bits.\n", + "2. Número de valores não nulos: Lidar com valores nulos é um passo importante na preparação de dados. Este será tratado mais tarde no notebook.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Suponha que temos muitos dados numéricos no nosso conjunto de dados. Cálculos estatísticos univariados, como a média, mediana, quartis, etc., podem ser realizados individualmente em cada uma das colunas. A função `DataFrame.describe()` fornece-nos um resumo estatístico das colunas numéricas de um conjunto de dados.\n" + "Suponha que temos muitos dados numéricos no nosso conjunto de dados. Cálculos estatísticos univariados, como a média, mediana, quartis, etc., podem ser realizados em cada uma das colunas individualmente. A função `DataFrame.describe()` fornece-nos um resumo estatístico das colunas numéricas de um conjunto de dados.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "O resultado acima mostra o número total de pontos de dados, média, desvio padrão, mínimo, primeiro quartil (25%), mediana (50%), terceiro quartil (75%) e o valor máximo de cada coluna.\n" + "O resultado acima mostra o número total de pontos de dados, média, desvio padrão, mínimo, quartil inferior (25%), mediana (50%), quartil superior (75%) e o valor máximo de cada coluna.\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "Com todas as funções e atributos mencionados acima, obtivemos uma visão geral do conjunto de dados. Sabemos quantos pontos de dados existem, quantas características estão presentes, o tipo de dado de cada característica e o número de valores não nulos para cada uma delas.\n", + "Com todas as funções e atributos mencionados acima, obtivemos uma visão geral do conjunto de dados. Sabemos quantos pontos de dados existem, quantas características existem, o tipo de dados de cada característica e o número de valores não nulos para cada característica.\n", "\n", - "Agora é hora de olhar para os próprios dados. Vamos ver como são as primeiras linhas (os primeiros pontos de dados) do nosso `DataFrame`:\n" + "Agora é hora de olhar para os dados propriamente ditos. Vamos ver como são as primeiras linhas (os primeiros pontos de dados) do nosso `DataFrame`:\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Exercício:\n", "\n", - "Pelo exemplo dado acima, é claro que, por padrão, `DataFrame.head` retorna as primeiras cinco linhas de um `DataFrame`. Na célula de código abaixo, consegue descobrir uma forma de exibir mais de cinco linhas?\n" + "Pelo exemplo dado acima, é claro que, por padrão, `DataFrame.head` retorna as primeiras cinco linhas de um `DataFrame`. No bloco de código abaixo, consegue descobrir uma forma de exibir mais de cinco linhas?\n" ] }, { @@ -582,7 +582,7 @@ "id": "31kBWfyLgRr3" }, "source": [ - "Na prática, é útil poder examinar facilmente as primeiras ou as últimas linhas de um `DataFrame`, especialmente quando se procura por valores atípicos em conjuntos de dados ordenados.\n", + "Na prática, é útil poder examinar facilmente as primeiras ou últimas linhas de um `DataFrame`, especialmente quando se está à procura de valores atípicos em conjuntos de dados ordenados.\n", "\n", "Todas as funções e atributos mostrados acima, com a ajuda de exemplos de código, ajudam-nos a ter uma visão geral dos dados.\n", "\n", @@ -596,17 +596,17 @@ }, "source": [ "### Dados em Falta\n", - "Vamos explorar o tema dos dados em falta. Dados em falta ocorrem quando não há nenhum valor armazenado em algumas das colunas.\n", + "Vamos explorar o tema dos dados em falta. Dados em falta ocorrem quando não há valor armazenado em algumas das colunas.\n", "\n", "Vamos considerar um exemplo: imagine que alguém está preocupado com o seu peso e decide não preencher o campo de peso num inquérito. Nesse caso, o valor do peso para essa pessoa estará em falta.\n", "\n", - "Na maioria das vezes, em conjuntos de dados do mundo real, é comum encontrar valores em falta.\n", + "Na maioria das vezes, em conjuntos de dados do mundo real, os valores em falta são comuns.\n", "\n", "**Como o Pandas lida com dados em falta**\n", "\n", - "O Pandas lida com valores em falta de duas formas. A primeira, que já viu em secções anteriores, é o `NaN`, ou Not a Number (Não é um Número). Este é, na verdade, um valor especial que faz parte da especificação IEEE para números de ponto flutuante e é usado apenas para indicar valores de ponto flutuante em falta.\n", + "O Pandas lida com valores em falta de duas formas. A primeira, que já foi mencionada em secções anteriores, é através de `NaN`, ou Not a Number. Este é, na verdade, um valor especial que faz parte da especificação de ponto flutuante IEEE e é usado apenas para indicar valores em falta de tipo ponto flutuante.\n", "\n", - "Para valores em falta que não sejam de ponto flutuante, o Pandas utiliza o objeto `None` do Python. Embora possa parecer confuso encontrar dois tipos diferentes de valores que essencialmente indicam a mesma coisa, existem razões programáticas válidas para esta escolha de design. Na prática, esta abordagem permite que o Pandas ofereça um bom compromisso para a grande maioria dos casos. Apesar disso, tanto `None` como `NaN` têm restrições que deve ter em mente no que diz respeito à forma como podem ser utilizados.\n" + "Para valores em falta que não sejam de tipo ponto flutuante, o Pandas utiliza o objeto `None` do Python. Embora possa parecer confuso encontrar dois tipos diferentes de valores que essencialmente indicam a mesma coisa, há razões programáticas válidas para esta escolha de design. Na prática, esta abordagem permite ao Pandas oferecer um bom compromisso para a grande maioria dos casos. Apesar disso, tanto `None` como `NaN` têm restrições que é importante ter em mente no que diz respeito à forma como podem ser utilizados.\n" ] }, { @@ -616,9 +616,9 @@ }, "source": [ "### `None`: dados ausentes não numéricos\n", - "Como `None` vem do Python, não pode ser utilizado em arrays do NumPy e pandas que não sejam do tipo de dados `'object'`. Lembre-se de que os arrays do NumPy (e as estruturas de dados no pandas) podem conter apenas um tipo de dado. É isso que lhes confere um enorme poder para trabalhar com grandes volumes de dados e cálculos, mas também limita a sua flexibilidade. Esses arrays precisam ser convertidos para o “menor denominador comum”, ou seja, o tipo de dado que abrange todos os elementos do array. Quando `None` está presente no array, significa que está a trabalhar com objetos do Python.\n", + "Como o `None` vem do Python, ele não pode ser utilizado em arrays do NumPy e pandas que não sejam do tipo de dados `'object'`. Lembre-se de que os arrays do NumPy (e as estruturas de dados no pandas) podem conter apenas um tipo de dado. É isso que lhes confere um enorme poder para trabalhar com dados em grande escala e realizar cálculos, mas também limita a sua flexibilidade. Esses arrays precisam ser convertidos para o \"denominador comum mais baixo\", ou seja, o tipo de dado que abrange tudo no array. Quando `None` está presente no array, significa que está a trabalhar com objetos do Python.\n", "\n", - "Para ver isto em ação, considere o seguinte exemplo de array (note o `dtype` associado):\n" + "Para ver isso em prática, considere o seguinte exemplo de array (note o `dtype` associado):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "A realidade dos tipos de dados promovidos traz consigo dois efeitos secundários. Primeiro, as operações serão realizadas ao nível do código interpretado em Python, em vez do código compilado do NumPy. Essencialmente, isto significa que quaisquer operações envolvendo `Series` ou `DataFrames` com `None` serão mais lentas. Embora provavelmente não note este impacto na performance, em conjuntos de dados grandes pode tornar-se um problema.\n", + "A realidade dos tipos de dados promovidos traz consigo dois efeitos secundários. Primeiro, as operações serão realizadas ao nível do código interpretado em Python, em vez do código compilado do NumPy. Essencialmente, isto significa que quaisquer operações envolvendo `Series` ou `DataFrames` que contenham `None` serão mais lentas. Embora provavelmente não note este impacto na performance, em conjuntos de dados grandes pode tornar-se um problema.\n", "\n", - "O segundo efeito secundário decorre do primeiro. Como `None` essencialmente faz com que `Series` ou `DataFrames` regressem ao mundo do Python puro, utilizar agregações do NumPy/pandas como `sum()` ou `min()` em arrays que contêm um valor ``None`` geralmente produzirá um erro:\n" + "O segundo efeito secundário decorre do primeiro. Como `None` essencialmente arrasta `Series` ou `DataFrames` de volta para o mundo do Python puro, usar agregações do NumPy/pandas como `sum()` ou `min()` em arrays que contêm um valor ``None`` geralmente resultará num erro:\n" ] }, { @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**Conclusão principal**: A adição (e outras operações) entre inteiros e valores `None` é indefinida, o que pode limitar o que se pode fazer com conjuntos de dados que os contenham.\n" + ] }, { "cell_type": "markdown", @@ -707,7 +709,7 @@ "source": [ "### `NaN`: valores de ponto flutuante em falta\n", "\n", - "Ao contrário de `None`, o NumPy (e, consequentemente, o pandas) suporta `NaN` para as suas operações rápidas, vetorizadas e ufuncs. A má notícia é que qualquer operação aritmética realizada com `NaN` resulta sempre em `NaN`. Por exemplo:\n" + "Ao contrário de `None`, NumPy (e, consequentemente, pandas) suporta `NaN` para as suas operações rápidas, vetorizadas e ufuncs. A má notícia é que qualquer operação aritmética realizada com `NaN` resulta sempre em `NaN`. Por exemplo:\n" ] }, { @@ -828,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "Lembre-se: `NaN` é apenas para valores de ponto flutuante em falta; não existe equivalente a `NaN` para inteiros, strings ou valores Booleanos.\n" + ] }, { "cell_type": "markdown", @@ -838,7 +842,7 @@ "source": [ "### `NaN` e `None`: valores nulos no pandas\n", "\n", - "Embora `NaN` e `None` possam comportar-se de forma ligeiramente diferente, o pandas foi concebido para lidar com ambos de forma intercambiável. Para perceber melhor, considere uma `Series` de números inteiros:\n" + "Embora `NaN` e `None` possam comportar-se de forma ligeiramente diferente, o pandas foi concebido para lidar com ambos de forma intercambiável. Para entender melhor, considere uma `Series` de inteiros:\n" ] }, { @@ -902,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "No processo de promoção de tipos de dados para estabelecer homogeneidade em `Series` e `DataFrame`s, o pandas troca de forma natural os valores em falta entre `None` e `NaN`. Devido a esta característica de design, pode ser útil pensar em `None` e `NaN` como duas variantes diferentes de \"nulo\" no pandas. De facto, alguns dos métodos principais que irá utilizar para lidar com valores em falta no pandas refletem esta ideia nos seus nomes:\n", + "No processo de promoção de tipos de dados para estabelecer homogeneidade de dados em `Series` e `DataFrame`s, o pandas troca facilmente valores em falta entre `None` e `NaN`. Devido a esta característica de design, pode ser útil pensar em `None` e `NaN` como dois tipos diferentes de \"nulo\" no pandas. De facto, alguns dos métodos principais que irá utilizar para lidar com valores em falta no pandas refletem esta ideia nos seus nomes:\n", "\n", - "- `isnull()`: Gera uma máscara booleana que indica os valores em falta\n", + "- `isnull()`: Gera uma máscara booleana que indica valores em falta\n", "- `notnull()`: O oposto de `isnull()`\n", "- `dropna()`: Retorna uma versão filtrada dos dados\n", - "- `fillna()`: Retorna uma cópia dos dados com os valores em falta preenchidos ou imputados\n", + "- `fillna()`: Retorna uma cópia dos dados com valores em falta preenchidos ou imputados\n", "\n", - "Estes são métodos importantes para dominar e com os quais deve sentir-se confortável, por isso vamos analisá-los com algum detalhe.\n" + "Estes são métodos importantes para dominar e se familiarizar, por isso vamos analisá-los cada um com mais detalhe.\n" ] }, { @@ -921,7 +925,7 @@ "### Detetar valores nulos\n", "\n", "Agora que compreendemos a importância dos valores em falta, precisamos de os identificar no nosso conjunto de dados antes de os tratar. \n", - "Tanto `isnull()` como `notnull()` são os seus métodos principais para detetar dados nulos. Ambos retornam máscaras booleanas sobre os seus dados.\n" + "Tanto `isnull()` como `notnull()` são os métodos principais para detetar dados nulos. Ambos devolvem máscaras Booleanas sobre os seus dados.\n" ] }, { @@ -974,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Olhe atentamente para o resultado. Alguma coisa nele surpreende você? Embora `0` seja um nulo aritmético, ainda assim é um número inteiro perfeitamente válido, e o pandas trata-o como tal. `''` é um pouco mais subtil. Embora o tenhamos usado na Secção 1 para representar um valor de string vazio, ainda assim é um objeto de string e não uma representação de nulo no que diz respeito ao pandas.\n", + "Olhe atentamente para o resultado. Alguma coisa surpreende? Embora `0` seja um nulo aritmético, é, no entanto, um número inteiro perfeitamente válido, e o pandas trata-o como tal. `''` é um pouco mais subtil. Embora o tenhamos usado na Secção 1 para representar um valor de string vazio, continua a ser um objeto de string e não uma representação de nulo no que diz respeito ao pandas.\n", "\n", - "Agora, vamos inverter a abordagem e usar estes métodos de uma forma mais parecida com a que você os usará na prática. Pode usar máscaras Booleanas diretamente como um índice de ``Series`` ou ``DataFrame``, o que pode ser útil ao tentar trabalhar com valores ausentes (ou presentes) isolados.\n", + "Agora, vamos inverter a abordagem e usar estes métodos de uma forma mais semelhante ao que fará na prática. Pode usar máscaras Booleanas diretamente como um índice de ``Series`` ou ``DataFrame``, o que pode ser útil ao trabalhar com valores ausentes (ou presentes) isolados.\n", "\n", - "Se quisermos o número total de valores ausentes, podemos simplesmente fazer uma soma sobre a máscara produzida pelo método `isnull()`.\n" + "Se quisermos o número total de valores ausentes, basta fazer uma soma sobre a máscara produzida pelo método `isnull()`.\n" ] }, { @@ -1036,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Conclusão principal**: Tanto os métodos `isnull()` como `notnull()` produzem resultados semelhantes quando os utiliza em DataFrames: mostram os resultados e o índice desses resultados, o que o ajudará imensamente enquanto trabalha com os seus dados.\n" + "**Conclusão principal**: Tanto o método `isnull()` como o método `notnull()` produzem resultados semelhantes quando utilizados em DataFrames: mostram os resultados e o índice desses resultados, o que será de grande ajuda enquanto lida com os seus dados.\n" ] }, { @@ -1049,13 +1053,13 @@ "\n", "> **Objetivo de aprendizagem:** No final desta subseção, deverá saber como e quando substituir ou remover valores nulos de DataFrames.\n", "\n", - "Os modelos de Machine Learning não conseguem lidar diretamente com dados em falta. Por isso, antes de passar os dados para o modelo, é necessário tratar esses valores ausentes.\n", + "Os modelos de Machine Learning não conseguem lidar diretamente com dados em falta. Por isso, antes de passar os dados para o modelo, é necessário tratar esses valores em falta.\n", "\n", - "A forma como os dados em falta são tratados envolve escolhas subtis, podendo influenciar a sua análise final e os resultados no mundo real.\n", + "A forma como os dados em falta são tratados envolve escolhas subtis, pode influenciar a sua análise final e os resultados no mundo real.\n", "\n", - "Existem principalmente duas maneiras de lidar com dados em falta:\n", + "Existem principalmente duas formas de lidar com dados em falta:\n", "\n", - "1. Remover a linha que contém o valor em falta\n", + "1. Eliminar a linha que contém o valor em falta\n", "2. Substituir o valor em falta por outro valor\n", "\n", "Vamos discutir ambos os métodos e os seus prós e contras em detalhe.\n" @@ -1069,9 +1073,9 @@ "source": [ "### Eliminar valores nulos\n", "\n", - "A quantidade de dados que passamos para o nosso modelo tem um efeito direto no seu desempenho. Eliminar valores nulos significa que estamos a reduzir o número de pontos de dados e, consequentemente, o tamanho do conjunto de dados. Por isso, é recomendável eliminar linhas com valores nulos quando o conjunto de dados é bastante grande.\n", + "A quantidade de dados que passamos ao nosso modelo tem um efeito direto no seu desempenho. Eliminar valores nulos significa que estamos a reduzir o número de pontos de dados e, consequentemente, o tamanho do conjunto de dados. Por isso, é recomendável eliminar linhas com valores nulos quando o conjunto de dados é bastante grande.\n", "\n", - "Outro caso pode ser que uma determinada linha ou coluna tenha muitos valores em falta. Nesse caso, podem ser eliminadas porque não acrescentariam muito valor à nossa análise, já que a maior parte dos dados está em falta nessa linha/coluna.\n", + "Outro caso pode ser quando uma determinada linha ou coluna tem muitos valores em falta. Nesse caso, podem ser eliminadas, pois não acrescentariam muito valor à nossa análise, já que a maior parte dos dados está em falta para essa linha/coluna.\n", "\n", "Para além de identificar valores em falta, pandas oferece uma forma prática de remover valores nulos de `Series` e `DataFrame`s. Para ver isto em ação, vamos voltar ao `example3`. A função `DataFrame.dropna()` ajuda a eliminar as linhas com valores nulos.\n" ] @@ -1112,7 +1116,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "Note que isto deve parecer com o seu resultado de `example3[example3.notnull()]`. A diferença aqui é que, em vez de apenas indexar os valores mascarados, `dropna` removeu esses valores em falta da `Series` `example3`.\n", + "Note que isto deve parecer-se com o resultado de `example3[example3.notnull()]`. A diferença aqui é que, em vez de apenas indexar os valores mascarados, `dropna` removeu esses valores em falta da `Series` `example3`.\n", "\n", "Como os DataFrames têm duas dimensões, oferecem mais opções para eliminar dados.\n" ] @@ -1204,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Reparaste que o pandas converteu duas das colunas para floats para acomodar os `NaN`s?)\n", + "(Reparou que o pandas converteu duas das colunas para floats para acomodar os `NaN`s?)\n", "\n", - "Não podes eliminar um único valor de um `DataFrame`, por isso tens de eliminar linhas ou colunas inteiras. Dependendo do que estás a fazer, podes preferir uma ou outra opção, e o pandas oferece-te alternativas para ambas. Como na ciência de dados as colunas geralmente representam variáveis e as linhas representam observações, é mais provável que elimines linhas de dados; a configuração padrão de `dropna()` é eliminar todas as linhas que contenham quaisquer valores nulos:\n" + "Não é possível remover um único valor de um `DataFrame`, por isso é necessário eliminar linhas ou colunas inteiras. Dependendo do que está a fazer, pode preferir uma ou outra opção, e o pandas oferece alternativas para ambas. Como, na ciência de dados, as colunas geralmente representam variáveis e as linhas representam observações, é mais comum eliminar linhas de dados; a configuração padrão de `dropna()` é eliminar todas as linhas que contêm quaisquer valores nulos:\n" ] }, { @@ -1279,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "Se necessário, pode remover valores NA das colunas. Use `axis=1` para o fazer:\n" + "Se necessário, pode eliminar valores NA das colunas. Utilize `axis=1` para o fazer:\n" ] }, { @@ -1358,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Note que isto pode eliminar muitos dados que talvez queira manter, especialmente em conjuntos de dados mais pequenos. E se apenas quiser eliminar linhas ou colunas que contenham vários ou mesmo todos os valores nulos? Pode especificar essas configurações em `dropna` com os parâmetros `how` e `thresh`.\n", + "Note que isto pode eliminar muitos dados que pode querer manter, especialmente em conjuntos de dados menores. E se quiser apenas eliminar linhas ou colunas que contenham vários ou até mesmo todos os valores nulos? Pode especificar essas configurações em `dropna` com os parâmetros `how` e `thresh`.\n", "\n", - "Por padrão, `how='any'` (se quiser verificar por si mesmo ou ver que outros parâmetros o método possui, execute `example4.dropna?` numa célula de código). Alternativamente, pode especificar `how='all'` para eliminar apenas linhas ou colunas que contenham todos os valores nulos. Vamos expandir o nosso exemplo de `DataFrame` para ver isto em ação no próximo exercício.\n" + "Por padrão, `how='any'` (se quiser verificar por si mesmo ou ver quais outros parâmetros o método possui, execute `example4.dropna?` numa célula de código). Pode, alternativamente, especificar `how='all'` para eliminar apenas linhas ou colunas que contenham todos os valores nulos. Vamos expandir o nosso exemplo de `DataFrame` para ver isto em ação no próximo exercício.\n" ] }, { @@ -1453,10 +1457,10 @@ }, "source": [ "> Principais pontos: \n", - "1. Eliminar valores nulos é uma boa ideia apenas se o conjunto de dados for suficientemente grande. \n", + "1. Eliminar valores nulos só é uma boa ideia se o conjunto de dados for suficientemente grande. \n", "2. Linhas ou colunas inteiras podem ser eliminadas se a maior parte dos seus dados estiver em falta. \n", "3. O método `DataFrame.dropna(axis=)` ajuda a eliminar valores nulos. O argumento `axis` indica se devem ser eliminadas linhas ou colunas. \n", - "4. O argumento `how` também pode ser utilizado. Por padrão, está definido como `any`. Assim, elimina apenas as linhas/colunas que contêm qualquer valor nulo. Pode ser definido como `all` para especificar que eliminaremos apenas as linhas/colunas onde todos os valores são nulos. \n" + "4. O argumento `how` também pode ser utilizado. Por padrão, está definido como `any`. Assim, elimina apenas as linhas/colunas que contêm algum valor nulo. Pode ser definido como `all` para especificar que apenas eliminaremos as linhas/colunas onde todos os valores são nulos. \n" ] }, { @@ -1572,11 +1576,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### Preenchimento de valores nulos\n", + "### Preenchendo valores nulos\n", "\n", - "Por vezes, faz sentido preencher valores em falta com outros que possam ser válidos. Existem algumas técnicas para preencher valores nulos. A primeira é utilizar Conhecimento do Domínio (conhecimento sobre o tema no qual o conjunto de dados se baseia) para, de alguma forma, aproximar os valores em falta.\n", + "Por vezes, faz sentido preencher valores em falta com aqueles que poderiam ser válidos. Existem algumas técnicas para preencher valores nulos. A primeira é usar Conhecimento do Domínio (conhecimento sobre o tema no qual o conjunto de dados se baseia) para, de alguma forma, aproximar os valores em falta.\n", "\n", - "Pode utilizar `isnull` para fazer isso diretamente, mas isso pode ser trabalhoso, especialmente se tiver muitos valores para preencher. Como esta é uma tarefa tão comum em ciência de dados, o pandas oferece o método `fillna`, que devolve uma cópia da `Series` ou do `DataFrame` com os valores em falta substituídos por um valor à sua escolha. Vamos criar outra `Series` de exemplo para ver como isso funciona na prática.\n" + "Pode usar `isnull` para fazer isto diretamente, mas pode ser trabalhoso, especialmente se tiver muitos valores para preencher. Como esta é uma tarefa tão comum em ciência de dados, pandas oferece `fillna`, que retorna uma cópia do `Series` ou `DataFrame` com os valores em falta substituídos por um à sua escolha. Vamos criar outro exemplo de `Series` para ver como isto funciona na prática.\n" ] }, { @@ -1585,12 +1589,12 @@ "id": "CE8S7louLezV" }, "source": [ - "### Dados Categóricos (Não numéricos)\n", - "Primeiro, vamos considerar dados não numéricos. Em conjuntos de dados, temos colunas com dados categóricos. Por exemplo, Género, Verdadeiro ou Falso, etc.\n", + "### Dados Categóricos (Não Numéricos)\n", + "Primeiro, vamos considerar dados não numéricos. Nos conjuntos de dados, temos colunas com dados categóricos. Por exemplo, Género, Verdadeiro ou Falso, etc.\n", "\n", "Na maioria destes casos, substituímos os valores em falta pelo `moda` da coluna. Por exemplo, temos 100 pontos de dados, 90 indicaram Verdadeiro, 8 indicaram Falso e 2 não preencheram. Então, podemos preencher os 2 com Verdadeiro, considerando a coluna inteira.\n", "\n", - "Novamente, aqui podemos usar conhecimento do domínio. Vamos considerar um exemplo de preenchimento com a moda.\n" + "Mais uma vez, aqui podemos usar conhecimento do domínio. Vamos considerar um exemplo de preenchimento com a moda.\n" ] }, { @@ -1695,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Agora, vamos primeiro encontrar a moda antes de preencher o valor `None` com a moda.\n" + ] }, { "cell_type": "code", @@ -1730,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Então, iremos substituir None por True\n" + ] }, { "cell_type": "code", @@ -1840,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Como podemos ver, o valor nulo foi substituído. Nem é preciso dizer que poderíamos ter escrito qualquer coisa em vez de `'True'` e teria sido substituído.\n" + "Como podemos ver, o valor nulo foi substituído. Nem é preciso dizer que poderíamos ter escrito qualquer coisa no lugar de `'True'` e teria sido substituído.\n" ] }, { @@ -1850,16 +1858,16 @@ }, "source": [ "### Dados Numéricos\n", - "Agora, falando sobre dados numéricos. Aqui, temos duas formas comuns de substituir valores em falta:\n", + "Agora, falando de dados numéricos. Aqui, temos duas formas comuns de substituir valores em falta:\n", "\n", - "1. Substituir pela mediana da linha\n", - "2. Substituir pela média da linha\n", + "1. Substituir pela Mediana da linha \n", + "2. Substituir pela Média da linha \n", "\n", - "Substituímos pela mediana no caso de dados enviesados com valores extremos. Isto porque a mediana é robusta a valores extremos.\n", + "Substituímos pela Mediana no caso de dados enviesados com outliers. Isto porque a mediana é robusta a outliers.\n", "\n", - "Quando os dados estão normalizados, podemos usar a média, pois, nesse caso, a média e a mediana estarão bastante próximas.\n", + "Quando os dados estão normalizados, podemos usar a média, pois, nesse caso, a média e a mediana seriam bastante próximas.\n", "\n", - "Primeiro, vamos pegar uma coluna que segue uma distribuição normal e preencher o valor em falta com a média da coluna.\n" + "Primeiro, vamos pegar numa coluna que segue uma distribuição normal e preencher os valores em falta com a média da coluna.\n" ] }, { @@ -1999,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Preenchimento com média\n" + ] }, { "cell_type": "code", @@ -2108,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Agora vamos experimentar outro dataframe, e desta vez iremos substituir os valores None pela mediana da coluna.\n" + "Agora vamos tentar outro dataframe, e desta vez iremos substituir os valores None pela mediana da coluna.\n" ] }, { @@ -2248,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Preenchimento com mediana\n" + ] }, { "cell_type": "code", @@ -2431,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Principais pontos a reter: \n", - "1. Preencher valores em falta deve ser feito quando há poucos dados ou quando existe uma estratégia para preencher os dados em falta. \n", - "2. O conhecimento do domínio pode ser utilizado para preencher valores em falta, aproximando-os. \n", - "3. Para dados categóricos, na maioria das vezes, os valores em falta são substituídos pela moda da coluna. \n", - "4. Para dados numéricos, os valores em falta são geralmente preenchidos com a média (para conjuntos de dados normalizados) ou com a mediana das colunas. \n" + "> Principais pontos:\n", + "1. Preencher valores em falta deve ser feito quando há menos dados ou existe uma estratégia para preencher os dados em falta.\n", + "2. O conhecimento do domínio pode ser utilizado para preencher valores em falta através de aproximações.\n", + "3. Para dados categóricos, geralmente, os valores em falta são substituídos pelo modo da coluna.\n", + "4. Para dados numéricos, os valores em falta são normalmente preenchidos com a média (para conjuntos de dados normalizados) ou a mediana das colunas.\n" ] }, { @@ -2465,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "Pode **preencher para a frente** valores nulos, que consiste em usar o último valor válido para preencher um nulo:\n" + ] }, { "cell_type": "code", @@ -2505,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Pode também **preencher para trás** para propagar o próximo valor válido para trás e preencher um nulo:\n" + "Pode também **preencher retroativamente** para propagar o próximo valor válido para trás e preencher um nulo:\n" ] }, { @@ -2720,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Note que, quando um valor anterior não está disponível para preenchimento para a frente, o valor nulo permanece.\n" + "Note que, quando um valor anterior não está disponível para preenchimento, o valor nulo permanece.\n" ] }, { @@ -2753,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Pode ser criativo na forma como utiliza `fillna`. Por exemplo, vejamos novamente o `example4`, mas desta vez vamos preencher os valores em falta com a média de todos os valores no `DataFrame`:\n" + "Pode ser criativo na forma como utiliza `fillna`. Por exemplo, vamos olhar novamente para o `example4`, mas desta vez vamos preencher os valores em falta com a média de todos os valores no `DataFrame`:\n" ] }, { @@ -2844,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Note que a coluna 3 ainda está sem valores: a direção padrão é preencher os valores linha a linha.\n", + "Repare que a coluna 3 ainda está sem valores: a direção padrão é preencher os valores linha a linha.\n", "\n", - "> **Conclusão:** Existem várias formas de lidar com valores em falta nos seus conjuntos de dados. A estratégia específica que escolher (removê-los, substituí-los ou até mesmo como os substitui) deve ser orientada pelas particularidades desses dados. Desenvolverá uma melhor noção de como lidar com valores em falta à medida que trabalhar e interagir mais com conjuntos de dados.\n" + "> **Conclusão:** Existem várias formas de lidar com valores em falta nos seus conjuntos de dados. A estratégia específica que escolher (removê-los, substituí-los ou até como os substitui) deve ser orientada pelas particularidades desses dados. Desenvolverá uma melhor noção de como lidar com valores em falta à medida que trabalhar e interagir mais com conjuntos de dados.\n" ] }, { @@ -2857,7 +2871,7 @@ "source": [ "### Codificação de Dados Categóricos\n", "\n", - "Os modelos de aprendizagem automática lidam apenas com números e qualquer tipo de dados numéricos. Eles não conseguem distinguir entre um Sim e um Não, mas conseguem diferenciar entre 0 e 1. Assim, depois de preencher os valores em falta, é necessário codificar os dados categóricos para uma forma numérica que o modelo consiga compreender.\n", + "Os modelos de aprendizagem automática trabalham apenas com números e qualquer tipo de dados numéricos. Eles não conseguem distinguir entre um \"Sim\" e um \"Não\", mas conseguem diferenciar entre 0 e 1. Assim, depois de preencher os valores em falta, é necessário codificar os dados categóricos para uma forma numérica que o modelo consiga compreender.\n", "\n", "A codificação pode ser feita de duas maneiras. Vamos discuti-las a seguir.\n" ] @@ -2870,7 +2884,7 @@ "source": [ "**CODIFICAÇÃO DE ETIQUETAS**\n", "\n", - "A codificação de etiquetas consiste basicamente em converter cada categoria num número. Por exemplo, imagine que temos um conjunto de dados de passageiros de uma companhia aérea e há uma coluna que contém a classe deles entre as seguintes ['business class', 'economy class', 'first class']. Se aplicarmos a codificação de etiquetas, isso seria transformado em [0,1,2]. Vamos ver um exemplo através de código. Como iremos aprender `scikit-learn` nos próximos cadernos, não o utilizaremos aqui.\n" + "A codificação de etiquetas consiste basicamente em converter cada categoria num número. Por exemplo, imagine que temos um conjunto de dados de passageiros de avião e há uma coluna que contém a classe deles entre as seguintes ['classe executiva', 'classe económica', 'primeira classe']. Se aplicarmos a codificação de etiquetas, isto seria transformado em [0,1,2]. Vamos ver um exemplo através de código. Como iremos aprender `scikit-learn` nos próximos notebooks, não o utilizaremos aqui.\n" ] }, { @@ -2978,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Para realizar a codificação de etiquetas na 1ª coluna, temos primeiro de descrever um mapeamento de cada classe para um número, antes de substituir\n" + "Para realizar a codificação de etiquetas na 1ª coluna, temos primeiro de descrever uma correspondência de cada classe para um número, antes de substituir.\n" ] }, { @@ -3080,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Como podemos ver, o resultado corresponde ao que esperávamos. Então, quando devemos usar a codificação de rótulos? A codificação de rótulos é utilizada em um ou ambos os seguintes casos: \n", + "Como podemos ver, o resultado corresponde ao que pensávamos que iria acontecer. Então, quando usamos a codificação de etiquetas? A codificação de etiquetas é utilizada em um ou ambos os seguintes casos: \n", "1. Quando o número de categorias é grande \n", - "2. Quando as categorias estão ordenadas. \n" + "2. Quando as categorias estão em ordem. \n" ] }, { @@ -3093,9 +3107,9 @@ "source": [ "**ONE HOT ENCODING**\n", "\n", - "Outro tipo de codificação é o One Hot Encoding. Neste tipo de codificação, cada categoria da coluna é adicionada como uma coluna separada, e cada ponto de dados recebe um 0 ou um 1, dependendo de conter ou não essa categoria. Assim, se houver n categorias diferentes, n colunas serão adicionadas ao dataframe.\n", + "Outro tipo de codificação é o One Hot Encoding. Neste tipo de codificação, cada categoria da coluna é adicionada como uma coluna separada, e cada ponto de dados recebe um 0 ou um 1, dependendo de conter ou não essa categoria. Assim, se existirem n categorias diferentes, n colunas serão adicionadas ao dataframe.\n", "\n", - "Por exemplo, vejamos o mesmo exemplo da classe de avião. As categorias eram: ['business class', 'economy class', 'first class']. Portanto, se realizarmos o One Hot Encoding, as seguintes três colunas serão adicionadas ao conjunto de dados: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Por exemplo, vamos considerar o mesmo exemplo das classes de avião. As categorias eram: ['business class', 'economy class', 'first class']. Portanto, se realizarmos o One Hot Encoding, as seguintes três colunas serão adicionadas ao conjunto de dados: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3203,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "Vamos realizar one hot encoding na 1ª coluna\n" + "Vamos realizar a codificação one hot na 1ª coluna\n" ] }, { @@ -3328,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Cada coluna codificada como one-hot contém 0 ou 1, o que especifica se essa categoria existe para esse ponto de dados.\n" + "Cada coluna codificada em one-hot contém 0 ou 1, o que especifica se essa categoria existe para esse ponto de dados.\n" ] }, { @@ -3349,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Principais Conclusões: \n", - "1. A codificação é utilizada para converter dados não numéricos em dados numéricos. \n", - "2. Existem dois tipos de codificação: Codificação de Rótulos (Label encoding) e Codificação One Hot (One Hot encoding), ambas podem ser realizadas conforme as necessidades do conjunto de dados. \n" + "> Principais pontos:\n", + "1. A codificação é feita para converter dados não numéricos em dados numéricos.\n", + "2. Existem dois tipos de codificação: Codificação por rótulos (Label encoding) e Codificação One Hot, ambas podem ser realizadas conforme as necessidades do conjunto de dados.\n" ] }, { @@ -3375,7 +3389,7 @@ "source": [ "### Identificar duplicados: `duplicated`\n", "\n", - "Pode identificar facilmente valores duplicados utilizando o método `duplicated` no pandas, que devolve uma máscara Booleana indicando se uma entrada num `DataFrame` é um duplicado de uma anterior. Vamos criar outro exemplo de `DataFrame` para ver isto em ação.\n" + "Pode identificar facilmente valores duplicados utilizando o método `duplicated` em pandas, que devolve uma máscara Booleana indicando se uma entrada num `DataFrame` é um duplicado de uma anterior. Vamos criar outro exemplo de `DataFrame` para ver isto em ação.\n" ] }, { @@ -3504,8 +3518,8 @@ "id": "0eDRJD4SgRsK" }, "source": [ - "### Remoção de duplicados: `drop_duplicates`\n", - "`drop_duplicates` simplesmente devolve uma cópia dos dados em que todos os valores `duplicated` são `False`:\n" + "### Remover duplicados: `drop_duplicates`\n", + "`drop_duplicates` simplesmente retorna uma cópia dos dados em que todos os valores `duplicated` são `False`:\n" ] }, { @@ -3588,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Tanto `duplicated` como `drop_duplicates` consideram por defeito todas as colunas, mas pode especificar que analisem apenas um subconjunto de colunas no seu `DataFrame`:\n" + "Tanto `duplicated` como `drop_duplicates` consideram por defeito todas as colunas, mas pode especificar que examinem apenas um subconjunto de colunas no seu `DataFrame`:\n" ] }, { @@ -3664,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Conclusão:** Remover dados duplicados é uma parte essencial de quase todos os projetos de ciência de dados. Dados duplicados podem alterar os resultados das suas análises e fornecer resultados imprecisos!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Verificações de Qualidade de Dados do Mundo Real\n", + "\n", + "> **Objetivo de aprendizagem:** No final desta secção, deverá sentir-se confortável em detetar e corrigir problemas comuns de qualidade de dados do mundo real, incluindo valores categóricos inconsistentes, valores numéricos anormais (outliers) e entidades duplicadas com variações.\n", + "\n", + "Embora valores em falta e duplicados exatos sejam problemas comuns, conjuntos de dados do mundo real frequentemente contêm problemas mais subtis:\n", + "\n", + "1. **Valores categóricos inconsistentes**: A mesma categoria escrita de forma diferente (ex.: \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Valores numéricos anormais**: Outliers extremos que indicam erros de introdução de dados (ex.: idade = 999)\n", + "3. **Linhas quase duplicadas**: Registos que representam a mesma entidade com pequenas variações\n", + "\n", + "Vamos explorar técnicas para detetar e lidar com estes problemas.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Criar um Exemplo de Conjunto de Dados \"Sujo\"\n", + "\n", + "Primeiro, vamos criar um exemplo de conjunto de dados que contém os tipos de problemas que encontramos frequentemente em dados do mundo real:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Detetar Valores Categóricos Inconsistentes\n", + "\n", + "Repare que a coluna `country` tem várias representações para os mesmos países. Vamos identificar estas inconsistências:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Padronizar Valores Categóricos\n", + "\n", + "Podemos criar um mapeamento para padronizar estes valores. Uma abordagem simples é converter para letras minúsculas e criar um dicionário de mapeamento:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternativa: Utilizar Correspondência Fuzzy**\n", + "\n", + "Para casos mais complexos, podemos usar a correspondência de strings fuzzy com a biblioteca `rapidfuzz` para detetar automaticamente strings semelhantes:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Detetar Valores Numéricos Anormais (Outliers)\n", + "\n", + "Ao analisar a coluna `age`, encontramos alguns valores suspeitos, como 199 e -5. Vamos utilizar métodos estatísticos para identificar estes outliers.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Utilizar o Método IQR (Intervalo Interquartil)\n", + "\n", + "O método IQR é uma técnica estatística robusta para deteção de valores atípicos, sendo menos sensível a valores extremos:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Utilizar o Método Z-Score\n", + "\n", + "O método Z-score identifica valores atípicos com base nos desvios padrão em relação à média:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Tratamento de Outliers\n", + "\n", + "Uma vez detetados, os outliers podem ser tratados de várias formas:\n", + "1. **Remover**: Eliminar linhas com outliers (se forem erros)\n", + "2. **Limitar**: Substituir pelos valores limite\n", + "3. **Substituir por NaN**: Tratar como dados em falta e usar técnicas de imputação\n", + "4. **Manter**: Se forem valores extremos legítimos\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Detetar Linhas Quase Duplicadas\n", + "\n", + "Repare que o nosso conjunto de dados tem várias entradas para \"John Smith\" com valores ligeiramente diferentes. Vamos identificar possíveis duplicados com base na semelhança dos nomes.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Encontrar Quase-Duplicados com Correspondência Fuzzy\n", + "\n", + "Para uma deteção mais avançada de duplicados, podemos usar a correspondência fuzzy para encontrar nomes semelhantes:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Lidar com Duplicados\n", + "\n", + "Depois de identificados, é necessário decidir como lidar com os duplicados:\n", + "1. **Manter a primeira ocorrência**: Utilize `drop_duplicates(keep='first')`\n", + "2. **Manter a última ocorrência**: Utilize `drop_duplicates(keep='last')`\n", + "3. **Agregação de informação**: Combine informações das linhas duplicadas\n", + "4. **Revisão manual**: Marcar para revisão humana\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Resumo: Pipeline Completo de Limpeza de Dados\n", + "\n", + "Vamos juntar tudo num pipeline abrangente de limpeza:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Exercício de Desafio\n", + "\n", + "Agora é a sua vez! Abaixo está uma nova linha de dados com vários problemas de qualidade. Consegue:\n", + "\n", + "1. Identificar todos os problemas nesta linha\n", + "2. Escrever código para corrigir cada problema\n", + "3. Adicionar a linha corrigida ao conjunto de dados\n", + "\n", + "Aqui estão os dados problemáticos:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Principais Pontos\n", + "\n", + "1. **Categorias inconsistentes** são comuns em dados do mundo real. Verifique sempre os valores únicos e padronize-os utilizando mapeamentos ou correspondência aproximada.\n", + "\n", + "2. **Outliers** podem afetar significativamente a sua análise. Utilize conhecimento do domínio combinado com métodos estatísticos (IQR, Z-score) para detetá-los.\n", + "\n", + "3. **Quase duplicados** são mais difíceis de identificar do que duplicados exatos. Considere usar correspondência aproximada e normalizar os dados (converter para minúsculas, remover espaços) para identificá-los.\n", + "\n", + "4. **A limpeza de dados é iterativa**. Pode ser necessário aplicar várias técnicas e rever os resultados antes de finalizar o conjunto de dados limpo.\n", + "\n", + "5. **Documente as suas decisões**. Registe os passos de limpeza que aplicou e os motivos, pois isso é importante para a reprodutibilidade e transparência.\n", + "\n", + "> **Melhor Prática:** Mantenha sempre uma cópia dos seus dados \"sujos\" originais. Nunca substitua os ficheiros de dados fonte - crie versões limpas com convenções de nomenclatura claras, como `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.\n" + "\n---\n\n**Aviso**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, tenha em atenção que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n" ] } ], @@ -3698,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:39:33+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:53:16+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "pt" } diff --git a/translations/ro/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/ro/2-Working-With-Data/08-data-preparation/notebook.ipynb index 9307214d..534568e8 100644 --- a/translations/ro/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/ro/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,13 +8,13 @@ "source": [ "# Pregătirea Datelor\n", "\n", - "[Notebook-ul original din *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Notebook-ul original sursă din *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio de Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## Explorarea informațiilor din `DataFrame`\n", "\n", - "> **Obiectiv de învățare:** Până la finalul acestei subsecțiuni, ar trebui să te simți confortabil să găsești informații generale despre datele stocate în pandas DataFrames.\n", + "> **Obiectiv de învățare:** Până la sfârșitul acestei subsecțiuni, ar trebui să fiți confortabil în a găsi informații generale despre datele stocate în pandas DataFrames.\n", "\n", - "Odată ce ai încărcat datele în pandas, cel mai probabil acestea vor fi într-un `DataFrame`. Totuși, dacă setul de date din `DataFrame` are 60.000 de rânduri și 400 de coloane, de unde începi să înțelegi cu ce lucrezi? Din fericire, pandas oferă câteva instrumente convenabile pentru a analiza rapid informațiile generale despre un `DataFrame`, pe lângă primele și ultimele câteva rânduri.\n", + "Odată ce ați încărcat datele în pandas, cel mai probabil vor fi într-un `DataFrame`. Totuși, dacă setul de date din `DataFrame` are 60.000 de rânduri și 400 de coloane, cum începeți să înțelegeți cu ce lucrați? Din fericire, pandas oferă câteva instrumente convenabile pentru a privi rapid informațiile generale despre un `DataFrame`, pe lângă primele și ultimele câteva rânduri.\n", "\n", "Pentru a explora această funcționalitate, vom importa biblioteca Python scikit-learn și vom folosi un set de date iconic pe care fiecare specialist în date l-a văzut de sute de ori: setul de date *Iris* al biologului britanic Ronald Fisher, utilizat în lucrarea sa din 1936 \"The use of multiple measurements in taxonomic problems\":\n" ] @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Am încărcat setul de date Iris în variabila `iris_df`. Înainte de a analiza datele, ar fi util să știm câte puncte de date avem și dimensiunea generală a setului de date. Este important să ne uităm la volumul de date cu care lucrăm.\n" + "Am încărcat setul de date Iris în variabila `iris_df`. Înainte de a analiza datele, ar fi util să știm numărul de puncte de date pe care le avem și dimensiunea generală a setului de date. Este util să ne uităm la volumul de date cu care lucrăm.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Așa cum putem vedea, există patru (4) coloane. Atributul `columns` ne spune numele coloanelor și, practic, nimic altceva. Acest atribut devine important atunci când dorim să identificăm caracteristicile pe care le conține un set de date.\n" + "Așa cum putem vedea, există patru(4) coloane. Atributul `columns` ne spune numele coloanelor și, practic, nimic altceva. Acest atribut devine important atunci când dorim să identificăm caracteristicile pe care le conține un set de date.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Cantitatea de date (indicată de atributul `shape`) și numele caracteristicilor sau coloanelor (indicată de atributul `columns`) ne oferă informații despre setul de date. Acum, am dori să explorăm mai în detaliu setul de date. Funcția `DataFrame.info()` este foarte utilă pentru acest lucru.\n" + "Cantitatea de date (dată de atributul `shape`) și numele caracteristicilor sau coloanelor (dată de atributul `columns`) ne oferă informații despre setul de date. Acum, am dori să explorăm mai în detaliu setul de date. Funcția `DataFrame.info()` este foarte utilă pentru acest lucru.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Din acest punct, putem face câteva observații: \n", - "1. Tipul de date al fiecărei coloane: În acest set de date, toate valorile sunt stocate ca numere în virgulă mobilă pe 64 de biți. \n", - "2. Numărul de valori non-nule: Gestionarea valorilor nule este un pas important în pregătirea datelor. Acest aspect va fi abordat mai târziu în notebook. \n" + "De aici, putem face câteva observații:\n", + "1. Tipul de date al fiecărei coloane: În acest set de date, toate datele sunt stocate ca numere în virgulă mobilă pe 64 de biți.\n", + "2. Numărul de valori non-nule: Gestionarea valorilor nule este un pas important în pregătirea datelor. Acest aspect va fi abordat mai târziu în notebook.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Să presupunem că avem multe date numerice în setul nostru de date. Calculele statistice univariate, cum ar fi media, mediana, quartilele etc., pot fi realizate individual pe fiecare coloană. Funcția `DataFrame.describe()` ne oferă un rezumat statistic al coloanelor numerice dintr-un set de date.\n" + "Să presupunem că avem multe date numerice în setul nostru de date. Calculările statistice univariate, cum ar fi media, mediana, quartilele etc., pot fi realizate individual pentru fiecare coloană. Funcția `DataFrame.describe()` ne oferă un rezumat statistic al coloanelor numerice dintr-un set de date.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "Rezultatul de mai sus arată numărul total de puncte de date, media, abaterea standard, valoarea minimă, primul quartil (25%), mediana (50%), al treilea quartil (75%) și valoarea maximă pentru fiecare coloană.\n" + "Rezultatul de mai sus arată numărul total de puncte de date, media, deviația standard, valoarea minimă, primul quartil (25%), mediana (50%), al treilea quartil (75%) și valoarea maximă pentru fiecare coloană.\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "Cu toate funcțiile și atributele de mai sus, avem o perspectivă de ansamblu asupra setului de date. Știm câte puncte de date există, câte caracteristici sunt, tipul de date al fiecărei caracteristici și numărul de valori nenule pentru fiecare caracteristică.\n", + "Cu toate funcțiile și atributele de mai sus, am obținut o perspectivă de ansamblu asupra setului de date. Știm câte puncte de date există, câte caracteristici sunt, tipul de date al fiecărei caracteristici și numărul de valori nenule pentru fiecare caracteristică.\n", "\n", - "Acum este momentul să ne uităm la datele propriu-zise. Să vedem cum arată primele câteva rânduri (primele câteva puncte de date) ale `DataFrame`:\n" + "Acum este momentul să analizăm datele propriu-zise. Să vedem cum arată primele câteva rânduri (primele câteva puncte de date) ale `DataFrame`:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Ca rezultat aici, putem vedea cinci (5) intrări ale setului de date. Dacă ne uităm la indexul din stânga, aflăm că acestea sunt primele cinci rânduri.\n" + "Așa cum se vede în output aici, putem observa cinci (5) intrări ale setului de date. Dacă ne uităm la indexul din stânga, aflăm că acestea sunt primele cinci rânduri.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Exercițiu:\n", "\n", - "Din exemplul dat mai sus, este clar că, în mod implicit, `DataFrame.head` returnează primele cinci rânduri ale unui `DataFrame`. În celula de cod de mai jos, poți găsi o modalitate de a afișa mai mult de cinci rânduri?\n" + "Din exemplul dat mai sus, este evident că, în mod implicit, `DataFrame.head` returnează primele cinci rânduri ale unui `DataFrame`. În celula de cod de mai jos, poți găsi o modalitate de a afișa mai mult de cinci rânduri?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "O altă modalitate de a analiza datele poate fi de la sfârșit (în loc de început). Opusul lui `DataFrame.head` este `DataFrame.tail`, care returnează ultimele cinci rânduri ale unui `DataFrame`:\n" + "O altă modalitate de a privi datele poate fi de la sfârșit (în loc de început). Contrapartea lui `DataFrame.head` este `DataFrame.tail`, care returnează ultimele cinci rânduri ale unui `DataFrame`:\n" ] }, { @@ -582,7 +582,7 @@ "id": "31kBWfyLgRr3" }, "source": [ - "În practică, este util să poți examina cu ușurință primele câteva rânduri sau ultimele câteva rânduri ale unui `DataFrame`, mai ales atunci când cauți valori anormale în seturi de date ordonate.\n", + "În practică, este util să poți examina cu ușurință primele câteva rânduri sau ultimele câteva rânduri ale unui `DataFrame`, mai ales atunci când cauți valori extreme în seturi de date ordonate.\n", "\n", "Toate funcțiile și atributele prezentate mai sus, cu ajutorul exemplelor de cod, ne ajută să obținem o perspectivă asupra datelor.\n", "\n", @@ -596,17 +596,17 @@ }, "source": [ "### Date Lipsă\n", - "Să explorăm datele lipsă. Datele lipsă apar atunci când nu există nicio valoare stocată în unele dintre coloane.\n", + "Să explorăm datele lipsă. Datele lipsă apar atunci când nu este stocată nicio valoare în unele dintre coloane.\n", "\n", - "Să luăm un exemplu: să presupunem că cineva este preocupat de greutatea sa și nu completează câmpul pentru greutate într-un sondaj. În acest caz, valoarea greutății pentru acea persoană va fi lipsă.\n", + "Să luăm un exemplu: să presupunem că cineva este preocupat de greutatea sa și nu completează câmpul de greutate într-un sondaj. În acest caz, valoarea greutății pentru acea persoană va fi lipsă.\n", "\n", "De cele mai multe ori, în seturile de date din lumea reală, apar valori lipsă.\n", "\n", "**Cum gestionează Pandas datele lipsă**\n", "\n", - "Pandas gestionează valorile lipsă în două moduri. Primul mod, pe care l-ai văzut deja în secțiunile anterioare, este `NaN`, sau Not a Number. Aceasta este, de fapt, o valoare specială care face parte din specificația IEEE pentru numere în virgulă mobilă și este utilizată doar pentru a indica valori lipsă de tip float.\n", + "Pandas gestionează valorile lipsă în două moduri. Primul, pe care l-ai văzut deja în secțiunile anterioare, este `NaN`, sau Not a Number. Acesta este, de fapt, o valoare specială care face parte din specificația IEEE pentru numere în virgulă mobilă și este utilizată doar pentru a indica valori lipsă de tip float.\n", "\n", - "Pentru valorile lipsă care nu sunt de tip float, pandas folosește obiectul `None` din Python. Deși poate părea confuz să întâlnești două tipuri diferite de valori care exprimă, în esență, același lucru, există motive programatice solide pentru această alegere de design, iar, în practică, această abordare permite pandas să ofere un compromis bun pentru marea majoritate a cazurilor. Cu toate acestea, atât `None`, cât și `NaN` au restricții de care trebuie să ții cont în ceea ce privește modul în care pot fi utilizate.\n" + "Pentru valorile lipsă care nu sunt de tip float, pandas folosește obiectul `None` din Python. Deși poate părea confuz să întâlnești două tipuri diferite de valori care indică, în esență, același lucru, există motive programatice solide pentru această alegere de design, iar în practică, această abordare permite pandas să ofere un compromis bun pentru marea majoritate a cazurilor. Cu toate acestea, atât `None`, cât și `NaN` au restricții de care trebuie să fii conștient în ceea ce privește modul în care pot fi utilizate.\n" ] }, { @@ -616,7 +616,7 @@ }, "source": [ "### `None`: date lipsă non-float\n", - "Deoarece `None` provine din Python, acesta nu poate fi utilizat în array-urile NumPy și pandas care nu au tipul de date `'object'`. Rețineți că array-urile NumPy (și structurile de date din pandas) pot conține un singur tip de date. Aceasta este ceea ce le oferă o putere extraordinară pentru lucrul cu date la scară largă și pentru calcule, dar le limitează și flexibilitatea. Astfel de array-uri trebuie să fie convertite la „cel mai mic numitor comun,” adică tipul de date care poate cuprinde totul din array. Când `None` este prezent în array, înseamnă că lucrați cu obiecte Python.\n", + "Deoarece `None` provine din Python, nu poate fi utilizat în array-uri NumPy și pandas care nu au tipul de date `'object'`. Rețineți că array-urile NumPy (și structurile de date din pandas) pot conține doar un singur tip de date. Acesta este motivul pentru care sunt extrem de puternice pentru lucrul cu date la scară largă și pentru calcule, dar această caracteristică le limitează flexibilitatea. Astfel de array-uri trebuie să fie convertite la „cel mai mic numitor comun”, adică tipul de date care poate cuprinde totul în array. Când `None` se află în array, înseamnă că lucrați cu obiecte Python.\n", "\n", "Pentru a vedea acest lucru în practică, luați în considerare următorul exemplu de array (observați `dtype` pentru acesta):\n" ] @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Realitatea tipurilor de date promovate vine cu două efecte secundare. În primul rând, operațiunile vor fi efectuate la nivelul codului Python interpretat, mai degrabă decât la nivelul codului compilat NumPy. Practic, acest lucru înseamnă că orice operațiuni care implică `Series` sau `DataFrames` ce conțin `None` vor fi mai lente. Deși probabil nu vei observa această scădere a performanței, pentru seturi de date mari ar putea deveni o problemă.\n", + "Realitatea tipurilor de date convertite în sus vine cu două efecte secundare. În primul rând, operațiunile vor fi efectuate la nivelul codului Python interpretat, mai degrabă decât al codului compilat NumPy. Practic, aceasta înseamnă că orice operațiuni care implică `Series` sau `DataFrames` ce conțin `None` vor fi mai lente. Deși probabil nu vei observa această scădere de performanță, pentru seturi de date mari ar putea deveni o problemă.\n", "\n", - "Al doilea efect secundar derivă din primul. Deoarece `None` trage, practic, `Series` sau `DataFrame`s înapoi în lumea Python-ului simplu, utilizarea agregărilor NumPy/pandas precum `sum()` sau `min()` pe array-uri care conțin o valoare ``None`` va produce, în general, o eroare:\n" + "Al doilea efect secundar derivă din primul. Deoarece `None` trage practic `Series` sau `DataFrame`s înapoi în lumea Python-ului standard, utilizarea agregărilor NumPy/pandas precum `sum()` sau `min()` pe array-uri care conțin o valoare ``None`` va produce, în general, o eroare:\n" ] }, { @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**Concluzie principală**: Adunarea (și alte operații) între numere întregi și valori `None` este nedefinită, ceea ce poate limita ceea ce poți face cu seturi de date care le conțin.\n" + ] }, { "cell_type": "markdown", @@ -707,7 +709,7 @@ "source": [ "### `NaN`: valori float lipsă\n", "\n", - "Spre deosebire de `None`, NumPy (și, prin urmare, pandas) acceptă `NaN` pentru operațiunile sale rapide, vectorizate și ufuncs. Vestea proastă este că orice operație aritmetică efectuată pe `NaN` va rezulta întotdeauna în `NaN`. De exemplu:\n" + "Spre deosebire de `None`, NumPy (și, prin urmare, pandas) acceptă `NaN` pentru operațiile sale rapide, vectorizate și ufuncs. Vestea proastă este că orice operație aritmetică efectuată pe `NaN` va avea întotdeauna ca rezultat `NaN`. De exemplu:\n" ] }, { @@ -770,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Vestea bună: agregările care rulează pe șiruri cu `NaN` în ele nu generează erori. Vestea proastă: rezultatele nu sunt uniform utile:\n" + "Vestea bună: agregările care rulează pe array-uri ce conțin `NaN` nu generează erori. Vestea proastă: rezultatele nu sunt uniform utile:\n" ] }, { @@ -806,7 +808,9 @@ "metadata": { "id": "nhlnNJT7gRr_" }, - "source": [] + "source": [ + "### Exercițiu:\n" + ] }, { "cell_type": "code", @@ -826,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "Amintește-ți: `NaN` este doar pentru valori lipsă de tip floating-point; nu există un echivalent `NaN` pentru întregi, șiruri de caractere sau valori Booleene.\n" + ] }, { "cell_type": "markdown", @@ -836,7 +842,7 @@ "source": [ "### `NaN` și `None`: valori nule în pandas\n", "\n", - "Deși `NaN` și `None` pot avea comportamente ușor diferite, pandas este totuși conceput să le gestioneze interschimbabil. Pentru a înțelege ce vrem să spunem, luați în considerare un `Series` de numere întregi:\n" + "Deși `NaN` și `None` pot avea comportamente ușor diferite, pandas este totuși conceput pentru a le gestiona interschimbabil. Pentru a înțelege ce vrem să spunem, luați în considerare un `Series` de numere întregi:\n" ] }, { @@ -875,7 +881,9 @@ "metadata": { "id": "WklCzqb8gRsB" }, - "source": [] + "source": [ + "### Exercițiu:\n" + ] }, { "cell_type": "code", @@ -898,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "În procesul de conversie a tipurilor de date pentru a stabili omogenitatea datelor în `Series` și `DataFrame`-uri, pandas va schimba fără probleme valorile lipsă între `None` și `NaN`. Datorită acestei caracteristici de design, poate fi util să consideri `None` și `NaN` ca două variante diferite ale valorii \"null\" în pandas. De fapt, unele dintre metodele de bază pe care le vei folosi pentru a gestiona valorile lipsă în pandas reflectă această idee în denumirile lor:\n", + "În procesul de conversie a tipurilor de date pentru a stabili omogenitatea datelor în `Series` și `DataFrame`, pandas va schimba cu ușurință valorile lipsă între `None` și `NaN`. Datorită acestei caracteristici de design, poate fi util să considerăm `None` și `NaN` ca două variante diferite de \"null\" în pandas. De fapt, unele dintre metodele de bază pe care le vei folosi pentru a gestiona valorile lipsă în pandas reflectă această idee în denumirile lor:\n", "\n", - "- `isnull()`: Generează o mască booleană care indică valorile lipsă\n", + "- `isnull()`: Generează o mască Boolean care indică valorile lipsă\n", "- `notnull()`: Opusul lui `isnull()`\n", "- `dropna()`: Returnează o versiune filtrată a datelor\n", - "- `fillna()`: Returnează o copie a datelor cu valorile lipsă completate sau imputate\n", + "- `fillna()`: Returnează o copie a datelor cu valorile lipsă completate sau estimate\n", "\n", - "Acestea sunt metode importante pe care trebuie să le stăpânești și cu care să te familiarizezi, așa că haide să le analizăm pe fiecare în detaliu.\n" + "Acestea sunt metode importante pe care trebuie să le stăpânești și să te familiarizezi cu ele, așa că haide să le analizăm pe fiecare în detaliu.\n" ] }, { @@ -917,7 +925,7 @@ "### Detectarea valorilor nule\n", "\n", "Acum că am înțeles importanța valorilor lipsă, trebuie să le detectăm în setul nostru de date înainte de a le gestiona. \n", - "Atât `isnull()`, cât și `notnull()` sunt metodele principale pentru detectarea datelor nule. Ambele returnează măști booleene aplicate asupra datelor tale.\n" + "Atât `isnull()` cât și `notnull()` sunt metodele principale pentru detectarea datelor nule. Ambele returnează măști booleene pentru datele tale.\n" ] }, { @@ -970,9 +978,9 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Privește cu atenție rezultatul. Te surprinde ceva? Deși `0` este un nul aritmetic, este totuși un număr întreg valid, iar pandas îl tratează ca atare. `''` este puțin mai subtil. Deși l-am folosit în Secțiunea 1 pentru a reprezenta o valoare de șir de caractere gol, este totuși un obiect de tip șir de caractere și nu o reprezentare a valorii nule din perspectiva pandas.\n", + "Privește cu atenție rezultatul. Te surprinde ceva? Deși `0` este considerat un nul aritmetic, este totuși un număr întreg valid, iar pandas îl tratează ca atare. `''` este puțin mai subtil. Deși l-am folosit în Secțiunea 1 pentru a reprezenta o valoare de șir gol, este totuși un obiect de tip șir și nu o reprezentare a nulului din perspectiva pandas.\n", "\n", - "Acum, să schimbăm perspectiva și să folosim aceste metode într-un mod mai apropiat de cum le vei utiliza în practică. Poți folosi măști booleene direct ca index pentru un ``Series`` sau un ``DataFrame``, ceea ce poate fi util atunci când încerci să lucrezi cu valori lipsă (sau prezente) izolate.\n", + "Acum, să schimbăm perspectiva și să utilizăm aceste metode într-un mod mai apropiat de cum le vei folosi în practică. Poți folosi măști booleene direct ca index pentru un ``Series`` sau ``DataFrame``, ceea ce poate fi util atunci când încerci să lucrezi cu valori lipsă (sau prezente) izolate.\n", "\n", "Dacă dorim numărul total de valori lipsă, putem pur și simplu să facem o sumă peste masca produsă de metoda `isnull()`.\n" ] @@ -1008,7 +1016,9 @@ "metadata": { "id": "PlBqEo3mgRsC" }, - "source": [] + "source": [ + "### Exercițiu:\n" + ] }, { "cell_type": "code", @@ -1030,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Concluzie principală**: Atât metodele `isnull()`, cât și `notnull()` produc rezultate similare atunci când le utilizați în DataFrame-uri: ele afișează rezultatele și indexul acelor rezultate, ceea ce vă va ajuta enorm în lucrul cu datele dumneavoastră.\n" + "**Concluzie principală**: Atât metodele `isnull()` cât și `notnull()` produc rezultate similare atunci când le utilizați în DataFrame-uri: ele afișează rezultatele și indexul acelor rezultate, ceea ce vă va ajuta enorm în procesul de analiză a datelor.\n" ] }, { @@ -1041,18 +1051,18 @@ "source": [ "### Gestionarea datelor lipsă\n", "\n", - "> **Obiectiv de învățare:** Până la finalul acestei subsecțiuni, ar trebui să știi cum și când să înlocuiești sau să elimini valorile nule din DataFrame-uri.\n", + "> **Obiectiv de învățare:** La finalul acestei subsecțiuni, ar trebui să știi cum și când să înlocuiești sau să elimini valorile nule din DataFrames.\n", "\n", - "Modelele de Machine Learning nu pot gestiona singure datele lipsă. Așadar, înainte de a introduce datele în model, trebuie să rezolvăm aceste valori lipsă.\n", + "Modelele de Machine Learning nu pot gestiona singure datele lipsă. Așadar, înainte de a introduce datele în model, trebuie să ne ocupăm de aceste valori lipsă.\n", "\n", - "Modul în care sunt gestionate datele lipsă implică compromisuri subtile, care pot influența analiza finală și rezultatele din lumea reală.\n", + "Modul în care sunt gestionate datele lipsă implică compromisuri subtile, poate influența analiza finală și rezultatele din lumea reală.\n", "\n", "Există în principal două moduri de a gestiona datele lipsă:\n", "\n", - "1. Eliminarea rândului care conține valoarea lipsă \n", - "2. Înlocuirea valorii lipsă cu o altă valoare \n", + "1. Eliminarea rândului care conține valoarea lipsă\n", + "2. Înlocuirea valorii lipsă cu o altă valoare\n", "\n", - "Vom discuta în detaliu ambele metode, împreună cu avantajele și dezavantajele lor.\n" + "Vom discuta ambele metode și avantajele și dezavantajele acestora în detaliu.\n" ] }, { @@ -1063,11 +1073,11 @@ "source": [ "### Eliminarea valorilor nule\n", "\n", - "Cantitatea de date pe care o transmitem modelului nostru are un efect direct asupra performanței acestuia. Eliminarea valorilor nule înseamnă că reducem numărul de puncte de date și, prin urmare, dimensiunea setului de date. Așadar, este recomandat să eliminăm rândurile cu valori nule atunci când setul de date este destul de mare.\n", + "Cantitatea de date pe care o transmitem modelului nostru are un efect direct asupra performanței acestuia. Eliminarea valorilor nule înseamnă că reducem numărul de puncte de date și, prin urmare, dimensiunea setului de date. Astfel, este recomandabil să eliminăm rândurile cu valori nule atunci când setul de date este destul de mare.\n", "\n", - "O altă situație poate fi aceea în care un anumit rând sau o anumită coloană are multe valori lipsă. În acest caz, acestea pot fi eliminate, deoarece nu ar adăuga prea multă valoare analizei noastre, având în vedere că majoritatea datelor lipsesc pentru acel rând/coloană.\n", + "O altă situație poate fi aceea în care un anumit rând sau o anumită coloană are multe valori lipsă. În acest caz, acestea pot fi eliminate deoarece nu ar adăuga prea multă valoare analizei noastre, având în vedere că majoritatea datelor lipsesc pentru acel rând/coloană.\n", "\n", - "Dincolo de identificarea valorilor lipsă, pandas oferă un mijloc convenabil de a elimina valorile nule din `Series` și `DataFrame`-uri. Pentru a vedea acest lucru în practică, să revenim la `example3`. Funcția `DataFrame.dropna()` ajută la eliminarea rândurilor cu valori nule.\n" + "Dincolo de identificarea valorilor lipsă, pandas oferă un mijloc convenabil de a elimina valorile nule din `Series` și `DataFrame`. Pentru a vedea acest lucru în practică, să revenim la `example3`. Funcția `DataFrame.dropna()` ajută la eliminarea rândurilor cu valori nule.\n" ] }, { @@ -1106,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "Rețineți că acest lucru ar trebui să arate ca rezultatul din `example3[example3.notnull()]`. Diferența aici este că, în loc să indexeze doar valorile mascate, `dropna` a eliminat acele valori lipsă din `Series` `example3`.\n", + "Observați că acest lucru ar trebui să arate ca rezultatul dvs. de la `example3[example3.notnull()]`. Diferența aici este că, în loc să indexeze doar valorile mascate, `dropna` a eliminat acele valori lipsă din `Series` `example3`.\n", "\n", - "Deoarece DataFrame-urile au două dimensiuni, acestea oferă mai multe opțiuni pentru eliminarea datelor.\n" + "Deoarece DataFrames au două dimensiuni, acestea oferă mai multe opțiuni pentru eliminarea datelor.\n" ] }, { @@ -1200,7 +1210,7 @@ "source": [ "(Ai observat că pandas a convertit două dintre coloane în tipul float pentru a acomoda valorile `NaN`?)\n", "\n", - "Nu poți elimina o singură valoare dintr-un `DataFrame`, așa că trebuie să elimini rânduri sau coloane întregi. În funcție de ceea ce faci, s-ar putea să vrei să alegi una dintre aceste opțiuni, iar pandas îți oferă posibilitatea de a face ambele. Deoarece, în știința datelor, coloanele reprezintă, în general, variabile, iar rândurile reprezintă observații, este mai probabil să elimini rânduri de date; setarea implicită pentru `dropna()` este să elimine toate rândurile care conțin orice valori nule:\n" + "Nu poți elimina o singură valoare dintr-un `DataFrame`, așa că trebuie să elimini rânduri sau coloane întregi. În funcție de ceea ce faci, s-ar putea să vrei să alegi una sau alta, iar pandas îți oferă opțiuni pentru ambele. Deoarece, în știința datelor, coloanele reprezintă de obicei variabile, iar rândurile reprezintă observații, este mai probabil să elimini rânduri de date; setarea implicită pentru `dropna()` este să elimine toate rândurile care conțin orice valori nule:\n" ] }, { @@ -1352,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Reține că acest lucru poate elimina o cantitate mare de date pe care ai putea dori să le păstrezi, mai ales în seturi de date mai mici. Ce se întâmplă dacă vrei să elimini doar rândurile sau coloanele care conțin mai multe sau chiar toate valorile nule? Poți specifica aceste setări în `dropna` folosind parametrii `how` și `thresh`.\n", + "Observați că acest lucru poate elimina o cantitate mare de date pe care poate doriți să le păstrați, mai ales în seturi de date mai mici. Ce se întâmplă dacă doriți să eliminați doar rândurile sau coloanele care conțin mai multe sau chiar toate valorile nule? Puteți specifica aceste setări în `dropna` folosind parametrii `how` și `thresh`.\n", "\n", - "Implicit, `how='any'` (dacă vrei să verifici singur sau să vezi ce alți parametri are metoda, rulează `example4.dropna?` într-o celulă de cod). Alternativ, ai putea specifica `how='all'` pentru a elimina doar rândurile sau coloanele care conțin toate valorile nule. Să extindem exemplul nostru de `DataFrame` pentru a vedea acest lucru în acțiune în exercițiul următor.\n" + "Implicit, `how='any'` (dacă doriți să verificați singuri sau să vedeți ce alți parametri are metoda, rulați `example4.dropna?` într-o celulă de cod). Alternativ, puteți specifica `how='all'` pentru a elimina doar rândurile sau coloanele care conțin toate valorile nule. Haideți să extindem exemplul nostru de `DataFrame` pentru a vedea acest lucru în acțiune în următorul exercițiu.\n" ] }, { @@ -1448,9 +1458,9 @@ "source": [ "> Puncte cheie: \n", "1. Eliminarea valorilor nule este o idee bună doar dacă setul de date este suficient de mare. \n", - "2. Rândurile sau coloanele întregi pot fi eliminate dacă majoritatea datelor lor lipsesc. \n", + "2. Rândurile sau coloanele complete pot fi eliminate dacă au majoritatea datelor lipsă. \n", "3. Metoda `DataFrame.dropna(axis=)` ajută la eliminarea valorilor nule. Argumentul `axis` indică dacă trebuie eliminate rândurile sau coloanele. \n", - "4. Se poate utiliza și argumentul `how`. Implicit, acesta este setat la `any`. Astfel, elimină doar acele rânduri/coloane care conțin orice valoare nulă. Poate fi setat la `all` pentru a specifica faptul că vom elimina doar acele rânduri/coloane unde toate valorile sunt nule. \n" + "4. Se poate folosi și argumentul `how`. Implicit, acesta este setat la `any`. Astfel, elimină doar acele rânduri/coloane care conțin orice valoare nulă. Poate fi setat la `all` pentru a specifica că vom elimina doar acele rânduri/coloane unde toate valorile sunt nule. \n" ] }, { @@ -1458,7 +1468,9 @@ "metadata": { "id": "oXXSfQFHgRsF" }, - "source": [] + "source": [ + "### Exercițiu:\n" + ] }, { "cell_type": "code", @@ -1480,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "Parametrul `thresh` îți oferă un control mai detaliat: setezi numărul de valori *nenule* pe care un rând sau o coloană trebuie să le aibă pentru a fi păstrate:\n" + "Parametrul `thresh` îți oferă un control mai detaliat: setezi numărul de valori *non-null* pe care o linie sau o coloană trebuie să le aibă pentru a fi păstrată:\n" ] }, { @@ -1554,7 +1566,9 @@ "metadata": { "id": "fmSFnzZegRsG" }, - "source": [] + "source": [ + "Aici, prima și ultima linie au fost eliminate, deoarece conțin doar două valori nenule.\n" + ] }, { "cell_type": "markdown", @@ -1580,7 +1594,7 @@ "\n", "În majoritatea acestor cazuri, înlocuim valorile lipsă cu `moda` coloanei. Să presupunem că avem 100 de puncte de date, dintre care 90 au răspuns Adevărat, 8 au răspuns Fals și 2 nu au completat. Atunci, putem completa cele 2 cu Adevărat, luând în considerare întreaga coloană.\n", "\n", - "Din nou, aici putem folosi cunoștințele de domeniu. Să luăm în considerare un exemplu de completare cu moda.\n" + "Din nou, aici putem folosi cunoștințele de domeniu. Să luăm un exemplu de completare cu moda.\n" ] }, { @@ -1685,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Acum, să găsim mai întâi moda înainte de a completa valoarea `None` cu moda.\n" + ] }, { "cell_type": "code", @@ -1720,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Deci, vom înlocui None cu True\n" + ] }, { "cell_type": "code", @@ -1845,9 +1863,9 @@ "1. Înlocuire cu Mediana rândului\n", "2. Înlocuire cu Media rândului\n", "\n", - "Înlocuim cu Mediana în cazul datelor distorsionate cu valori extreme. Acest lucru se datorează faptului că mediana este robustă la valori extreme.\n", + "Înlocuim cu Mediana în cazul datelor distorsionate cu valori extreme. Acest lucru se datorează faptului că mediana este rezistentă la valori extreme.\n", "\n", - "Când datele sunt normalizate, putem folosi media, deoarece, în acest caz, media și mediana ar fi destul de apropiate.\n", + "Când datele sunt normalizate, putem folosi media, deoarece în acest caz, media și mediana ar fi destul de apropiate.\n", "\n", "Mai întâi, să luăm o coloană care este distribuită normal și să completăm valoarea lipsă cu media coloanei.\n" ] @@ -1989,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Completare cu medie\n" + ] }, { "cell_type": "code", @@ -2238,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Completare cu mediană\n" + ] }, { "cell_type": "code", @@ -2338,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Așa cum putem observa, valoarea NaN a fost înlocuită cu mediana coloanei\n" + "Așa cum putem vedea, valoarea NaN a fost înlocuită cu mediana coloanei\n" ] }, { @@ -2380,7 +2402,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "Puteți completa toate intrările nule cu o singură valoare, cum ar fi `0`:\n" + "Poți completa toate intrările nule cu o singură valoare, cum ar fi `0`:\n" ] }, { @@ -2421,9 +2443,9 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Idei principale:\n", - "1. Completarea valorilor lipsă ar trebui realizată fie atunci când există mai puține date, fie când există o strategie pentru a completa datele lipsă.\n", - "2. Cunoștințele din domeniu pot fi utilizate pentru a completa valorile lipsă prin aproximare.\n", + "> Concluzii principale:\n", + "1. Completarea valorilor lipsă ar trebui făcută fie atunci când există mai puține date, fie când există o strategie pentru completarea datelor lipsă.\n", + "2. Cunoștințele din domeniu pot fi utilizate pentru a completa valorile lipsă prin aproximarea acestora.\n", "3. Pentru datele categorice, de obicei, valorile lipsă sunt înlocuite cu moda coloanei.\n", "4. Pentru datele numerice, valorile lipsă sunt, de regulă, completate cu media (pentru seturi de date normalizate) sau cu mediana coloanelor.\n" ] @@ -2433,7 +2455,9 @@ "metadata": { "id": "FI9MmqFJgRsH" }, - "source": [] + "source": [ + "### Exercițiu:\n" + ] }, { "cell_type": "code", @@ -2453,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "Poți **completa înainte** valorile nule, adică să folosești ultima valoare validă pentru a completa o valoare nulă:\n" + ] }, { "cell_type": "code", @@ -2493,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Puteți, de asemenea, să **completați înapoi** pentru a propaga următoarea valoare validă înapoi pentru a umple un null:\n" + "De asemenea, puteți **completa retroactiv** pentru a propaga următoarea valoare validă înapoi pentru a umple un null:\n" ] }, { @@ -2535,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "Așa cum ai putea ghici, acest lucru funcționează la fel cu DataFrames, dar poți specifica și un `axis` de-a lungul căruia să completezi valorile nule:\n" + "Așa cum probabil ghicești, acest lucru funcționează la fel și cu DataFrames, dar poți specifica și un `axis` de-a lungul căruia să completezi valorile nule:\n" ] }, { @@ -2708,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Rețineți că, atunci când o valoare anterioară nu este disponibilă pentru completarea înainte, valoarea nulă rămâne.\n" + "Observați că atunci când o valoare anterioară nu este disponibilă pentru completarea în avans, valoarea nulă rămâne.\n" ] }, { @@ -2716,7 +2742,9 @@ "metadata": { "id": "eeAoOU0RgRsJ" }, - "source": [] + "source": [ + "### Exercițiu:\n" + ] }, { "cell_type": "code", @@ -2739,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Poți fi creativ în modul în care folosești `fillna`. De exemplu, să ne uităm din nou la `example4`, dar de data aceasta să completăm valorile lipsă cu media tuturor valorilor din `DataFrame`:\n" + "Poți fi creativ în modul în care utilizezi `fillna`. De exemplu, să ne uităm din nou la `example4`, dar de data aceasta să completăm valorile lipsă cu media tuturor valorilor din `DataFrame`:\n" ] }, { @@ -2830,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Observați că coloana 3 este încă fără valoare: direcția implicită este de a completa valorile pe rânduri.\n", + "Observați că coloana 3 este încă fără valoare: direcția implicită este de a completa valorile pe rând.\n", "\n", - "> **Concluzie:** Există multiple modalități de a gestiona valorile lipsă în seturile de date. Strategia specifică pe care o utilizați (eliminarea lor, înlocuirea lor sau chiar modul în care le înlocuiți) ar trebui să fie dictată de particularitățile acelui set de date. Veți dezvolta un simț mai bun pentru a gestiona valorile lipsă pe măsură ce lucrați și interacționați mai mult cu seturile de date.\n" + "> **Concluzie:** Există mai multe modalități de a gestiona valorile lipsă în seturile de date. Strategia specifică pe care o utilizați (eliminarea lor, înlocuirea lor sau chiar modul în care le înlocuiți) ar trebui să fie dictată de particularitățile acelui set de date. Veți dezvolta o înțelegere mai bună a modului de a gestiona valorile lipsă pe măsură ce lucrați și interacționați mai mult cu seturile de date.\n" ] }, { @@ -2843,7 +2871,7 @@ "source": [ "### Codificarea Datelor Categoriale\n", "\n", - "Modelele de învățare automată lucrează doar cu numere și orice formă de date numerice. Ele nu vor putea face diferența între un Da și un Nu, dar vor putea distinge între 0 și 1. Așadar, după completarea valorilor lipsă, trebuie să codificăm datele categoriale într-o formă numerică pentru ca modelul să le poată înțelege.\n", + "Modelele de învățare automată lucrează doar cu numere și orice formă de date numerice. Ele nu pot face diferența între un Da și un Nu, dar pot distinge între 0 și 1. Așadar, după completarea valorilor lipsă, trebuie să codificăm datele categoriale într-o formă numerică pentru ca modelul să le poată înțelege.\n", "\n", "Codificarea poate fi realizată în două moduri. Vom discuta despre acestea în continuare.\n" ] @@ -2856,7 +2884,7 @@ "source": [ "**ENCODAREA ETICHETELOR**\n", "\n", - "Encodarea etichetelor presupune transformarea fiecărei categorii într-un număr. De exemplu, să presupunem că avem un set de date cu pasageri de avion și există o coloană care conține clasa lor dintre următoarele ['clasa business', 'clasa economică', 'clasa întâi']. Dacă se aplică encodarea etichetelor, aceasta ar fi transformată în [0,1,2]. Să vedem un exemplu prin cod. Deoarece vom învăța `scikit-learn` în caietele viitoare, nu îl vom folosi aici.\n" + "Encodarea etichetelor presupune, în esență, convertirea fiecărei categorii într-un număr. De exemplu, să presupunem că avem un set de date cu pasageri de avion și există o coloană care conține clasa lor, dintre următoarele ['business class', 'economy class', 'first class']. Dacă aplicăm encodarea etichetelor, aceasta va fi transformată în [0, 1, 2]. Să vedem un exemplu prin cod. Deoarece vom învăța despre `scikit-learn` în caietele viitoare, nu îl vom folosi aici.\n" ] }, { @@ -2964,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Pentru a efectua codificarea etichetelor pe prima coloană, trebuie mai întâi să descriem o mapare de la fiecare clasă la un număr, înainte de a înlocui\n" + "Pentru a efectua codificarea etichetelor pe prima coloană, trebuie mai întâi să descriem o mapare de la fiecare clasă la un număr, înainte de înlocuire.\n" ] }, { @@ -3066,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Așa cum putem observa, rezultatul corespunde cu ceea ce ne așteptam să se întâmple. Deci, când folosim codificarea etichetelor? Codificarea etichetelor este utilizată în unul sau ambele dintre următoarele cazuri: \n", - "1. Când numărul de categorii este mare \n", - "2. Când categoriile sunt ordonate. \n" + "Așa cum putem observa, rezultatul corespunde cu ceea ce ne așteptam să se întâmple. Deci, când folosim codificarea etichetelor? Codificarea etichetelor este utilizată în unul sau ambele dintre următoarele cazuri:\n", + "1. Când numărul de categorii este mare\n", + "2. Când categoriile sunt ordonate.\n" ] }, { @@ -3077,11 +3105,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**CODIFICARE ONE HOT**\n", + "**ONE HOT ENCODING**\n", "\n", - "Un alt tip de codificare este Codificarea One Hot. În acest tip de codificare, fiecare categorie a coloanei este adăugată ca o coloană separată, iar fiecare punct de date va primi un 0 sau un 1, în funcție de dacă conține sau nu acea categorie. Astfel, dacă există n categorii diferite, n coloane vor fi adăugate la dataframe.\n", + "Un alt tip de codificare este One Hot Encoding. În acest tip de codificare, fiecare categorie a coloanei este adăugată ca o coloană separată, iar fiecare punct de date va primi 0 sau 1, în funcție de faptul dacă conține sau nu acea categorie. Astfel, dacă există n categorii diferite, n coloane vor fi adăugate la dataframe.\n", "\n", - "De exemplu, să luăm același exemplu cu clasele de avion. Categoriile erau: ['business class', 'economy class', 'first class']. Așadar, dacă aplicăm codificarea one hot, următoarele trei coloane vor fi adăugate la setul de date: ['class_business class', 'class_economy class', 'class_first class'].\n" + "De exemplu, să luăm același exemplu cu clasele de avion. Categoriile erau: ['business class', 'economy class', 'first class']. Deci, dacă aplicăm One Hot Encoding, următoarele trei coloane vor fi adăugate la setul de date: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3323,7 +3351,7 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "Când folosim one hot encoding? One hot encoding este utilizat în unul sau ambele dintre următoarele cazuri:\n", + "Când folosim codificarea one hot? Codificarea one hot este utilizată în unul sau ambele dintre următoarele cazuri:\n", "\n", "1. Când numărul de categorii și dimensiunea setului de date sunt mai mici.\n", "2. Când categoriile nu urmează o ordine specifică.\n" @@ -3335,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Aspecte esențiale:\n", + "> Concluzii principale:\n", "1. Codificarea se face pentru a transforma datele non-numerice în date numerice.\n", - "2. Există două tipuri de codificare: Codificarea etichetelor și Codificarea One Hot, ambele putând fi realizate în funcție de cerințele setului de date.\n" + "2. Există două tipuri de codificare: Codificare prin etichetare și Codificare One Hot, ambele putând fi realizate în funcție de cerințele setului de date.\n" ] }, { @@ -3348,9 +3376,9 @@ "source": [ "## Eliminarea datelor duplicate\n", "\n", - "> **Obiectiv de învățare:** La finalul acestei subsecțiuni, ar trebui să te simți confortabil să identifici și să elimini valorile duplicate din DataFrames.\n", + "> **Obiectiv de învățare:** Până la sfârșitul acestei subsecțiuni, ar trebui să fiți confortabil cu identificarea și eliminarea valorilor duplicate din DataFrames.\n", "\n", - "Pe lângă datele lipsă, vei întâlni adesea date duplicate în seturile de date din lumea reală. Din fericire, pandas oferă o modalitate simplă de a detecta și elimina înregistrările duplicate.\n" + "Pe lângă datele lipsă, veți întâlni adesea date duplicate în seturile de date din lumea reală. Din fericire, pandas oferă o modalitate simplă de a detecta și elimina înregistrările duplicate.\n" ] }, { @@ -3361,7 +3389,7 @@ "source": [ "### Identificarea duplicatelor: `duplicated`\n", "\n", - "Poți identifica cu ușurință valorile duplicate folosind metoda `duplicated` din pandas, care returnează o mască Boolean ce indică dacă o intrare într-un `DataFrame` este un duplicat al uneia anterioare. Hai să creăm un alt exemplu de `DataFrame` pentru a vedea cum funcționează acest lucru.\n" + "Puteți identifica cu ușurință valorile duplicate utilizând metoda `duplicated` din pandas, care returnează o mască Boolean ce indică dacă o intrare într-un `DataFrame` este un duplicat al uneia anterioare. Să creăm un alt exemplu de `DataFrame` pentru a vedea acest lucru în acțiune.\n" ] }, { @@ -3574,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Atât `duplicated`, cât și `drop_duplicates` iau în considerare implicit toate coloanele, dar puteți specifica să examineze doar un subset de coloane din `DataFrame`-ul dvs.:\n" + "Atât `duplicated`, cât și `drop_duplicates` consideră implicit toate coloanele, dar puteți specifica să examineze doar un subset de coloane din `DataFrame`-ul dvs.:\n" ] }, { @@ -3650,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Concluzie:** Eliminarea datelor duplicate este o parte esențială a aproape fiecărui proiect de știința datelor. Datele duplicate pot modifica rezultatele analizelor și pot oferi rezultate inexacte!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Verificări ale calității datelor din lumea reală\n", + "\n", + "> **Obiectiv de învățare:** Până la sfârșitul acestei secțiuni, ar trebui să vă simțiți confortabil să detectați și să corectați problemele comune de calitate a datelor din lumea reală, inclusiv valori categorice inconsistente, valori numerice anormale (outlieri) și entități duplicate cu variații.\n", + "\n", + "Deși valorile lipsă și duplicatele exacte sunt probleme comune, seturile de date din lumea reală conțin adesea probleme mai subtile:\n", + "\n", + "1. **Valori categorice inconsistente**: Aceeași categorie scrisă diferit (de exemplu, \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Valori numerice anormale**: Outlieri extremi care indică erori de introducere a datelor (de exemplu, vârsta = 999)\n", + "3. **Rânduri aproape duplicate**: Înregistrări care reprezintă aceeași entitate cu variații ușoare\n", + "\n", + "Să explorăm tehnici pentru a detecta și a gestiona aceste probleme.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Crearea unui set de date „murdar” de exemplu\n", + "\n", + "Mai întâi, să creăm un set de date de exemplu care conține tipurile de probleme pe care le întâlnim frecvent în datele din lumea reală:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Detectarea Valorilor Categoriale Inconsistente\n", + "\n", + "Observați că coloana `country` are mai multe reprezentări pentru aceleași țări. Haideți să identificăm aceste inconsistențe:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Standardizarea Valorilor Categoriale\n", + "\n", + "Putem crea o mapare pentru a standardiza aceste valori. O abordare simplă este să convertim la litere mici și să creăm un dicționar de mapare:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternativă: Utilizarea potrivirii aproximative**\n", + "\n", + "Pentru cazuri mai complexe, putem folosi potrivirea aproximativă a șirurilor de caractere cu biblioteca `rapidfuzz` pentru a detecta automat șiruri similare:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Detectarea Valorilor Numerice Anormale (Outlieri)\n", + "\n", + "Analizând coloana `age`, observăm câteva valori suspecte, cum ar fi 199 și -5. Să folosim metode statistice pentru a detecta acești outlieri.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Utilizarea metodei IQR (Interval Interquartil)\n", + "\n", + "Metoda IQR este o tehnică statistică robustă pentru detectarea valorilor aberante, care este mai puțin sensibilă la valorile extreme:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Utilizarea metodei Z-Score\n", + "\n", + "Metoda Z-score identifică valorile extreme pe baza deviațiilor standard față de medie:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Gestionarea Valorilor Aberante\n", + "\n", + "Odată detectate, valorile aberante pot fi gestionate în mai multe moduri:\n", + "1. **Eliminare**: Șterge rândurile cu valori aberante (dacă sunt erori)\n", + "2. **Limitare**: Înlocuiește cu valori de limită\n", + "3. **Înlocuire cu NaN**: Tratează-le ca date lipsă și folosește tehnici de imputare\n", + "4. **Păstrare**: Dacă sunt valori extreme legitime\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Detectarea rândurilor aproape identice\n", + "\n", + "Observați că setul nostru de date are mai multe înregistrări pentru \"John Smith\" cu valori ușor diferite. Haideți să identificăm posibile duplicate pe baza similarității numelui.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Găsirea Aproape-Duplicatelor cu Potrivire Fuzzy\n", + "\n", + "Pentru o detectare mai avansată a duplicatelor, putem folosi potrivirea fuzzy pentru a găsi nume similare:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Gestionarea Duplicatelor\n", + "\n", + "Odată identificate, trebuie să decideți cum să gestionați duplicatele:\n", + "1. **Păstrați prima apariție**: Utilizați `drop_duplicates(keep='first')`\n", + "2. **Păstrați ultima apariție**: Utilizați `drop_duplicates(keep='last')`\n", + "3. **Agregarea informațiilor**: Combinați informațiile din rândurile duplicate\n", + "4. **Revizuire manuală**: Marcați pentru revizuire umană\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Rezumat: Pipeline complet de curățare a datelor\n", + "\n", + "Să punem totul împreună într-un pipeline cuprinzător de curățare:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Exercițiu de Provocare\n", + "\n", + "Acum e rândul tău! Mai jos este un rând nou de date cu multiple probleme de calitate. Poți:\n", + "\n", + "1. Identifica toate problemele din acest rând\n", + "2. Scrie cod pentru a corecta fiecare problemă\n", + "3. Adăuga rândul curățat la setul de date\n", + "\n", + "Iată datele problematice:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Puncte Cheie\n", + "\n", + "1. **Categorii inconsistente** sunt frecvente în datele din lumea reală. Verifică întotdeauna valorile unice și standardizează-le folosind mapări sau potrivire aproximativă.\n", + "\n", + "2. **Valorile extreme** pot afecta semnificativ analiza. Folosește cunoștințele de domeniu împreună cu metode statistice (IQR, Z-score) pentru a le detecta.\n", + "\n", + "3. **Aproape duplicatele** sunt mai greu de identificat decât duplicatele exacte. Ia în considerare utilizarea potrivirii aproximative și normalizarea datelor (transformarea în litere mici, eliminarea spațiilor) pentru a le identifica.\n", + "\n", + "4. **Curățarea datelor este iterativă**. Este posibil să fie nevoie să aplici mai multe tehnici și să revizuiești rezultatele înainte de a finaliza setul de date curățat.\n", + "\n", + "5. **Documentează deciziile tale**. Ține evidența pașilor de curățare pe care i-ai aplicat și motivele pentru care ai făcut acest lucru, deoarece este important pentru reproducibilitate și transparență.\n", + "\n", + "> **Practica Recomandată:** Păstrează întotdeauna o copie a datelor originale \"murdare\". Nu suprascrie fișierele sursă de date - creează versiuni curățate cu convenții clare de denumire, cum ar fi `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Declinarea responsabilității**: \nAcest document a fost tradus folosind serviciul de traducere AI [Co-op Translator](https://github.com/Azure/co-op-translator). Deși depunem eforturi pentru a asigura acuratețea, vă rugăm să rețineți că traducerile automate pot conține erori sau inexactități. Documentul original în limba sa nativă ar trebui considerat sursa autoritară. Pentru informații critice, se recomandă traducerea profesională realizată de un specialist uman. Nu ne asumăm răspunderea pentru eventualele neînțelegeri sau interpretări greșite care pot apărea din utilizarea acestei traduceri.\n" + "\n---\n\n**Declinare de responsabilitate**: \nAcest document a fost tradus folosind serviciul de traducere AI [Co-op Translator](https://github.com/Azure/co-op-translator). Deși ne străduim să asigurăm acuratețea, vă rugăm să fiți conștienți că traducerile automate pot conține erori sau inexactități. Documentul original în limba sa maternă ar trebui considerat sursa autoritară. Pentru informații critice, se recomandă traducerea profesională realizată de un specialist. Nu ne asumăm responsabilitatea pentru eventualele neînțelegeri sau interpretări greșite care pot apărea din utilizarea acestei traduceri.\n" ] } ], @@ -3684,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:42:43+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T21:02:39+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "ro" } diff --git a/translations/ru/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/ru/2-Working-With-Data/08-data-preparation/notebook.ipynb index ab8b1602..d2989479 100644 --- a/translations/ru/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/ru/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -14,7 +14,7 @@ "\n", "> **Цель обучения:** К концу этого раздела вы должны уверенно находить общую информацию о данных, хранящихся в pandas DataFrame.\n", "\n", - "После того как вы загрузили свои данные в pandas, скорее всего, они будут находиться в `DataFrame`. Однако если ваш набор данных в `DataFrame` содержит 60,000 строк и 400 столбцов, с чего вообще начать, чтобы понять, с чем вы работаете? К счастью, pandas предоставляет удобные инструменты для быстрого получения общей информации о `DataFrame`, а также для просмотра первых и последних строк.\n", + "После того как вы загрузили свои данные в pandas, скорее всего, они будут находиться в `DataFrame`. Однако если ваш набор данных в `DataFrame` содержит 60,000 строк и 400 столбцов, с чего вообще начать, чтобы понять, с чем вы работаете? К счастью, pandas предоставляет удобные инструменты для быстрого ознакомления с общей информацией о `DataFrame`, а также с первыми и последними строками.\n", "\n", "Чтобы изучить эту функциональность, мы импортируем библиотеку Python scikit-learn и воспользуемся знаковым набором данных, который каждый специалист по данным видел сотни раз: набор данных британского биолога Рональда Фишера *Iris*, использованный в его статье 1936 года \"Использование множественных измерений в таксономических задачах\":\n" ] @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Итак, у нас есть 150 строк и 4 столбца данных. Каждая строка представляет одну точку данных, а каждый столбец — одну характеристику, связанную с таблицей данных. Таким образом, у нас есть 150 точек данных, каждая из которых содержит 4 характеристики.\n", + "Итак, у нас есть 150 строк и 4 столбца данных. Каждая строка представляет одну точку данных, а каждый столбец — одну характеристику, связанную с датафреймом. Таким образом, у нас есть 150 точек данных, каждая из которых содержит 4 характеристики.\n", "\n", - "`shape` здесь является атрибутом таблицы данных, а не функцией, поэтому он не заканчивается парой круглых скобок.\n" + "`shape` здесь является атрибутом датафрейма, а не функцией, поэтому он не заканчивается парой круглых скобок.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Теперь давайте рассмотрим 4 столбца данных. Что именно представляет каждый из них? Атрибут `columns` предоставит нам названия столбцов в датафрейме.\n" + "Теперь давайте рассмотрим 4 столбца данных. Что именно каждый из них представляет? Атрибут `columns` предоставит нам названия столбцов в датафрейме.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Как мы видим, есть четыре (4) столбца. Атрибут `columns` сообщает нам названия столбцов и, по сути, ничего больше. Этот атрибут приобретает значение, когда мы хотим определить признаки, содержащиеся в наборе данных.\n" + "Как мы видим, есть четыре (4) столбца. Атрибут `columns` сообщает нам названия столбцов и, по сути, ничего больше. Этот атрибут приобретает важность, когда мы хотим определить признаки, которые содержит набор данных.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Объем данных (определяется атрибутом `shape`) и названия признаков или столбцов (определяются атрибутом `columns`) дают нам некоторое представление о наборе данных. Теперь мы хотели бы изучить набор данных более подробно. Функция `DataFrame.info()` очень полезна для этого.\n" + "Объем данных (определяемый атрибутом `shape`) и названия признаков или столбцов (определяемые атрибутом `columns`) дают нам некоторое представление о наборе данных. Теперь мы хотим углубиться в изучение набора данных. Функция `DataFrame.info()` очень полезна для этого.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Из этого можно сделать несколько наблюдений: \n", - "1. Тип данных каждого столбца: В этом наборе данных все данные хранятся в виде 64-битных чисел с плавающей запятой. \n", - "2. Количество ненулевых значений: Работа с пропущенными значениями — важный этап подготовки данных. Этот вопрос будет рассмотрен позже в ноутбуке. \n" + "Отсюда можно сделать несколько наблюдений:\n", + "1. Тип данных каждого столбца: В этом наборе данных все данные хранятся в виде 64-битных чисел с плавающей точкой.\n", + "2. Количество ненулевых значений: Работа с нулевыми значениями — важный этап подготовки данных. Это будет рассмотрено позже в блокноте.\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "В результате здесь мы видим пять (5) записей набора данных. Если посмотреть на индекс слева, мы обнаружим, что это первые пять строк.\n" + "На выходе здесь мы видим пять (5) записей набора данных. Если посмотреть на индекс слева, мы обнаружим, что это первые пять строк.\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Другой способ просмотра данных — это начать с конца (вместо начала). Противоположностью `DataFrame.head` является `DataFrame.tail`, который возвращает последние пять строк `DataFrame`:\n" + "Другой способ просмотра данных — с конца (вместо начала). Противоположностью `DataFrame.head` является `DataFrame.tail`, который возвращает последние пять строк `DataFrame`:\n" ] }, { @@ -584,9 +584,9 @@ "source": [ "На практике полезно иметь возможность легко просматривать первые несколько строк или последние несколько строк `DataFrame`, особенно когда вы ищете выбросы в упорядоченных наборах данных.\n", "\n", - "Все функции и атрибуты, показанные выше с помощью примеров кода, помогают нам получить общее представление о данных.\n", + "Все функции и атрибуты, показанные выше с помощью примеров кода, помогают нам получить представление о данных.\n", "\n", - "> **Вывод:** Даже просто взглянув на метаданные о информации в DataFrame или на первые и последние несколько значений, вы можете сразу получить представление о размере, форме и содержании данных, с которыми вы работаете.\n" + "> **Вывод:** Даже просто взглянув на метаданные о информации в DataFrame или на первые и последние несколько значений, вы можете сразу получить представление о размере, форме и содержании данных, с которыми работаете.\n" ] }, { @@ -596,17 +596,17 @@ }, "source": [ "### Отсутствующие данные\n", - "Давайте разберемся с отсутствующими данными. Отсутствующие данные возникают, когда в некоторых столбцах не указано значение.\n", + "Давайте разберемся с отсутствующими данными. Отсутствующие данные возникают, когда в некоторых столбцах не сохранено значение.\n", "\n", - "Рассмотрим пример: допустим, кто-то стесняется своего веса и не заполняет поле \"вес\" в анкете. Тогда значение веса для этого человека будет отсутствовать.\n", + "Возьмем пример: предположим, кто-то очень переживает за свой вес и не заполняет поле \"вес\" в анкете. Тогда значение веса для этого человека будет отсутствовать.\n", "\n", "В большинстве случаев в реальных наборах данных встречаются отсутствующие значения.\n", "\n", "**Как Pandas обрабатывает отсутствующие данные**\n", "\n", - "Pandas обрабатывает отсутствующие значения двумя способами. Первый способ вы уже видели в предыдущих разделах: `NaN`, или Not a Number (не число). Это специальное значение, которое является частью спецификации IEEE для чисел с плавающей точкой и используется исключительно для обозначения отсутствующих значений с плавающей точкой.\n", + "Pandas обрабатывает отсутствующие значения двумя способами. Первый способ вы уже видели в предыдущих разделах: `NaN`, или Not a Number (не число). Это на самом деле специальное значение, которое является частью спецификации IEEE для чисел с плавающей точкой и используется только для обозначения отсутствующих значений с плавающей точкой.\n", "\n", - "Для отсутствующих значений, которые не являются числами с плавающей точкой, pandas использует объект Python `None`. Хотя может показаться запутанным, что вы сталкиваетесь с двумя разными типами значений, которые по сути означают одно и то же, у такого подхода есть веские программные причины. На практике это решение позволяет pandas предложить хороший компромисс для подавляющего большинства случаев. Тем не менее, и `None`, и `NaN` имеют ограничения, о которых нужно помнить в контексте их использования.\n" + "Для отсутствующих значений, кроме чисел с плавающей точкой, pandas использует объект Python `None`. Хотя может показаться запутанным, что вы сталкиваетесь с двумя разными типами значений, которые по сути означают одно и то же, существуют веские программные причины для такого выбора дизайна. На практике этот подход позволяет pandas предложить хороший компромисс для подавляющего большинства случаев. Тем не менее, и `None`, и `NaN` имеют ограничения, которые необходимо учитывать в отношении их использования.\n" ] }, { @@ -615,8 +615,8 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: отсутствие данных не в формате float\n", - "Поскольку `None` происходит из Python, его нельзя использовать в массивах NumPy и pandas, которые не имеют тип данных `'object'`. Помните, что массивы NumPy (и структуры данных в pandas) могут содержать только один тип данных. Это и обеспечивает их огромную мощность для работы с большими объемами данных и вычислений, но также ограничивает их гибкость. Такие массивы должны быть приведены к \"наименьшему общему знаменателю\" — типу данных, который охватывает все элементы массива. Если в массиве присутствует `None`, это означает, что вы работаете с объектами Python.\n", + "### `None`: отсутствие данных не типа float\n", + "Поскольку `None` является частью Python, его нельзя использовать в массивах NumPy и pandas, если их тип данных не `'object'`. Помните, что массивы NumPy (и структуры данных в pandas) могут содержать только один тип данных. Именно это обеспечивает их огромную мощность для работы с большими объемами данных и вычислений, но также ограничивает их гибкость. Такие массивы должны быть приведены к «наименьшему общему знаменателю» — типу данных, который охватывает все элементы массива. Если в массиве присутствует `None`, это означает, что вы работаете с объектами Python.\n", "\n", "Чтобы увидеть это на практике, рассмотрим следующий пример массива (обратите внимание на его `dtype`):\n" ] @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Реальность повышения типов данных несет с собой два побочных эффекта. Во-первых, операции будут выполняться на уровне интерпретируемого кода Python, а не скомпилированного кода NumPy. По сути, это означает, что любые операции, связанные с `Series` или `DataFrame`, содержащими `None`, будут выполняться медленнее. Хотя вы, вероятно, не заметите этого снижения производительности, для больших наборов данных это может стать проблемой.\n", + "Реальность повышения типов данных имеет два побочных эффекта. Во-первых, операции будут выполняться на уровне интерпретируемого кода Python, а не скомпилированного кода NumPy. По сути, это означает, что любые операции, связанные с `Series` или `DataFrame`, содержащими `None`, будут происходить медленнее. Хотя вы, вероятно, не заметите этого снижения производительности, для больших наборов данных это может стать проблемой.\n", "\n", - "Второй побочный эффект вытекает из первого. Поскольку `None` фактически возвращает `Series` или `DataFrame` в мир стандартного Python, использование агрегатных функций NumPy/pandas, таких как `sum()` или `min()`, на массивах, содержащих значение `None`, обычно приведет к ошибке:\n" + "Второй побочный эффект вытекает из первого. Поскольку `None` фактически возвращает `Series` или `DataFrame` в мир обычного Python, использование агрегатов NumPy/pandas, таких как `sum()` или `min()`, на массивах, содержащих значение ``None``, обычно приведет к ошибке:\n" ] }, { @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**Основной вывод**: Сложение (и другие операции) между целыми числами и значениями `None` не определено, что может ограничивать возможности работы с наборами данных, содержащими их.\n" + ] }, { "cell_type": "markdown", @@ -705,9 +707,9 @@ "id": "pWvVHvETgRr9" }, "source": [ - "### `NaN`: отсутствующие значения с плавающей точкой\n", + "### `NaN`: отсутствующие значения типа float\n", "\n", - "В отличие от `None`, NumPy (а следовательно, и pandas) поддерживает `NaN` для своих быстрых векторизованных операций и ufuncs. Плохая новость заключается в том, что любые арифметические операции с `NaN` всегда приводят к `NaN`. Например:\n" + "В отличие от `None`, NumPy (а следовательно, и pandas) поддерживает `NaN` для быстрых векторизированных операций и ufuncs. Плохая новость заключается в том, что любые арифметические операции с `NaN` всегда приводят к `NaN`. Например:\n" ] }, { @@ -770,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Хорошие новости: агрегации, выполняемые на массивах с `NaN`, не вызывают ошибок. Плохие новости: результаты не всегда полезны:\n" + "Хорошая новость: агрегации, выполняемые на массивах с `NaN`, не вызывают ошибок. Плохая новость: результаты не всегда полезны:\n" ] }, { @@ -806,7 +808,9 @@ "metadata": { "id": "nhlnNJT7gRr_" }, - "source": [] + "source": [ + "### Упражнение:\n" + ] }, { "cell_type": "code", @@ -826,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "Помните: `NaN` используется только для отсутствующих значений с плавающей точкой; эквивалента `NaN` для целых чисел, строк или логических значений не существует.\n" + ] }, { "cell_type": "markdown", @@ -834,9 +840,9 @@ "id": "kj6EKdsAgRsA" }, "source": [ - "### `NaN` и `None`: нулевые значения в pandas\n", + "### `NaN` и `None`: пустые значения в pandas\n", "\n", - "Хотя `NaN` и `None` могут вести себя немного по-разному, pandas всё же разработан так, чтобы обрабатывать их взаимозаменяемо. Чтобы понять, о чём идёт речь, рассмотрим `Series` из целых чисел:\n" + "Несмотря на то, что `NaN` и `None` могут вести себя немного по-разному, pandas все же разработан для работы с ними как с взаимозаменяемыми значениями. Чтобы понять, о чем идет речь, рассмотрим `Series` из целых чисел:\n" ] }, { @@ -875,7 +881,9 @@ "metadata": { "id": "WklCzqb8gRsB" }, - "source": [] + "source": [ + "### Упражнение:\n" + ] }, { "cell_type": "code", @@ -898,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "В процессе приведения типов данных к единому формату в `Series` и `DataFrame`, pandas легко заменяет пропущенные значения между `None` и `NaN`. Благодаря этой особенности дизайна, полезно рассматривать `None` и `NaN` как два разных варианта \"null\" в pandas. На самом деле, некоторые основные методы, которые вы будете использовать для работы с пропущенными значениями в pandas, отражают эту идею в своих названиях:\n", + "В процессе приведения типов данных к единому формату в `Series` и `DataFrame` pandas легко заменяет пропущенные значения между `None` и `NaN`. Благодаря этой особенности дизайна полезно рассматривать `None` и `NaN` как два разных типа \"нулевых\" значений в pandas. На самом деле, некоторые основные методы, которые вы будете использовать для работы с пропущенными значениями в pandas, отражают эту идею в своих названиях:\n", "\n", "- `isnull()`: Создает булевую маску, указывающую на пропущенные значения\n", "- `notnull()`: Противоположность `isnull()`\n", "- `dropna()`: Возвращает отфильтрованную версию данных\n", - "- `fillna()`: Возвращает копию данных с заполненными или восстановленными пропущенными значениями\n", + "- `fillna()`: Возвращает копию данных с заполненными или замененными пропущенными значениями\n", "\n", - "Эти методы важно освоить и привыкнуть к их использованию, поэтому давайте рассмотрим каждый из них более подробно.\n" + "Эти методы важны для освоения и уверенного использования, поэтому давайте рассмотрим каждый из них более подробно.\n" ] }, { @@ -916,7 +924,7 @@ "source": [ "### Обнаружение пустых значений\n", "\n", - "Теперь, когда мы поняли важность отсутствующих значений, необходимо выявить их в нашем наборе данных, прежде чем приступать к их обработке. \n", + "Теперь, когда мы поняли важность отсутствующих значений, нам нужно обнаружить их в нашем наборе данных, прежде чем начинать с ними работать. \n", "Методы `isnull()` и `notnull()` являются основными для обнаружения пустых данных. Оба возвращают булевы маски для ваших данных.\n" ] }, @@ -970,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Посмотрите внимательно на результат. Есть ли что-то, что вас удивляет? Хотя `0` является арифметическим нулем, он, тем не менее, вполне себе целое число, и pandas рассматривает его именно так. `''` немного более тонкий случай. Хотя мы использовали его в Разделе 1 для представления пустого строкового значения, он, тем не менее, является строковым объектом, а не представлением null с точки зрения pandas.\n", + "Внимательно посмотрите на результат. Вас что-то удивляет? Хотя `0` является арифметическим нулем, он всё же считается вполне допустимым целым числом, и pandas обрабатывает его именно так. `''` немного сложнее. Хотя мы использовали его в Разделе 1 для представления пустой строки, он всё же является объектом типа строка, а не представлением null с точки зрения pandas.\n", "\n", - "Теперь давайте перевернем ситуацию и используем эти методы так, как вы будете применять их на практике. Вы можете использовать булевы маски непосредственно в качестве индекса ``Series`` или ``DataFrame``, что может быть полезно при работе с изолированными отсутствующими (или присутствующими) значениями.\n", + "Теперь давайте изменим подход и применим эти методы так, как вы будете использовать их на практике. Вы можете использовать булевы маски непосредственно в качестве индекса для ``Series`` или ``DataFrame``, что может быть полезно при работе с отдельными пропущенными (или присутствующими) значениями.\n", "\n", - "Если мы хотим получить общее количество отсутствующих значений, мы можем просто выполнить суммирование по маске, созданной методом `isnull()`.\n" + "Если мы хотим узнать общее количество пропущенных значений, мы можем просто выполнить суммирование по маске, созданной методом `isnull()`.\n" ] }, { @@ -1008,7 +1016,9 @@ "metadata": { "id": "PlBqEo3mgRsC" }, - "source": [] + "source": [ + "### Упражнение:\n" + ] }, { "cell_type": "code", @@ -1030,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Основной вывод**: Оба метода `isnull()` и `notnull()` дают схожие результаты при их использовании в DataFrame: они показывают результаты и индекс этих результатов, что окажет вам огромную помощь при работе с вашими данными.\n" + "**Основной вывод**: Оба метода `isnull()` и `notnull()` дают схожие результаты при использовании их в DataFrame: они показывают результаты и индекс этих результатов, что значительно поможет вам в работе с данными.\n" ] }, { @@ -1041,18 +1051,18 @@ "source": [ "### Работа с отсутствующими данными\n", "\n", - "> **Цель обучения:** К концу этого раздела вы должны понимать, как и когда заменять или удалять отсутствующие значения в DataFrame.\n", + "> **Цель обучения:** К концу этого раздела вы должны понимать, как и когда заменять или удалять пустые значения в DataFrames.\n", "\n", - "Модели машинного обучения не могут самостоятельно работать с отсутствующими данными. Поэтому перед передачей данных в модель необходимо обработать эти пропущенные значения.\n", + "Модели машинного обучения не могут самостоятельно работать с отсутствующими данными. Поэтому перед передачей данных в модель необходимо разобраться с этими пропущенными значениями.\n", "\n", - "Способ обработки отсутствующих данных связан с тонкими компромиссами, которые могут повлиять на ваш итоговый анализ и результаты в реальном мире.\n", + "Способ обработки отсутствующих данных имеет тонкие компромиссы, которые могут повлиять на ваш окончательный анализ и результаты в реальном мире.\n", "\n", "Существует два основных способа работы с отсутствующими данными:\n", "\n", - "1. Удалить строку, содержащую отсутствующее значение\n", - "2. Заменить отсутствующее значение на другое значение\n", + "1. Удалить строку, содержащую пропущенное значение \n", + "2. Заменить пропущенное значение на другое значение \n", "\n", - "Мы подробно обсудим оба этих метода, а также их преимущества и недостатки.\n" + "Мы обсудим оба этих метода, а также их плюсы и минусы более подробно.\n" ] }, { @@ -1063,9 +1073,9 @@ "source": [ "### Удаление пустых значений\n", "\n", - "Количество данных, которые мы передаем в нашу модель, напрямую влияет на ее производительность. Удаление пустых значений означает сокращение количества точек данных, а следовательно, и уменьшение размера набора данных. Поэтому рекомендуется удалять строки с пустыми значениями, если набор данных достаточно большой.\n", + "Количество данных, которые мы передаем нашей модели, напрямую влияет на ее производительность. Удаление пустых значений означает сокращение количества точек данных, а следовательно, уменьшение размера набора данных. Поэтому рекомендуется удалять строки с пустыми значениями, если набор данных достаточно большой.\n", "\n", - "Другой случай может быть, когда в определенной строке или столбце много пропущенных значений. Тогда их можно удалить, так как они не добавят особой ценности нашему анализу, поскольку большая часть данных для этой строки/столбца отсутствует.\n", + "Другой случай может быть связан с тем, что определенная строка или столбец содержит много пропущенных значений. Тогда их можно удалить, так как они не добавят значительной ценности нашему анализу, поскольку большая часть данных для этой строки/столбца отсутствует.\n", "\n", "Помимо выявления пропущенных значений, pandas предоставляет удобный способ удаления пустых значений из `Series` и `DataFrame`. Чтобы увидеть это на практике, вернемся к `example3`. Функция `DataFrame.dropna()` помогает удалять строки с пустыми значениями.\n" ] @@ -1106,7 +1116,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "Обратите внимание, что это должно выглядеть как ваш вывод из `example3[example3.notnull()]`. Разница здесь в том, что вместо индексации только по маскированным значениям, `dropna` удалил эти пропущенные значения из `Series` `example3`.\n", + "Обратите внимание, что это должно выглядеть как ваш вывод из `example3[example3.notnull()]`. Разница здесь в том, что вместо индексации только по значениям с маской, `dropna` удалил эти пропущенные значения из `Series` `example3`.\n", "\n", "Поскольку DataFrame имеет две измерения, он предоставляет больше возможностей для удаления данных.\n" ] @@ -1200,7 +1210,7 @@ "source": [ "(Вы заметили, что pandas преобразовал два столбца в тип float, чтобы учесть значения `NaN`?)\n", "\n", - "Вы не можете удалить одно значение из `DataFrame`, поэтому вам придется удалять целые строки или столбцы. В зависимости от ваших задач, вам может понадобиться одно или другое, и поэтому pandas предоставляет вам варианты для обоих случаев. Поскольку в науке о данных столбцы обычно представляют переменные, а строки — наблюдения, вы, скорее всего, будете удалять строки данных; настройка по умолчанию для `dropna()` — удалять все строки, содержащие любые пустые значения:\n" + "Вы не можете удалить одно значение из `DataFrame`, поэтому вам придется удалять целые строки или столбцы. В зависимости от ваших задач, вам может понадобиться одно или другое, и pandas предоставляет вам варианты для обоих случаев. Поскольку в анализе данных столбцы обычно представляют переменные, а строки — наблюдения, чаще всего удаляют строки данных; настройка по умолчанию для `dropna()` — удаление всех строк, содержащих любые пустые значения:\n" ] }, { @@ -1352,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Обратите внимание, что это может привести к удалению большого количества данных, которые вы, возможно, захотите сохранить, особенно в небольших наборах данных. Что, если вы хотите удалить только строки или столбцы, содержащие несколько или даже все значения null? Вы можете задать эти параметры в `dropna` с помощью параметров `how` и `thresh`.\n", + "Обратите внимание, что это может удалить много данных, которые вы, возможно, захотите сохранить, особенно в небольших наборах данных. Что, если вы хотите удалить только строки или столбцы, содержащие несколько или даже все значения null? Вы можете указать эти настройки в `dropna` с помощью параметров `how` и `thresh`.\n", "\n", - "По умолчанию используется `how='any'` (если вы хотите проверить это самостоятельно или посмотреть, какие еще параметры есть у метода, выполните `example4.dropna?` в ячейке кода). Вы также можете указать `how='all'`, чтобы удалять только строки или столбцы, содержащие исключительно значения null. Давайте расширим наш пример `DataFrame`, чтобы увидеть это в действии в следующем упражнении.\n" + "По умолчанию `how='any'` (если вы хотите проверить это самостоятельно или посмотреть, какие еще параметры есть у метода, выполните `example4.dropna?` в ячейке кода). Вы также можете указать `how='all'`, чтобы удалять только строки или столбцы, содержащие все значения null. Давайте расширим наш пример `DataFrame`, чтобы увидеть это в действии в следующем упражнении.\n" ] }, { @@ -1446,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> Основные моменты:\n", - "1. Удаление пустых значений имеет смысл только в том случае, если набор данных достаточно большой.\n", - "2. Полные строки или столбцы можно удалить, если в них отсутствует большая часть данных.\n", - "3. Метод `DataFrame.dropna(axis=)` помогает удалять пустые значения. Аргумент `axis` указывает, следует ли удалять строки или столбцы.\n", - "4. Также можно использовать аргумент `how`. По умолчанию он установлен на `any`, поэтому удаляются только те строки/столбцы, которые содержат любые пустые значения. Его можно установить на `all`, чтобы указать, что будут удалены только те строки/столбцы, где все значения пустые.\n" + "> Основные выводы: \n", + "1. Удаление пустых значений имеет смысл только в том случае, если набор данных достаточно большой. \n", + "2. Полные строки или столбцы можно удалить, если в них отсутствует большая часть данных. \n", + "3. Метод `DataFrame.dropna(axis=)` помогает удалять пустые значения. Аргумент `axis` указывает, следует ли удалять строки или столбцы. \n", + "4. Также можно использовать аргумент `how`. По умолчанию он установлен на `any`, поэтому удаляются только те строки/столбцы, которые содержат хотя бы одно пустое значение. Его можно установить на `all`, чтобы удалять только те строки/столбцы, где все значения пустые. \n" ] }, { @@ -1458,7 +1468,9 @@ "metadata": { "id": "oXXSfQFHgRsF" }, - "source": [] + "source": [ + "### Упражнение:\n" + ] }, { "cell_type": "code", @@ -1480,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "Параметр `thresh` дает вам более точный контроль: вы задаете количество *ненулевых* значений, которые строка или столбец должны иметь, чтобы быть сохраненными:\n" + "Параметр `thresh` предоставляет более тонкий контроль: вы задаете количество *ненулевых* значений, которые строка или столбец должны иметь, чтобы быть сохраненными:\n" ] }, { @@ -1554,7 +1566,9 @@ "metadata": { "id": "fmSFnzZegRsG" }, - "source": [] + "source": [ + "Здесь первая и последняя строки были удалены, так как они содержат только два ненулевых значения.\n" + ] }, { "cell_type": "markdown", @@ -1564,7 +1578,7 @@ "source": [ "### Заполнение пропущенных значений\n", "\n", - "Иногда имеет смысл заполнить пропущенные значения теми, которые могут быть допустимыми. Существует несколько методов для заполнения null-значений. Первый — использование предметных знаний (знаний о теме, на которой основан набор данных) для приблизительного определения пропущенных значений.\n", + "Иногда имеет смысл заполнить пропущенные значения теми, которые могут быть допустимыми. Существует несколько методов заполнения null-значений. Первый — использование предметных знаний (знаний о теме, на которой основан набор данных) для приблизительного определения пропущенных значений.\n", "\n", "Вы можете использовать `isnull` для выполнения этой задачи на месте, но это может быть трудоемко, особенно если у вас много значений для заполнения. Поскольку это очень распространенная задача в области анализа данных, pandas предоставляет метод `fillna`, который возвращает копию `Series` или `DataFrame` с заменой пропущенных значений на выбранные вами. Давайте создадим еще один пример `Series`, чтобы увидеть, как это работает на практике.\n" ] @@ -1576,11 +1590,11 @@ }, "source": [ "### Категориальные данные (нечисловые)\n", - "Сначала рассмотрим нечисловые данные. В наборах данных у нас есть столбцы с категориальными данными, например, Пол, Истина или Ложь и т.д.\n", + "Сначала рассмотрим нечисловые данные. В наборах данных есть столбцы с категориальными данными, например, пол, значения True или False и т.д.\n", "\n", - "В большинстве таких случаев мы заменяем пропущенные значения на `моду` столбца. Допустим, у нас есть 100 точек данных: 90 указали Истина, 8 указали Ложь, а 2 не заполнили. Тогда мы можем заполнить эти 2 пропущенных значения Истиной, учитывая весь столбец.\n", + "В большинстве случаев мы заменяем пропущенные значения на `моду` столбца. Например, у нас есть 100 точек данных: 90 указали True, 8 указали False, а 2 оставили пустыми. Тогда мы можем заполнить эти 2 значения True, учитывая весь столбец.\n", "\n", - "Опять же, здесь мы можем использовать знания предметной области. Рассмотрим пример заполнения с использованием моды.\n" + "Также здесь можно использовать знания предметной области. Рассмотрим пример заполнения значений модой.\n" ] }, { @@ -1685,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Теперь давайте сначала найдем моду, прежде чем заполнять значение `None` модой.\n" + ] }, { "cell_type": "code", @@ -1720,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Итак, мы заменим None на True\n" + ] }, { "cell_type": "code", @@ -1830,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Как мы видим, значение null было заменено. Само собой разумеется, мы могли написать что угодно вместо `'True'`, и это было бы подставлено.\n" + "Как мы видим, значение null было заменено. Само собой разумеется, мы могли написать что угодно вместо `'True'`, и оно было бы подставлено.\n" ] }, { @@ -1845,11 +1863,11 @@ "1. Замена на медиану строки\n", "2. Замена на среднее значение строки\n", "\n", - "Мы используем медиану в случае перекошенных данных с выбросами. Это связано с тем, что медиана устойчива к выбросам.\n", + "Мы используем медиану в случае смещенных данных с выбросами. Это связано с тем, что медиана устойчива к выбросам.\n", "\n", "Когда данные нормализованы, можно использовать среднее значение, так как в этом случае среднее и медиана будут довольно близки.\n", "\n", - "Сначала возьмем столбец с нормальным распределением и заполним пропущенные значения средним значением столбца.\n" + "Сначала возьмем столбец, который имеет нормальное распределение, и заполним пропущенные значения средним значением столбца.\n" ] }, { @@ -1989,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Заполнение средним\n" + ] }, { "cell_type": "code", @@ -2098,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Теперь давайте попробуем другой датафрейм, и на этот раз заменим значения None на медиану столбца.\n" + "Теперь давайте попробуем другой датафрейм, и на этот раз мы заменим значения None на медиану столбца.\n" ] }, { @@ -2204,7 +2224,7 @@ "id": "mM1GpXYmjHnc" }, "source": [ - "Медиана второго столбца равна\n" + "Медиана второго столбца составляет\n" ] }, { @@ -2238,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Заполнение медианой\n" + ] }, { "cell_type": "code", @@ -2421,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Основные выводы: \n", - "1. Заполнение пропущенных значений следует выполнять, когда данных мало или есть стратегия для их заполнения. \n", - "2. Для заполнения пропущенных значений можно использовать знания предметной области, чтобы приблизительно восстановить их. \n", - "3. Для категориальных данных чаще всего пропущенные значения заменяются модой столбца. \n", - "4. Для числовых данных пропущенные значения обычно заполняются средним значением (для нормализованных наборов данных) или медианой столбцов. \n" + "> Основные выводы:\n", + "1. Заполнение пропущенных значений следует выполнять, если данных недостаточно или если есть стратегия для их заполнения.\n", + "2. Для заполнения пропущенных значений можно использовать знания предметной области, приближая их.\n", + "3. В случае категориальных данных пропущенные значения чаще всего заменяются модой столбца.\n", + "4. Для числовых данных пропущенные значения обычно заполняются средним значением (для нормализованных наборов данных) или медианой столбцов.\n" ] }, { @@ -2433,7 +2455,9 @@ "metadata": { "id": "FI9MmqFJgRsH" }, - "source": [] + "source": [ + "### Упражнение:\n" + ] }, { "cell_type": "code", @@ -2453,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "Вы можете **заполнить вперед** пустые значения, используя последнее допустимое значение для заполнения пустого:\n" + ] }, { "cell_type": "code", @@ -2535,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "Как вы могли догадаться, это работает так же с DataFrame, но вы также можете указать `axis`, вдоль которого будут заполняться значения null:\n" + "Как вы могли догадаться, это работает так же с DataFrame, но вы также можете указать `axis`, вдоль которого заполнять значения null:\n" ] }, { @@ -2708,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Обратите внимание, что когда предыдущее значение недоступно для заполнения вперед, остается значение null.\n" + "Обратите внимание, что если предыдущего значения нет для заполнения вперед, пустое значение остается.\n" ] }, { @@ -2716,7 +2742,9 @@ "metadata": { "id": "eeAoOU0RgRsJ" }, - "source": [] + "source": [ + "### Упражнение:\n" + ] }, { "cell_type": "code", @@ -2830,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Обратите внимание, что третий столбец все еще пуст: значения по умолчанию заполняются построчно.\n", + "Обратите внимание, что столбец 3 все еще остается пустым: значения по умолчанию заполняются построчно.\n", "\n", - "> **Вывод:** Существует множество способов справляться с отсутствующими значениями в ваших наборах данных. Конкретная стратегия (удаление, замена или способ замены) должна определяться особенностями этих данных. Чем больше вы работаете с наборами данных и взаимодействуете с ними, тем лучше вы будете понимать, как справляться с отсутствующими значениями.\n" + "> **Вывод:** Существует множество способов справляться с отсутствующими значениями в ваших наборах данных. Конкретная стратегия (удаление, замена или способ замены) должна определяться особенностями этих данных. Чем больше вы работаете с наборами данных, тем лучше вы будете понимать, как справляться с отсутствующими значениями.\n" ] }, { @@ -2856,7 +2884,7 @@ "source": [ "**КОДИРОВАНИЕ МЕТКИ**\n", "\n", - "Кодирование метки — это процесс преобразования каждой категории в число. Например, предположим, у нас есть набор данных о пассажирах авиалиний, и в нем есть столбец, содержащий их класс из следующих вариантов: ['бизнес-класс', 'эконом-класс', 'первый класс']. Если выполнить кодирование метки для этого столбца, он будет преобразован в [0, 1, 2]. Давайте рассмотрим пример с помощью кода. Так как мы будем изучать `scikit-learn` в следующих ноутбуках, здесь мы его использовать не будем.\n" + "Кодирование метки — это процесс преобразования каждой категории в число. Например, предположим, у нас есть набор данных о пассажирах авиакомпании, и в нем есть столбец, содержащий их класс из следующих ['бизнес-класс', 'эконом-класс', 'первый класс']. Если выполнить кодирование метки, это будет преобразовано в [0,1,2]. Давайте рассмотрим пример с помощью кода. Поскольку мы будем изучать `scikit-learn` в следующих блокнотах, здесь мы его использовать не будем.\n" ] }, { @@ -2964,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Чтобы выполнить кодирование меток для первого столбца, сначала необходимо описать отображение каждого класса на число, прежде чем заменить\n" + "Чтобы выполнить кодирование меток в первом столбце, сначала необходимо описать отображение каждого класса в число, прежде чем заменить.\n" ] }, { @@ -3066,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Как мы видим, результат соответствует нашим ожиданиям. Итак, когда же использовать кодирование меток? Кодирование меток применяется в одном или обоих из следующих случаев:\n", + "Как мы видим, результат соответствует тому, что мы ожидали. Итак, когда же использовать кодирование меток? Кодирование меток применяется в одном или обоих из следующих случаев:\n", "1. Когда количество категорий велико\n", - "2. Когда категории имеют определённый порядок.\n" + "2. Когда категории имеют порядок.\n" ] }, { @@ -3079,9 +3107,9 @@ "source": [ "**ONE HOT ENCODING**\n", "\n", - "Другой вид кодирования — это One Hot Encoding. При таком способе кодирования каждая категория столбца добавляется как отдельный столбец, и каждая точка данных получает 0 или 1 в зависимости от того, содержит ли она эту категорию. Таким образом, если есть n различных категорий, к датафрейму будет добавлено n столбцов.\n", + "Другой тип кодирования — это One Hot Encoding. При таком кодировании каждая категория столбца добавляется как отдельный столбец, и каждой точке данных присваивается 0 или 1 в зависимости от того, содержит ли она эту категорию. Таким образом, если есть n различных категорий, к датафрейму будет добавлено n столбцов.\n", "\n", - "Например, возьмем тот же пример с классами самолета. Категории были: ['business class', 'economy class', 'first class']. Если мы применим One Hot Encoding, то в набор данных будут добавлены следующие три столбца: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Например, возьмем тот же пример с классами самолета. Категории были: ['business class', 'economy class', 'first class']. Если мы применим One Hot Encoding, к набору данных будут добавлены следующие три столбца: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3314,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Каждый закодированный методом one-hot столбец содержит 0 или 1, что указывает, существует ли эта категория для данной точки данных.\n" + "Каждый закодированный столбец содержит 0 или 1, что указывает, существует ли эта категория для данной точки данных.\n" ] }, { @@ -3323,7 +3351,7 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "Когда мы используем one hot encoding? One hot encoding используется в одном или обоих из следующих случаев:\n", + "Когда мы используем one hot encoding? One hot encoding применяется в одном или обоих следующих случаях:\n", "\n", "1. Когда количество категорий и размер набора данных невелики.\n", "2. Когда категории не имеют определенного порядка.\n" @@ -3336,7 +3364,7 @@ }, "source": [ "> Основные выводы:\n", - "1. Кодирование используется для преобразования ненумерических данных в числовые.\n", + "1. Кодирование используется для преобразования ненумерованных данных в числовые.\n", "2. Существует два типа кодирования: кодирование меток и One Hot кодирование, которые можно применять в зависимости от требований набора данных.\n" ] }, @@ -3346,11 +3374,11 @@ "id": "K8UXOJYRgRsJ" }, "source": [ - "## Удаление дублирующихся данных\n", + "## Удаление дублированных данных\n", "\n", - "> **Цель обучения:** К концу этого раздела вы должны уверенно определять и удалять дублирующиеся значения из DataFrame.\n", + "> **Цель обучения:** К концу этого раздела вы должны уверенно определять и удалять дублированные значения из DataFrame.\n", "\n", - "Помимо отсутствующих данных, в реальных наборах данных вы часто будете сталкиваться с дублирующимися данными. К счастью, pandas предоставляет простой способ обнаружения и удаления дублирующихся записей.\n" + "Помимо отсутствующих данных, в реальных наборах данных вы часто будете сталкиваться с дублированными данными. К счастью, pandas предоставляет простой способ обнаружения и удаления повторяющихся записей.\n" ] }, { @@ -3361,7 +3389,7 @@ "source": [ "### Определение дубликатов: `duplicated`\n", "\n", - "Вы можете легко обнаружить повторяющиеся значения с помощью метода `duplicated` в pandas. Этот метод возвращает булеву маску, указывающую, является ли запись в `DataFrame` дубликатом более ранней записи. Давайте создадим еще один пример `DataFrame`, чтобы увидеть, как это работает.\n" + "Вы можете легко обнаружить повторяющиеся значения с помощью метода `duplicated` в pandas, который возвращает булевую маску, указывающую, является ли запись в `DataFrame` дубликатом более ранней. Давайте создадим еще один пример `DataFrame`, чтобы увидеть, как это работает.\n" ] }, { @@ -3491,7 +3519,7 @@ }, "source": [ "### Удаление дубликатов: `drop_duplicates`\n", - "`drop_duplicates` просто возвращает копию данных, для которых все значения, отмеченные как `duplicated`, равны `False`:\n" + "`drop_duplicates` просто возвращает копию данных, для которых все значения `duplicated` равны `False`:\n" ] }, { @@ -3574,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Оба метода `duplicated` и `drop_duplicates` по умолчанию учитывают все столбцы, но вы можете указать, чтобы они рассматривали только подмножество столбцов в вашем `DataFrame`:\n" + "Оба метода `duplicated` и `drop_duplicates` по умолчанию учитывают все столбцы, но вы можете указать, чтобы они проверяли только подмножество столбцов в вашем `DataFrame`:\n" ] }, { @@ -3650,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Вывод:** Удаление дублирующихся данных является важной частью практически каждого проекта в области науки о данных. Дублирующиеся данные могут изменить результаты ваших анализов и привести к неточным выводам!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Проверка качества данных в реальных условиях\n", + "\n", + "> **Цель обучения:** К концу этого раздела вы сможете уверенно выявлять и исправлять распространенные проблемы качества данных, такие как несогласованные категориальные значения, аномальные числовые значения (выбросы) и дублирующиеся сущности с вариациями.\n", + "\n", + "Хотя пропущенные значения и точные дубликаты являются распространенными проблемами, в реальных наборах данных часто встречаются более тонкие ошибки:\n", + "\n", + "1. **Несогласованные категориальные значения**: Одна и та же категория записана по-разному (например, \"USA\", \"U.S.A\", \"United States\").\n", + "2. **Аномальные числовые значения**: Экстремальные выбросы, указывающие на ошибки ввода данных (например, возраст = 999).\n", + "3. **Почти дублирующиеся строки**: Записи, представляющие одну и ту же сущность с небольшими вариациями.\n", + "\n", + "Давайте рассмотрим методы выявления и устранения этих проблем.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Создание примера \"грязного\" набора данных\n", + "\n", + "Сначала давайте создадим пример набора данных, содержащий типичные проблемы, с которыми мы часто сталкиваемся в реальных данных:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Обнаружение несоответствий в категориальных значениях\n", + "\n", + "Обратите внимание, что в столбце `country` есть несколько вариантов написания одних и тех же стран. Давайте выявим эти несоответствия:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Стандартизация категориальных значений\n", + "\n", + "Мы можем создать отображение для стандартизации этих значений. Простой подход — преобразовать значения в нижний регистр и создать словарь отображения:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Альтернатива: использование нечеткого сопоставления**\n", + "\n", + "Для более сложных случаев можно использовать нечеткое строковое сопоставление с библиотекой `rapidfuzz` для автоматического обнаружения похожих строк:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Обнаружение аномальных числовых значений (выбросов)\n", + "\n", + "Рассматривая столбец `age`, мы видим подозрительные значения, такие как 199 и -5. Давайте используем статистические методы для выявления этих выбросов.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Использование метода IQR (межквартильный размах)\n", + "\n", + "Метод IQR — это надежный статистический подход для обнаружения выбросов, который менее чувствителен к экстремальным значениям:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Использование метода Z-оценки\n", + "\n", + "Метод Z-оценки определяет выбросы на основе стандартных отклонений от среднего значения:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Работа с выбросами\n", + "\n", + "После обнаружения выбросов их можно обработать несколькими способами:\n", + "1. **Удалить**: Удалить строки с выбросами (если это ошибки)\n", + "2. **Ограничить**: Заменить на граничные значения\n", + "3. **Заменить на NaN**: Рассматривать как пропущенные данные и использовать методы импутации\n", + "4. **Оставить**: Если это действительно допустимые экстремальные значения\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Обнаружение почти одинаковых строк\n", + "\n", + "Обратите внимание, что в нашем наборе данных есть несколько записей для \"John Smith\" с немного отличающимися значениями. Давайте определим возможные дубликаты на основе сходства имен.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Поиск почти дубликатов с помощью нечеткого сопоставления\n", + "\n", + "Для более сложного обнаружения дубликатов можно использовать нечеткое сопоставление для поиска похожих имен:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Работа с дубликатами\n", + "\n", + "После выявления необходимо решить, как поступить с дубликатами:\n", + "1. **Сохранить первое вхождение**: Используйте `drop_duplicates(keep='first')`\n", + "2. **Сохранить последнее вхождение**: Используйте `drop_duplicates(keep='last')`\n", + "3. **Агрегировать информацию**: Объединить данные из повторяющихся строк\n", + "4. **Ручная проверка**: Отметить для проверки человеком\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Резюме: Полный процесс очистки данных\n", + "\n", + "Давайте соберем все вместе в единый процесс очистки данных:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Задание\n", + "\n", + "Теперь ваша очередь! Ниже приведена новая строка данных с несколькими проблемами качества. Можете ли вы:\n", + "\n", + "1. Выявить все проблемы в этой строке\n", + "2. Написать код для исправления каждой проблемы\n", + "3. Добавить очищенную строку в набор данных\n", + "\n", + "Вот проблемные данные:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Основные выводы\n", + "\n", + "1. **Несогласованные категории** часто встречаются в реальных данных. Всегда проверяйте уникальные значения и стандартизируйте их с помощью сопоставлений или нечеткого поиска совпадений.\n", + "\n", + "2. **Выбросы** могут существенно повлиять на ваш анализ. Используйте знания предметной области в сочетании со статистическими методами (IQR, Z-оценка) для их обнаружения.\n", + "\n", + "3. **Почти дубликаты** сложнее обнаружить, чем точные дубликаты. Рассмотрите возможность использования нечеткого поиска совпадений и нормализации данных (приведение к нижнему регистру, удаление пробелов) для их идентификации.\n", + "\n", + "4. **Очистка данных — это итеративный процесс**. Возможно, вам придется применять несколько методов и пересматривать результаты, прежде чем завершить процесс очистки данных.\n", + "\n", + "5. **Документируйте свои решения**. Фиксируйте, какие шаги по очистке данных вы применили и почему, так как это важно для воспроизводимости и прозрачности.\n", + "\n", + "> **Лучший подход:** Всегда сохраняйте копию ваших исходных \"грязных\" данных. Никогда не перезаписывайте исходные файлы данных — создавайте очищенные версии с понятными именами, например, `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Отказ от ответственности**: \nЭтот документ был переведен с использованием сервиса автоматического перевода [Co-op Translator](https://github.com/Azure/co-op-translator). Хотя мы стремимся к точности, пожалуйста, имейте в виду, что автоматические переводы могут содержать ошибки или неточности. Оригинальный документ на его исходном языке следует считать авторитетным источником. Для получения критически важной информации рекомендуется профессиональный перевод человеком. Мы не несем ответственности за любые недоразумения или неправильные толкования, возникшие в результате использования данного перевода.\n" + "\n---\n\n**Отказ от ответственности**: \nЭтот документ был переведен с использованием сервиса автоматического перевода [Co-op Translator](https://github.com/Azure/co-op-translator). Несмотря на наши усилия обеспечить точность, автоматические переводы могут содержать ошибки или неточности. Оригинальный документ на его родном языке следует считать авторитетным источником. Для получения критически важной информации рекомендуется профессиональный перевод человеком. Мы не несем ответственности за любые недоразумения или неправильные интерпретации, возникающие в результате использования данного перевода.\n" ] } ], @@ -3684,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:45:50+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:02:29+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "ru" } diff --git a/translations/sk/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/sk/2-Working-With-Data/08-data-preparation/notebook.ipynb index 041456a8..a9a82619 100644 --- a/translations/sk/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/sk/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -12,11 +12,11 @@ "\n", "## Preskúmanie informácií o `DataFrame`\n", "\n", - "> **Cieľ učenia:** Na konci tejto podsekcie by ste mali byť schopní pohodlne nájsť všeobecné informácie o dátach uložených v pandas DataFrame.\n", + "> **Cieľ učenia:** Na konci tejto podsekcie by ste mali byť schopní pohodlne nájsť všeobecné informácie o dátach uložených v pandas DataFrames.\n", "\n", - "Keď načítate svoje dáta do pandas, je veľmi pravdepodobné, že budú uložené v `DataFrame`. Ak však má dátová sada vo vašom `DataFrame` 60 000 riadkov a 400 stĺpcov, ako vôbec začať získavať prehľad o tom, s čím pracujete? Našťastie pandas poskytuje niekoľko praktických nástrojov na rýchle získanie celkových informácií o `DataFrame`, ako aj na zobrazenie prvých a posledných niekoľkých riadkov.\n", + "Keď načítate svoje dáta do pandas, je veľmi pravdepodobné, že budú vo forme `DataFrame`. Ak však má váš `DataFrame` 60 000 riadkov a 400 stĺpcov, ako vôbec začať chápať, s čím pracujete? Našťastie pandas poskytuje niekoľko praktických nástrojov na rýchle získanie celkových informácií o `DataFrame`, ako aj na zobrazenie prvých a posledných niekoľkých riadkov.\n", "\n", - "Aby sme preskúmali túto funkcionalitu, importujeme knižnicu Python scikit-learn a použijeme ikonickú dátovú sadu, ktorú každý dátový vedec videl už stokrát: dátovú sadu britského biológa Ronalda Fishera *Iris*, použitú v jeho článku z roku 1936 \"Použitie viacerých meraní v taxonomických problémoch\":\n" + "Aby sme preskúmali túto funkcionalitu, importujeme knižnicu Python scikit-learn a použijeme ikonický dataset, ktorý každý dátový vedec videl stokrát: dataset britského biológa Ronalda Fishera *Iris*, použitý v jeho článku z roku 1936 \"Použitie viacerých meraní v taxonomických problémoch\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Načítali sme dataset Iris do premennej `iris_df`. Predtým, než sa pustíme do analýzy údajov, by bolo užitočné zistiť, koľko dátových bodov máme a aká je celková veľkosť datasetu. Je užitočné pozrieť sa na objem údajov, s ktorými pracujeme.\n" + "Načítali sme dataset Iris do premennej `iris_df`. Predtým, než sa pustíme do analýzy dát, by bolo užitočné vedieť, koľko dátových bodov máme a aká je celková veľkosť datasetu. Je užitočné pozrieť sa na objem dát, s ktorými pracujeme.\n" ] }, { @@ -80,7 +80,7 @@ "source": [ "Takže máme do činenia so 150 riadkami a 4 stĺpcami údajov. Každý riadok predstavuje jeden dátový bod a každý stĺpec predstavuje jednu vlastnosť spojenú s dátovým rámcom. V podstate teda ide o 150 dátových bodov, z ktorých každý obsahuje 4 vlastnosti.\n", "\n", - "`shape` je tu atribútom dátového rámca, nie funkciou, a preto nekončí dvojicou zátvoriek.\n" + "`shape` je tu atribút dátového rámca, nie funkcia, a preto nekončí dvojicou zátvoriek.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Z tohto môžeme urobiť niekoľko pozorovaní: \n", - "1. Dátový typ každého stĺpca: V tomto datasete sú všetky údaje uložené ako 64-bitové čísla s pohyblivou desatinnou čiarkou. \n", - "2. Počet nenulových hodnôt: Práca s nulovými hodnotami je dôležitým krokom pri príprave údajov. Týmto sa budeme zaoberať neskôr v notebooku. \n" + "Odtiaľto môžeme urobiť niekoľko pozorovaní:\n", + "1. Typ údajov každého stĺpca: V tomto súbore údajov sú všetky údaje uložené ako 64-bitové čísla s pohyblivou desatinnou čiarkou.\n", + "2. Počet nenulových hodnôt: Práca s nulovými hodnotami je dôležitým krokom pri príprave údajov. Týmto sa budeme zaoberať neskôr v notebooku.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Predstavme si, že máme veľa číselných údajov v našej dátovej sade. Jednovariabilné štatistické výpočty, ako napríklad priemer, medián, kvartily a podobne, je možné vykonať na každom stĺpci samostatne. Funkcia `DataFrame.describe()` nám poskytuje štatistický prehľad číselných stĺpcov dátovej sady.\n" + "Povedzme, že máme veľa číselných údajov v našej dátovej sade. Jednoduché štatistické výpočty, ako je priemer, medián, kvartily atď., môžu byť vykonané na každom stĺpci samostatne. Funkcia `DataFrame.describe()` nám poskytuje štatistický prehľad číselných stĺpcov dátovej sady.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "Výstup vyššie zobrazuje celkový počet dátových bodov, priemer, smerodajnú odchýlku, minimum, dolný kvartil (25 %), medián (50 %), horný kvartil (75 %) a maximálnu hodnotu každého stĺpca.\n" + "Výstup vyššie zobrazuje celkový počet dátových bodov, priemer, štandardnú odchýlku, minimum, dolný kvartil (25 %), medián (50 %), horný kvartil (75 %) a maximálnu hodnotu každého stĺpca.\n" ] }, { @@ -332,7 +332,7 @@ }, "source": [ "### `DataFrame.head`\n", - "S použitím všetkých vyššie uvedených funkcií a atribútov sme získali prehľad o dátovom súbore. Vieme, koľko dátových bodov obsahuje, koľko má vlastností, aký je dátový typ každej vlastnosti a koľko neprázdnych hodnôt má každá vlastnosť.\n", + "So všetkými vyššie uvedenými funkciami a atribútmi sme získali všeobecný prehľad o dátovom súbore. Vieme, koľko dátových bodov obsahuje, koľko má vlastností, aký je dátový typ každej vlastnosti a koľko neprázdnych hodnôt má každá vlastnosť.\n", "\n", "Teraz je čas pozrieť sa na samotné dáta. Pozrime sa, ako vyzerajú prvé riadky (prvé dátové body) nášho `DataFrame`:\n" ] @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Ako výstup tu vidíme päť (5) záznamov z datasetu. Ak sa pozrieme na index vľavo, zistíme, že ide o prvých päť riadkov.\n" + "Ako výstup tu vidíme päť (5) záznamov z datasetu. Ak sa pozrieme na index naľavo, zistíme, že ide o prvých päť riadkov.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Cvičenie:\n", "\n", - "Z vyššie uvedeného príkladu je zrejmé, že predvolene `DataFrame.head` vráti prvých päť riadkov `DataFrame`. V bunkách kódu nižšie, dokážete nájsť spôsob, ako zobraziť viac ako päť riadkov?\n" + "Z vyššie uvedeného príkladu je zrejmé, že predvolene `DataFrame.head` vráti prvých päť riadkov z `DataFrame`. V kódovom bloku nižšie, dokážete nájsť spôsob, ako zobraziť viac ako päť riadkov?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Ďalší spôsob, ako sa pozrieť na údaje, môže byť od konca (namiesto od začiatku). Opačnou funkciou k `DataFrame.head` je `DataFrame.tail`, ktorá vráti posledných päť riadkov `DataFrame`:\n" + "Ďalší spôsob, ako sa pozrieť na údaje, je od konca (namiesto od začiatku). Opačnou funkciou k `DataFrame.head` je `DataFrame.tail`, ktorá vráti posledných päť riadkov `DataFrame`:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "V praxi je užitočné mať možnosť jednoducho prezrieť prvých pár riadkov alebo posledných pár riadkov `DataFrame`, najmä keď hľadáte odľahlé hodnoty v usporiadaných datasetoch.\n", + "V praxi je užitočné mať možnosť jednoducho si prezrieť prvé alebo posledné riadky `DataFrame`, najmä keď hľadáte odľahlé hodnoty v usporiadaných dátových súboroch.\n", "\n", - "Všetky funkcie a atribúty uvedené vyššie pomocou príkladov kódu nám pomáhajú získať pohľad na dáta.\n", + "Všetky funkcie a atribúty uvedené vyššie s pomocou príkladov kódu nám umožňujú získať prehľad o dátach.\n", "\n", - "> **Poučenie:** Už len pohľad na metadáta o informáciách v `DataFrame` alebo na prvé a posledné hodnoty v ňom vám môže okamžite poskytnúť predstavu o veľkosti, tvare a obsahu dát, s ktorými pracujete.\n" + "> **Hlavná myšlienka:** Už len pohľad na metadáta o informáciách v `DataFrame` alebo na prvé a posledné hodnoty v ňom vám môže okamžite poskytnúť predstavu o veľkosti, tvare a obsahu dát, s ktorými pracujete.\n" ] }, { @@ -596,9 +596,9 @@ }, "source": [ "### Chýbajúce údaje\n", - "Pozrime sa na chýbajúce údaje. Chýbajúce údaje vznikajú, keď v niektorých stĺpcoch nie je uložená žiadna hodnota.\n", + "Pozrime sa na problematiku chýbajúcich údajov. Chýbajúce údaje nastávajú, keď v niektorých stĺpcoch nie je uložená žiadna hodnota.\n", "\n", - "Uveďme si príklad: povedzme, že niekto je citlivý na svoju váhu a nevyplní pole s váhou v prieskume. Potom bude hodnota váhy pre túto osobu chýbať.\n", + "Uveďme si príklad: povedzme, že niekto je citlivý na svoju váhu a nevyplní pole s váhou v prieskume. V takom prípade bude hodnota váhy pre danú osobu chýbať.\n", "\n", "Vo väčšine prípadov sa v reálnych datasetoch vyskytujú chýbajúce hodnoty.\n", "\n", @@ -606,7 +606,7 @@ "\n", "Pandas spracováva chýbajúce hodnoty dvoma spôsobmi. Prvý ste už videli v predchádzajúcich sekciách: `NaN`, alebo Not a Number. Toto je špeciálna hodnota, ktorá je súčasťou špecifikácie IEEE pre čísla s pohyblivou desatinnou čiarkou a používa sa iba na označenie chýbajúcich hodnôt typu float.\n", "\n", - "Pre chýbajúce hodnoty, ktoré nie sú typu float, pandas používa objekt `None` z Pythonu. Aj keď sa môže zdať mätúce, že sa stretnete s dvoma rôznymi typmi hodnôt, ktoré v podstate vyjadrujú to isté, existujú dobré programátorské dôvody pre toto rozhodnutie. V praxi tento prístup umožňuje pandas dosiahnuť dobrý kompromis vo väčšine prípadov. Napriek tomu majú `None` aj `NaN` určité obmedzenia, na ktoré si musíte dávať pozor, pokiaľ ide o ich použitie.\n" + "Pre chýbajúce hodnoty, ktoré nie sú typu float, používa pandas objekt Pythonu `None`. Aj keď sa môže zdať mätúce, že sa stretnete s dvoma rôznymi typmi hodnôt, ktoré v podstate vyjadrujú to isté, existujú rozumné programátorské dôvody pre toto rozhodnutie. V praxi tento prístup umožňuje pandas dosiahnuť dobrý kompromis vo väčšine prípadov. Napriek tomu však `None` aj `NaN` majú obmedzenia, na ktoré si musíte dávať pozor, pokiaľ ide o ich použitie.\n" ] }, { @@ -616,7 +616,7 @@ }, "source": [ "### `None`: nečíselné chýbajúce údaje\n", - "Keďže `None` pochádza z Pythonu, nemôže byť použitý v poliach NumPy a pandas, ktoré nemajú dátový typ `'object'`. Pamätajte, že polia NumPy (a dátové štruktúry v pandas) môžu obsahovať iba jeden typ údajov. Práve toto im dáva obrovskú silu pri práci s veľkými dátami a výpočtami, no zároveň to obmedzuje ich flexibilitu. Takéto polia musia byť \"povýšené\" na „najnižší spoločný menovateľ“, teda dátový typ, ktorý dokáže obsiahnuť všetko v poli. Ak je v poli `None`, znamená to, že pracujete s Python objektmi.\n", + "Keďže `None` pochádza z Pythonu, nemôže byť použitý v poliach NumPy a pandas, ktoré nemajú dátový typ `'object'`. Pamätajte, že polia NumPy (a dátové štruktúry v pandas) môžu obsahovať iba jeden typ údajov. Práve to im dáva obrovskú silu pri práci s veľkými dátami a výpočtovými operáciami, ale zároveň obmedzuje ich flexibilitu. Takéto polia musia byť pretypované na „najnižší spoločný menovateľ“, teda dátový typ, ktorý zahŕňa všetko v poli. Keď sa v poli nachádza `None`, znamená to, že pracujete s Python objektmi.\n", "\n", "Aby ste to videli v praxi, zvážte nasledujúce príkladové pole (všimnite si jeho `dtype`):\n" ] @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Realita povýšených dátových typov prináša so sebou dva vedľajšie účinky. Po prvé, operácie sa budú vykonávať na úrovni interpretovaného Python kódu namiesto skompilovaného NumPy kódu. V podstate to znamená, že akékoľvek operácie zahŕňajúce `Series` alebo `DataFrames`, ktoré obsahujú `None`, budú pomalšie. Aj keď si tento pokles výkonu pravdepodobne nevšimnete, pri veľkých datasetoch by to mohlo predstavovať problém.\n", + "Realita upcastovaných dátových typov prináša so sebou dva vedľajšie účinky. Po prvé, operácie sa budú vykonávať na úrovni interpretovaného Python kódu namiesto skompilovaného NumPy kódu. V podstate to znamená, že akékoľvek operácie zahŕňajúce `Series` alebo `DataFrames`, ktoré obsahujú `None`, budú pomalšie. Aj keď si tento pokles výkonu pravdepodobne nevšimnete, pri veľkých datasetoch by to mohlo predstavovať problém.\n", "\n", - "Druhý vedľajší účinok vyplýva z prvého. Keďže `None` v podstate vracia `Series` alebo `DataFrame`s späť do sveta základného Pythonu, použitie agregácií NumPy/pandas, ako napríklad `sum()` alebo `min()`, na poliach obsahujúcich hodnotu `None` vo všeobecnosti spôsobí chybu:\n" + "Druhý vedľajší účinok vyplýva z prvého. Keďže `None` v podstate vracia `Series` alebo `DataFrame` späť do sveta obyčajného Pythonu, použitie agregácií NumPy/pandas, ako napríklad `sum()` alebo `min()`, na poliach obsahujúcich hodnotu ``None`` vo všeobecnosti spôsobí chybu:\n" ] }, { @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**Hlavný bod**: Sčítanie (a iné operácie) medzi celými číslami a hodnotami `None` je nedefinované, čo môže obmedziť možnosti práce s dátovými súbormi, ktoré ich obsahujú.\n" + ] }, { "cell_type": "markdown", @@ -707,7 +709,7 @@ "source": [ "### `NaN`: chýbajúce hodnoty typu float\n", "\n", - "Na rozdiel od `None`, NumPy (a teda aj pandas) podporuje `NaN` pre svoje rýchle, vektorové operácie a ufuncs. Zlou správou je, že akákoľvek aritmetická operácia vykonaná na `NaN` vždy vedie k výsledku `NaN`. Napríklad:\n" + "Na rozdiel od `None`, NumPy (a teda aj pandas) podporuje `NaN` pre svoje rýchle, vektorové operácie a ufuncs. Nevýhodou je, že akákoľvek aritmetická operácia vykonaná na `NaN` vždy vedie k výsledku `NaN`. Napríklad:\n" ] }, { @@ -770,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Dobrá správa: agregácie spustené na poliach s `NaN` v nich nespôsobujú chyby. Zlá správa: výsledky nie sú jednotne užitočné:\n" + "Dobrá správa: agregácie vykonávané na poliach s `NaN` v nich nevyhadzujú chyby. Zlá správa: výsledky nie sú jednotne užitočné:\n" ] }, { @@ -806,7 +808,9 @@ "metadata": { "id": "nhlnNJT7gRr_" }, - "source": [] + "source": [ + "### Cvičenie:\n" + ] }, { "cell_type": "code", @@ -826,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "Pamätajte: `NaN` je len pre chýbajúce hodnoty s pohyblivou desatinnou čiarkou; neexistuje ekvivalent `NaN` pre celé čísla, reťazce alebo Booleovské hodnoty.\n" + ] }, { "cell_type": "markdown", @@ -836,7 +842,7 @@ "source": [ "### `NaN` a `None`: nulové hodnoty v pandas\n", "\n", - "Aj keď sa `NaN` a `None` môžu správať trochu odlišne, pandas je navrhnutý tak, aby ich spracovával zameniteľne. Aby sme to ukázali, pozrime sa na `Series` celých čísel:\n" + "Aj keď sa `NaN` a `None` môžu správať trochu odlišne, pandas je navrhnutý tak, aby s nimi pracoval zameniteľne. Aby sme si to ukázali, pozrime sa na `Series` celých čísel:\n" ] }, { @@ -875,7 +881,9 @@ "metadata": { "id": "WklCzqb8gRsB" }, - "source": [] + "source": [ + "### Cvičenie:\n" + ] }, { "cell_type": "code", @@ -898,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Pri upgradovaní dátových typov na zabezpečenie homogénnosti údajov v `Series` a `DataFrame`s, pandas ochotne prepína chýbajúce hodnoty medzi `None` a `NaN`. Kvôli tejto dizajnovej vlastnosti môže byť užitočné vnímať `None` a `NaN` ako dva rôzne typy \"null\" hodnôt v pandas. V skutočnosti niektoré základné metódy, ktoré budete používať na prácu s chýbajúcimi hodnotami v pandas, túto myšlienku odrážajú vo svojich názvoch:\n", + "Pri procese zjednocovania dátových typov na zabezpečenie homogénnosti dát v `Series` a `DataFrame`s pandas ochotne prepína chýbajúce hodnoty medzi `None` a `NaN`. Vďaka tejto vlastnosti dizajnu môže byť užitočné vnímať `None` a `NaN` ako dva rôzne typy \"nulových\" hodnôt v pandas. Skutočne, niektoré základné metódy, ktoré budete používať na prácu s chýbajúcimi hodnotami v pandas, túto myšlienku odrážajú vo svojich názvoch:\n", "\n", - "- `isnull()`: Generuje Booleovskú masku označujúcu chýbajúce hodnoty\n", + "- `isnull()`: Vytvára Booleovskú masku označujúcu chýbajúce hodnoty\n", "- `notnull()`: Opak metódy `isnull()`\n", - "- `dropna()`: Vráti filtrovanú verziu údajov\n", - "- `fillna()`: Vráti kópiu údajov s vyplnenými alebo imputovanými chýbajúcimi hodnotami\n", + "- `dropna()`: Vracia filtrovanú verziu dát\n", + "- `fillna()`: Vracia kópiu dát s vyplnenými alebo imputovanými chýbajúcimi hodnotami\n", "\n", - "Tieto metódy sú dôležité na zvládnutie a získanie istoty pri ich používaní, preto si ich prejdime podrobnejšie.\n" + "Tieto metódy sú dôležité na zvládnutie a pohodlné používanie, preto si ich prejdime podrobnejšie.\n" ] }, { @@ -916,8 +924,7 @@ "source": [ "### Detekcia nulových hodnôt\n", "\n", - "Teraz, keď sme pochopili dôležitosť chýbajúcich hodnôt, musíme ich v našej dátovej sade najskôr odhaliť, než s nimi začneme pracovať. \n", - "Metódy `isnull()` a `notnull()` sú vaše hlavné nástroje na detekciu nulových údajov. Obe vracajú Booleovské masky nad vašimi údajmi.\n" + "Teraz, keď sme pochopili význam chýbajúcich hodnôt, musíme ich najskôr identifikovať v našej dátovej sade, než s nimi začneme pracovať. Metódy `isnull()` a `notnull()` sú vaše hlavné nástroje na detekciu nulových údajov. Obe vracajú Booleovské masky nad vašimi údajmi.\n" ] }, { @@ -970,11 +977,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Pozorne sa pozrite na výstup. Prekvapilo vás niečo? Aj keď `0` je aritmetická nula, stále je to úplne platné celé číslo a pandas ho tak aj považuje. `''` je o niečo jemnejšie. Aj keď sme ho v časti 1 použili na reprezentáciu prázdnej textovej hodnoty, stále ide o objekt typu string a nie o reprezentáciu nulovej hodnoty z pohľadu pandas.\n", + "Pozrite sa pozorne na výstup. Prekvapilo vás niečo? Aj keď `0` je aritmetická nula, stále je to úplne platné celé číslo a pandas ho tak aj považuje. `''` je trochu jemnejší prípad. Aj keď sme ho v sekcii 1 použili na reprezentáciu prázdnej hodnoty reťazca, stále ide o objekt typu reťazec a pandas ho nepovažuje za reprezentáciu nulovej hodnoty.\n", "\n", - "Teraz to otočme a použime tieto metódy spôsobom, akým ich budete používať v praxi. Boolean masky môžete použiť priamo ako index ``Series`` alebo ``DataFrame``, čo môže byť užitočné pri práci s izolovanými chýbajúcimi (alebo prítomnými) hodnotami.\n", + "Teraz to otočíme a použijeme tieto metódy spôsobom, akým ich budete používať v praxi. Boolean masky môžete použiť priamo ako index pre ``Series`` alebo ``DataFrame``, čo môže byť užitočné pri práci s izolovanými chýbajúcimi (alebo prítomnými) hodnotami.\n", "\n", - "Ak chceme zistiť celkový počet chýbajúcich hodnôt, stačí nám urobiť súčet nad maskou, ktorú vytvorí metóda `isnull()`.\n" + "Ak chceme získať celkový počet chýbajúcich hodnôt, stačí vykonať súčet nad maskou, ktorú vytvorí metóda `isnull()`.\n" ] }, { @@ -1008,7 +1015,9 @@ "metadata": { "id": "PlBqEo3mgRsC" }, - "source": [] + "source": [ + "### Cvičenie:\n" + ] }, { "cell_type": "code", @@ -1030,7 +1039,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Hlavný bod**: Metódy `isnull()` a `notnull()` prinášajú podobné výsledky, keď ich použijete v DataFrame: zobrazujú výsledky a index týchto výsledkov, čo vám nesmierne pomôže pri práci s vašimi údajmi.\n" + "**Hlavný bod**: Metódy `isnull()` a `notnull()` produkujú podobné výsledky, keď ich použijete v DataFrame: zobrazujú výsledky a index týchto výsledkov, čo vám môže výrazne pomôcť pri práci s vašimi údajmi.\n" ] }, { @@ -1039,15 +1048,15 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### Riešenie chýbajúcich údajov\n", + "### Práca s chýbajúcimi údajmi\n", "\n", "> **Cieľ učenia:** Na konci tejto podsekcie by ste mali vedieť, ako a kedy nahradiť alebo odstrániť nulové hodnoty z DataFrames.\n", "\n", - "Modely strojového učenia nedokážu samy pracovať s chýbajúcimi údajmi. Preto je potrebné pred odovzdaním údajov do modelu vyriešiť tieto chýbajúce hodnoty.\n", + "Modely strojového učenia nedokážu samy pracovať s chýbajúcimi údajmi. Preto je potrebné pred odovzdaním údajov do modelu tieto chýbajúce hodnoty spracovať.\n", "\n", - "Spôsob, akým sa chýbajúce údaje riešia, prináša jemné kompromisy a môže ovplyvniť vašu konečnú analýzu a výsledky v reálnom svete.\n", + "Spôsob, akým sa chýbajúce údaje riešia, prináša jemné kompromisy, ktoré môžu ovplyvniť vašu konečnú analýzu a výsledky v reálnom svete.\n", "\n", - "Existujú dva hlavné spôsoby riešenia chýbajúcich údajov:\n", + "Existujú dva hlavné spôsoby, ako sa vysporiadať s chýbajúcimi údajmi:\n", "\n", "1. Odstrániť riadok obsahujúci chýbajúcu hodnotu\n", "2. Nahradiť chýbajúcu hodnotu inou hodnotou\n", @@ -1063,7 +1072,7 @@ "source": [ "### Odstraňovanie nulových hodnôt\n", "\n", - "Množstvo údajov, ktoré posúvame do nášho modelu, má priamy vplyv na jeho výkon. Odstraňovanie nulových hodnôt znamená, že znižujeme počet dátových bodov, a tým aj veľkosť datasetu. Preto je vhodné odstrániť riadky s nulovými hodnotami, keď je dataset pomerne veľký.\n", + "Množstvo údajov, ktoré poskytneme nášmu modelu, má priamy vplyv na jeho výkon. Odstraňovanie nulových hodnôt znamená, že znižujeme počet dátových bodov, a tým aj veľkosť datasetu. Preto je vhodné odstrániť riadky s nulovými hodnotami, keď je dataset pomerne veľký.\n", "\n", "Ďalším prípadom môže byť situácia, keď určitý riadok alebo stĺpec obsahuje veľa chýbajúcich hodnôt. V takom prípade ich možno odstrániť, pretože by nepriniesli veľkú hodnotu do našej analýzy, keďže väčšina údajov pre daný riadok/stĺpec chýba.\n", "\n", @@ -1108,7 +1117,7 @@ "source": [ "Všimnite si, že toto by malo vyzerať ako váš výstup z `example3[example3.notnull()]`. Rozdiel je v tom, že namiesto indexovania na základe maskovaných hodnôt, `dropna` odstránil tieto chýbajúce hodnoty zo `Series` `example3`.\n", "\n", - "Keďže DataFrames majú dve dimenzie, ponúkajú viac možností na odstraňovanie údajov.\n" + "Keďže DataFrames majú dve dimenzie, ponúkajú viac možností na odstránenie údajov.\n" ] }, { @@ -1200,7 +1209,7 @@ "source": [ "(Všimli ste si, že pandas zmenil typ dvoch stĺpcov na float, aby mohli obsahovať hodnoty `NaN`?)\n", "\n", - "Nemôžete odstrániť jednu hodnotu z `DataFrame`, takže musíte odstrániť celé riadky alebo stĺpce. V závislosti od toho, čo robíte, môžete chcieť vykonať jedno alebo druhé, a preto vám pandas poskytuje možnosti pre obe. Keďže v dátovej vede stĺpce zvyčajne predstavujú premenné a riadky predstavujú pozorovania, je pravdepodobnejšie, že budete odstraňovať riadky dát; predvolené nastavenie pre `dropna()` je odstrániť všetky riadky, ktoré obsahujú akékoľvek nulové hodnoty:\n" + "Nie je možné odstrániť jednu hodnotu z `DataFrame`, takže musíte odstrániť celé riadky alebo stĺpce. V závislosti od toho, čo robíte, môžete chcieť použiť jednu alebo druhú možnosť, a preto vám pandas ponúka obe. Keďže v dátovej vede stĺpce zvyčajne predstavujú premenné a riadky predstavujú pozorovania, častejšie budete odstraňovať riadky dát; predvolené nastavenie pre `dropna()` je odstrániť všetky riadky, ktoré obsahujú akékoľvek nulové hodnoty:\n" ] }, { @@ -1273,7 +1282,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "Ak je to potrebné, môžete odstrániť hodnoty NA zo stĺpcov. Použite `axis=1` na to:\n" + "Ak je to potrebné, môžete odstrániť hodnoty NA zo stĺpcov. Použite `axis=1` na tento účel:\n" ] }, { @@ -1352,9 +1361,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Upozorňujeme, že toto môže odstrániť veľa údajov, ktoré by ste mohli chcieť zachovať, najmä v menších datasetoch. Čo ak chcete odstrániť iba riadky alebo stĺpce, ktoré obsahujú niekoľko alebo dokonca všetky nulové hodnoty? Tieto nastavenia môžete špecifikovať v `dropna` pomocou parametrov `how` a `thresh`.\n", + "Všimnite si, že týmto spôsobom môžete odstrániť veľa údajov, ktoré by ste možno chceli zachovať, najmä v menších súboroch údajov. Čo ak chcete odstrániť iba riadky alebo stĺpce, ktoré obsahujú niekoľko alebo dokonca všetky nulové hodnoty? Tieto nastavenia môžete špecifikovať v `dropna` pomocou parametrov `how` a `thresh`.\n", "\n", - "Predvolene je nastavené `how='any'` (ak by ste si to chceli overiť sami alebo zistiť, aké ďalšie parametre táto metóda má, spustite `example4.dropna?` v bunkách kódu). Alternatívne môžete špecifikovať `how='all'`, aby sa odstránili iba riadky alebo stĺpce, ktoré obsahujú všetky nulové hodnoty. Rozšírme náš príklad `DataFrame`, aby sme si to ukázali v praxi v nasledujúcom cvičení.\n" + "Predvolene je nastavené `how='any'` (ak si to chcete sami overiť alebo zistiť, aké ďalšie parametre má táto metóda, spustite `example4.dropna?` v bunkách kódu). Alternatívne môžete špecifikovať `how='all'`, aby ste odstránili iba riadky alebo stĺpce, ktoré obsahujú všetky nulové hodnoty. Rozšírime náš príklad `DataFrame`, aby sme si to ukázali v praxi v nasledujúcom cvičení.\n" ] }, { @@ -1446,11 +1455,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> Kľúčové poznatky: \n", - "1. Odstraňovanie nulových hodnôt je dobrý nápad iba v prípade, že dataset je dostatočne veľký. \n", - "2. Celé riadky alebo stĺpce môžu byť odstránené, ak im chýba väčšina údajov. \n", - "3. Metóda `DataFrame.dropna(axis=)` pomáha pri odstraňovaní nulových hodnôt. Argument `axis` určuje, či sa majú odstrániť riadky alebo stĺpce. \n", - "4. Môže sa použiť aj argument `how`. Predvolene je nastavený na hodnotu `any`. To znamená, že odstráni iba tie riadky/stĺpce, ktoré obsahujú akékoľvek nulové hodnoty. Môže byť nastavený na hodnotu `all`, aby sa špecifikovalo, že odstránime iba tie riadky/stĺpce, kde sú všetky hodnoty nulové. \n" + "> Hlavné body: \n", + "1. Odstránenie nulových hodnôt je dobrý nápad iba v prípade, že dataset je dostatočne veľký.\n", + "2. Celé riadky alebo stĺpce môžu byť odstránené, ak väčšina ich údajov chýba.\n", + "3. Metóda `DataFrame.dropna(axis=)` pomáha pri odstraňovaní nulových hodnôt. Argument `axis` určuje, či sa majú odstrániť riadky alebo stĺpce.\n", + "4. Môže sa použiť aj argument `how`. Predvolene je nastavený na hodnotu `any`. Takže odstraňuje iba tie riadky/stĺpce, ktoré obsahujú akékoľvek nulové hodnoty. Môže byť nastavený na hodnotu `all`, aby sa špecifikovalo, že odstránime iba tie riadky/stĺpce, kde sú všetky hodnoty nulové.\n" ] }, { @@ -1458,7 +1467,9 @@ "metadata": { "id": "oXXSfQFHgRsF" }, - "source": [] + "source": [ + "### Cvičenie:\n" + ] }, { "cell_type": "code", @@ -1554,7 +1565,9 @@ "metadata": { "id": "fmSFnzZegRsG" }, - "source": [] + "source": [ + "Tu boli prvý a posledný riadok vynechané, pretože obsahujú iba dve nenulové hodnoty.\n" + ] }, { "cell_type": "markdown", @@ -1564,9 +1577,9 @@ "source": [ "### Vyplnenie nulových hodnôt\n", "\n", - "Niekedy má zmysel vyplniť chýbajúce hodnoty takými, ktoré by mohli byť platné. Existuje niekoľko techník na vyplnenie nulových hodnôt. Prvou je použitie doménových znalostí (znalostí o téme, na ktorej je dataset založený) na približné určenie chýbajúcich hodnôt.\n", + "Niekedy má zmysel vyplniť chýbajúce hodnoty takými, ktoré by mohli byť platné. Existuje niekoľko techník na vyplnenie nulových hodnôt. Prvou je použitie znalostí z danej oblasti (znalosti témy, na ktorej je dataset založený) na približné určenie chýbajúcich hodnôt.\n", "\n", - "Môžete použiť `isnull` na vykonanie tejto operácie priamo, ale to môže byť zdĺhavé, najmä ak máte veľa hodnôt na vyplnenie. Keďže ide o tak bežnú úlohu v dátovej vede, pandas poskytuje funkciu `fillna`, ktorá vráti kópiu `Series` alebo `DataFrame` s chýbajúcimi hodnotami nahradenými hodnotami podľa vášho výberu. Vytvorme si ďalší príklad `Series`, aby sme videli, ako to funguje v praxi.\n" + "Môžete použiť `isnull` na vykonanie tejto operácie priamo, ale to môže byť zdĺhavé, najmä ak máte veľa hodnôt na vyplnenie. Keďže ide o tak bežnú úlohu v dátovej vede, pandas poskytuje funkciu `fillna`, ktorá vráti kópiu `Series` alebo `DataFrame` s chýbajúcimi hodnotami nahradenými hodnotami podľa vášho výberu. Vytvorme ďalší príklad `Series`, aby sme videli, ako to funguje v praxi.\n" ] }, { @@ -1685,7 +1698,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Teraz najprv nájdime modus pred vyplnením hodnoty `None` modusom.\n" + ] }, { "cell_type": "code", @@ -1720,7 +1735,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Takže, nahradíme None hodnotou True\n" + ] }, { "cell_type": "code", @@ -1845,9 +1862,9 @@ "1. Nahradiť mediánom riadku\n", "2. Nahradiť priemerom riadku\n", "\n", - "Medián používame v prípade, že údaje sú skreslené a obsahujú odľahlé hodnoty. Je to preto, že medián je odolný voči odľahlým hodnotám.\n", + "Medián používame v prípade skreslených údajov s odľahlými hodnotami. Je to preto, že medián je odolný voči odľahlým hodnotám.\n", "\n", - "Keď sú údaje normalizované, môžeme použiť priemer, pretože v takom prípade budú priemer a medián veľmi podobné.\n", + "Keď sú údaje normalizované, môžeme použiť priemer, pretože v takom prípade by priemer a medián boli veľmi podobné.\n", "\n", "Najprv si vezmime stĺpec, ktorý má normálne rozdelenie, a vyplňme chýbajúce hodnoty priemerom stĺpca.\n" ] @@ -1989,7 +2006,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Vyplnenie priemerom\n" + ] }, { "cell_type": "code", @@ -2089,7 +2108,7 @@ "id": "CwpVFCrPTC5z" }, "source": [ - "Ako môžeme vidieť, chýbajúca hodnota bola nahradená jej priemerom.\n" + "Ako vidíme, chýbajúca hodnota bola nahradená jej priemerom.\n" ] }, { @@ -2098,7 +2117,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Teraz vyskúšajme ďalší dataframe a tentokrát nahradíme hodnoty None mediánom stĺpca.\n" + "Teraz vyskúšajme ďalší dataframe, a tentokrát nahradíme hodnoty None mediánom stĺpca.\n" ] }, { @@ -2238,7 +2257,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Vyplnenie mediánom\n" + ] }, { "cell_type": "code", @@ -2338,7 +2359,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Ako môžeme vidieť, hodnota NaN bola nahradená mediánom stĺpca\n" + "Ako môžeme vidieť, hodnota NaN bola nahradená mediánom stĺpca.\n" ] }, { @@ -2380,7 +2401,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "Všetky prázdne položky môžete vyplniť jednou hodnotou, napríklad `0`:\n" + "Môžete vyplniť všetky prázdne položky jednou hodnotou, napríklad `0`:\n" ] }, { @@ -2422,10 +2443,10 @@ }, "source": [ "> Hlavné body:\n", - "1. Dopĺňanie chýbajúcich hodnôt by sa malo vykonávať buď v prípade, že je málo údajov, alebo ak existuje stratégia na doplnenie chýbajúcich údajov.\n", - "2. Na doplnenie chýbajúcich hodnôt je možné využiť znalosti z danej oblasti a odhadnúť ich.\n", - "3. Pri kategóriálnych údajoch sa chýbajúce hodnoty najčastejšie nahrádzajú módou stĺpca.\n", - "4. Pri číselných údajoch sa chýbajúce hodnoty zvyčajne dopĺňajú priemerom (pre normalizované datasety) alebo mediánom stĺpcov.\n" + "1. Dopĺňanie chýbajúcich hodnôt by sa malo vykonávať, keď je k dispozícii menej údajov alebo existuje stratégia na ich doplnenie.\n", + "2. Na dopĺňanie chýbajúcich hodnôt je možné využiť odborné znalosti z danej oblasti, a to ich približným odhadom.\n", + "3. Pri kategorizovaných údajoch sa chýbajúce hodnoty najčastejšie nahrádzajú módou stĺpca.\n", + "4. Pri číselných údajoch sa chýbajúce hodnoty zvyčajne dopĺňajú priemerom (pri normalizovaných datasetoch) alebo mediánom stĺpcov.\n" ] }, { @@ -2433,7 +2454,9 @@ "metadata": { "id": "FI9MmqFJgRsH" }, - "source": [] + "source": [ + "### Cvičenie:\n" + ] }, { "cell_type": "code", @@ -2453,7 +2476,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "Môžete **dopĺňať dopredu** nulové hodnoty, čo znamená použiť poslednú platnú hodnotu na vyplnenie nulovej hodnoty:\n" + ] }, { "cell_type": "code", @@ -2493,7 +2518,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Môžete tiež **spätne doplniť**, aby ste spätne propagovali ďalšiu platnú hodnotu na vyplnenie null:\n" + "Môžete tiež **dopĺňať späť**, aby ste propagovali nasledujúcu platnú hodnotu dozadu na vyplnenie null:\n" ] }, { @@ -2708,7 +2733,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Všimnite si, že keď nie je k dispozícii predchádzajúca hodnota na doplnenie, zostáva nulová hodnota.\n" + "Všimnite si, že keď predchádzajúca hodnota nie je dostupná na doplnenie, nulová hodnota zostáva.\n" ] }, { @@ -2716,7 +2741,9 @@ "metadata": { "id": "eeAoOU0RgRsJ" }, - "source": [] + "source": [ + "### Cvičenie:\n" + ] }, { "cell_type": "code", @@ -2739,7 +2766,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Môžete byť kreatívni pri používaní `fillna`. Napríklad sa pozrime znova na `example4`, ale tentokrát vyplňme chýbajúce hodnoty priemerom všetkých hodnôt v `DataFrame`:\n" + "Môžete byť kreatívni pri používaní `fillna`. Napríklad sa pozrime na `example4` znova, ale tentokrát vyplňme chýbajúce hodnoty priemerom všetkých hodnôt v `DataFrame`:\n" ] }, { @@ -2832,7 +2859,7 @@ "source": [ "Všimnite si, že stĺpec 3 je stále bez hodnoty: predvolený smer je vyplniť hodnoty po riadkoch.\n", "\n", - "> **Poučenie:** Existuje viacero spôsobov, ako sa vysporiadať s chýbajúcimi hodnotami vo vašich dátových súboroch. Konkrétna stratégia, ktorú použijete (odstránenie, nahradenie alebo spôsob, akým ich nahradíte), by mala byť určená špecifikami daných dát. Lepší zmysel pre prácu s chýbajúcimi hodnotami si vyviniete čím viac budete pracovať a interagovať s dátovými súbormi.\n" + "> **Poučenie:** Existuje viacero spôsobov, ako sa vysporiadať s chýbajúcimi hodnotami vo vašich dátových súboroch. Konkrétna stratégia, ktorú použijete (odstránenie, nahradenie alebo dokonca spôsob, akým ich nahradíte), by mala byť určená špecifikami daných dát. Lepší cit pre riešenie chýbajúcich hodnôt si vyviniete postupne, čím viac budete pracovať a interagovať s dátovými súbormi.\n" ] }, { @@ -2843,9 +2870,9 @@ "source": [ "### Kódovanie kategóriálnych údajov\n", "\n", - "Modely strojového učenia pracujú iba s číslami a akoukoľvek formou číselných údajov. Nebudú schopné rozlíšiť medzi Áno a Nie, ale dokážu rozlíšiť medzi 0 a 1. Preto po doplnení chýbajúcich hodnôt musíme kategóriálne údaje zakódovať do nejakej číselnej formy, aby ich model pochopil.\n", + "Modely strojového učenia pracujú iba s číslami a akoukoľvek formou číselných údajov. Nedokážu rozlíšiť medzi Áno a Nie, ale dokážu rozlíšiť medzi 0 a 1. Preto po doplnení chýbajúcich hodnôt musíme kategóriálne údaje zakódovať do nejakej číselnej formy, aby ich model pochopil.\n", "\n", - "Kódovanie je možné vykonať dvoma spôsobmi. Budeme ich diskutovať ďalej.\n" + "Kódovanie je možné vykonať dvoma spôsobmi. Budeme ich rozoberať ďalej.\n" ] }, { @@ -2856,7 +2883,7 @@ "source": [ "**KÓDOVANIE ŠTÍTKA**\n", "\n", - "Kódovanie štítka v podstate znamená prevod každej kategórie na číslo. Napríklad, povedzme, že máme dataset leteckých pasažierov a je tu stĺpec obsahujúci ich triedu medzi nasledujúcimi ['business class', 'economy class', 'first class']. Ak sa vykoná kódovanie štítka, bude to transformované na [0,1,2]. Pozrime sa na príklad pomocou kódu. Keďže sa budeme učiť `scikit-learn` v nadchádzajúcich poznámkových blokoch, tu ho nepoužijeme.\n" + "Kódovanie štítka spočíva v konverzii každej kategórie na číslo. Napríklad, povedzme, že máme dataset cestujúcich leteckej spoločnosti a je tu stĺpec obsahujúci ich triedu medzi nasledujúcimi ['business class', 'economy class', 'first class']. Ak sa vykoná kódovanie štítka, bude to transformované na [0,1,2]. Pozrime sa na príklad pomocou kódu. Keďže sa budeme učiť `scikit-learn` v nadchádzajúcich poznámkach, tu ho nepoužijeme.\n" ] }, { @@ -2964,7 +2991,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Na vykonanie kódovania štítkov v 1. stĺpci musíme najprv opísať mapovanie z každej triedy na číslo, predtým ako nahradíme\n" + "Na vykonanie kódovania štítkov na 1. stĺpci musíme najskôr opísať mapovanie z každej triedy na číslo, predtým ako nahradíme.\n" ] }, { @@ -3066,7 +3093,7 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Ako vidíme, výsledok zodpovedá tomu, čo sme očakávali. Takže, kedy používame kódovanie štítkov? Kódovanie štítkov sa používa v jednej alebo oboch z nasledujúcich situácií:\n", + "Ako vidíme, výstup zodpovedá tomu, čo sme očakávali. Kedy teda používame kódovanie štítkov? Kódovanie štítkov sa používa v jednej alebo oboch z nasledujúcich situácií:\n", "1. Keď je počet kategórií veľký\n", "2. Keď sú kategórie usporiadané.\n" ] @@ -3077,11 +3104,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**JEDNOHORÚCE KÓDOVANIE**\n", + "**ONE HOT ENCODING**\n", "\n", - "Ďalším typom kódovania je Jednohorúce kódovanie. Pri tomto type kódovania sa každá kategória stĺpca pridá ako samostatný stĺpec a každému dátovému bodu sa priradí 0 alebo 1 podľa toho, či obsahuje danú kategóriu. Ak teda existuje n rôznych kategórií, do dátového rámca sa pridá n stĺpcov.\n", + "Ďalším typom kódovania je One Hot Encoding. Pri tomto type kódovania sa každá kategória stĺpca pridá ako samostatný stĺpec a každému dátovému bodu sa priradí 0 alebo 1 podľa toho, či obsahuje danú kategóriu. Ak teda existuje n rôznych kategórií, do dátového rámca sa pridá n stĺpcov.\n", "\n", - "Napríklad, vezmime si ten istý príklad triedy lietadla. Kategórie boli: ['business class', 'economy class', 'first class']. Ak vykonáme jednohorúce kódovanie, do datasetu sa pridajú nasledujúce tri stĺpce: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Napríklad, vezmime si ten istý príklad triedy lietadla. Kategórie boli: ['business class', 'economy class', 'first class']. Ak vykonáme One Hot Encoding, do datasetu sa pridajú nasledujúce tri stĺpce: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3189,7 +3216,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "Poďme vykonať one hot encoding na 1. stĺpci\n" + "Poďme vykonať one hot encoding na prvom stĺpci\n" ] }, { @@ -3314,7 +3341,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Každý stĺpec s jedným horúcim kódovaním obsahuje 0 alebo 1, čo určuje, či daná kategória existuje pre daný dátový bod.\n" + "Každý stĺpec s one-hot kódovaním obsahuje 0 alebo 1, čo určuje, či daná kategória existuje pre daný dátový bod.\n" ] }, { @@ -3335,9 +3362,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Kľúčové poznatky: \n", - "1. Kódovanie sa vykonáva na prevod nenumerických údajov na numerické údaje. \n", - "2. Existujú dva typy kódovania: Label encoding a One Hot encoding, pričom oba môžu byť použité podľa požiadaviek datasetu. \n" + "> Hlavné body:\n", + "1. Kódovanie sa vykonáva na konverziu nenumerických údajov na numerické údaje.\n", + "2. Existujú dva typy kódovania: Label encoding a One Hot encoding, ktoré je možné vykonať podľa požiadaviek datasetu.\n" ] }, { @@ -3350,7 +3377,7 @@ "\n", "> **Cieľ učenia:** Na konci tejto podsekcie by ste mali byť schopní identifikovať a odstrániť duplicitné hodnoty z DataFrames.\n", "\n", - "Okrem chýbajúcich údajov sa často stretnete s duplicitnými údajmi v reálnych datasetoch. Našťastie, pandas poskytuje jednoduchý spôsob na detekciu a odstránenie duplicitných záznamov.\n" + "Okrem chýbajúcich údajov sa v reálnych dátových súboroch často stretnete s duplicitnými údajmi. Našťastie, pandas poskytuje jednoduchý spôsob na detekciu a odstránenie duplicitných záznamov.\n" ] }, { @@ -3574,7 +3601,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Oba `duplicated` a `drop_duplicates` štandardne zohľadňujú všetky stĺpce, ale môžete špecifikovať, aby skúmali iba podmnožinu stĺpcov vo vašom `DataFrame`:\n" + "Obe funkcie `duplicated` a `drop_duplicates` štandardne zohľadňujú všetky stĺpce, ale môžete špecifikovať, aby skúmali iba podmnožinu stĺpcov vo vašom `DataFrame`:\n" ] }, { @@ -3650,13 +3677,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Poučenie:** Odstránenie duplicitných údajov je nevyhnutnou súčasťou takmer každého projektu v oblasti dátovej vedy. Duplicitné údaje môžu zmeniť výsledky vašich analýz a poskytnúť vám nepresné výsledky!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Kontroly kvality údajov v reálnom svete\n", + "\n", + "> **Cieľ učenia:** Na konci tejto sekcie by ste mali byť schopní identifikovať a opraviť bežné problémy s kvalitou údajov v reálnom svete, vrátane nekonzistentných kategórií, abnormálnych číselných hodnôt (extrémnych hodnôt) a duplicitných entít s variáciami.\n", + "\n", + "Aj keď chýbajúce hodnoty a presné duplikáty sú bežné problémy, dátové súbory v reálnom svete často obsahujú jemnejšie problémy:\n", + "\n", + "1. **Nekonzistentné kategórie**: Rovnaká kategória napísaná rôznymi spôsobmi (napr. \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Abnormálne číselné hodnoty**: Extrémne hodnoty, ktoré naznačujú chyby pri zadávaní údajov (napr. vek = 999)\n", + "3. **Takmer duplicitné riadky**: Záznamy, ktoré predstavujú tú istú entitu s miernymi variáciami\n", + "\n", + "Poďme preskúmať techniky na identifikáciu a riešenie týchto problémov.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Vytvorenie ukážkového „nečistého“ datasetu\n", + "\n", + "Najskôr si vytvoríme ukážkový dataset, ktorý obsahuje typy problémov, s ktorými sa často stretávame v reálnych dátach:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Detekcia nekonzistentných kategóriálnych hodnôt\n", + "\n", + "Všimnite si, že stĺpec `country` má viacero reprezentácií pre tie isté krajiny. Poďme identifikovať tieto nekonzistencie:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Štandardizácia kategóriálnych hodnôt\n", + "\n", + "Môžeme vytvoriť mapovanie na štandardizáciu týchto hodnôt. Jednoduchý prístup je konvertovať na malé písmená a vytvoriť mapovaciu slovník:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternatíva: Použitie nepresného porovnávania**\n", + "\n", + "Pre zložitejšie prípady môžeme použiť nepresné porovnávanie reťazcov s knižnicou `rapidfuzz` na automatickú detekciu podobných reťazcov:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Detekcia abnormálnych číselných hodnôt (odľahlých hodnôt)\n", + "\n", + "Pri pohľade na stĺpec `age` máme niektoré podozrivé hodnoty, ako napríklad 199 a -5. Použime štatistické metódy na detekciu týchto odľahlých hodnôt.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Použitie metódy IQR (Interkvartilový rozsah)\n", + "\n", + "Metóda IQR je robustná štatistická technika na detekciu odľahlých hodnôt, ktorá je menej citlivá na extrémne hodnoty:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Použitie metódy Z-skóre\n", + "\n", + "Metóda Z-skóre identifikuje odľahlé hodnoty na základe štandardných odchýlok od priemeru:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Riešenie odľahlých hodnôt\n", + "\n", + "Po ich identifikácii je možné odľahlé hodnoty riešiť niekoľkými spôsobmi:\n", + "1. **Odstrániť**: Vymazať riadky s odľahlými hodnotami (ak ide o chyby)\n", + "2. **Obmedziť**: Nahradiť hraničnými hodnotami\n", + "3. **Nahradiť NaN**: Považovať za chýbajúce údaje a použiť techniky imputácie\n", + "4. **Ponechať**: Ak ide o legitímne extrémne hodnoty\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Detekcia takmer duplicitných riadkov\n", + "\n", + "Všimnite si, že náš dataset obsahuje viacero záznamov pre \"John Smith\" s mierne odlišnými hodnotami. Poďme identifikovať potenciálne duplicity na základe podobnosti mien.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Hľadanie takmer duplicitných záznamov pomocou nepresného porovnávania\n", + "\n", + "Pre pokročilejšie zisťovanie duplicít môžeme použiť nepresné porovnávanie na nájdenie podobných mien:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Riešenie duplicít\n", + "\n", + "Keď ich identifikujete, musíte sa rozhodnúť, ako s nimi naložiť:\n", + "1. **Zachovať prvý výskyt**: Použite `drop_duplicates(keep='first')`\n", + "2. **Zachovať posledný výskyt**: Použite `drop_duplicates(keep='last')`\n", + "3. **Agregovať informácie**: Skombinovať informácie z duplicitných riadkov\n", + "4. **Manuálna kontrola**: Označiť na manuálne preskúmanie\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Zhrnutie: Kompletný proces čistenia dát\n", + "\n", + "Spojme všetko dohromady do komplexného procesu čistenia dát:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Výzva na cvičenie\n", + "\n", + "Teraz je rad na vás! Nižšie je nový riadok údajov s viacerými problémami s kvalitou. Dokážete:\n", + "\n", + "1. Identifikovať všetky problémy v tomto riadku\n", + "2. Napísať kód na opravu každého problému\n", + "3. Pridať opravený riadok do datasetu\n", + "\n", + "Tu sú problematické údaje:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Hlavné poznatky\n", + "\n", + "1. **Nekonzistentné kategórie** sú bežné v reálnych dátach. Vždy skontrolujte jedinečné hodnoty a štandardizujte ich pomocou mapovania alebo fuzzy porovnávania.\n", + "\n", + "2. **Extrémy** môžu výrazne ovplyvniť vašu analýzu. Na ich detekciu použite kombináciu odborných znalostí a štatistických metód (IQR, Z-score).\n", + "\n", + "3. **Takmer duplicitné údaje** sa ťažšie identifikujú ako presné duplikáty. Zvážte použitie fuzzy porovnávania a normalizácie údajov (zmenšenie písmen, odstránenie medzier) na ich identifikáciu.\n", + "\n", + "4. **Čistenie dát je iteratívny proces**. Možno budete musieť použiť viacero techník a preskúmať výsledky predtým, než dokončíte svoj vyčistený dataset.\n", + "\n", + "5. **Dokumentujte svoje rozhodnutia**. Sledujte, aké kroky čistenia ste aplikovali a prečo, pretože je to dôležité pre reprodukovateľnosť a transparentnosť.\n", + "\n", + "> **Najlepšia prax:** Vždy si ponechajte kópiu svojich pôvodných \"špinavých\" dát. Nikdy neprepíšte svoje zdrojové súbory - vytvorte vyčistené verzie s jasnými konvenciami pomenovania, ako napríklad `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Upozornenie**: \nTento dokument bol preložený pomocou služby na automatický preklad [Co-op Translator](https://github.com/Azure/co-op-translator). Hoci sa snažíme o presnosť, upozorňujeme, že automatické preklady môžu obsahovať chyby alebo nepresnosti. Pôvodný dokument v jeho pôvodnom jazyku by mal byť považovaný za autoritatívny zdroj. Pre kritické informácie sa odporúča profesionálny ľudský preklad. Nezodpovedáme za akékoľvek nedorozumenia alebo nesprávne interpretácie vyplývajúce z použitia tohto prekladu.\n" + "\n---\n\n**Upozornenie**: \nTento dokument bol preložený pomocou služby AI prekladu [Co-op Translator](https://github.com/Azure/co-op-translator). Hoci sa snažíme o presnosť, prosím, berte na vedomie, že automatizované preklady môžu obsahovať chyby alebo nepresnosti. Pôvodný dokument v jeho rodnom jazyku by mal byť považovaný za autoritatívny zdroj. Pre kritické informácie sa odporúča profesionálny ľudský preklad. Nenesieme zodpovednosť za akékoľvek nedorozumenia alebo nesprávne interpretácie vyplývajúce z použitia tohto prekladu.\n" ] } ], @@ -3684,8 +4229,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:49:02+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:59:22+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "sk" } diff --git a/translations/sl/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/sl/2-Working-With-Data/08-data-preparation/notebook.ipynb index 7e33e8cf..d7001a44 100644 --- a/translations/sl/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/sl/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -12,7 +12,7 @@ "\n", "## Raziskovanje informacij o `DataFrame`\n", "\n", - "> **Cilj učenja:** Do konca tega podpoglavja bi morali biti sposobni najti splošne informacije o podatkih, shranjenih v pandas DataFrame.\n", + "> **Cilj učenja:** Do konca tega podpoglavja bi morali biti sposobni pridobiti splošne informacije o podatkih, shranjenih v pandas DataFrame.\n", "\n", "Ko enkrat naložite svoje podatke v pandas, bodo najverjetneje shranjeni v `DataFrame`. Toda če ima vaš `DataFrame` 60.000 vrstic in 400 stolpcev, kako sploh začeti razumeti, s čim delate? Na srečo pandas ponuja nekaj priročnih orodij za hitro pregledovanje splošnih informacij o `DataFrame`, poleg prvih in zadnjih nekaj vrstic.\n", "\n", @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Podatkovni niz Iris smo naložili v spremenljivko `iris_df`. Preden se poglobimo v podatke, bi bilo koristno vedeti, koliko podatkovnih točk imamo in kakšna je skupna velikost podatkovnega niza. Koristno je pogledati obseg podatkov, s katerimi delamo.\n" + "Podatkovni niz Iris smo naložili v spremenljivko `iris_df`. Preden se poglobimo v podatke, bi bilo koristno vedeti, koliko podatkovnih točk imamo in kakšna je celotna velikost podatkovnega niza. Koristno je pogledati obseg podatkov, s katerimi delamo.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Torej, imamo opravka s 150 vrsticami in 4 stolpci podatkov. Vsaka vrstica predstavlja eno podatkovno točko, vsak stolpec pa eno značilnost, povezano s podatkovnim okvirom. Skratka, gre za 150 podatkovnih točk, od katerih ima vsaka 4 značilnosti.\n", + "Torej, imamo opravka s 150 vrsticami in 4 stolpci podatkov. Vsaka vrstica predstavlja eno podatkovno točko, vsak stolpec pa predstavlja eno značilnost, povezano s podatkovnim okvirjem. Torej, v bistvu je 150 podatkovnih točk, ki vsebujejo po 4 značilnosti.\n", "\n", - "`shape` je tukaj atribut podatkovnega okvira in ne funkcija, zato se ne konča z oklepaji.\n" + "`shape` je tukaj atribut podatkovnega okvirja in ne funkcija, zato se ne konča s parom oklepajev.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Poglejmo si zdaj 4 stolpce podatkov. Kaj točno predstavlja vsak od njih? Atribut `columns` nam bo prikazal imena stolpcev v podatkovnem okviru.\n" + "Poglejmo zdaj štiri stolpce podatkov. Kaj natančno predstavlja vsak od njih? Atribut `columns` nam bo dal imena stolpcev v podatkovnem okviru.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Kot lahko vidimo, so štirje (4) stolpci. Atribut `columns` nam pove imena stolpcev in v bistvu nič drugega. Ta atribut postane pomemben, ko želimo prepoznati značilnosti, ki jih vsebuje podatkovni niz.\n" + "Kot lahko vidimo, so štirje (4) stolpci. Lastnost `columns` nam pove imena stolpcev in v bistvu nič drugega. Ta lastnost postane pomembna, ko želimo identificirati značilnosti, ki jih vsebuje podatkovni niz.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Od tu lahko naredimo nekaj opažanj: \n", - "1. Podatkovni tip vsakega stolpca: V tem naboru podatkov so vsi podatki shranjeni kot 64-bitna števila s plavajočo vejico. \n", - "2. Število vrednosti, ki niso null: Obdelava null vrednosti je pomemben korak pri pripravi podatkov. S tem se bomo ukvarjali kasneje v zvezku. \n" + "Od tu lahko naredimo nekaj opažanj:\n", + "1. Podatkovni tip vsakega stolpca: V tem naboru podatkov so vsi podatki shranjeni kot 64-bitna števila s plavajočo vejico.\n", + "2. Število nenull vrednosti: Obdelava null vrednosti je pomemben korak pri pripravi podatkov. S tem se bomo ukvarjali kasneje v zvezku.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Recimo, da imamo v našem naboru podatkov veliko številskih podatkov. Enovariatne statistične izračune, kot so povprečje, mediana, kvartili itd., lahko izvedemo za vsako posamezno stolpec. Funkcija `DataFrame.describe()` nam ponuja statistični povzetek številskih stolpcev v naboru podatkov.\n" + "Recimo, da imamo veliko številskih podatkov v našem naboru podatkov. Enovariatne statistične izračune, kot so povprečje, mediana, kvartili itd., lahko izvedemo za vsakega od stolpcev posebej. Funkcija `DataFrame.describe()` nam ponuja statistični povzetek številskih stolpcev nabora podatkov.\n" ] }, { @@ -332,7 +332,7 @@ }, "source": [ "### `DataFrame.head`\n", - "Z vsemi zgoraj omenjenimi funkcijami in atributi smo dobili splošen pregled nad podatkovnim nizom. Vemo, koliko podatkovnih točk je prisotnih, koliko značilnosti je na voljo, kakšen je podatkovni tip vsake značilnosti in koliko značilnosti ima nenull vrednosti.\n", + "Z vsemi zgoraj omenjenimi funkcijami in atributi smo dobili splošen pregled nad podatkovnim nizom. Vemo, koliko podatkovnih točk je prisotnih, koliko značilnosti je na voljo, kakšen je podatkovni tip vsake značilnosti in koliko ne-null vrednosti ima vsaka značilnost.\n", "\n", "Zdaj je čas, da si ogledamo same podatke. Poglejmo, kako izgledajo prve vrstice (prve podatkovne točke) našega `DataFrame`:\n" ] @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Kot rezultat tukaj lahko vidimo pet (5) vnosov nabora podatkov. Če pogledamo indeks na levi, ugotovimo, da gre za prvih pet vrstic.\n" + "Kot rezultat tukaj lahko vidimo pet (5) vnosov podatkovnega nabora. Če pogledamo indeks na levi, ugotovimo, da gre za prvih pet vrstic.\n" ] }, { @@ -450,9 +450,9 @@ "id": "oj7GkrTdgRry" }, "source": [ - "### Vaja:\n", + "### Naloga:\n", "\n", - "Iz zgornjega primera je razvidno, da `DataFrame.head` privzeto vrne prvih pet vrstic `DataFrame`. Ali lahko v spodnji programski celici ugotovite, kako prikazati več kot pet vrstic?\n" + "Iz zgornjega primera je razvidno, da `DataFrame.head` privzeto vrne prvih pet vrstic `DataFrame`. Ali lahko v spodnji kodi ugotovite način, kako prikazati več kot pet vrstic?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Drug način za ogled podatkov je lahko od konca (namesto od začetka). Nasprotje `DataFrame.head` je `DataFrame.tail`, ki vrne zadnjih pet vrstic `DataFrame`:\n" + "Drug način za ogled podatkov je od konca (namesto od začetka). Nasprotje funkcije `DataFrame.head` je `DataFrame.tail`, ki vrne zadnjih pet vrstic `DataFrame`:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "V praksi je koristno, da lahko enostavno pregledate prve nekaj vrstic ali zadnje nekaj vrstic `DataFrame`, še posebej, ko iščete odstopanja v urejenih podatkovnih nizih.\n", + "V praksi je koristno, da lahko enostavno pregledate prvih nekaj vrstic ali zadnjih nekaj vrstic `DataFrame`, še posebej, ko iščete odstopanja v urejenih podatkovnih nizih.\n", "\n", "Vse funkcije in atributi, prikazani zgoraj s pomočjo primerov kode, nam pomagajo pridobiti vpogled v podatke.\n", "\n", - "> **Ključna misel:** Že samo z ogledom metapodatkov o informacijah v `DataFrame` ali prvih in zadnjih nekaj vrednostih v njem lahko takoj dobite predstavo o velikosti, obliki in vsebini podatkov, s katerimi delate.\n" + "> **Ključna misel:** Že samo z ogledom metapodatkov o informacijah v DataFrame ali prvih in zadnjih nekaj vrednosti v njem lahko takoj dobite predstavo o velikosti, obliki in vsebini podatkov, s katerimi delate.\n" ] }, { @@ -596,17 +596,17 @@ }, "source": [ "### Manjkajoči podatki\n", - "Poglobimo se v manjkajoče podatke. Manjkajoči podatki se pojavijo, ko v nekaterih stolpcih ni shranjene nobene vrednosti.\n", + "Poglejmo si manjkajoče podatke. Manjkajoči podatki se pojavijo, ko v nekaterih stolpcih ni shranjene nobene vrednosti.\n", "\n", - "Vzemimo primer: recimo, da je nekdo občutljiv glede svoje teže in zato v anketi ne izpolni polja za težo. V tem primeru bo vrednost teže za to osebo manjkajoča.\n", + "Vzemimo primer: recimo, da je nekdo zelo pozoren na svojo težo in ne izpolni polja za težo v anketi. Potem bo vrednost teže za to osebo manjkajoča.\n", "\n", "V večini primerov se v resničnih podatkovnih zbirkah pojavljajo manjkajoče vrednosti.\n", "\n", "**Kako Pandas obravnava manjkajoče podatke**\n", "\n", - "Pandas obravnava manjkajoče vrednosti na dva načina. Prvi način ste že videli v prejšnjih poglavjih: `NaN`, kar pomeni \"Not a Number\" (ni število). To je pravzaprav posebna vrednost, ki je del IEEE specifikacije za plavajoče števke in se uporablja izključno za označevanje manjkajočih vrednosti plavajočih števk.\n", + "Pandas obravnava manjkajoče vrednosti na dva načina. Prvi način ste že videli v prejšnjih poglavjih: `NaN`, ali Not a Number (ni število). To je pravzaprav posebna vrednost, ki je del IEEE specifikacije za plavajoče števke in se uporablja izključno za označevanje manjkajočih vrednosti pri plavajočih števkah.\n", "\n", - "Za manjkajoče vrednosti, ki niso plavajoče števke, pandas uporablja Pythonov objekt `None`. Čeprav se morda zdi zmedeno, da boste naleteli na dve različni vrsti vrednosti, ki v bistvu pomenita isto stvar, obstajajo tehtni programski razlogi za to oblikovalsko odločitev. V praksi ta pristop omogoča pandasu, da ponudi dobro ravnovesje za veliko večino primerov. Kljub temu pa imata tako `None` kot `NaN` omejitve, na katere morate biti pozorni glede tega, kako ju lahko uporabljate.\n" + "Za manjkajoče vrednosti, ki niso plavajoče števke, Pandas uporablja Pythonov objekt `None`. Čeprav se morda zdi zmedeno, da se srečujete z dvema različnima vrstama vrednosti, ki v bistvu pomenita isto, obstajajo tehtni programerski razlogi za to oblikovno odločitev. V praksi ta pristop Pandasu omogoča, da ponudi dobro kompromisno rešitev za veliko večino primerov. Kljub temu pa imata tako `None` kot `NaN` omejitve, na katere morate biti pozorni glede tega, kako jih lahko uporabljate.\n" ] }, { @@ -615,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: manjkajoči podatki, ki niso številski\n", - "Ker `None` izvira iz Pythona, ga ni mogoče uporabiti v poljih NumPy in pandas, ki nimajo podatkovnega tipa `'object'`. Ne pozabite, NumPy polja (in podatkovne strukture v pandas) lahko vsebujejo le eno vrsto podatkov. To jim daje izjemno moč za obdelavo velikih količin podatkov in računske naloge, hkrati pa omejuje njihovo prilagodljivost. Takšna polja morajo biti \"povišana\" na \"najnižji skupni imenovalec\", torej na podatkovni tip, ki lahko zajame vse elemente v polju. Ko je v polju prisoten `None`, to pomeni, da delate s Pythonovimi objekti.\n", + "### `None`: neplavajoči manjkajoči podatki\n", + "Ker `None` izvira iz Pythona, ga ni mogoče uporabiti v poljih NumPy in pandas, ki niso podatkovnega tipa `'object'`. Ne pozabite, da lahko polja NumPy (in podatkovne strukture v pandas) vsebujejo le eno vrsto podatkov. To jim daje izjemno moč za obdelavo podatkov in računsko delo v velikem obsegu, hkrati pa omejuje njihovo prilagodljivost. Takšna polja morajo biti \"nadgrajena\" na \"najnižji skupni imenovalec\", podatkovni tip, ki zajema vse v polju. Ko je v polju prisoten `None`, to pomeni, da delate s Pythonovimi objekti.\n", "\n", - "Da bi to videli v praksi, si oglejte naslednji primer polja (opazite njegov `dtype`):\n" + "Da bi to videli v praksi, si oglejte naslednje primer polja (opazite `dtype` zanj):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Resničnost nadgrajenih podatkovnih tipov prinaša s seboj dva stranska učinka. Prvič, operacije se bodo izvajale na ravni interpretirane Python kode namesto na ravni prevedene NumPy kode. To v bistvu pomeni, da bodo vse operacije, ki vključujejo `Series` ali `DataFrame` z vrednostjo `None`, počasnejše. Čeprav tega upada zmogljivosti verjetno ne boste opazili, bi to pri velikih naborih podatkov lahko postalo težava.\n", + "Resničnost nadgrajenih podatkovnih tipov prinaša dve posledici. Prva je, da se operacije izvajajo na ravni interpretirane Python kode namesto prevedene NumPy kode. To v bistvu pomeni, da bodo vse operacije, ki vključujejo `Series` ali `DataFrames` z vrednostjo `None`, počasnejše. Čeprav tega upada zmogljivosti verjetno ne boste opazili, bi lahko pri velikih podatkovnih nizih to postalo težava.\n", "\n", - "Drugi stranski učinek izhaja iz prvega. Ker `None` v bistvu povleče `Series` ali `DataFrame` nazaj v svet osnovnega Pythona, bo uporaba NumPy/pandas agregacij, kot sta `sum()` ali `min()`, na nizih, ki vsebujejo vrednost ``None``, običajno povzročila napako:\n" + "Druga posledica izhaja iz prve. Ker `None` v bistvu povleče `Series` ali `DataFrame` nazaj v svet osnovnega Pythona, bo uporaba NumPy/pandas agregacij, kot sta `sum()` ali `min()`, na nizih, ki vsebujejo vrednost ``None``, običajno povzročila napako:\n" ] }, { @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Ključna ugotovitev**: Seštevanje (in druge operacije) med celimi števili in vrednostmi `None` je nedefinirano, kar lahko omeji, kaj lahko storite z nabori podatkov, ki jih vsebujejo.\n" + "**Ključna ugotovitev**: Seštevanje (in druge operacije) med celimi števili in vrednostmi `None` ni definirano, kar lahko omeji možnosti dela z nabori podatkov, ki jih vsebujejo.\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Dobra novica: združevanja, ki se izvajajo na poljih z `NaN`, ne povzročajo napak. Slaba novica: rezultati niso enakomerno uporabni:\n" + "Dobra novica: združevanja, ki se izvajajo na poljih z `NaN`, ne povzročajo napak. Slaba novica: rezultati niso enotno uporabni:\n" ] }, { @@ -831,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "Ne pozabite: `NaN` je namenjen samo za manjkajoče vrednosti s plavajočo vejico; za cela števila, nize ali logične vrednosti ni ekvivalenta `NaN`.\n" + "Zapomni si: `NaN` je samo za manjkajoče vrednosti s plavajočo vejico; ne obstaja ekvivalent `NaN` za cela števila, nize ali logične vrednosti.\n" ] }, { @@ -842,7 +842,7 @@ "source": [ "### `NaN` in `None`: ničelne vrednosti v pandas\n", "\n", - "Čeprav se `NaN` in `None` lahko obnašata nekoliko drugače, je pandas vseeno zasnovan tako, da jih obravnava zamenljivo. Da bi razumeli, kaj mislimo, si oglejmo `Series` celih števil:\n" + "Čeprav se `NaN` in `None` lahko obnašata nekoliko drugače, je pandas vseeno zasnovan tako, da ju obravnava zamenljivo. Da bi razumeli, kaj mislimo, si oglejmo `Series` celih števil:\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Med postopkom dviga podatkovnih tipov za vzpostavitev podatkovne homogenosti v `Series` in `DataFrame`-ih bo pandas brez težav zamenjal manjkajoče vrednosti med `None` in `NaN`. Zaradi te oblikovne značilnosti je koristno razmišljati o `None` in `NaN` kot o dveh različnih vrstah \"ničelnih\" vrednosti v pandas. Pravzaprav nekateri osnovni postopki, ki jih boste uporabljali za obravnavo manjkajočih vrednosti v pandas, to idejo odražajo v svojih imenih:\n", + "Med postopkom nadgradnje podatkovnih tipov za vzpostavitev podatkovne homogenosti v `Series` in `DataFrame`-ih bo pandas zlahka preklapljal manjkajoče vrednosti med `None` in `NaN`. Zaradi te oblikovne značilnosti je koristno razmišljati o `None` in `NaN` kot o dveh različnih vrstah \"null\" vrednosti v pandas. Pravzaprav nekateri osnovni postopki, ki jih boste uporabljali za obravnavo manjkajočih vrednosti v pandas, to idejo odražajo v svojih imenih:\n", "\n", "- `isnull()`: Ustvari logično masko, ki označuje manjkajoče vrednosti\n", "- `notnull()`: Nasprotje funkcije `isnull()`\n", "- `dropna()`: Vrne filtrirano različico podatkov\n", "- `fillna()`: Vrne kopijo podatkov z zapolnjenimi ali imputiranimi manjkajočimi vrednostmi\n", "\n", - "To so ključne metode, ki jih je treba obvladati in se z njimi udobno spoprijeti, zato si jih poglejmo podrobneje.\n" + "To so pomembne metode, ki jih je treba obvladati in se z njimi udobno spoprijeti, zato si jih poglejmo podrobneje.\n" ] }, { @@ -922,10 +922,9 @@ "id": "Yh5ifd9FgRsB" }, "source": [ - "### Zaznavanje manjkajočih vrednosti\n", + "### Zaznavanje ničelnih vrednosti\n", "\n", - "Zdaj, ko smo razumeli pomen manjkajočih vrednosti, jih moramo najprej zaznati v našem naboru podatkov, preden jih obravnavamo. \n", - "Tako `isnull()` kot `notnull()` sta vaši glavni metodi za zaznavanje manjkajočih podatkov. Obe metodi vrneta Booleove maske za vaše podatke.\n" + "Zdaj, ko smo razumeli pomen manjkajočih vrednosti, jih moramo zaznati v našem naboru podatkov, preden se lotimo njihove obdelave. Tako `isnull()` kot `notnull()` sta vaši glavni metodi za zaznavanje ničelnih podatkov. Obe vrneta Boolean maske za vaše podatke.\n" ] }, { @@ -978,9 +977,9 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Poglejte natančno na rezultat. Vas kaj preseneča? Čeprav je `0` aritmetična ničla, je kljub temu povsem veljavno celo število, in pandas ga obravnava kot takega. `''` je nekoliko bolj subtilen. Čeprav smo ga v poglavju 1 uporabili za predstavitev prazne vrednosti niza, je kljub temu objekt niza in ga pandas ne obravnava kot predstavitev ničle.\n", + "Poglejte natančno izhod. Vas kaj preseneča? Čeprav je `0` aritmetična ničla, je kljub temu povsem veljavna cela številka, ki jo pandas obravnava kot takšno. `''` je nekoliko bolj subtilen. Čeprav smo ga v poglavju 1 uporabili za predstavitev prazne vrednosti niza, je kljub temu objekt niza in ga pandas ne obravnava kot predstavitev ničelne vrednosti.\n", "\n", - "Zdaj pa obrnimo to perspektivo in uporabimo te metode na način, kot jih boste uporabljali v praksi. Boolean maske lahko neposredno uporabite kot indeks za ``Series`` ali ``DataFrame``, kar je lahko koristno, ko poskušate delati z izoliranimi manjkajočimi (ali prisotnimi) vrednostmi.\n", + "Zdaj pa obrnimo perspektivo in uporabimo te metode na način, ki je bolj podoben dejanski uporabi v praksi. Boolean maske lahko neposredno uporabite kot indeks ``Series`` ali ``DataFrame``, kar je lahko koristno, ko želite delati z izoliranimi manjkajočimi (ali prisotnimi) vrednostmi.\n", "\n", "Če želimo skupno število manjkajočih vrednosti, lahko preprosto izvedemo vsoto nad masko, ki jo ustvari metoda `isnull()`.\n" ] @@ -1040,7 +1039,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Ključna ugotovitev**: Tako metodi `isnull()` kot `notnull()` dajeta podobne rezultate, ko ju uporabite v DataFrame-ih: prikazujeta rezultate in indeks teh rezultatov, kar vam bo izjemno pomagalo pri delu z vašimi podatki.\n" + "**Ključna ugotovitev**: Tako metoda `isnull()` kot metoda `notnull()` dajeta podobne rezultate, ko ju uporabite v DataFrame-ih: prikazujeta rezultate in indeks teh rezultatov, kar vam bo izjemno pomagalo pri obdelavi vaših podatkov.\n" ] }, { @@ -1049,13 +1048,13 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### Obdelava manjkajočih podatkov\n", + "### Obvladovanje manjkajočih podatkov\n", "\n", - "> **Cilj učenja:** Do konca tega podpoglavja bi morali vedeti, kako in kdaj zamenjati ali odstraniti manjkajoče vrednosti iz DataFrame-ov.\n", + "> **Cilj učenja:** Na koncu tega podpoglavja boste vedeli, kako in kdaj zamenjati ali odstraniti ničelne vrednosti iz DataFrame-ov.\n", "\n", "Modeli strojnega učenja sami ne morejo obdelovati manjkajočih podatkov. Zato moramo pred posredovanjem podatkov v model obravnavati te manjkajoče vrednosti.\n", "\n", - "Način obravnave manjkajočih podatkov vključuje subtilne kompromise, ki lahko vplivajo na vašo končno analizo in rezultate v resničnem svetu.\n", + "Način obravnave manjkajočih podatkov prinaša subtilne kompromise, ki lahko vplivajo na vašo končno analizo in rezultate v resničnem svetu.\n", "\n", "Obstajata predvsem dva načina za obravnavo manjkajočih podatkov:\n", "\n", @@ -1073,9 +1072,9 @@ "source": [ "### Odstranjevanje manjkajočih vrednosti\n", "\n", - "Količina podatkov, ki jih posredujemo našemu modelu, neposredno vpliva na njegovo zmogljivost. Odstranjevanje manjkajočih vrednosti pomeni, da zmanjšujemo število podatkovnih točk in s tem tudi velikost nabora podatkov. Zato je priporočljivo odstraniti vrstice z manjkajočimi vrednostmi, kadar je nabor podatkov precej velik.\n", + "Količina podatkov, ki jih posredujemo našemu modelu, neposredno vpliva na njegovo učinkovitost. Odstranjevanje manjkajočih vrednosti pomeni, da zmanjšujemo število podatkovnih točk in s tem velikost nabora podatkov. Zato je priporočljivo odstraniti vrstice z manjkajočimi vrednostmi, kadar je nabor podatkov precej velik.\n", "\n", - "Drug primer je lahko, da ima določena vrstica ali stolpec veliko manjkajočih vrednosti. V tem primeru jih lahko odstranimo, saj ne bi veliko prispevali k naši analizi, ker večina podatkov za to vrstico/stolpec manjka.\n", + "Drugi primer je lahko, da ima določena vrstica ali stolpec veliko manjkajočih vrednosti. V takem primeru jih lahko odstranimo, saj ne bi veliko prispevali k naši analizi, ker večina podatkov za to vrstico/stolpec manjka.\n", "\n", "Poleg prepoznavanja manjkajočih vrednosti pandas ponuja priročen način za odstranjevanje manjkajočih vrednosti iz `Series` in `DataFrame`-ov. Da bi to videli v praksi, se vrnimo k `example3`. Funkcija `DataFrame.dropna()` pomaga pri odstranjevanju vrstic z manjkajočimi vrednostmi.\n" ] @@ -1116,9 +1115,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "Upoštevajte, da bi to moralo izgledati kot vaš izhod iz `example3[example3.notnull()]`. Razlika tukaj je, da je `dropna` namesto zgolj indeksiranja na podlagi zamaskiranih vrednosti odstranil manjkajoče vrednosti iz `Series` `example3`.\n", + "Upoštevajte, da bi to moralo izgledati kot vaš rezultat iz `example3[example3.notnull()]`. Razlika tukaj je, da je `dropna` namesto zgolj indeksiranja na maskiranih vrednostih odstranil manjkajoče vrednosti iz `Series` `example3`.\n", "\n", - "Ker imajo DataFrame-i dve dimenziji, ponujajo več možnosti za odstranjevanje podatkov.\n" + "Ker imajo DataFramei dve dimenziji, omogočajo več možnosti za odstranjevanje podatkov.\n" ] }, { @@ -1208,9 +1207,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Ali ste opazili, da je pandas spremenil dve stolpci v float, da bi omogočil `NaN` vrednosti?)\n", + "(Ali ste opazili, da je pandas dve stolpci spremenil v tipe float, da bi omogočil `NaN` vrednosti?)\n", "\n", - "Iz `DataFrame` ne morete odstraniti posamezne vrednosti, zato morate odstraniti cele vrstice ali stolpce. Glede na to, kaj počnete, boste morda želeli narediti eno ali drugo, zato vam pandas ponuja možnosti za obe. Ker stolpci v podatkovni znanosti običajno predstavljajo spremenljivke, vrstice pa opazovanja, boste verjetno pogosteje odstranjevali vrstice podatkov; privzeta nastavitev za `dropna()` je, da odstrani vse vrstice, ki vsebujejo katero koli manjkajočo vrednost:\n" + "Iz `DataFrame` ne morete odstraniti posamezne vrednosti, zato morate odstraniti cele vrstice ali stolpce. Glede na to, kaj počnete, boste morda želeli narediti eno ali drugo, zato vam pandas omogoča obe možnosti. Ker v podatkovni znanosti stolpci običajno predstavljajo spremenljivke, vrstice pa opazovanja, boste verjetno pogosteje odstranjevali vrstice podatkov; privzeta nastavitev za `dropna()` je, da odstrani vse vrstice, ki vsebujejo kakršne koli null vrednosti:\n" ] }, { @@ -1362,9 +1361,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Upoštevajte, da to lahko odstrani veliko podatkov, ki jih morda želite obdržati, še posebej v manjših naborih podatkov. Kaj pa, če želite odstraniti samo vrstice ali stolpce, ki vsebujejo več ali celo samo vse manjkajoče vrednosti? Te nastavitve določite v `dropna` s parametroma `how` in `thresh`.\n", + "Upoštevajte, da lahko to odstrani veliko podatkov, ki jih morda želite obdržati, zlasti pri manjših naborih podatkov. Kaj pa, če želite odstraniti samo vrstice ali stolpce, ki vsebujejo več ali celo vse ničelne vrednosti? Te nastavitve določite v `dropna` z uporabo parametrov `how` in `thresh`.\n", "\n", - "Privzeto je `how='any'` (če želite preveriti sami ali videti, katere druge parametre ima metoda, zaženite `example4.dropna?` v kodi). Lahko pa alternativno določite `how='all'`, da odstranite samo vrstice ali stolpce, ki vsebujejo vse manjkajoče vrednosti. Razširimo naš primer `DataFrame`, da to vidimo v praksi v naslednji vaji.\n" + "Privzeto je `how='any'` (če želite preveriti sami ali videti, katere druge parametre ima metoda, zaženite `example4.dropna?` v kodi). Lahko pa določite `how='all'`, da odstranite samo vrstice ali stolpce, ki vsebujejo vse ničelne vrednosti. Razširimo naš primer `DataFrame`, da to vidimo v praksi v naslednji vaji.\n" ] }, { @@ -1457,10 +1456,10 @@ }, "source": [ "> Ključne točke:\n", - "1. Odstranjevanje ničelnih vrednosti je smiselno le, če je podatkovni niz dovolj velik.\n", - "2. Celotne vrstice ali stolpci se lahko odstranijo, če večina podatkov manjka.\n", - "3. Metoda `DataFrame.dropna(axis=)` pomaga pri odstranjevanju ničelnih vrednosti. Argument `axis` označuje, ali naj se odstranijo vrstice ali stolpci.\n", - "4. Uporablja se lahko tudi argument `how`. Privzeto je nastavljen na `any`, kar pomeni, da odstrani le tiste vrstice/stolpce, ki vsebujejo katero koli ničelno vrednost. Lahko ga nastavite na `all`, da določite, da bomo odstranili le tiste vrstice/stolpce, kjer so vse vrednosti ničelne.\n" + "1. Odstranjevanje manjkajočih vrednosti je smiselno le, če je podatkovni niz dovolj velik.\n", + "2. Celotne vrstice ali stolpci se lahko odstranijo, če večina njihovih podatkov manjka.\n", + "3. Metoda `DataFrame.dropna(axis=)` omogoča odstranjevanje manjkajočih vrednosti. Argument `axis` določa, ali naj se odstranijo vrstice ali stolpci.\n", + "4. Uporablja se lahko tudi argument `how`. Privzeto je nastavljen na `any`, kar pomeni, da se odstranijo le tiste vrstice/stolpci, ki vsebujejo katero koli manjkajočo vrednost. Lahko ga nastavite na `all`, da določite, da bomo odstranili le tiste vrstice/stolpce, kjer so vse vrednosti manjkajoče.\n" ] }, { @@ -1492,7 +1491,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "Parameter `thresh` vam omogoča natančnejši nadzor: določite število *nepraznih* vrednosti, ki jih mora imeti vrstica ali stolpec, da se ohrani:\n" + "Parameter `thresh` vam omogoča bolj natančen nadzor: določite število *ne-null* vrednosti, ki jih mora imeti vrstica ali stolpec, da se ohrani:\n" ] }, { @@ -1567,7 +1566,7 @@ "id": "fmSFnzZegRsG" }, "source": [ - "Tukaj sta bila prva in zadnja vrstica izpuščeni, ker vsebujeta le dve nenull vrednosti.\n" + "Tukaj sta bila prva in zadnja vrstica odstranjeni, ker vsebujeta le dve nenull vrednosti.\n" ] }, { @@ -1576,11 +1575,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### Izpolnjevanje manjkajočih vrednosti\n", + "### Polnjenje manjkajočih vrednosti\n", "\n", - "Včasih je smiselno zapolniti manjkajoče vrednosti s takšnimi, ki bi lahko bile veljavne. Obstaja nekaj tehnik za zapolnjevanje manjkajočih vrednosti. Prva je uporaba domenskega znanja (znanje o temi, na kateri temelji podatkovni niz), da nekako približamo manjkajoče vrednosti.\n", + "Včasih je smiselno zapolniti manjkajoče vrednosti z takšnimi, ki bi lahko bile veljavne. Obstaja nekaj tehnik za zapolnjevanje manjkajočih vrednosti. Prva je uporaba domenskega znanja (znanje o področju, na katerem temelji podatkovni niz), da nekako približamo manjkajoče vrednosti.\n", "\n", - "Za to lahko uporabite `isnull` neposredno, vendar je to lahko zamudno, še posebej, če imate veliko vrednosti za zapolnitev. Ker je to tako pogosta naloga v podatkovni znanosti, pandas ponuja `fillna`, ki vrne kopijo `Series` ali `DataFrame` z manjkajočimi vrednostmi, nadomeščenimi z vrednostjo po vaši izbiri. Ustvarimo še en primer `Series`, da vidimo, kako to deluje v praksi.\n" + "Za to lahko uporabite `isnull` neposredno, vendar je to lahko zamudno, še posebej, če imate veliko vrednosti za zapolnitev. Ker je to tako pogosta naloga v podatkovni znanosti, pandas ponuja funkcijo `fillna`, ki vrne kopijo `Series` ali `DataFrame` z manjkajočimi vrednostmi, zamenjanimi z vrednostjo po vaši izbiri. Ustvarimo še en primer `Series`, da vidimo, kako to deluje v praksi.\n" ] }, { @@ -1592,9 +1591,9 @@ "### Kategorijski podatki (neštevilčni)\n", "Najprej si poglejmo neštevilčne podatke. V podatkovnih nizih imamo stolpce s kategorijskimi podatki, npr. spol, resnično ali neresnično itd.\n", "\n", - "V večini teh primerov manjkajoče vrednosti nadomestimo z `modusom` stolpca. Recimo, da imamo 100 podatkovnih točk, od katerih jih je 90 označilo resnično, 8 neresnično, 2 pa nista podala odgovora. V tem primeru lahko manjkajoči vrednosti (2) zapolnimo z resnično, upoštevajoč celoten stolpec.\n", + "V večini teh primerov manjkajoče vrednosti nadomestimo z `modusom` stolpca. Recimo, da imamo 100 podatkovnih točk, od katerih jih je 90 označilo resnično, 8 neresnično, 2 pa nista podala odgovora. V tem primeru lahko manjkajoči vrednosti (2) zapolnimo z \"resnično\", upoštevajoč celoten stolpec.\n", "\n", - "Tukaj lahko ponovno uporabimo strokovno znanje. Poglejmo primer zapolnjevanja z modusom.\n" + "Tudi tukaj lahko uporabimo strokovno znanje. Poglejmo primer zapolnjevanja z modusom.\n" ] }, { @@ -1699,7 +1698,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Zdaj najprej poiščimo modus, preden zapolnimo vrednost `None` z modusom.\n" + ] }, { "cell_type": "code", @@ -1734,7 +1735,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Torej, bomo zamenjali None s True\n" + ] }, { "cell_type": "code", @@ -1844,7 +1847,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Kot lahko vidimo, je bila ničelna vrednost zamenjana. Seveda bi lahko namesto `'True'` napisali karkoli in bi bilo to nadomeščeno.\n" + "Kot lahko vidimo, je bila ničelna vrednost zamenjana. Seveda bi lahko namesto `'True'` napisali karkoli in to bi bilo nadomeščeno.\n" ] }, { @@ -1853,15 +1856,15 @@ "id": "heYe1I0dOmQ_" }, "source": [ - "### Številčni podatki\n", - "Zdaj pa k številčnim podatkom. Tukaj imamo dva pogosta načina za nadomeščanje manjkajočih vrednosti:\n", + "### Številski podatki\n", + "Zdaj preidimo na številskih podatkih. Tukaj imamo dva pogosta načina za nadomeščanje manjkajočih vrednosti:\n", "\n", "1. Nadomestitev z mediano vrstice\n", "2. Nadomestitev s povprečjem vrstice\n", "\n", - "Mediano uporabimo v primeru, ko so podatki pristranski in vsebujejo odstopajoče vrednosti. To je zato, ker je mediana odporna na odstopajoče vrednosti.\n", + "Mediano uporabimo v primeru porazdeljenih podatkov z odstopajočimi vrednostmi. To je zato, ker je mediana odporna na odstopajoče vrednosti.\n", "\n", - "Ko so podatki normalizirani, lahko uporabimo povprečje, saj sta v tem primeru povprečje in mediana zelo blizu.\n", + "Ko so podatki normalizirani, lahko uporabimo povprečje, saj sta v tem primeru povprečje in mediana precej blizu.\n", "\n", "Najprej vzemimo stolpec, ki je normalno porazdeljen, in zapolnimo manjkajoče vrednosti s povprečjem stolpca.\n" ] @@ -2003,7 +2006,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Polnjenje s povprečjem\n" + ] }, { "cell_type": "code", @@ -2112,7 +2117,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Zdaj poskusimo z drugim podatkovnim okvirom, tokrat pa bomo vrednosti None zamenjali s srednjo vrednostjo stolpca.\n" + "Zdaj poskusimo z drugim podatkovnim okvirom, tokrat pa bomo vrednosti None zamenjali z mediano stolpca.\n" ] }, { @@ -2252,7 +2257,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Polnjenje z mediano\n" + ] }, { "cell_type": "code", @@ -2352,7 +2359,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Kot lahko vidimo, je bila vrednost NaN zamenjana s mediano stolpca\n" + "Kot lahko vidimo, je bila vrednost NaN zamenjana z mediano stolpca\n" ] }, { @@ -2436,10 +2443,10 @@ }, "source": [ "> Ključne točke:\n", - "1. Manjkajoče vrednosti je treba zapolniti, kadar je na voljo manj podatkov ali kadar obstaja strategija za zapolnitev manjkajočih podatkov.\n", - "2. Manjkajoče vrednosti je mogoče zapolniti z uporabo strokovnega znanja iz domene, tako da jih približamo.\n", - "3. Pri kategorijskih podatkih se manjkajoče vrednosti najpogosteje nadomestijo z modusom stolpca.\n", - "4. Pri številskih podatkih se manjkajoče vrednosti običajno zapolnijo s povprečjem (za normalizirane nabore podatkov) ali mediano stolpcev.\n" + "1. Manjkajoče vrednosti je treba zapolniti, kadar je podatkov malo ali kadar obstaja strategija za zapolnitev manjkajočih podatkov.\n", + "2. Za zapolnitev manjkajočih vrednosti se lahko uporabi strokovno znanje iz področja, tako da se vrednosti približno ocenijo.\n", + "3. Pri kategorijskih podatkih se manjkajoče vrednosti večinoma nadomestijo z modusom stolpca.\n", + "4. Pri številskih podatkih se manjkajoče vrednosti običajno zapolnijo s povprečjem (za normalizirane podatkovne nabore) ali mediano stolpca.\n" ] }, { @@ -2470,7 +2477,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "Lahko **zapolnite naprej** manjkajoče vrednosti, kar pomeni, da uporabite zadnjo veljavno vrednost za zapolnitev manjkajoče:\n" + "Lahko **zapolnite naprej** ničelne vrednosti, kar pomeni, da uporabite zadnjo veljavno vrednost za zapolnitev ničelne:\n" ] }, { @@ -2511,7 +2518,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Prav tako lahko **nazaj izpolnite**, da nazaj razširite naslednjo veljavno vrednost in zapolnite ničlo:\n" + "Lahko tudi **zapolnite nazaj**, da propagirate naslednjo veljavno vrednost nazaj in zapolnite ničlo:\n" ] }, { @@ -2553,7 +2560,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "Kot lahko ugibate, to deluje enako z DataFrames, vendar lahko določite tudi `axis`, vzdolž katerega zapolnite manjkajoče vrednosti:\n" + "Kot lahko ugibate, to deluje enako z DataFrame-i, vendar lahko določite tudi `axis`, vzdolž katerega zapolnite ničelne vrednosti:\n" ] }, { @@ -2726,7 +2733,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Upoštevajte, da če prejšnja vrednost ni na voljo za zapolnitev naprej, ostane ničelna vrednost.\n" + "Opazite, da ko prejšnja vrednost ni na voljo za zapolnitev naprej, ostane ničelna vrednost.\n" ] }, { @@ -2850,9 +2857,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Upoštevajte, da je stolpec 3 še vedno brez vrednosti: privzeta smer je zapolnjevanje vrednosti po vrsticah.\n", + "Opazite, da stolpec 3 še vedno nima vrednosti: privzeta usmeritev je zapolnjevanje vrednosti po vrsticah.\n", "\n", - "> **Ključna misel:** Obstaja več načinov za obravnavo manjkajočih vrednosti v vaših podatkovnih nizih. Konkretna strategija, ki jo uporabite (odstranjevanje, nadomeščanje ali celo način nadomeščanja), mora biti prilagojena specifičnim značilnostim teh podatkov. Boljši občutek za obravnavo manjkajočih vrednosti boste razvili z večjo prakso in interakcijo s podatkovnimi nizi.\n" + "> **Ključna misel:** Obstaja več načinov za obravnavo manjkajočih vrednosti v vaših podatkovnih nizih. Konkretna strategija, ki jo uporabite (odstranjevanje, zamenjava ali celo način zamenjave), naj bo prilagojena značilnostim teh podatkov. Boljši občutek za obravnavo manjkajočih vrednosti boste razvili z večjo izkušnjo pri delu s podatkovnimi nizi.\n" ] }, { @@ -2863,9 +2870,9 @@ "source": [ "### Kodiranje kategorijskih podatkov\n", "\n", - "Modeli strojnega učenja obravnavajo le številke in kakršno koli obliko številskih podatkov. Ne bodo mogli razlikovati med \"Da\" in \"Ne\", vendar bodo lahko ločili med 0 in 1. Zato moramo po zapolnitvi manjkajočih vrednosti kategorijske podatke kodirati v neko številčno obliko, da jih model lahko razume.\n", + "Modeli strojnega učenja obravnavajo samo številke in kakršno koli obliko številskih podatkov. Ne bodo mogli razlikovati med \"Da\" in \"Ne\", lahko pa razlikujejo med 0 in 1. Zato moramo po zapolnitvi manjkajočih vrednosti kategorijske podatke kodirati v številčno obliko, da jih model lahko razume.\n", "\n", - "Kodiranje lahko izvedemo na dva načina. O teh metodah bomo razpravljali v nadaljevanju.\n" + "Kodiranje lahko izvedemo na dva načina. O njih bomo razpravljali v nadaljevanju.\n" ] }, { @@ -2874,9 +2881,9 @@ "id": "uDq9SxB7mu5i" }, "source": [ - "**ŠIFRIRANJE OZNAK** \n", + "**KODIRANJE OZNAK**\n", "\n", - "Šifriranje oznak pomeni pretvorbo vsake kategorije v številko. Na primer, recimo, da imamo podatkovni niz letalskih potnikov in stolpec, ki vsebuje njihov razred med naslednjimi ['poslovni razred', 'ekonomski razred', 'prvi razred']. Če izvedemo šifriranje oznak na tem stolpcu, bi se to pretvorilo v [0,1,2]. Poglejmo primer s pomočjo kode. Ker bomo v prihodnjih zvezkih spoznavali `scikit-learn`, ga tukaj ne bomo uporabili.\n" + "Kodiranje oznak pomeni pretvorbo vsake kategorije v številko. Na primer, recimo, da imamo podatkovni niz letalskih potnikov, kjer je stolpec, ki vsebuje njihov razred med naslednjimi ['poslovni razred', 'ekonomski razred', 'prvi razred']. Če izvedemo kodiranje oznak na tem stolpcu, bi se to pretvorilo v [0,1,2]. Poglejmo primer s pomočjo kode. Ker bomo v prihodnjih zvezkih spoznavali `scikit-learn`, ga tukaj ne bomo uporabili.\n" ] }, { @@ -2984,7 +2991,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Za izvedbo kodiranja oznak na prvem stolpcu moramo najprej opisati preslikavo vsakega razreda v številko, preden zamenjamo\n" + "Za izvedbo kodiranja oznak na 1. stolpcu moramo najprej opisati preslikavo vsakega razreda v številko, preden zamenjamo.\n" ] }, { @@ -3086,7 +3093,7 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Kot lahko vidimo, rezultat ustreza našim pričakovanjem. Torej, kdaj uporabimo kodiranje oznak? Kodiranje oznak se uporablja v enem ali obeh naslednjih primerih:\n", + "Kot lahko vidimo, se rezultat ujema s tem, kar smo pričakovali. Torej, kdaj uporabimo kodiranje oznak? Kodiranje oznak se uporablja v enem ali obeh naslednjih primerih:\n", "1. Ko je število kategorij veliko\n", "2. Ko so kategorije urejene.\n" ] @@ -3097,11 +3104,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**ENKODIRANJE ONE HOT**\n", + "**ONE HOT ENCODING**\n", "\n", - "Drug način kodiranja je enkodiranje One Hot. Pri tej vrsti kodiranja se vsaka kategorija stolpca doda kot ločen stolpec, pri čemer vsaka podatkovna točka dobi vrednost 0 ali 1 glede na to, ali vsebuje to kategorijo. Če torej obstaja n različnih kategorij, se podatkovnemu okviru doda n stolpcev.\n", + "Druga vrsta kodiranja je One Hot Encoding. Pri tej vrsti kodiranja se vsaka kategorija stolpca doda kot ločen stolpec, pri čemer vsak podatkovni element dobi vrednost 0 ali 1 glede na to, ali vsebuje to kategorijo. Če je na voljo n različnih kategorij, se podatkovnemu okviru doda n stolpcev.\n", "\n", - "Na primer, vzemimo isti primer razreda letala. Kategorije so bile: ['poslovni razred', 'ekonomski razred', 'prvi razred']. Če izvedemo enkodiranje One Hot, bodo podatkovnemu naboru dodani naslednji trije stolpci: ['razred_poslovni razred', 'razred_ekonomski razred', 'razred_prvi razred'].\n" + "Na primer, vzemimo isti primer razreda letala. Kategorije so bile: ['business class', 'economy class', 'first class']. Če izvedemo One Hot Encoding, se bodo podatkovnemu naboru dodali naslednji trije stolpci: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3209,7 +3216,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "Naj izvedemo enovročno kodiranje na 1. stolpcu\n" + "Naj izvedemo enovročno kodiranje na prvem stolpcu\n" ] }, { @@ -3334,7 +3341,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Vsak enovročno kodiran stolpec vsebuje 0 ali 1, kar določa, ali ta kategorija obstaja za tisto podatkovno točko.\n" + "Vsak stolpec z enovročno kodiranjem vsebuje 0 ali 1, kar določa, ali ta kategorija obstaja za tisto podatkovno točko.\n" ] }, { @@ -3346,7 +3353,7 @@ "Kdaj uporabljamo enovrstično kodiranje? Enovrstično kodiranje se uporablja v enem ali obeh naslednjih primerih:\n", "\n", "1. Ko je število kategorij in velikost podatkovnega nabora manjša.\n", - "2. Ko kategorije ne sledijo nobenemu določenemu vrstnemu redu.\n" + "2. Ko kategorije ne sledijo nobenemu posebnemu vrstnemu redu.\n" ] }, { @@ -3356,8 +3363,8 @@ }, "source": [ "> Ključne točke:\n", - "1. Kodiranje se uporablja za pretvorbo nenumeričnih podatkov v numerične podatke.\n", - "2. Obstajata dve vrsti kodiranja: Label kodiranje in One Hot kodiranje, ki ju lahko izvedemo glede na zahteve podatkovnega nabora.\n" + "1. Kodiranje se izvaja za pretvorbo nenumeričnih podatkov v numerične podatke.\n", + "2. Obstajata dve vrsti kodiranja: kodiranje z oznakami in kodiranje One Hot, ki ju je mogoče izvesti glede na zahteve podatkovnega nabora.\n" ] }, { @@ -3368,9 +3375,9 @@ "source": [ "## Odstranjevanje podvojenih podatkov\n", "\n", - "> **Cilj učenja:** Na koncu tega podpoglavja bi morali biti samozavestni pri prepoznavanju in odstranjevanju podvojenih vrednosti iz DataFrame-ov.\n", + "> **Cilj učenja:** Do konca tega pododdelka bi morali biti sposobni prepoznati in odstraniti podvojene vrednosti iz DataFrames.\n", "\n", - "Poleg manjkajočih podatkov boste v resničnih podatkovnih nizih pogosto naleteli na podvojene podatke. Na srečo pandas ponuja preprost način za zaznavanje in odstranjevanje podvojenih zapisov.\n" + "Poleg manjkajočih podatkov boste v resničnih podatkovnih nizih pogosto naleteli na podvojene podatke. Na srečo pandas ponuja enostaven način za zaznavanje in odstranjevanje podvojenih zapisov.\n" ] }, { @@ -3381,7 +3388,7 @@ "source": [ "### Prepoznavanje podvojenih vrednosti: `duplicated`\n", "\n", - "Podvojene vrednosti lahko enostavno prepoznate z metodo `duplicated` v pandas, ki vrne logično masko, ki označuje, ali je vnos v `DataFrame` podvojen glede na prejšnjega. Ustvarimo še en primer `DataFrame`, da vidimo, kako to deluje.\n" + "Podvojene vrednosti lahko enostavno prepoznate z metodo `duplicated` v pandas, ki vrne Boolean masko, ki označuje, ali je vnos v `DataFrame` podvojen glede na prejšnjega. Ustvarimo še en primer `DataFrame`, da vidimo, kako to deluje.\n" ] }, { @@ -3671,14 +3678,530 @@ "id": "GvX4og1EgRsL" }, "source": [ - "> **Ključna misel:** Odstranjevanje podvojenih podatkov je bistven del skoraj vsakega podatkovno-znanstvenega projekta. Podvojeni podatki lahko spremenijo rezultate vaših analiz in vam dajo netočne rezultate!\n" + "> **Povzetek:** Odstranjevanje podvojenih podatkov je bistven del skoraj vsakega podatkovno-znanstvenega projekta. Podvojeni podatki lahko spremenijo rezultate vaših analiz in vam dajo netočne rezultate!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Preverjanje kakovosti podatkov v resničnem svetu\n", + "\n", + "> **Cilj učenja:** Na koncu tega poglavja boste znali zaznati in popraviti pogoste težave s kakovostjo podatkov v resničnem svetu, vključno z nedoslednimi kategorijskimi vrednostmi, nenavadnimi številskimi vrednostmi (odstopanja) in podvojenimi entitetami z različicami.\n", + "\n", + "Čeprav so manjkajoče vrednosti in natančne podvojitve pogoste težave, resnični podatkovni nabori pogosto vsebujejo bolj subtilne težave:\n", + "\n", + "1. **Nedosledne kategorijske vrednosti**: Enaka kategorija, zapisana različno (npr. \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Nenavadne številčne vrednosti**: Ekstremna odstopanja, ki kažejo na napake pri vnosu podatkov (npr. starost = 999)\n", + "3. **Skoraj podvojene vrstice**: Zapisi, ki predstavljajo isto entiteto z manjšimi različicami\n", + "\n", + "Raziskali bomo tehnike za zaznavanje in obravnavo teh težav.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Ustvarjanje vzorčnega \"umazanega\" nabora podatkov\n", + "\n", + "Najprej ustvarimo vzorčni nabor podatkov, ki vsebuje vrste težav, s katerimi se pogosto srečujemo pri podatkih iz resničnega sveta:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Zaznavanje nedoslednih kategorijskih vrednosti\n", + "\n", + "Opazite, da ima stolpec `country` več predstavitev za iste države. Prepoznajmo te nedoslednosti:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Standardizacija kategorijskih vrednosti\n", + "\n", + "Lahko ustvarimo preslikavo za standardizacijo teh vrednosti. Preprost pristop je pretvorba v male črke in ustvarjanje slovarja preslikav:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternativa: Uporaba nejasnega ujemanja**\n", + "\n", + "Za bolj zapletene primere lahko uporabimo nejasno ujemanje nizov z knjižnico `rapidfuzz`, da samodejno zaznamo podobne nize:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Zaznavanje nenavadnih številskih vrednosti (odstopanj)\n", + "\n", + "Če pogledamo stolpec `age`, opazimo nekaj sumljivih vrednosti, kot sta 199 in -5. Uporabimo statistične metode za zaznavanje teh odstopanj.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Uporaba metode IQR (interkvartilni razpon)\n", + "\n", + "Metoda IQR je zanesljiva statistična tehnika za odkrivanje odstopanj, ki je manj občutljiva na skrajne vrednosti:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Uporaba metode Z-tovorka\n", + "\n", + "Metoda Z-tovorka prepozna odstopajoče vrednosti na podlagi standardnih odklonov od povprečja:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Obdelava odstopanj\n", + "\n", + "Ko so odstopanja zaznana, jih lahko obdelamo na več načinov:\n", + "1. **Odstranitev**: Izločite vrstice z odstopanji (če gre za napake)\n", + "2. **Omejitev**: Zamenjajte z mejno vrednostjo\n", + "3. **Zamenjava z NaN**: Obravnavajte kot manjkajoče podatke in uporabite tehnike imputacije\n", + "4. **Ohranitev**: Če gre za legitimne ekstremne vrednosti\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Zaznavanje skoraj podvojenih vrstic\n", + "\n", + "Opazite, da ima naš podatkovni niz več vnosov za \"John Smith\" z nekoliko različnimi vrednostmi. Identificirajmo morebitne podvojene vnose na podlagi podobnosti imen.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Iskanje skoraj enakih podvojenih zapisov z mehkim ujemanjem\n", + "\n", + "Za bolj napredno odkrivanje podvojenih zapisov lahko uporabimo mehko ujemanje za iskanje podobnih imen:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Obvladovanje podvojenih podatkov\n", + "\n", + "Ko jih identificirate, morate odločiti, kako ravnati s podvojenimi podatki:\n", + "1. **Obdržite prvi pojav**: Uporabite `drop_duplicates(keep='first')`\n", + "2. **Obdržite zadnji pojav**: Uporabite `drop_duplicates(keep='last')`\n", + "3. **Združite informacije**: Združite informacije iz podvojenih vrstic\n", + "4. **Ročni pregled**: Označite za pregled s strani človeka\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Povzetek: Celovit postopek čiščenja podatkov\n", + "\n", + "Združimo vse skupaj v celovit postopek čiščenja podatkov:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Izzivna naloga\n", + "\n", + "Zdaj je na vrsti vaš izziv! Spodaj je nov vrstni red podatkov z več težavami glede kakovosti. Ali lahko:\n", + "\n", + "1. Prepoznate vse težave v tej vrstici\n", + "2. Napišete kodo za odpravo vsake težave\n", + "3. Dodate očiščeno vrstico v podatkovni niz\n", + "\n", + "Tukaj so problematični podatki:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Ključne točke\n", + "\n", + "1. **Neskladne kategorije** so pogoste v podatkih iz resničnega sveta. Vedno preverite edinstvene vrednosti in jih standardizirajte z uporabo preslikav ali približnega ujemanja.\n", + "\n", + "2. **Izstopajoče vrednosti** lahko pomembno vplivajo na vašo analizo. Uporabite strokovno znanje v kombinaciji s statističnimi metodami (IQR, Z-score) za njihovo odkrivanje.\n", + "\n", + "3. **Skoraj podvojeni podatki** so težje zaznavni kot popolni podvojeni podatki. Razmislite o uporabi približnega ujemanja in normalizaciji podatkov (pretvorba v male črke, odstranjevanje presledkov) za njihovo identifikacijo.\n", + "\n", + "4. **Čiščenje podatkov je iterativno**. Morda boste morali uporabiti več tehnik in pregledati rezultate, preden dokončno očistite svoj nabor podatkov.\n", + "\n", + "5. **Dokumentirajte svoje odločitve**. Beležite, katere korake čiščenja ste uporabili in zakaj, saj je to pomembno za ponovljivost in transparentnost.\n", + "\n", + "> **Najboljša praksa:** Vedno shranite kopijo svojih originalnih \"neurejenih\" podatkov. Nikoli ne prepišite izvornih datotek podatkov - ustvarite očiščene različice z jasnimi poimenovanji, kot je `data_cleaned.csv`.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Omejitev odgovornosti**: \nTa dokument je bil preveden z uporabo storitve za strojno prevajanje [Co-op Translator](https://github.com/Azure/co-op-translator). Čeprav si prizadevamo za natančnost, vas prosimo, da upoštevate, da lahko avtomatizirani prevodi vsebujejo napake ali netočnosti. Izvirni dokument v njegovem izvirnem jeziku je treba obravnavati kot avtoritativni vir. Za ključne informacije priporočamo strokovno človeško prevajanje. Ne prevzemamo odgovornosti za morebitna nesporazumevanja ali napačne razlage, ki izhajajo iz uporabe tega prevoda.\n" + "\n---\n\n**Omejitev odgovornosti**: \nTa dokument je bil preveden z uporabo storitve za prevajanje z umetno inteligenco [Co-op Translator](https://github.com/Azure/co-op-translator). Čeprav si prizadevamo za natančnost, vas prosimo, da upoštevate, da lahko avtomatski prevodi vsebujejo napake ali netočnosti. Izvirni dokument v njegovem maternem jeziku je treba obravnavati kot avtoritativni vir. Za ključne informacije priporočamo profesionalni človeški prevod. Ne prevzemamo odgovornosti za morebitne nesporazume ali napačne razlage, ki bi nastale zaradi uporabe tega prevoda.\n" ] } ], @@ -3706,8 +4229,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:52:19+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T21:16:09+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "sl" } diff --git a/translations/sr/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/sr/2-Working-With-Data/08-data-preparation/notebook.ipynb index 93ae352b..4bcaff9e 100644 --- a/translations/sr/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/sr/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -12,11 +12,11 @@ "\n", "## Истраживање информација о `DataFrame`\n", "\n", - "> **Циљ учења:** До краја овог пододељка, требало би да будете у могућности да пронађете опште информације о подацима који се чувају у pandas DataFrame-овима.\n", + "> **Циљ учења:** На крају овог пододељка, требало би да будете у могућности да пронађете опште информације о подацима који се чувају у pandas DataFrame-овима.\n", "\n", - "Када учитате своје податке у pandas, врло је вероватно да ће бити у облику `DataFrame`. Међутим, ако ваш скуп података у `DataFrame`-у има 60.000 редова и 400 колона, како уопште почети да стичете осећај о томе са чим радите? Срећом, pandas пружа неке згодне алате за брз преглед општих информација о `DataFrame`, поред првих и последњих неколико редова.\n", + "Када учитате своје податке у pandas, веома је вероватно да ће бити у облику `DataFrame`. Међутим, ако ваш скуп података у `DataFrame`-у има 60,000 редова и 400 колона, како уопште да почнете да разумете са чим радите? Срећом, pandas пружа неке практичне алате за брз преглед општих информација о `DataFrame`, као и првих и последњих неколико редова.\n", "\n", - "Да бисмо истражили ову функционалност, увешћемо Python библиотеку scikit-learn и користити један иконичан скуп података који је сваки научник података видео стотине пута: скуп података британског биолога Роналда Фишера *Iris*, који је коришћен у његовом раду из 1936. године \"The use of multiple measurements in taxonomic problems\":\n" + "Да бисмо истражили ову функционалност, увешћемо Python библиотеку scikit-learn и користити један иконичан скуп података који је сваки научник података видео стотине пута: скуп података британског биолога Роналда Фишера *Iris*, коришћен у његовом раду из 1936. године \"The use of multiple measurements in taxonomic problems\":\n" ] }, { @@ -80,7 +80,7 @@ "source": [ "Дакле, имамо 150 редова и 4 колоне података. Сваки ред представља једну тачку података, а свака колона представља једну карактеристику повезану са оквиром података. У суштини, постоји 150 тачака података које садрже по 4 карактеристике.\n", "\n", - "`shape` је овде атрибут оквира података, а не функција, због чега се не завршава паром заграда.\n" + "`shape` је овде атрибут оквира података, а не функција, због чега се не завршава са паром заграда.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Хајде сада да пређемо на 4 колоне података. Шта тачно свака од њих представља? Атрибут `columns` ће нам дати имена колона у датафрејму.\n" + "Хајде сада да пређемо на 4 колоне података. Шта тачно представља свака од њих? Атрибут `columns` ће нам дати имена колона у датафрејму.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Како можемо видети, постоје четири(4) колоне. Атрибут `columns` нам говори имена колона и у суштини ништа више. Овај атрибут постаје важан када желимо да идентификујемо карактеристике које скуп података садржи.\n" + "Као што можемо видети, постоје четири (4) колоне. Атрибут `columns` нам говори имена колона и у суштини ништа више. Овај атрибут постаје важан када желимо да идентификујемо карактеристике које скуп података садржи.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Количина података (дата атрибутом `shape`) и имена карактеристика или колона (дата атрибутом `columns`) нам пружају одређене информације о скупу података. Сада бисмо желели да се детаљније упознамо са скупом података. Функција `DataFrame.info()` је веома корисна за ово.\n" + "Количина података (датих преко атрибута `shape`) и имена карактеристика или колона (датих преко атрибута `columns`) нам говоре нешто о скупу података. Сада бисмо желели да се детаљније позабавимо скупом података. Функција `DataFrame.info()` је веома корисна за ово.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Одавде можемо направити неколико запажања: \n", - "1. Тип података сваке колоне: У овом скупу података, сви подаци су сачувани као 64-битни бројеви са покретним зарезом. \n", - "2. Број вредности које нису null: Рад са null вредностима је важан корак у припреми података. Овим ћемо се бавити касније у бележници. \n" + "Одавде можемо направити неколико запажања:\n", + "1. Тип података сваке колоне: У овом скупу података, сви подаци су сачувани као 64-битни бројеви са покретним зарезом.\n", + "2. Број вредности које нису Null: Рад са Null вредностима је важан корак у припреми података. Овим ће се бавити касније у бележници.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Рецимо да имамо пуно нумеричких података у нашем скупу података. Једноваријантни статистички прорачуни као што су средња вредност, медијана, квартил итд. могу се извршити за сваку колону појединачно. Функција `DataFrame.describe()` нам пружа статистички преглед нумеричких колона скупа података.\n" + "Рецимо да имамо много нумеричких података у нашем сету података. Једноваријантне статистичке прорачуне, као што су средња вредност, медијана, квартили итд., можемо извршити за сваку колону појединачно. Функција `DataFrame.describe()` нам пружа статистички преглед нумеричких колона у сету података.\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "Са свим горе наведеним функцијама и атрибутима, добили смо преглед података на највишем нивоу. Знамо колико има података, колико има карактеристика, који је тип података за сваку карактеристику и колико има вредности које нису празне за сваку карактеристику.\n", + "Са свим горе наведеним функцијама и атрибутима, добили смо преглед на високом нивоу скупа података. Знамо колико има тачака података, колико има карактеристика, тип података сваке карактеристике и број вредности које нису null за сваку карактеристику.\n", "\n", - "Сада је време да погледамо саме податке. Хајде да видимо како изгледају првих неколико редова (првих неколико тачака података) нашег `DataFrame`:\n" + "Сада је време да погледамо самe податке. Хајде да видимо како изгледају првих неколико редова (првих неколико тачака података) нашег `DataFrame`:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Као што видимо у излазу, имамо пет (5) уноса из скупа података. Ако погледамо индекс са леве стране, откривамо да су то првих пет редова.\n" + "Као што је приказано овде, можемо видети пет (5) уноса из скупа података. Ако погледамо индекс са леве стране, откривамо да су то првих пет редова.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Вежба:\n", "\n", - "Из горњег примера је јасно да `DataFrame.head` подразумевано враћа првих пет редова `DataFrame`. У коду испод, можете ли смислити начин да прикажете више од пет редова?\n" + "Из горњег примера је јасно да `DataFrame.head` подразумевано враћа првих пет редова `DataFrame`-а. У коду испод, можете ли смислити начин да прикажете више од пет редова?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Још један начин да погледате податке може бити од краја (уместо од почетка). Супротност `DataFrame.head` је `DataFrame.tail`, који враћа последњих пет редова `DataFrame`:\n" + "Још један начин гледања на податке може бити од краја (уместо од почетка). Супротност `DataFrame.head` је `DataFrame.tail`, који враћа последњих пет редова `DataFrame`:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "У пракси је корисно имати могућност да лако прегледате првих неколико редова или последњих неколико редова `DataFrame`-а, посебно када тражите одступања у уређеним скуповима података.\n", + "У пракси је корисно моћи лако прегледати првих неколико редова или последњих неколико редова `DataFrame`, посебно када тражите екстремне вредности у уређеним скуповима података.\n", "\n", - "Све функције и атрибути приказани изнад уз помоћ примера кода помажу нам да стекнемо увид и осећај за податке.\n", + "Све функције и атрибути приказани изнад уз помоћ примера кода помажу нам да стекнемо увид у податке.\n", "\n", - "> **Закључак:** Чак и само посматрањем метаподатака о информацијама у `DataFrame`-у или првих и последњих неколико вредности у њему, можете одмах стећи представу о величини, облику и садржају података са којима радите.\n" + "> **Закључак:** Чак и само гледањем метаподатака о информацијама у `DataFrame`-у или првих и последњих неколико вредности у њему, можете одмах добити идеју о величини, облику и садржају података са којима радите.\n" ] }, { @@ -596,17 +596,17 @@ }, "source": [ "### Недостајући подаци\n", - "Хајде да се позабавимо недостајућим подацима. Недостајући подаци се јављају када нека вредност није унетa у одређене колоне.\n", + "Хајде да се позабавимо недостајућим подацима. Недостајући подаци се јављају када нека вредност није ускладиштена у одређеним колонама.\n", "\n", - "Узмимо пример: рецимо да је неко ко је свестан своје тежине одлучио да не попуни поље за тежину у анкети. У том случају, вредност тежине за ту особу ће недостајати.\n", + "Узмимо пример: рецимо да је неко свестан своје тежине и не попуни поље за тежину у анкети. Тада ће вредност тежине за ту особу недостајати.\n", "\n", - "У већини случајева, у стварним скуповима података, недостајуће вредности су честа појава.\n", + "У већини случајева, у стварним скуповима података, јављају се недостајуће вредности.\n", "\n", "**Како Pandas обрађује недостајуће податке**\n", "\n", - "Pandas обрађује недостајуће вредности на два начина. Први начин сте већ видели у претходним одељцима: `NaN`, или Not a Number. Ово је заправо посебна вредност која је део IEEE спецификације за бројеве са покретним зарезом и користи се искључиво за означавање недостајућих вредности са покретним зарезом.\n", + "Pandas обрађује недостајуће вредности на два начина. Први начин сте већ видели у претходним одељцима: `NaN`, или Not a Number. Ово је заправо посебна вредност која је део IEEE спецификације за бројеве са покретним зарезом и користи се само за означавање недостајућих вредности са покретним зарезом.\n", "\n", - "За недостајуће вредности које нису типа float, pandas користи Python објекат `None`. Иако може деловати збуњујуће што ћете наићи на две различите врсте вредности које у суштини означавају исту ствар, постоје добри програмски разлози за овај дизајн. У пракси, овај приступ омогућава pandas-у да понуди добар компромис за велику већину случајева. Упркос томе, и `None` и `NaN` имају одређена ограничења која треба имати на уму у погледу начина на који се могу користити.\n" + "За недостајуће вредности које нису бројеви са покретним зарезом, pandas користи Python објекат `None`. Иако може изгледати збуњујуће што ћете наићи на две различите врсте вредности које у суштини значе исто, постоје добри програмски разлози за овај избор дизајна, а у пракси, овај приступ омогућава pandas-у да пружи добар компромис за велику већину случајева. Упркос томе, и `None` и `NaN` имају ограничења која треба имати на уму у погледу начина на који се могу користити.\n" ] }, { @@ -616,9 +616,9 @@ }, "source": [ "### `None`: недостајући подаци који нису типа float\n", - "Пошто `None` долази из Python-а, не може се користити у NumPy и pandas низовима који нису типа `'object'`. Запамтите, NumPy низови (и структуре података у pandas-у) могу садржати само један тип података. Ово им даје огромну моћ за рад са великим количинама података и обраду, али истовремено ограничава њихову флексибилност. Такви низови морају се прилагодити „најнижој заједничкој основи“, односно типу података који ће обухватити све у низу. Када се `None` налази у низу, то значи да радите са Python објектима.\n", + "Пошто `None` потиче из Python-а, не може се користити у NumPy и pandas низовима који нису типа података `'object'`. Запамтите, NumPy низови (и структуре података у pandas-у) могу садржати само један тип података. Управо то им даје огромну моћ за рад са великим количинама података и обраду, али истовремено ограничава њихову флексибилност. Такви низови морају да се конвертују у „најнижи заједнички именилац“, односно тип података који може обухватити све у низу. Када је `None` у низу, то значи да радите са Python објектима.\n", "\n", - "Да бисмо ово видели на делу, размотримо следећи пример низа (обратите пажњу на `dtype` за њега):\n" + "Да бисте видели како ово функционише, погледајте следећи пример низа (обратите пажњу на `dtype` за њега):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Реалност надограђених типова података носи са собом два споредна ефекта. Прво, операције ће се изводити на нивоу интерпретираног Python кода, а не компајлираног NumPy кода. У суштини, то значи да ће све операције које укључују `Series` или `DataFrames` са `None` вредностима бити спорије. Иако вероватно нећете приметити овај пад у перформансама, код великих скупова података то може постати проблем.\n", + "Реалност надограђених типова података носи са собом два споредна ефекта. Прво, операције ће се изводити на нивоу интерпретираног Python кода, а не компајлираног NumPy кода. У суштини, то значи да ће све операције које укључују `Series` или `DataFrames` са `None` у њима бити спорије. Иако вероватно нећете приметити овај пад перформанси, код великих скупова података то би могло постати проблем.\n", "\n", - "Други споредни ефекат произилази из првог. Пошто `None` у суштини враћа `Series` или `DataFrame` у свет обичног Python-а, коришћење NumPy/pandas агрегатних функција као што су `sum()` или `min()` на низовима који садрже вредност ``None`` генерално ће произвести грешку:\n" + "Други споредни ефекат произилази из првог. Пошто `None` у суштини враћа `Series` или `DataFrame` у свет обичног Python-а, коришћење NumPy/pandas агрегација као што су `sum()` или `min()` на низовима који садрже вредност ``None`` генерално ће произвести грешку:\n" ] }, { @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Кључна поента**: Сабирање (и друге операције) између целих бројева и вредности `None` је неодређено, што може ограничити оно што можете урадити са скуповима података који их садрже.\n" + "**Кључна порука**: Сабирање (и друге операције) између целих бројева и вредности `None` је недефинисано, што може ограничити оно што можете урадити са скуповима података који их садрже.\n" ] }, { @@ -709,7 +709,7 @@ "source": [ "### `NaN`: недостајуће вредности типа float\n", "\n", - "За разлику од `None`, NumPy (а самим тим и pandas) подржава `NaN` за своје брзе, векторизоване операције и ufunc-ове. Лоша вест је да свака аритметичка операција извршена над `NaN` увек резултира у `NaN`. На пример:\n" + "За разлику од `None`, NumPy (а самим тим и pandas) подржава `NaN` за своје брзе, векторизоване операције и ufuncs. Лоша вест је да свака аритметичка операција извршена над `NaN` увек резултира `NaN`. На пример:\n" ] }, { @@ -831,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "Запамтите: `NaN` је само за недостајуће вредности са покретним зарезом; не постоји еквивалент `NaN` за целе бројеве, стрингове или булове вредности.\n" + "Запамти: `NaN` је само за недостајуће вредности са покретним зарезом; не постоји еквивалент `NaN` за целе бројеве, стрингове или булове вредности.\n" ] }, { @@ -840,9 +840,9 @@ "id": "kj6EKdsAgRsA" }, "source": [ - "### `NaN` и `None`: null вредности у pandas-у\n", + "### `NaN` и `None`: нулте вредности у pandas-у\n", "\n", - "Иако `NaN` и `None` могу да се понашају мало другачије, pandas је ипак направљен да их обрађује на исти начин. Да бисмо објаснили шта мислимо, погледајмо `Series` целих бројева:\n" + "Иако се `NaN` и `None` могу понашати мало другачије, pandas је ипак направљен тако да их обрађује наизменично. Да бисмо објаснили шта то значи, размотримо `Series` целих бројева:\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "У процесу подизања типова података ради успостављања хомогености података у `Series` и `DataFrame` објектима, pandas ће без проблема заменити недостајуће вредности између `None` и `NaN`. Због ове карактеристике дизајна, може бити корисно размишљати о `None` и `NaN` као о две различите врсте \"null\" вредности у pandas-у. Заиста, неке од основних метода које ћете користити за рад са недостајућим вредностима у pandas-у одражавају ову идеју у својим називима:\n", + "У процесу подизања типова података ради успостављања хомогености података у `Series` и `DataFrame` објектима, pandas ће без проблема заменити недостајуће вредности између `None` и `NaN`. Због ове дизајнерске карактеристике, корисно је размишљати о `None` и `NaN` као о две различите врсте \"нултог\" у pandas-у. Заиста, неки од основних метода које ћете користити за рад са недостајућим вредностима у pandas-у одражавају ову идеју у својим називима:\n", "\n", "- `isnull()`: Генерише Булову маску која указује на недостајуће вредности\n", "- `notnull()`: Супротно од `isnull()`\n", "- `dropna()`: Враћа филтрирану верзију података\n", "- `fillna()`: Враћа копију података са попуњеним или импутираним недостајућим вредностима\n", "\n", - "Ово су важне методе које треба савладати и са којима треба постати комфоран, па хајде да их детаљније размотримо.\n" + "Ово су важни методи које треба савладати и са којима треба бити комфоран, па хајде да их детаљније размотримо.\n" ] }, { @@ -922,10 +922,10 @@ "id": "Yh5ifd9FgRsB" }, "source": [ - "### Детектовање null вредности\n", + "### Откривање null вредности\n", "\n", - "Сада када смо разумели значај недостајућих вредности, потребно је да их откријемо у нашем скупу података пре него што их обрадимо. \n", - "И `isnull()` и `notnull()` су ваши основни методи за детектовање null података. Оба враћају Булове маске преко ваших података.\n" + "Сада када смо разумели значај недостајућих вредности, потребно је да их откријемо у нашем скупу података пре него што их обрадимо. \n", + "И `isnull()` и `notnull()` су ваши основни методи за откривање null података. Оба враћају Булове маске преко ваших података.\n" ] }, { @@ -978,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Погледајте пажљиво резултате. Да ли вас нешто изненађује? Иако је `0` аритметичка нула, он је ипак савршено добар целобројни тип, и pandas га тако третира. `''` је мало суптилнији. Иако смо га користили у Одељку 1 да представимо празну вредност низа, он је ипак објекат низа и није представљање нуле у смислу како pandas то схвата.\n", + "Пажљиво погледајте резултат. Да ли вас нешто изненађује? Иако је `0` аритметичка нула, он је ипак сасвим добар целобројни тип, и pandas га тако третира. `''` је мало суптилнији. Иако смо га у Секцији 1 користили да представимо празну вредност стринга, он је ипак објекат типа стринг, а не представљање null вредности када је у питању pandas.\n", "\n", - "Сада, хајде да ово преокренемо и употребимо ове методе на начин који је ближи стварној пракси. Boolean маске можете користити директно као индекс ``Series`` или ``DataFrame``, што може бити корисно када покушавате да радите са изолованим недостајућим (или присутним) вредностима.\n", + "Сада, хајде да ово окренемо и користимо ове методе на начин који је ближи стварној пракси. Boolean маске можете користити директно као индекс ``Series`` или ``DataFrame``, што може бити корисно када покушавате да радите са изолованим недостајућим (или присутним) вредностима.\n", "\n", - "Ако желимо укупан број недостајућих вредности, можемо једноставно извршити суму преко маске коју производи метода `isnull()`.\n" + "Ако желимо укупан број недостајућих вредности, можемо једноставно урадити суму преко маске коју производи метода `isnull()`.\n" ] }, { @@ -1040,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Кључна поука**: И методе `isnull()` и `notnull()` дају сличне резултате када их користите у DataFrame-овима: приказују резултате и индекс тих резултата, што ће вам изузетно помоћи док се бавите својим подацима.\n" + "**Кључна ствар**: И `isnull()` и `notnull()` методе дају сличне резултате када их користите у DataFrame-овима: приказују резултате и индекс тих резултата, што ће вам изузетно помоћи док се борите са вашим подацима.\n" ] }, { @@ -1051,9 +1051,9 @@ "source": [ "### Рад са недостајућим подацима\n", "\n", - "> **Циљ учења:** На крају овог пододељка, требало би да знате како и када да замените или уклоните null вредности из DataFrame-ова.\n", + "> **Циљ учења:** До краја овог пододељка, требало би да знате како и када да замените или уклоните null вредности из DataFrame-ова.\n", "\n", - "Модели машинског учења не могу сами да обрађују недостајуће податке. Због тога, пре него што податке проследимо моделу, морамо да решимо проблем недостајућих вредности.\n", + "Модели машинског учења не могу сами да обрађују недостајуће податке. Зато је неопходно да се ти недостајући подаци обраде пре него што се проследе моделу.\n", "\n", "Начин на који се недостајући подаци обрађују носи са собом суптилне компромисе, може утицати на вашу коначну анализу и исходе у стварном свету.\n", "\n", @@ -1062,7 +1062,7 @@ "1. Уклонити ред који садржи недостајућу вредност\n", "2. Заменити недостајућу вредност неком другом вредношћу\n", "\n", - "Размотрићемо оба ова метода, као и њихове предности и мане, у детаљима.\n" + "Размотрићемо оба ова метода и њихове предности и мане у детаљима.\n" ] }, { @@ -1071,13 +1071,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### Уклањање null вредности\n", + "### Уклањање празних вредности\n", "\n", - "Количина података коју прослеђујемо нашем моделу директно утиче на његове перформансе. Уклањање null вредности значи да смањујемо број података, а самим тим и величину скупа података. Због тога је препоручљиво уклонити редове са null вредностима када је скуп података прилично велик.\n", + "Количина података коју прослеђујемо нашем моделу директно утиче на његову перформансу. Уклањање празних вредности значи да смањујемо број тачака података, а тиме и величину скупа података. Због тога је препоручљиво уклонити редове са празним вредностима када је скуп података прилично велик.\n", "\n", - "Други случај може бити да одређени ред или колона имају много недостајућих вредности. У том случају, могу се уклонити јер не би значајно допринели нашој анализи, с обзиром на то да већина података недостаје за тај ред/колону.\n", + "Други случај може бити да одређени ред или колона имају много недостајућих вредности. У том случају, могу бити уклоњени јер не би значајно допринели нашој анализи, пошто је већина података за тај ред/колону недостајућа.\n", "\n", - "Поред идентификовања недостајућих вредности, pandas пружа згодан начин за уклањање null вредности из `Series` и `DataFrame` објеката. Да бисмо видели како то функционише, вратимо се на `example3`. Функција `DataFrame.dropna()` помаже у уклањању редова са null вредностима.\n" + "Поред идентификовања недостајућих вредности, pandas пружа практичан начин за уклањање празних вредности из `Series` и `DataFrame`-ова. Да бисмо видели како то функционише, вратићемо се на `example3`. Функција `DataFrame.dropna()` помаже у уклањању редова са празним вредностима.\n" ] }, { @@ -1116,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "Имајте на уму да ово треба да изгледа као ваш излаз из `example3[example3.notnull()]`. Разлика овде је у томе што, уместо само индексирања на основу вредности са маском, `dropna` је уклонио те недостајуће вредности из `Series` `example3`.\n", + "Имајте на уму да ово треба да изгледа као ваш излаз из `example3[example3.notnull()]`. Разлика овде је у томе што је, уместо само индексирања на маскиране вредности, `dropna` уклонио те недостајуће вредности из `Series` `example3`.\n", "\n", - "Пошто DataFrame-ови имају две димензије, они пружају више опција за уклањање података.\n" + "Пошто DataFrame има две димензије, пружа више опција за уклањање података.\n" ] }, { @@ -1208,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Да ли сте приметили да је pandas променио тип података за две колоне у float како би прилагодио `NaN` вредности?)\n", + "(Да ли сте приметили да је pandas претворио две колоне у тип података `float` како би прилагодио `NaN` вредности?)\n", "\n", - "Не можете уклонити само једну вредност из `DataFrame`, већ морате уклонити целе редове или колоне. У зависности од тога шта радите, можда ћете желети да урадите једно или друго, и зато вам pandas нуди опције за оба случаја. Пошто у науци о подацима колоне углавном представљају променљиве, а редови представљају запажања, вероватније је да ћете уклањати редове података; подразумевана поставка за `dropna()` је да уклони све редове који садрже било какве null вредности:\n" + "Не можете уклонити само једну вредност из `DataFrame`, већ морате уклонити целе редове или колоне. У зависности од тога шта радите, можда ћете желети да урадите једно или друго, па вам pandas пружа могућности за оба. Пошто у науци о подацима колоне углавном представљају променљиве, а редови представљају запажања, вероватније је да ћете уклањати редове података; подразумевана поставка за `dropna()` је да уклони све редове који садрже било какве null вредности:\n" ] }, { @@ -1362,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Имајте на уму да ово може уклонити доста података које можда желите да задржите, нарочито у мањим скуповима података. Шта ако желите да уклоните само редове или колоне које садрже неколико или чак све недостајуће вредности? Те поставке можете одредити у `dropna` помоћу параметара `how` и `thresh`.\n", + "Имајте на уму да ово може уклонити много података које можда желите да задржите, посебно у мањим скуповима података. Шта ако желите да уклоните само редове или колоне које садрже неколико или чак све null вредности? Те поставке можете одредити у `dropna` помоћу параметара `how` и `thresh`.\n", "\n", - "Подразумевано, `how='any'` (ако желите сами да проверите или видите које друге параметре метода има, покрените `example4.dropna?` у код ћелији). Алтернативно, можете одредити `how='all'` како бисте уклонили само редове или колоне које садрже све недостајуће вредности. Хајде да проширимо наш пример `DataFrame` да бисмо видели како ово функционише у наредној вежби.\n" + "Подразумевано, `how='any'` (ако желите сами да проверите или видите које друге параметре метода има, покрените `example4.dropna?` у коду). Алтернативно, можете одредити `how='all'` како бисте уклонили само редове или колоне које садрже све null вредности. Проширићемо наш пример `DataFrame` да бисмо видели како ово функционише у наредној вежби.\n" ] }, { @@ -1456,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> Кључне поуке: \n", - "1. Уклањање null вредности је добра идеја само ако је скуп података довољно велик. \n", - "2. Цели редови или колоне могу се уклонити ако им недостаје већина података. \n", - "3. Метода `DataFrame.dropna(axis=)` помаже у уклањању null вредности. Аргумент `axis` означава да ли се уклањају редови или колоне. \n", - "4. Аргумент `how` такође може бити коришћен. Подразумевано је подешен на `any`. Дакле, уклања само оне редове/колоне који садрже било какве null вредности. Може се подесити на `all` како би се прецизирало да ће бити уклоњени само они редови/колоне где су све вредности null. \n" + "> Кључне напомене: \n", + "1. Уклањање празних вредности је добра идеја само ако је скуп података довољно велики. \n", + "2. Цели редови или колоне могу бити уклоњени ако већина њихових података недостаје. \n", + "3. Метода `DataFrame.dropna(axis=)` помаже у уклањању празних вредности. Аргумент `axis` означава да ли треба уклонити редове или колоне. \n", + "4. Аргумент `how` такође може бити коришћен. Подразумевано је постављен на `any`. Дакле, уклањају се само они редови/колоне који садрже било какве празне вредности. Може бити постављен на `all` да би се одредило да ће бити уклоњени само они редови/колоне где су све вредности празне. \n" ] }, { @@ -1492,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "Параметар `thresh` вам пружа прецизнију контролу: подешавате број *ненултих* вредности које ред или колона треба да имају како би били задржани:\n" + "Параметар `thresh` вам пружа прецизнију контролу: постављате број *не-null* вредности које ред или колона морају имати да би били задржани:\n" ] }, { @@ -1567,7 +1567,7 @@ "id": "fmSFnzZegRsG" }, "source": [ - "Овде су први и последњи ред одбачени, јер садрже само две ненулте вредности.\n" + "Овде су први и последњи ред уклоњени, јер садрже само две ненулте вредности.\n" ] }, { @@ -1580,7 +1580,7 @@ "\n", "Понекад има смисла попунити недостајуће вредности оним које би могле бити валидне. Постоји неколико техника за попуњавање празних вредности. Прва је коришћење доменског знања (знања о теми на којој се заснива скуп података) како би се на неки начин приближно одредиле недостајуће вредности.\n", "\n", - "Можете користити `isnull` за ово директно, али то може бити напорно, нарочито ако имате много вредности које треба попунити. Пошто је ово тако чест задатак у науци о подацима, pandas пружа `fillna`, који враћа копију `Series` или `DataFrame` са недостајућим вредностима замењеним оним које сами изаберете. Хајде да направимо још један пример `Series` да видимо како ово функционише у пракси.\n" + "Можете користити `isnull` за попуњавање вредности директно, али то може бити напорно, нарочито ако имате много вредности које треба попунити. Пошто је ово веома чест задатак у науци о подацима, pandas пружа функцију `fillna`, која враћа копију `Series` или `DataFrame` са недостајућим вредностима замењеним оним које сами изаберете. Хајде да направимо још један пример `Series` да видимо како ово функционише у пракси.\n" ] }, { @@ -1590,11 +1590,11 @@ }, "source": [ "### Категоријски подаци (Ненумерички)\n", - "Прво, хајде да размотримо ненумеричке податке. У скуповима података имамо колоне са категоријским подацима. На пример, пол, тачно или нетачно итд.\n", + "Прво, хајде да размотримо ненумеричке податке. У скуповима података имамо колоне са категоријским подацима, на пример, пол, тачно или нетачно итд.\n", "\n", - "У већини ових случајева, недостајуће вредности замењујемо `модом` колоне. Рецимо, имамо 100 података, од којих је 90 рекло тачно, 8 нетачно, а 2 нису попуњена. Тада можемо попунити та 2 са тачно, узимајући у обзир целу колону.\n", + "У већини ових случајева, недостајуће вредности замењујемо `модом` колоне. Рецимо, имамо 100 података, од којих је 90 одговорило тачно, 8 нетачно, а 2 нису попуњена. Тада можемо попунити та два са тачно, узимајући у обзир целу колону.\n", "\n", - "Опет, овде можемо користити знање из домена. Хајде да размотримо пример попуњавања са модом.\n" + "И овде можемо користити знање из домена. Хајде да размотримо пример попуњавања модом.\n" ] }, { @@ -1699,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Сада, хајде прво да пронађемо мод пре него што попунимо вредност `None` модом.\n" + ] }, { "cell_type": "code", @@ -1734,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Дакле, заменићемо None са True\n" + ] }, { "cell_type": "code", @@ -1844,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Како можемо видети, нулта вредност је замењена. Подразумева се да смо могли написати било шта уместо `'True'` и то би било замењено.\n" + "Као што можемо видети, нулта вредност је замењена. Наравно, могли смо написати било шта уместо `'True'` и то би било замењено.\n" ] }, { @@ -1857,13 +1861,13 @@ "Сада прелазимо на нумеричке податке. Овде постоје два уобичајена начина за замену недостајућих вредности:\n", "\n", "1. Замена медијаном реда\n", - "2. Замена аритметичком средином реда\n", + "2. Замена средњом вредношћу реда\n", "\n", - "Медијан користимо у случају искошених података са екстремним вредностима. Ово је зато што је медијан отпоран на екстремне вредности.\n", + "Медијан користимо у случају искривљених података са екстремним вредностима. То је зато што је медијан отпоран на екстремне вредности.\n", "\n", - "Када су подаци нормализовани, можемо користити аритметичку средину, јер би у том случају аритметичка средина и медијан били прилично слични.\n", + "Када су подаци нормализовани, можемо користити средњу вредност, јер би у том случају средња вредност и медијан били прилично блиски.\n", "\n", - "Прво, хајде да узмемо колону која је нормално распоређена и попунимо недостајућу вредност аритметичком средином те колоне.\n" + "Прво, узмимо колону која је нормално распоређена и попунимо недостајућу вредност средњом вредношћу те колоне.\n" ] }, { @@ -2003,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Попуњавање са средњом вредношћу\n" + ] }, { "cell_type": "code", @@ -2103,7 +2109,7 @@ "id": "CwpVFCrPTC5z" }, "source": [ - "Како можемо видети, недостајућа вредност је замењена њеном средњом вредношћу.\n" + "Као што можемо видети, недостајућа вредност је замењена њеном средином.\n" ] }, { @@ -2112,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Сада хајде да пробамо још један датафрејм, и овог пута ћемо заменити вредности None медијаном колоне.\n" + "Сада хајде да пробамо други датафрејм, и овог пута ћемо заменити вредности None медијаном колоне.\n" ] }, { @@ -2252,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Попуњавање медијаном\n" + ] }, { "cell_type": "code", @@ -2352,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Као што можемо видети, вредност NaN је замењена медијаном колоне\n" + "Као што можемо видети, вредност NaN је замењена медијаном колоне.\n" ] }, { @@ -2435,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Кључне тачке:\n", - "1. Попуњавање недостајућих вредности треба обавити када има мање података или када постоји стратегија за попуњавање недостајућих података.\n", - "2. Доменско знање може се користити за попуњавање недостајућих вредности њиховим приближним вредностима.\n", - "3. За категоријске податке, углавном се недостајуће вредности замењују модом колоне.\n", - "4. За нумеричке податке, недостајуће вредности се обично попуњавају просеком (за нормализоване скупове података) или медијаном колона.\n" + "> Главне напомене:\n", + "1. Попуњавање недостајућих вредности треба обавити када има мање података или постоји стратегија за попуњавање недостајућих података.\n", + "2. Доменско знање може се користити за попуњавање недостајућих вредности приближним проценама.\n", + "3. Код категоријских података, недостајуће вредности се углавном замењују модом колоне.\n", + "4. Код нумеричких података, недостајуће вредности се обично попуњавају просеком (за нормализоване скупове података) или медијаном колона.\n" ] }, { @@ -2470,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "Можете **попунити унапред** нултне вредности, што значи користити последњу важећу вредност за попуњавање нултне:\n" + "Можете **попунити унапред** празне вредности, што значи користити последњу важећу вредност за попуњавање празног места:\n" ] }, { @@ -2511,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Такође можете **уназад попунити** како бисте уназад пренели следећу важећу вредност и попунили празнину:\n" + "Можете такође **уназад попунити** да бисте уназад пренели следећу важећу вредност како бисте попунили празнину:\n" ] }, { @@ -2726,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Имајте у виду да када претходна вредност није доступна за попуњавање унапред, нулта вредност остаје.\n" + "Имајте на уму да када претходна вредност није доступна за попуњавање унапред, празна вредност остаје.\n" ] }, { @@ -2759,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Можете бити креативни у начину на који користите `fillna`. На пример, хајде да поново погледамо `example4`, али овог пута хајде да попунимо недостајуће вредности просеком свих вредности у `DataFrame`:\n" + "Можете бити креативни у начину на који користите `fillna`. На пример, хајде да поново погледамо `example4`, али овог пута да попунимо недостајуће вредности просеком свих вредности у `DataFrame`:\n" ] }, { @@ -2850,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Имајте на уму да је трећа колона још увек без вредности: подразумевани начин је попуњавање вредности ред по ред.\n", + "Приметите да је колона 3 и даље без вредности: подразумевани начин је попуњавање вредности ред по ред.\n", "\n", - "> **Закључак:** Постоји више начина за решавање недостајућих вредности у вашим скуповима података. Конкретна стратегија коју користите (уклањање, замена или начин на који их замењујете) треба да буде диктирана специфичностима тих података. Развићете бољи осећај за решавање недостајућих вредности што више радите и интерагујете са скуповима података.\n" + "> **Закључак:** Постоји више начина за решавање недостајућих вредности у вашим скуповима података. Конкретна стратегија коју користите (уклањање, замена или чак начин на који их замењујете) треба да буде одређена специфичностима тих података. Развићете бољи осећај за решавање недостајућих вредности што више радите и интерагујете са скуповима података.\n" ] }, { @@ -2863,7 +2871,7 @@ "source": [ "### Кодирање категоријалних података\n", "\n", - "Машинско учење модели раде искључиво са бројевима и било којим обликом нумеричких података. Неће моћи да разликује између \"Да\" и \"Не\", али ће моћи да разликује између 0 и 1. Зато, након попуњавања недостајућих вредности, потребно је да категоријалне податке кодирамо у неки нумерички облик како би модел могао да их разуме.\n", + "Машинско учење ради искључиво са бројевима и било којим обликом нумеричких података. Неће моћи да разликује између \"Да\" и \"Не\", али ће моћи да разликује између 0 и 1. Зато, након попуњавања недостајућих вредности, потребно је да категоријалне податке кодирамо у неки нумерички облик како би модел могао да их разуме.\n", "\n", "Кодирање се може обавити на два начина. О њима ћемо говорити у наставку.\n" ] @@ -2876,7 +2884,7 @@ "source": [ "**КОДИРАЊЕ ЕТИКЕТА**\n", "\n", - "Кодирање етикета је процес претварања сваке категорије у број. На пример, рецимо да имамо скуп података о путницима авиона и постоји колона која садржи њихову класу међу следећим ['бизнис класа', 'економска класа', 'прва класа']. Ако се изврши кодирање етикета, ово би било трансформисано у [0,1,2]. Хајде да видимо пример кроз код. Како ћемо учити `scikit-learn` у наредним бележницама, овде га нећемо користити.\n" + "Кодирање етикета подразумева претварање сваке категорије у број. На пример, рецимо да имамо скуп података о путницима авиона и постоји колона која садржи њихову класу међу следећим ['бизнис класа', 'економска класа', 'прва класа']. Ако се изврши кодирање етикета, ово би се трансформисало у [0,1,2]. Хајде да видимо пример кроз код. Како ћемо учити `scikit-learn` у наредним бележницама, овде га нећемо користити.\n" ] }, { @@ -2984,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Да бисмо извршили кодирање етикета на првој колони, прво морамо описати пресликавање из сваке класе у број, пре него што заменимо\n" + "Да бисмо извршили кодирање етикета на првој колони, прво морамо описати пресликавање сваке класе у број, пре него што заменимо.\n" ] }, { @@ -3086,7 +3094,7 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Као што можемо видети, резултат одговара ономе што смо очекивали. Дакле, када користимо енкодирање етикета? Енкодирање етикета се користи у једном или оба од следећа два случаја:\n", + "Као што можемо видети, резултат одговара ономе што смо очекивали. Дакле, када користимо кодирање етикета? Кодирање етикета се користи у једном или оба следећа случаја:\n", "1. Када је број категорија велики\n", "2. Када су категорије у одређеном редоследу.\n" ] @@ -3097,11 +3105,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**ЕНКОДИРАЊЕ ЈЕДНОГ ВРУЋЕГ**\n", + "**ONE HOT ENCODING**\n", "\n", - "Још један тип енкодирања је енкодирање једног врућег (One Hot Encoding). Код овог типа енкодирања, свака категорија из колоне се додаје као посебна колона, а свака тачка података добија 0 или 1 у зависности од тога да ли садржи ту категорију. Дакле, ако постоји *n* различитих категорија, *n* колона ће бити додато у оквир података.\n", + "Један од типова кодирања је One Hot Encoding. Код овог типа кодирања, свака категорија из колоне се додаје као посебна колона, а свака тачка података добија 0 или 1 у зависности од тога да ли садржи ту категорију. Дакле, ако постоји n различитих категорија, n колона ће бити додато у датасет.\n", "\n", - "На пример, узмимо исти пример класа у авиону. Категорије су биле: ['бизнис класа', 'економска класа', 'прва класа']. Дакле, ако извршимо енкодирање једног врућег, следеће три колоне ће бити додате у скуп података: ['class_business class', 'class_economy class', 'class_first class'].\n" + "На пример, узмимо исти пример класе авиона. Категорије су биле: ['business class', 'economy class', 'first class']. Дакле, ако применимо One Hot Encoding, следеће три колоне ће бити додате у датасет: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3209,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "Хајде да извршимо one hot encoding на првој колони\n" + "Хајде да извршимо једно-вруће кодирање на првој колони\n" ] }, { @@ -3334,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Свака колона кодирана методом један-вруће садржи 0 или 1, што означава да ли та категорија постоји за ту тачку података.\n" + "Свака колона кодирана методом један-на-један садржи 0 или 1, што означава да ли та категорија постоји за ту тачку података.\n" ] }, { @@ -3343,9 +3351,9 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "Када користимо one hot encoding? One hot encoding се користи у једном или оба од следећа два случаја:\n", + "Када користимо one hot encoding? One hot encoding се користи у једном или оба следећа случаја:\n", "\n", - "1. Када је број категорија и величина скупа података мања.\n", + "1. Када је број категорија и величина скупа података мањи.\n", "2. Када категорије не прате никакав одређени редослед.\n" ] }, @@ -3355,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Кључне тачке: \n", - "1. Кодирање се користи за претварање ненумеричких података у нумеричке податке. \n", - "2. Постоје две врсте кодирања: кодирање етикета (Label encoding) и једнократно кодирање (One Hot encoding), а оба се могу применити у зависности од захтева скупа података. \n" + "> Главне тачке:\n", + "1. Кодирање се врши како би се неконумерички подаци претворили у нумеричке.\n", + "2. Постоје два типа кодирања: кодирање етикета и One Hot кодирање, оба се могу применити у зависности од потреба скупа података.\n" ] }, { @@ -3370,7 +3378,7 @@ "\n", "> **Циљ учења:** На крају овог пододељка, требало би да будете спремни да идентификујете и уклоните дуплиране вредности из DataFrame-ова.\n", "\n", - "Поред недостајућих података, често ћете наићи на дуплиране податке у стварним скуповима података. Срећом, pandas пружа једноставан начин за откривање и уклањање дуплираних уноса.\n" + "Поред недостајућих података, често ћете наилазити на дуплиране податке у стварним скуповима података. Срећом, pandas пружа једноставан начин за откривање и уклањање дуплираних уноса.\n" ] }, { @@ -3381,7 +3389,7 @@ "source": [ "### Препознавање дупликата: `duplicated`\n", "\n", - "Можете лако уочити дупликатне вредности користећи метод `duplicated` у pandas-у, који враћа Булову маску која указује да ли је унос у `DataFrame`-у дупликат неког претходног. Хајде да направимо још један пример `DataFrame`-а како бисмо видели како ово функционише.\n" + "Можете лако уочити дупликате користећи метод `duplicated` у pandas-у, који враћа Булову маску која показује да ли је неки унос у `DataFrame`-у дупликат ранијег. Хајде да направимо још један пример `DataFrame`-а да видимо како то функционише.\n" ] }, { @@ -3511,7 +3519,7 @@ }, "source": [ "### Уклањање дупликата: `drop_duplicates`\n", - "`drop_duplicates` једноставно враћа копију података за које су све вредности означене као `duplicated` `False`:\n" + "`drop_duplicates` једноставно враћа копију података за које су све вредности `duplicated` `False`:\n" ] }, { @@ -3594,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "И `duplicated` и `drop_duplicates` подразумевано разматрају све колоне, али можете навести да разматрају само подскуп колона у вашем `DataFrame`:\n" + "И `duplicated` и `drop_duplicates` подразумевано узимају у обзир све колоне, али можете одредити да испитују само подскуп колона у вашем `DataFrame`:\n" ] }, { @@ -3670,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Закључак:** Уклањање дупликата података је суштински део готово сваког пројекта из области науке о подацима. Дупликати података могу променити резултате ваших анализа и дати вам нетачне резултате!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Провера квалитета података у стварном свету\n", + "\n", + "> **Циљ учења:** До краја овог одељка, требало би да будете способни да откривате и исправљате уобичајене проблеме са квалитетом података у стварном свету, укључујући недоследне категоријске вредности, абнормалне нумеричке вредности (изузетке) и дупликате ентитета са варијацијама.\n", + "\n", + "Иако су недостајуће вредности и тачни дупликати уобичајени проблеми, скупови података из стварног света често садрже суптилније проблеме:\n", + "\n", + "1. **Недоследне категоријске вредности**: Иста категорија написана на различите начине (нпр. \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Абнормалне нумеричке вредности**: Екстремни изузеци који указују на грешке у уносу података (нпр. старост = 999)\n", + "3. **Редови који су скоро дупликати**: Записи који представљају исти ентитет са благим варијацијама\n", + "\n", + "Хајде да истражимо технике за откривање и решавање ових проблема.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Прављење примерка „нечистог“ скупа података\n", + "\n", + "Прво, хајде да направимо пример скупа података који садржи типове проблема са којима се често сусрећемо у стварним подацима:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Откривање недоследних категоријских вредности\n", + "\n", + "Приметите да колона `country` има више представљања за исте земље. Хајде да идентификујемо те недоследности:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Стандардизација категоријских вредности\n", + "\n", + "Можемо направити мапирање за стандардизацију ових вредности. Једноставан приступ је конвертовање у мала слова и креирање речника за мапирање:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Алтернатива: Коришћење фазијског упоређивања**\n", + "\n", + "За сложеније случајеве, можемо користити фазијско упоређивање стрингова са библиотеком `rapidfuzz` како бисмо аутоматски открили сличне стрингове:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Откривање необичних нумеричких вредности (изузетака)\n", + "\n", + "Гледајући колону `age`, имамо неке сумњиве вредности као што су 199 и -5. Хајде да користимо статистичке методе за откривање ових изузетака.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Коришћење методе IQR (Интерквартилни опсег)\n", + "\n", + "Метода IQR је робусна статистичка техника за откривање одступајућих вредности која је мање осетљива на екстремне вредности:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Коришћење Z-Score методе\n", + "\n", + "Метода Z-score идентификује одступања на основу стандардних девијација од просека:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Руковање одступањима\n", + "\n", + "Када се открију, одступања могу бити обрађена на неколико начина:\n", + "1. **Уклонити**: Избрисати редове са одступањима (ако су грешке)\n", + "2. **Ограничити**: Заменити граничним вредностима\n", + "3. **Заменити са NaN**: Третирати као недостајуће податке и користити технике импутације\n", + "4. **Задржати**: Ако су легитимне екстремне вредности\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Откривање скоро идентичних редова\n", + "\n", + "Приметите да наш скуп података има више уноса за „John Smith“ са мало различитим вредностима. Хајде да идентификујемо потенцијалне дупликате на основу сличности имена.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Проналажење скоро идентичних подударности помоћу фазијског упаривања\n", + "\n", + "За напредније откривање дупликата, можемо користити фазијско упаривање за проналажење сличних имена:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Руковање дупликатима\n", + "\n", + "Када их идентификујете, потребно је да одлучите како да поступите са дупликатима:\n", + "1. **Задржати прво појављивање**: Користите `drop_duplicates(keep='first')`\n", + "2. **Задржати последње појављивање**: Користите `drop_duplicates(keep='last')`\n", + "3. **Агрегирати информације**: Комбиновати информације из редова који се понављају\n", + "4. **Ручна провера**: Означити за преглед од стране човека\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Резиме: Комплетан процес чишћења података\n", + "\n", + "Хајде да све спојимо у свеобухватан процес чишћења података:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Вежба изазова\n", + "\n", + "Сада је ваш ред! Испод је нови ред података са више проблема у квалитету. Можете ли:\n", + "\n", + "1. Идентификовати све проблеме у овом реду\n", + "2. Написати код за исправљање сваког проблема\n", + "3. Додати очишћени ред у скуп података\n", + "\n", + "Ево проблематичних података:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Кључне тачке\n", + "\n", + "1. **Неконзистентне категорије** су честе у подацима из стварног света. Увек проверите јединствене вредности и стандардизујте их користећи мапирање или фази упоређивање.\n", + "\n", + "2. **Екстремне вредности** могу значајно утицати на вашу анализу. Користите знање из области у комбинацији са статистичким методама (IQR, Z-score) да их откријете.\n", + "\n", + "3. **Скоро дупликати** су теже уочљиви од потпуних дупликата. Размотрите употребу фази упоређивања и нормализацију података (претварање у мала слова, уклањање празних места) како бисте их идентификовали.\n", + "\n", + "4. **Чишћење података је итеративно**. Можда ћете морати да примените више техника и прегледате резултате пре него што финализујете очишћен скуп података.\n", + "\n", + "5. **Документујте своје одлуке**. Водите евиденцију о корацима чишћења које сте применили и разлозима за то, јер је то важно за репродуктивност и транспарентност.\n", + "\n", + "> **Најбоља пракса:** Увек чувајте копију оригиналних \"неочишћених\" података. Никада не преписујте изворне датотеке са подацима - креирајте очишћене верзије са јасним конвенцијама именовања, као што је `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Одрицање од одговорности**: \nОвај документ је преведен коришћењем услуге за превођење помоћу вештачке интелигенције [Co-op Translator](https://github.com/Azure/co-op-translator). Иако тежимо тачности, молимо вас да имате у виду да аутоматски преводи могу садржати грешке или нетачности. Оригинални документ на изворном језику треба сматрати меродавним извором. За критичне информације препоручује се професионални превод од стране људи. Не сносимо одговорност за било каква неспоразумевања или погрешна тумачења која могу произаћи из коришћења овог превода.\n" + "\n---\n\n**Одрицање од одговорности**: \nОвај документ је преведен помоћу услуге за превођење уз помоћ вештачке интелигенције [Co-op Translator](https://github.com/Azure/co-op-translator). Иако настојимо да обезбедимо тачност, молимо вас да имате у виду да аутоматски преводи могу садржати грешке или нетачности. Оригинални документ на његовом изворном језику треба сматрати меродавним извором. За критичне информације препоручује се професионални превод од стране људског преводиоца. Не преузимамо одговорност за било каква погрешна тумачења или неспоразуме који могу настати услед коришћења овог превода.\n" ] } ], @@ -3704,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:56:01+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T21:09:31+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "sr" } diff --git a/translations/sv/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/sv/2-Working-With-Data/08-data-preparation/notebook.ipynb index ef9b63b1..883253e1 100644 --- a/translations/sv/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/sv/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,13 +8,13 @@ "source": [ "# Databeredning\n", "\n", - "[Original Notebook-källa från *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Original Notebook-källa från *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio av Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", - "## Utforska information i `DataFrame`\n", + "## Utforska information om `DataFrame`\n", "\n", "> **Lärandemål:** Efter denna del ska du känna dig bekväm med att hitta generell information om data som lagras i pandas DataFrames.\n", "\n", - "När du har laddat in din data i pandas kommer den med största sannolikhet att vara i en `DataFrame`. Men om datasettet i din `DataFrame` har 60,000 rader och 400 kolumner, hur börjar du ens få en uppfattning om vad du arbetar med? Lyckligtvis erbjuder pandas några praktiska verktyg för att snabbt få en översiktlig information om en `DataFrame` samt de första och sista raderna.\n", + "När du har laddat in din data i pandas kommer den med största sannolikhet att vara i en `DataFrame`. Men om datasettet i din `DataFrame` har 60 000 rader och 400 kolumner, hur börjar du ens få en känsla för vad du arbetar med? Lyckligtvis erbjuder pandas några praktiska verktyg för att snabbt få en överblick över en `DataFrame`, inklusive de första och sista raderna.\n", "\n", "För att utforska denna funktionalitet kommer vi att importera Python-biblioteket scikit-learn och använda ett ikoniskt dataset som varje dataanalytiker har sett hundratals gånger: den brittiske biologen Ronald Fishers *Iris*-dataset som användes i hans artikel från 1936 \"The use of multiple measurements in taxonomic problems\":\n" ] @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Vi har laddat in Iris-datasetet i variabeln `iris_df`. Innan vi börjar analysera datan kan det vara värdefullt att veta hur många datapunkter vi har och den totala storleken på datasetet. Det är användbart att få en överblick över mängden data vi arbetar med.\n" + "Vi har laddat in Iris-datasetet i variabeln `iris_df`. Innan vi börjar analysera datan kan det vara värdefullt att veta hur många datapunkter vi har och datasetets totala storlek. Det är användbart att få en överblick över mängden data vi arbetar med.\n" ] }, { @@ -78,7 +78,7 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Så, vi har att göra med 150 rader och 4 kolumner av data. Varje rad representerar en datapunkt och varje kolumn representerar en enskild egenskap som är kopplad till dataframen. Så i princip finns det 150 datapunkter som vardera innehåller 4 egenskaper.\n", + "Så vi har att göra med 150 rader och 4 kolumner av data. Varje rad representerar en datapunkt och varje kolumn representerar en enskild egenskap som är kopplad till dataframen. Så i princip finns det 150 datapunkter som innehåller 4 egenskaper vardera.\n", "\n", "`shape` här är ett attribut för dataframen och inte en funktion, vilket är anledningen till att det inte avslutas med ett par parenteser.\n" ] @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Låt oss nu gå vidare till de 4 kolumnerna med data. Vad representerar var och en av dem egentligen? Attributet `columns` ger oss namnen på kolumnerna i dataframe.\n" + "Låt oss nu gå vidare till de 4 kolumnerna med data. Vad representerar var och en av dem exakt? Attributet `columns` ger oss namnen på kolumnerna i dataramen.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Som vi kan se finns det fyra(4) kolumner. Attributet `columns` berättar namnen på kolumnerna och i princip inget annat. Detta attribut blir viktigt när vi vill identifiera vilka funktioner en dataset innehåller.\n" + "Som vi kan se, finns det fyra(4) kolumner. Attributet `columns` berättar för oss namnen på kolumnerna och i princip inget annat. Detta attribut blir viktigt när vi vill identifiera vilka funktioner en dataset innehåller.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Från detta kan vi göra några observationer: \n", - "1. Datatypen för varje kolumn: I detta dataset är all data lagrad som 64-bitars flyttal. \n", - "2. Antal icke-null-värden: Att hantera null-värden är ett viktigt steg i databeredningen. Detta kommer att behandlas senare i notebooken. \n" + "Här kan vi göra några observationer:\n", + "1. Datatypen för varje kolumn: I detta dataset lagras all data som 64-bitars flyttal.\n", + "2. Antal icke-nullvärden: Att hantera nullvärden är ett viktigt steg i databeredningen. Detta kommer att behandlas senare i notebooken.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Anta att vi har mycket numerisk data i vårt dataset. Univariata statistiska beräkningar såsom medelvärde, median, kvartiler etc. kan göras på var och en av kolumnerna individuellt. Funktionen `DataFrame.describe()` ger oss en statistisk sammanfattning av de numeriska kolumnerna i ett dataset.\n" + "Anta att vi har mycket numerisk data i vår dataset. Univariata statistiska beräkningar såsom medelvärde, median, kvartiler etc. kan göras på varje kolumn individuellt. Funktionen `DataFrame.describe()` ger oss en statistisk sammanfattning av de numeriska kolumnerna i en dataset.\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Som resultat här kan vi se fem(5) poster av datasetet. Om vi tittar på indexet till vänster, upptäcker vi att detta är de första fem raderna.\n" + "Som output här kan vi se fem(5) poster av datasetet. Om vi tittar på indexet till vänster, upptäcker vi att detta är de första fem raderna.\n" ] }, { @@ -582,9 +582,9 @@ "id": "31kBWfyLgRr3" }, "source": [ - "I praktiken är det användbart att enkelt kunna granska de första eller sista raderna i en `DataFrame`, särskilt när du letar efter avvikelser i ordnade dataset.\n", + "I praktiken är det användbart att enkelt kunna granska de första eller sista raderna i en `DataFrame`, särskilt när du letar efter avvikande värden i ordnade dataset.\n", "\n", - "Alla funktioner och attribut som visas ovan med hjälp av kodexempel hjälper oss att få en överblick och känsla för datan.\n", + "Alla funktioner och attribut som visas ovan med hjälp av kodexempel hjälper oss att få en känsla för datan.\n", "\n", "> **Slutsats:** Bara genom att titta på metadata om informationen i en DataFrame eller de första och sista värdena i en, kan du snabbt få en uppfattning om storlek, form och innehåll i den data du arbetar med.\n" ] @@ -606,7 +606,7 @@ "\n", "Pandas hanterar saknade värden på två sätt. Det första har du sett tidigare i tidigare avsnitt: `NaN`, eller Not a Number. Detta är faktiskt ett specialvärde som är en del av IEEE:s flyttalspecifikation och används endast för att indikera saknade flyttalsvärden.\n", "\n", - "För saknade värden som inte är flyttal använder pandas Python-objektet `None`. Även om det kan verka förvirrande att du kommer att stöta på två olika typer av värden som i princip säger samma sak, finns det goda programmatiska skäl för detta designval. I praktiken möjliggör detta att pandas kan erbjuda en bra kompromiss för de allra flesta fall. Trots detta har både `None` och `NaN` begränsningar som du behöver vara medveten om när det gäller hur de kan användas.\n" + "För saknade värden som inte är flyttal använder pandas Python-objektet `None`. Även om det kan verka förvirrande att du stöter på två olika typer av värden som i princip säger samma sak, finns det goda programmatiska skäl för detta designval. I praktiken möjliggör detta att pandas kan erbjuda en bra kompromiss för de allra flesta fall. Trots detta har både `None` och `NaN` begränsningar som du behöver vara medveten om när det gäller hur de kan användas.\n" ] }, { @@ -616,7 +616,7 @@ }, "source": [ "### `None`: icke-flytande saknade data\n", - "Eftersom `None` kommer från Python kan det inte användas i NumPy- och pandas-arrayer som inte har datatypen `'object'`. Kom ihåg att NumPy-arrayer (och datastrukturerna i pandas) kan innehålla endast en typ av data. Det är detta som ger dem deras enorma kraft för storskalig data- och beräkningsarbete, men det begränsar också deras flexibilitet. Sådana arrayer måste omvandlas till den \"lägsta gemensamma nämnaren\", datatypen som kan omfatta allt i arrayen. När `None` finns i arrayen betyder det att du arbetar med Python-objekt.\n", + "Eftersom `None` kommer från Python kan det inte användas i NumPy- och pandas-arrayer som inte har datatypen `'object'`. Kom ihåg att NumPy-arrayer (och datastrukturerna i pandas) endast kan innehålla en typ av data. Detta är vad som ger dem deras enorma kraft för storskalig data- och beräkningsarbete, men det begränsar också deras flexibilitet. Sådana arrayer måste omvandlas till den \"lägsta gemensamma nämnaren\", datatypen som kan omfatta allt i arrayen. När `None` finns i arrayen betyder det att du arbetar med Python-objekt.\n", "\n", "För att se detta i praktiken, överväg följande exempelarray (notera `dtype` för den):\n" ] @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Verkligheten med upphöjda datatyper medför två bieffekter. För det första kommer operationer att utföras på nivån av tolkad Python-kod snarare än kompilerad NumPy-kod. I praktiken innebär detta att alla operationer som involverar `Series` eller `DataFrames` med `None` i sig kommer att vara långsammare. Även om du förmodligen inte märker denna prestandaförlust, kan det bli ett problem för stora dataset.\n", + "Verkligheten med upphöjda datatyper medför två bieffekter. För det första kommer operationer att utföras på nivån av tolkad Python-kod snarare än kompilerad NumPy-kod. I praktiken innebär detta att alla operationer som involverar `Series` eller `DataFrames` med `None` i dem kommer att vara långsammare. Även om du förmodligen inte märker denna prestandaförlust, kan det bli ett problem för stora dataset.\n", "\n", - "Den andra bieffekten härrör från den första. Eftersom `None` i princip drar tillbaka `Series` eller `DataFrame`s till den vanliga Python-världen, kommer användning av NumPy/pandas-aggregationer som `sum()` eller `min()` på arrayer som innehåller ett ``None``-värde generellt att resultera i ett fel:\n" + "Den andra bieffekten härstammar från den första. Eftersom `None` i princip drar tillbaka `Series` eller `DataFrame`s till den vanliga Python-världen, kommer användning av NumPy/pandas-aggregationer som `sum()` eller `min()` på arrayer som innehåller ett ``None``-värde generellt att resultera i ett fel:\n" ] }, { @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Viktig poäng**: Addition (och andra operationer) mellan heltal och `None`-värden är odefinierad, vilket kan begränsa vad du kan göra med dataset som innehåller dem.\n" + "**Viktig insikt**: Addition (och andra operationer) mellan heltal och `None`-värden är odefinierad, vilket kan begränsa vad du kan göra med dataset som innehåller dem.\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "De goda nyheterna: aggregeringar som körs på arrayer med `NaN` i dem ger inga fel. De dåliga nyheterna: resultaten är inte konsekvent användbara:\n" + "Den goda nyheten: aggregeringar som körs på arrayer med `NaN` i dem ger inga fel. Den dåliga nyheten: resultaten är inte konsekvent användbara:\n" ] }, { @@ -842,7 +842,7 @@ "source": [ "### `NaN` och `None`: nullvärden i pandas\n", "\n", - "Även om `NaN` och `None` kan bete sig något olika, är pandas ändå utformat för att hantera dem som utbytbara. För att förstå vad vi menar, betrakta en `Series` av heltal:\n" + "Även om `NaN` och `None` kan bete sig något olika, är pandas ändå utformat för att hantera dem omväxlande. För att förstå vad vi menar, betrakta en `Series` med heltal:\n" ] }, { @@ -906,7 +906,7 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Vid uppgradering av datatyper för att skapa datahomogenitet i `Series` och `DataFrame`s, kommer pandas villigt att byta ut saknade värden mellan `None` och `NaN`. På grund av denna designfunktion kan det vara användbart att tänka på `None` och `NaN` som två olika varianter av \"null\" i pandas. Faktum är att några av de centrala metoderna du kommer att använda för att hantera saknade värden i pandas återspeglar denna idé i sina namn:\n", + "När man uppgraderar datatyper för att skapa datahomogenitet i `Series` och `DataFrame`s, kommer pandas villigt att byta ut saknade värden mellan `None` och `NaN`. På grund av denna designfunktion kan det vara användbart att tänka på `None` och `NaN` som två olika varianter av \"null\" i pandas. Faktum är att några av de centrala metoderna du kommer att använda för att hantera saknade värden i pandas återspeglar denna idé i sina namn:\n", "\n", "- `isnull()`: Genererar en Boolean-mask som indikerar saknade värden\n", "- `notnull()`: Motsatsen till `isnull()`\n", @@ -924,7 +924,7 @@ "source": [ "### Upptäcka nullvärden\n", "\n", - "Nu när vi har förstått vikten av saknade värden, behöver vi identifiera dem i vår dataset innan vi hanterar dem. \n", + "Nu när vi har förstått vikten av saknade värden, behöver vi identifiera dem i vår dataset innan vi hanterar dem. \n", "Både `isnull()` och `notnull()` är dina primära metoder för att upptäcka nullvärden. Båda returnerar Boolean-masker över dina data.\n" ] }, @@ -978,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Titta noga på resultatet. Är det något som förvånar dig? Även om `0` är ett aritmetiskt nollvärde, är det ändå ett fullvärdigt heltal och pandas behandlar det som sådant. `''` är lite mer subtilt. Även om vi använde det i avsnitt 1 för att representera ett tomt strängvärde, är det ändå ett strängobjekt och inte en representation av null enligt pandas.\n", + "Titta noga på resultatet. Är något av det förvånande? Även om `0` är en aritmetisk null, är det ändå ett fullt giltigt heltal och pandas behandlar det som sådant. `''` är lite mer subtilt. Även om vi använde det i avsnitt 1 för att representera ett tomt strängvärde, är det ändå ett strängobjekt och inte en representation av null enligt pandas.\n", "\n", - "Nu ska vi vända på detta och använda dessa metoder på ett sätt som liknar hur du kommer att använda dem i praktiken. Du kan använda Booleanska masker direkt som ett ``Series``- eller ``DataFrame``-index, vilket kan vara användbart när du försöker arbeta med isolerade saknade (eller befintliga) värden.\n", + "Nu ska vi vända på detta och använda dessa metoder på ett sätt som liknar hur du kommer att använda dem i praktiken. Du kan använda Booleska masker direkt som ett ``Series``- eller ``DataFrame``-index, vilket kan vara användbart när du försöker arbeta med isolerade saknade (eller befintliga) värden.\n", "\n", - "Om vi vill ha det totala antalet saknade värden kan vi helt enkelt summera masken som produceras av metoden `isnull()`.\n" + "Om vi vill ha det totala antalet saknade värden kan vi helt enkelt göra en summering över masken som produceras av metoden `isnull()`.\n" ] }, { @@ -1049,15 +1049,15 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### Hantering av saknade data\n", + "### Hantera saknade data\n", "\n", - "> **Lärandemål:** Efter att ha gått igenom denna del bör du veta hur och när du ska ersätta eller ta bort nullvärden från DataFrames.\n", + "> **Lärandemål:** I slutet av denna del bör du veta hur och när du ska ersätta eller ta bort nullvärden från DataFrames.\n", "\n", - "Maskininlärningsmodeller kan inte hantera saknade data själva. Därför måste vi hantera dessa saknade värden innan vi skickar in datan i modellen.\n", + "Maskininlärningsmodeller kan inte hantera saknade data själva. Därför måste vi hantera dessa saknade värden innan vi skickar in data i modellen.\n", "\n", - "Hur saknade data hanteras innebär subtila kompromisser och kan påverka din slutliga analys och verkliga resultat.\n", + "Hur saknade data hanteras innebär subtila avvägningar och kan påverka din slutliga analys och verkliga resultat.\n", "\n", - "Det finns främst två sätt att hantera saknade data:\n", + "Det finns huvudsakligen två sätt att hantera saknade data:\n", "\n", "1. Ta bort raden som innehåller det saknade värdet\n", "2. Ersätt det saknade värdet med något annat värde\n", @@ -1073,7 +1073,7 @@ "source": [ "### Ta bort nullvärden\n", "\n", - "Mängden data vi skickar vidare till vår modell har en direkt påverkan på dess prestanda. Att ta bort nullvärden innebär att vi minskar antalet datapunkter och därmed storleken på datasetet. Därför är det rekommenderat att ta bort rader med nullvärden när datasetet är ganska stort.\n", + "Mängden data vi skickar vidare till vår modell har en direkt påverkan på dess prestanda. Att ta bort nullvärden innebär att vi minskar antalet datapunkter och därmed minskar storleken på datasetet. Därför är det lämpligt att ta bort rader med nullvärden när datasetet är ganska stort.\n", "\n", "Ett annat exempel kan vara att en viss rad eller kolumn har många saknade värden. Då kan de tas bort eftersom de inte skulle tillföra mycket värde till vår analys, eftersom det mesta av datan saknas för den raden/kolumnen.\n", "\n", @@ -1116,7 +1116,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "Observera att detta ska se ut som ditt resultat från `example3[example3.notnull()]`. Skillnaden här är att, istället för att bara indexera på de maskerade värdena, har `dropna` tagit bort de saknade värdena från `Series` `example3`.\n", + "Observera att detta bör se ut som ditt resultat från `example3[example3.notnull()]`. Skillnaden här är att, istället för att bara indexera på de maskerade värdena, har `dropna` tagit bort de saknade värdena från `Series` `example3`.\n", "\n", "Eftersom DataFrames har två dimensioner, erbjuder de fler alternativ för att ta bort data.\n" ] @@ -1208,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Såg du att pandas konverterade två av kolumnerna till flyttal för att hantera `NaN`-värdena?)\n", + "(Såg du att pandas ändrade två av kolumnerna till flyttal för att hantera `NaN`-värdena?)\n", "\n", - "Du kan inte ta bort en enskild värde från en `DataFrame`, så du måste ta bort hela rader eller kolumner. Beroende på vad du gör kan det vara mer lämpligt att välja det ena eller det andra, och därför ger pandas dig alternativ för båda. Eftersom kolumner i dataanalys vanligtvis representerar variabler och rader representerar observationer, är det mer sannolikt att du tar bort rader med data; standardinställningen för `dropna()` är att ta bort alla rader som innehåller några nullvärden:\n" + "Du kan inte ta bort en enskild värde från en `DataFrame`, så du måste ta bort hela rader eller kolumner. Beroende på vad du gör kan du vilja göra det ena eller det andra, och därför ger pandas dig alternativ för båda. Eftersom kolumner i datavetenskap vanligtvis representerar variabler och rader representerar observationer, är det mer sannolikt att du tar bort rader med data; standardinställningen för `dropna()` är att ta bort alla rader som innehåller några nullvärden:\n" ] }, { @@ -1362,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Observera att detta kan ta bort mycket data som du kanske vill behålla, särskilt i mindre dataset. Vad händer om du bara vill ta bort rader eller kolumner som innehåller flera eller till och med bara alla nullvärden? Du anger dessa inställningar i `dropna` med parametrarna `how` och `thresh`.\n", + "Observera att detta kan ta bort mycket data som du kanske vill behålla, särskilt i mindre dataset. Vad händer om du bara vill ta bort rader eller kolumner som innehåller flera eller till och med alla nullvärden? Du anger dessa inställningar i `dropna` med parametrarna `how` och `thresh`.\n", "\n", - "Som standard är `how='any'` (om du vill kontrollera själv eller se vilka andra parametrar metoden har, kör `example4.dropna?` i en kodcell). Du kan alternativt ange `how='all'` för att endast ta bort rader eller kolumner som innehåller alla nullvärden. Låt oss utöka vårt exempel på `DataFrame` för att se detta i praktiken i nästa övning.\n" + "Som standard är `how='any'` (om du vill kontrollera själv eller se vilka andra parametrar metoden har, kör `example4.dropna?` i en kodcell). Du kan alternativt ange `how='all'` för att endast ta bort rader eller kolumner som innehåller alla nullvärden. Låt oss utöka vårt exempel `DataFrame` för att se detta i praktiken i nästa övning.\n" ] }, { @@ -1456,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> Viktiga punkter: \n", - "1. Att ta bort nullvärden är en bra idé endast om datasetet är tillräckligt stort. \n", - "2. Hela rader eller kolumner kan tas bort om de saknar större delen av sin data. \n", - "3. Metoden `DataFrame.dropna(axis=)` hjälper till att ta bort nullvärden. Argumentet `axis` anger om rader eller kolumner ska tas bort. \n", - "4. Argumentet `how` kan också användas. Som standard är det inställt på `any`, vilket innebär att endast de rader/kolumner som innehåller några nullvärden tas bort. Det kan ställas in på `all` för att ange att vi endast tar bort de rader/kolumner där alla värden är null. \n" + "> Viktiga punkter:\n", + "1. Att ta bort nullvärden är en bra idé endast om datasetet är tillräckligt stort.\n", + "2. Hela rader eller kolumner kan tas bort om de saknar större delen av sina data.\n", + "3. Metoden `DataFrame.dropna(axis=)` hjälper till att ta bort nullvärden. Argumentet `axis` anger om rader eller kolumner ska tas bort.\n", + "4. Argumentet `how` kan också användas. Som standard är det inställt på `any`, vilket innebär att endast de rader/kolumner som innehåller några nullvärden tas bort. Det kan ställas in på `all` för att ange att vi endast tar bort de rader/kolumner där alla värden är null.\n" ] }, { @@ -1492,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "Parametern `thresh` ger dig mer detaljerad kontroll: du anger antalet *icke-null* värden som en rad eller kolumn måste ha för att behållas:\n" + "Parametern `thresh` ger dig mer detaljerad kontroll: du anger antalet *icke-null* värden som en rad eller kolumn behöver ha för att behållas:\n" ] }, { @@ -1567,7 +1567,7 @@ "id": "fmSFnzZegRsG" }, "source": [ - "Här har den första och sista raden tagits bort, eftersom de endast innehåller två icke-nollvärden.\n" + "Här har den första och sista raden tagits bort, eftersom de endast innehåller två icke-nullvärden.\n" ] }, { @@ -1576,11 +1576,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### Fyll i nullvärden\n", + "### Fyllning av nullvärden\n", "\n", - "Ibland kan det vara logiskt att fylla i saknade värden med sådana som kan vara giltiga. Det finns några tekniker för att fylla i nullvärden. Den första är att använda domänkunskap (kunskap om ämnet som datasetet baseras på) för att på något sätt approximera de saknade värdena.\n", + "Ibland kan det vara logiskt att fylla i saknade värden med sådana som kan vara giltiga. Det finns några tekniker för att fylla nullvärden. Den första är att använda domänkunskap (kunskap om ämnet som datasetet baseras på) för att på något sätt approximera de saknade värdena.\n", "\n", - "Du kan använda `isnull` för att göra detta direkt, men det kan vara arbetskrävande, särskilt om du har många värden att fylla i. Eftersom detta är en så vanlig uppgift inom dataanalys, erbjuder pandas `fillna`, som returnerar en kopia av `Series` eller `DataFrame` där de saknade värdena ersätts med ett värde du väljer. Låt oss skapa ett annat exempel på `Series` för att se hur detta fungerar i praktiken.\n" + "Du kan använda `isnull` för att göra detta direkt, men det kan vara arbetskrävande, särskilt om du har många värden att fylla. Eftersom detta är en så vanlig uppgift inom datavetenskap, erbjuder pandas `fillna`, som returnerar en kopia av `Series` eller `DataFrame` där de saknade värdena ersätts med ett värde du väljer. Låt oss skapa ett annat exempel på `Series` för att se hur detta fungerar i praktiken.\n" ] }, { @@ -1592,9 +1592,9 @@ "### Kategoriska data (icke-numeriska)\n", "Låt oss först titta på icke-numeriska data. I dataset har vi kolumner med kategoriska data, t.ex. kön, sant eller falskt osv.\n", "\n", - "I de flesta av dessa fall ersätter vi saknade värden med kolumnens `mode`. Anta att vi har 100 datapunkter där 90 har angett sant, 8 har angett falskt och 2 har inte fyllt i. Då kan vi fylla de 2 saknade värdena med sant, baserat på hela kolumnen.\n", + "I de flesta av dessa fall ersätter vi saknade värden med kolumnens `mode`. Anta att vi har 100 datapunkter där 90 har angett Sant, 8 har angett Falskt och 2 har inte fyllt i. Då kan vi fylla de 2 med Sant, baserat på hela kolumnen.\n", "\n", - "Även här kan vi använda domänkunskap. Låt oss titta på ett exempel på att fylla med mode.\n" + "Även här kan vi använda domänkunskap. Låt oss ta ett exempel på att fylla med mode.\n" ] }, { @@ -1699,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Nu ska vi först hitta typvärdet innan vi fyller `None`-värdet med typvärdet.\n" + ] }, { "cell_type": "code", @@ -1734,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Så vi kommer att ersätta None med True\n" + ] }, { "cell_type": "code", @@ -1853,17 +1857,17 @@ "id": "heYe1I0dOmQ_" }, "source": [ - "### Numerisk data\n", - "Nu går vi vidare till numerisk data. Här har vi två vanliga sätt att ersätta saknade värden:\n", + "### Numerisk Data\n", + "Nu går vi vidare till numerisk data. Här finns det två vanliga sätt att ersätta saknade värden:\n", "\n", "1. Ersätt med medianen för raden \n", "2. Ersätt med medelvärdet för raden \n", "\n", - "Vi ersätter med medianen när det handlar om snedfördelad data med avvikande värden. Detta beror på att medianen är robust mot avvikande värden.\n", + "Vi använder medianen när data är snedfördelad och innehåller avvikande värden. Detta beror på att medianen är robust mot avvikande värden.\n", "\n", - "När datan är normaliserad kan vi använda medelvärdet, eftersom medelvärde och median i det fallet skulle ligga ganska nära varandra.\n", + "När data är normaliserad kan vi använda medelvärdet, eftersom medelvärdet och medianen då ligger ganska nära varandra.\n", "\n", - "Låt oss först ta en kolumn som är normalfördelad och fylla i det saknade värdet med kolumnens medelvärde.\n" + "Låt oss först ta en kolumn som är normalfördelad och fylla de saknade värdena med medelvärdet för kolumnen.\n" ] }, { @@ -2003,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Fyller med medel\n" + ] }, { "cell_type": "code", @@ -2103,7 +2109,7 @@ "id": "CwpVFCrPTC5z" }, "source": [ - "Som vi kan se har det saknade värdet ersatts med sitt medelvärde.\n" + "Som vi kan se har det saknade värdet ersatts med dess medelvärde.\n" ] }, { @@ -2252,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Fyllning med median\n" + ] }, { "cell_type": "code", @@ -2436,8 +2444,8 @@ }, "source": [ "> Viktiga punkter:\n", - "1. Att fylla i saknade värden bör göras antingen när det finns lite data eller när det finns en strategi för att fylla i de saknade värdena.\n", - "2. Domänkunskap kan användas för att fylla i saknade värden genom att approximera dem.\n", + "1. Att fylla i saknade värden bör göras när det antingen finns lite data eller när det finns en strategi för att fylla i de saknade värdena.\n", + "2. Domänkunskap kan användas för att approximera och fylla i saknade värden.\n", "3. För kategoriska data ersätts saknade värden oftast med kolumnens typvärde.\n", "4. För numeriska data fylls saknade värden vanligtvis i med medelvärdet (för normaliserade dataset) eller medianen av kolumnerna.\n" ] @@ -2470,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "Du kan **framåtifylla** nullvärden, vilket innebär att använda det senaste giltiga värdet för att fylla ett null:\n" + "Du kan **framåt-fylla** nullvärden, vilket innebär att använda det senaste giltiga värdet för att fylla ett null:\n" ] }, { @@ -2511,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Du kan också **bakåtifylla** för att sprida nästa giltiga värde bakåt för att fylla ett null:\n" + "Du kan också **bakfylla** för att sprida nästa giltiga värde bakåt för att fylla ett null:\n" ] }, { @@ -2726,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Observera att när ett tidigare värde inte är tillgängligt för framåtfyllning, kvarstår nullvärdet.\n" + "Observera att när ett tidigare värde inte är tillgängligt för framåtifyllning, kvarstår nullvärdet.\n" ] }, { @@ -2759,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Du kan vara kreativ med hur du använder `fillna`. Till exempel, låt oss titta på `example4` igen, men den här gången fyller vi de saknade värdena med genomsnittet av alla värden i `DataFrame`:\n" + "Du kan vara kreativ med hur du använder `fillna`. Till exempel, låt oss titta på `example4` igen, men den här gången fyller vi de saknade värdena med medelvärdet av alla värden i `DataFrame`:\n" ] }, { @@ -2852,7 +2860,7 @@ "source": [ "Observera att kolumn 3 fortfarande saknar värden: standardriktningen är att fylla värden radvis.\n", "\n", - "> **Slutsats:** Det finns flera sätt att hantera saknade värden i dina dataset. Den specifika strategi du använder (ta bort dem, ersätta dem, eller till och med hur du ersätter dem) bör styras av detaljerna i den specifika datan. Du kommer att utveckla en bättre känsla för hur du hanterar saknade värden ju mer du arbetar med och interagerar med dataset.\n" + "> **Slutsats:** Det finns flera sätt att hantera saknade värden i dina dataset. Den specifika strategi du använder (ta bort dem, ersätta dem eller till och med hur du ersätter dem) bör styras av detaljerna i just det datat. Du kommer att utveckla en bättre känsla för hur du hanterar saknade värden ju mer du arbetar med och interagerar med dataset.\n" ] }, { @@ -2863,7 +2871,7 @@ "source": [ "### Kodning av kategoriska data\n", "\n", - "Maskininlärningsmodeller hanterar endast siffror och all typ av numerisk data. De kan inte skilja mellan ett Ja och ett Nej, men de kan skilja mellan 0 och 1. Så efter att ha fyllt i de saknade värdena behöver vi koda den kategoriska datan till någon form av numerisk representation för att modellen ska kunna förstå.\n", + "Maskininlärningsmodeller hanterar endast siffror och all form av numerisk data. De kan inte skilja mellan ett Ja och ett Nej, men de kan skilja mellan 0 och 1. Så efter att ha fyllt i de saknade värdena behöver vi koda de kategoriska data till någon numerisk form för att modellen ska kunna förstå dem.\n", "\n", "Kodning kan göras på två sätt. Vi kommer att diskutera dem härnäst.\n" ] @@ -2876,7 +2884,7 @@ "source": [ "**ETIKETTKODNING**\n", "\n", - "Etikettkodning innebär att varje kategori omvandlas till ett nummer. Till exempel, säg att vi har en dataset med flygpassagerare och det finns en kolumn som innehåller deras klass bland följande ['business class', 'economy class', 'first class']. Om etikettkodning görs på detta, skulle det omvandlas till [0,1,2]. Låt oss se ett exempel via kod. Eftersom vi kommer att lära oss `scikit-learn` i de kommande anteckningsböckerna, kommer vi inte att använda det här.\n" + "Etikettkodning innebär att varje kategori omvandlas till ett nummer. Till exempel, anta att vi har en dataset med flygpassagerare och det finns en kolumn som innehåller deras klass bland följande ['business class', 'economy class', 'first class']. Om etikettkodning utförs på detta, skulle det omvandlas till [0,1,2]. Låt oss se ett exempel via kod. Eftersom vi kommer att lära oss `scikit-learn` i de kommande anteckningsböckerna, kommer vi inte att använda det här.\n" ] }, { @@ -2984,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "För att utföra etikettkodning på den första kolumnen måste vi först beskriva en mappning från varje klass till ett nummer, innan vi ersätter\n" + "För att utföra etikettkodning på den första kolumnen måste vi först beskriva en mappning från varje klass till ett nummer, innan vi ersätter.\n" ] }, { @@ -3086,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Som vi kan se, stämmer resultatet överens med vad vi förväntade oss. Så, när använder vi etikettkodning? Etikettkodning används i ett eller båda av följande fall: \n", - "1. När antalet kategorier är stort \n", - "2. När kategorierna har en ordning. \n" + "Som vi kan se, stämmer resultatet överens med vad vi trodde skulle hända. Så, när använder vi etikettkodning? Etikettkodning används i ett eller båda av följande fall:\n", + "1. När antalet kategorier är stort\n", + "2. När kategorierna har en ordning.\n" ] }, { @@ -3099,9 +3107,9 @@ "source": [ "**ONE HOT ENCODING**\n", "\n", - "En annan typ av kodning är One Hot Encoding. I denna typ av kodning läggs varje kategori i kolumnen till som en separat kolumn, och varje datapunkt får en 0 eller en 1 beroende på om den innehåller den kategorin eller inte. Så, om det finns n olika kategorier, kommer n kolumner att läggas till i dataramen.\n", + "En annan typ av kodning är One Hot Encoding. I denna typ av kodning läggs varje kategori i kolumnen till som en separat kolumn, och varje datapunkt får antingen en 0 eller en 1 beroende på om den innehåller den kategorin. Så, om det finns n olika kategorier, kommer n kolumner att läggas till i dataramen.\n", "\n", - "Till exempel, låt oss ta samma exempel med flygplansklasser. Kategorierna var: ['business class', 'economy class', 'first class']. Om vi utför one hot encoding, kommer följande tre kolumner att läggas till i datasetet: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Till exempel, låt oss ta samma exempel med flygplansklasser. Kategorierna var: ['business class', 'economy class', 'first class']. Om vi utför One Hot Encoding kommer följande tre kolumner att läggas till i datasetet: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3334,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Varje one-hot-kodad kolumn innehåller 0 eller 1, vilket anger om den kategorin existerar för den datapunkten.\n" + "Varje one-hot-kodad kolumn innehåller 0 eller 1, vilket anger om den kategorin finns för den datapunkten.\n" ] }, { @@ -3357,7 +3365,7 @@ "source": [ "> Viktiga punkter:\n", "1. Kodning görs för att omvandla icke-numerisk data till numerisk data.\n", - "2. Det finns två typer av kodning: Label encoding och One Hot encoding, som båda kan utföras beroende på datasetets behov.\n" + "2. Det finns två typer av kodning: Etikettkodning och One Hot-kodning, som båda kan utföras beroende på datasetets behov.\n" ] }, { @@ -3368,9 +3376,9 @@ "source": [ "## Ta bort duplicerad data\n", "\n", - "> **Lärandemål:** Efter denna del ska du känna dig bekväm med att identifiera och ta bort duplicerade värden från DataFrames.\n", + "> **Lärandemål:** Efter denna del bör du känna dig bekväm med att identifiera och ta bort duplicerade värden från DataFrames.\n", "\n", - "Förutom saknade data kommer du ofta stöta på duplicerad data i verkliga dataset. Lyckligtvis erbjuder pandas ett enkelt sätt att upptäcka och ta bort duplicerade poster.\n" + "Förutom saknade data kommer du ofta att stöta på duplicerad data i verkliga dataset. Lyckligtvis erbjuder pandas ett enkelt sätt att upptäcka och ta bort duplicerade poster.\n" ] }, { @@ -3670,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Slutsats:** Att ta bort duplicerad data är en viktig del av nästan varje datavetenskapsprojekt. Duplicerad data kan förändra resultaten av dina analyser och ge dig felaktiga resultat!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Kvalitetskontroller för verkliga data\n", + "\n", + "> **Lärandemål:** Efter denna sektion bör du känna dig bekväm med att upptäcka och korrigera vanliga kvalitetsproblem i verkliga data, inklusive inkonsekventa kategoriska värden, avvikande numeriska värden (outliers) och duplicerade enheter med variationer.\n", + "\n", + "Även om saknade värden och exakta dubbletter är vanliga problem, innehåller verkliga dataset ofta mer subtila problem:\n", + "\n", + "1. **Inkonsekventa kategoriska värden**: Samma kategori stavas olika (t.ex. \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Avvikande numeriska värden**: Extremvärden som indikerar fel vid dataregistrering (t.ex. ålder = 999)\n", + "3. **Nästan duplicerade rader**: Poster som representerar samma enhet med små variationer\n", + "\n", + "Låt oss utforska tekniker för att upptäcka och hantera dessa problem.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Skapa ett exempel på ett \"smutsigt\" dataset\n", + "\n", + "Först ska vi skapa ett exempel på dataset som innehåller de typer av problem vi ofta stöter på i verkliga data:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Identifiera inkonsekventa kategoriska värden\n", + "\n", + "Observera att kolumnen `country` har flera representationer för samma länder. Låt oss identifiera dessa inkonsekvenser:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Standardisera kategoriska värden\n", + "\n", + "Vi kan skapa en kartläggning för att standardisera dessa värden. En enkel metod är att konvertera till små bokstäver och skapa en kartläggningsordbok:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternativ: Använda Fuzzy Matching**\n", + "\n", + "För mer komplexa fall kan vi använda fuzzy-strängmatchning med `rapidfuzz`-biblioteket för att automatiskt upptäcka liknande strängar:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Upptäcka avvikande numeriska värden (Outliers)\n", + "\n", + "Om vi tittar på kolumnen `age` ser vi några misstänkta värden som 199 och -5. Låt oss använda statistiska metoder för att identifiera dessa avvikande värden.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Använda IQR-metoden (Interkvartilavstånd)\n", + "\n", + "IQR-metoden är en robust statistisk teknik för att identifiera avvikande värden som är mindre känslig för extrema värden:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Använda Z-score-metoden\n", + "\n", + "Z-score-metoden identifierar avvikare baserat på standardavvikelser från medelvärdet:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Hantering av avvikare\n", + "\n", + "När avvikare har upptäckts kan de hanteras på flera sätt:\n", + "1. **Ta bort**: Ta bort rader med avvikare (om de är felaktiga)\n", + "2. **Begränsa**: Ersätt med gränsvärden\n", + "3. **Ersätt med NaN**: Behandla som saknade data och använd imputeringstekniker\n", + "4. **Behåll**: Om de är legitima extrema värden\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Identifiera Nästan-Duplikerade Rader\n", + "\n", + "Observera att vår dataset har flera poster för \"John Smith\" med något olika värden. Låt oss identifiera potentiella duplikat baserat på namns likhet.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Hitta nästan-duplicat med fuzzy matching\n", + "\n", + "För mer avancerad upptäckt av duplicat kan vi använda fuzzy matching för att hitta liknande namn:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Hantering av dubbletter\n", + "\n", + "När dubbletter har identifierats måste du bestämma hur de ska hanteras:\n", + "1. **Behåll första förekomsten**: Använd `drop_duplicates(keep='first')`\n", + "2. **Behåll sista förekomsten**: Använd `drop_duplicates(keep='last')`\n", + "3. **Sammanfoga information**: Kombinera information från dubblettrader\n", + "4. **Manuell granskning**: Markera för mänsklig granskning\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Sammanfattning: Komplett Data Cleaning Pipeline\n", + "\n", + "Låt oss sätta ihop allt till en omfattande rengöringspipeline:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Utmaningsövning\n", + "\n", + "Nu är det din tur! Nedan finns en ny rad med data som har flera kvalitetsproblem. Kan du:\n", + "\n", + "1. Identifiera alla problem i denna rad\n", + "2. Skriva kod för att åtgärda varje problem\n", + "3. Lägga till den rengjorda raden i datasetet\n", + "\n", + "Här är den problematiska datan:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Viktiga punkter\n", + "\n", + "1. **Inkonsekventa kategorier** är vanliga i verkliga data. Kontrollera alltid unika värden och standardisera dem med hjälp av mappningar eller oskarp matchning.\n", + "\n", + "2. **Avvikare** kan påverka din analys avsevärt. Använd domänkunskap i kombination med statistiska metoder (IQR, Z-score) för att upptäcka dem.\n", + "\n", + "3. **Nästan-duplicat** är svårare att upptäcka än exakta duplicat. Överväg att använda oskarp matchning och normalisera data (göra små bokstäver, ta bort mellanslag) för att identifiera dem.\n", + "\n", + "4. **Datastädning är iterativ**. Du kan behöva tillämpa flera tekniker och granska resultaten innan du slutför din städade dataset.\n", + "\n", + "5. **Dokumentera dina beslut**. Håll reda på vilka städningssteg du har tillämpat och varför, eftersom detta är viktigt för reproducerbarhet och transparens.\n", + "\n", + "> **Bästa praxis:** Behåll alltid en kopia av dina ursprungliga \"smutsiga\" data. Överskriv aldrig dina källdatafiler - skapa städade versioner med tydliga namnkonventioner som `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Ansvarsfriskrivning**: \nDetta dokument har översatts med hjälp av AI-översättningstjänsten [Co-op Translator](https://github.com/Azure/co-op-translator). Även om vi strävar efter noggrannhet, vänligen notera att automatiska översättningar kan innehålla fel eller felaktigheter. Det ursprungliga dokumentet på dess originalspråk bör betraktas som den auktoritativa källan. För kritisk information rekommenderas professionell mänsklig översättning. Vi ansvarar inte för eventuella missförstånd eller feltolkningar som uppstår vid användning av denna översättning.\n" + "\n---\n\n**Ansvarsfriskrivning**: \nDetta dokument har översatts med hjälp av AI-översättningstjänsten [Co-op Translator](https://github.com/Azure/co-op-translator). Även om vi strävar efter noggrannhet, bör det noteras att automatiserade översättningar kan innehålla fel eller felaktigheter. Det ursprungliga dokumentet på dess originalspråk bör betraktas som den auktoritativa källan. För kritisk information rekommenderas professionell mänsklig översättning. Vi ansvarar inte för eventuella missförstånd eller feltolkningar som uppstår vid användning av denna översättning.\n" ] } ], @@ -3704,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T07:59:16+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:16:44+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "sv" } diff --git a/translations/sw/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/sw/2-Working-With-Data/08-data-preparation/notebook.ipynb index 7224478e..75a71344 100644 --- a/translations/sw/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/sw/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# Maandalizi ya Data\n", "\n", - "[Chanzo cha Notebook asili kutoka *Data Science: Utangulizi wa Kujifunza Mashine kwa Data Science Python na Machine Learning Studio na Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Chanzo cha Notebook asili kutoka *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio na Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## Kuchunguza taarifa za `DataFrame`\n", "\n", - "> **Lengo la kujifunza:** Mwisho wa sehemu hii, unapaswa kuwa na uelewa wa jinsi ya kupata taarifa za jumla kuhusu data iliyohifadhiwa katika pandas DataFrames.\n", + "> **Lengo la kujifunza:** Mwisho wa sehemu hii ndogo, unapaswa kuwa na uelewa wa jinsi ya kupata taarifa za jumla kuhusu data iliyohifadhiwa kwenye pandas DataFrames.\n", "\n", - "Baada ya kupakia data yako kwenye pandas, kuna uwezekano mkubwa kuwa itakuwa katika `DataFrame`. Hata hivyo, ikiwa seti ya data katika `DataFrame` yako ina safu 60,000 na nguzo 400, utaanzaje kupata picha ya kile unachofanya kazi nacho? Kwa bahati nzuri, pandas inatoa zana rahisi za kuangalia haraka taarifa za jumla kuhusu `DataFrame` pamoja na safu chache za mwanzo na za mwisho.\n", + "Baada ya kupakia data yako kwenye pandas, kuna uwezekano mkubwa kuwa itakuwa katika `DataFrame`. Hata hivyo, ikiwa seti ya data katika `DataFrame` yako ina safu 60,000 na nguzo 400, utaanzaje kupata hisia ya unachofanya kazi nacho? Kwa bahati nzuri, pandas inatoa zana rahisi za kuangalia haraka taarifa za jumla kuhusu `DataFrame` pamoja na safu chache za mwanzo na za mwisho.\n", "\n", - "Ili kuchunguza utendaji huu, tutapakia maktaba ya Python scikit-learn na kutumia seti ya data maarufu ambayo kila mtaalamu wa data ameiona mara nyingi: seti ya data ya *Iris* ya mwanabiolojia wa Uingereza Ronald Fisher iliyotumika katika karatasi yake ya mwaka 1936 \"Matumizi ya vipimo vingi katika matatizo ya taxonomia\":\n" + "Ili kuchunguza utendaji huu, tutapakia maktaba ya Python scikit-learn na kutumia seti ya data maarufu ambayo kila mwanasayansi wa data ameiona mara nyingi: seti ya data ya *Iris* ya mwana-bailojia wa Uingereza Ronald Fisher iliyotumika katika karatasi yake ya mwaka 1936 \"Matumizi ya vipimo vingi katika matatizo ya taxonomia\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Tumeweka Dataset ya Iris kwenye kigezo `iris_df`. Kabla ya kuanza kuchambua data, itakuwa muhimu kujua idadi ya vipengele tulivyonavyo na ukubwa wa jumla wa dataset. Ni muhimu kuangalia kiasi cha data tunachoshughulikia.\n" + "Tumepakia Dataset ya Iris kwenye kigezo `iris_df`. Kabla ya kuanza kuchambua data, itakuwa muhimu kujua idadi ya vipengele tulivyo navyo na ukubwa wa jumla wa dataset. Ni muhimu kuangalia kiasi cha data tunachoshughulikia.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Kwa hivyo, tunashughulika na safu 150 na nguzo 4 za data. Kila safu inawakilisha nukta moja ya data na kila nguzo inawakilisha kipengele kimoja kinachohusiana na fremu ya data. Kwa msingi, kuna nukta 150 za data zenye vipengele 4 kila moja.\n", + "Kwa hivyo, tunashughulika na safu 150 na nguzo 4 za data. Kila safu inawakilisha kipengele kimoja cha data, na kila nguzo inawakilisha sifa moja inayohusiana na fremu ya data. Kwa hivyo kimsingi, kuna vipengele 150 vya data vyenye sifa 4 kila moja.\n", "\n", - "`shape` hapa ni sifa ya fremu ya data na si kazi, ndiyo sababu haimalizii na jozi ya mabano.\n" + "`shape` hapa ni sifa ya fremu ya data na si kazi, ndiyo sababu haimalizwi na jozi ya mabano.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Kama tunavyoona, kuna safu nne (4). Sifa ya `columns` inatuambia majina ya safu na kimsingi hakuna kingine. Sifa hii inakuwa muhimu tunapotaka kutambua vipengele ambavyo seti ya data inavyo.\n" + "Kama tunavyoona, kuna safu nne (4). Sifa ya `columns` inatuambia majina ya safu na kimsingi hakuna kingine. Sifa hii inakuwa muhimu tunapotaka kutambua vipengele ambavyo seti ya data ina.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Kiasi cha data (kinachotolewa na sifa ya `shape`) na majina ya vipengele au safu (vinavyotolewa na sifa ya `columns`) vinatupa taarifa fulani kuhusu seti ya data. Sasa, tungependa kuchunguza kwa undani zaidi seti ya data. Kazi ya `DataFrame.info()` ni muhimu sana kwa hili.\n" + "Kiasi cha data (kinachotolewa na sifa ya `shape`) na majina ya vipengele au safu (vinavyotolewa na sifa ya `columns`) vinatupa taarifa fulani kuhusu seti ya data. Sasa, tungependa kuchunguza zaidi seti ya data. Kazi ya `DataFrame.info()` ni muhimu sana kwa hili.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Kutoka hapa, tunaweza kufanya uchunguzi kadhaa: \n", - "1. Aina ya Data ya kila safu: Katika seti hii ya data, data yote imehifadhiwa kama nambari za desimali za biti 64. \n", - "2. Idadi ya Thamani Zisizo Null: Kushughulikia thamani za null ni hatua muhimu katika maandalizi ya data. Hili litatatuliwa baadaye kwenye daftari. \n" + "Kutoka hapa, tunaweza kufanya uchunguzi kadhaa:\n", + "1. Aina ya Data ya kila safu: Katika seti hii ya data, data yote imehifadhiwa kama nambari za desimali za 64-bit.\n", + "2. Idadi ya Thamani Zisizo Null: Kushughulikia thamani za null ni hatua muhimu katika maandalizi ya data. Hili litatatuliwa baadaye kwenye daftari.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Tuseme tuna data nyingi za namba kwenye seti yetu ya data. Mahesabu ya takwimu za upande mmoja kama vile wastani, mediani, robo n.k. yanaweza kufanywa kwenye kila safu moja moja. Kazi ya `DataFrame.describe()` inatupatia muhtasari wa takwimu za safu za namba kwenye seti ya data.\n" + "Tuseme tuna data nyingi za namba kwenye seti yetu ya data. Mahesabu ya takwimu za upande mmoja kama wastani, mediani, robo n.k. yanaweza kufanywa kwa kila safu moja moja. Kazi ya `DataFrame.describe()` inatupatia muhtasari wa takwimu za safu za namba kwenye seti ya data.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "Matokeo hapo juu yanaonyesha jumla ya idadi ya pointi za data, wastani, upotofu wa kawaida, thamani ya chini, robo ya chini (25%), mediani (50%), robo ya juu (75%) na thamani ya juu ya kila safu.\n" + "Matokeo hapo juu yanaonyesha jumla ya idadi ya alama za data, wastani, upotofu wa kawaida, kiwango cha chini, robo ya chini (25%), mediani (50%), robo ya juu (75%) na thamani ya juu ya kila safu.\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "Kwa kutumia kazi na sifa zote zilizotajwa hapo juu, tumepata muhtasari wa juu wa seti ya data. Tunajua ni alama ngapi za data zipo, ni sifa ngapi zipo, aina ya data ya kila sifa, na idadi ya thamani zisizo tupu kwa kila sifa.\n", + "Kwa kutumia kazi na sifa zote zilizotajwa hapo juu, tumepata muhtasari wa juu wa seti ya data. Tunajua idadi ya pointi za data zilizopo, idadi ya vipengele vilivyopo, aina ya data ya kila kipengele, na idadi ya thamani zisizo tupu kwa kila kipengele.\n", "\n", - "Sasa ni wakati wa kuangalia data yenyewe. Hebu tuone jinsi safu chache za mwanzo (alama chache za mwanzo za data) za `DataFrame` yetu zinavyoonekana:\n" + "Sasa ni wakati wa kuangalia data yenyewe. Hebu tuone jinsi safu chache za mwanzo (pointi chache za mwanzo za data) za `DataFrame` yetu zinavyoonekana:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Kama matokeo hapa, tunaweza kuona maingizo matano (5) ya seti ya data. Tukitazama faharasa upande wa kushoto, tunagundua kuwa hizi ni safu tano za kwanza.\n" + "Kama matokeo hapa, tunaweza kuona maingizo matano (5) ya seti ya data. Tukitazama kwenye faharasa upande wa kushoto, tunagundua kwamba hizi ni safu tano za kwanza.\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "Katika mazoezi, ni muhimu kuwa na uwezo wa kuchunguza kwa urahisi safu chache za mwanzo au safu chache za mwisho za `DataFrame`, hasa unapokuwa unatafuta thamani zisizo za kawaida katika seti za data zilizo na mpangilio.\n", + "Kwa vitendo, ni muhimu kuwa na uwezo wa kuchunguza kwa urahisi safu chache za mwanzo au safu chache za mwisho za `DataFrame`, hasa unapokuwa unatafuta thamani zisizo za kawaida katika seti za data zilizo na mpangilio.\n", "\n", - "Kazi zote na sifa zilizoonyeshwa hapo juu kwa msaada wa mifano ya msimbo, zinatusaidia kupata muonekano na hisia ya data.\n", + "Kazi zote na sifa zilizoonyeshwa hapo juu kwa msaada wa mifano ya msimbo, zinatusaidia kupata mwonekano na hisia ya data.\n", "\n", - "> **Mafunzo:** Hata kwa kuangalia tu metadata kuhusu taarifa katika `DataFrame` au thamani chache za mwanzo na mwisho ndani yake, unaweza kupata wazo la haraka kuhusu ukubwa, umbo, na maudhui ya data unayoshughulikia.\n" + "> **Mafunzo:** Hata kwa kuangalia tu metadata kuhusu taarifa ndani ya DataFrame au thamani chache za mwanzo na mwisho, unaweza kupata wazo la haraka kuhusu ukubwa, umbo, na maudhui ya data unayoshughulikia.\n" ] }, { @@ -596,17 +596,17 @@ }, "source": [ "### Data Inayokosekana\n", - "Hebu tujadili kuhusu data inayokosekana. Data inayokosekana hutokea pale ambapo hakuna thamani iliyohifadhiwa katika baadhi ya safu.\n", + "Hebu tuangalie data inayokosekana. Data inayokosekana hutokea pale ambapo hakuna thamani iliyohifadhiwa katika baadhi ya safu.\n", "\n", - "Hebu tuchukue mfano: tuseme mtu fulani anajali sana kuhusu uzito wake na hawezi kujaza sehemu ya uzito katika dodoso. Basi, thamani ya uzito kwa mtu huyo itakuwa haipo.\n", + "Hebu tuchukue mfano: tuseme mtu anajali sana kuhusu uzito wake na hatoi taarifa ya uzito wake kwenye dodoso. Basi, thamani ya uzito kwa mtu huyo itakosekana.\n", "\n", "Mara nyingi, katika seti za data za ulimwengu halisi, thamani zinazokosekana hutokea.\n", "\n", "**Jinsi Pandas Inavyoshughulikia Data Inayokosekana**\n", "\n", - "Pandas hushughulikia thamani zinazokosekana kwa njia mbili. Ya kwanza umeiona hapo awali katika sehemu zilizopita: `NaN`, au Not a Number. Hii ni thamani maalum ambayo ni sehemu ya vipimo vya IEEE vya namba za desimali na hutumika tu kuonyesha thamani za desimali zinazokosekana.\n", + "Pandas hushughulikia thamani zinazokosekana kwa njia mbili. Ya kwanza umeiona katika sehemu za awali: `NaN`, au Not a Number. Hii ni thamani maalum ambayo ni sehemu ya maelezo ya IEEE floating-point na hutumika tu kuonyesha thamani za nambari zinazokosekana.\n", "\n", - "Kwa thamani zinazokosekana ambazo si za desimali, pandas hutumia kitu cha Python `None`. Ingawa inaweza kuonekana kuchanganya kwamba utakutana na aina mbili tofauti za thamani zinazomaanisha kimsingi kitu kimoja, kuna sababu za kimipangilio za kubuni chaguo hili, na kwa vitendo, njia hii inaiwezesha pandas kutoa suluhisho bora kwa hali nyingi. Hata hivyo, `None` na `NaN` zote zina vizuizi ambavyo unapaswa kuwa makini navyo kuhusiana na jinsi zinavyoweza kutumika.\n" + "Kwa thamani zinazokosekana ambazo si za nambari za desimali, pandas hutumia kitu cha Python `None`. Ingawa inaweza kuonekana kuwa ni jambo linalochanganya kwamba utakutana na aina mbili tofauti za thamani zinazosema kimsingi jambo lile lile, kuna sababu za kimaandishi za programu kwa chaguo hili la muundo, na kwa vitendo, njia hii inaiwezesha pandas kutoa suluhisho bora kwa hali nyingi. Pamoja na hayo, `None` na `NaN` zote zina vizuizi ambavyo unapaswa kuzingatia kuhusu jinsi zinavyoweza kutumika.\n" ] }, { @@ -615,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: data isiyokuwepo isiyo ya aina ya float\n", - "Kwa sababu `None` inatoka kwenye Python, haiwezi kutumika katika arrays za NumPy na pandas ambazo si za aina ya data `'object'`. Kumbuka, arrays za NumPy (na miundo ya data katika pandas) zinaweza kuwa na aina moja tu ya data. Hii ndiyo inazipa nguvu kubwa kwa kazi za data na mahesabu makubwa, lakini pia inapunguza uwezo wao wa kubadilika. Arrays kama hizo lazima zibadilishwe hadi kwenye “kiwango cha chini cha kawaida,” yaani aina ya data ambayo itajumuisha kila kitu kilichopo kwenye array. Wakati `None` ipo kwenye array, inamaanisha unafanya kazi na vitu vya Python.\n", + "### `None`: data isiyokuwepo isiyo ya float\n", + "Kwa sababu `None` inatoka Python, haiwezi kutumika katika arrays za NumPy na pandas ambazo hazina aina ya data `'object'`. Kumbuka, arrays za NumPy (na miundo ya data katika pandas) zinaweza kuwa na aina moja tu ya data. Hii ndiyo inawapa nguvu kubwa kwa kazi za data na hesabu za kiwango kikubwa, lakini pia inapunguza uwezo wao wa kubadilika. Arrays kama hizi zinapaswa kubadilishwa hadi \"kiwango cha chini cha kawaida,\" aina ya data ambayo itajumuisha kila kitu kilichomo kwenye array. Wakati `None` ipo kwenye array, inamaanisha unafanya kazi na vitu vya Python.\n", "\n", - "Ili kuona hili likifanyika, zingatia mfano wa array ifuatayo (angalia `dtype` yake):\n" + "Ili kuona hili likifanya kazi, fikiria array ifuatayo (angalia `dtype` yake):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Uhalisia wa aina za data zilizopandishwa huleta athari mbili. Kwanza, operesheni zitafanyika katika kiwango cha msimbo wa Python unaotafsiriwa badala ya msimbo wa NumPy uliokusanywa. Kimsingi, hii inamaanisha kuwa operesheni yoyote inayohusisha `Series` au `DataFrames` zenye `None` ndani yake itakuwa polepole zaidi. Ingawa huenda usione athari hii ya utendaji, kwa seti kubwa za data inaweza kuwa tatizo.\n", + "Uhalisia wa aina za data zilizopandishwa daraja huleta athari mbili. Kwanza, operesheni zitafanyika katika kiwango cha msimbo wa Python unaotafsiriwa badala ya msimbo wa NumPy uliosimbwa. Kimsingi, hii inamaanisha kuwa operesheni yoyote inayohusisha `Series` au `DataFrames` zenye `None` ndani yake itakuwa polepole. Ingawa huenda usione athari hii ya utendaji, kwa seti kubwa za data inaweza kuwa tatizo.\n", "\n", - "Athari ya pili inatokana na ya kwanza. Kwa sababu `None` kimsingi inarudisha `Series` au `DataFrame`s katika ulimwengu wa Python ya kawaida, kutumia mkusanyiko wa NumPy/pandas kama `sum()` au `min()` kwenye safu ambazo zina thamani ya ``None`` kwa ujumla kutasababisha hitilafu:\n" + "Athari ya pili inatokana na ya kwanza. Kwa sababu `None` kimsingi huirudisha `Series` au `DataFrame` katika ulimwengu wa Python ya kawaida, kutumia hesabu za NumPy/pandas kama `sum()` au `min()` kwenye arrays zenye thamani ya ``None`` kwa kawaida kutasababisha kosa:\n" ] }, { @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**Mambo ya msingi**: Kuongeza (na operesheni nyingine) kati ya nambari nzima na thamani za `None` haina maana, jambo ambalo linaweza kupunguza kile unachoweza kufanya na seti za data zinazozijumuisha.\n" + ] }, { "cell_type": "markdown", @@ -705,9 +707,9 @@ "id": "pWvVHvETgRr9" }, "source": [ - "### `NaN`: thamani za float zinazokosekana\n", + "### `NaN`: thamani za float zilizokosekana\n", "\n", - "Tofauti na `None`, NumPy (na kwa hivyo pandas) inasaidia `NaN` kwa ajili ya operesheni zake za haraka, za vekta, na ufuncs. Habari mbaya ni kwamba hesabu yoyote inayofanywa kwenye `NaN` daima husababisha `NaN`. Kwa mfano:\n" + "Tofauti na `None`, NumPy (na hivyo pia pandas) inasaidia `NaN` kwa ajili ya operesheni zake za haraka, za vektori, na ufuncs. Habari mbaya ni kwamba hesabu yoyote inayofanywa kwenye `NaN` daima hutoa `NaN`. Kwa mfano:\n" ] }, { @@ -770,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Habari njema: mkusanyiko unaoendeshwa kwenye safu zenye `NaN` ndani yake hauleti makosa. Habari mbaya: matokeo si ya manufaa kwa usawa:\n" + "Habari njema: mkusanyiko unaoendeshwa kwenye safu zenye `NaN` ndani yake hauleti makosa. Habari mbaya: matokeo si ya msaada kwa kiwango sawa:\n" ] }, { @@ -806,7 +808,9 @@ "metadata": { "id": "nhlnNJT7gRr_" }, - "source": [] + "source": [ + "### Mazoezi:\n" + ] }, { "cell_type": "code", @@ -826,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "Kumbuka: `NaN` ni kwa ajili ya thamani za nambari za desimali zinazokosekana tu; hakuna sawa na `NaN` kwa nambari kamili, maandishi, au Boolean.\n" + ] }, { "cell_type": "markdown", @@ -834,9 +840,9 @@ "id": "kj6EKdsAgRsA" }, "source": [ - "### `NaN` na `None`: thamani tupu katika pandas\n", + "### `NaN` na `None`: Thamani za sifuri katika pandas\n", "\n", - "Ingawa `NaN` na `None` zinaweza kuonyesha tabia tofauti kidogo, pandas imeundwa kushughulikia zote mbili kwa njia inayofanana. Ili kuelewa tunachomaanisha, fikiria `Series` ya nambari kamili:\n" + "Ingawa `NaN` na `None` zinaweza kuonyesha tabia tofauti kidogo, pandas imeundwa kushughulikia zote kwa njia inayofanana. Ili kuelewa tunachomaanisha, fikiria `Series` ya nambari za mzima:\n" ] }, { @@ -875,7 +881,9 @@ "metadata": { "id": "WklCzqb8gRsB" }, - "source": [] + "source": [ + "### Mazoezi:\n" + ] }, { "cell_type": "code", @@ -898,12 +906,12 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Katika mchakato wa kubadilisha aina za data ili kuanzisha usawa wa data katika `Series` na `DataFrame`s, pandas itabadilisha kwa hiari thamani zilizokosekana kati ya `None` na `NaN`. Kwa sababu ya kipengele hiki cha muundo, inaweza kuwa muhimu kufikiria `None` na `NaN` kama ladha mbili tofauti za \"null\" katika pandas. Kwa kweli, baadhi ya mbinu za msingi utakazotumia kushughulikia thamani zilizokosekana katika pandas zinaakisi wazo hili katika majina yao:\n", + "Katika mchakato wa kubadilisha aina za data ili kuanzisha usawa wa data katika `Series` na `DataFrame`s, pandas itabadilisha kwa hiari thamani zilizokosekana kati ya `None` na `NaN`. Kwa sababu ya kipengele hiki cha muundo, inaweza kuwa muhimu kufikiria `None` na `NaN` kama ladha mbili tofauti za \"null\" katika pandas. Kwa kweli, baadhi ya mbinu za msingi ambazo utatumia kushughulikia thamani zilizokosekana katika pandas zinaakisi wazo hili katika majina yao:\n", "\n", - "- `isnull()`: Hutengeneza mask ya Boolean inayoonyesha thamani zilizokosekana\n", + "- `isnull()`: Hutengeneza maski ya Boolean inayoonyesha thamani zilizokosekana\n", "- `notnull()`: Kinyume cha `isnull()`\n", "- `dropna()`: Hurejesha toleo lililochujwa la data\n", - "- `fillna()`: Hurejesha nakala ya data na thamani zilizokosekana zikiwa zimejazwa au kuwekewa makadirio\n", + "- `fillna()`: Hurejesha nakala ya data yenye thamani zilizokosekana kujazwa au kuhesabiwa\n", "\n", "Hizi ni mbinu muhimu za kuzifahamu na kuzoea, kwa hivyo hebu tuzipitie kila moja kwa undani zaidi.\n" ] @@ -916,7 +924,7 @@ "source": [ "### Kugundua thamani za null\n", "\n", - "Sasa kwa kuwa tumeelewa umuhimu wa thamani zinazokosekana, tunahitaji kuzitambua kwenye seti yetu ya data kabla ya kushughulika nazo. \n", + "Sasa kwa kuwa tumeelewa umuhimu wa thamani zinazokosekana, tunahitaji kuzitambua kwenye seti yetu ya data kabla ya kuzishughulikia. \n", "Zote `isnull()` na `notnull()` ni mbinu zako za msingi za kugundua data ya null. Zote zinarudisha maski za Boolean juu ya data yako.\n" ] }, @@ -970,9 +978,9 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Angalia kwa makini matokeo. Je, kuna lolote linalokushangaza? Ingawa `0` ni null ya hesabu, bado ni nambari kamili nzuri na pandas inaitendea hivyo. `''` ni kidogo zaidi ya hila. Ingawa tulitumia katika Sehemu ya 1 kuwakilisha thamani ya mnyororo tupu, bado ni kitu cha mnyororo na si uwakilishi wa null kulingana na pandas.\n", + "Angalia kwa makini matokeo. Je, kuna chochote kinachokushangaza? Ingawa `0` ni null ya hesabu, bado ni nambari kamili nzuri na pandas inaitendea hivyo. `''` ni kidogo zaidi ya hila. Ingawa tulitumia katika Sehemu ya 1 kuwakilisha thamani ya mnyororo tupu, bado ni kitu cha mnyororo na si uwakilishi wa null kulingana na pandas.\n", "\n", - "Sasa, hebu tugeuze hili na tutumie mbinu hizi kwa namna ambayo utazitumia kwa vitendo. Unaweza kutumia vinyago vya Boolean moja kwa moja kama ``Series`` au ``DataFrame`` index, ambayo inaweza kuwa muhimu unapojaribu kufanya kazi na thamani zilizokosekana (au zilizopo) pekee.\n", + "Sasa, hebu tugeuze hili na tutumie mbinu hizi kwa namna ambayo ni karibu na jinsi utakavyotumia kwa vitendo. Unaweza kutumia vinyago vya Boolean moja kwa moja kama ``Series`` au ``DataFrame`` index, ambayo inaweza kuwa muhimu unapojaribu kufanya kazi na thamani zilizokosekana (au zilizopo) pekee.\n", "\n", "Ikiwa tunataka jumla ya idadi ya thamani zilizokosekana, tunaweza kufanya jumla juu ya kinyago kinachozalishwa na mbinu ya `isnull()`.\n" ] @@ -1008,7 +1016,9 @@ "metadata": { "id": "PlBqEo3mgRsC" }, - "source": [] + "source": [ + "### Mazoezi:\n" + ] }, { "cell_type": "code", @@ -1030,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Mambo ya msingi**: Mbinu za `isnull()` na `notnull()` hutoa matokeo yanayofanana unapotumia katika DataFrames: zinaonyesha matokeo na faharasa ya matokeo hayo, ambayo yatakusaidia sana unaposhughulika na data yako.\n" + "**Ujumbe muhimu**: Njia zote za `isnull()` na `notnull()` hutoa matokeo yanayofanana unapotumia katika DataFrames: zinaonyesha matokeo na faharasa ya matokeo hayo, ambayo yatakusaidia sana unaposhughulika na data yako.\n" ] }, { @@ -1039,18 +1049,18 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### Kushughulikia data iliyokosekana\n", + "### Kushughulikia Data Inayokosekana\n", "\n", - "> **Lengo la kujifunza:** Kufikia mwisho wa sehemu hii ndogo, unapaswa kujua jinsi na wakati wa kubadilisha au kuondoa thamani za null kutoka kwa DataFrames.\n", + "> **Lengo la kujifunza:** Mwisho wa sehemu hii ndogo, unapaswa kujua jinsi na wakati wa kubadilisha au kuondoa thamani za null kutoka kwa DataFrames.\n", "\n", - "Mifano ya Kujifunza Mashine haziwezi kushughulikia data iliyokosekana zenyewe. Kwa hivyo, kabla ya kupitisha data kwenye mfano, tunahitaji kushughulikia thamani hizi zilizokosekana.\n", + "Mifano ya Kujifunza Mashine haiwezi kushughulikia data inayokosekana yenyewe. Kwa hivyo, kabla ya kupitisha data kwenye mfano, tunahitaji kushughulikia thamani hizi zinazokosekana.\n", "\n", - "Jinsi data iliyokosekana inavyoshughulikiwa huleta maamuzi yenye athari ndogo, inaweza kuathiri uchambuzi wako wa mwisho na matokeo halisi ya ulimwengu.\n", + "Jinsi data inayokosekana inavyoshughulikiwa huleta maamuzi yenye athari ndogo, inaweza kuathiri uchambuzi wako wa mwisho na matokeo halisi ya ulimwengu.\n", "\n", - "Kuna njia mbili kuu za kushughulikia data iliyokosekana:\n", + "Kuna njia mbili kuu za kushughulikia data inayokosekana:\n", "\n", - "1. Kuondoa safu inayojumuisha thamani iliyokosekana\n", - "2. Kubadilisha thamani iliyokosekana na thamani nyingine\n", + "1. Kuondoa safu inayojumuisha thamani inayokosekana\n", + "2. Kubadilisha thamani inayokosekana na thamani nyingine\n", "\n", "Tutajadili njia hizi zote mbili na faida na hasara zake kwa undani.\n" ] @@ -1061,13 +1071,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### Kuondoa Thamani Zisizo na Maana (Null Values)\n", + "### Kuondoa Thamani Zisizo na Maana\n", "\n", - "Kiasi cha data tunachopitisha kwenye modeli yetu kina athari ya moja kwa moja kwenye utendaji wake. Kuondoa thamani zisizo na maana kunamaanisha tunapunguza idadi ya vipengele vya data, na hivyo kupunguza ukubwa wa seti ya data. Kwa hivyo, inashauriwa kuondoa safu zilizo na thamani zisizo na maana wakati seti ya data ni kubwa sana.\n", + "Kiasi cha data tunachopitisha kwa modeli yetu kina athari ya moja kwa moja kwenye utendaji wake. Kuondoa thamani zisizo na maana (null values) kunamaanisha tunapunguza idadi ya vipengele vya data, na hivyo kupunguza ukubwa wa seti ya data. Kwa hivyo, inashauriwa kuondoa safu zenye thamani zisizo na maana pale ambapo seti ya data ni kubwa sana.\n", "\n", - "Mfano mwingine unaweza kuwa kwamba safu fulani au safu wima ina idadi kubwa ya thamani zinazokosekana. Katika hali hiyo, zinaweza kuondolewa kwa sababu hazitachangia sana kwenye uchambuzi wetu kwani data nyingi inakosekana kwa safu/safu wima hiyo.\n", + "Mfano mwingine unaweza kuwa kwamba safu fulani au safu wima ina idadi kubwa ya thamani zisizo na maana. Katika hali hiyo, zinaweza kuondolewa kwa sababu hazitachangia sana kwenye uchambuzi wetu kwani data nyingi zinakosekana kwa safu/safu wima hiyo.\n", "\n", - "Zaidi ya kutambua thamani zinazokosekana, pandas inatoa njia rahisi ya kuondoa thamani zisizo na maana kutoka kwa `Series` na `DataFrame`s. Ili kuona hili likifanyika, hebu turudi kwenye `example3`. Kazi ya `DataFrame.dropna()` husaidia kuondoa safu zilizo na thamani zisizo na maana.\n" + "Zaidi ya kutambua thamani zisizo na maana, pandas inatoa njia rahisi ya kuondoa thamani zisizo na maana kutoka kwa `Series` na `DataFrame`s. Ili kuona hili likifanya kazi, hebu turudi kwenye `example3`. Kazi ya `DataFrame.dropna()` husaidia kuondoa safu zenye thamani zisizo na maana.\n" ] }, { @@ -1106,7 +1116,7 @@ "id": "hil2cr64gRsD" }, "source": [ - "Kumbuka kwamba hii inapaswa kuonekana kama matokeo yako kutoka `example3[example3.notnull()]`. Tofauti hapa ni kwamba, badala ya kuorodhesha tu kwenye thamani zilizofichwa, `dropna` imeondoa zile thamani zilizokosekana kutoka kwa `Series` `example3`.\n", + "Kumbuka kwamba hii inapaswa kuonekana kama matokeo yako kutoka `example3[example3.notnull()]`. Tofauti hapa ni kwamba, badala ya kuorodhesha tu thamani zilizofichwa, `dropna` imeondoa zile thamani zilizokosekana kutoka kwa `Series` `example3`.\n", "\n", "Kwa sababu DataFrames zina vipimo viwili, zinatoa chaguo zaidi za kuondoa data.\n" ] @@ -1198,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(Je, uliona kwamba pandas ilibadilisha safu mbili kuwa nambari za desimali ili kushughulikia `NaN`?)\n", + "(Je, uliona kwamba pandas ilibadilisha aina ya safu mbili kuwa nambari za desimali ili kuzingatia `NaN`?)\n", "\n", - "Huwezi kuondoa thamani moja pekee kutoka kwa `DataFrame`, kwa hivyo unapaswa kuondoa safu nzima au safu wima. Kulingana na unachofanya, unaweza kutaka kufanya moja au nyingine, na hivyo pandas inakupa chaguo kwa zote mbili. Kwa sababu katika sayansi ya data, safu wima kwa kawaida huwakilisha vigezo na safu huwakilisha uchunguzi, kuna uwezekano mkubwa wa kuondoa safu za data; mpangilio wa chaguo-msingi wa `dropna()` ni kuondoa safu zote ambazo zina thamani yoyote isiyo na maana:\n" + "Huwezi kuondoa thamani moja kutoka kwa `DataFrame`, kwa hivyo lazima uondoe safu nzima au safu wima. Kulingana na unachofanya, unaweza kutaka kufanya moja au nyingine, na hivyo pandas inakupa chaguo kwa zote mbili. Kwa sababu katika sayansi ya data, safu wima kwa kawaida huwakilisha vigezo na safu huwakilisha uchunguzi, kuna uwezekano mkubwa wa kuondoa safu za data; mpangilio wa chaguo-msingi wa `dropna()` ni kuondoa safu zote zinazojumuisha thamani zozote tupu:\n" ] }, { @@ -1273,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "Ikiwa ni lazima, unaweza kuondoa thamani za NA kutoka kwenye safu. Tumia `axis=1` kufanya hivyo:\n" + "Ikiwa ni lazima, unaweza kuondoa thamani za NA kutoka kwa safu. Tumia `axis=1` kufanya hivyo:\n" ] }, { @@ -1352,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Kumbuka kwamba hii inaweza kuondoa data nyingi ambayo unaweza kutaka kuhifadhi, hasa katika seti ndogo za data. Je, unafanyaje ikiwa unataka tu kuondoa safu au nguzo ambazo zina thamani kadhaa au hata zote zikiwa tupu? Unaweza kubainisha mipangilio hiyo katika `dropna` kwa kutumia vigezo vya `how` na `thresh`.\n", + "Kumbuka kwamba hii inaweza kuondoa data nyingi ambayo unaweza kutaka kuhifadhi, hasa katika seti ndogo za data. Je, itakuwaje ikiwa unataka tu kuondoa safu au nguzo ambazo zina thamani kadhaa au hata zote zikiwa tupu? Unaweza kubainisha mipangilio hiyo katika `dropna` kwa kutumia vigezo vya `how` na `thresh`.\n", "\n", - "Kwa chaguo-msingi, `how='any'` (ikiwa ungependa kuthibitisha mwenyewe au kuona vigezo vingine ambavyo njia hii inayo, endesha `example4.dropna?` katika seli ya msimbo). Vinginevyo, unaweza kubainisha `how='all'` ili kuondoa tu safu au nguzo ambazo zina thamani zote tupu. Hebu tuongeze mfano wetu wa `DataFrame` ili kuona hili likifanyika katika zoezi lijalo.\n" + "Kwa chaguo-msingi, `how='any'` (ikiwa ungependa kuangalia mwenyewe au kuona vigezo vingine ambavyo njia hii ina, endesha `example4.dropna?` katika seli ya msimbo). Vinginevyo, unaweza kubainisha `how='all'` ili kuondoa tu safu au nguzo ambazo zina thamani zote zikiwa tupu. Hebu tuongeze mfano wetu wa `DataFrame` ili kuona hili likifanya kazi katika zoezi lijalo.\n" ] }, { @@ -1446,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> Mambo ya Muhimu: \n", + "> Mambo muhimu ya kuzingatia: \n", "1. Kuondoa thamani za null ni wazo zuri tu ikiwa seti ya data ni kubwa vya kutosha. \n", - "2. Safu nzima au nguzo zinaweza kuondolewa ikiwa zina data nyingi zilizokosekana. \n", - "3. Njia ya `DataFrame.dropna(axis=)` husaidia kuondoa thamani za null. Hoja ya `axis` inaonyesha kama safu (rows) zinapaswa kuondolewa au nguzo (columns). \n", - "4. Hoja ya `how` pia inaweza kutumika. Kwa chaguo-msingi imewekwa kuwa `any`. Hivyo, inaondoa tu safu/nguzo ambazo zina thamani yoyote ya null. Inaweza kuwekwa kuwa `all` ili kubainisha kwamba tutaondoa tu safu/nguzo ambazo thamani zote ni null. \n" + "2. Safu nzima au nguzo zinaweza kuondolewa ikiwa zina data nyingi iliyokosekana. \n", + "3. Njia ya `DataFrame.dropna(axis=)` husaidia kuondoa thamani za null. Kipengele cha `axis` kinaonyesha ikiwa safu zinapaswa kuondolewa au nguzo. \n", + "4. Kipengele cha `how` pia kinaweza kutumika. Kwa chaguo-msingi kimewekwa kuwa `any`. Kwa hivyo, kinaondoa tu safu/nguzo ambazo zina thamani yoyote ya null. Kinaweza kuwekwa kuwa `all` ili kubainisha kwamba tutaondoa tu safu/nguzo ambapo thamani zote ni null. \n" ] }, { @@ -1458,7 +1468,9 @@ "metadata": { "id": "oXXSfQFHgRsF" }, - "source": [] + "source": [ + "### Mazoezi:\n" + ] }, { "cell_type": "code", @@ -1480,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "Kigezo cha `thresh` kinakupa udhibiti wa kina zaidi: unaweka idadi ya thamani *zisizo tupu* ambazo safu au safu wima inahitaji kuwa nazo ili kuhifadhiwa:\n" + "Kigezo cha `thresh` kinakupa udhibiti wa kina zaidi: unaweka idadi ya thamani *zisizo-null* ambazo safu au safu wima inahitaji kuwa nazo ili kuhifadhiwa:\n" ] }, { @@ -1554,7 +1566,9 @@ "metadata": { "id": "fmSFnzZegRsG" }, - "source": [] + "source": [ + "Hapa, safu ya kwanza na ya mwisho zimeondolewa, kwa sababu zina maadili mawili tu yasiyo tupu.\n" + ] }, { "cell_type": "markdown", @@ -1564,9 +1578,9 @@ "source": [ "### Kujaza Thamani Zilizokosekana\n", "\n", - "Wakati mwingine inafaa kujaza thamani zilizokosekana na zile ambazo zinaweza kuwa halali. Kuna mbinu kadhaa za kujaza thamani tupu. Ya kwanza ni kutumia Maarifa ya Eneo (maarifa ya mada ambayo dataset inahusu) ili kwa namna fulani kukadiria thamani zilizokosekana.\n", + "Wakati mwingine ina mantiki kujaza thamani zilizokosekana na zile ambazo zinaweza kuwa sahihi. Kuna mbinu kadhaa za kujaza thamani za null. Ya kwanza ni kutumia Ujuzi wa Eneo (maarifa ya somo ambalo dataset inahusu) ili kukadiria kwa namna fulani thamani zilizokosekana.\n", "\n", - "Unaweza kutumia `isnull` kufanya hili moja kwa moja, lakini hilo linaweza kuwa kazi ngumu, hasa ikiwa una thamani nyingi za kujaza. Kwa sababu hii ni kazi ya kawaida sana katika sayansi ya data, pandas inatoa `fillna`, ambayo inarudisha nakala ya `Series` au `DataFrame` na thamani zilizokosekana kubadilishwa na zile unazochagua. Hebu tuunde mfano mwingine wa `Series` ili kuona jinsi hii inavyofanya kazi kwa vitendo.\n" + "Unaweza kutumia `isnull` kufanya hili moja kwa moja, lakini hilo linaweza kuwa kazi ngumu, hasa ikiwa una thamani nyingi za kujaza. Kwa sababu hili ni jukumu la kawaida katika sayansi ya data, pandas inatoa `fillna`, ambayo inarudisha nakala ya `Series` au `DataFrame` na thamani zilizokosekana kubadilishwa na moja unayochagua. Hebu tuunde mfano mwingine wa `Series` ili kuona jinsi hii inavyofanya kazi kwa vitendo.\n" ] }, { @@ -1576,11 +1590,11 @@ }, "source": [ "### Data ya Kategoria (Isiyo ya Nambari)\n", - "Kwanza, tuzingatie data isiyo ya nambari. Katika seti za data, tuna safu zenye data ya kategoria. Mfano: Jinsia, Kweli au Siyo Kweli, n.k.\n", + "Kwanza, tuzingatie data isiyo ya nambari. Katika seti za data, tunayo safu zenye data ya kategoria. Mfano: Jinsia, Kweli au Siyo Kweli, n.k.\n", "\n", - "Katika hali nyingi, tunabadilisha thamani zilizokosekana kwa kutumia `mode` ya safu husika. Kwa mfano, tuna alama 100 za data ambapo 90 zimesema Kweli, 8 zimesema Siyo Kweli, na 2 hazijajazwa. Basi, tunaweza kujaza zile 2 kwa Kweli, tukizingatia safu nzima.\n", + "Katika hali nyingi, tunabadilisha thamani zilizokosekana kwa kutumia `mode` ya safu husika. Kwa mfano, tuseme tuna alama 100 za data ambapo 90 zimesema Kweli, 8 zimesema Siyo Kweli, na 2 hazijajazwa. Basi, tunaweza kujaza zile 2 kwa Kweli, tukizingatia safu nzima.\n", "\n", - "Tena, hapa tunaweza kutumia maarifa ya uwanja. Hebu tuzingatie mfano wa kujaza kwa kutumia mode.\n" + "Tena, hapa tunaweza kutumia maarifa ya uwanja husika. Hebu tuchukue mfano wa kujaza kwa kutumia mode.\n" ] }, { @@ -1685,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Sasa, hebu kwanza tupate modi kabla ya kujaza thamani ya `None` na modi.\n" + ] }, { "cell_type": "code", @@ -1720,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Kwa hivyo, tutabadilisha None na True\n" + ] }, { "cell_type": "code", @@ -1830,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Kama tunavyoona, thamani ya null imebadilishwa. Bila shaka, tungeweza kuandika chochote badala ya `'True'` na kingechukua nafasi hiyo.\n" + "Kama tunavyoweza kuona, thamani ya null imebadilishwa. Bila shaka, tungeweza kuandika chochote badala ya `'True'` na kingesubstituliwa.\n" ] }, { @@ -1839,17 +1857,17 @@ "id": "heYe1I0dOmQ_" }, "source": [ - "### Takwimu za Kihesabu\n", - "Sasa, tukija kwenye takwimu za kihesabu. Hapa, tuna njia mbili za kawaida za kujaza thamani zilizokosekana:\n", + "### Data ya Nambari\n", + "Sasa, tukija kwenye data ya nambari. Hapa, tuna njia mbili za kawaida za kubadilisha thamani zilizopotea:\n", "\n", - "1. Kujaza kwa Median ya safu\n", - "2. Kujaza kwa Mean ya safu\n", + "1. Badilisha na Median ya safu\n", + "2. Badilisha na Mean ya safu\n", "\n", - "Tunatumia Median pale ambapo data ina mwelekeo na ina outliers. Hii ni kwa sababu median haiguswi sana na outliers.\n", + "Tunabadilisha na Median, endapo data ina mwelekeo na ina outliers. Hii ni kwa sababu median haiguswi sana na outliers.\n", "\n", - "Wakati data imesawazishwa, tunaweza kutumia mean, kwa kuwa katika hali hiyo, mean na median zitakuwa karibu sana.\n", + "Wakati data imesawazishwa, tunaweza kutumia mean, kwani katika hali hiyo, mean na median zitakuwa karibu sana.\n", "\n", - "Kwanza, hebu tuchukue safu ambayo imegawanyika kawaida na tujaze thamani iliyokosekana kwa kutumia mean ya safu hiyo.\n" + "Kwanza, hebu tuchukue safu ambayo imegawanyika kawaida na tujaze thamani iliyopotea kwa mean ya safu.\n" ] }, { @@ -1989,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Kujaza kwa wastani\n" + ] }, { "cell_type": "code", @@ -2098,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Sasa hebu tujaribu fremu nyingine ya data, na wakati huu tutabadilisha thamani za None na wastani wa safu.\n" + "Sasa hebu tujaribu dataframe nyingine, na wakati huu tutabadilisha thamani za None na wastani wa safu.\n" ] }, { @@ -2204,7 +2224,7 @@ "id": "mM1GpXYmjHnc" }, "source": [ - "Median ya safu ya pili ni\n" + "Kati ya safu ya pili ni\n" ] }, { @@ -2238,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Kujaza kwa mediani\n" + ] }, { "cell_type": "code", @@ -2338,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Kama tunavyoona, thamani ya NaN imebadilishwa na wastani wa safu hiyo\n" + "Kama tunavyoona, thamani ya NaN imebadilishwa na wastani wa safu.\n" ] }, { @@ -2421,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Mambo ya Muhimu:\n", - "1. Kujaza thamani zilizokosekana kunapaswa kufanywa pale ambapo kuna data kidogo au kuna mkakati wa kujaza data iliyokosekana.\n", + "> Mambo muhimu ya kuzingatia:\n", + "1. Kujaza thamani zilizokosekana kunapaswa kufanyika pale ambapo kuna data kidogo au kuna mkakati wa kujaza data iliyokosekana.\n", "2. Maarifa ya uwanja yanaweza kutumika kujaza thamani zilizokosekana kwa kuzikadiria.\n", "3. Kwa data ya Kategoria, mara nyingi, thamani zilizokosekana hubadilishwa na hali ya kawaida ya safu husika.\n", - "4. Kwa data ya namba, thamani zilizokosekana kwa kawaida hujazwa na wastani (kwa seti za data zilizonormalishwa) au median ya safu husika.\n" + "4. Kwa data ya nambari, thamani zilizokosekana kwa kawaida hujazwa kwa wastani (kwa seti za data zilizonormalishwa) au kwa median ya safu.\n" ] }, { @@ -2433,7 +2455,9 @@ "metadata": { "id": "FI9MmqFJgRsH" }, - "source": [] + "source": [ + "### Mazoezi:\n" + ] }, { "cell_type": "code", @@ -2453,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "Unaweza **kujaza mbele** thamani za null, ambayo ni kutumia thamani halali ya mwisho kujaza null:\n" + ] }, { "cell_type": "code", @@ -2493,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Unaweza pia **kujaza nyuma** ili kusambaza thamani halali inayofuata nyuma kujaza tupu:\n" + "Unaweza pia **kujaza nyuma** ili kusambaza thamani halali inayofuata kurudi nyuma kujaza null:\n" ] }, { @@ -2535,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "Kama unavyoweza kudhani, hii inafanya kazi vivyo hivyo na DataFrames, lakini pia unaweza kubainisha `axis` ambayo utaijaza thamani za null:\n" + "Kama unavyoweza kudhani, hii inafanya kazi vivyo hivyo na DataFrames, lakini pia unaweza kubainisha `axis` ambayo itajazwa thamani za null:\n" ] }, { @@ -2707,14 +2733,18 @@ "metadata": { "id": "ZeMc-I1EgRsI" }, - "source": [] + "source": [ + "Kumbuka kwamba wakati thamani ya awali haipatikani kwa kujaza mbele, thamani ya null inabaki.\n" + ] }, { "cell_type": "markdown", "metadata": { "id": "eeAoOU0RgRsJ" }, - "source": [] + "source": [ + "### Mazoezi:\n" + ] }, { "cell_type": "code", @@ -2828,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Kumbuka kwamba safu ya 3 bado haina thamani: mwelekeo wa chaguo-msingi ni kujaza thamani kwa mpangilio wa safu.\n", + "Kumbuka kwamba safu ya 3 bado haina thamani: mwelekeo wa chaguo-msingi ni kujaza thamani kwa kila mstari.\n", "\n", - "> **Mafunzo Muhimu:** Kuna njia nyingi za kushughulikia thamani zinazokosekana katika seti zako za data. Mkakati maalum unaotumia (kuondoa, kubadilisha, au hata jinsi unavyobadilisha) unapaswa kuamuliwa na maelezo ya data hiyo. Utapata uelewa bora wa jinsi ya kushughulikia thamani zinazokosekana kadri unavyoshughulikia na kuingiliana na seti za data.\n" + "> **Mafunzo:** Kuna njia nyingi za kushughulikia thamani zinazokosekana katika seti zako za data. Mkakati maalum unaotumia (kuondoa, kubadilisha, au hata jinsi unavyobadilisha) unapaswa kuamuliwa na maelezo ya data hiyo. Utapata uelewa bora wa jinsi ya kushughulikia thamani zinazokosekana kadri unavyoshughulikia na kuingiliana na seti za data.\n" ] }, { @@ -2841,9 +2871,9 @@ "source": [ "### Usimbaji wa Data ya Kategoria\n", "\n", - "Miundo ya kujifunza kwa mashine hushughulikia tu nambari na aina yoyote ya data ya nambari. Haiwezi kutofautisha kati ya Ndiyo na Hapana, lakini inaweza kutofautisha kati ya 0 na 1. Kwa hivyo, baada ya kujaza thamani zilizokosekana, tunahitaji kusimba data ya kategoria kwa aina fulani ya nambari ili modeli iweze kuelewa.\n", + "Mifano ya kujifunza kwa mashine hushughulikia tu namba na aina yoyote ya data ya namba. Haiwezi kutofautisha kati ya Ndiyo na Hapana, lakini inaweza kutofautisha kati ya 0 na 1. Kwa hivyo, baada ya kujaza thamani zilizokosekana, tunahitaji kusimba data ya kategoria kwa namna ya namba ili mfano uweze kuelewa.\n", "\n", - "Usimbaji unaweza kufanywa kwa njia mbili. Tutazijadili baadaye.\n" + "Usimbaji unaweza kufanywa kwa njia mbili. Tutazijadili hapa chini.\n" ] }, { @@ -2852,9 +2882,9 @@ "id": "uDq9SxB7mu5i" }, "source": [ - "**KODIFIKESHENI YA LEBELE** \n", + "**KODI YA LEBO**\n", "\n", - "Kodifikesheni ya lebele ni mchakato wa kubadilisha kila kategoria kuwa namba. Kwa mfano, tuseme tuna seti ya data ya abiria wa ndege na kuna safu inayojumuisha daraja lao miongoni mwa haya ['daraja la biashara', 'daraja la uchumi', 'daraja la kwanza']. Ikiwa kodifikesheni ya lebele itafanyika hapa, itabadilishwa kuwa [0,1,2]. Hebu tuone mfano kupitia msimbo. Kwa kuwa tutajifunza `scikit-learn` katika daftari zijazo, hatutaitumia hapa.\n" + "Kodi ya lebo ni mchakato wa kubadilisha kila kategoria kuwa namba. Kwa mfano, tuseme tuna seti ya data ya abiria wa ndege na kuna safu inayojumuisha daraja lao miongoni mwa haya ['daraja la biashara', 'daraja la uchumi', 'daraja la kwanza']. Ikiwa kodi ya lebo itafanywa kwenye hii, itabadilishwa kuwa [0,1,2]. Hebu tuone mfano kupitia msimbo. Kwa kuwa tutakuwa tunajifunza `scikit-learn` katika daftari zijazo, hatutaitumia hapa.\n" ] }, { @@ -2962,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Ili kufanya usimbaji wa lebo kwenye safu ya kwanza, tunapaswa kwanza kuelezea ramani kutoka kwa kila darasa hadi nambari, kabla ya kubadilisha\n" + "Ili kufanya usimbaji wa lebo kwenye safu ya kwanza, tunapaswa kwanza kuelezea ramani kutoka kila darasa hadi nambari, kabla ya kubadilisha.\n" ] }, { @@ -3064,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Kama tunavyoona, matokeo yanalingana na tulivyotarajia. Kwa hivyo, ni lini tunatumia label encoding? Label encoding hutumika katika hali moja au zote zifuatazo: \n", - "1. Wakati idadi ya kategoria ni kubwa \n", - "2. Wakati kategoria ziko katika mpangilio. \n" + "Kama tunavyoona, matokeo yanalingana na tulivyotarajia yatokee. Kwa hivyo, tunatumia label encoding lini? Label encoding hutumika katika mojawapo au zote za hali zifuatazo:\n", + "1. Wakati idadi ya makundi ni kubwa\n", + "2. Wakati makundi yako katika mpangilio.\n" ] }, { @@ -3075,11 +3105,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**UJUMUISHAJI WA ONE HOT**\n", + "**ONE HOT ENCODING**\n", "\n", - "Aina nyingine ya ujumishaji ni Ujumishaji wa One Hot. Katika aina hii ya ujumishaji, kila kategoria ya safu huongezwa kama safu tofauti, na kila kipengele cha data hupata 0 au 1 kulingana na kama kina kategoria hiyo au la. Kwa hivyo, ikiwa kuna kategoria n tofauti, safu n zitaongezwa kwenye dataframe.\n", + "Aina nyingine ya usimbaji ni One Hot Encoding. Katika aina hii ya usimbaji, kila kategoria ya safu huongezwa kama safu tofauti, na kila data itapewa 0 au 1 kulingana na kama inajumuisha kategoria hiyo. Kwa hivyo, ikiwa kuna kategoria n tofauti, safu n zitaongezwa kwenye dataframe.\n", "\n", - "Kwa mfano, hebu tuchukue mfano ule ule wa daraja la ndege. Kategoria zilikuwa: ['business class', 'economy class', 'first class']. Kwa hivyo, tukifanya ujumishaji wa one hot, safu tatu zifuatazo zitaongezwa kwenye seti ya data: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Kwa mfano, hebu tuchukue mfano ule ule wa darasa la ndege. Kategoria zilikuwa: ['business class', 'economy class', 'first class']. Kwa hivyo, tukifanya one hot encoding, safu tatu zifuatazo zitaongezwa kwenye dataset: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3187,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "Tufanye usimbaji wa one hot kwenye safu ya kwanza\n" + "Tufanye usimbaji wa moja kwa moja kwenye safu ya kwanza\n" ] }, { @@ -3312,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Kila safu iliyo na hot encoding ina 0 au 1, ambayo inaonyesha kama jamii hiyo ipo kwa data hiyo.\n" + "Kila safu iliyosimbwa kwa moto mmoja ina 0 au 1, ambayo inaonyesha ikiwa jamii hiyo ipo kwa data hiyo.\n" ] }, { @@ -3323,8 +3353,8 @@ "source": [ "Tunatumia one hot encoding lini? One hot encoding hutumika katika mojawapo au zote za hali zifuatazo:\n", "\n", - "1. Wakati idadi ya kategoria na ukubwa wa seti ya data ni ndogo.\n", - "2. Wakati kategoria hazifuati mpangilio maalum.\n" + "1. Wakati idadi ya makundi na ukubwa wa seti ya data ni ndogo.\n", + "2. Wakati makundi hayafuati mpangilio maalum.\n" ] }, { @@ -3344,11 +3374,11 @@ "id": "K8UXOJYRgRsJ" }, "source": [ - "## Kuondoa data inayojirudia\n", + "## Kuondoa data zinazojirudia\n", "\n", - "> **Lengo la kujifunza:** Kufikia mwisho wa sehemu hii, unapaswa kuwa na ujuzi wa kutambua na kuondoa thamani zinazojirudia kutoka kwa DataFrames.\n", + "> **Lengo la kujifunza:** Kufikia mwisho wa sehemu hii ndogo, unapaswa kuwa na ujuzi wa kutambua na kuondoa thamani zinazojirudia kutoka kwa DataFrames.\n", "\n", - "Mbali na data inayokosekana, mara nyingi utakutana na data inayojirudia katika seti za data za maisha halisi. Kwa bahati nzuri, pandas inatoa njia rahisi ya kugundua na kuondoa maingizo yanayojirudia.\n" + "Mbali na data inayokosekana, mara nyingi utakutana na data zinazojirudia katika seti za data za ulimwengu halisi. Kwa bahati nzuri, pandas inatoa njia rahisi ya kugundua na kuondoa maingizo yanayojirudia.\n" ] }, { @@ -3359,7 +3389,7 @@ "source": [ "### Kutambua nakala: `duplicated`\n", "\n", - "Unaweza kutambua kwa urahisi thamani zinazojirudia kwa kutumia mbinu ya `duplicated` katika pandas, ambayo inarudisha maski ya Boolean inayoonyesha kama ingizo katika `DataFrame` ni nakala ya ingizo la awali. Hebu tuunde mfano mwingine wa `DataFrame` ili kuona hii ikifanya kazi.\n" + "Unaweza kutambua kwa urahisi thamani zinazojirudia ukitumia njia ya `duplicated` katika pandas, ambayo inarudisha mask ya Boolean inayoonyesha ikiwa kiingilio katika `DataFrame` ni nakala ya kilichotangulia. Hebu tuunde mfano mwingine wa `DataFrame` ili kuona hili likifanya kazi.\n" ] }, { @@ -3572,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Zote `duplicated` na `drop_duplicates` kwa chaguo-msingi huzingatia safu zote lakini unaweza kubainisha kwamba zichunguze tu sehemu ndogo ya safu katika `DataFrame` yako:\n" + "Zote `duplicated` na `drop_duplicates` kwa chaguo-msingi huzingatia safu zote lakini unaweza kubainisha kwamba zichunguze tu sehemu ya safu katika `DataFrame` yako:\n" ] }, { @@ -3648,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Muktasari:** Kuondoa data zinazojirudia ni sehemu muhimu ya karibu kila mradi wa sayansi ya data. Data zinazojirudia zinaweza kubadilisha matokeo ya uchambuzi wako na kukupa matokeo yasiyo sahihi!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Ukaguzi wa Ubora wa Data ya Ulimwengu Halisi\n", + "\n", + "> **Lengo la kujifunza:** Kufikia mwisho wa sehemu hii, unapaswa kuwa na ujuzi wa kugundua na kurekebisha changamoto za kawaida za ubora wa data ya ulimwengu halisi, ikiwa ni pamoja na thamani za kategoria zisizo thabiti, thamani za nambari zisizo za kawaida (outliers), na entiti zinazojirudia zenye tofauti.\n", + "\n", + "Ingawa thamani zinazokosekana na nakala halisi ni changamoto za kawaida, seti za data za ulimwengu halisi mara nyingi zina matatizo ya hila zaidi:\n", + "\n", + "1. **Thamani za kategoria zisizo thabiti**: Kategoria moja kuandikwa kwa njia tofauti (mfano, \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Thamani za nambari zisizo za kawaida**: Outliers kali zinazoashiria makosa ya kuingiza data (mfano, umri = 999)\n", + "3. **Safu zinazokaribia kujirudia**: Rekodi zinazowakilisha entiti moja lakini zikiwa na tofauti ndogo\n", + "\n", + "Hebu tuchunguze mbinu za kugundua na kushughulikia changamoto hizi.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Kuunda Seti ya Data \"Chafu\" ya Mfano\n", + "\n", + "Kwanza, hebu tuunde seti ya data ya mfano inayojumuisha aina za changamoto tunazokutana nazo mara kwa mara katika data halisi:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Kugundua Thamani Zisizoendana za Kategoria\n", + "\n", + "Angalia safu ya `country` ina uwakilishi tofauti kwa nchi zile zile. Hebu tutambue kutokubaliana huku:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Kuweka Thamani za Kategoria katika Muundo wa Kawaida\n", + "\n", + "Tunaweza kuunda ramani ili kuweka thamani hizi katika muundo wa kawaida. Njia rahisi ni kubadilisha kuwa herufi ndogo na kuunda kamusi ya ramani:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Njia Mbadala: Kutumia Ulinganishaji wa Maneno Usio Sahihi**\n", + "\n", + "Kwa hali ngumu zaidi, tunaweza kutumia ulinganishaji wa maneno usio sahihi kwa kutumia maktaba ya `rapidfuzz` ili kugundua maneno yanayofanana kiotomatiki:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Kugundua Thamani za Nambari Zisizo za Kawaida (Outliers)\n", + "\n", + "Tukiangalia safu ya `age`, tunaona baadhi ya thamani zinazotia shaka kama 199 na -5. Hebu tutumie mbinu za takwimu kugundua outliers hizi.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Kutumia Njia ya IQR (Interquartile Range)\n", + "\n", + "Njia ya IQR ni mbinu thabiti ya takwimu kwa kugundua thamani zisizo za kawaida ambayo haiguswi sana na thamani za kupita kiasi:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Kutumia Njia ya Z-Score\n", + "\n", + "Njia ya Z-score inatambua vipimo vya nje kwa kuzingatia tofauti za kawaida kutoka kwa wastani:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Kushughulikia Thamani Zisizo za Kawaida\n", + "\n", + "Baada ya kugunduliwa, thamani zisizo za kawaida zinaweza kushughulikiwa kwa njia kadhaa:\n", + "1. **Kuondoa**: Futa safu zenye thamani zisizo za kawaida (ikiwa ni makosa)\n", + "2. **Kuweka Kikomo**: Badilisha na thamani za mipaka\n", + "3. **Badilisha na NaN**: Zitendee kama data iliyokosekana na tumia mbinu za kujaza\n", + "4. **Kuhifadhi**: Ikiwa ni thamani halali za kipekee\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Kugundua Safu Zinazokaribiana Kuwa Nakala\n", + "\n", + "Angalia kwamba seti yetu ya data ina maingizo mengi kwa \"John Smith\" yenye thamani zinazotofautiana kidogo. Hebu tutambue nakala zinazoweza kutokea kulingana na mfanano wa majina.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Kupata Nakala Karibu Zinazofanana kwa Kutumia Ulinganishaji wa Kifuzzy\n", + "\n", + "Kwa kugundua nakala zinazofanana kwa njia ya hali ya juu zaidi, tunaweza kutumia ulinganishaji wa kifuzzy ili kupata majina yanayofanana:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Kushughulikia Nakala Zilizojirudia\n", + "\n", + "Baada ya kuzitambua, unahitaji kuamua jinsi ya kushughulikia nakala zilizojirudia:\n", + "1. **Hifadhi tukio la kwanza**: Tumia `drop_duplicates(keep='first')`\n", + "2. **Hifadhi tukio la mwisho**: Tumia `drop_duplicates(keep='last')`\n", + "3. **Kusanya taarifa**: Changanya taarifa kutoka kwa safu zilizojirudia\n", + "4. **Ukaguzi wa mikono**: Weka alama kwa ukaguzi wa binadamu\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Muhtasari: Mchakato Kamili wa Kusafisha Data\n", + "\n", + "Hebu tuunganishe yote pamoja katika mchakato wa kusafisha data kwa ukamilifu:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Zoezi la Changamoto\n", + "\n", + "Sasa ni zamu yako! Hapa chini kuna safu mpya ya data yenye masuala kadhaa ya ubora. Je, unaweza:\n", + "\n", + "1. Kutambua masuala yote katika safu hii\n", + "2. Kuandika msimbo wa kusafisha kila tatizo\n", + "3. Kuongeza safu iliyosafishwa kwenye seti ya data\n", + "\n", + "Hii hapa data yenye matatizo:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Mambo Muhimu\n", + "\n", + "1. **Makundi yasiyo thabiti** ni jambo la kawaida katika data halisi. Daima hakikisha unakagua thamani za kipekee na kuzistandardisha kwa kutumia ramani au kulinganisha kwa ukaribu.\n", + "\n", + "2. **Vipimo vya mbali (Outliers)** vinaweza kuathiri uchambuzi wako kwa kiasi kikubwa. Tumia maarifa ya uwanja pamoja na mbinu za takwimu (IQR, Z-score) ili kuvitambua.\n", + "\n", + "3. **Karibu nakala rudufu (Near-duplicates)** ni ngumu zaidi kutambua kuliko nakala rudufu halisi. Fikiria kutumia kulinganisha kwa ukaribu na kusawazisha data (kuandika kwa herufi ndogo, kuondoa nafasi zisizo za lazima) ili kuvitambua.\n", + "\n", + "4. **Usafi wa data ni wa hatua kwa hatua**. Huenda ukahitaji kutumia mbinu mbalimbali na kupitia matokeo kabla ya kukamilisha seti yako ya data iliyosafishwa.\n", + "\n", + "5. **Rekodi maamuzi yako**. Weka kumbukumbu ya hatua za usafi ulizotumia na sababu zake, kwani hili ni muhimu kwa kurudia na uwazi.\n", + "\n", + "> **Mazoea Bora:** Daima weka nakala ya data yako \"chafu\" ya awali. Usibadilishe faili zako za chanzo - tengeneza matoleo yaliyosafishwa na majina ya faili yaliyo wazi kama `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Kanusho**: \nHati hii imetafsiriwa kwa kutumia huduma ya tafsiri ya AI [Co-op Translator](https://github.com/Azure/co-op-translator). Ingawa tunajitahidi kwa usahihi, tafadhali fahamu kuwa tafsiri za kiotomatiki zinaweza kuwa na makosa au kutokuwa sahihi. Hati ya asili katika lugha yake ya awali inapaswa kuzingatiwa kama chanzo cha mamlaka. Kwa taarifa muhimu, inashauriwa kutumia tafsiri ya kitaalamu ya binadamu. Hatutawajibika kwa maelewano mabaya au tafsiri zisizo sahihi zinazotokana na matumizi ya tafsiri hii.\n" + "\n---\n\n**Kanusho**: \nHati hii imetafsiriwa kwa kutumia huduma ya tafsiri ya AI [Co-op Translator](https://github.com/Azure/co-op-translator). Ingawa tunajitahidi kuhakikisha usahihi, tafadhali fahamu kuwa tafsiri za kiotomatiki zinaweza kuwa na makosa au kutokuwa sahihi. Hati ya asili katika lugha yake ya awali inapaswa kuzingatiwa kama chanzo cha mamlaka. Kwa taarifa muhimu, tafsiri ya kitaalamu ya binadamu inapendekezwa. Hatutawajibika kwa kutoelewana au tafsiri zisizo sahihi zinazotokana na matumizi ya tafsiri hii.\n" ] } ], @@ -3682,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T08:02:30+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:49:12+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "sw" } diff --git a/translations/th/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/th/2-Working-With-Data/08-data-preparation/notebook.ipynb index 42b874fc..accfb31e 100644 --- a/translations/th/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/th/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# การเตรียมข้อมูล\n", "\n", - "[แหล่งโน้ตบุ๊คต้นฉบับจาก *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio โดย Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[แหล่งโน้ตบุ๊กต้นฉบับจาก *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio โดย Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", - "## การสำรวจข้อมูลใน `DataFrame`\n", + "## การสำรวจข้อมูล `DataFrame`\n", "\n", - "> **เป้าหมายการเรียนรู้:** เมื่อจบหัวข้อนี้ คุณควรจะสามารถค้นหาข้อมูลทั่วไปเกี่ยวกับข้อมูลที่จัดเก็บใน pandas DataFrames ได้อย่างคล่องแคล่ว\n", + "> **เป้าหมายการเรียนรู้:** เมื่อจบส่วนย่อยนี้ คุณควรจะสามารถค้นหาข้อมูลทั่วไปเกี่ยวกับข้อมูลที่จัดเก็บใน pandas DataFrames ได้อย่างคล่องแคล่ว\n", "\n", - "เมื่อคุณโหลดข้อมูลของคุณเข้าสู่ pandas ข้อมูลนั้นมักจะอยู่ในรูปแบบ `DataFrame` อย่างไรก็ตาม หากชุดข้อมูลใน `DataFrame` ของคุณมี 60,000 แถวและ 400 คอลัมน์ คุณจะเริ่มต้นทำความเข้าใจข้อมูลที่คุณกำลังทำงานด้วยได้อย่างไร? โชคดีที่ pandas มีเครื่องมือที่สะดวกในการดูข้อมูลโดยรวมของ `DataFrame` อย่างรวดเร็ว รวมถึงแถวแรกและแถวสุดท้ายของข้อมูล\n", + "เมื่อคุณโหลดข้อมูลเข้าสู่ pandas ข้อมูลนั้นมักจะอยู่ในรูปแบบ `DataFrame` อย่างไรก็ตาม หากชุดข้อมูลใน `DataFrame` ของคุณมี 60,000 แถวและ 400 คอลัมน์ คุณจะเริ่มต้นทำความเข้าใจข้อมูลที่คุณกำลังทำงานด้วยได้อย่างไร? โชคดีที่ pandas มีเครื่องมือที่สะดวกในการดูข้อมูลโดยรวมของ `DataFrame` อย่างรวดเร็ว รวมถึงแถวแรกและแถวสุดท้ายบางส่วน\n", "\n", - "เพื่อสำรวจฟังก์ชันนี้ เราจะนำเข้าไลบรารี scikit-learn ของ Python และใช้ชุดข้อมูลที่โด่งดังซึ่งนักวิทยาศาสตร์ข้อมูลทุกคนเคยเห็นมาหลายร้อยครั้ง: ชุดข้อมูล *Iris* ของนักชีววิทยาชาวอังกฤษ Ronald Fisher ซึ่งใช้ในงานวิจัยปี 1936 ของเขา \"The use of multiple measurements in taxonomic problems\":\n" + "เพื่อสำรวจฟังก์ชันนี้ เราจะนำเข้าไลบรารี scikit-learn ของ Python และใช้ชุดข้อมูลที่โด่งดังซึ่งนักวิทยาศาสตร์ข้อมูลทุกคนเคยเห็นมาหลายร้อยครั้ง: ชุดข้อมูล *Iris* ของนักชีววิทยาชาวอังกฤษ Ronald Fisher ที่ใช้ในงานวิจัยปี 1936 ของเขา \"The use of multiple measurements in taxonomic problems\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "เราได้โหลดชุดข้อมูล Iris ไว้ในตัวแปร `iris_df` ก่อนที่จะเริ่มสำรวจข้อมูล จะเป็นประโยชน์ถ้าเรารู้จำนวนข้อมูลที่เรามีและขนาดรวมของชุดข้อมูล การดูปริมาณข้อมูลที่เรากำลังจัดการจะช่วยให้เราเข้าใจภาพรวมได้ดีขึ้น\n" + "เราได้โหลดชุดข้อมูล Iris ลงในตัวแปร `iris_df` ก่อนที่จะเริ่มสำรวจข้อมูล จะเป็นประโยชน์มากหากเราทราบจำนวนจุดข้อมูลที่เรามีและขนาดโดยรวมของชุดข้อมูล การดูปริมาณข้อมูลที่เรากำลังจัดการถือว่าเป็นสิ่งที่มีประโยชน์\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "ดังนั้น เรากำลังจัดการกับข้อมูลจำนวน 150 แถวและ 4 คอลัมน์ โดยแต่ละแถวแสดงถึงจุดข้อมูลหนึ่งจุด และแต่ละคอลัมน์แสดงถึงคุณลักษณะหนึ่งที่เกี่ยวข้องกับกรอบข้อมูล กล่าวคือ มีจุดข้อมูลทั้งหมด 150 จุด โดยแต่ละจุดมีคุณลักษณะ 4 อย่าง\n", + "ดังนั้น เรากำลังจัดการกับข้อมูลจำนวน 150 แถวและ 4 คอลัมน์ โดยแต่ละแถวแสดงถึงจุดข้อมูลหนึ่งจุด และแต่ละคอลัมน์แสดงถึงคุณลักษณะหนึ่งที่เกี่ยวข้องกับกรอบข้อมูล ดังนั้นโดยพื้นฐานแล้ว มีจุดข้อมูลทั้งหมด 150 จุดที่มีคุณลักษณะ 4 อย่างต่อจุด\n", "\n", - "`shape` ในที่นี้เป็นแอตทริบิวต์ของกรอบข้อมูล ไม่ใช่ฟังก์ชัน ซึ่งเป็นเหตุผลว่าทำไมมันถึงไม่มีวงเล็บตามท้าย\n" + "`shape` ในที่นี้เป็นแอตทริบิวต์ของกรอบข้อมูล ไม่ใช่ฟังก์ชัน ซึ่งเป็นเหตุผลว่าทำไมมันจึงไม่มีวงเล็บตามท้าย\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "ตอนนี้เรามาดูข้อมูลใน 4 คอลัมน์กัน แต่ละคอลัมน์แสดงถึงอะไรบ้าง? คุณสมบัติ `columns` จะให้ชื่อของคอลัมน์ใน dataframe กับเรา\n" + "ตอนนี้เรามาดูข้อมูลใน 4 คอลัมน์กันดีกว่า แต่ละคอลัมน์แสดงถึงอะไรบ้าง? คุณสมบัติ `columns` จะให้ชื่อของคอลัมน์ใน dataframe กับเรา\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "ตามที่เราเห็น มีสี่ (4) คอลัมน์ คุณสมบัติ `columns` บอกเราถึงชื่อของคอลัมน์และไม่มีข้อมูลอื่น ๆ คุณสมบัตินี้มีความสำคัญเมื่อเราต้องการระบุคุณลักษณะที่ชุดข้อมูลมี\n" + "ตามที่เราเห็น มีสี่(4) คอลัมน์ คุณสมบัติ `columns` บอกเราถึงชื่อของคอลัมน์และโดยพื้นฐานแล้วไม่มีอะไรอื่น คุณสมบัตินี้มีความสำคัญเมื่อเราต้องการระบุคุณลักษณะที่ชุดข้อมูลมีอยู่\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "จำนวนข้อมูล (ระบุโดย `shape` attribute) และชื่อของฟีเจอร์หรือคอลัมน์ (ระบุโดย `columns` attribute) ให้ข้อมูลบางอย่างเกี่ยวกับชุดข้อมูลแก่เรา ตอนนี้เราต้องการเจาะลึกลงไปในชุดข้อมูล ฟังก์ชัน `DataFrame.info()` มีประโยชน์มากสำหรับสิ่งนี้\n" + "จำนวนข้อมูล (ระบุโดยแอตทริบิวต์ `shape`) และชื่อของฟีเจอร์หรือคอลัมน์ (ระบุโดยแอตทริบิวต์ `columns`) ให้ข้อมูลบางอย่างเกี่ยวกับชุดข้อมูลแก่เรา ตอนนี้เราต้องการเจาะลึกลงไปในชุดข้อมูล ฟังก์ชัน `DataFrame.info()` มีประโยชน์มากสำหรับสิ่งนี้\n" ] }, { @@ -180,9 +180,8 @@ "id": "1XgVMpvigRru" }, "source": [ - "จากตรงนี้ เราสามารถสังเกตได้บางอย่าง:\n", - "\n", - "1. ประเภทข้อมูลของแต่ละคอลัมน์: ในชุดข้อมูลนี้ ข้อมูลทั้งหมดถูกเก็บในรูปแบบตัวเลขทศนิยมแบบ 64 บิต \n", + "จากนี้ เราสามารถสังเกตได้ดังนี้:\n", + "1. ประเภทข้อมูลของแต่ละคอลัมน์: ในชุดข้อมูลนี้ ข้อมูลทั้งหมดถูกจัดเก็บในรูปแบบตัวเลขทศนิยมแบบ 64 บิต\n", "2. จำนวนค่าที่ไม่เป็น Null: การจัดการกับค่าที่เป็น Null เป็นขั้นตอนสำคัญในกระบวนการเตรียมข้อมูล ซึ่งจะถูกจัดการในภายหลังในโน้ตบุ๊ก\n" ] }, @@ -193,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "สมมติว่าเรามีข้อมูลเชิงตัวเลขจำนวนมากในชุดข้อมูลของเรา การคำนวณสถิติแบบตัวแปรเดียว เช่น ค่าเฉลี่ย ค่ามัธยฐาน ควอไทล์ เป็นต้น สามารถทำได้กับแต่ละคอลัมน์แยกกัน ฟังก์ชัน `DataFrame.describe()` จะให้สรุปทางสถิติของคอลัมน์เชิงตัวเลขในชุดข้อมูลแก่เรา\n" + "สมมติว่าเรามีข้อมูลตัวเลขจำนวนมากในชุดข้อมูลของเรา การคำนวณสถิติแบบตัวแปรเดียว เช่น ค่าเฉลี่ย ค่ามัธยฐาน ควอร์ไทล์ ฯลฯ สามารถทำได้กับแต่ละคอลัมน์แยกกัน ฟังก์ชัน `DataFrame.describe()` จะให้สรุปทางสถิติของคอลัมน์ตัวเลขในชุดข้อมูลแก่เรา\n" ] }, { @@ -323,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "ผลลัพธ์ด้านบนแสดงจำนวนข้อมูลทั้งหมด ค่าเฉลี่ย ส่วนเบี่ยงเบนมาตรฐาน ค่าต่ำสุด ควอไทล์ล่าง (25%) ค่ามัธยฐาน (50%) ควอไทล์บน (75%) และค่าสูงสุดของแต่ละคอลัมน์\n" + "ผลลัพธ์ด้านบนแสดงจำนวนจุดข้อมูลทั้งหมด ค่าเฉลี่ย ส่วนเบี่ยงเบนมาตรฐาน ค่าต่ำสุด ควอไทล์ล่าง (25%) ค่ามัธยฐาน (50%) ควอไทล์บน (75%) และค่าสูงสุดของแต่ละคอลัมน์\n" ] }, { @@ -333,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "ด้วยฟังก์ชันและคุณสมบัติทั้งหมดที่กล่าวมาข้างต้น เราได้ภาพรวมของชุดข้อมูลในระดับสูง เรารู้ว่ามีจำนวนข้อมูลเท่าไร มีจำนวนคุณลักษณะเท่าไร ประเภทข้อมูลของแต่ละคุณลักษณะ และจำนวนค่าที่ไม่เป็น null สำหรับแต่ละคุณลักษณะ\n", + "ด้วยฟังก์ชันและคุณสมบัติทั้งหมดที่กล่าวมาข้างต้น เราได้มุมมองระดับสูงของชุดข้อมูลแล้ว เรารู้ว่ามีจำนวนจุดข้อมูลเท่าไร มีจำนวนฟีเจอร์เท่าไร ประเภทข้อมูลของแต่ละฟีเจอร์คืออะไร และจำนวนค่าที่ไม่เป็น null สำหรับแต่ละฟีเจอร์\n", "\n", - "ตอนนี้ถึงเวลาที่จะดูข้อมูลจริงกันแล้ว ลองมาดูว่าบรรทัดแรกๆ (จุดข้อมูลแรกๆ) ของ `DataFrame` ของเรามีลักษณะอย่างไร:\n" + "ตอนนี้ถึงเวลาที่จะดูข้อมูลจริงกันแล้ว ลองมาดูว่าบรรทัดแรกๆ (จุดข้อมูลแรกๆ) ของ `DataFrame` ของเรามีหน้าตาเป็นอย่างไร:\n" ] }, { @@ -442,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "ในผลลัพธ์นี้ เราสามารถเห็นรายการห้า (5) รายการของชุดข้อมูล หากเราดูที่ดัชนีทางด้านซ้าย เราจะพบว่านี่คือห้าบรรทัดแรก\n" + "จากผลลัพธ์ที่นี่ เราสามารถเห็นรายการห้า(5) รายการของชุดข้อมูล หากเราดูที่ดัชนีทางด้านซ้าย เราจะพบว่านี่คือห้าบรรทัดแรก\n" ] }, { @@ -453,7 +452,7 @@ "source": [ "### แบบฝึกหัด:\n", "\n", - "จากตัวอย่างที่ให้ไว้ข้างต้น จะเห็นได้ว่าโดยค่าเริ่มต้น `DataFrame.head` จะคืนค่าแถวแรก 5 แถวของ `DataFrame` ในเซลล์โค้ดด้านล่าง คุณสามารถหาวิธีแสดงแถวมากกว่า 5 แถวได้หรือไม่?\n" + "จากตัวอย่างที่ให้ไว้ข้างต้น จะเห็นได้ว่าโดยค่าเริ่มต้น `DataFrame.head` จะคืนค่าห้าบรรทัดแรกของ `DataFrame` ในเซลล์โค้ดด้านล่าง คุณสามารถหาวิธีแสดงมากกว่าห้าบรรทัดได้หรือไม่?\n" ] }, { @@ -476,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "อีกวิธีหนึ่งในการดูข้อมูลคือดูจากส่วนท้าย (แทนที่จะดูจากส่วนต้น) ฟังก์ชันที่ตรงข้ามกับ `DataFrame.head` คือ `DataFrame.tail` ซึ่งจะคืนค่าห้าบรรทัดสุดท้ายของ `DataFrame`:\n" + "อีกวิธีหนึ่งในการดูข้อมูลคือการดูจากส่วนท้าย (แทนที่จะดูจากส่วนต้น) ฟังก์ชันที่ตรงข้ามกับ `DataFrame.head` คือ `DataFrame.tail` ซึ่งจะคืนค่าห้าบรรทัดสุดท้ายของ `DataFrame`:\n" ] }, { @@ -583,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "ในการปฏิบัติจริง การตรวจสอบแถวแรกๆ หรือแถวสุดท้ายๆ ของ `DataFrame` อย่างง่ายดายนั้นมีประโยชน์มาก โดยเฉพาะเมื่อคุณกำลังมองหาค่าผิดปกติในชุดข้อมูลที่มีการเรียงลำดับ\n", + "ในทางปฏิบัติ การตรวจสอบแถวแรกๆ หรือแถวสุดท้ายของ `DataFrame` อย่างง่ายดายเป็นสิ่งที่มีประโยชน์ โดยเฉพาะเมื่อคุณกำลังมองหาค่าผิดปกติในชุดข้อมูลที่มีการเรียงลำดับ\n", "\n", - "ฟังก์ชันและแอตทริบิวต์ทั้งหมดที่แสดงไว้ข้างต้นพร้อมตัวอย่างโค้ด ช่วยให้เราได้สัมผัสและเข้าใจข้อมูลได้ดีขึ้น\n", + "ฟังก์ชันและคุณสมบัติทั้งหมดที่แสดงไว้ข้างต้นพร้อมตัวอย่างโค้ดช่วยให้เราเข้าใจลักษณะและความรู้สึกของข้อมูลได้\n", "\n", - "> **ข้อคิดสำคัญ:** เพียงแค่ดูเมตาดาต้าเกี่ยวกับข้อมูลใน DataFrame หรือค่าชุดแรกและชุดสุดท้าย คุณก็สามารถเข้าใจได้ทันทีเกี่ยวกับขนาด รูปร่าง และเนื้อหาของข้อมูลที่คุณกำลังจัดการ\n" + "> **ข้อคิดสำคัญ:** เพียงแค่ดูข้อมูลเมตาเกี่ยวกับข้อมูลใน DataFrame หรือค่าชุดแรกและชุดสุดท้าย คุณก็สามารถเข้าใจขนาด รูปร่าง และเนื้อหาของข้อมูลที่คุณกำลังจัดการได้ทันที\n" ] }, { @@ -596,18 +595,18 @@ "id": "TvurZyLSDxq_" }, "source": [ - "### ข้อมูลที่ขาดหายไป\n", - "มาดูเรื่องข้อมูลที่ขาดหายไปกัน ข้อมูลที่ขาดหายไปเกิดขึ้นเมื่อไม่มีการบันทึกค่าในบางคอลัมน์\n", + "### ข้อมูลที่หายไป\n", + "มาดูเรื่องข้อมูลที่หายไปกัน ข้อมูลที่หายไปเกิดขึ้นเมื่อไม่มีการบันทึกค่าในบางคอลัมน์\n", "\n", - "ลองยกตัวอย่าง: สมมติว่ามีคนที่ใส่ใจเรื่องน้ำหนักของตัวเองและไม่กรอกข้อมูลน้ำหนักในแบบสำรวจ ดังนั้น ค่าน้ำหนักของบุคคลนั้นจะถือว่าขาดหายไป\n", + "ลองดูตัวอย่าง: สมมติว่ามีคนที่ใส่ใจเรื่องน้ำหนักของตัวเองและไม่กรอกช่องน้ำหนักในแบบสำรวจ ดังนั้นค่าของน้ำหนักสำหรับบุคคลนั้นจะหายไป\n", "\n", - "ในโลกความเป็นจริง ส่วนใหญ่แล้วข้อมูลที่ขาดหายไปมักจะเกิดขึ้นในชุดข้อมูล\n", + "ในโลกความเป็นจริง ข้อมูลที่หายไปมักเกิดขึ้นในชุดข้อมูลส่วนใหญ่\n", "\n", - "**Pandas จัดการกับข้อมูลที่ขาดหายไปอย่างไร**\n", + "**วิธีที่ Pandas จัดการกับข้อมูลที่หายไป**\n", "\n", - "Pandas จัดการกับข้อมูลที่ขาดหายไปได้สองวิธี วิธีแรกที่คุณเคยเห็นมาก่อนในส่วนก่อนหน้านี้คือ `NaN` หรือ Not a Number นี่เป็นค่าพิเศษที่เป็นส่วนหนึ่งของข้อกำหนด IEEE floating-point และใช้เพื่อระบุค่าที่ขาดหายไปในตัวเลขแบบทศนิยม\n", + "Pandas มีวิธีจัดการกับข้อมูลที่หายไปอยู่สองวิธี วิธีแรกที่คุณเคยเห็นในส่วนก่อนหน้านี้คือ `NaN` หรือ Not a Number ซึ่งเป็นค่าพิเศษที่เป็นส่วนหนึ่งของข้อกำหนด IEEE floating-point และใช้เพื่อระบุค่าที่หายไปในตัวเลขแบบทศนิยมเท่านั้น\n", "\n", - "สำหรับค่าที่ขาดหายไปที่ไม่ใช่ตัวเลขทศนิยม Pandas ใช้ Python `None` object แม้ว่ามันอาจดูสับสนที่คุณจะพบค่าที่แตกต่างกันสองแบบที่แสดงถึงสิ่งเดียวกัน แต่ก็มีเหตุผลทางโปรแกรมที่ดีสำหรับการออกแบบเช่นนี้ และในทางปฏิบัติ การเลือกใช้วิธีนี้ช่วยให้ Pandas สามารถจัดการกับกรณีส่วนใหญ่ได้อย่างมีประสิทธิภาพ อย่างไรก็ตาม ทั้ง `None` และ `NaN` มีข้อจำกัดที่คุณต้องระวังเกี่ยวกับวิธีการใช้งาน\n" + "สำหรับค่าที่หายไปที่ไม่ใช่ตัวเลขแบบทศนิยม Pandas ใช้ Python `None` object แม้ว่ามันอาจดูสับสนที่คุณจะพบค่าที่แตกต่างกันสองแบบที่บอกสิ่งเดียวกัน แต่มีเหตุผลทางโปรแกรมที่ดีสำหรับการออกแบบเช่นนี้ และในทางปฏิบัติ การเลือกใช้วิธีนี้ช่วยให้ Pandas สามารถจัดการกับกรณีส่วนใหญ่ได้อย่างมีประสิทธิภาพ อย่างไรก็ตาม ทั้ง `None` และ `NaN` มีข้อจำกัดที่คุณต้องระวังเกี่ยวกับวิธีการใช้งานของมัน\n" ] }, { @@ -616,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: ข้อมูลที่หายไปแบบไม่ใช่ float\n", - "เนื่องจาก `None` มาจาก Python จึงไม่สามารถใช้ใน NumPy และ pandas arrays ที่ไม่ได้มีชนิดข้อมูลเป็น `'object'` โปรดจำไว้ว่า NumPy arrays (และโครงสร้างข้อมูลใน pandas) สามารถมีได้เพียงชนิดข้อมูลเดียวเท่านั้น นี่คือสิ่งที่ทำให้มันมีพลังมหาศาลสำหรับการทำงานกับข้อมูลและการคำนวณขนาดใหญ่ แต่ก็จำกัดความยืดหยุ่นของมันเช่นกัน อาร์เรย์เหล่านี้ต้องถูกปรับชนิดข้อมูลให้เป็น “ตัวกลางที่ต่ำที่สุด” ซึ่งเป็นชนิดข้อมูลที่ครอบคลุมทุกอย่างในอาร์เรย์ เมื่อ `None` อยู่ในอาร์เรย์ หมายความว่าคุณกำลังทำงานกับ Python objects\n", + "### `None`: ข้อมูลที่ขาดหายซึ่งไม่ใช่ float\n", + "เนื่องจาก `None` มาจาก Python จึงไม่สามารถใช้งานในอาร์เรย์ของ NumPy และ pandas ที่ไม่ได้มีชนิดข้อมูลเป็น `'object'` ได้ โปรดจำไว้ว่า อาร์เรย์ของ NumPy (รวมถึงโครงสร้างข้อมูลใน pandas) สามารถมีได้เพียงชนิดข้อมูลเดียวเท่านั้น นี่คือสิ่งที่ทำให้อาร์เรย์เหล่านี้มีพลังมหาศาลสำหรับการทำงานกับข้อมูลขนาดใหญ่และการคำนวณ แต่ก็จำกัดความยืดหยุ่นของมันเช่นกัน อาร์เรย์เหล่านี้จำเป็นต้องปรับชนิดข้อมูลให้เป็น “ตัวกลางที่ต่ำที่สุด” ซึ่งเป็นชนิดข้อมูลที่สามารถครอบคลุมทุกอย่างในอาร์เรย์ได้ เมื่อมี `None` อยู่ในอาร์เรย์ หมายความว่าคุณกำลังทำงานกับออบเจ็กต์ของ Python\n", "\n", - "เพื่อดูตัวอย่างนี้ ลองพิจารณาอาร์เรย์ตัวอย่างต่อไปนี้ (สังเกต `dtype` ของมัน):\n" + "ลองดูตัวอย่างอาร์เรย์ต่อไปนี้ (สังเกต `dtype` ของมัน):\n" ] }, { @@ -658,7 +657,7 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "ผลกระทบสองประการที่เกิดจากการเปลี่ยนประเภทข้อมูลเป็นแบบ upcast คือ อย่างแรก การดำเนินการจะถูกดำเนินการในระดับของโค้ด Python ที่ถูกตีความแทนที่จะเป็นโค้ด NumPy ที่ถูกคอมไพล์ โดยพื้นฐานแล้วหมายความว่าการดำเนินการใด ๆ ที่เกี่ยวข้องกับ `Series` หรือ `DataFrames` ที่มี `None` อยู่ในนั้นจะทำงานช้าลง แม้ว่าคุณอาจจะไม่สังเกตเห็นผลกระทบด้านประสิทธิภาพนี้ แต่สำหรับชุดข้อมูลขนาดใหญ่ อาจกลายเป็นปัญหาได้\n", + "ความจริงเกี่ยวกับการแปลงประเภทข้อมูลแบบ upcast มีผลกระทบสองประการตามมา ประการแรก การดำเนินการจะถูกดำเนินการในระดับของโค้ด Python ที่ถูกตีความแทนที่จะเป็นโค้ด NumPy ที่ถูกคอมไพล์ โดยพื้นฐานแล้ว หมายความว่าการดำเนินการใด ๆ ที่เกี่ยวข้องกับ `Series` หรือ `DataFrames` ที่มี `None` อยู่ในนั้นจะทำงานช้าลง แม้ว่าคุณอาจจะไม่สังเกตเห็นผลกระทบด้านประสิทธิภาพนี้ แต่สำหรับชุดข้อมูลขนาดใหญ่ มันอาจกลายเป็นปัญหาได้\n", "\n", "ผลกระทบประการที่สองเกิดจากผลกระทบแรก เนื่องจาก `None` โดยพื้นฐานแล้วจะดึง `Series` หรือ `DataFrame` กลับเข้าสู่โลกของ Python แบบดั้งเดิม การใช้การรวมข้อมูลของ NumPy/pandas เช่น `sum()` หรือ `min()` บนอาร์เรย์ที่มีค่า ``None`` อยู่ในนั้นมักจะทำให้เกิดข้อผิดพลาด:\n" ] @@ -698,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**ข้อสำคัญ**: การบวก (และการดำเนินการอื่นๆ) ระหว่างจำนวนเต็มและค่า `None` ไม่สามารถกำหนดได้ ซึ่งอาจจำกัดสิ่งที่คุณสามารถทำได้กับชุดข้อมูลที่มีค่าเหล่านี้\n" + ] }, { "cell_type": "markdown", @@ -706,9 +707,9 @@ "id": "pWvVHvETgRr9" }, "source": [ - "### `NaN`: ค่าตัวเลขทศนิยมที่หายไป\n", + "### `NaN`: ค่าลอยตัวที่หายไป\n", "\n", - "แตกต่างจาก `None`, NumPy (และ pandas ด้วย) รองรับ `NaN` สำหรับการทำงานแบบเวกเตอร์ที่รวดเร็วและ ufuncs ข้อเสียคือ การคำนวณทางคณิตศาสตร์ใดๆ ที่ทำกับ `NaN` จะได้ผลลัพธ์เป็น `NaN` เสมอ ตัวอย่างเช่น:\n" + "แตกต่างจาก `None`, NumPy (และ pandas ด้วย) รองรับ `NaN` สำหรับการดำเนินการแบบเวกเตอร์ที่รวดเร็วและ ufuncs ข่าวร้ายคือการคำนวณใดๆ ที่ทำกับ `NaN` จะให้ผลลัพธ์เป็น `NaN` เสมอ ตัวอย่างเช่น:\n" ] }, { @@ -771,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "ข่าวดี: การรวมข้อมูลที่ทำงานบนอาร์เรย์ที่มี `NaN` อยู่ในนั้นจะไม่แสดงข้อผิดพลาด ข่าวร้าย: ผลลัพธ์ไม่ได้มีประโยชน์อย่างสม่ำเสมอ:\n" + "ข่าวดี: การรวมข้อมูลที่ทำงานบนอาร์เรย์ที่มี `NaN` อยู่ในนั้นจะไม่เกิดข้อผิดพลาด ข่าวร้าย: ผลลัพธ์ไม่ได้มีประโยชน์อย่างสม่ำเสมอ:\n" ] }, { @@ -807,7 +808,9 @@ "metadata": { "id": "nhlnNJT7gRr_" }, - "source": [] + "source": [ + "### แบบฝึกหัด:\n" + ] }, { "cell_type": "code", @@ -827,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "จำไว้ว่า: `NaN` ใช้สำหรับค่าที่ขาดหายไปของตัวเลขทศนิยมเท่านั้น; ไม่มีค่า `NaN` ที่เทียบเท่าสำหรับจำนวนเต็ม, สตริง หรือบูลีน\n" + ] }, { "cell_type": "markdown", @@ -837,7 +842,7 @@ "source": [ "### `NaN` และ `None`: ค่าที่เป็น null ใน pandas\n", "\n", - "แม้ว่า `NaN` และ `None` อาจมีพฤติกรรมที่แตกต่างกันเล็กน้อย แต่ pandas ถูกออกแบบมาให้จัดการกับทั้งสองอย่างได้อย่างแทนที่กันได้ ลองพิจารณา `Series` ของตัวเลขจำนวนเต็ม:\n" + "แม้ว่า `NaN` และ `None` อาจมีพฤติกรรมที่แตกต่างกันเล็กน้อย แต่ pandas ถูกออกแบบมาให้จัดการกับทั้งสองอย่างแทนกันได้ ลองพิจารณา `Series` ของตัวเลขจำนวนเต็ม:\n" ] }, { @@ -876,7 +881,9 @@ "metadata": { "id": "WklCzqb8gRsB" }, - "source": [] + "source": [ + "### การออกกำลังกาย:\n" + ] }, { "cell_type": "code", @@ -899,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "ในกระบวนการเปลี่ยนประเภทข้อมูล (upcasting) เพื่อสร้างความสม่ำเสมอของข้อมูลใน `Series` และ `DataFrame` นั้น pandas จะยอมเปลี่ยนค่าที่หายไประหว่าง `None` และ `NaN` ได้อย่างยืดหยุ่น เนื่องจากคุณสมบัติการออกแบบนี้ จึงอาจเป็นประโยชน์ที่จะมองว่า `None` และ `NaN` เป็นสองรูปแบบที่แตกต่างกันของ \"ค่าว่าง\" ใน pandas จริง ๆ แล้ว วิธีการหลักบางอย่างที่คุณจะใช้ในการจัดการกับค่าที่หายไปใน pandas ก็สะท้อนแนวคิดนี้ในชื่อของมันด้วย:\n", + "ในกระบวนการปรับเปลี่ยนประเภทข้อมูลเพื่อสร้างความเป็นเอกภาพของข้อมูลใน `Series` และ `DataFrame` ของ pandas จะมีการเปลี่ยนค่าที่หายไประหว่าง `None` และ `NaN` ได้อย่างยืดหยุ่น เนื่องจากคุณสมบัติการออกแบบนี้ จึงอาจเป็นประโยชน์ที่จะมองว่า `None` และ `NaN` เป็นสองรูปแบบที่แตกต่างกันของ \"null\" ใน pandas จริง ๆ แล้ว วิธีการหลักบางอย่างที่คุณจะใช้ในการจัดการค่าที่หายไปใน pandas ก็สะท้อนแนวคิดนี้ในชื่อของมัน:\n", "\n", "- `isnull()`: สร้างหน้ากาก Boolean เพื่อระบุค่าที่หายไป\n", "- `notnull()`: ตรงข้ามกับ `isnull()`\n", - "- `dropna()`: คืนค่าข้อมูลในรูปแบบที่กรองแล้ว\n", - "- `fillna()`: คืนสำเนาของข้อมูลที่เติมหรือประมาณค่าที่หายไป\n", + "- `dropna()`: ส่งคืนข้อมูลที่ถูกกรอง\n", + "- `fillna()`: ส่งคืนสำเนาของข้อมูลที่มีการเติมหรือประมาณค่าที่หายไป\n", "\n", - "วิธีการเหล่านี้เป็นสิ่งสำคัญที่ควรเรียนรู้และทำความคุ้นเคย ดังนั้นเรามาเจาะลึกแต่ละวิธีกัน\n" + "วิธีการเหล่านี้เป็นสิ่งสำคัญที่คุณควรเรียนรู้และทำความคุ้นเคย ดังนั้นเรามาทำความเข้าใจแต่ละวิธีอย่างละเอียดกันเถอะ\n" ] }, { @@ -918,7 +925,7 @@ "### การตรวจจับค่าที่เป็น null\n", "\n", "เมื่อเราเข้าใจถึงความสำคัญของค่าที่หายไปแล้ว ขั้นตอนต่อไปคือการตรวจจับค่าที่หายไปในชุดข้อมูลของเรา ก่อนที่จะจัดการกับมัน \n", - "ทั้ง `isnull()` และ `notnull()` เป็นวิธีหลักในการตรวจจับข้อมูลที่เป็น null โดยทั้งสองจะคืนค่าหน้ากาก Boolean ที่ครอบคลุมข้อมูลของคุณ\n" + "ทั้ง `isnull()` และ `notnull()` เป็นวิธีหลักในการตรวจจับข้อมูลที่เป็น null โดยทั้งสองจะคืนค่ามาสก์แบบ Boolean สำหรับข้อมูลของคุณ\n" ] }, { @@ -971,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "ดูให้ดี ๆ กับผลลัพธ์นี้ มีอะไรที่ทำให้คุณแปลกใจหรือเปล่า? แม้ว่า `0` จะเป็นค่าศูนย์ในเชิงคณิตศาสตร์ แต่มันก็ยังคงเป็นจำนวนเต็มที่สมบูรณ์ และ pandas ก็จัดการกับมันในลักษณะนั้น ส่วน `''` นั้นมีความละเอียดอ่อนกว่าเล็กน้อย แม้ว่าเราใช้มันในส่วนที่ 1 เพื่อแสดงถึงค่าข้อความว่างเปล่า แต่มันก็ยังคงเป็นวัตถุประเภทข้อความ และไม่ได้เป็นตัวแทนของ null ในมุมมองของ pandas\n", + "ลองดูผลลัพธ์อย่างละเอียด มีอะไรที่ทำให้คุณแปลกใจหรือเปล่า? แม้ว่า `0` จะเป็นค่าศูนย์ในเชิงคณิตศาสตร์ แต่ก็ยังถือว่าเป็นจำนวนเต็มที่สมบูรณ์ และ pandas ก็จัดการกับมันในลักษณะนั้น ส่วน `''` นั้นมีความละเอียดอ่อนกว่าเล็กน้อย แม้ว่าเราใช้มันใน Section 1 เพื่อแสดงถึงค่าข้อความว่างเปล่า แต่จริง ๆ แล้วมันเป็นวัตถุประเภทข้อความ และไม่ได้เป็นตัวแทนของ null ในมุมมองของ pandas\n", "\n", - "ตอนนี้ ลองเปลี่ยนมุมมองและใช้วิธีการเหล่านี้ในลักษณะที่คุณจะใช้จริงในทางปฏิบัติ คุณสามารถใช้ Boolean masks โดยตรงเป็นดัชนีของ ``Series`` หรือ ``DataFrame`` ซึ่งมีประโยชน์เมื่อคุณต้องการทำงานกับค่าที่หายไป (หรือค่าที่มีอยู่) แบบแยกส่วน\n", + "ตอนนี้ ลองเปลี่ยนมุมมองและใช้วิธีการเหล่านี้ในลักษณะที่ใกล้เคียงกับการใช้งานจริง คุณสามารถใช้ Boolean masks โดยตรงเป็นดัชนีของ ``Series`` หรือ ``DataFrame`` ซึ่งมีประโยชน์เมื่อคุณต้องการทำงานกับค่าที่หายไป (หรือค่าที่มีอยู่) แบบแยกส่วน\n", "\n", - "หากเราต้องการจำนวนรวมของค่าที่หายไป เราสามารถใช้การบวกผลรวมของ mask ที่สร้างขึ้นโดยเมธอด `isnull()` ได้เลย\n" + "หากเราต้องการจำนวนรวมของค่าที่หายไป เราสามารถใช้การบวกค่าทั้งหมดใน mask ที่สร้างขึ้นโดยวิธี `isnull()`\n" ] }, { @@ -1009,7 +1016,9 @@ "metadata": { "id": "PlBqEo3mgRsC" }, - "source": [] + "source": [ + "### แบบฝึกหัด:\n" + ] }, { "cell_type": "code", @@ -1030,7 +1039,9 @@ "metadata": { "id": "D_jWN7mHgRsD" }, - "source": [] + "source": [ + "**ข้อคิดสำคัญ**: ทั้งวิธี `isnull()` และ `notnull()` ให้ผลลัพธ์ที่คล้ายกันเมื่อใช้งานใน DataFrame: พวกมันจะแสดงผลลัพธ์และดัชนีของผลลัพธ์เหล่านั้น ซึ่งจะช่วยคุณได้อย่างมากเมื่อคุณจัดการกับข้อมูลของคุณ.\n" + ] }, { "cell_type": "markdown", @@ -1038,18 +1049,18 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### การจัดการกับข้อมูลที่ขาดหายไป\n", + "### การจัดการกับข้อมูลที่หายไป\n", "\n", - "> **เป้าหมายการเรียนรู้:** เมื่อจบหัวข้อนี้ คุณควรจะรู้วิธีและเวลาที่เหมาะสมในการแทนที่หรือกำจัดค่าที่เป็น null จาก DataFrames\n", + "> **เป้าหมายการเรียนรู้:** เมื่อจบหัวข้อนี้ คุณควรทราบวิธีและเวลาที่เหมาะสมในการแทนที่หรือลบค่าที่เป็น null จาก DataFrames\n", "\n", - "โมเดล Machine Learning ไม่สามารถจัดการกับข้อมูลที่ขาดหายไปได้ด้วยตัวเอง ดังนั้น ก่อนที่จะส่งข้อมูลเข้าสู่โมเดล เราจำเป็นต้องจัดการกับค่าที่ขาดหายไปเหล่านี้\n", + "โมเดล Machine Learning ไม่สามารถจัดการกับข้อมูลที่หายไปได้ด้วยตัวเอง ดังนั้นก่อนที่จะส่งข้อมูลเข้าสู่โมเดล เราจำเป็นต้องจัดการกับค่าที่หายไปเหล่านี้\n", "\n", - "วิธีการจัดการกับข้อมูลที่ขาดหายไปนั้นมีผลกระทบที่ละเอียดอ่อน ซึ่งอาจส่งผลต่อการวิเคราะห์ขั้นสุดท้ายและผลลัพธ์ในโลกความเป็นจริง\n", + "วิธีการจัดการกับข้อมูลที่หายไปมีผลกระทบที่ละเอียดอ่อน ซึ่งอาจส่งผลต่อการวิเคราะห์ขั้นสุดท้ายและผลลัพธ์ในโลกความเป็นจริง\n", "\n", - "มีวิธีหลัก ๆ สองวิธีในการจัดการกับข้อมูลที่ขาดหายไป:\n", + "มีวิธีหลัก ๆ สองวิธีในการจัดการกับข้อมูลที่หายไป:\n", "\n", - "1. ลบแถวที่มีค่าที่ขาดหายไป\n", - "2. แทนค่าที่ขาดหายไปด้วยค่าอื่น\n", + "1. ลบแถวที่มีค่าที่หายไป\n", + "2. แทนค่าที่หายไปด้วยค่าบางอย่าง\n", "\n", "เราจะพูดถึงทั้งสองวิธีนี้ รวมถึงข้อดีและข้อเสียของแต่ละวิธีอย่างละเอียด\n" ] @@ -1060,13 +1071,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### การลบค่าที่เป็นค่าว่าง\n", + "### การลบค่าที่เป็น null\n", "\n", - "ปริมาณข้อมูลที่เราส่งต่อไปยังโมเดลของเรามีผลโดยตรงต่อประสิทธิภาพของมัน การลบค่าที่เป็นค่าว่างหมายความว่าเรากำลังลดจำนวนข้อมูล และด้วยเหตุนี้จึงลดขนาดของชุดข้อมูล ดังนั้นจึงแนะนำให้ลบแถวที่มีค่าว่างเมื่อชุดข้อมูลมีขนาดค่อนข้างใหญ่\n", + "ปริมาณข้อมูลที่เราส่งต่อไปยังโมเดลมีผลโดยตรงต่อประสิทธิภาพของมัน การลบค่าที่เป็น null หมายความว่าเรากำลังลดจำนวนจุดข้อมูล และด้วยเหตุนี้จึงลดขนาดของชุดข้อมูล ดังนั้นจึงแนะนำให้ลบแถวที่มีค่าที่เป็น null เมื่อชุดข้อมูลมีขนาดค่อนข้างใหญ่\n", "\n", - "อีกกรณีหนึ่งอาจเป็นไปได้ว่าแถวหรือคอลัมน์บางแถวมีค่าที่หายไปจำนวนมาก ในกรณีนี้อาจลบออกได้ เพราะมันจะไม่เพิ่มคุณค่ามากนักให้กับการวิเคราะห์ของเรา เนื่องจากข้อมูลส่วนใหญ่ในแถวหรือคอลัมน์นั้นขาดหายไป\n", + "อีกกรณีหนึ่งอาจเป็นแถวหรือคอลัมน์ที่มีค่าหายไปจำนวนมาก ในกรณีนี้อาจลบออกได้ เพราะมันจะไม่เพิ่มคุณค่ามากนักให้กับการวิเคราะห์ของเรา เนื่องจากข้อมูลส่วนใหญ่ในแถวหรือคอลัมน์นั้นหายไป\n", "\n", - "นอกเหนือจากการระบุค่าที่หายไปแล้ว pandas ยังมีวิธีที่สะดวกในการลบค่าที่เป็นค่าว่างออกจาก `Series` และ `DataFrame` เพื่อดูตัวอย่างการใช้งานนี้ เรามาดูที่ `example3` ฟังก์ชัน `DataFrame.dropna()` ช่วยในการลบแถวที่มีค่าที่เป็นค่าว่างออก\n" + "นอกเหนือจากการระบุค่าที่หายไปแล้ว pandas ยังมีวิธีที่สะดวกในการลบค่าที่เป็น null จาก `Series` และ `DataFrame` เพื่อดูตัวอย่างการใช้งานนี้ เรามาดูที่ `example3` ฟังก์ชัน `DataFrame.dropna()` ช่วยในการลบแถวที่มีค่าที่เป็น null\n" ] }, { @@ -1105,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "โปรดทราบว่าสิ่งนี้ควรมีลักษณะเหมือนผลลัพธ์จาก `example3[example3.notnull()]` ความแตกต่างในที่นี้คือ แทนที่จะทำการอินเด็กซ์เฉพาะค่าที่ถูกกรองด้วยหน้ากาก `dropna` ได้ลบค่าที่หายไปออกจาก `Series` `example3` แล้ว\n", + "โปรดทราบว่าสิ่งนี้ควรมีลักษณะเหมือนผลลัพธ์จาก `example3[example3.notnull()]` ความแตกต่างคือแทนที่จะทำการจัดดัชนีบนค่าที่ถูกปิดบังไว้ `dropna` ได้ลบค่าที่หายไปเหล่านั้นออกจาก `Series` `example3`\n", "\n", - "เนื่องจาก DataFrames มีสองมิติ จึงมีตัวเลือกเพิ่มเติมสำหรับการลบข้อมูล\n" + "เนื่องจาก DataFrames มีสองมิติ จึงมีตัวเลือกมากขึ้นสำหรับการลบข้อมูล\n" ] }, { @@ -1197,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(คุณสังเกตเห็นหรือไม่ว่า pandas ได้เปลี่ยนประเภทข้อมูลของสองคอลัมน์เป็น float เพื่อรองรับค่า `NaN`?)\n", + "(คุณสังเกตไหมว่า pandas ได้เปลี่ยนประเภทข้อมูลของสองคอลัมน์เป็น float เพื่อรองรับค่า `NaN`?)\n", "\n", - "คุณไม่สามารถลบค่าหนึ่งค่าออกจาก `DataFrame` ได้ ดังนั้นคุณจำเป็นต้องลบทั้งแถวหรือทั้งคอลัมน์ ขึ้นอยู่กับสิ่งที่คุณกำลังทำ คุณอาจต้องการทำอย่างใดอย่างหนึ่ง และ pandas ก็มีตัวเลือกให้คุณทั้งสองแบบ เนื่องจากในงานด้านวิทยาศาสตร์ข้อมูล คอลัมน์มักจะเป็นตัวแทนของตัวแปร และแถวเป็นตัวแทนของการสังเกต คุณจึงมีแนวโน้มที่จะลบแถวของข้อมูลมากกว่า การตั้งค่าเริ่มต้นของ `dropna()` คือการลบแถวทั้งหมดที่มีค่าที่เป็น null:\n" + "คุณไม่สามารถลบค่าหนึ่งค่าออกจาก `DataFrame` ได้ ดังนั้นคุณต้องลบทั้งแถวหรือทั้งคอลัมน์ ขึ้นอยู่กับสิ่งที่คุณกำลังทำ คุณอาจต้องการทำอย่างใดอย่างหนึ่ง และ pandas ก็มีตัวเลือกให้คุณทั้งสองแบบ เนื่องจากในงานด้านวิทยาศาสตร์ข้อมูล คอลัมน์มักจะแทนตัวแปร และแถวแทนการสังเกตข้อมูล คุณจึงมีแนวโน้มที่จะลบแถวของข้อมูลมากกว่า โดยค่าเริ่มต้นของ `dropna()` จะลบทุกแถวที่มีค่า null อยู่ในนั้น:\n" ] }, { @@ -1272,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "หากจำเป็น คุณสามารถลบค่า NA ออกจากคอลัมน์ได้ ใช้ `axis=1` เพื่อทำเช่นนั้น:\n" + "หากจำเป็น คุณสามารถลบค่าที่เป็น NA ออกจากคอลัมน์ได้ โดยใช้ `axis=1` เพื่อทำเช่นนั้น:\n" ] }, { @@ -1351,7 +1362,7 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "โปรดทราบว่าสิ่งนี้อาจทำให้ข้อมูลจำนวนมากหายไป โดยเฉพาะในชุดข้อมูลที่มีขนาดเล็ก แล้วถ้าคุณต้องการลบเฉพาะแถวหรือคอลัมน์ที่มีค่าที่เป็น null หลายค่า หรือแม้กระทั่งทั้งหมดล่ะ? คุณสามารถกำหนดการตั้งค่าเหล่านี้ใน `dropna` โดยใช้พารามิเตอร์ `how` และ `thresh`\n", + "โปรดทราบว่าสิ่งนี้อาจทำให้ข้อมูลจำนวนมากที่คุณอาจต้องการเก็บไว้หายไป โดยเฉพาะในชุดข้อมูลขนาดเล็ก หากคุณต้องการลบเฉพาะแถวหรือคอลัมน์ที่มีค่าที่เป็น null หลายค่า หรือแม้กระทั่งทั้งหมด คุณสามารถกำหนดการตั้งค่าเหล่านี้ใน `dropna` โดยใช้พารามิเตอร์ `how` และ `thresh`\n", "\n", "โดยค่าเริ่มต้น `how='any'` (หากคุณต้องการตรวจสอบด้วยตัวเองหรือดูว่ามีพารามิเตอร์อื่นๆ ในเมธอดนี้หรือไม่ ให้รัน `example4.dropna?` ในเซลล์โค้ด) คุณสามารถกำหนด `how='all'` เพื่อให้ลบเฉพาะแถวหรือคอลัมน์ที่มีค่าที่เป็น null ทั้งหมด ลองขยายตัวอย่าง `DataFrame` ของเราเพื่อดูการทำงานนี้ในแบบฝึกหัดถัดไป\n" ] @@ -1445,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> ประเด็นสำคัญ: \n", - "1. การลบค่าที่เป็น null เป็นความคิดที่ดีเมื่อชุดข้อมูลมีขนาดใหญ่เพียงพอ \n", - "2. สามารถลบทั้งแถวหรือคอลัมน์ได้ หากข้อมูลส่วนใหญ่ในแถวหรือคอลัมน์นั้นหายไป \n", - "3. เมธอด `DataFrame.dropna(axis=)` ช่วยในการลบค่าที่เป็น null โดยอาร์กิวเมนต์ `axis` ใช้ระบุว่าจะลบแถวหรือคอลัมน์ \n", - "4. อาร์กิวเมนต์ `how` ก็สามารถใช้งานได้เช่นกัน โดยค่าเริ่มต้นจะตั้งไว้ที่ `any` ซึ่งหมายความว่าจะลบเฉพาะแถว/คอลัมน์ที่มีค่า null อย่างน้อยหนึ่งค่าเท่านั้น แต่สามารถตั้งค่าเป็น `all` เพื่อระบุว่าจะลบเฉพาะแถว/คอลัมน์ที่มีค่า null ทั้งหมด\n" + "> ข้อควรทราบ:\n", + "1. การลบค่าที่เป็น null เป็นความคิดที่ดีเฉพาะเมื่อชุดข้อมูลมีขนาดใหญ่พอสมควร\n", + "2. สามารถลบทั้งแถวหรือคอลัมน์ได้ หากข้อมูลส่วนใหญ่ในแถวหรือคอลัมน์นั้นหายไป\n", + "3. เมธอด `DataFrame.dropna(axis=)` ช่วยในการลบค่าที่เป็น null โดยอาร์กิวเมนต์ `axis` ใช้ระบุว่าจะลบแถวหรือคอลัมน์\n", + "4. สามารถใช้อาร์กิวเมนต์ `how` ได้เช่นกัน โดยค่าเริ่มต้นจะตั้งไว้ที่ `any` ซึ่งจะลบเฉพาะแถวหรือคอลัมน์ที่มีค่าที่เป็น null อย่างน้อยหนึ่งค่าเท่านั้น แต่สามารถตั้งค่าเป็น `all` เพื่อระบุว่าจะลบเฉพาะแถวหรือคอลัมน์ที่มีค่าทั้งหมดเป็น null\n" ] }, { @@ -1457,7 +1468,9 @@ "metadata": { "id": "oXXSfQFHgRsF" }, - "source": [] + "source": [ + "### แบบฝึกหัด:\n" + ] }, { "cell_type": "code", @@ -1479,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "พารามิเตอร์ `thresh` ช่วยให้คุณควบคุมได้ละเอียดมากขึ้น: คุณกำหนดจำนวนค่าที่ *ไม่เป็นค่าว่าง* ที่แถวหรือคอลัมน์ต้องมีเพื่อที่จะถูกเก็บไว้:\n" + "พารามิเตอร์ `thresh` ให้คุณควบคุมได้ละเอียดมากขึ้น: คุณกำหนดจำนวนค่าที่ *ไม่เป็นค่าว่าง* ที่แถวหรือคอลัมน์ต้องมีเพื่อที่จะถูกเก็บไว้:\n" ] }, { @@ -1553,7 +1566,9 @@ "metadata": { "id": "fmSFnzZegRsG" }, - "source": [] + "source": [ + "ที่นี่ แถวแรกและแถวสุดท้ายถูกลบออก เนื่องจากมีเพียงสองค่าที่ไม่เป็นค่าว่างเท่านั้น\n" + ] }, { "cell_type": "markdown", @@ -1563,9 +1578,9 @@ "source": [ "### การเติมค่าที่เป็น null\n", "\n", - "บางครั้งการเติมค่าที่ขาดหายไปด้วยค่าที่อาจจะเป็นไปได้ก็สมเหตุสมผล มีเทคนิคอยู่ไม่กี่อย่างในการเติมค่าที่เป็น null วิธีแรกคือการใช้ความรู้เฉพาะด้าน (ความรู้เกี่ยวกับหัวข้อที่ชุดข้อมูลนั้นอ้างอิง) เพื่อประมาณค่าที่ขาดหายไป\n", + "บางครั้งการเติมค่าที่หายไปด้วยค่าที่อาจเป็นไปได้ก็สมเหตุสมผล มีเทคนิคบางอย่างในการเติมค่าที่เป็น null วิธีแรกคือการใช้ความรู้เฉพาะด้าน (ความรู้เกี่ยวกับหัวข้อที่ชุดข้อมูลนั้นอ้างอิง) เพื่อประมาณค่าที่หายไป\n", "\n", - "คุณสามารถใช้ `isnull` เพื่อทำสิ่งนี้ในที่เดียวกันได้ แต่บางครั้งอาจจะยุ่งยาก โดยเฉพาะถ้าคุณมีค่าที่ต้องเติมจำนวนมาก เนื่องจากนี่เป็นงานที่พบได้บ่อยในวิทยาศาสตร์ข้อมูล pandas จึงมีฟังก์ชัน `fillna` ซึ่งจะคืนค่าชุดสำเนาของ `Series` หรือ `DataFrame` โดยค่าที่ขาดหายไปจะถูกแทนที่ด้วยค่าที่คุณเลือก ลองสร้างตัวอย่าง `Series` อีกตัวเพื่อดูว่าสิ่งนี้ทำงานอย่างไรในทางปฏิบัติ\n" + "คุณสามารถใช้ `isnull` เพื่อทำสิ่งนี้โดยตรง แต่บางครั้งอาจเป็นงานที่ยุ่งยาก โดยเฉพาะอย่างยิ่งถ้าคุณมีค่าที่ต้องเติมจำนวนมาก เนื่องจากนี่เป็นงานที่พบได้บ่อยในวิทยาศาสตร์ข้อมูล pandas จึงมีฟังก์ชัน `fillna` ซึ่งจะคืนค่าชุด `Series` หรือ `DataFrame` ที่มีค่าที่หายไปถูกแทนที่ด้วยค่าที่คุณเลือก ลองสร้างตัวอย่าง `Series` อีกตัวเพื่อดูว่ามันทำงานอย่างไรในทางปฏิบัติ\n" ] }, { @@ -1574,12 +1589,12 @@ "id": "CE8S7louLezV" }, "source": [ - "### ข้อมูลเชิงหมวดหมู่ (ไม่ใช่ตัวเลข)\n", - "ก่อนอื่นเรามาพิจารณาข้อมูลที่ไม่ใช่ตัวเลขกันก่อน ในชุดข้อมูล เรามักจะมีคอลัมน์ที่เป็นข้อมูลเชิงหมวดหมู่ เช่น เพศ, จริงหรือเท็จ เป็นต้น\n", + "### ข้อมูลประเภทหมวดหมู่ (ไม่ใช่ตัวเลข)\n", + "ก่อนอื่นเรามาพิจารณาข้อมูลที่ไม่ใช่ตัวเลขกัน ในชุดข้อมูล เรามีคอลัมน์ที่มีข้อมูลประเภทหมวดหมู่ เช่น เพศ, จริงหรือเท็จ เป็นต้น\n", "\n", - "ในกรณีส่วนใหญ่ เราจะแทนค่าที่หายไปด้วย `mode` ของคอลัมน์นั้น สมมติว่าเรามีข้อมูล 100 จุด โดย 90 จุดระบุว่า จริง, 8 จุดระบุว่า เท็จ และ 2 จุดไม่ได้กรอกข้อมูล เราสามารถเติมค่าที่หายไป 2 จุดนั้นด้วยค่า จริง โดยพิจารณาจากทั้งคอลัมน์\n", + "ในกรณีส่วนใหญ่ เราจะแทนค่าที่หายไปด้วย `mode` ของคอลัมน์นั้น เช่น หากเรามีข้อมูล 100 จุด และ 90 จุดระบุว่า จริง, 8 จุดระบุว่า เท็จ และ 2 จุดไม่ได้กรอกข้อมูล เราสามารถเติมค่าที่หายไป 2 จุดนั้นด้วย \"จริง\" โดยพิจารณาจากทั้งคอลัมน์\n", "\n", - "อีกครั้ง เราสามารถใช้ความรู้เฉพาะทางในกรณีนี้ได้ ลองพิจารณาตัวอย่างของการเติมค่าด้วย mode\n" + "อีกครั้ง เราสามารถใช้ความรู้เฉพาะด้านในกรณีนี้ได้ ลองพิจารณาตัวอย่างการเติมค่าด้วย mode\n" ] }, { @@ -1684,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "ตอนนี้ มาหาค่าฐานนิยมก่อนที่จะเติมค่า `None` ด้วยค่าฐานนิยม\n" + ] }, { "cell_type": "code", @@ -1719,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "ดังนั้น เราจะแทนที่ None ด้วย True\n" + ] }, { "cell_type": "code", @@ -1828,7 +1847,9 @@ "metadata": { "id": "SktitLxxOR16" }, - "source": [] + "source": [ + "ดังที่เราเห็น ค่า null ได้ถูกแทนที่แล้ว ไม่ต้องบอกก็รู้ว่าเราสามารถเขียนอะไรก็ได้แทนที่ `'True'` และมันจะถูกแทนที่\n" + ] }, { "cell_type": "markdown", @@ -1836,17 +1857,17 @@ "id": "heYe1I0dOmQ_" }, "source": [ - "### ข้อมูลเชิงตัวเลข\n", - "ตอนนี้มาดูข้อมูลเชิงตัวเลขกันบ้าง ที่นี่เรามีวิธีทั่วไปสองวิธีในการแทนค่าที่หายไป:\n", + "### ข้อมูลตัวเลข\n", + "ตอนนี้มาดูข้อมูลตัวเลขกันบ้าง โดยทั่วไปมีสองวิธีที่นิยมใช้ในการแทนค่าที่หายไป:\n", "\n", "1. แทนด้วยค่ามัธยฐานของแถว\n", "2. แทนด้วยค่าเฉลี่ยของแถว\n", "\n", - "เราจะแทนด้วยค่ามัธยฐานในกรณีที่ข้อมูลมีการกระจายแบบเบ้และมีค่าผิดปกติ เนื่องจากค่ามัธยฐานมีความทนทานต่อค่าผิดปกติ\n", + "เรามักใช้ค่ามัธยฐานในกรณีที่ข้อมูลมีการกระจายแบบเบ้และมีค่าผิดปกติ เนื่องจากค่ามัธยฐานมีความทนทานต่อค่าผิดปกติได้ดี\n", "\n", - "เมื่อข้อมูลได้รับการปรับให้อยู่ในรูปแบบปกติแล้ว เราสามารถใช้ค่าเฉลี่ยได้ เพราะในกรณีนั้น ค่าเฉลี่ยและค่ามัธยฐานจะมีค่าใกล้เคียงกัน\n", + "แต่เมื่อข้อมูลถูกปรับให้เป็นมาตรฐานแล้ว เราสามารถใช้ค่าเฉลี่ยได้ เพราะในกรณีนั้น ค่าเฉลี่ยและค่ามัธยฐานจะมีค่าที่ใกล้เคียงกัน\n", "\n", - "ก่อนอื่น มาลองดูคอลัมน์ที่มีการกระจายแบบปกติ และเติมค่าที่หายไปด้วยค่าเฉลี่ยของคอลัมน์นั้น\n" + "ก่อนอื่น เรามาลองเลือกคอลัมน์ที่มีการแจกแจงแบบปกติ และเติมค่าที่หายไปด้วยค่าเฉลี่ยของคอลัมน์นั้นกัน\n" ] }, { @@ -1986,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "เติมด้วยค่าเฉลี่ย\n" + ] }, { "cell_type": "code", @@ -2085,7 +2108,9 @@ "metadata": { "id": "CwpVFCrPTC5z" }, - "source": [] + "source": [ + "ดังที่เราเห็น ค่าที่หายไปถูกแทนที่ด้วยค่าเฉลี่ยของมัน\n" + ] }, { "cell_type": "markdown", @@ -2093,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "ตอนนี้ลองใช้ดาต้าเฟรมอีกอัน และคราวนี้เราจะเปลี่ยนค่าที่เป็น None ด้วยค่ามัธยฐานของคอลัมน์\n" + "ตอนนี้ลองใช้ DataFrame อีกตัวหนึ่ง และคราวนี้เราจะแทนค่าที่เป็น None ด้วยค่ามัธยฐานของคอลัมน์นั้น\n" ] }, { @@ -2233,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "การเติมด้วยค่ามัธยฐาน\n" + ] }, { "cell_type": "code", @@ -2333,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "ดังที่เราเห็น ค่า NaN ถูกแทนที่ด้วยค่ามัธยฐานของคอลัมน์\n" + "ดังที่เราเห็น ค่า NaN ได้ถูกแทนที่ด้วยค่ามัธยฐานของคอลัมน์\n" ] }, { @@ -2416,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> ประเด็นสำคัญ:\n", + "> ข้อควรทราบ:\n", "1. การเติมค่าที่หายไปควรทำเมื่อมีข้อมูลน้อยหรือมีวิธีการที่ชัดเจนในการเติมค่าที่หายไป\n", "2. ความรู้เฉพาะด้านสามารถนำมาใช้ในการประมาณค่าเพื่อเติมค่าที่หายไปได้\n", - "3. สำหรับข้อมูลประเภทหมวดหมู่ ค่าที่หายไปมักจะถูกแทนด้วยค่าที่พบมากที่สุดในคอลัมน์นั้น\n", - "4. สำหรับข้อมูลเชิงตัวเลข ค่าที่หายไปมักจะถูกเติมด้วยค่าเฉลี่ย (สำหรับชุดข้อมูลที่ผ่านการปรับมาตรฐาน) หรือค่ามัธยฐานของคอลัมน์\n" + "3. สำหรับข้อมูลประเภทหมวดหมู่ ค่าที่หายไปมักจะถูกแทนด้วยค่าที่พบมากที่สุดในคอลัมน์\n", + "4. สำหรับข้อมูลเชิงตัวเลข ค่าที่หายไปมักจะถูกเติมด้วยค่าเฉลี่ย (สำหรับชุดข้อมูลที่ผ่านการปรับให้เป็นมาตรฐาน) หรือค่ามัธยฐานของคอลัมน์\n" ] }, { @@ -2428,7 +2455,9 @@ "metadata": { "id": "FI9MmqFJgRsH" }, - "source": [] + "source": [ + "### การออกกำลังกาย:\n" + ] }, { "cell_type": "code", @@ -2448,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "คุณสามารถ **เติมค่าด้วยค่าก่อนหน้า** สำหรับค่าที่เป็น null ซึ่งหมายถึงการใช้ค่าที่ถูกต้องล่าสุดเพื่อเติมค่าที่เป็น null:\n" + ] }, { "cell_type": "code", @@ -2488,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "คุณยังสามารถ **เติมกลับ** เพื่อกระจายค่าที่ถูกต้องถัดไปย้อนกลับเพื่อเติมค่า null:\n" + "คุณสามารถ **เติมย้อนกลับ** เพื่อกระจายค่าที่ถูกต้องถัดไปย้อนกลับเพื่อเติมค่า null:\n" ] }, { @@ -2530,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "ตามที่คุณอาจเดาได้ สิ่งนี้ทำงานเหมือนกันกับ DataFrames แต่คุณยังสามารถระบุ `axis` ที่จะเติมค่าที่เป็น null ได้:\n" + "ดังที่คุณอาจเดาได้ สิ่งนี้ทำงานในลักษณะเดียวกันกับ DataFrames แต่คุณยังสามารถระบุ `axis` ที่จะใช้เติมค่าที่เป็น null ได้:\n" ] }, { @@ -2702,14 +2733,18 @@ "metadata": { "id": "ZeMc-I1EgRsI" }, - "source": [] + "source": [ + "โปรดทราบว่าเมื่อไม่มีค่าก่อนหน้าเพื่อเติมไปข้างหน้า ค่าที่เป็น null จะยังคงอยู่.\n" + ] }, { "cell_type": "markdown", "metadata": { "id": "eeAoOU0RgRsJ" }, - "source": [] + "source": [ + "### แบบฝึกหัด:\n" + ] }, { "cell_type": "code", @@ -2732,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "คุณสามารถสร้างสรรค์วิธีการใช้ `fillna` ได้ตามต้องการ ตัวอย่างเช่น ลองดูที่ `example4` อีกครั้ง แต่คราวนี้เราจะเติมค่าที่หายไปด้วยค่าเฉลี่ยของค่าทั้งหมดใน `DataFrame`:\n" + "คุณสามารถสร้างสรรค์วิธีการใช้ `fillna` ได้อย่างหลากหลาย ตัวอย่างเช่น ลองดูที่ `example4` อีกครั้ง แต่คราวนี้เราจะเติมค่าที่หายไปด้วยค่าเฉลี่ยของค่าทั้งหมดใน `DataFrame`:\n" ] }, { @@ -2823,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "โปรดทราบว่าคอลัมน์ที่ 3 ยังคงไม่มีค่า: ทิศทางเริ่มต้นคือการเติมค่าแบบเรียงตามแถว\n", + "สังเกตว่าคอลัมน์ที่ 3 ยังคงไม่มีค่า: ทิศทางเริ่มต้นคือการเติมค่าแบบเรียงตามแถว\n", "\n", - "> **ข้อคิดสำคัญ:** มีหลายวิธีในการจัดการกับค่าที่หายไปในชุดข้อมูลของคุณ กลยุทธ์เฉพาะที่คุณเลือกใช้ (การลบออก, การแทนที่, หรือแม้กระทั่งวิธีการแทนที่) ควรขึ้นอยู่กับลักษณะเฉพาะของข้อมูลนั้น คุณจะพัฒนาความเข้าใจที่ดีขึ้นเกี่ยวกับการจัดการค่าที่หายไปเมื่อคุณมีประสบการณ์มากขึ้นในการทำงานและโต้ตอบกับชุดข้อมูล\n" + "> **ข้อคิดสำคัญ:** มีหลายวิธีในการจัดการกับค่าที่หายไปในชุดข้อมูลของคุณ กลยุทธ์เฉพาะที่คุณใช้ (การลบออก, การแทนที่, หรือแม้กระทั่งวิธีการแทนที่) ควรขึ้นอยู่กับลักษณะเฉพาะของข้อมูลนั้น คุณจะพัฒนาความเข้าใจที่ดีขึ้นเกี่ยวกับการจัดการค่าที่หายไปเมื่อคุณมีประสบการณ์มากขึ้นในการทำงานและโต้ตอบกับชุดข้อมูล\n" ] }, { @@ -2836,7 +2871,7 @@ "source": [ "### การเข้ารหัสข้อมูลเชิงหมวดหมู่\n", "\n", - "โมเดลการเรียนรู้ของเครื่องสามารถจัดการได้เฉพาะข้อมูลที่เป็นตัวเลขหรือข้อมูลในรูปแบบตัวเลขเท่านั้น มันไม่สามารถแยกแยะความแตกต่างระหว่าง \"ใช่\" และ \"ไม่ใช่\" ได้ แต่สามารถแยกแยะระหว่าง 0 และ 1 ได้ ดังนั้น หลังจากเติมค่าที่ขาดหายไปแล้ว เราจำเป็นต้องเข้ารหัสข้อมูลเชิงหมวดหมู่ให้อยู่ในรูปแบบตัวเลขเพื่อให้โมเดลเข้าใจ\n", + "โมเดลการเรียนรู้ของเครื่องสามารถจัดการได้เฉพาะข้อมูลที่เป็นตัวเลขเท่านั้น และไม่สามารถแยกแยะความแตกต่างระหว่าง \"ใช่\" และ \"ไม่ใช่\" ได้ แต่สามารถแยกแยะระหว่าง 0 และ 1 ได้ ดังนั้น หลังจากเติมค่าที่หายไปแล้ว เราจำเป็นต้องเข้ารหัสข้อมูลเชิงหมวดหมู่ให้อยู่ในรูปแบบตัวเลขเพื่อให้โมเดลเข้าใจ\n", "\n", "การเข้ารหัสสามารถทำได้สองวิธี ซึ่งเราจะพูดถึงในส่วนถัดไป\n" ] @@ -2849,7 +2884,7 @@ "source": [ "**การเข้ารหัสป้ายกำกับ**\n", "\n", - "การเข้ารหัสป้ายกำกับคือการแปลงแต่ละหมวดหมู่ให้เป็นตัวเลข ตัวอย่างเช่น สมมติว่าเรามีชุดข้อมูลของผู้โดยสารสายการบิน และมีคอลัมน์ที่แสดงชั้นโดยสารของพวกเขาในหมวดหมู่ต่อไปนี้ ['business class', 'economy class', 'first class'] หากทำการเข้ารหัสป้ายกำกับ คอลัมน์นี้จะถูกแปลงเป็น [0,1,2] ลองมาดูตัวอย่างผ่านโค้ดกัน เนื่องจากเราจะเรียนรู้ `scikit-learn` ในสมุดบันทึกถัดไป เราจะยังไม่ใช้มันในที่นี้\n" + "การเข้ารหัสป้ายกำกับคือการแปลงแต่ละหมวดหมู่ให้เป็นตัวเลข ตัวอย่างเช่น สมมติว่าเรามีชุดข้อมูลของผู้โดยสารสายการบิน และมีคอลัมน์ที่ระบุชั้นโดยสารของพวกเขาในหมวดหมู่ต่อไปนี้ ['business class', 'economy class', 'first class'] หากทำการเข้ารหัสป้ายกำกับ คอลัมน์นี้จะถูกแปลงเป็น [0,1,2] ลองมาดูตัวอย่างผ่านโค้ดกัน เนื่องจากเราจะเรียนรู้ `scikit-learn` ในสมุดบันทึกถัดไป เราจะยังไม่ใช้มันในที่นี้\n" ] }, { @@ -2957,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "ในการทำการเข้ารหัสป้ายกำกับในคอลัมน์แรก เราต้องกำหนดการจับคู่จากแต่ละคลาสไปยังตัวเลขก่อนที่จะทำการแทนที่\n" + "ในการเข้ารหัสป้ายกำกับในคอลัมน์แรก เราต้องอธิบายการจับคู่จากแต่ละคลาสไปยังตัวเลขก่อนที่จะทำการแทนที่\n" ] }, { @@ -3059,8 +3094,8 @@ "id": "ftnF-TyapOPt" }, "source": [ - "ตามที่เราเห็น ผลลัพธ์ตรงกับที่เราคาดไว้ ดังนั้น เมื่อไหร่ที่เราควรใช้การเข้ารหัสป้ายกำกับ (label encoding)? การเข้ารหัสป้ายกำกับถูกใช้ในกรณีใดกรณีหนึ่งหรือทั้งสองกรณีดังนี้: \n", - "1. เมื่อจำนวนหมวดหมู่มีมาก \n", + "ตามที่เราเห็น ผลลัพธ์ตรงกับสิ่งที่เราคิดว่าจะเกิดขึ้น ดังนั้น เราจะใช้การเข้ารหัสป้ายกำกับเมื่อไหร่? การเข้ารหัสป้ายกำกับจะถูกใช้ในกรณีใดกรณีหนึ่งหรือทั้งสองกรณีดังต่อไปนี้:\n", + "1. เมื่อจำนวนหมวดหมู่มีมาก\n", "2. เมื่อหมวดหมู่มีลำดับ\n" ] }, @@ -3072,9 +3107,9 @@ "source": [ "**การเข้ารหัสแบบ One Hot Encoding**\n", "\n", - "การเข้ารหัสอีกประเภทหนึ่งคือ One Hot Encoding ในการเข้ารหัสประเภทนี้ แต่ละหมวดหมู่ในคอลัมน์จะถูกเพิ่มเป็นคอลัมน์แยกต่างหาก และแต่ละข้อมูลจะได้รับค่า 0 หรือ 1 ขึ้นอยู่กับว่ามีหมวดหมู่นั้นหรือไม่ ดังนั้น หากมีหมวดหมู่ที่แตกต่างกัน n หมวดหมู่ จะมีการเพิ่มคอลัมน์ n คอลัมน์เข้าไปใน dataframe\n", + "การเข้ารหัสอีกประเภทหนึ่งคือ One Hot Encoding ในการเข้ารหัสประเภทนี้ แต่ละหมวดหมู่ของคอลัมน์จะถูกเพิ่มเป็นคอลัมน์แยกต่างหาก และแต่ละข้อมูลจะได้รับค่า 0 หรือ 1 ขึ้นอยู่กับว่ามันมีหมวดหมู่นั้นหรือไม่ ดังนั้น หากมี n หมวดหมู่ที่แตกต่างกัน จะมีการเพิ่มคอลัมน์ n คอลัมน์เข้าไปใน dataframe\n", "\n", - "ตัวอย่างเช่น ลองพิจารณาตัวอย่างคลาสของเครื่องบิน หมวดหมู่คือ: ['business class', 'economy class', 'first class'] ดังนั้น หากเราทำการเข้ารหัสแบบ one hot encoding จะมีการเพิ่มสามคอลัมน์ต่อไปนี้ลงในชุดข้อมูล: ['class_business class', 'class_economy class', 'class_first class']\n" + "ตัวอย่างเช่น ลองพิจารณาตัวอย่างประเภทที่นั่งในเครื่องบิน หมวดหมู่คือ: ['business class', 'economy class', 'first class'] ดังนั้น หากเราทำการเข้ารหัสแบบ One Hot Encoding จะมีการเพิ่มสามคอลัมน์ต่อไปนี้ลงในชุดข้อมูล: ['class_business class', 'class_economy class', 'class_first class']\n" ] }, { @@ -3307,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "แต่ละคอลัมน์ที่ถูกเข้ารหัสแบบ one-hot จะมีค่าเป็น 0 หรือ 1 ซึ่งระบุว่าหมวดหมู่นั้นมีอยู่สำหรับจุดข้อมูลนั้นหรือไม่\n" + "แต่ละคอลัมน์ที่ถูกเข้ารหัสแบบ One-hot จะมีค่า 0 หรือ 1 ซึ่งระบุว่าหมวดหมู่นั้นมีอยู่สำหรับจุดข้อมูลนั้นหรือไม่\n" ] }, { @@ -3316,7 +3351,7 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "เมื่อไหร่ที่เราควรใช้การเข้ารหัสแบบ One Hot? การเข้ารหัสแบบ One Hot ถูกใช้ในกรณีใดกรณีหนึ่งหรือทั้งสองกรณีดังนี้:\n", + "เราควรใช้การเข้ารหัสแบบ One Hot เมื่อใด? การเข้ารหัสแบบ One Hot ถูกใช้ในกรณีใดกรณีหนึ่งหรือทั้งสองกรณีดังต่อไปนี้:\n", "\n", "1. เมื่อจำนวนหมวดหมู่และขนาดของชุดข้อมูลมีขนาดเล็ก\n", "2. เมื่อหมวดหมู่ไม่มีลำดับที่เฉพาะเจาะจง\n" @@ -3328,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> ประเด็นสำคัญ:\n", - "1. การเข้ารหัสข้อมูลใช้เพื่อแปลงข้อมูลที่ไม่ใช่ตัวเลขให้เป็นข้อมูลตัวเลข\n", - "2. การเข้ารหัสมีสองประเภท: การเข้ารหัสแบบ Label และการเข้ารหัสแบบ One Hot ซึ่งสามารถเลือกใช้ได้ตามความต้องการของชุดข้อมูล\n" + "> ข้อควรทราบ:\n", + "1. การเข้ารหัสใช้เพื่อแปลงข้อมูลที่ไม่ใช่ตัวเลขให้เป็นข้อมูลตัวเลข\n", + "2. การเข้ารหัสมีสองประเภท ได้แก่ การเข้ารหัสแบบ Label และการเข้ารหัสแบบ One Hot ซึ่งสามารถเลือกใช้ตามความต้องการของชุดข้อมูล\n" ] }, { @@ -3339,11 +3374,11 @@ "id": "K8UXOJYRgRsJ" }, "source": [ - "## การลบข้อมูลที่ซ้ำกัน\n", + "## การลบข้อมูลซ้ำ\n", "\n", "> **เป้าหมายการเรียนรู้:** เมื่อจบหัวข้อนี้ คุณควรจะสามารถระบุและลบค่าที่ซ้ำกันจาก DataFrames ได้อย่างมั่นใจ\n", "\n", - "นอกจากข้อมูลที่ขาดหายไปแล้ว คุณมักจะพบข้อมูลที่ซ้ำกันในชุดข้อมูลจริง โชคดีที่ pandas มีวิธีที่ง่ายในการตรวจจับและลบรายการที่ซ้ำกัน\n" + "นอกจากข้อมูลที่หายไปแล้ว คุณมักจะพบข้อมูลที่ซ้ำกันในชุดข้อมูลจริง โชคดีที่ pandas มีวิธีที่ง่ายในการตรวจจับและลบรายการที่ซ้ำกันออกไป\n" ] }, { @@ -3352,9 +3387,9 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### การระบุค่าที่ซ้ำกัน: `duplicated`\n", + "### การระบุค่าซ้ำ: `duplicated`\n", "\n", - "คุณสามารถตรวจสอบค่าที่ซ้ำกันได้อย่างง่ายดายด้วยเมธอด `duplicated` ใน pandas ซึ่งจะคืนค่าเป็น Boolean mask ที่บ่งบอกว่าเอนทรีใน `DataFrame` นั้นซ้ำกับเอนทรีก่อนหน้าหรือไม่ ลองสร้างตัวอย่าง `DataFrame` อีกตัวเพื่อดูการทำงานนี้\n" + "คุณสามารถตรวจสอบค่าที่ซ้ำกันได้อย่างง่ายดายโดยใช้เมธอด `duplicated` ใน pandas ซึ่งจะคืนค่าหน้ากาก Boolean ที่บ่งบอกว่ารายการใน `DataFrame` เป็นค่าซ้ำของรายการก่อนหน้าหรือไม่ ลองสร้างตัวอย่าง `DataFrame` อีกตัวเพื่อดูการทำงานนี้\n" ] }, { @@ -3483,8 +3518,8 @@ "id": "0eDRJD4SgRsK" }, "source": [ - "### การลบข้อมูลซ้ำ: `drop_duplicates`\n", - "`drop_duplicates` จะคืนค่าชุดข้อมูลที่เป็นสำเนา โดยที่ค่าทั้งหมดที่ `duplicated` เป็น `False`:\n" + "### การลบค่าซ้ำ: `drop_duplicates`\n", + "`drop_duplicates` จะคืนค่าข้อมูลสำเนาที่ค่าทั้งหมดใน `duplicated` เป็น `False`:\n" ] }, { @@ -3567,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "ทั้ง `duplicated` และ `drop_duplicates` จะตั้งค่าเริ่มต้นให้พิจารณาทุกคอลัมน์ แต่คุณสามารถระบุให้พวกมันตรวจสอบเฉพาะคอลัมน์ย่อยใน `DataFrame` ของคุณได้:\n" + "ทั้ง `duplicated` และ `drop_duplicates` จะพิจารณาคอลัมน์ทั้งหมดโดยค่าเริ่มต้น แต่คุณสามารถระบุให้พวกมันตรวจสอบเฉพาะชุดย่อยของคอลัมน์ใน `DataFrame` ของคุณได้:\n" ] }, { @@ -3643,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **ข้อคิดสำคัญ:** การลบข้อมูลที่ซ้ำกันเป็นส่วนสำคัญของแทบทุกโครงการด้านวิทยาศาสตร์ข้อมูล ข้อมูลที่ซ้ำกันสามารถเปลี่ยนผลลัพธ์ของการวิเคราะห์และทำให้คุณได้ผลลัพธ์ที่ไม่ถูกต้อง!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## การตรวจสอบคุณภาพข้อมูลในโลกจริง\n", + "\n", + "> **เป้าหมายการเรียนรู้:** เมื่อจบส่วนนี้ คุณควรมีความมั่นใจในการตรวจจับและแก้ไขปัญหาคุณภาพข้อมูลทั่วไปในโลกจริง เช่น ค่าประเภทที่ไม่สอดคล้องกัน ค่าตัวเลขที่ผิดปกติ (ค่าผิดปกติ) และข้อมูลซ้ำที่มีความแตกต่างเล็กน้อย\n", + "\n", + "แม้ว่าค่าที่หายไปและข้อมูลซ้ำแบบตรงตัวจะเป็นปัญหาที่พบได้ทั่วไป แต่ชุดข้อมูลในโลกจริงมักมีปัญหาที่ซับซ้อนมากขึ้น:\n", + "\n", + "1. **ค่าประเภทที่ไม่สอดคล้องกัน**: หมวดหมู่เดียวกันที่สะกดต่างกัน (เช่น \"USA\", \"U.S.A\", \"United States\")\n", + "2. **ค่าตัวเลขที่ผิดปกติ**: ค่าผิดปกติที่รุนแรงซึ่งบ่งบอกถึงข้อผิดพลาดในการป้อนข้อมูล (เช่น อายุ = 999)\n", + "3. **แถวที่เกือบซ้ำกัน**: บันทึกที่แสดงถึงหน่วยเดียวกันแต่มีความแตกต่างเล็กน้อย\n", + "\n", + "มาสำรวจเทคนิคในการตรวจจับและจัดการกับปัญหาเหล่านี้กันเถอะ\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### การสร้างชุดข้อมูลตัวอย่างที่ \"ไม่สะอาด\"\n", + "\n", + "ก่อนอื่น เรามาสร้างชุดข้อมูลตัวอย่างที่มีปัญหาต่างๆ ซึ่งเรามักพบในข้อมูลจริง:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. การตรวจจับค่าประเภทที่ไม่สอดคล้องกัน\n", + "\n", + "สังเกตว่าคอลัมน์ `country` มีการแสดงผลหลายรูปแบบสำหรับประเทศเดียวกัน เรามาระบุความไม่สอดคล้องเหล่านี้กัน:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### การทำให้ค่าประเภทเป็นมาตรฐาน\n", + "\n", + "เราสามารถสร้างการแมปเพื่อทำให้ค่าประเภทเหล่านี้เป็นมาตรฐานได้ วิธีง่ายๆ คือการแปลงเป็นตัวพิมพ์เล็กและสร้างพจนานุกรมการแมป:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**ทางเลือก: การใช้การจับคู่แบบ Fuzzy**\n", + "\n", + "สำหรับกรณีที่ซับซ้อนมากขึ้น เราสามารถใช้การจับคู่สตริงแบบ Fuzzy ด้วยไลบรารี `rapidfuzz` เพื่อช่วยตรวจจับสตริงที่คล้ายกันโดยอัตโนมัติ:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. การตรวจจับค่าตัวเลขที่ผิดปกติ (Outliers)\n", + "\n", + "เมื่อดูที่คอลัมน์ `age` เราพบค่าที่น่าสงสัยบางค่า เช่น 199 และ -5 ลองใช้วิธีทางสถิติเพื่อตรวจจับค่าผิดปกติเหล่านี้กันเถอะ\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### การใช้วิธี IQR (Interquartile Range)\n", + "\n", + "วิธี IQR เป็นเทคนิคทางสถิติที่มีความทนทานสำหรับการตรวจจับค่าผิดปกติ ซึ่งมีความไวต่อค่าที่สุดขีดน้อยกว่า:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### การใช้วิธี Z-Score\n", + "\n", + "วิธี Z-Score ใช้ในการระบุค่าผิดปกติโดยอ้างอิงจากจำนวนส่วนเบี่ยงเบนมาตรฐานจากค่าเฉลี่ย:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### การจัดการค่าผิดปกติ\n", + "\n", + "เมื่อพบค่าผิดปกติ สามารถจัดการได้หลายวิธี:\n", + "1. **ลบออก**: ลบแถวที่มีค่าผิดปกติ (หากเป็นข้อผิดพลาด)\n", + "2. **จำกัดค่า**: แทนที่ด้วยค่าขอบเขต\n", + "3. **แทนที่ด้วย NaN**: ถือว่าเป็นข้อมูลที่หายไปและใช้เทคนิคการเติมข้อมูล\n", + "4. **เก็บไว้**: หากเป็นค่าที่สุดโต่งที่ถูกต้อง\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. การตรวจจับแถวที่คล้ายกันมาก\n", + "\n", + "สังเกตว่าชุดข้อมูลของเรามีหลายรายการสำหรับ \"John Smith\" ที่มีค่าต่างกันเล็กน้อย ลองมาระบุรายการที่อาจเป็นข้อมูลซ้ำกันโดยอิงจากความคล้ายคลึงของชื่อ\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### การค้นหาข้อมูลซ้ำที่คล้ายกันด้วยการจับคู่แบบคลุมเครือ\n", + "\n", + "สำหรับการตรวจจับข้อมูลซ้ำที่ซับซ้อนมากขึ้น เราสามารถใช้การจับคู่แบบคลุมเครือเพื่อค้นหาชื่อที่คล้ายกัน:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### การจัดการข้อมูลซ้ำ\n", + "\n", + "เมื่อระบุข้อมูลซ้ำได้แล้ว คุณต้องตัดสินใจว่าจะจัดการอย่างไร:\n", + "1. **เก็บรายการแรกที่พบ**: ใช้ `drop_duplicates(keep='first')`\n", + "2. **เก็บรายการสุดท้ายที่พบ**: ใช้ `drop_duplicates(keep='last')`\n", + "3. **รวมข้อมูล**: รวมข้อมูลจากแถวที่ซ้ำกัน\n", + "4. **ตรวจสอบด้วยตนเอง**: ทำเครื่องหมายเพื่อให้มนุษย์ตรวจสอบ\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### สรุป: กระบวนการทำความสะอาดข้อมูลแบบครบวงจร\n", + "\n", + "มารวมทุกอย่างเข้าด้วยกันเพื่อสร้างกระบวนการทำความสะอาดข้อมูลที่สมบูรณ์:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 แบบฝึกหัดท้าทาย\n", + "\n", + "ถึงเวลาของคุณแล้ว! ด้านล่างนี้คือแถวข้อมูลใหม่ที่มีปัญหาด้านคุณภาพหลายจุด คุณสามารถ:\n", + "\n", + "1. ระบุปัญหาทั้งหมดในแถวนี้\n", + "2. เขียนโค้ดเพื่อแก้ไขแต่ละปัญหา\n", + "3. เพิ่มแถวที่แก้ไขแล้วลงในชุดข้อมูล\n", + "\n", + "นี่คือข้อมูลที่มีปัญหา:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ประเด็นสำคัญ\n", + "\n", + "1. **หมวดหมู่ที่ไม่สอดคล้องกัน** เป็นเรื่องปกติในข้อมูลจริง ควรตรวจสอบค่าที่ไม่ซ้ำกันและปรับมาตรฐานด้วยการใช้การจับคู่หรือการจับคู่แบบคลุมเครือ\n", + "\n", + "2. **ค่าผิดปกติ** สามารถส่งผลกระทบต่อการวิเคราะห์ได้อย่างมาก ใช้ความรู้เฉพาะด้านร่วมกับวิธีการทางสถิติ (IQR, Z-score) เพื่อตรวจจับค่าผิดปกติ\n", + "\n", + "3. **ข้อมูลที่เกือบซ้ำกัน** ตรวจจับได้ยากกว่าข้อมูลที่ซ้ำกันแบบตรงไปตรงมา ลองใช้การจับคู่แบบคลุมเครือและการปรับข้อมูลให้เป็นมาตรฐาน (เช่น การเปลี่ยนเป็นตัวพิมพ์เล็ก, การลบช่องว่าง) เพื่อช่วยระบุข้อมูลเหล่านี้\n", + "\n", + "4. **การทำความสะอาดข้อมูลเป็นกระบวนการที่ต้องทำซ้ำ** อาจต้องใช้เทคนิคหลายอย่างและตรวจสอบผลลัพธ์ก่อนที่จะสรุปชุดข้อมูลที่ทำความสะอาดแล้ว\n", + "\n", + "5. **บันทึกการตัดสินใจของคุณ** เก็บข้อมูลเกี่ยวกับขั้นตอนการทำความสะอาดที่คุณใช้และเหตุผลที่ทำ เนื่องจากสิ่งนี้สำคัญต่อการทำซ้ำและความโปร่งใส\n", + "\n", + "> **แนวทางปฏิบัติที่ดีที่สุด:** ควรเก็บสำเนาของข้อมูล \"ดิบ\" ไว้เสมอ อย่าทับไฟล์ข้อมูลต้นฉบับของคุณ - สร้างเวอร์ชันที่ทำความสะอาดแล้วพร้อมตั้งชื่อไฟล์ให้ชัดเจน เช่น `data_cleaned.csv`\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**ข้อจำกัดความรับผิดชอบ**: \nเอกสารนี้ได้รับการแปลโดยใช้บริการแปลภาษา AI [Co-op Translator](https://github.com/Azure/co-op-translator) แม้ว่าเราจะพยายามให้การแปลมีความถูกต้อง แต่โปรดทราบว่าการแปลอัตโนมัติอาจมีข้อผิดพลาดหรือความไม่แม่นยำ เอกสารต้นฉบับในภาษาดั้งเดิมควรถือเป็นแหล่งข้อมูลที่เชื่อถือได้ สำหรับข้อมูลที่สำคัญ ขอแนะนำให้ใช้บริการแปลภาษาจากผู้เชี่ยวชาญ เราไม่รับผิดชอบต่อความเข้าใจผิดหรือการตีความที่ผิดพลาดซึ่งเกิดจากการใช้การแปลนี้\n" + "\n---\n\n**ข้อจำกัดความรับผิดชอบ**: \nเอกสารนี้ได้รับการแปลโดยใช้บริการแปลภาษา AI [Co-op Translator](https://github.com/Azure/co-op-translator) แม้ว่าเราจะพยายามให้การแปลมีความถูกต้อง แต่โปรดทราบว่าการแปลโดยอัตโนมัติอาจมีข้อผิดพลาดหรือความไม่ถูกต้อง เอกสารต้นฉบับในภาษาดั้งเดิมควรถือเป็นแหล่งข้อมูลที่เชื่อถือได้ สำหรับข้อมูลที่สำคัญ ขอแนะนำให้ใช้บริการแปลภาษามนุษย์ที่มีความเชี่ยวชาญ เราไม่รับผิดชอบต่อความเข้าใจผิดหรือการตีความผิดที่เกิดจากการใช้การแปลนี้\n" ] } ], @@ -3677,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T08:05:45+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:13:34+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "th" } diff --git a/translations/tl/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/tl/2-Working-With-Data/08-data-preparation/notebook.ipynb index 971b867a..7c906d49 100644 --- a/translations/tl/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/tl/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -6,17 +6,17 @@ "id": "rQ8UhzFpgRra" }, "source": [ - "# Paghahanda ng Datos\n", + "# Paghahanda ng Data\n", "\n", "[Orihinal na Notebook mula sa *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio ni Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## Paggalugad ng impormasyon ng `DataFrame`\n", "\n", - "> **Layunin ng pag-aaral:** Sa pagtatapos ng bahaging ito, dapat kang maging komportable sa paghahanap ng pangkalahatang impormasyon tungkol sa datos na nakaimbak sa pandas DataFrames.\n", + "> **Layunin ng pag-aaral:** Sa pagtatapos ng bahaging ito, dapat kang maging komportable sa paghahanap ng pangkalahatang impormasyon tungkol sa data na nakaimbak sa pandas DataFrames.\n", "\n", - "Kapag na-load mo na ang iyong datos sa pandas, malamang na ito ay nasa anyo ng isang `DataFrame`. Gayunpaman, kung ang data set sa iyong `DataFrame` ay may 60,000 na hanay at 400 na kolum, paano mo sisimulan ang pag-unawa sa kung ano ang iyong pinagtatrabahuhan? Sa kabutihang-palad, ang pandas ay nagbibigay ng ilang maginhawang kasangkapan upang mabilis na makita ang pangkalahatang impormasyon tungkol sa isang `DataFrame` bukod pa sa unang ilang at huling ilang hanay.\n", + "Kapag na-load mo na ang iyong data sa pandas, malamang na ito ay nasa isang `DataFrame`. Gayunpaman, kung ang data set sa iyong `DataFrame` ay may 60,000 na mga hilera at 400 na mga kolum, paano mo sisimulan ang pag-unawa sa kung ano ang iyong pinagtatrabahuhan? Sa kabutihang-palad, ang pandas ay nagbibigay ng ilang maginhawang kasangkapan upang mabilis na makita ang pangkalahatang impormasyon tungkol sa isang `DataFrame` bukod pa sa unang ilang at huling ilang mga hilera.\n", "\n", - "Upang galugarin ang kakayahang ito, mag-i-import tayo ng Python scikit-learn library at gagamit ng isang iconic na dataset na pamilyar sa bawat data scientist: ang *Iris* dataset ng British biologist na si Ronald Fisher na ginamit sa kanyang papel noong 1936 na \"The use of multiple measurements in taxonomic problems\":\n" + "Upang galugarin ang kakayahang ito, mag-iimport tayo ng Python scikit-learn library at gagamit ng isang iconic na dataset na nakita na ng bawat data scientist nang daan-daang beses: ang *Iris* dataset ng British biologist na si Ronald Fisher na ginamit sa kanyang papel noong 1936 na \"The use of multiple measurements in taxonomic problems\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Na-load na natin ang Iris Dataset sa variable na `iris_df`. Bago tayo sumisid sa datos, mahalagang malaman ang bilang ng mga datapoint na mayroon tayo at ang kabuuang laki ng dataset. Kapaki-pakinabang na tingnan ang dami ng datos na ating pinagtatrabahuhan.\n" + "Na-load na natin ang Iris Dataset sa variable na `iris_df`. Bago tayo sumisid sa data, mahalagang malaman ang bilang ng mga datapoints na mayroon tayo at ang kabuuang laki ng dataset. Kapaki-pakinabang na tingnan ang dami ng data na ating pinagtatrabahuhan.\n" ] }, { @@ -78,7 +78,7 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Kaya, mayroon tayong 150 na hanay at 4 na kolum ng datos. Ang bawat hanay ay kumakatawan sa isang datapoint at ang bawat kolum ay kumakatawan sa isang tampok na nauugnay sa data frame. Kaya't sa madaling salita, mayroong 150 na datapoint na may tig-4 na tampok bawat isa.\n", + "Kaya, mayroon tayong 150 na hanay at 4 na kolum ng datos. Ang bawat hanay ay kumakatawan sa isang datapoint at ang bawat kolum ay kumakatawan sa isang tampok na nauugnay sa data frame. Kaya't sa madaling salita, mayroong 150 datapoints na naglalaman ng tig-4 na tampok bawat isa.\n", "\n", "Ang `shape` dito ay isang katangian ng dataframe at hindi isang function, kaya hindi ito nagtatapos sa pares ng mga panaklong.\n" ] @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Ngayon, talakayin natin ang 4 na column ng datos. Ano nga ba ang eksaktong kinakatawan ng bawat isa sa kanila? Ang `columns` na attribute ay magbibigay sa atin ng mga pangalan ng mga column sa dataframe.\n" + "Ngayon, tingnan natin ang 4 na column ng data. Ano ang eksaktong kinakatawan ng bawat isa sa kanila? Ang `columns` na attribute ay magbibigay sa atin ng mga pangalan ng mga column sa dataframe.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Tulad ng nakikita natin, mayroong apat (4) na kolum. Ang `columns` na katangian ay nagsasabi sa atin ng pangalan ng mga kolum at wala nang iba. Nagiging mahalaga ang katangiang ito kapag nais nating tukuyin ang mga tampok na nilalaman ng isang dataset.\n" + "Tulad ng nakikita natin, mayroong apat(4) na kolum. Ang `columns` na katangian ay nagsasabi sa atin ng pangalan ng mga kolum at wala nang iba pa. Ang katangiang ito ay nagiging mahalaga kapag nais nating tukuyin ang mga tampok na nilalaman ng isang dataset.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Ang dami ng datos (ibinibigay ng `shape` attribute) at ang pangalan ng mga tampok o kolum (ibinibigay ng `columns` attribute) ay nagbibigay ng impormasyon tungkol sa dataset. Ngayon, nais nating mas pag-aralan ang dataset. Ang `DataFrame.info()` na function ay lubos na kapaki-pakinabang para dito.\n" + "Ang dami ng datos (ibinibigay ng `shape` attribute) at ang pangalan ng mga tampok o kolum (ibinibigay ng `columns` attribute) ay nagbibigay ng impormasyon tungkol sa dataset. Ngayon, nais nating mas suriin ang dataset. Ang `DataFrame.info()` function ay napaka-kapaki-pakinabang para dito.\n" ] }, { @@ -181,8 +181,8 @@ }, "source": [ "Mula rito, makakagawa tayo ng ilang obserbasyon: \n", - "1. Ang Uri ng Data ng bawat kolum: Sa dataset na ito, lahat ng data ay nakaimbak bilang 64-bit floating-point numbers. \n", - "2. Bilang ng mga Non-Null na halaga: Ang paghawak sa mga null na halaga ay isang mahalagang hakbang sa paghahanda ng data. Ito ay tatalakayin sa mga susunod na bahagi ng notebook. \n" + "1. Ang Uri ng Data ng bawat column: Sa dataset na ito, lahat ng data ay nakaimbak bilang 64-bit floating-point numbers. \n", + "2. Bilang ng mga Non-Null na halaga: Ang paghawak sa mga null na halaga ay isang mahalagang hakbang sa paghahanda ng data. Ito ay tatalakayin sa susunod na bahagi ng notebook. \n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "Sa lahat ng mga nabanggit na function at attribute, mayroon na tayong pangkalahatang ideya tungkol sa dataset. Alam na natin kung ilang data points ang naroon, kung ilang features ang mayroon, ang uri ng data ng bawat feature, at ang bilang ng mga non-null na halaga para sa bawat feature.\n", + "Sa lahat ng mga nabanggit na function at attribute, nakuha na natin ang pangkalahatang pananaw sa dataset. Alam natin kung ilang data points ang naroon, kung ilang features ang mayroon, ang uri ng data ng bawat feature, at ang bilang ng mga non-null na halaga para sa bawat feature.\n", "\n", - "Ngayon, oras na para tingnan mismo ang data. Tingnan natin kung ano ang hitsura ng unang ilang row (ang unang ilang data points) ng ating `DataFrame`:\n" + "Ngayon, oras na para tingnan ang mismong data. Tingnan natin kung ano ang hitsura ng unang ilang row (ang unang ilang data points) ng ating `DataFrame`:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Makikita natin dito sa output ang limang (5) entry ng dataset. Kung titingnan natin ang index sa kaliwa, malalaman natin na ito ang unang limang hanay.\n" + "Makikita natin dito sa output ang limang (5) entries ng dataset. Kung titingnan natin ang index sa kaliwa, malalaman natin na ito ang unang limang hanay.\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Isa pang paraan ng pagtingin sa datos ay mula sa dulo (sa halip na sa simula). Ang kabaligtaran ng `DataFrame.head` ay ang `DataFrame.tail`, na nagbabalik ng huling limang hanay ng isang `DataFrame`:\n" + "Isa pang paraan ng pagtingin sa datos ay mula sa dulo (sa halip na sa simula). Ang kabaligtaran ng `DataFrame.head` ay `DataFrame.tail`, na nagbabalik ng huling limang hanay ng isang `DataFrame`:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "Sa praktika, mahalagang magkaroon ng kakayahang madaling masuri ang unang ilang hanay o ang huling ilang hanay ng isang `DataFrame`, lalo na kung naghahanap ka ng mga outlier sa mga nakaayos na dataset.\n", + "Sa praktika, kapaki-pakinabang na madaling masuri ang unang ilang hanay o ang huling ilang hanay ng isang `DataFrame`, lalo na kapag naghahanap ka ng mga outlier sa mga nakaayos na dataset.\n", "\n", "Ang lahat ng mga function at attribute na ipinakita sa itaas gamit ang mga halimbawa ng code ay tumutulong sa atin na magkaroon ng ideya at pakiramdam tungkol sa datos.\n", "\n", - "> **Mahalagang Punto:** Kahit sa simpleng pagtingin lamang sa metadata tungkol sa impormasyon sa isang DataFrame o sa unang at huling ilang halaga nito, maaari ka nang magkaroon ng agarang ideya tungkol sa laki, hugis, at nilalaman ng datos na iyong hinaharap.\n" + "> **Punto:** Kahit sa simpleng pagtingin lamang sa metadata tungkol sa impormasyon sa isang DataFrame o sa unang at huling ilang halaga nito, maaari kang agad magkaroon ng ideya tungkol sa laki, hugis, at nilalaman ng datos na iyong hinahawakan.\n" ] }, { @@ -595,18 +595,18 @@ "id": "TvurZyLSDxq_" }, "source": [ - "### Nawawalang Datos\n", - "Tuklasin natin ang tungkol sa nawawalang datos. Ang nawawalang datos ay nangyayari kapag walang halaga na nakaimbak sa ilang mga kolum.\n", + "### Nawawalang Data\n", + "Tuklasin natin ang tungkol sa nawawalang data. Ang nawawalang data ay nangyayari kapag walang halaga ang nakaimbak sa ilang mga column.\n", "\n", - "Halimbawa: sabihin nating may isang tao na masyadong sensitibo tungkol sa kanyang timbang at hindi pinupunan ang field para sa timbang sa isang survey. Sa ganitong kaso, ang halaga ng timbang para sa taong iyon ay magiging nawawala.\n", + "Halimbawa: sabihin nating may isang tao na masyadong maingat sa kanyang timbang at hindi pinupunan ang field ng timbang sa isang survey. Sa ganitong kaso, ang halaga ng timbang para sa taong iyon ay magiging nawawala.\n", "\n", - "Kadalasan, sa mga totoong dataset sa mundo, madalas na may mga nawawalang halaga.\n", + "Kadalasan, sa mga dataset sa totoong mundo, madalas na may mga nawawalang halaga.\n", "\n", - "**Paano Hinahawakan ng Pandas ang Nawawalang Datos**\n", + "**Paano Hinahandle ng Pandas ang Nawawalang Data**\n", "\n", - "Hinahawakan ng Pandas ang nawawalang mga halaga sa dalawang paraan. Ang una ay nakita mo na sa mga naunang seksyon: `NaN`, o Not a Number. Ito ay isang espesyal na halaga na bahagi ng IEEE floating-point specification at ginagamit lamang upang ipahiwatig ang nawawalang floating-point na mga halaga.\n", + "Hinahandle ng Pandas ang nawawalang data sa dalawang paraan. Ang una ay nakita mo na sa mga nakaraang seksyon: `NaN`, o Not a Number. Ito ay isang espesyal na halaga na bahagi ng IEEE floating-point specification at ginagamit lamang upang ipakita ang nawawalang floating-point na mga halaga.\n", "\n", - "Para sa mga nawawalang halaga na hindi floats, ginagamit ng pandas ang Python na `None` object. Bagama't maaaring nakakalito na makatagpo ng dalawang magkaibang uri ng halaga na nagsasabi ng halos parehong bagay, may mga makatwirang programmatic na dahilan para sa ganitong disenyo. Sa praktika, ang ganitong paraan ay nagbibigay-daan sa pandas na maghatid ng balanseng solusyon para sa karamihan ng mga kaso. Gayunpaman, parehong `None` at `NaN` ay may mga limitasyon na kailangan mong tandaan kaugnay sa kung paano sila maaaring gamitin.\n" + "Para sa nawawalang mga halaga maliban sa floats, ginagamit ng pandas ang Python na object na `None`. Bagama't maaaring nakakalito na makatagpo ng dalawang magkaibang uri ng mga halaga na nagsasabi ng halos pareho, may mga matibay na programmatic na dahilan para sa ganitong disenyo, at sa praktika, ang ganitong paraan ay nagbibigay-daan sa pandas na maghatid ng magandang kompromiso para sa karamihan ng mga kaso. Gayunpaman, parehong `None` at `NaN` ay may mga limitasyon na dapat mong tandaan kaugnay sa kung paano sila maaaring gamitin.\n" ] }, { @@ -616,9 +616,9 @@ }, "source": [ "### `None`: non-float na nawawalang data\n", - "Dahil ang `None` ay nagmula sa Python, hindi ito maaaring gamitin sa mga NumPy at pandas arrays na hindi may data type na `'object'`. Tandaan, ang mga NumPy arrays (at ang mga data structure sa pandas) ay maaaring maglaman lamang ng isang uri ng data. Ito ang nagbibigay sa kanila ng napakalaking kapangyarihan para sa malakihang data at computational na gawain, ngunit nililimitahan din nito ang kanilang kakayahang mag-adjust. Ang ganitong mga arrays ay kailangang mag-upcast sa “pinakamababang karaniwang denominador,” ang data type na kayang maglaman ng lahat sa array. Kapag ang `None` ay nasa array, nangangahulugan ito na ikaw ay nagtatrabaho gamit ang mga Python objects.\n", + "Dahil ang `None` ay mula sa Python, hindi ito magagamit sa mga NumPy at pandas arrays na hindi may data type na `'object'`. Tandaan, ang mga NumPy arrays (at ang mga istruktura ng data sa pandas) ay maaari lamang maglaman ng isang uri ng data. Ito ang nagbibigay sa kanila ng napakalaking kapangyarihan para sa malakihang data at computational na gawain, ngunit nililimitahan din nito ang kanilang kakayahang umangkop. Ang ganitong mga arrays ay kailangang mag-upcast sa “pinakamababang karaniwang denominator,” ang uri ng data na magpapaloob sa lahat ng nasa array. Kapag ang `None` ay nasa array, nangangahulugan ito na nagtatrabaho ka gamit ang mga Python objects.\n", "\n", - "Upang makita ito sa aktwal, isaalang-alang ang sumusunod na halimbawa ng array (pansinin ang `dtype` nito):\n" + "Para makita ito sa aktwal, isaalang-alang ang sumusunod na halimbawa ng array (pansinin ang `dtype` nito):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Ang realidad ng paggamit ng upcast na mga data type ay may dalawang epekto. Una, ang mga operasyon ay isasagawa sa antas ng interpreted na Python code sa halip na compiled na NumPy code. Sa madaling salita, nangangahulugan ito na ang anumang operasyon na may kinalaman sa `Series` o `DataFrames` na may `None` ay magiging mas mabagal. Bagamat maaaring hindi mo mapansin ang epekto nito sa performance, para sa malalaking dataset, maaari itong maging isang isyu.\n", + "Ang realidad ng mga upcast na uri ng data ay may dalawang epekto. Una, ang mga operasyon ay isasagawa sa antas ng na-interpret na Python code sa halip na sa na-compile na NumPy code. Sa madaling salita, nangangahulugan ito na ang anumang operasyon na may kinalaman sa `Series` o `DataFrames` na may `None` ay magiging mas mabagal. Bagama't maaaring hindi mo mapansin ang epekto sa performance na ito, para sa malalaking dataset, maaari itong maging problema.\n", "\n", - "Ang pangalawang epekto ay nagmumula sa una. Dahil ang `None` ay karaniwang nagdadala ng `Series` o `DataFrame` pabalik sa mundo ng vanilla Python, ang paggamit ng mga NumPy/pandas aggregation tulad ng `sum()` o `min()` sa mga array na naglalaman ng `None` na halaga ay karaniwang magdudulot ng error:\n" + "Ang pangalawang epekto ay nagmumula sa una. Dahil ang `None` ay karaniwang nagdadala ng `Series` o `DataFrame`s pabalik sa mundo ng karaniwang Python, ang paggamit ng mga NumPy/pandas aggregations tulad ng `sum()` o `min()` sa mga array na naglalaman ng isang ``None`` na halaga ay kadalasang magdudulot ng error:\n" ] }, { @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**Pangunahing aral**: Ang pagdaragdag (at iba pang operasyon) sa pagitan ng mga integer at mga `None` na halaga ay hindi natutukoy, na maaaring maglimita sa kung ano ang magagawa mo sa mga dataset na naglalaman ng mga ito.\n" + ] }, { "cell_type": "markdown", @@ -705,7 +707,7 @@ "id": "pWvVHvETgRr9" }, "source": [ - "### `NaN`: nawawalang float na halaga\n", + "### `NaN`: nawawalang float na mga halaga\n", "\n", "Sa kaibahan sa `None`, sinusuportahan ng NumPy (at samakatuwid ng pandas) ang `NaN` para sa mabilis, vectorized na mga operasyon at ufuncs. Ang masamang balita ay anumang arithmetic na ginawa sa `NaN` ay palaging nagreresulta sa `NaN`. Halimbawa:\n" ] @@ -770,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Ang magandang balita: ang mga pagsasama-sama na tumatakbo sa mga array na may `NaN` sa loob nito ay hindi nagdudulot ng mga error. Ang masamang balita: ang mga resulta ay hindi palaging kapaki-pakinabang:\n" + "Ang magandang balita: ang mga aggregations na tumatakbo sa mga array na may `NaN` ay hindi nagdudulot ng mga error. Ang masamang balita: ang mga resulta ay hindi palaging kapaki-pakinabang:\n" ] }, { @@ -828,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "Tandaan: `NaN` ay para lamang sa nawawalang floating-point na mga halaga; walang katumbas na `NaN` para sa mga integer, string, o Boolean.\n" + ] }, { "cell_type": "markdown", @@ -838,7 +842,7 @@ "source": [ "### `NaN` at `None`: mga null na halaga sa pandas\n", "\n", - "Kahit na ang `NaN` at `None` ay maaaring kumilos nang medyo magkaiba, ang pandas ay ginawa upang hawakan ang mga ito nang magkapareho. Upang makita kung ano ang ibig naming sabihin, isaalang-alang ang isang `Series` ng mga integer:\n" + "Kahit na ang `NaN` at `None` ay maaaring kumilos nang medyo magkaiba, ang pandas ay ginawa upang hawakan ang mga ito nang palitan. Upang makita kung ano ang ibig naming sabihin, isaalang-alang ang isang `Series` ng mga integer:\n" ] }, { @@ -902,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Sa proseso ng pag-upcast ng mga uri ng data upang maitatag ang pagkakapareho ng data sa `Series` at `DataFrame`s, kusang pinapalitan ng pandas ang mga nawawalang halaga sa pagitan ng `None` at `NaN`. Dahil sa katangiang ito ng disenyo, makatutulong na isipin ang `None` at `NaN` bilang dalawang magkaibang uri ng \"null\" sa pandas. Sa katunayan, ang ilang pangunahing mga pamamaraan na gagamitin mo upang harapin ang mga nawawalang halaga sa pandas ay sumasalamin sa ideyang ito sa kanilang mga pangalan:\n", + "Sa proseso ng pag-upcast ng mga uri ng data upang maitatag ang pagkakapareho ng data sa `Series` at `DataFrame`s, ang pandas ay kusang nagpapalit ng mga nawawalang halaga sa pagitan ng `None` at `NaN`. Dahil sa tampok na disenyo na ito, makakatulong na isipin ang `None` at `NaN` bilang dalawang magkaibang uri ng \"null\" sa pandas. Sa katunayan, ang ilan sa mga pangunahing pamamaraan na gagamitin mo upang harapin ang mga nawawalang halaga sa pandas ay nagpapakita ng ideyang ito sa kanilang mga pangalan:\n", "\n", - "- `isnull()`: Gumagawa ng Boolean mask na nagpapakita ng mga nawawalang halaga\n", + "- `isnull()`: Gumagawa ng Boolean mask na nagpapahiwatig ng mga nawawalang halaga\n", "- `notnull()`: Kabaligtaran ng `isnull()`\n", "- `dropna()`: Nagbabalik ng na-filter na bersyon ng data\n", - "- `fillna()`: Nagbabalik ng kopya ng data na may napunan o na-impute na mga nawawalang halaga\n", + "- `fillna()`: Nagbabalik ng kopya ng data na may mga nawawalang halaga na napunan o na-impute\n", "\n", - "Mahalagang matutunan at maging pamilyar sa mga pamamaraang ito, kaya talakayin natin ang bawat isa nang mas malalim.\n" + "Ito ay mga mahalagang pamamaraan na dapat mong matutunan at maging komportable sa paggamit, kaya't talakayin natin ang bawat isa nang mas malalim.\n" ] }, { @@ -920,8 +924,7 @@ "source": [ "### Pagtukoy sa mga null na halaga\n", "\n", - "Ngayon na nauunawaan na natin ang kahalagahan ng mga nawawalang halaga, kailangan muna nating tukuyin ang mga ito sa ating dataset bago ito harapin. \n", - "Ang parehong `isnull()` at `notnull()` ang iyong pangunahing mga pamamaraan para matukoy ang null na data. Ang dalawa ay nagbabalik ng Boolean masks sa iyong data.\n" + "Ngayon na nauunawaan na natin ang kahalagahan ng nawawalang mga halaga, kailangan nating tukuyin ang mga ito sa ating dataset bago ito ayusin. Ang parehong `isnull()` at `notnull()` ay pangunahing mga pamamaraan para sa pagtukoy ng null na data. Pareho itong nagbabalik ng Boolean masks sa iyong data.\n" ] }, { @@ -974,11 +977,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Tingnan mong mabuti ang output. Mayroon bang anumang bagay na nakakagulat sa iyo? Bagama't ang `0` ay isang arithmetic null, ito ay isang ganap na wastong integer at tinatrato ito ng pandas bilang ganoon. Ang `''` naman ay medyo mas maselan. Bagama't ginamit natin ito sa Seksyon 1 upang kumatawan sa isang walang laman na string na halaga, ito ay isang string object pa rin at hindi itinuturing na null ayon sa pandas.\n", + "Tingnan nang mabuti ang output. Mayroon bang anumang ikinagulat mo? Bagama't ang `0` ay isang arithmetic null, ito ay isang ganap na maayos na integer at itinuturing ito ng pandas bilang ganoon. Ang `''` ay medyo mas banayad. Bagama't ginamit natin ito sa Seksyon 1 upang kumatawan sa isang walang laman na string na halaga, ito ay isang string object pa rin at hindi isang representasyon ng null ayon sa pandas.\n", "\n", - "Ngayon, baliktarin natin ito at gamitin ang mga pamamaraang ito sa paraang mas malapit sa aktwal na paggamit mo sa kanila. Maaari mong gamitin ang Boolean masks nang direkta bilang isang ``Series`` o ``DataFrame`` index, na maaaring maging kapaki-pakinabang kapag sinusubukang magtrabaho sa mga nakahiwalay na nawawalang (o naroroon) na mga halaga.\n", + "Ngayon, baligtarin natin ito at gamitin ang mga pamamaraang ito sa paraang mas malapit sa kung paano mo ito gagamitin sa aktwal na sitwasyon. Maaari mong gamitin ang Boolean masks nang direkta bilang isang ``Series`` o ``DataFrame`` index, na maaaring maging kapaki-pakinabang kapag sinusubukang magtrabaho sa mga hiwalay na nawawala (o naroroon) na mga halaga.\n", "\n", - "Kung nais nating makuha ang kabuuang bilang ng mga nawawalang halaga, maaari lamang tayong mag-sum sa mask na ginawa ng `isnull()` na pamamaraan.\n" + "Kung gusto natin ang kabuuang bilang ng nawawalang mga halaga, maaari lang tayong mag-sum sa mask na ginawa ng `isnull()` method.\n" ] }, { @@ -1036,7 +1039,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Pangunahing aral**: Parehong ang mga pamamaraan na `isnull()` at `notnull()` ay nagbibigay ng magkatulad na resulta kapag ginamit mo ang mga ito sa mga DataFrame: ipinapakita nila ang mga resulta at ang index ng mga resulta, na makakatulong sa iyo nang malaki habang pinoproseso mo ang iyong data.\n" + "**Pangunahing aral**: Parehong `isnull()` at `notnull()` na mga pamamaraan ay nagbibigay ng magkatulad na resulta kapag ginamit sa mga DataFrame: ipinapakita nila ang mga resulta at ang index ng mga resulta, na makakatulong nang malaki sa iyo habang inaayos mo ang iyong data.\n" ] }, { @@ -1045,20 +1048,20 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### Pagtugon sa Nawawalang Datos\n", + "### Pagtugon sa nawawalang datos\n", "\n", - "> **Layunin ng Pag-aaral:** Sa pagtatapos ng bahaging ito, dapat mong malaman kung paano at kailan papalitan o aalisin ang mga null na halaga mula sa mga DataFrame.\n", + "> **Layunin ng pag-aaral:** Sa pagtatapos ng bahaging ito, dapat mong malaman kung paano at kailan papalitan o aalisin ang mga null na halaga mula sa mga DataFrame.\n", "\n", "Ang mga modelo ng Machine Learning ay hindi kayang direktang magproseso ng nawawalang datos. Kaya, bago ipasa ang datos sa modelo, kailangan nating tugunan ang mga nawawalang halaga.\n", "\n", - "Ang paraan ng paghawak sa nawawalang datos ay may kasamang mga maseselang tradeoff, at maaaring makaapekto sa iyong huling pagsusuri at mga resulta sa totoong mundo.\n", + "Ang paraan ng paghawak sa nawawalang datos ay may kasamang mga maseselang tradeoff, na maaaring makaapekto sa iyong huling pagsusuri at mga resulta sa totoong mundo.\n", "\n", - "Mayroong pangunahing dalawang paraan upang tugunan ang nawawalang datos:\n", + "May dalawang pangunahing paraan ng pagtugon sa nawawalang datos:\n", "\n", - "1. Alisin ang row na naglalaman ng nawawalang halaga \n", - "2. Palitan ang nawawalang halaga ng ibang halaga \n", + "1. Alisin ang row na naglalaman ng nawawalang halaga\n", + "2. Palitan ang nawawalang halaga ng ibang halaga\n", "\n", - "Tatalakayin natin ang parehong mga pamamaraang ito at ang kanilang mga kalamangan at kahinaan nang detalyado.\n" + "Tatalakayin natin ang parehong mga pamamaraan at ang kanilang mga kalamangan at kahinaan nang detalyado.\n" ] }, { @@ -1069,11 +1072,11 @@ "source": [ "### Pag-aalis ng mga null na halaga\n", "\n", - "Ang dami ng datos na ipinapasa natin sa ating modelo ay may direktang epekto sa performance nito. Ang pag-aalis ng mga null na halaga ay nangangahulugan na binabawasan natin ang bilang ng mga datapoint, at sa gayon ay binabawasan ang laki ng dataset. Kaya, inirerekomenda na alisin ang mga row na may null na halaga kapag ang dataset ay medyo malaki.\n", + "Ang dami ng datos na ipinapasa natin sa ating modelo ay may direktang epekto sa pagganap nito. Ang pag-aalis ng mga null na halaga ay nangangahulugan na binabawasan natin ang bilang ng mga datapoint, at sa gayon ay binabawasan ang laki ng dataset. Kaya, mas mainam na alisin ang mga row na may null na halaga kapag ang dataset ay medyo malaki.\n", "\n", - "Isa pang halimbawa ay kung ang isang partikular na row o column ay may maraming nawawalang halaga. Sa ganitong kaso, maaaring alisin ang mga ito dahil hindi naman sila makakapagdagdag ng malaking halaga sa ating pagsusuri dahil karamihan sa datos para sa row/column na iyon ay nawawala.\n", + "Isa pang sitwasyon ay kung ang isang partikular na row o column ay may maraming nawawalang halaga. Sa ganitong kaso, maaaring alisin ang mga ito dahil hindi sila magdadagdag ng malaking halaga sa ating pagsusuri dahil karamihan sa datos para sa row/column na iyon ay nawawala.\n", "\n", - "Bukod sa pagtukoy ng mga nawawalang halaga, ang pandas ay nagbibigay ng maginhawang paraan upang alisin ang mga null na halaga mula sa `Series` at `DataFrame`s. Upang makita ito sa aksyon, balikan natin ang `example3`. Ang function na `DataFrame.dropna()` ay tumutulong sa pag-aalis ng mga row na may null na halaga.\n" + "Bukod sa pagtukoy ng mga nawawalang halaga, nagbibigay ang pandas ng maginhawang paraan upang alisin ang mga null na halaga mula sa `Series` at `DataFrame`s. Upang makita ito sa aksyon, balikan natin ang `example3`. Ang function na `DataFrame.dropna()` ay tumutulong sa pag-aalis ng mga row na may null na halaga.\n" ] }, { @@ -1112,9 +1115,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "Tandaan na dapat itong magmukhang iyong output mula sa `example3[example3.notnull()]`. Ang pagkakaiba dito ay, sa halip na i-index lamang ang mga masked na halaga, inalis ng `dropna` ang mga nawawalang halaga mula sa `Series` na `example3`.\n", + "Tandaan na dapat itong magmukhang katulad ng output mula sa `example3[example3.notnull()]`. Ang pagkakaiba dito ay, sa halip na i-index lamang ang mga nakamaskarang halaga, inalis ng `dropna` ang mga nawawalang halaga mula sa `Series` na `example3`.\n", "\n", - "Dahil ang mga DataFrame ay may dalawang dimensyon, nagbibigay ito ng mas maraming opsyon para sa pag-aalis ng data.\n" + "Dahil ang mga DataFrame ay may dalawang dimensyon, mas maraming opsyon ang mayroon para sa pag-aalis ng data.\n" ] }, { @@ -1279,7 +1282,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "Kung kinakailangan, maaari mong tanggalin ang mga NA na halaga mula sa mga kolum. Gamitin ang `axis=1` upang gawin ito:\n" + "Kung kinakailangan, maaari mong tanggalin ang mga NA na halaga mula sa mga column. Gamitin ang `axis=1` para gawin ito:\n" ] }, { @@ -1358,9 +1361,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Tandaan na maaaring mawala ang maraming datos na maaaring gusto mong itago, lalo na sa mas maliliit na dataset. Paano kung gusto mo lang tanggalin ang mga row o column na may ilang o kahit lahat ng null na halaga? Maaari mong tukuyin ang mga setting na ito sa `dropna` gamit ang mga parameter na `how` at `thresh`.\n", + "Pansinin na maaaring mawala ang maraming datos na gusto mong itago, lalo na sa mas maliliit na dataset. Paano kung gusto mo lang tanggalin ang mga row o column na may ilang null values o kahit lahat ng null values? Maaari mong itakda ang mga setting na ito sa `dropna` gamit ang mga parameter na `how` at `thresh`.\n", "\n", - "Sa default, `how='any'` (kung nais mong suriin ito mismo o makita ang iba pang mga parameter na mayroon ang method, patakbuhin ang `example4.dropna?` sa isang code cell). Maaari mo ring tukuyin ang `how='all'` upang tanggalin lamang ang mga row o column na may lahat ng null na halaga. Palawakin natin ang ating halimbawa ng `DataFrame` upang makita ito sa aksyon sa susunod na ehersisyo.\n" + "Sa default, `how='any'` (kung gusto mong suriin ito para sa iyong sarili o makita ang iba pang mga parameter ng method, patakbuhin ang `example4.dropna?` sa isang code cell). Maaari mo ring tukuyin ang `how='all'` upang tanggalin lamang ang mga row o column na may lahat ng null values. Palawakin natin ang halimbawa ng `DataFrame` upang makita ito sa aksyon sa susunod na ehersisyo.\n" ] }, { @@ -1452,11 +1455,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> Mahahalagang Punto: \n", - "1. Ang pagtanggal ng mga null na halaga ay magandang ideya lamang kung sapat na kalaki ang dataset. \n", - "2. Maaaring tanggalin ang buong mga row o column kung karamihan sa kanilang data ay nawawala. \n", - "3. Ang `DataFrame.dropna(axis=)` na method ay tumutulong sa pagtanggal ng mga null na halaga. Ang argumentong `axis` ay nagpapahiwatig kung ang mga row o column ang tatanggalin. \n", - "4. Maaaring gamitin ang argumentong `how`. Sa default, ito ay nakatakda sa `any`. Kaya, tinatanggal lamang nito ang mga row/column na mayroong kahit anong null na halaga. Maaari itong itakda sa `all` upang tukuyin na tatanggalin lamang ang mga row/column kung lahat ng halaga ay null. \n" + "> Mahahalagang puntos:\n", + "1. Ang pag-aalis ng mga null na halaga ay magandang ideya lamang kung sapat ang laki ng dataset.\n", + "2. Maaaring alisin ang buong mga row o column kung karamihan sa kanilang data ay nawawala.\n", + "3. Ang `DataFrame.dropna(axis=)` na pamamaraan ay nakakatulong sa pag-aalis ng mga null na halaga. Ang argumento na `axis` ay nagpapahiwatig kung ang mga row o column ang aalisin.\n", + "4. Maaaring gamitin ang argumento na `how`. Sa default, ito ay nakatakda sa `any`. Kaya, aalisin lamang nito ang mga row/column na mayroong anumang null na halaga. Maaari itong itakda sa `all` upang tukuyin na aalisin lamang natin ang mga row/column kung saan lahat ng halaga ay null.\n" ] }, { @@ -1562,7 +1565,9 @@ "metadata": { "id": "fmSFnzZegRsG" }, - "source": [] + "source": [ + "Dito, ang unang at huling hanay ay inalis, dahil naglalaman lamang ang mga ito ng dalawang hindi null na halaga.\n" + ] }, { "cell_type": "markdown", @@ -1570,11 +1575,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### Pagpuno ng mga null na halaga\n", + "### Pagpuno ng mga nawawalang halaga\n", "\n", - "Minsan may kabuluhan na punan ang mga nawawalang halaga gamit ang mga maaaring maging wasto. May ilang mga teknik para punan ang mga null na halaga. Ang una ay ang paggamit ng Kaalaman sa Larangan (kaalaman tungkol sa paksa kung saan nakabatay ang dataset) upang sa paanuman ay matantiya ang mga nawawalang halaga.\n", + "Minsan may kabuluhan na punan ang mga nawawalang halaga ng mga maaaring maging wasto. May ilang mga teknik para punan ang mga null na halaga. Ang una ay ang paggamit ng Domain Knowledge (kaalaman sa paksa kung saan nakabase ang dataset) upang tantyahin ang mga nawawalang halaga.\n", "\n", - "Maaari mong gamitin ang `isnull` upang gawin ito nang direkta, ngunit maaaring matrabaho ito, lalo na kung marami kang halagang kailangang punan. Dahil ito ay isang karaniwang gawain sa data science, ang pandas ay nagbibigay ng `fillna`, na nagbabalik ng kopya ng `Series` o `DataFrame` kung saan ang mga nawawalang halaga ay pinalitan ng halagang iyong pinili. Gumawa tayo ng isa pang halimbawa ng `Series` upang makita kung paano ito gumagana sa praktika.\n" + "Maaari mong gamitin ang `isnull` upang gawin ito nang direkta, ngunit maaaring matrabaho ito, lalo na kung marami kang halaga na kailangang punan. Dahil ito ay isang karaniwang gawain sa data science, nagbibigay ang pandas ng `fillna`, na nagbabalik ng kopya ng `Series` o `DataFrame` na may mga nawawalang halaga na pinalitan ng napili mo. Gumawa tayo ng isa pang halimbawa ng `Series` upang makita kung paano ito gumagana sa praktika.\n" ] }, { @@ -1583,12 +1588,12 @@ "id": "CE8S7louLezV" }, "source": [ - "### Datos na Kategorya (Hindi-Numeriko)\n", - "Unahin nating talakayin ang hindi-numerikong datos. Sa mga dataset, may mga kolum na naglalaman ng datos na kategorya. Halimbawa: Kasarian, Totoo o Mali, at iba pa.\n", + "### Categorical Data (Hindi-numeriko)\n", + "Una, tingnan natin ang hindi-numerikong data. Sa mga dataset, may mga column na naglalaman ng categorical data. Halimbawa: Kasarian, Tama o Mali, at iba pa.\n", "\n", - "Sa karamihan ng mga ganitong kaso, pinapalitan natin ang mga nawawalang halaga gamit ang `mode` ng kolum. Halimbawa, mayroon tayong 100 data points kung saan 90 ang nagsabing Totoo, 8 ang nagsabing Mali, at 2 ang walang sagot. Sa ganitong sitwasyon, maaari nating punan ang 2 na nawawala ng Totoo, batay sa kabuuang datos ng kolum.\n", + "Sa karamihan ng mga ganitong kaso, pinapalitan natin ang nawawalang mga halaga gamit ang `mode` ng column. Halimbawa, mayroon tayong 100 data points kung saan 90 ang nagsabi ng Tama, 8 ang nagsabi ng Mali, at 2 ang hindi naglagay ng sagot. Sa ganitong sitwasyon, maaari nating punan ang 2 na nawawala ng Tama, batay sa kabuuang data ng column.\n", "\n", - "Muli, maaari rin nating gamitin ang kaalaman sa domain dito. Tingnan natin ang isang halimbawa ng pagpuno gamit ang mode.\n" + "Muli, maaari nating gamitin ang kaalaman sa domain dito. Tingnan natin ang isang halimbawa ng pagpuno gamit ang mode.\n" ] }, { @@ -1693,7 +1698,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Ngayon, hanapin muna natin ang moda bago punan ang halagang `None` ng moda.\n" + ] }, { "cell_type": "code", @@ -1728,7 +1735,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Kaya, papalitan natin ang None ng True\n" + ] }, { "cell_type": "code", @@ -1838,7 +1847,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Tulad ng nakikita natin, napalitan na ang null na halaga. Hindi na kailangang sabihin, maaari tayong magsulat ng kahit ano kapalit ng `'True'` at ito ay mapapalitan.\n" + "Tulad ng nakikita natin, ang null na halaga ay napalitan. Hindi na kailangang sabihin, maaari tayong magsulat ng kahit ano sa lugar ng `'True'` at ito ay mapapalitan.\n" ] }, { @@ -1848,14 +1857,14 @@ }, "source": [ "### Numeric Data\n", - "Ngayon, pag-usapan natin ang numeric data. Dito, may dalawang karaniwang paraan ng pagpapalit sa mga nawawalang halaga:\n", + "Ngayon, tungkol sa numeric na datos. Dito, may dalawang karaniwang paraan ng pagpapalit ng nawawalang mga halaga:\n", "\n", "1. Palitan gamit ang Median ng row\n", "2. Palitan gamit ang Mean ng row\n", "\n", - "Ginagamit natin ang Median kapag ang data ay skewed at may mga outlier. Ito ay dahil ang median ay hindi gaanong naaapektuhan ng mga outlier.\n", + "Ginagamit natin ang Median kapag ang datos ay skewed at may mga outlier. Ito ay dahil ang median ay hindi gaanong naaapektuhan ng mga outlier.\n", "\n", - "Kapag ang data ay na-normalize, maaari nating gamitin ang mean, dahil sa ganitong kaso, ang mean at median ay halos magkapareho.\n", + "Kapag ang datos ay normalisado, maaari nating gamitin ang mean, dahil sa ganitong kaso, ang mean at median ay halos magkapareho.\n", "\n", "Una, kumuha tayo ng isang column na may normal na distribusyon at punan natin ang nawawalang halaga gamit ang mean ng column.\n" ] @@ -1997,7 +2006,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Pagpuno gamit ang mean\n" + ] }, { "cell_type": "code", @@ -2097,7 +2108,7 @@ "id": "CwpVFCrPTC5z" }, "source": [ - "Tulad ng nakikita natin, ang nawawalang halaga ay napalitan ng kanyang mean.\n" + "Makikita natin na ang nawawalang halaga ay pinalitan ng kanyang mean.\n" ] }, { @@ -2246,7 +2257,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Pagpuno gamit ang median\n" + ] }, { "cell_type": "code", @@ -2346,7 +2359,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Tulad ng nakikita natin, ang NaN na halaga ay napalitan ng median ng kolum\n" + "Tulad ng nakikita natin, ang NaN na halaga ay napalitan ng median ng kolum.\n" ] }, { @@ -2429,11 +2442,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Mahahalagang Punto:\n", - "1. Ang paglalagay ng nawawalang halaga ay dapat gawin kapag kaunti lamang ang datos o mayroong estratehiya para punan ang nawawalang datos.\n", - "2. Maaaring gamitin ang kaalaman sa larangan upang punan ang nawawalang halaga sa pamamagitan ng pagtantya sa mga ito.\n", - "3. Para sa Categorical na datos, kadalasan, ang nawawalang halaga ay pinapalitan ng mode ng kolum.\n", - "4. Para sa numeric na datos, ang nawawalang halaga ay karaniwang pinupunan gamit ang mean (para sa mga normalisadong dataset) o ang median ng mga kolum.\n" + "> Mahahalagang puntos:\n", + "1. Ang paglalagay ng nawawalang halaga ay dapat gawin kapag kaunti lamang ang datos o may estratehiya para punan ang nawawalang datos.\n", + "2. Maaaring gamitin ang kaalaman sa larangan upang punan ang nawawalang halaga sa pamamagitan ng pagtatantiya.\n", + "3. Para sa Categorical na datos, kadalasan, ang nawawalang halaga ay pinapalitan ng mode ng column.\n", + "4. Para sa numeric na datos, ang nawawalang halaga ay karaniwang pinupunan gamit ang mean (para sa mga normalisadong dataset) o median ng mga column.\n" ] }, { @@ -2463,7 +2476,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "Maaari mong **i-forward-fill** ang mga null na halaga, kung saan gagamitin ang huling wastong halaga upang punan ang null:\n" + ] }, { "cell_type": "code", @@ -2503,7 +2518,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Maaari mo ring **back-fill** upang ipalaganap ang susunod na wastong halaga pabalik upang punan ang null:\n" + "Maaari mo ring **mag-back-fill** upang ipalaganap ang susunod na wastong halaga pabalik upang punan ang null:\n" ] }, { @@ -2545,7 +2560,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "Tulad ng maaari mong hulaan, gumagana ito nang pareho sa mga DataFrame, ngunit maaari ka ring magtakda ng isang `axis` kung saan pupunan ang mga null na halaga:\n" + "Tulad ng maaari mong hulaan, ganito rin ang paraan ng paggamit sa DataFrames, ngunit maaari ka ring magtakda ng `axis` kung saan pupunan ang mga null na halaga:\n" ] }, { @@ -2718,7 +2733,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Pansinin na kapag walang nakaraang halaga na magagamit para sa forward-filling, nananatili ang null na halaga.\n" + "Pansinin na kapag walang available na nakaraang halaga para sa forward-filling, nananatili ang null na halaga.\n" ] }, { @@ -2751,7 +2766,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Maaari kang maging malikhain sa paggamit ng `fillna`. Halimbawa, balikan natin ang `example4`, ngunit sa pagkakataong ito, punan natin ang mga nawawalang halaga gamit ang average ng lahat ng mga halaga sa `DataFrame`:\n" + "Maaari kang maging malikhain sa paggamit ng `fillna`. Halimbawa, tingnan natin muli ang `example4`, ngunit sa pagkakataong ito punan natin ang mga nawawalang halaga gamit ang average ng lahat ng mga halaga sa `DataFrame`:\n" ] }, { @@ -2844,7 +2859,7 @@ "source": [ "Pansinin na ang column 3 ay wala pa ring halaga: ang default na direksyon ay punan ang mga halaga nang pa-row.\n", "\n", - "> **Punto:** Maraming paraan upang harapin ang mga nawawalang halaga sa iyong mga dataset. Ang partikular na estratehiya na gagamitin mo (pag-aalis ng mga ito, pagpapalit ng mga ito, o kahit paano mo papalitan ang mga ito) ay dapat nakabatay sa mga detalye ng datos na iyon. Mas magkakaroon ka ng mas mahusay na pag-unawa kung paano harapin ang mga nawawalang halaga habang mas madalas kang humawak at makipag-ugnayan sa mga dataset.\n" + "> **Punto:** Maraming paraan upang harapin ang mga nawawalang halaga sa iyong mga dataset. Ang partikular na estratehiya na gagamitin mo (pag-aalis, pagpapalit, o kung paano mo ito papalitan) ay dapat nakabatay sa mga detalye ng data na iyon. Mas magkakaroon ka ng mas mahusay na pag-unawa kung paano harapin ang mga nawawalang halaga habang mas madalas kang humawak at makipag-ugnayan sa mga dataset.\n" ] }, { @@ -2853,9 +2868,9 @@ "id": "bauDnESIl9FH" }, "source": [ - "### Pag-encode ng Kategoryal na Data\n", + "### Pag-encode ng Categorical Data\n", "\n", - "Ang mga modelo ng machine learning ay gumagana lamang sa mga numero at anumang uri ng numerikong data. Hindi nito kayang tukuyin ang pagkakaiba ng Oo at Hindi, ngunit kaya nitong tukuyin ang pagkakaiba ng 0 at 1. Kaya, pagkatapos punan ang mga nawawalang halaga, kailangan nating i-encode ang kategoryal na data sa isang numerikong anyo upang maunawaan ito ng modelo.\n", + "Ang mga modelo ng machine learning ay gumagana lamang sa mga numero at anumang uri ng numerikong data. Hindi nito kayang tukuyin ang pagkakaiba ng Yes at No, ngunit kaya nitong tukuyin ang pagkakaiba ng 0 at 1. Kaya, pagkatapos punan ang mga nawawalang halaga, kailangan nating i-encode ang categorical data sa isang numerikong anyo upang maunawaan ng modelo.\n", "\n", "Ang pag-encode ay maaaring gawin sa dalawang paraan. Tatalakayin natin ang mga ito sa susunod.\n" ] @@ -2868,7 +2883,7 @@ "source": [ "**PAG-ENCODE NG LABEL**\n", "\n", - "Ang pag-encode ng label ay ang proseso ng pag-convert ng bawat kategorya sa isang numero. Halimbawa, sabihin nating mayroon tayong dataset ng mga pasahero ng eroplano at may isang column na naglalaman ng kanilang klase mula sa mga sumusunod ['business class', 'economy class', 'first class']. Kapag in-encode ang mga label nito, ito ay magiging [0,1,2]. Tingnan natin ang isang halimbawa gamit ang code. Dahil pag-aaralan natin ang `scikit-learn` sa mga susunod na notebook, hindi natin ito gagamitin dito.\n" + "Ang pag-encode ng label ay ang proseso ng pag-convert ng bawat kategorya sa isang numero. Halimbawa, sabihin nating mayroon tayong dataset ng mga pasahero ng eroplano at may isang column na naglalaman ng kanilang klase mula sa mga sumusunod ['business class', 'economy class', 'first class']. Kapag ginawa ang pag-encode ng label dito, ito ay magiging [0,1,2]. Tingnan natin ang isang halimbawa gamit ang code. Dahil matututo tayo ng `scikit-learn` sa mga susunod na notebook, hindi natin ito gagamitin dito.\n" ] }, { @@ -2976,7 +2991,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Upang maisagawa ang label encoding sa unang kolum, kailangan muna nating ilarawan ang isang mapping mula sa bawat klase patungo sa isang numero, bago palitan\n" + "Upang maisagawa ang label encoding sa unang kolum, kailangan muna nating ilarawan ang pagmamapa mula sa bawat klase patungo sa isang numero, bago palitan.\n" ] }, { @@ -3078,9 +3093,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Tulad ng nakikita natin, ang resulta ay tumutugma sa inaasahan natin. Kaya, kailan natin ginagamit ang label encoding? Ginagamit ang label encoding sa isa o pareho sa mga sumusunod na sitwasyon: \n", - "1. Kapag ang bilang ng mga kategorya ay malaki \n", - "2. Kapag ang mga kategorya ay may pagkakasunod-sunod. \n" + "Tulad ng nakikita natin, ang resulta ay tumutugma sa inaasahan natin. Kaya, kailan natin ginagamit ang label encoding? Ang label encoding ay ginagamit sa isa o pareho sa mga sumusunod na kaso:\n", + "1. Kapag ang bilang ng mga kategorya ay marami\n", + "2. Kapag ang mga kategorya ay may pagkakasunod-sunod.\n" ] }, { @@ -3091,7 +3106,7 @@ "source": [ "**ONE HOT ENCODING**\n", "\n", - "Isa pang uri ng encoding ay ang One Hot Encoding. Sa ganitong uri ng encoding, ang bawat kategorya ng isang column ay nagiging hiwalay na column, at ang bawat datapoint ay magkakaroon ng 0 o 1 depende kung kabilang ito sa kategoryang iyon. Kaya, kung mayroong n na magkakaibang kategorya, n na column ang idadagdag sa dataframe.\n", + "Ang isa pang uri ng encoding ay ang One Hot Encoding. Sa ganitong uri ng encoding, ang bawat kategorya ng column ay nagiging hiwalay na column, at bawat datapoint ay magkakaroon ng 0 o 1 batay sa kung naglalaman ito ng kategoryang iyon. Kaya, kung mayroong n iba't ibang kategorya, n na mga column ang idadagdag sa dataframe.\n", "\n", "Halimbawa, kunin natin ang parehong halimbawa ng klase ng eroplano. Ang mga kategorya ay: ['business class', 'economy class', 'first class']. Kaya, kung gagamit tayo ng one hot encoding, ang sumusunod na tatlong column ay idadagdag sa dataset: ['class_business class', 'class_economy class', 'class_first class'].\n" ] @@ -3326,7 +3341,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Ang bawat one-hot encoded na kolum ay naglalaman ng 0 o 1, na nagsasaad kung ang kategoryang iyon ay umiiral para sa datapoint na iyon.\n" + "Ang bawat one hot encoded na column ay naglalaman ng 0 o 1, na tumutukoy kung ang kategoryang iyon ay umiiral para sa datapoint na iyon.\n" ] }, { @@ -3335,7 +3350,7 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "Kailan ginagamit ang one hot encoding? Ginagamit ang one hot encoding sa isa o pareho sa mga sumusunod na sitwasyon:\n", + "Kailan ginagamit ang one hot encoding? Ginagamit ang one hot encoding sa isa o pareho sa mga sumusunod na kaso:\n", "\n", "1. Kapag ang bilang ng mga kategorya at ang laki ng dataset ay mas maliit.\n", "2. Kapag ang mga kategorya ay walang partikular na pagkakasunod-sunod.\n" @@ -3348,7 +3363,7 @@ }, "source": [ "> Mahahalagang Punto:\n", - "1. Ang encoding ay ginagawa upang ma-convert ang hindi numerikong datos sa numerikong datos.\n", + "1. Ang encoding ay ginagawa upang i-convert ang hindi numerikong datos sa numerikong datos.\n", "2. May dalawang uri ng encoding: Label encoding at One Hot encoding, na maaaring isagawa batay sa pangangailangan ng dataset.\n" ] }, @@ -3360,7 +3375,7 @@ "source": [ "## Pag-aalis ng dobleng datos\n", "\n", - "> **Layunin ng pag-aaral:** Sa pagtatapos ng bahaging ito, dapat kang maging komportable sa pag-identipika at pag-aalis ng mga dobleng halaga mula sa mga DataFrame.\n", + "> **Layunin ng pag-aaral:** Sa pagtatapos ng bahaging ito, dapat kang maging komportable sa pagtukoy at pag-aalis ng mga dobleng halaga mula sa mga DataFrame.\n", "\n", "Bukod sa nawawalang datos, madalas kang makakakita ng dobleng datos sa mga aktwal na dataset. Sa kabutihang-palad, nagbibigay ang pandas ng madaling paraan para matukoy at maalis ang mga dobleng entry.\n" ] @@ -3371,9 +3386,9 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### Pagtukoy ng mga duplicate: `duplicated`\n", + "### Pagkilala sa mga duplicate: `duplicated`\n", "\n", - "Madali mong matutukoy ang mga duplicate na halaga gamit ang `duplicated` na method sa pandas, na nagbabalik ng Boolean mask na nagpapakita kung ang isang entry sa isang `DataFrame` ay duplicate ng naunang entry. Gumawa tayo ng isa pang halimbawa ng `DataFrame` upang makita ito sa aksyon.\n" + "Madali mong matutukoy ang mga duplicate na halaga gamit ang `duplicated` na method sa pandas, na nagbabalik ng Boolean mask na nagpapakita kung ang isang entry sa `DataFrame` ay duplicate ng naunang isa. Gumawa tayo ng isa pang halimbawa ng `DataFrame` upang makita ito sa aksyon.\n" ] }, { @@ -3502,8 +3517,8 @@ "id": "0eDRJD4SgRsK" }, "source": [ - "### Pagtanggal ng mga duplicate: `drop_duplicates`\n", - "Ang `drop_duplicates` ay simpleng nagbabalik ng kopya ng data kung saan lahat ng mga halagang `duplicated` ay `False`:\n" + "### Pag-aalis ng mga duplicate: `drop_duplicates`\n", + "Ang `drop_duplicates` ay nagbabalik lamang ng kopya ng data kung saan lahat ng mga halaga na `duplicated` ay `False`:\n" ] }, { @@ -3586,7 +3601,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Parehong `duplicated` at `drop_duplicates` ay default na isaalang-alang ang lahat ng mga column ngunit maaari mong tukuyin na suriin lamang nila ang isang subset ng mga column sa iyong `DataFrame`:\n" + "Parehong `duplicated` at `drop_duplicates` ay default na isinasaalang-alang ang lahat ng mga column ngunit maaari mong tukuyin na suriin lamang nila ang isang subset ng mga column sa iyong `DataFrame`:\n" ] }, { @@ -3662,13 +3677,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Punto:** Ang pagtanggal ng dobleng datos ay mahalagang bahagi ng halos bawat proyekto sa agham ng datos. Ang dobleng datos ay maaaring magbago ng resulta ng iyong mga pagsusuri at magbigay sa iyo ng hindi tamang resulta!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Mga Pag-check ng Kalidad ng Data sa Totoong Mundo\n", + "\n", + "> **Layunin ng pag-aaral:** Sa pagtatapos ng seksyong ito, dapat kang maging komportable sa pagtukoy at pagwawasto ng mga karaniwang isyu sa kalidad ng data sa totoong mundo, kabilang ang hindi pare-parehong mga halaga ng kategorya, abnormal na mga numerong halaga (mga outlier), at mga duplicate na entity na may mga pagkakaiba.\n", + "\n", + "Bagama't ang mga nawawalang halaga at eksaktong mga duplicate ay karaniwang mga isyu, ang mga dataset sa totoong mundo ay madalas na naglalaman ng mas banayad na mga problema:\n", + "\n", + "1. **Hindi pare-parehong mga halaga ng kategorya**: Ang parehong kategorya ay may iba't ibang baybay (hal., \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Abnormal na mga numerong halaga**: Mga matinding outlier na nagpapahiwatig ng mga error sa pagpasok ng data (hal., edad = 999)\n", + "3. **Halos magkaparehong mga hilera**: Mga rekord na kumakatawan sa parehong entity na may bahagyang pagkakaiba\n", + "\n", + "Tuklasin natin ang mga teknik upang matukoy at maayos ang mga isyung ito.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Paglikha ng Halimbawang \"Maruming\" Dataset\n", + "\n", + "Una, gumawa tayo ng isang halimbawang dataset na naglalaman ng mga uri ng problema na karaniwang nararanasan natin sa totoong datos:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Pagtukoy sa Hindi Pare-parehong Halaga ng Kategorya\n", + "\n", + "Pansinin na ang kolum na `country` ay may iba't ibang representasyon para sa parehong mga bansa. Tukuyin natin ang mga hindi pagkakapareho na ito:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Pag-standardize ng Mga Halagang Kategorya\n", + "\n", + "Maaari tayong gumawa ng mapping upang i-standardize ang mga halagang ito. Isang simpleng paraan ay ang pag-convert sa lowercase at paggawa ng mapping dictionary:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternatibo: Paggamit ng Fuzzy Matching**\n", + "\n", + "Para sa mas komplikadong mga kaso, maaari nating gamitin ang fuzzy string matching gamit ang `rapidfuzz` library upang awtomatikong matukoy ang magkatulad na mga string:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Pagtukoy sa Hindi Karaniwang Halaga ng Numero (Outliers)\n", + "\n", + "Sa pagtingin sa kolum na `age`, may ilang kahina-hinalang halaga tulad ng 199 at -5. Gamitin natin ang mga pamamaraang estadistikal upang matukoy ang mga outlier na ito.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Paggamit ng IQR (Interquartile Range) na Paraan\n", + "\n", + "Ang IQR na paraan ay isang matibay na teknik sa estadistika para sa pagtukoy ng mga outlier na hindi gaanong sensitibo sa mga matitinding halaga:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Paggamit ng Z-Score Method\n", + "\n", + "Ang Z-score method ay tumutukoy sa mga outlier batay sa mga standard deviation mula sa mean:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Pag-aasikaso ng Mga Outlier\n", + "\n", + "Kapag natukoy, ang mga outlier ay maaaring asikasuhin sa iba't ibang paraan:\n", + "1. **Tanggalin**: Alisin ang mga row na may outlier (kung ito ay mga pagkakamali)\n", + "2. **Limitahan**: Palitan ng mga hangganang halaga\n", + "3. **Palitan ng NaN**: Ituring bilang nawawalang datos at gumamit ng mga teknik sa imputation\n", + "4. **Panatilihin**: Kung ito ay lehitimong matitinding halaga\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Pagtukoy sa Halos Magkakaparehong Rows\n", + "\n", + "Pansinin na ang ating dataset ay may maraming entry para kay \"John Smith\" na may bahagyang magkakaibang mga halaga. Tukuyin natin ang mga posibleng duplicate batay sa pagkakahawig ng pangalan.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Paghahanap ng Malapit na Duplicates gamit ang Fuzzy Matching\n", + "\n", + "Para sa mas sopistikadong pagtuklas ng duplicate, maaari nating gamitin ang fuzzy matching upang mahanap ang magkatulad na mga pangalan:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Paghawak ng Mga Doble\n", + "\n", + "Kapag natukoy na, kailangan mong magdesisyon kung paano hahawakan ang mga doble:\n", + "1. **Panatilihin ang unang paglitaw**: Gamitin ang `drop_duplicates(keep='first')`\n", + "2. **Panatilihin ang huling paglitaw**: Gamitin ang `drop_duplicates(keep='last')`\n", + "3. **Pagsama-samahin ang impormasyon**: Pagsamahin ang impormasyon mula sa mga dobleng hanay\n", + "4. **Manwal na pagsusuri**: I-flag para sa pagsusuri ng tao\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Buod: Kumpletong Pipeline para sa Paglilinis ng Data\n", + "\n", + "Pagsamahin natin ang lahat upang makabuo ng isang komprehensibong pipeline para sa paglilinis ng data:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Hamon na Ehersisyo\n", + "\n", + "Ngayon ay ikaw naman! Narito ang isang bagong hanay ng datos na may maraming isyu sa kalidad. Kaya mo bang:\n", + "\n", + "1. Tukuyin ang lahat ng isyu sa hanay na ito\n", + "2. Sumulat ng code upang linisin ang bawat isyu\n", + "3. Idagdag ang nalinis na hanay sa dataset\n", + "\n", + "Narito ang problemadong datos:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Mahahalagang Punto\n", + "\n", + "1. **Hindi pare-parehong mga kategorya** ay karaniwang makikita sa totoong datos. Laging suriin ang mga natatanging halaga at gawing pare-pareho gamit ang mappings o fuzzy matching.\n", + "\n", + "2. **Mga outlier** ay maaaring malaki ang epekto sa iyong pagsusuri. Gumamit ng kaalaman sa larangan kasabay ng mga pamamaraang estadistikal (IQR, Z-score) upang matukoy ang mga ito.\n", + "\n", + "3. **Halos magkapareho na mga duplicate** ay mas mahirap tukuyin kaysa sa eksaktong mga duplicate. Isaalang-alang ang paggamit ng fuzzy matching at pag-normalize ng datos (pagbababa ng case, pagtanggal ng whitespace) upang mahanap ang mga ito.\n", + "\n", + "4. **Ang paglilinis ng datos ay paulit-ulit na proseso**. Maaaring kailanganin mong gumamit ng iba't ibang teknika at suriin ang mga resulta bago tapusin ang iyong nalinis na dataset.\n", + "\n", + "5. **I-dokumento ang iyong mga desisyon**. Itala ang mga hakbang sa paglilinis na iyong ginawa at ang dahilan nito, dahil mahalaga ito para sa reproducibility at transparency.\n", + "\n", + "> **Pinakamahusay na Praktis:** Laging magtago ng kopya ng iyong orihinal na \"maruming\" datos. Huwag kailanman i-overwrite ang iyong source data files - gumawa ng mga nalinis na bersyon na may malinaw na naming conventions tulad ng `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Paunawa**: \nAng dokumentong ito ay isinalin gamit ang AI translation service na [Co-op Translator](https://github.com/Azure/co-op-translator). Bagama't sinisikap naming maging tumpak, pakitandaan na ang mga awtomatikong pagsasalin ay maaaring maglaman ng mga pagkakamali o hindi pagkakatugma. Ang orihinal na dokumento sa orihinal nitong wika ang dapat ituring na opisyal na sanggunian. Para sa mahalagang impormasyon, inirerekomenda ang propesyonal na pagsasalin ng tao. Hindi kami mananagot sa anumang hindi pagkakaunawaan o maling interpretasyon na maaaring magmula sa paggamit ng pagsasaling ito.\n" + "\n---\n\n**Paunawa**: \nAng dokumentong ito ay isinalin gamit ang AI translation service na [Co-op Translator](https://github.com/Azure/co-op-translator). Bagama't sinisikap naming maging tumpak, mangyaring tandaan na ang mga awtomatikong pagsasalin ay maaaring maglaman ng mga pagkakamali o hindi pagkakatugma. Ang orihinal na dokumento sa kanyang katutubong wika ang dapat ituring na opisyal na pinagmulan. Para sa mahalagang impormasyon, inirerekomenda ang propesyonal na pagsasalin ng tao. Hindi kami mananagot sa anumang hindi pagkakaunawaan o maling interpretasyon na dulot ng paggamit ng pagsasaling ito.\n" ] } ], @@ -3696,8 +4229,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T08:09:20+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:45:52+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "tl" } diff --git a/translations/tr/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/tr/2-Working-With-Data/08-data-preparation/notebook.ipynb index e7cc5750..84b61e0c 100644 --- a/translations/tr/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/tr/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -10,13 +10,13 @@ "\n", "[Orijinal Notebook kaynağı *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", - "## `DataFrame` Bilgilerini Keşfetmek\n", + "## `DataFrame` Bilgilerini Keşfetme\n", "\n", - "> **Öğrenme hedefi:** Bu alt bölümün sonunda, pandas DataFrame'lerde saklanan veriler hakkında genel bilgi bulma konusunda rahat olmalısınız.\n", + "> **Öğrenme hedefi:** Bu alt bölümün sonunda, pandas DataFrame'lerinde saklanan veriler hakkında genel bilgi bulma konusunda rahat olmalısınız.\n", "\n", - "Verilerinizi pandas'a yüklediğinizde, büyük olasılıkla bir `DataFrame` içinde olacaktır. Ancak, `DataFrame`'inizdeki veri seti 60.000 satır ve 400 sütun içeriyorsa, neyle çalıştığınızı anlamaya nereden başlarsınız? Neyse ki, pandas, bir `DataFrame` hakkında genel bilgileri hızlıca görmek ve ilk birkaç ile son birkaç satırı incelemek için kullanışlı araçlar sunar.\n", + "Verilerinizi pandas'a yüklediğinizde, büyük olasılıkla bir `DataFrame` içinde olacaktır. Ancak, `DataFrame`'inizdeki veri seti 60.000 satır ve 400 sütun içeriyorsa, neyle çalıştığınızı nasıl anlamaya başlarsınız? Neyse ki, pandas, bir `DataFrame` hakkında genel bilgileri hızlıca görmek için birkaç kullanışlı araç sunar; bunlar, ilk birkaç ve son birkaç satırı görmenin yanı sıra genel bilgileri içerir.\n", "\n", - "Bu işlevselliği keşfetmek için Python scikit-learn kütüphanesini içe aktaracağız ve her veri bilimcisinin yüzlerce kez gördüğü ikonik bir veri setini kullanacağız: İngiliz biyolog Ronald Fisher'ın 1936 tarihli \"Taksonomik problemler için çoklu ölçümlerin kullanımı\" adlı makalesinde kullandığı *Iris* veri seti:\n" + "Bu işlevselliği keşfetmek için Python scikit-learn kütüphanesini içe aktaracağız ve her veri bilimcisinin yüzlerce kez gördüğü ikonik bir veri setini kullanacağız: İngiliz biyolog Ronald Fisher'ın 1936 tarihli \"Taksonomik problemler için çoklu ölçümlerin kullanımı\" adlı makalesinde kullanılan *Iris* veri seti:\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "`iris_df` değişkenine Iris Veri Seti'ni yükledik. Verilere dalmadan önce, elimizde kaç veri noktası olduğunu ve veri setinin genel boyutunu bilmek faydalı olacaktır. Çalıştığımız veri hacmini görmek yararlıdır.\n" + "`iris_df` değişkenine Iris Veri Seti'ni yükledik. Verilere dalmadan önce, elimizdeki veri noktalarının sayısını ve veri setinin genel boyutunu bilmek faydalı olacaktır. Çalıştığımız veri hacmini görmek yararlıdır.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Yani, elimizde 150 satır ve 4 sütundan oluşan bir veri var. Her bir satır bir veri noktasını temsil eder ve her bir sütun, veri çerçevesiyle ilişkili tek bir özelliği ifade eder. Temelde, her biri 4 özelliğe sahip 150 veri noktası bulunmaktadır.\n", + "Yani, 150 satır ve 4 sütundan oluşan bir veriyle çalışıyoruz. Her bir satır bir veri noktasını temsil ediyor ve her sütun veri çerçevesiyle ilişkili tek bir özelliği ifade ediyor. Temelde, her biri 4 özellik içeren 150 veri noktası var.\n", "\n", - "Buradaki `shape`, bir fonksiyon değil, veri çerçevesinin bir özelliğidir; bu yüzden bir çift parantezle bitmez.\n" + "Buradaki `shape`, veri çerçevesinin bir özelliğidir ve bir fonksiyon olmadığı için sonunda parantez bulunmaz.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Şimdi 4 veri sütununa geçelim. Her biri tam olarak neyi temsil ediyor? `columns` özelliği, dataframe'deki sütunların adlarını bize verecektir.\n" + "Şimdi veri setindeki 4 sütuna geçelim. Her biri tam olarak neyi temsil ediyor? `columns` özelliği, veri çerçevesindeki sütunların adlarını bize verecektir.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Gördüğümüz gibi, dört (4) sütun var. `columns` özelliği bize sütunların adını söyler ve temelde başka bir şey söylemez. Bu özellik, bir veri kümesinin içerdiği özellikleri tanımlamak istediğimizde önem kazanır.\n" + "Gördüğümüz gibi, dört(4) sütun var. `columns` özelliği bize sütunların adını söyler ve temelde başka bir şey söylemez. Bu özellik, bir veri setinin içerdiği özellikleri tanımlamak istediğimizde önem kazanır.\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "Veri miktarı (`shape` özelliği tarafından verilen) ve özelliklerin veya sütunların adları (`columns` özelliği tarafından verilen) veri seti hakkında bize bir şeyler anlatır. Şimdi, veri setine daha derinlemesine bakmak isteyeceğiz. `DataFrame.info()` fonksiyonu bu konuda oldukça kullanışlıdır.\n" + "Veri miktarı (`shape` özelliği ile belirtilir) ve özelliklerin veya sütunların adları (`columns` özelliği ile belirtilir) veri seti hakkında bize bazı bilgiler verir. Şimdi, veri setine daha derinlemesine bakmak isteyeceğiz. `DataFrame.info()` fonksiyonu bu konuda oldukça kullanışlıdır.\n" ] }, { @@ -181,8 +181,8 @@ }, "source": [ "Buradan birkaç gözlem yapabiliriz:\n", - "1. Her sütunun Veri Tipi: Bu veri setinde, tüm veriler 64-bit kayan nokta sayıları olarak saklanmaktadır.\n", - "2. Null Olmayan Değerlerin Sayısı: Null değerlerle başa çıkmak, veri hazırlığında önemli bir adımdır. Bu konu daha sonra not defterinde ele alınacaktır.\n" + "1. Her sütunun Veri Tipi: Bu veri setinde, tüm veriler 64-bit kayan nokta sayıları olarak saklanmıştır.\n", + "2. Null Olmayan değerlerin sayısı: Null değerlerle başa çıkmak, veri hazırlığında önemli bir adımdır. Bu konu daha sonra not defterinde ele alınacaktır.\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "Diyelim ki veri setimizde çok fazla sayısal veri var. Ortalama, medyan, çeyrekler gibi tek değişkenli istatistiksel hesaplamalar, her bir sütun üzerinde ayrı ayrı yapılabilir. `DataFrame.describe()` fonksiyonu, bir veri setinin sayısal sütunları hakkında istatistiksel bir özet sağlar.\n" + "Diyelim ki veri setimizde çok fazla sayısal veri var. Ortalama, medyan, çeyrekler gibi tek değişkenli istatistiksel hesaplamalar, her bir sütun üzerinde ayrı ayrı yapılabilir. `DataFrame.describe()` fonksiyonu, bir veri setinin sayısal sütunları hakkında istatistiksel bir özet sunar.\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "Yukarıdaki çıktı, her sütunun toplam veri noktası sayısını, ortalamasını, standart sapmasını, minimum değerini, alt çeyreğini (%25), medyanını (%50), üst çeyreğini (%75) ve maksimum değerini göstermektedir.\n" + "Yukarıdaki çıktı, her sütunun toplam veri noktası sayısını, ortalamayı, standart sapmayı, minimum değeri, alt çeyreği (%25), medyanı (%50), üst çeyreği (%75) ve maksimum değerini göstermektedir.\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "Yukarıdaki tüm fonksiyonlar ve özelliklerle, veri kümesine genel bir bakış elde ettik. Kaç veri noktası olduğunu, kaç özelliğin bulunduğunu, her bir özelliğin veri tipini ve her bir özellik için kaç tane boş olmayan değer olduğunu öğrendik.\n", + "Yukarıdaki tüm fonksiyonlar ve özelliklerle, veri setine genel bir bakış elde ettik. Kaç veri noktası olduğunu, kaç özellik bulunduğunu, her bir özelliğin veri tipini ve her bir özellik için kaç tane null olmayan değer olduğunu biliyoruz.\n", "\n", - "Şimdi verinin kendisine bakma zamanı. `DataFrame`imizin ilk birkaç satırının (ilk birkaç veri noktasının) nasıl göründüğüne bir göz atalım:\n" + "Şimdi verinin kendisine bakma zamanı. `DataFrame`imizin ilk birkaç satırına (ilk birkaç veri noktasına) bakalım:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Çıktıda, veri kümesinin beş (5) girdisini görebiliyoruz. Sol taraftaki indekse baktığımızda, bunların ilk beş satır olduğunu anlıyoruz.\n" + "Buradaki çıktıda, veri setinin beş (5) girişini görebiliyoruz. Sol taraftaki indekse bakarsak, bunların ilk beş satır olduğunu anlıyoruz.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Alıştırma:\n", "\n", - "Yukarıdaki örnekten açıkça görülüyor ki, varsayılan olarak `DataFrame.head`, bir `DataFrame`'in ilk beş satırını döndürür. Aşağıdaki kod hücresinde, beşten fazla satırı görüntülemenin bir yolunu bulabilir misiniz?\n" + "Yukarıda verilen örnekten açıkça görülüyor ki, varsayılan olarak `DataFrame.head`, bir `DataFrame`'in ilk beş satırını döndürür. Aşağıdaki kod hücresinde, beşten fazla satırı görüntülemenin bir yolunu bulabilir misiniz?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Verilere bakmanın bir başka yolu, başlangıç yerine sondan bakmaktır. `DataFrame.head`'in tersine, `DataFrame.tail` bir `DataFrame`'in son beş satırını döndürür:\n" + "Verilere bakmanın başka bir yolu, başlangıç yerine sondan olabilir. `DataFrame.head`'in tersine, `DataFrame.tail` bir `DataFrame`'in son beş satırını döndürür:\n" ] }, { @@ -586,7 +586,7 @@ "\n", "Yukarıda kod örnekleriyle gösterilen tüm fonksiyonlar ve özellikler, veriye bir bakış ve hissiyat kazanmamıza yardımcı olur.\n", "\n", - "> **Çıkarım:** Bir DataFrame'deki bilgilere ait meta veriye veya bir DataFrame'in ilk ve son birkaç değerine sadece bakarak, üzerinde çalıştığınız verinin boyutu, şekli ve içeriği hakkında hemen bir fikir edinebilirsiniz.\n" + "> **Çıkarım:** Bir DataFrame'deki bilgilerin meta verilerine veya ilk ve son birkaç değerine bakarak, üzerinde çalıştığınız verinin boyutu, şekli ve içeriği hakkında hemen bir fikir edinebilirsiniz.\n" ] }, { @@ -598,15 +598,15 @@ "### Eksik Veri\n", "Eksik veri konusuna dalalım. Eksik veri, bazı sütunlarda hiçbir değer saklanmadığında meydana gelir.\n", "\n", - "Bir örnek alalım: diyelim ki bir kişi kilosu konusunda hassas ve bir ankette kilo alanını doldurmuyor. O zaman, bu kişinin kilo değeri eksik olacaktır.\n", + "Bir örnek alalım: Diyelim ki biri kilosu konusunda hassas ve bir ankette kilo alanını doldurmuyor. O zaman, bu kişinin kilo değeri eksik olacaktır.\n", "\n", "Gerçek dünya veri setlerinde, eksik değerler çoğu zaman ortaya çıkar.\n", "\n", - "**Pandas Eksik Veriyi Nasıl Ele Alır**\n", + "**Pandas Eksik Verileri Nasıl Ele Alır**\n", "\n", - "Pandas eksik değerleri iki şekilde ele alır. İlk yöntem, önceki bölümlerde gördüğünüz `NaN`, yani Not a Number'dır. Bu aslında IEEE kayan nokta spesifikasyonunun bir parçası olan özel bir değerdir ve yalnızca eksik kayan nokta değerlerini belirtmek için kullanılır.\n", + "Pandas eksik değerleri iki şekilde ele alır. İlkini önceki bölümlerde görmüştünüz: `NaN`, yani Not a Number (Sayı Değil). Bu aslında IEEE kayan nokta spesifikasyonunun bir parçası olan özel bir değerdir ve yalnızca eksik kayan nokta değerlerini belirtmek için kullanılır.\n", "\n", - "Kayan nokta dışındaki eksik değerler için pandas, Python `None` nesnesini kullanır. İki farklı türde eksik değerle karşılaşmanın kafa karıştırıcı görünebileceği doğru olsa da, bu tasarım seçiminin sağlam programatik nedenleri vardır ve pratikte bu yaklaşım, pandas'ın çoğu durumda iyi bir denge sunmasını sağlar. Bununla birlikte, hem `None` hem de `NaN` ile ilgili olarak nasıl kullanılabilecekleri konusunda dikkat edilmesi gereken sınırlamalar taşır.\n" + "Kayan nokta dışındaki eksik değerler için pandas, Python `None` nesnesini kullanır. İki farklı türde eksik değerle karşılaşmanın kafa karıştırıcı görünebileceği düşünülse de, bu tasarım seçiminin sağlam programatik nedenleri vardır ve pratikte bu yaklaşım, pandas'ın çoğu durumda iyi bir denge sunmasını sağlar. Bununla birlikte, hem `None` hem de `NaN` ile ilgili olarak nasıl kullanılabilecekleri konusunda dikkat edilmesi gereken sınırlamalar taşır.\n" ] }, { @@ -615,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: float olmayan eksik veriler\n", - "`None` Python'dan geldiği için, veri türü `'object'` olmayan NumPy ve pandas dizilerinde kullanılamaz. Unutmayın, NumPy dizileri (ve pandas'taki veri yapıları) yalnızca tek bir tür veri içerebilir. Bu, onları büyük ölçekli veri ve hesaplama işleri için son derece güçlü kılar, ancak aynı zamanda esnekliklerini sınırlar. Bu tür diziler, dizideki her şeyi kapsayacak olan \"en düşük ortak payda\" veri türüne yükseltilmek zorundadır. Dizide `None` bulunduğunda, Python nesneleriyle çalışıyorsunuz demektir.\n", + "### `None`: float olmayan eksik veri\n", + "Python'dan gelen `None`, veri türü `'object'` olmayan NumPy ve pandas dizilerinde kullanılamaz. Unutmayın, NumPy dizileri (ve pandas'taki veri yapıları) yalnızca tek bir tür veri içerebilir. Bu, büyük ölçekli veri ve hesaplama çalışmaları için onlara muazzam bir güç sağlar, ancak aynı zamanda esnekliklerini sınırlar. Bu tür diziler, dizideki her şeyi kapsayacak olan \"en düşük ortak payda\" veri türüne yükseltilmek zorundadır. Dizide `None` olduğunda, Python nesneleriyle çalışıyorsunuz demektir.\n", "\n", - "Bunu uygulamada görmek için, aşağıdaki örnek diziye bir göz atın (dizinin `dtype` değerine dikkat edin):\n" + "Bunu uygulamada görmek için aşağıdaki örnek diziye bir göz atın (dizinin `dtype` değerine dikkat edin):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Yükseltilmiş veri türlerinin gerçekliği iki yan etkiyi beraberinde getirir. Birincisi, işlemler derlenmiş NumPy kodu yerine yorumlanmış Python kodu seviyesinde gerçekleştirilir. Temelde bu, içinde `None` bulunan `Series` veya `DataFrame`lerle yapılan işlemlerin daha yavaş olacağı anlamına gelir. Bu performans düşüşünü muhtemelen fark etmezsiniz, ancak büyük veri kümelerinde sorun haline gelebilir.\n", + "Yukarıya dönüştürülen veri türlerinin gerçekliği iki yan etkiyi beraberinde getirir. Birincisi, işlemler derlenmiş NumPy kodu yerine yorumlanmış Python kodu seviyesinde gerçekleştirilir. Temelde bu, içinde `None` bulunan `Series` veya `DataFrame`lerle yapılan işlemlerin daha yavaş olacağı anlamına gelir. Bu performans düşüşünü muhtemelen fark etmezsiniz, ancak büyük veri kümelerinde sorun haline gelebilir.\n", "\n", - "İkinci yan etki birincisinden kaynaklanır. Çünkü `None`, `Series` veya `DataFrame`leri temel Python dünyasına geri çeker, içinde ``None`` değeri bulunan dizilerde NumPy/pandas toplama işlemleri, örneğin `sum()` veya `min()`, genellikle bir hata üretir:\n" + "İkinci yan etki birincisinden kaynaklanır. Çünkü `None`, `Series` veya `DataFrame`leri temel Python dünyasına geri çeker, içinde ``None`` değeri bulunan dizilerde NumPy/pandas toplama işlemleri (örneğin `sum()` veya `min()`) genellikle bir hata üretir:\n" ] }, { @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**Ana fikir**: Tamsayılar ile `None` değerleri arasındaki toplama (ve diğer işlemler) tanımsızdır, bu da bunları içeren veri setleriyle yapabileceklerinizi sınırlayabilir.\n" + "**Ana fikir**: Tamsayılar ile `None` değerleri arasındaki toplama (ve diğer işlemler) tanımsızdır, bu da bu tür değerler içeren veri kümeleriyle yapabileceklerinizi sınırlayabilir.\n" ] }, { @@ -709,7 +709,7 @@ "source": [ "### `NaN`: eksik float değerler\n", "\n", - "`None`'ın aksine, NumPy (ve dolayısıyla pandas), hızlı, vektörleştirilmiş işlemleri ve ufunc'ları için `NaN`'i destekler. Kötü haber şu ki, `NaN` üzerinde yapılan herhangi bir aritmetik işlem her zaman `NaN` sonucunu verir. Örneğin:\n" + "`None`'dan farklı olarak, NumPy (dolayısıyla pandas) hızlı, vektörleştirilmiş işlemleri ve ufunc'ları için `NaN`'ı destekler. Kötü haber şu ki, `NaN` üzerinde yapılan herhangi bir aritmetik işlem her zaman `NaN` ile sonuçlanır. Örneğin:\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "İyi haber: `NaN` içeren dizilerde çalışan toplamalar hata vermez. Kötü haber: sonuçlar her zaman kullanışlı değildir:\n" + "İyi haber: `NaN` içeren dizilerde çalışan toplama işlemleri hata vermiyor. Kötü haber: sonuçlar her zaman kullanışlı değil:\n" ] }, { @@ -831,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "Unutmayın: `NaN` yalnızca eksik kayan nokta değerleri içindir; tamsayılar, dizeler veya Boolean'lar için `NaN` eşdeğeri yoktur.\n" + "Unutmayın: `NaN` yalnızca eksik kayan nokta değerleri içindir; tamsayılar, dizeler veya Boole değerleri için `NaN` eşdeğeri yoktur.\n" ] }, { @@ -840,9 +840,9 @@ "id": "kj6EKdsAgRsA" }, "source": [ - "### `NaN` ve `None`: pandas'ta boş değerler\n", + "### `NaN` ve `None`: pandas'ta null değerler\n", "\n", - "`NaN` ve `None` biraz farklı davranabilse de, pandas bunları birbirinin yerine kullanılabilir şekilde işlemek üzere tasarlanmıştır. Ne demek istediğimizi görmek için bir dizi (`Series`) tam sayı düşünün:\n" + "`NaN` ve `None` biraz farklı davranabilse de, pandas bunları birbirinin yerine kullanılabilir şekilde işlemeye uygun olarak tasarlanmıştır. Ne demek istediğimizi görmek için, bir tam sayı `Series`'ini düşünün:\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Veri türlerini aynı hale getirmek için `Series` ve `DataFrame`lerde yukarıya doğru dönüştürme işlemi sırasında, pandas eksik değerleri `None` ve `NaN` arasında kolayca değiştirebilir. Bu tasarım özelliği nedeniyle, pandas'ta `None` ve `NaN`'i \"null\"un iki farklı çeşidi olarak düşünmek faydalı olabilir. Aslında, pandas'ta eksik değerlerle başa çıkmak için kullanacağınız bazı temel yöntemler, bu fikri isimlerinde yansıtır:\n", + "Pandas'da `Series` ve `DataFrame`lerde veri türlerini aynı hale getirmek için veri türlerini yükseltme işlemi sırasında, eksik değerler arasında `None` ve `NaN` geçişi yapılabilir. Bu tasarım özelliği nedeniyle, pandas'ta `None` ve `NaN`'ı \"null\"ın iki farklı çeşidi olarak düşünmek faydalı olabilir. Nitekim, pandas'ta eksik değerlerle başa çıkmak için kullanacağınız bazı temel yöntemler bu fikri isimlerinde yansıtır:\n", "\n", "- `isnull()`: Eksik değerleri gösteren bir Boolean maskesi oluşturur\n", - "- `notnull()`: `isnull()` yönteminin tam tersi\n", + "- `notnull()`: `isnull()`'un tersi\n", "- `dropna()`: Verinin filtrelenmiş bir versiyonunu döndürür\n", "- `fillna()`: Eksik değerlerin doldurulduğu veya tahmin edildiği bir veri kopyası döndürür\n", "\n", - "Bu yöntemleri öğrenmek ve rahatça kullanabilmek oldukça önemlidir, bu yüzden her birini biraz daha detaylı inceleyelim.\n" + "Bu yöntemleri öğrenmek ve rahatça kullanabilmek oldukça önemlidir, bu yüzden her birini detaylı bir şekilde inceleyelim.\n" ] }, { @@ -925,7 +925,7 @@ "### Null değerlerini tespit etme\n", "\n", "Eksik değerlerin önemini anladıktan sonra, onlarla başa çıkmadan önce veri setimizdeki eksik değerleri tespit etmemiz gerekiyor. \n", - "Hem `isnull()` hem de `notnull()` null verileri tespit etmek için temel yöntemlerinizdir. Her ikisi de verileriniz üzerinde Boolean maskeleri döndürür.\n" + "Hem `isnull()` hem de `notnull()` null verileri tespit etmek için kullanılan temel yöntemlerdir. Her ikisi de verileriniz üzerinde Boolean maskeleri döndürür.\n" ] }, { @@ -978,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Çıktıya yakından bakın. Sizi şaşırtan bir şey var mı? `0` aritmetik olarak bir null değeri olsa da, yine de oldukça geçerli bir tam sayı ve pandas bunu böyle kabul eder. `''` ise biraz daha ince bir durum. Bölüm 1'de boş bir string değeri temsil etmek için kullandığımız halde, pandas açısından bir null temsili değil, bir string nesnesidir.\n", + "Çıktıya dikkatlice bakın. Sizi şaşırtan bir şey var mı? `0` aritmetik olarak bir null değeri olsa da, yine de gayet geçerli bir tam sayı ve pandas bunu bu şekilde ele alır. `''` ise biraz daha ince bir durum. Bölüm 1'de boş bir dize değerini temsil etmek için kullandığımız halde, pandas açısından null bir temsil değil, bir dize nesnesidir.\n", "\n", "Şimdi bunu tersine çevirelim ve bu yöntemleri pratikte kullanacağınız şekilde uygulayalım. Boolean maskeleri doğrudan bir ``Series`` veya ``DataFrame`` indeksi olarak kullanabilirsiniz, bu da izole edilmiş eksik (veya mevcut) değerlerle çalışmaya çalışırken faydalı olabilir.\n", "\n", - "Eğer eksik değerlerin toplam sayısını öğrenmek istiyorsak, `isnull()` metodunun ürettiği mask üzerinde bir toplam işlemi yapmamız yeterlidir.\n" + "Eksik değerlerin toplam sayısını öğrenmek istiyorsak, `isnull()` yöntemi tarafından üretilen maskenin üzerinde bir toplam işlemi yapmamız yeterlidir.\n" ] }, { @@ -1051,18 +1051,18 @@ "source": [ "### Eksik Verilerle Başa Çıkma\n", "\n", - "> **Öğrenme hedefi:** Bu alt bölümün sonunda, DataFrame'lerdeki boş değerleri ne zaman ve nasıl değiştireceğinizi veya kaldıracağınızı öğrenmiş olmalısınız.\n", + "> **Öğrenme hedefi:** Bu alt bölümün sonunda, DataFrame'lerdeki null değerleri nasıl ve ne zaman değiştireceğinizi veya kaldıracağınızı öğrenmiş olmalısınız.\n", "\n", "Makine Öğrenimi modelleri eksik verilerle doğrudan çalışamaz. Bu nedenle, verileri modele göndermeden önce bu eksik değerlerle ilgilenmemiz gerekir.\n", "\n", - "Eksik verilerin nasıl ele alındığı, ince dengelemeler içerir ve nihai analiziniz ile gerçek dünya sonuçlarınızı etkileyebilir.\n", + "Eksik verilerin nasıl ele alındığı, ince dengeler taşır, nihai analiziniz ve gerçek dünya sonuçlarınızı etkileyebilir.\n", "\n", "Eksik verilerle başa çıkmanın temel olarak iki yolu vardır:\n", "\n", - "1. Eksik değeri içeren satırı kaldırmak \n", + "1. Eksik değeri içeren satırı silmek \n", "2. Eksik değeri başka bir değerle değiştirmek \n", "\n", - "Bu iki yöntemi ve bunların avantajları ile dezavantajlarını ayrıntılı olarak tartışacağız.\n" + "Her iki yöntemi de detaylı bir şekilde tartışacağız ve avantajları ile dezavantajlarını ele alacağız.\n" ] }, { @@ -1071,9 +1071,9 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### Null değerlerini kaldırma\n", + "### Null Değerleri Kaldırma\n", "\n", - "Modelimize aktardığımız veri miktarı, performansını doğrudan etkiler. Null değerlerini kaldırmak, veri noktalarının sayısını azaltmak ve dolayısıyla veri setinin boyutunu küçültmek anlamına gelir. Bu nedenle, veri seti oldukça büyük olduğunda null değer içeren satırları kaldırmak önerilir.\n", + "Modelimize aktardığımız veri miktarı, performansını doğrudan etkiler. Null değerleri kaldırmak, veri noktalarının sayısını azaltmak ve dolayısıyla veri setinin boyutunu küçültmek anlamına gelir. Bu nedenle, veri seti oldukça büyük olduğunda null değer içeren satırları kaldırmak önerilir.\n", "\n", "Bir diğer durum ise, belirli bir satır veya sütunun çok fazla eksik değere sahip olması olabilir. Bu durumda, bu satır/sütunlar kaldırılabilir çünkü çoğu veri eksik olduğundan analizimize fazla bir değer katmayacaktır.\n", "\n", @@ -1116,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "Bu, `example3[example3.notnull()]` çıktınıza benzemelidir. Buradaki fark, yalnızca maskelenmiş değerlere indeksleme yapmak yerine, `dropna`'nın `Series` olan `example3`'ten eksik değerleri kaldırmış olmasıdır.\n", + "Unutmayın, bu `example3[example3.notnull()]` çıktınıza benzemelidir. Buradaki fark, yalnızca maskelenmiş değerlere indeksleme yapmak yerine, `dropna`'nın `Series` `example3` içindeki eksik değerleri kaldırmış olmasıdır.\n", "\n", - "DataFrame'ler iki boyutlu olduğu için, veri silme konusunda daha fazla seçenek sunarlar.\n" + "DataFrame'ler iki boyutlu olduğu için, veri düşürme konusunda daha fazla seçenek sunarlar.\n" ] }, { @@ -1210,7 +1210,7 @@ "source": [ "(Pandas'ın `NaN` değerlerini barındırmak için iki sütunu float türüne yükselttiğini fark ettiniz mi?)\n", "\n", - "Bir `DataFrame`'den tek bir değeri silemezsiniz, bu yüzden tam satırları veya sütunları silmeniz gerekir. Ne yapmak istediğinize bağlı olarak, birini veya diğerini tercih edebilirsiniz ve bu nedenle pandas her iki seçenek için de size imkan tanır. Veri bilimi bağlamında, sütunlar genellikle değişkenleri, satırlar ise gözlemleri temsil ettiğinden, genellikle veri satırlarını silmeniz daha olasıdır; `dropna()` için varsayılan ayar, herhangi bir null değer içeren tüm satırları silmektir:\n" + "Bir `DataFrame`'den tek bir değeri silemezsiniz, bu yüzden tam satırları veya sütunları silmeniz gerekir. Ne yapmak istediğinize bağlı olarak, birini veya diğerini tercih edebilirsiniz ve bu nedenle pandas her ikisi için de seçenekler sunar. Veri bilimi bağlamında, sütunlar genellikle değişkenleri, satırlar ise gözlemleri temsil ettiğinden, genellikle veri satırlarını silmeniz daha olasıdır; `dropna()` için varsayılan ayar, herhangi bir null değer içeren tüm satırları silmektir:\n" ] }, { @@ -1283,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "Gerekirse, sütunlardaki NA değerlerini kaldırabilirsiniz. Bunu yapmak için `axis=1` kullanın:\n" + "Gerekirse, sütunlardan NA değerlerini kaldırabilirsiniz. Bunu yapmak için `axis=1` kullanın:\n" ] }, { @@ -1362,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Bu durum özellikle daha küçük veri kümelerinde, saklamak isteyebileceğiniz birçok veriyi kaybetmenize neden olabilir. Peki ya sadece birkaç veya hatta tüm değerleri null olan satırları ya da sütunları silmek isterseniz? Bu ayarları `dropna` içinde `how` ve `thresh` parametreleriyle belirtebilirsiniz.\n", + "Unutmayın, bu işlem özellikle daha küçük veri kümelerinde tutmak isteyebileceğiniz birçok veriyi silebilir. Peki ya sadece birkaç veya tüm null değerleri içeren satırları ya da sütunları silmek isterseniz? Bu ayarları `dropna` yönteminde `how` ve `thresh` parametreleriyle belirtebilirsiniz.\n", "\n", - "Varsayılan olarak, `how='any'` (kendiniz kontrol etmek veya metodun diğer parametrelerini görmek isterseniz, bir kod hücresinde `example4.dropna?` çalıştırabilirsiniz). Alternatif olarak, yalnızca tüm değerleri null olan satırları veya sütunları silmek için `how='all'` belirtebilirsiniz. Bu durumu bir sonraki alıştırmada örnek `DataFrame`imizi genişleterek uygulamalı olarak göreceğiz.\n" + "Varsayılan olarak, `how='any'` (kendiniz kontrol etmek veya yöntemin diğer parametrelerini görmek isterseniz, bir kod hücresinde `example4.dropna?` çalıştırabilirsiniz). Alternatif olarak, yalnızca tüm değerleri null olan satırları veya sütunları silmek için `how='all'` belirtebilirsiniz. Bu işlemi görmek için örnek `DataFrame`imizi genişletelim ve bir sonraki alıştırmada bunu uygulayalım.\n" ] }, { @@ -1456,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> Önemli Noktalar: \n", - "1. Eksik değerleri kaldırmak, yalnızca veri kümesi yeterince büyükse iyi bir fikirdir. \n", - "2. Çoğu verisi eksik olan tam satırlar veya sütunlar kaldırılabilir. \n", - "3. `DataFrame.dropna(axis=)` yöntemi, eksik değerleri kaldırmaya yardımcı olur. `axis` argümanı, satırların mı yoksa sütunların mı kaldırılacağını belirtir. \n", - "4. `how` argümanı da kullanılabilir. Varsayılan olarak `any` olarak ayarlanmıştır. Bu nedenle, yalnızca herhangi bir eksik değer içeren satırları/sütunları kaldırır. Tüm değerlerin eksik olduğu satırları/sütunları kaldıracağımızı belirtmek için `all` olarak ayarlanabilir. \n" + "> Önemli noktalar: \n", + "1. Eksik değerleri kaldırmak, yalnızca veri seti yeterince büyükse iyi bir fikirdir.\n", + "2. Çoğu verisi eksik olan tam satırlar veya sütunlar kaldırılabilir.\n", + "3. `DataFrame.dropna(axis=)` yöntemi, eksik değerleri kaldırmaya yardımcı olur. `axis` argümanı, satırların mı yoksa sütunların mı kaldırılacağını belirtir.\n", + "4. `how` argümanı da kullanılabilir. Varsayılan olarak `any` olarak ayarlanmıştır. Bu nedenle, yalnızca herhangi bir eksik değer içeren satırları/sütunları kaldırır. `all` olarak ayarlanabilir, böylece yalnızca tüm değerlerin eksik olduğu satırları/sütunları kaldırırız.\n" ] }, { @@ -1492,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "`thresh` parametresi size daha ince ayarlı bir kontrol sağlar: bir satırın veya sütunun korunması için sahip olması gereken *boş olmayan* değerlerin sayısını belirlersiniz:\n" + "`thresh` parametresi size daha ince ayarlı bir kontrol sağlar: bir satırın veya sütunun korunması için sahip olması gereken *null olmayan* değerlerin sayısını belirlersiniz:\n" ] }, { @@ -1567,7 +1567,7 @@ "id": "fmSFnzZegRsG" }, "source": [ - "Burada, ilk ve son satır yalnızca iki boş olmayan değer içerdiği için çıkarılmıştır.\n" + "Burada, yalnızca iki geçerli olmayan değer içerdiği için ilk ve son satır düşürülmüştür.\n" ] }, { @@ -1576,9 +1576,9 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### Boş değerleri doldurma\n", + "### Boş Değerleri Doldurma\n", "\n", - "Bazen eksik değerleri, geçerli olabilecek değerlerle doldurmak mantıklı olabilir. Boş değerleri doldurmak için birkaç teknik vardır. İlki, veri setinin dayandığı konu hakkında bilgi sahibi olmak (Alan Bilgisi) ve eksik değerleri bir şekilde tahmin etmektir.\n", + "Bazen eksik değerleri, geçerli olabilecek değerlerle doldurmak mantıklı olabilir. Boş değerleri doldurmak için birkaç teknik vardır. İlki, veri setinin dayandığı konu hakkındaki alan bilgisi (Domain Knowledge) kullanılarak eksik değerleri yaklaşık olarak tahmin etmektir.\n", "\n", "Bunu yerinde yapmak için `isnull` kullanabilirsiniz, ancak bu zahmetli olabilir, özellikle doldurmanız gereken çok fazla değer varsa. Veri bilimi alanında bu kadar yaygın bir görev olduğu için, pandas `fillna` sağlar. Bu, eksik değerlerin sizin seçtiğiniz bir değerle değiştirildiği bir `Series` veya `DataFrame` kopyası döndürür. Bunun pratikte nasıl çalıştığını görmek için başka bir örnek `Series` oluşturalım.\n" ] @@ -1590,11 +1590,11 @@ }, "source": [ "### Kategorik Veri (Sayısal Olmayan)\n", - "Öncelikle sayısal olmayan verileri ele alalım. Veri setlerinde, kategorik veriler içeren sütunlar bulunur. Örneğin, Cinsiyet, Doğru veya Yanlış gibi.\n", + "Öncelikle sayısal olmayan verileri ele alalım. Veri setlerinde, kategorik veri içeren sütunlar bulunur. Örneğin, Cinsiyet, Doğru veya Yanlış gibi.\n", "\n", - "Bu tür durumların çoğunda, eksik değerleri sütunun `modu` ile değiştiririz. Diyelim ki elimizde 100 veri noktası var ve bunların 90'ı Doğru, 8'i Yanlış demiş, 2'si ise doldurulmamış. Bu durumda, tüm sütunu dikkate alarak eksik olan 2 değeri Doğru ile doldurabiliriz.\n", + "Bu tür durumların çoğunda, eksik değerleri sütunun `mod`u ile doldururuz. Diyelim ki elimizde 100 veri noktası var ve 90'ı Doğru, 8'i Yanlış demiş, 2'si ise doldurulmamış. Bu durumda, tüm sütunu dikkate alarak eksik olan 2 değeri Doğru ile doldurabiliriz.\n", "\n", - "Yine burada alan bilgimizi kullanabiliriz. Şimdi modu kullanarak doldurma işlemine bir örnek düşünelim.\n" + "Yine burada alan bilgisi kullanabiliriz. Mod ile doldurma örneğini ele alalım.\n" ] }, { @@ -1699,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Şimdi, önce modu bulalım ve ardından `None` değerini mod ile dolduralım.\n" + ] }, { "cell_type": "code", @@ -1734,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Bu yüzden, None yerine True ile değiştireceğiz\n" + ] }, { "cell_type": "code", @@ -1844,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Gördüğümüz gibi, null değer değiştirilmiş. Söylemeye gerek yok, `'True'` yerine herhangi bir şey yazabilirdik ve o da yerine geçmiş olurdu.\n" + "Gördüğümüz gibi, null değer değiştirilmiş. Söylemeye gerek yok, yerine `'True'` veya başka bir şey yazabilirdik ve o da yerine geçecekti.\n" ] }, { @@ -1853,17 +1857,17 @@ "id": "heYe1I0dOmQ_" }, "source": [ - "### Sayısal Veriler\n", - "Şimdi, sayısal verilere gelelim. Burada, eksik değerleri doldurmak için iki yaygın yöntemimiz var:\n", + "### Sayısal Veri\n", + "Şimdi, sayısal verilere geçelim. Eksik değerleri doldurmanın iki yaygın yöntemi vardır:\n", "\n", "1. Satırın Medyanı ile Değiştirme \n", "2. Satırın Ortalaması ile Değiştirme \n", "\n", - "Eğer veri, aykırı değerlerle çarpık bir dağılıma sahipse, medyan ile değiştirme yaparız. Bunun nedeni, medyanın aykırı değerlere karşı dayanıklı olmasıdır.\n", + "Verilerde uç değerler (outlier) olduğunda, medyan ile değiştirme tercih edilir. Bunun nedeni, medyanın uç değerlere karşı dayanıklı olmasıdır.\n", "\n", - "Veri normalize edildiğinde, ortalamayı kullanabiliriz çünkü bu durumda, ortalama ve medyan birbirine oldukça yakın olur.\n", + "Veriler normalleştirildiğinde ise ortalama kullanılabilir, çünkü bu durumda ortalama ve medyan birbirine oldukça yakın olur.\n", "\n", - "Öncelikle, normal dağılıma sahip bir sütun alalım ve eksik değeri sütunun ortalaması ile dolduralım.\n" + "Öncelikle, normal dağılıma sahip bir sütun alalım ve eksik değerleri sütunun ortalaması ile dolduralım.\n" ] }, { @@ -2003,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Ortalama ile doldurma\n" + ] }, { "cell_type": "code", @@ -2103,7 +2109,7 @@ "id": "CwpVFCrPTC5z" }, "source": [ - "Gördüğümüz gibi, eksik değer ortalamasıyla değiştirilmiştir.\n" + "Gördüğümüz gibi, eksik değer ortalaması ile değiştirilmiştir.\n" ] }, { @@ -2252,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Medyan ile doldurma\n" + ] }, { "cell_type": "code", @@ -2352,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Gördüğümüz gibi, NaN değeri sütunun medyanı ile değiştirilmiştir\n" + "Gördüğümüz gibi, NaN değeri sütunun medyanı ile değiştirilmiştir.\n" ] }, { @@ -2436,9 +2444,9 @@ }, "source": [ "> Önemli Noktalar:\n", - "1. Eksik değerleri doldurmak, ya veri az olduğunda ya da eksik verileri doldurmak için bir strateji olduğunda yapılmalıdır.\n", - "2. Eksik değerleri tahmin ederek doldurmak için alan bilgisi kullanılabilir.\n", - "3. Kategorik verilerde genellikle eksik değerler, sütunun moduyla değiştirilir.\n", + "1. Eksik değerlerin doldurulması, ya veri az olduğunda ya da eksik verileri doldurmak için bir strateji olduğunda yapılmalıdır.\n", + "2. Eksik değerleri yaklaşık olarak doldurmak için alan bilgisi kullanılabilir.\n", + "3. Kategorik verilerde genellikle eksik değerler sütunun moduyla değiştirilir.\n", "4. Sayısal verilerde eksik değerler genellikle sütunların ortalaması (normalleştirilmiş veri setleri için) veya medyanı ile doldurulur.\n" ] }, @@ -2470,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "Boş değerleri **ileri doldurma** yöntemiyle doldurabilirsiniz, yani bir boş değeri doldurmak için son geçerli değeri kullanabilirsiniz:\n" + "Null değerleri **ileri doldurabilirsiniz**, yani son geçerli değeri kullanarak bir null değeri doldurabilirsiniz:\n" ] }, { @@ -2511,9 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Aşağıdaki gibi bir çeviri sağlanabilir:\n", - "\n", - "Boş bir değeri doldurmak için bir sonraki geçerli değeri geriye doğru yaymak amacıyla **geri doldurma** da yapabilirsiniz:\n" + "Ayrıca, bir null değeri doldurmak için bir sonraki geçerli değeri geriye doğru yaymak üzere **geri doldurma** yapabilirsiniz:\n" ] }, { @@ -2555,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "Tahmin edebileceğiniz gibi, bu DataFrame'ler ile aynı şekilde çalışır, ancak boş değerleri doldurmak için bir `axis` de belirtebilirsiniz:\n" + "Tahmin edebileceğiniz gibi, bu aynı şekilde DataFrame'lerle de çalışır, ancak null değerleri doldurmak için bir `axis` belirtebilirsiniz:\n" ] }, { @@ -2728,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Önceki bir değer ileri doldurma için mevcut olmadığında, boş değer olduğu gibi kalır.\n" + "Önceki bir değer ileri doldurma için mevcut olmadığında, boş değerlerin aynı kaldığını unutmayın.\n" ] }, { @@ -2761,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Eksik değerleri doldurmak için `fillna` kullanımında yaratıcı olabilirsiniz. Örneğin, `example4`e tekrar bakalım, ancak bu sefer eksik değerleri `DataFrame`deki tüm değerlerin ortalamasıyla dolduralım:\n" + "Eksik değerleri doldurmak için `fillna` kullanımı konusunda yaratıcı olabilirsiniz. Örneğin, tekrar `example4`'e bakalım, ancak bu sefer eksik değerleri `DataFrame`'deki tüm değerlerin ortalaması ile dolduralım:\n" ] }, { @@ -2852,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Unutmayın ki 3. sütun hala değersiz: varsayılan yön, değerleri satır bazında doldurmaktır.\n", + "Dikkat edin, 3. sütun hala değersiz: varsayılan yön, değerleri satır bazında doldurmaktır.\n", "\n", - "> **Çıkarım:** Veri setlerinizdeki eksik değerlerle başa çıkmanın birden fazla yolu vardır. Kullanacağınız spesifik strateji (onları kaldırmak, değiştirmek ya da nasıl değiştireceğiniz) o verinin özelliklerine bağlı olmalıdır. Veri setleriyle ne kadar çok çalışır ve etkileşimde bulunursanız, eksik değerlerle nasıl başa çıkacağınız konusunda o kadar iyi bir anlayış geliştireceksiniz.\n" + "> **Çıkarım:** Veri setlerinizdeki eksik değerlerle başa çıkmanın birden fazla yolu vardır. Kullanacağınız özel strateji (eksik değerleri kaldırmak, değiştirmek veya nasıl değiştireceğiniz) o verinin özelliklerine bağlı olmalıdır. Veri setleriyle daha fazla çalışıp etkileşimde bulundukça eksik değerlerle nasıl başa çıkacağınız konusunda daha iyi bir anlayış geliştireceksiniz.\n" ] }, { @@ -2865,7 +2871,7 @@ "source": [ "### Kategorik Verilerin Kodlanması\n", "\n", - "Makine öğrenimi modelleri yalnızca sayılar ve herhangi bir türdeki sayısal verilerle çalışır. Bir model, Evet ile Hayır arasındaki farkı anlayamaz, ancak 0 ile 1 arasındaki farkı ayırt edebilir. Bu nedenle, eksik değerleri doldurduktan sonra, modelin anlayabilmesi için kategorik verileri sayısal bir forma dönüştürmemiz gerekir.\n", + "Makine öğrenimi modelleri yalnızca sayılarla ve herhangi bir sayısal veriyle çalışır. Bir model, Evet ile Hayır arasındaki farkı anlayamaz, ancak 0 ile 1 arasındaki farkı ayırt edebilir. Bu nedenle, eksik değerleri doldurduktan sonra, modelin anlayabilmesi için kategorik verileri bir tür sayısal forma dönüştürmemiz gerekir.\n", "\n", "Kodlama iki şekilde yapılabilir. Bunları şimdi tartışacağız.\n" ] @@ -2878,7 +2884,7 @@ "source": [ "**ETİKET KODLAMA**\n", "\n", - "Etiket kodlama, temel olarak her kategoriyi bir sayıya dönüştürmektir. Örneğin, bir havayolu yolcuları veri setimiz olduğunu varsayalım ve bu veri setinde yolcuların sınıfını içeren bir sütun bulunsun: ['business class', 'economy class', 'first class']. Eğer etiket kodlama uygulanırsa, bu [0,1,2] olarak dönüştürülür. Şimdi bunu bir kod örneğiyle görelim. İlerleyen not defterlerinde `scikit-learn` öğreneceğimiz için burada kullanmayacağız.\n" + "Etiket kodlama, temelde her kategoriyi bir sayıya dönüştürmektir. Örneğin, bir havayolu yolcuları veri setimiz olduğunu ve bu veri setinde yolcuların sınıfını içeren bir sütun bulunduğunu varsayalım: ['business class', 'economy class', 'first class']. Eğer etiket kodlama uygulanırsa, bu [0,1,2] şeklinde dönüştürülür. Şimdi bunu bir kod örneğiyle görelim. İlerleyen not defterlerinde `scikit-learn` öğreneceğimiz için burada kullanmayacağız.\n" ] }, { @@ -2986,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "1. sütunda etiket kodlaması yapmak için, her bir sınıfı bir sayıya eşleyen bir eşleme tanımlamamız ve ardından değiştirme işlemini gerçekleştirmemiz gerekir.\n" + "1. sütunda etiket kodlaması yapmak için, önce her sınıfı bir sayıya eşleyen bir eşleme tanımlamamız ve ardından değiştirmemiz gerekir.\n" ] }, { @@ -3088,7 +3094,7 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Gördüğümüz gibi, çıktı beklediğimizle eşleşiyor. Peki, etiket kodlamayı ne zaman kullanırız? Etiket kodlama aşağıdaki durumlardan birinde veya her ikisinde kullanılır:\n", + "Gördüğümüz gibi, çıktı beklediğimizle eşleşiyor. Peki, etiket kodlamayı ne zaman kullanırız? Etiket kodlama aşağıdaki durumlarda kullanılır:\n", "1. Kategori sayısı fazla olduğunda\n", "2. Kategoriler sıralı olduğunda.\n" ] @@ -3099,11 +3105,11 @@ "id": "eQPAPVwsqWT7" }, "source": [ - "**TEK SEFERDE KODLAMA**\n", + "**ONE HOT ENCODING**\n", "\n", - "Bir diğer kodlama türü Tek Seferde Kodlama'dır (One Hot Encoding). Bu kodlama türünde, sütunun her bir kategorisi ayrı bir sütun olarak eklenir ve her bir veri noktası, o kategoriyi içerip içermediğine bağlı olarak 0 veya 1 alır. Yani, eğer n farklı kategori varsa, veri çerçevesine n sütun eklenir.\n", + "Bir diğer kodlama türü One Hot Encoding'dir. Bu kodlama türünde, sütunun her bir kategorisi ayrı bir sütun olarak eklenir ve her veri noktası, o kategoriyi içerip içermediğine bağlı olarak 0 veya 1 alır. Yani, eğer n farklı kategori varsa, veri çerçevesine n sütun eklenir.\n", "\n", - "Örneğin, aynı uçak sınıfı örneğini ele alalım. Kategoriler şunlardı: ['business class', 'economy class', 'first class']. Eğer tek seferde kodlama yaparsak, veri kümesine şu üç sütun eklenir: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Örneğin, aynı uçak sınıfı örneğini ele alalım. Kategoriler şunlardı: ['business class', 'economy class', 'first class']. Eğer one hot encoding uygularsak, veri setine şu üç sütun eklenir: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3211,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "Haydi, birinci sütun üzerinde one hot encoding gerçekleştirelim\n" + "Haydi birinci sütunda tekil kodlama gerçekleştirelim.\n" ] }, { @@ -3357,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Önemli Noktalar:\n", + "> Temel Çıkarımlar:\n", "1. Kodlama, sayısal olmayan verileri sayısal verilere dönüştürmek için yapılır.\n", - "2. Kodlama iki türde gerçekleştirilir: Etiket kodlama ve Tek Sıcak Kodlama, her ikisi de veri setinin gereksinimlerine göre uygulanabilir.\n" + "2. Kodlama iki türdür: Etiket kodlama ve Tek Sıcak Kodlama. Her ikisi de veri setinin gereksinimlerine göre gerçekleştirilebilir.\n" ] }, { @@ -3368,11 +3374,11 @@ "id": "K8UXOJYRgRsJ" }, "source": [ - "## Yinelenen Verilerin Kaldırılması\n", + "## Yinelenen verilerin kaldırılması\n", "\n", "> **Öğrenme hedefi:** Bu alt bölümü tamamladığınızda, DataFrame'lerden yinelenen değerleri tanımlama ve kaldırma konusunda rahat olmalısınız.\n", "\n", - "Eksik verilere ek olarak, gerçek dünya veri setlerinde sıkça yinelenen verilere rastlarsınız. Neyse ki, pandas yinelenen girişleri tespit etmek ve kaldırmak için kolay bir yöntem sunar.\n" + "Eksik verilere ek olarak, gerçek dünya veri setlerinde sıkça yinelenen verilere rastlarsınız. Neyse ki, pandas, yinelenen girişleri tespit etmek ve kaldırmak için kolay bir yöntem sunar.\n" ] }, { @@ -3383,7 +3389,7 @@ "source": [ "### Kopyaları tespit etme: `duplicated`\n", "\n", - "Pandas'taki `duplicated` yöntemiyle kopya değerleri kolayca tespit edebilirsiniz. Bu yöntem, bir `DataFrame` içindeki bir girişin daha önceki bir girişin kopyası olup olmadığını gösteren bir Boolean maskesi döndürür. Bunun nasıl çalıştığını görmek için başka bir örnek `DataFrame` oluşturalım.\n" + "Pandas'ta `duplicated` yöntemiyle kopya değerleri kolayca tespit edebilirsiniz. Bu yöntem, bir `DataFrame` içindeki bir girişin daha önceki bir girişin kopyası olup olmadığını gösteren bir Boolean maske döndürür. Bunun nasıl çalıştığını görmek için başka bir örnek `DataFrame` oluşturalım.\n" ] }, { @@ -3513,7 +3519,7 @@ }, "source": [ "### Yinelenenleri Kaldırma: `drop_duplicates`\n", - "`drop_duplicates`, `duplicated` değerlerinin tümünün `False` olduğu verilerin bir kopyasını döndürür:\n" + "`drop_duplicates`, `duplicated` değerlerinin tümünün `False` olduğu verilerin bir kopyasını basitçe döndürür:\n" ] }, { @@ -3672,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Çıkarım:** Yinelenen verilerin kaldırılması, neredeyse her veri bilimi projesinin önemli bir parçasıdır. Yinelenen veriler, analizlerinizin sonuçlarını değiştirebilir ve size yanlış sonuçlar verebilir!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Gerçek Dünya Verilerinde Kalite Kontrolleri\n", + "\n", + "> **Öğrenme hedefi:** Bu bölümü tamamladığınızda, tutarsız kategorik değerler, anormal sayısal değerler (aykırı değerler) ve küçük farklılıklarla yinelenen varlıklar gibi yaygın gerçek dünya veri kalitesi sorunlarını tespit etme ve düzeltme konusunda rahat olmalısınız.\n", + "\n", + "Eksik değerler ve tam kopyalar yaygın sorunlar olsa da, gerçek dünya veri setleri genellikle daha ince sorunlar içerir:\n", + "\n", + "1. **Tutarsız kategorik değerler**: Aynı kategorinin farklı şekilde yazılması (ör. \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Anormal sayısal değerler**: Veri giriş hatalarını gösteren aşırı aykırı değerler (ör. yaş = 999)\n", + "3. **Neredeyse yinelenen satırlar**: Küçük farklılıklarla aynı varlığı temsil eden kayıtlar\n", + "\n", + "Bu sorunları tespit etmek ve ele almak için teknikleri inceleyelim.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Örnek \"Kirli\" Bir Veri Seti Oluşturma\n", + "\n", + "Öncelikle, gerçek dünyadaki verilerde sıkça karşılaştığımız türde sorunları içeren bir örnek veri seti oluşturalım:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Tutarsız Kategorik Değerleri Tespit Etme\n", + "\n", + "`country` sütununun aynı ülkeler için birden fazla temsil içerdiğini fark edin. Bu tutarsızlıkları belirleyelim:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Kategorik Değerleri Standartlaştırma\n", + "\n", + "Bu değerleri standartlaştırmak için bir eşleme oluşturabiliriz. Basit bir yaklaşım, küçük harfe dönüştürmek ve bir eşleme sözlüğü oluşturmaktır:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Alternatif: Bulanık Eşleştirme Kullanımı**\n", + "\n", + "Daha karmaşık durumlar için, benzer dizeleri otomatik olarak algılamak için `rapidfuzz` kütüphanesi ile bulanık dize eşleştirme kullanabiliriz:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Anormal Sayısal Değerleri (Aykırı Değerler) Tespit Etme\n", + "\n", + "`age` sütununa baktığımızda, 199 ve -5 gibi şüpheli değerler görüyoruz. Bu aykırı değerleri tespit etmek için istatistiksel yöntemler kullanalım.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### IQR (Çeyrekler Arası Aralık) Yöntemini Kullanma\n", + "\n", + "IQR yöntemi, uç değerlere daha az duyarlı olan sağlam bir istatistiksel aykırı değer tespit tekniğidir:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Z-Skor Yöntemini Kullanma\n", + "\n", + "Z-skor yöntemi, aykırı değerleri ortalamadan standart sapmalara göre belirler:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Aykırı Değerleri Yönetme\n", + "\n", + "Tespit edildikten sonra, aykırı değerler birkaç şekilde yönetilebilir:\n", + "1. **Kaldır**: Aykırı değer içeren satırları silin (eğer hata ise)\n", + "2. **Sınırla**: Sınır değerlerle değiştirin\n", + "3. **NaN ile Değiştir**: Eksik veri olarak ele alın ve imputasyon tekniklerini kullanın\n", + "4. **Tut**: Eğer meşru uç değerlerse\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Yakın Çift Satırları Tespit Etme\n", + "\n", + "Veri setimizde \"John Smith\" için biraz farklı değerlerle birden fazla giriş olduğunu fark edin. İsim benzerliğine dayalı potansiyel çiftleri belirleyelim.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Bulanık Eşleştirme ile Yakın Kopyaları Bulma\n", + "\n", + "Daha gelişmiş kopya tespiti için, benzer isimleri bulmak amacıyla bulanık eşleştirme kullanabiliriz:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Çift Kayıtları Yönetme\n", + "\n", + "Belirlendikten sonra, çift kayıtları nasıl yöneteceğinize karar vermeniz gerekir:\n", + "1. **İlk kaydı tut**: `drop_duplicates(keep='first')` kullanın\n", + "2. **Son kaydı tut**: `drop_duplicates(keep='last')` kullanın\n", + "3. **Bilgileri birleştir**: Çift satırlardaki bilgileri birleştirin\n", + "4. **Manuel inceleme**: İnsan tarafından incelenmek üzere işaretleyin\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Özet: Tam Veri Temizleme Süreci\n", + "\n", + "Hadi her şeyi bir araya getirip kapsamlı bir temizleme süreci oluşturalım:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Zorluk Alıştırması\n", + "\n", + "Şimdi sıra sizde! Aşağıda, birden fazla kalite sorunu içeren yeni bir veri satırı bulunmaktadır. Yapabilir misiniz:\n", + "\n", + "1. Bu satırdaki tüm sorunları belirlemek\n", + "2. Her sorunu temizlemek için kod yazmak\n", + "3. Temizlenmiş satırı veri setine eklemek\n", + "\n", + "İşte sorunlu veri:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Önemli Noktalar\n", + "\n", + "1. **Tutarsız kategoriler** gerçek dünya verilerinde yaygındır. Her zaman benzersiz değerleri kontrol edin ve bunları eşleştirme veya bulanık eşleştirme yöntemleriyle standartlaştırın.\n", + "\n", + "2. **Aykırı değerler** analizlerinizi önemli ölçüde etkileyebilir. Bunları tespit etmek için alan bilgisiyle birlikte istatistiksel yöntemler (IQR, Z-skoru) kullanın.\n", + "\n", + "3. **Yakın kopyalar**, tam kopyalardan daha zor tespit edilir. Bunları belirlemek için bulanık eşleştirme ve veriyi normalleştirme (küçük harfe dönüştürme, boşlukları kaldırma) yöntemlerini göz önünde bulundurun.\n", + "\n", + "4. **Veri temizleme tekrarlıdır**. Temizlenmiş veri setinizi sonlandırmadan önce birden fazla teknik uygulamanız ve sonuçları gözden geçirmeniz gerekebilir.\n", + "\n", + "5. **Kararlarınızı belgeleyin**. Uyguladığınız temizleme adımlarını ve nedenlerini takip edin, çünkü bu tekrarlanabilirlik ve şeffaflık açısından önemlidir.\n", + "\n", + "> **En İyi Uygulama:** Her zaman orijinal \"kirli\" verinizin bir kopyasını saklayın. Kaynak veri dosyalarınızı asla üzerine yazmayın - `data_cleaned.csv` gibi açık adlandırma kurallarıyla temizlenmiş versiyonlar oluşturun.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Feragatname**: \nBu belge, [Co-op Translator](https://github.com/Azure/co-op-translator) adlı yapay zeka çeviri hizmeti kullanılarak çevrilmiştir. Doğruluk için çaba göstersek de, otomatik çevirilerin hata veya yanlışlıklar içerebileceğini lütfen unutmayın. Orijinal belgenin kendi dilindeki hali, yetkili kaynak olarak kabul edilmelidir. Kritik bilgiler için profesyonel insan çevirisi önerilir. Bu çevirinin kullanımından kaynaklanan yanlış anlamalar veya yanlış yorumlamalar için sorumluluk kabul etmiyoruz.\n" + "\n---\n\n**Feragatname**: \nBu belge, AI çeviri hizmeti [Co-op Translator](https://github.com/Azure/co-op-translator) kullanılarak çevrilmiştir. Doğruluğu sağlamak için çaba göstersek de, otomatik çevirilerin hata veya yanlışlık içerebileceğini lütfen unutmayın. Belgenin orijinal dili, yetkili kaynak olarak kabul edilmelidir. Kritik bilgiler için profesyonel insan çevirisi önerilir. Bu çevirinin kullanımından kaynaklanan yanlış anlamalar veya yanlış yorumlamalar için sorumluluk kabul edilmez.\n" ] } ], @@ -3706,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T08:12:36+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:06:11+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "tr" } diff --git a/translations/tw/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/tw/2-Working-With-Data/08-data-preparation/notebook.ipynb index 0ff6838c..a46dd743 100644 --- a/translations/tw/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/tw/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -6,17 +6,17 @@ "id": "rQ8UhzFpgRra" }, "source": [ - "# 數據準備\n", + "# 資料準備\n", "\n", "[原始筆記本來源:*Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## 探索 `DataFrame` 資訊\n", "\n", - "> **學習目標:** 在完成本小節後,您應該能夠熟悉如何查找存儲在 pandas DataFrame 中的數據的一般資訊。\n", + "> **學習目標:** 在本小節結束時,您應該能夠熟悉如何查找 pandas DataFrame 中儲存的資料的一般資訊。\n", "\n", - "當您將數據載入到 pandas 中後,數據通常會以 `DataFrame` 的形式存在。然而,如果您的 `DataFrame` 中的數據集有 60,000 行和 400 列,您該如何開始了解您正在處理的內容呢?幸運的是,pandas 提供了一些方便的工具,可以快速查看 `DataFrame` 的整體資訊,以及前幾行和後幾行的數據。\n", + "當您將資料載入 pandas 後,資料通常會以 `DataFrame` 的形式存在。然而,如果您的 `DataFrame` 中的資料集有 60,000 行和 400 列,您該如何開始了解您正在處理的內容呢?幸運的是,pandas 提供了一些方便的工具,可以快速查看 `DataFrame` 的整體資訊,以及前幾行和後幾行的內容。\n", "\n", - "為了探索這些功能,我們將導入 Python 的 scikit-learn 庫,並使用一個每位數據科學家都看過數百次的經典數據集:英國生物學家 Ronald Fisher 在他1936年的論文《多重測量在分類問題中的應用》中使用的 *Iris* 數據集:\n" + "為了探索這些功能,我們將匯入 Python 的 scikit-learn 庫,並使用一個每位資料科學家都看過數百次的經典資料集:英國生物學家 Ronald Fisher 在他 1936 年的論文《The use of multiple measurements in taxonomic problems》中使用的 *Iris* 資料集:\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "所以,我們正在處理150行4列的數據。每一行代表一個數據點,每一列代表與數據框相關的一個特徵。基本上,就是有150個數據點,每個數據點包含4個特徵。\n", + "我們正在處理150行4列的數據。每一行代表一個數據點,每一列代表與數據框相關的一個特徵。基本上,這裡有150個數據點,每個數據點包含4個特徵。\n", "\n", - "`shape`在這裡是數據框的一個屬性,而不是一個函數,這就是為什麼它的後面沒有一對括號。\n" + "`shape`在這裡是數據框的一個屬性,而不是一個函數,因此它的末尾沒有一對括號。\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "現在讓我們來看看這 4 個數據欄位。每個欄位究竟代表什麼呢?`columns` 屬性會提供我們數據框中欄位的名稱。\n" + "現在讓我們來看看這個數據的四個欄位。每個欄位究竟代表什麼呢?`columns` 屬性會提供我們數據框中欄位的名稱。\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "正如我們所見,有四(4)列。`columns` 屬性告訴我們列的名稱,基本上沒有其他內容。當我們想要識別數據集包含的特徵時,這個屬性變得重要。\n" + "如我們所見,有四(4)列。`columns`屬性告訴我們列的名稱,基本上沒有其他內容。當我們想要識別數據集包含的特徵時,這個屬性就顯得重要了。\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "透過 `shape` 屬性提供的數據量以及透過 `columns` 屬性提供的特徵或欄位名稱,可以讓我們了解一些關於資料集的資訊。現在,我們希望更深入地探索資料集。`DataFrame.info()` 函數在這方面非常有用。\n" + "透過 `shape` 屬性提供的數據量以及透過 `columns` 屬性提供的特徵或欄位名稱,可以讓我們對資料集有初步的了解。現在,我們希望更深入地探索資料集。`DataFrame.info()` 函數在這方面非常有用。\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "從這裡,我們可以做出一些觀察: \n", - "1. 每列的資料類型:在這個數據集中,所有數據都以64位浮點數的形式存儲。 \n", - "2. 非空值的數量:處理空值是數據準備中的一個重要步驟,稍後會在筆記本中處理。 \n" + "從這裡,我們可以做出以下幾個觀察:\n", + "1. 每個欄位的資料類型:在這個資料集中,所有的資料都以64位元浮點數形式儲存。\n", + "2. 非空值的數量:處理空值是資料準備中的重要步驟,稍後會在筆記本中進行處理。\n" ] }, { @@ -192,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "假設我們的數據集中有許多數值型數據。像平均值、中位數、四分位數等單變量統計計算可以分別對每一列進行操作。`DataFrame.describe()` 函數為我們提供了數據集中數值列的統計摘要。\n" + "假設我們的資料集中有大量的數值資料。像是平均值、中位數、四分位數等單變量統計計算可以針對每個欄位單獨進行。`DataFrame.describe()` 函數可以為我們提供資料集中數值欄位的統計摘要。\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "作為輸出,我們可以看到數據集的五(5)個條目。如果我們查看左側的索引,我們會發現這是前五行。\n" + "在此輸出中,我們可以看到數據集的五(5)個條目。如果查看左側的索引,我們會發現這是前五行。\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### 練習:\n", "\n", - "從上面的例子可以看出,預設情況下,`DataFrame.head` 會返回 `DataFrame` 的前五行。在下面的程式碼區塊中,你能找到一種方法來顯示超過五行嗎?\n" + "從上面的例子可以看出,預設情況下,`DataFrame.head` 會返回 `DataFrame` 的前五行。在下面的程式碼單元中,你能找到一種方法來顯示超過五行嗎?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "另一種查看數據的方式是從結尾開始(而不是從開頭)。`DataFrame.head` 的相反方法是 `DataFrame.tail`,它會返回 `DataFrame` 的最後五行:\n" + "另一種查看數據的方式是從結尾開始(而不是從開頭)。`DataFrame.head` 的反面是 `DataFrame.tail`,它會返回 `DataFrame` 的最後五行:\n" ] }, { @@ -584,9 +584,9 @@ "source": [ "在實際操作中,能夠輕鬆檢視 `DataFrame` 的前幾行或後幾行非常有用,特別是在檢查有序數據集中的異常值時。\n", "\n", - "上面透過程式碼範例展示的所有函數和屬性,幫助我們了解數據的外觀和感覺。\n", + "上述透過程式碼範例展示的所有函數和屬性,都能幫助我們快速了解數據的外觀和特性。\n", "\n", - "> **重點提示:** 僅僅透過查看 `DataFrame` 中的資訊元數據或其前幾個和後幾個值,就能立即對您正在處理的數據的大小、形狀和內容有一個初步的了解。\n" + "> **重點提示:** 即使僅僅透過查看 `DataFrame` 的元數據或其中的前幾個和後幾個值,也能立即對您正在處理的數據的大小、形狀和內容有一個初步的了解。\n" ] }, { @@ -596,17 +596,17 @@ }, "source": [ "### 缺失資料\n", - "讓我們來探討缺失資料。當某些欄位中沒有儲存任何值時,就會出現缺失資料。\n", + "讓我們深入探討缺失資料。缺失資料是指某些欄位中沒有儲存任何值。\n", "\n", - "舉個例子:假設某人對自己的體重很在意,因此在調查問卷中沒有填寫體重欄位。那麼,這個人的體重值就會是缺失的。\n", + "舉個例子:假設某人對自己的體重很在意,因此在問卷中不填寫體重欄位。那麼,該人的體重值就會是缺失的。\n", "\n", "在現實世界的數據集中,缺失值是非常常見的。\n", "\n", "**Pandas 如何處理缺失資料**\n", "\n", - "Pandas 有兩種方式來處理缺失值。第一種方式你在之前的章節中可能已經見過:`NaN`,即「非數值」(Not a Number)。這其實是一個特殊值,屬於 IEEE 浮點數規範的一部分,專門用來表示缺失的浮點數值。\n", + "Pandas 以兩種方式處理缺失值。第一種方式是你在之前的章節中已經見過的:`NaN`,即「非數值」(Not a Number)。這實際上是一個特殊值,屬於 IEEE 浮點數規範的一部分,僅用於表示缺失的浮點數值。\n", "\n", - "對於浮點數以外的缺失值,Pandas 使用的是 Python 的 `None` 物件。雖然遇到兩種不同的值來表示相同的概念可能會讓人感到困惑,但這種設計選擇背後有其合理的程式邏輯原因。實際上,這樣的做法使得 Pandas 能夠在大多數情況下提供一個良好的折衷方案。儘管如此,`None` 和 `NaN` 都有各自的限制,特別是在使用它們時需要注意的地方。\n" + "對於非浮點數的缺失值,Pandas 使用 Python 的 `None` 物件。雖然遇到兩種不同的值來表示相同的概念可能會讓人感到困惑,但這種設計選擇有其合理的程式邏輯原因。實際上,這樣的設計使得 Pandas 能夠在大多數情況下提供良好的平衡。不過,無論是 `None` 還是 `NaN`,它們都帶有一些限制,必須注意它們在使用上的差異。\n" ] }, { @@ -615,10 +615,10 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: 非浮點數的缺失資料\n", - "由於 `None` 來自 Python,因此它無法用於非 `'object'` 資料類型的 NumPy 和 pandas 陣列。請記住,NumPy 陣列(以及 pandas 中的資料結構)只能包含一種類型的資料。這正是它們在大規模資料和計算工作中具有強大功能的原因,但也因此限制了它們的靈活性。這類陣列必須向上轉型為“最低共同分母”,即能夠涵蓋陣列中所有內容的資料類型。當陣列中包含 `None` 時,這表示您正在處理 Python 物件。\n", + "### `None`:非浮點型缺失資料\n", + "由於 `None` 來自 Python,它無法用於資料型別非 `'object'` 的 NumPy 和 pandas 陣列。請記住,NumPy 陣列(以及 pandas 中的資料結構)只能包含一種型別的資料。這正是它們在大規模資料和計算工作中展現強大效能的原因,但也限制了它們的靈活性。這類陣列必須提升為「最低共同分母」,即能涵蓋陣列中所有內容的資料型別。當陣列中包含 `None` 時,表示您正在處理 Python 物件。\n", "\n", - "為了更清楚地了解這一點,請參考以下範例陣列(注意其 `dtype`):\n" + "以下範例陣列展示了這一點(請注意其 `dtype`):\n" ] }, { @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "上升數據類型的現實伴隨著兩個副作用。首先,操作將在解釋的 Python 代碼層面進行,而不是編譯的 NumPy 代碼層面。基本上,這意味著任何涉及包含 `None` 的 `Series` 或 `DataFrame` 的操作都會變得較慢。雖然你可能不會注意到這種性能影響,但對於大型數據集來說,這可能會成為一個問題。\n", + "上升型資料類型的現實情況伴隨著兩個副作用。首先,操作將在解釋型 Python 代碼層面執行,而不是編譯型 NumPy 代碼層面。基本上,這意味著任何涉及包含 `None` 的 `Series` 或 `DataFrame` 的操作都會變得較慢。雖然你可能不會注意到這種性能下降,但對於大型數據集來說,這可能會成為一個問題。\n", "\n", - "第二個副作用源於第一個副作用。由於 `None` 本質上將 `Series` 或 `DataFrame` 拉回到原生 Python 的世界,因此在包含 ``None`` 值的數組上使用像 `sum()` 或 `min()` 這樣的 NumPy/pandas 聚合操作通常會產生錯誤:\n" + "第二個副作用源於第一個副作用。由於 `None` 本質上將 `Series` 或 `DataFrame` 拉回到原生 Python 的世界,因此在包含 ``None`` 值的陣列上使用像 `sum()` 或 `min()` 這樣的 NumPy/pandas 聚合函數通常會產生錯誤:\n" ] }, { @@ -698,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**主要結論**:整數與 `None` 值之間的加法(以及其他操作)是未定義的,這可能會限制您對包含這些值的數據集所能執行的操作。\n" + "**主要結論**:整數與 `None` 值之間的加法(以及其他運算)是未定義的,這可能會限制您對包含這些值的數據集所能執行的操作。\n" ] }, { @@ -772,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "好消息:在包含 `NaN` 的數組上運行的聚合不會出現錯誤。壞消息:結果並非一律有用:\n" + "好消息:在包含 `NaN` 的數組上運行的聚合不會出現錯誤。壞消息:結果並不完全有用:\n" ] }, { @@ -831,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "請記住:`NaN` 只是用於缺失的浮點值;整數、字串或布林值沒有 `NaN` 的對應值。\n" + "請記住:`NaN` 僅用於表示缺失的浮點數值;整數、字串或布林值沒有對應的 `NaN`。\n" ] }, { @@ -842,7 +842,7 @@ "source": [ "### `NaN` 和 `None`:pandas 中的空值\n", "\n", - "即使 `NaN` 和 `None` 的行為略有不同,pandas 仍然設計為可以互換處理它們。為了說明這一點,請考慮一個整數的 `Series`:\n" + "儘管 `NaN` 和 `None` 的行為可能略有不同,但 pandas 仍然設計為可以互換處理它們。為了更清楚地了解這一點,請考慮一個整數的 `Series`:\n" ] }, { @@ -906,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "在將資料型別向上轉型以建立 `Series` 和 `DataFrame` 的資料一致性時,pandas 會自動在 `None` 和 `NaN` 之間切換缺失值。由於這種設計特性,將 `None` 和 `NaN` 視為 pandas 中兩種不同形式的「空值」是很有幫助的。事實上,pandas 中一些處理缺失值的核心方法名稱就反映了這個概念:\n", + "在將資料型別向上轉型以建立 `Series` 和 `DataFrame` 的資料一致性過程中,pandas 會自動在 `None` 和 `NaN` 之間切換缺失值。由於這種設計特性,將 `None` 和 `NaN` 視為 pandas 中兩種不同形式的「空值」是很有幫助的。事實上,pandas 中一些核心方法的命名就反映了這種概念,這些方法用於處理缺失值:\n", "\n", - "- `isnull()`: 生成一個布林遮罩,標示出缺失值\n", - "- `notnull()`: 與 `isnull()` 相反\n", - "- `dropna()`: 返回一個過濾後的資料版本\n", - "- `fillna()`: 返回一個填補或推算缺失值後的資料副本\n", + "- `isnull()`:生成一個布林遮罩以指示缺失值\n", + "- `notnull()`:與 `isnull()` 相反\n", + "- `dropna()`:返回過濾後的資料版本\n", + "- `fillna()`:返回填充或推算缺失值後的資料副本\n", "\n", - "這些方法非常重要,必須熟練掌握並運用自如,因此我們將逐一深入探討它們。\n" + "這些方法非常重要,掌握並熟悉它們是必要的,因此我們將逐一深入探討這些方法。\n" ] }, { @@ -924,8 +924,8 @@ "source": [ "### 偵測空值\n", "\n", - "現在我們已經了解了缺失值的重要性,在處理它們之前,我們需要在數據集中偵測它們。 \n", - "`isnull()` 和 `notnull()` 是偵測空值的主要方法。這兩個方法都會對數據返回布林遮罩。\n" + "既然我們已經了解缺失值的重要性,在處理它們之前,我們需要在數據集中偵測它們。\n", + "`isnull()` 和 `notnull()` 是偵測空值的主要方法。這兩個方法都會返回布林遮罩,覆蓋在你的數據上。\n" ] }, { @@ -978,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "仔細看看輸出的內容。有什麼讓你感到意外的嗎?雖然 `0` 是一個算術上的「空值」,但它仍然是一個完全有效的整數,而 pandas 也將其視為如此。`''` 則稍微微妙一些。雖然我們在第 1 節中使用它來表示一個空字串值,但對 pandas 而言,它仍然是一個字串物件,而不是空值的表示。\n", + "仔細看看輸出的結果,有沒有讓你感到驚訝的地方?雖然 `0` 是一個算術上的空值,但它仍然是一個完全有效的整數,pandas 也將其視為如此。而 `''` 就稍微微妙一些。雖然我們在第 1 節中用它來表示空字串值,但對 pandas 而言,它仍然是一個字串物件,而不是空值的表示。\n", "\n", - "現在,讓我們換個角度,將這些方法以更接近實際使用的方式來應用。你可以直接將布林遮罩用作 ``Series`` 或 ``DataFrame`` 的索引,這在處理孤立的缺失值(或存在值)時非常有用。\n", + "現在,讓我們換個角度,按照實際使用的方式來運用這些方法。你可以直接將布林遮罩用作 ``Series`` 或 ``DataFrame`` 的索引,這在處理孤立的缺失值(或存在的值)時非常有用。\n", "\n", - "如果我們想要計算缺失值的總數,只需對 `isnull()` 方法生成的遮罩進行一次加總即可。\n" + "如果我們想要計算缺失值的總數,只需對 `isnull()` 方法生成的遮罩進行求和即可。\n" ] }, { @@ -1017,7 +1017,7 @@ "id": "PlBqEo3mgRsC" }, "source": [ - "### 運動:\n" + "### 練習:\n" ] }, { @@ -1040,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**主要收穫**:當您在 DataFrame 中使用 `isnull()` 和 `notnull()` 方法時,它們會產生類似的結果:顯示結果及其索引,這將在您處理數據時對您有極大的幫助。\n" + "**主要收穫**:當您在資料框中使用 `isnull()` 和 `notnull()` 方法時,兩者會產生相似的結果:它們顯示結果以及這些結果的索引,這將在您處理數據時提供極大的幫助。\n" ] }, { @@ -1049,18 +1049,18 @@ "id": "BvnoojWsgRr4" }, "source": [ - "### 處理缺失數據\n", + "### 處理遺漏資料\n", "\n", "> **學習目標:** 在本小節結束時,您應該了解如何以及何時替換或移除 DataFrame 中的空值。\n", "\n", - "機器學習模型本身無法處理缺失數據。因此,在將數據傳入模型之前,我們需要先處理這些缺失值。\n", + "機器學習模型本身無法處理遺漏資料。因此,在將資料傳入模型之前,我們需要先處理這些遺漏值。\n", "\n", - "處理缺失數據的方法涉及微妙的取捨,可能會影響您的最終分析結果以及實際應用的效果。\n", + "如何處理遺漏資料涉及微妙的取捨,可能會影響您的最終分析結果以及實際應用的效果。\n", "\n", - "主要有兩種處理缺失數據的方法:\n", + "處理遺漏資料主要有兩種方法:\n", "\n", - "1. 移除包含缺失值的行\n", - "2. 用其他值替換缺失值\n", + "1. 移除包含遺漏值的行\n", + "2. 用其他值替換遺漏值\n", "\n", "我們將詳細討論這兩種方法及其優缺點。\n" ] @@ -1071,13 +1071,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### 刪除空值\n", + "### 移除空值\n", "\n", - "我們傳遞給模型的數據量會直接影響其性能。刪除空值意味著我們減少了數據點的數量,從而縮小了數據集的規模。因此,當數據集相當大時,建議刪除包含空值的行。\n", + "我們傳遞給模型的數據量會直接影響其性能。移除空值意味著我們減少了數據點的數量,因此也減少了數據集的大小。因此,當數據集相當大時,建議移除包含空值的行。\n", "\n", - "另一種情況可能是某一行或列有大量缺失值。在這種情況下,可以刪除它們,因為這些行/列的大部分數據都缺失,對我們的分析幫助不大。\n", + "另一種情況可能是某一行或列有大量缺失值。在這種情況下,可以考慮移除它們,因為該行或列的大部分數據都缺失,對分析的價值不大。\n", "\n", - "除了識別缺失值之外,pandas 還提供了一種方便的方法來從 `Series` 和 `DataFrame` 中移除空值。為了實際了解這一點,我們回到 `example3`。`DataFrame.dropna()` 函數可以幫助刪除包含空值的行。\n" + "除了識別缺失值之外,pandas 還提供了一種方便的方法來從 `Series` 和 `DataFrame` 中移除空值。為了實際了解這一點,我們可以回到 `example3`。`DataFrame.dropna()` 函數可以幫助移除包含空值的行。\n" ] }, { @@ -1116,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "請注意,這應該看起來像是您從 `example3[example3.notnull()]` 的輸出。這裡的不同之處在於,`dropna` 並非僅僅索引遮罩值,而是從 `Series` `example3` 中移除了那些缺失值。\n", + "請注意,這應該看起來像是您從 `example3[example3.notnull()]` 的輸出。這裡的不同之處在於,`dropna` 不僅僅是基於遮罩值進行索引,而是從 `Series` `example3` 中移除了那些缺失值。\n", "\n", - "由於 DataFrame 是二維的,因此在刪除數據時提供了更多選擇。\n" + "由於 DataFrame 是二維的,因此它提供了更多刪除數據的選項。\n" ] }, { @@ -1208,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(你是否注意到 pandas 將其中兩列提升為浮點數類型以容納 `NaN` 值?)\n", + "(你是否注意到 pandas 將其中兩個欄位提升為浮點型,以容納 `NaN` 值?)\n", "\n", - "你無法僅刪除 `DataFrame` 中的一個值,因此必須刪除整行或整列。根據你的需求,你可能會選擇刪除其中一種,而 pandas 提供了這兩種選項。由於在資料科學中,列通常代表變數,行則代表觀測值,因此你更有可能刪除資料的行;`dropna()` 的預設設定是刪除所有包含任何空值的行:\n" + "你無法從 `DataFrame` 中刪除單一值,因此必須刪除整行或整列。根據你的需求,你可能會選擇其中一種方式,因此 pandas 提供了兩種選項。在資料科學中,欄位通常代表變數,行則代表觀測值,因此你更可能刪除包含資料的行;`dropna()` 的預設設定是刪除所有包含任何空值的行:\n" ] }, { @@ -1283,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "如果需要,您可以從列中刪除 NA 值。使用 `axis=1` 來執行:\n" + "如果需要,您可以從列中刪除 NA 值。使用 `axis=1` 來完成:\n" ] }, { @@ -1362,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "請注意,這可能會刪除許多您可能希望保留的數據,特別是在較小的數據集中。如果您只想刪除包含幾個甚至所有空值的行或列該怎麼辦?您可以在 `dropna` 中使用 `how` 和 `thresh` 參數來指定這些設置。\n", + "請注意,這可能會刪除許多您可能希望保留的數據,特別是在較小的數據集中。如果您只想刪除包含多個甚至全部空值的行或列該怎麼辦?您可以在 `dropna` 中使用 `how` 和 `thresh` 參數來指定這些設定。\n", "\n", - "預設情況下,`how='any'`(如果您想自行檢查或查看該方法的其他參數,可以在程式碼單元中執行 `example4.dropna?`)。或者,您可以指定 `how='all'`,這樣只會刪除包含所有空值的行或列。讓我們擴展我們的範例 `DataFrame`,在下一個練習中看看這是如何運作的。\n" + "預設情況下,`how='any'`(如果您想自行檢查或查看該方法的其他參數,可以在程式碼單元中執行 `example4.dropna?`)。您也可以選擇指定 `how='all'`,以便僅刪除包含所有空值的行或列。在下一個練習中,我們將擴展範例 `DataFrame` 來看看這些設定的實際效果。\n" ] }, { @@ -1456,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> 關鍵重點:\n", - "1. 僅在資料集足夠大的情況下,刪除空值才是一個好主意。\n", - "2. 如果某些行或列的大部分數據都缺失,可以刪除整行或整列。\n", - "3. `DataFrame.dropna(axis=)` 方法可以用來刪除空值。`axis` 參數表示是要刪除行還是列。\n", - "4. 還可以使用 `how` 參數。預設值為 `any`,因此它只會刪除包含任意空值的行/列。可以將其設置為 `all`,以指定僅刪除所有值皆為空的行/列。\n" + "> 關鍵要點:\n", + "1. 只有在資料集足夠大的情況下,刪除空值才是明智的選擇。\n", + "2. 如果整行或整列的大部分資料都缺失,可以考慮刪除。\n", + "3. `DataFrame.dropna(axis=)` 方法可用於刪除空值。`axis` 參數表示是要刪除行還是列。\n", + "4. 也可以使用 `how` 參數。預設值為 `any`,因此它只會刪除包含任何空值的行或列。可以將其設置為 `all`,以指定僅刪除所有值均為空的行或列。\n" ] }, { @@ -1492,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "`thresh` 參數提供更細緻的控制:您可以設定一行或一列需要具有的*非空*值數量,以便保留:\n" + "`thresh` 參數提供更細緻的控制:您可以設定一行或一列需要具有的*非空*值的數量,以便保留該行或列:\n" ] }, { @@ -1578,9 +1578,9 @@ "source": [ "### 填補空值\n", "\n", - "有時候,用可能有效的值來填補缺失值是有意義的。填補空值有幾種技術。第一種是使用領域知識(即對數據集所基於主題的了解)來某種程度上估算缺失值。\n", + "有時候填補缺失值為可能有效的值是合理的。有幾種方法可以用來填補空值。第一種方法是使用領域知識(即對數據集所基於的主題的了解)來近似缺失值。\n", "\n", - "你可以使用 `isnull` 直接進行操作,但這可能會很繁瑣,特別是當你有很多值需要填補時。由於這在數據科學中是一個非常常見的任務,pandas 提供了 `fillna`,它會返回一個 `Series` 或 `DataFrame` 的副本,將缺失值替換為你選擇的值。我們來創建另一個範例 `Series`,看看這在實際操作中是如何運作的。\n" + "你可以使用 `isnull` 直接進行操作,但這可能會很繁瑣,特別是當你有大量的值需要填補時。由於這在數據科學中是一個非常常見的任務,pandas 提供了 `fillna` 方法,它會返回一個 `Series` 或 `DataFrame` 的副本,並將缺失值替換為你選擇的值。讓我們創建另一個示例 `Series`,來看看這在實際操作中的效果。\n" ] }, { @@ -1590,11 +1590,11 @@ }, "source": [ "### 類別型資料(非數值型)\n", - "首先,我們來討論非數值型資料。在數據集中,我們可能會有包含類別型資料的欄位,例如性別、True 或 False 等。\n", + "首先讓我們來探討非數值型資料。在資料集中,我們可能會有包含類別型資料的欄位,例如性別、True 或 False 等。\n", "\n", - "在大多數情況下,我們會用該欄位的「眾數」來替換缺失值。假設我們有 100 筆數據,其中 90 筆為 True,8 筆為 False,還有 2 筆未填寫。那麼,我們可以將這 2 筆未填寫的數據補為 True,因為 True 是該欄位的眾數。\n", + "在大多數情況下,我們會用該欄位的`眾數`來替換缺失值。假設我們有 100 筆資料,其中 90 筆是 True,8 筆是 False,還有 2 筆未填寫。那麼,我們可以將這 2 筆未填寫的資料填為 True,基於整個欄位的情況來考量。\n", "\n", - "此外,在這裡我們也可以運用領域知識來進行補值。以下是一個使用眾數進行補值的例子。\n" + "此外,我們也可以運用領域知識來進行填補。以下是一個使用眾數填補的範例。\n" ] }, { @@ -1699,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "現在,讓我們先找到眾數,再用眾數填充 `None` 值。\n" + ] }, { "cell_type": "code", @@ -1734,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "所以,我們將用 True 替換 None\n" + ] }, { "cell_type": "code", @@ -1844,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "正如我們所見,空值已被替換。毋庸置疑,我們本可以在 `'True'` 的位置寫任何內容,它都會被替代。\n" + "如我們所見,空值已被替換。毋庸置疑,我們本可以在 `'True'` 的位置寫任何內容,它都會被替代。\n" ] }, { @@ -1859,11 +1863,11 @@ "1. 用該行的中位數替換\n", "2. 用該行的平均值替換\n", "\n", - "當資料存在偏態且有異常值時,我們使用中位數進行替換。這是因為中位數對異常值具有穩健性。\n", + "如果資料有偏態且存在異常值,我們會選擇用中位數替換。這是因為中位數對異常值具有穩健性。\n", "\n", - "當資料已經正規化時,我們可以使用平均值,因為在這種情況下,平均值和中位數會非常接近。\n", + "當資料已被標準化時,我們可以使用平均值,因為在這種情況下,平均值和中位數會非常接近。\n", "\n", - "首先,我們選擇一個呈正態分佈的欄位,並用該欄的平均值填補缺失值。\n" + "首先,我們選擇一個呈正態分佈的欄位,並用該欄位的平均值填補缺失值。\n" ] }, { @@ -2003,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "填充平均值\n" + ] }, { "cell_type": "code", @@ -2103,7 +2109,7 @@ "id": "CwpVFCrPTC5z" }, "source": [ - "正如我們所見,缺失值已被其平均值取代。\n" + "如我們所見,缺失值已被替換為其平均值。\n" ] }, { @@ -2112,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "現在讓我們嘗試另一個數據框,這次我們將用該列的中位數替換 None 值。\n" + "現在讓我們嘗試另一個數據框架,這次我們將用該列的中位數替換 None 值。\n" ] }, { @@ -2252,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "填充中位數\n" + ] }, { "cell_type": "code", @@ -2352,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "正如我們所見,NaN 值已被該列的中位數取代\n" + "如我們所見,NaN 值已被該列的中位數替換。\n" ] }, { @@ -2394,7 +2402,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "您可以使用單一值(例如 `0`)填充所有的空值條目:\n" + "您可以使用單一值(例如 `0`)填充所有的空值:\n" ] }, { @@ -2436,10 +2444,10 @@ }, "source": [ "> 關鍵要點:\n", - "1. 當數據較少或有策略填補缺失數據時,應進行缺失值填補。\n", - "2. 可以利用領域知識通過近似方法填補缺失值。\n", + "1. 填補缺失值應在數據較少或有填補策略時進行。\n", + "2. 可以利用領域知識來估算並填補缺失值。\n", "3. 對於分類數據,通常使用該列的眾數來替代缺失值。\n", - "4. 對於數值數據,缺失值通常用平均值(針對正規化數據集)或該列的中位數來填補。\n" + "4. 對於數值型數據,缺失值通常以平均值(針對正規化數據集)或該列的中位數來填補。\n" ] }, { @@ -2470,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "您可以使用**向前填充**空值,即使用最後一個有效值來填充空值:\n" + "您可以使用 **前向填充** 空值,即使用最後一個有效值來填充空值:\n" ] }, { @@ -2511,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "您也可以使用**回填**將下一個有效值向後傳播以填補空值:\n" + "您也可以使用 **回填** 將下一個有效值向後傳播以填補空值:\n" ] }, { @@ -2553,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "正如你可能猜到的,這與 DataFrame 的操作方式相同,但你也可以指定一個 `axis` 來填充空值:\n" + "如您所料,這與 DataFrames 的操作方式相同,但您也可以指定一個 `axis` 來填充空值:\n" ] }, { @@ -2726,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "請注意,當先前的值無法用於向前填充時,空值將保留。\n" + "請注意,當前一個值不可用於向前填充時,空值將保持不變。\n" ] }, { @@ -2759,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "您可以創意地使用 `fillna`。例如,我們再來看看 `example4`,但這次讓我們用 `DataFrame` 中所有值的平均值來填補缺失值:\n" + "您可以創造性地使用 `fillna`。例如,我們再次查看 `example4`,但這次我們用 `DataFrame` 中所有值的平均值填充缺失值:\n" ] }, { @@ -2850,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "注意,第 3 欄仍然是空的:預設方向是按行填充值。\n", + "請注意,第 3 欄仍然是空的:預設方向是按行填充值。\n", "\n", - "> **重點提示:** 處理數據集中缺失值的方法有很多種。具體採用的策略(移除、替換,甚至替換的方式)應該根據該數據的特點來決定。隨著你處理和接觸更多數據集,你將更好地掌握如何應對缺失值的技巧。\n" + "> **重點提示:** 處理資料集中缺失值的方法有很多。具體採用的策略(移除、替換,甚至替換的方式)應根據該資料的具體情況來決定。隨著你處理和接觸更多的資料集,你將更能掌握如何應對缺失值的技巧。\n" ] }, { @@ -2861,11 +2869,11 @@ "id": "bauDnESIl9FH" }, "source": [ - "### 編碼分類數據\n", + "### 編碼分類資料\n", "\n", - "機器學習模型只能處理數字以及任何形式的數值數據。它無法分辨「是」和「否」,但能區分 0 和 1。因此,在填補缺失值之後,我們需要將分類數據編碼為某種數字形式,讓模型能夠理解。\n", + "機器學習模型只能處理數字以及任何形式的數值資料。它無法辨別「是」和「否」的差異,但能區分 0 和 1。因此,在填補缺失值之後,我們需要將分類資料編碼成某種數值形式,讓模型能夠理解。\n", "\n", - "編碼可以通過兩種方式完成。我們接下來將討論這些方法。\n" + "編碼可以透過兩種方式完成。我們接下來將討論這些方法。\n" ] }, { @@ -2876,7 +2884,7 @@ "source": [ "**標籤編碼**\n", "\n", - "標籤編碼基本上是將每個類別轉換為一個數字。例如,假設我們有一個航空乘客的數據集,其中有一列包含他們的艙等,分別是 ['business class', 'economy class', 'first class']。如果對這些數據進行標籤編碼,則會被轉換為 [0, 1, 2]。讓我們通過程式碼來看一個例子。由於我們會在接下來的筆記本中學習 `scikit-learn`,這裡我們不會使用它。\n" + "標籤編碼基本上是將每個類別轉換為一個數字。例如,假設我們有一個航空乘客的數據集,其中有一列包含他們的艙等,艙等包括以下類別:['商務艙', '經濟艙', '頭等艙']。如果對這些類別進行標籤編碼,則會被轉換為 [0,1,2]。讓我們通過程式碼來看一個例子。由於我們會在接下來的筆記本中學習 `scikit-learn`,因此這裡不使用它。\n" ] }, { @@ -2984,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "要對第一列執行標籤編碼,我們必須先描述每個類別到數字的映射,然後再進行替換\n" + "要對第一列進行標籤編碼,我們必須先描述每個類別到數字的映射,然後再進行替換\n" ] }, { @@ -3086,10 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "正如我們所見,輸出結果與我們預期的一致。那麼,我們什麼時候使用標籤編碼呢?標籤編碼適用於以下一種或兩種情況:\n", - "\n", - "1. 當類別數量很多時 \n", - "2. 當類別具有順序性時 \n" + "正如我們所見,輸出結果與我們預期的一致。那麼,我們什麼時候使用標籤編碼呢?標籤編碼通常在以下情況之一或兩者都適用時使用:\n", + "1. 當類別數量很大時\n", + "2. 當類別具有順序性時。\n" ] }, { @@ -3100,9 +3107,9 @@ "source": [ "**獨熱編碼**\n", "\n", - "另一種編碼方式是獨熱編碼(One Hot Encoding)。在這種編碼方式中,每個欄位的類別會被新增為一個單獨的欄位,並且每個數據點根據是否包含該類別,分別被賦值為 0 或 1。因此,如果有 n 種不同的類別,則會在資料框中新增 n 個欄位。\n", + "另一種編碼方式是獨熱編碼。在這種編碼方式中,欄位中的每個類別都會被新增為一個獨立的欄位,並且每個數據點會根據是否包含該類別而被賦予 0 或 1。因此,如果有 n 個不同的類別,則會向資料框中新增 n 個欄位。\n", "\n", - "例如,我們以相同的飛機艙等為例。類別為:['business class', 'economy class', 'first class']。那麼,如果我們執行獨熱編碼,數據集中將新增以下三個欄位:['class_business class', 'class_economy class', 'class_first class']。\n" + "例如,讓我們以相同的飛機艙等例子來說。類別是:['商務艙', '經濟艙', '頭等艙']。如果我們執行獨熱編碼,以下三個欄位將被新增到資料集中:['class_business class', 'class_economy class', 'class_first class']。\n" ] }, { @@ -3210,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "讓我們對第一列執行獨熱編碼\n" + "讓我們對第一列進行獨熱編碼\n" ] }, { @@ -3335,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "每個獨熱編碼欄位包含 0 或 1,表示該數據點是否存在該類別。\n" + "每個獨熱編碼的列包含 0 或 1,指定該數據點是否存在該類別。\n" ] }, { @@ -3344,11 +3351,10 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "什麼時候使用獨熱編碼(One Hot Encoding)? \n", - "獨熱編碼通常在以下一種或兩種情況下使用:\n", + "我們何時使用獨熱編碼?獨熱編碼通常在以下其中一種或兩種情況下使用:\n", "\n", - "1. 當類別數量和數據集的規模較小時。\n", - "2. 當類別之間沒有特定的順序時。\n" + "1. 當分類數量和資料集的大小較小時。\n", + "2. 當分類沒有特定的順序時。\n" ] }, { @@ -3357,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> 關鍵重點: \n", - "1. 編碼的目的是將非數值型資料轉換為數值型資料。 \n", - "2. 編碼主要有兩種類型:標籤編碼(Label encoding)和獨熱編碼(One Hot encoding),可以根據資料集的需求選擇使用。 \n" + "> 主要重點:\n", + "1. 編碼是將非數值型資料轉換為數值型資料的過程。\n", + "2. 編碼有兩種類型:標籤編碼和獨熱編碼,可以根據資料集的需求進行選擇。\n" ] }, { @@ -3368,11 +3374,11 @@ "id": "K8UXOJYRgRsJ" }, "source": [ - "## 移除重複數據\n", + "## 移除重複資料\n", "\n", "> **學習目標:** 在本小節結束時,您應該能夠熟練地識別並移除 DataFrame 中的重複值。\n", "\n", - "除了缺失數據之外,您在處理真實世界的數據集時,經常會遇到重複的數據。幸運的是,pandas 提供了一種簡單的方法來檢測和移除重複的條目。\n" + "除了遺漏資料之外,您在真實世界的數據集中經常會遇到重複的資料。幸運的是,pandas 提供了一個簡便的方法來檢測和移除重複的項目。\n" ] }, { @@ -3381,9 +3387,9 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### 識別重複值:`duplicated`\n", + "### 識別重複項目:`duplicated`\n", "\n", - "你可以使用 pandas 的 `duplicated` 方法輕鬆找出重複的值。該方法會返回一個布林遮罩,指示 `DataFrame` 中某個條目是否是之前條目的重複值。讓我們創建另一個範例 `DataFrame` 來實際看看這個方法的效果。\n" + "您可以使用 pandas 中的 `duplicated` 方法輕鬆找到重複的值。該方法會返回一個布林遮罩,指示 `DataFrame` 中的某個項目是否是之前項目的重複。讓我們建立另一個範例 `DataFrame` 來看看它的運作方式。\n" ] }, { @@ -3512,7 +3518,7 @@ "id": "0eDRJD4SgRsK" }, "source": [ - "### 刪除重複值:`drop_duplicates`\n", + "### 刪除重複項:`drop_duplicates`\n", "`drop_duplicates` 會返回一份數據的副本,其中所有 `duplicated` 值均為 `False`:\n" ] }, @@ -3672,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **重點:** 移除重複數據是幾乎每個數據科學項目中不可或缺的一部分。重複數據可能會改變您的分析結果並導致不準確的結論!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 真實世界的數據品質檢查\n", + "\n", + "> **學習目標:** 在本節結束時,您應該能夠熟練地檢測並修正常見的真實世界數據品質問題,包括不一致的分類值、異常的數值(離群值)以及具有變化的重複實體。\n", + "\n", + "雖然缺失值和完全重複是常見問題,但真實世界的數據集通常包含更微妙的問題:\n", + "\n", + "1. **不一致的分類值**:同一分類以不同方式拼寫(例如:\"USA\"、\"U.S.A\"、\"United States\")\n", + "2. **異常的數值**:極端的離群值可能表示數據輸入錯誤(例如,年齡 = 999)\n", + "3. **近似重複的行**:表示同一實體但有些微差異的記錄\n", + "\n", + "讓我們來探討檢測和處理這些問題的技巧。\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 建立範例「髒」資料集\n", + "\n", + "首先,讓我們建立一個範例資料集,其中包含我們在真實世界數據中常見的問題類型:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. 偵測不一致的分類值\n", + "\n", + "注意到 `country` 欄位中,同一個國家有多種表示方式。讓我們來識別這些不一致之處:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 標準化分類值\n", + "\n", + "我們可以建立一個映射來標準化這些值。一個簡單的方法是將值轉換為小寫並建立一個映射字典:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**替代方法:使用模糊匹配**\n", + "\n", + "對於更複雜的情況,我們可以使用 `rapidfuzz` 庫進行模糊字符串匹配,以自動檢測相似的字符串:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. 偵測異常數值(離群值)\n", + "\n", + "查看 `age` 欄位時,我們發現一些可疑的數值,例如 199 和 -5。讓我們使用統計方法來偵測這些離群值。\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 使用 IQR(四分位距)方法\n", + "\n", + "IQR 方法是一種穩健的統計技術,用於檢測異常值,且對極端值的敏感性較低:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 使用 Z 分數方法\n", + "\n", + "Z 分數方法根據與平均值的標準差來識別異常值:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 處理異常值\n", + "\n", + "一旦檢測到異常值,可以用以下幾種方式處理:\n", + "1. **移除**:刪除包含異常值的行(如果它們是錯誤)\n", + "2. **限制**:用邊界值替代\n", + "3. **替換為 NaN**:視為缺失數據並使用插補技術\n", + "4. **保留**:如果它們是合法的極端值\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. 偵測近似重複的行\n", + "\n", + "注意,我們的數據集中有多個「John Smith」的條目,且值略有不同。我們來根據名字的相似性識別潛在的重複項。\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 使用模糊匹配尋找近似重複項\n", + "\n", + "為了進行更高級的重複檢測,我們可以使用模糊匹配來尋找相似的名稱:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 處理重複項\n", + "\n", + "一旦識別出來,您需要決定如何處理重複項:\n", + "1. **保留第一次出現**:使用 `drop_duplicates(keep='first')`\n", + "2. **保留最後一次出現**:使用 `drop_duplicates(keep='last')`\n", + "3. **聚合資訊**:合併重複行中的資訊\n", + "4. **人工審查**:標記以供人工審查\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 摘要:完整的資料清理流程\n", + "\n", + "讓我們將所有內容整合成一個全面的清理流程:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 挑戰練習\n", + "\n", + "現在輪到你了!以下是一行包含多個品質問題的新數據。你能否:\n", + "\n", + "1. 找出這行數據中的所有問題\n", + "2. 撰寫程式碼來清理每個問題\n", + "3. 將清理後的數據行添加到數據集\n", + "\n", + "以下是有問題的數據:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 關鍵要點\n", + "\n", + "1. **分類不一致**在真實世界的數據中很常見。務必檢查唯一值,並使用映射或模糊匹配來標準化它們。\n", + "\n", + "2. **異常值**可能會對分析產生重大影響。結合領域知識與統計方法(如 IQR、Z-score)來檢測異常值。\n", + "\n", + "3. **近似重複項**比完全重複項更難檢測。考慮使用模糊匹配並對數據進行標準化(如轉小寫、去除空白)來識別它們。\n", + "\n", + "4. **數據清理是反覆進行的過程**。可能需要應用多種技術並檢查結果,才能最終完成清理後的數據集。\n", + "\n", + "5. **記錄你的決策**。追蹤你所採用的清理步驟及其原因,這對於可重現性和透明度非常重要。\n", + "\n", + "> **最佳實踐:**務必保留原始的「髒」數據副本。切勿覆蓋原始數據文件,應創建清理後的版本,並使用清晰的命名規則,例如 `data_cleaned.csv`。\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**免責聲明**: \n本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。\n" + "\n---\n\n**免責聲明**: \n本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或誤釋不承擔責任。\n" ] } ], @@ -3706,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T08:15:52+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:25:37+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "tw" } diff --git a/translations/uk/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/uk/2-Working-With-Data/08-data-preparation/notebook.ipynb index 40de1de6..93a1067a 100644 --- a/translations/uk/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/uk/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -12,9 +12,9 @@ "\n", "## Дослідження інформації про `DataFrame`\n", "\n", - "> **Мета навчання:** До кінця цього підрозділу ви повинні впевнено знаходити загальну інформацію про дані, що зберігаються в pandas DataFrame.\n", + "> **Мета навчання:** До кінця цього підрозділу ви повинні впевнено знаходити загальну інформацію про дані, збережені в pandas DataFrames.\n", "\n", - "Коли ви завантажуєте свої дані в pandas, вони, швидше за все, будуть у форматі `DataFrame`. Але якщо ваш набір даних у `DataFrame` містить 60,000 рядків і 400 стовпців, як взагалі почати розуміти, з чим ви працюєте? На щастя, pandas надає зручні інструменти для швидкого перегляду загальної інформації про `DataFrame`, а також перших і останніх кількох рядків.\n", + "Коли ви завантажуєте свої дані в pandas, вони, швидше за все, будуть у форматі `DataFrame`. Але якщо набір даних у вашому `DataFrame` містить 60,000 рядків і 400 стовпців, як взагалі почати розуміти, з чим ви працюєте? На щастя, pandas надає зручні інструменти для швидкого перегляду загальної інформації про `DataFrame`, а також перших і останніх кількох рядків.\n", "\n", "Щоб дослідити цю функціональність, ми імпортуємо бібліотеку Python scikit-learn і використаємо знаковий набір даних, який кожен дата-сайєнтист бачив сотні разів: набір даних британського біолога Рональда Фішера *Iris*, використаний у його статті 1936 року \"Використання множинних вимірювань у таксономічних проблемах\":\n" ] @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Ми завантажили набір даних Iris у змінну `iris_df`. Перед тим як заглиблюватися в дані, буде корисно дізнатися кількість точок даних, які ми маємо, і загальний розмір набору даних. Це допоможе оцінити обсяг даних, з якими ми працюємо.\n" + "Ми завантажили набір даних Iris у змінну `iris_df`. Перед тим як заглиблюватися в дані, було б корисно дізнатися кількість точок даних, які ми маємо, і загальний розмір набору даних. Це допоможе оцінити обсяг даних, з якими ми працюємо.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Отже, ми маємо 150 рядків і 4 стовпці даних. Кожен рядок представляє одну точку даних, а кожен стовпець відповідає за одну характеристику, пов’язану з фреймом даних. Тобто, у нас є 150 точок даних, кожна з яких містить 4 характеристики.\n", + "Отже, ми маємо справу з 150 рядками та 4 стовпцями даних. Кожен рядок представляє одну точку даних, а кожен стовпець представляє одну ознаку, пов'язану з датафреймом. Тобто, є 150 точок даних, кожна з яких містить 4 ознаки.\n", "\n", - "`shape` тут є атрибутом фрейму даних, а не функцією, тому він не закінчується парою круглих дужок.\n" + "`shape` тут є атрибутом датафрейму, а не функцією, тому він не закінчується парою круглих дужок.\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "Як ми можемо бачити, є чотири (4) стовпці. Атрибут `columns` повідомляє нам назви стовпців і, в основному, нічого більше. Цей атрибут набуває важливості, коли ми хочемо визначити характеристики, які містить набір даних.\n" + "Як ми бачимо, є чотири (4) стовпці. Атрибут `columns` повідомляє нам назви стовпців і, в основному, нічого більше. Цей атрибут набуває важливості, коли ми хочемо визначити характеристики, які містить набір даних.\n" ] }, { @@ -180,9 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "Звідси можна зробити кілька спостережень: \n", - "1. Тип даних кожного стовпця: У цьому наборі даних усі дані зберігаються у вигляді 64-бітних чисел з плаваючою комою. \n", - "2. Кількість ненульових значень: Робота з нульовими значеннями є важливим етапом підготовки даних. Це буде розглянуто пізніше у зошиті. \n" + "Звідси ми можемо зробити кілька спостережень:\n", + "1. Тип даних кожного стовпця: У цьому наборі даних вся інформація зберігається у вигляді 64-бітних чисел з плаваючою точкою.\n", + "2. Кількість ненульових значень: Робота з нульовими значеннями є важливим етапом підготовки даних. Це буде розглянуто пізніше в блокноті.\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "З усіма вищезазначеними функціями та атрибутами ми отримали загальний огляд набору даних. Ми знаємо, скільки є точок даних, скільки є ознак, який тип даних у кожної ознаки та скільки ненульових значень має кожна ознака.\n", + "З усіма наведеними функціями та атрибутами ми отримали загальний огляд набору даних. Ми знаємо, скільки точок даних є, скільки ознак, тип даних кожної ознаки та кількість ненульових значень для кожної ознаки.\n", "\n", - "Тепер настав час подивитися на самі дані. Давайте подивимося, як виглядають перші кілька рядків (перші кілька точок даних) нашого `DataFrame`:\n" + "Тепер настав час поглянути на самі дані. Давайте подивимося, як виглядають перші кілька рядків (перші кілька точок даних) нашого `DataFrame`:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Як видно з результату, тут представлено п'ять (5) записів набору даних. Якщо подивитися на індекс зліва, то можна побачити, що це перші п'ять рядків.\n" + "Як видно з результату, тут є п'ять (5) записів набору даних. Якщо подивитися на індекс зліва, ми дізнаємося, що це перші п'ять рядків.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Вправа:\n", "\n", - "З наведеного прикладу видно, що за замовчуванням `DataFrame.head` повертає перші п'ять рядків `DataFrame`. У кодовій комірці нижче, чи можете ви знайти спосіб відобразити більше ніж п'ять рядків?\n" + "З наведеного вище прикладу зрозуміло, що за замовчуванням `DataFrame.head` повертає перші п'ять рядків `DataFrame`. У кодовій комірці нижче, чи можете ви знайти спосіб відобразити більше ніж п'ять рядків?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Інший спосіб перегляду даних — це почати з кінця (замість початку). Протилежністю до `DataFrame.head` є `DataFrame.tail`, який повертає останні п'ять рядків `DataFrame`:\n" + "Інший спосіб перегляду даних — це почати з кінця (замість початку). Протилежністю `DataFrame.head` є `DataFrame.tail`, який повертає останні п'ять рядків `DataFrame`:\n" ] }, { @@ -586,7 +586,7 @@ "\n", "Усі функції та атрибути, показані вище за допомогою прикладів коду, допомагають нам отримати уявлення про дані.\n", "\n", - "> **Висновок:** Навіть просто переглянувши метадані про інформацію в DataFrame або перші й останні кілька значень, ви можете одразу отримати уявлення про розмір, форму та зміст даних, з якими ви працюєте.\n" + "> **Висновок:** Навіть просто переглянувши метадані про інформацію в DataFrame або перші й останні кілька значень, ви можете одразу отримати уявлення про розмір, форму та зміст даних, з якими працюєте.\n" ] }, { @@ -600,13 +600,13 @@ "\n", "Розглянемо приклад: припустимо, хтось дуже переймається своєю вагою і не заповнює поле \"вага\" в опитуванні. У такому випадку значення ваги для цієї людини буде відсутнім.\n", "\n", - "У більшості випадків у реальних наборах даних зустрічаються відсутні значення.\n", + "У більшості випадків у реальних наборах даних трапляються відсутні значення.\n", "\n", "**Як Pandas обробляє відсутні дані**\n", "\n", - "Pandas обробляє відсутні значення двома способами. Перший ви вже бачили в попередніх розділах: `NaN`, або Not a Number (не число). Це насправді спеціальне значення, яке є частиною специфікації IEEE для чисел з плаваючою комою, і воно використовується лише для позначення відсутніх значень з плаваючою комою.\n", + "Pandas обробляє відсутні значення двома способами. Перший спосіб ви вже бачили в попередніх розділах: `NaN`, або Not a Number. Це насправді спеціальне значення, яке є частиною специфікації IEEE для чисел з плаваючою точкою, і воно використовується лише для позначення відсутніх значень типу float.\n", "\n", - "Для відсутніх значень, які не є числами з плаваючою комою, pandas використовує об'єкт Python `None`. Хоча може здатися заплутаним, що ви зустрічаєте два різних типи значень, які по суті означають одне й те саме, існують обґрунтовані програмні причини для такого вибору дизайну. На практиці це дозволяє pandas забезпечити хороший компроміс для переважної більшості випадків. Незважаючи на це, і `None`, і `NaN` мають обмеження, про які вам потрібно пам'ятати щодо того, як їх можна використовувати.\n" + "Для відсутніх значень, які не є числами з плаваючою точкою, pandas використовує об'єкт Python `None`. Хоча може здатися заплутаним, що ви зустрічаєте два різні типи значень, які фактично означають одне й те саме, існують обґрунтовані програмні причини для такого вибору дизайну. На практиці це дозволяє pandas забезпечити хороший компроміс для переважної більшості випадків. Незважаючи на це, як `None`, так і `NaN` мають обмеження, про які потрібно пам'ятати щодо того, як їх можна використовувати.\n" ] }, { @@ -615,8 +615,8 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`: відсутні дані не типу float\n", - "Оскільки `None` походить із Python, його не можна використовувати в масивах NumPy та pandas, які не мають типу даних `'object'`. Пам’ятайте, що масиви NumPy (і структури даних у pandas) можуть містити лише один тип даних. Це надає їм величезну потужність для роботи з великими обсягами даних і обчислень, але також обмежує їхню гнучкість. Такі масиви повинні бути приведені до \"найменшого спільного знаменника\", тобто до типу даних, який охоплює все в масиві. Коли в масиві є `None`, це означає, що ви працюєте з об’єктами Python.\n", + "### `None`: відсутні дані, які не є числами з плаваючою точкою\n", + "Оскільки `None` походить з Python, його не можна використовувати в масивах NumPy і pandas, які не мають типу даних `'object'`. Пам’ятайте, що масиви NumPy (і структури даних у pandas) можуть містити лише один тип даних. Це надає їм величезну потужність для роботи з великими обсягами даних і обчислень, але також обмежує їхню гнучкість. Такі масиви повинні бути приведені до \"найнижчого спільного знаменника\", тобто типу даних, який охоплює все в масиві. Коли в масиві є `None`, це означає, що ви працюєте з об'єктами Python.\n", "\n", "Щоб побачити це на практиці, розгляньте наступний приклад масиву (зверніть увагу на його `dtype`):\n" ] @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Реальність підвищення типів даних має два побічні ефекти. По-перше, операції виконуватимуться на рівні інтерпретованого коду Python, а не скомпільованого коду NumPy. По суті, це означає, що будь-які операції, які включають `Series` або `DataFrames` з `None`, будуть повільнішими. Хоча ви, ймовірно, не помітите цього впливу на продуктивність, для великих наборів даних це може стати проблемою.\n", + "Реальність підвищення типів даних має два побічні ефекти. По-перше, операції виконуватимуться на рівні інтерпретованого коду Python, а не компільованого коду NumPy. По суті, це означає, що будь-які операції, які включають `Series` або `DataFrames` із `None`, будуть повільнішими. Хоча ви, ймовірно, не помітите цього впливу на продуктивність, для великих наборів даних це може стати проблемою.\n", "\n", - "Другий побічний ефект випливає з першого. Оскільки `None` фактично повертає `Series` або `DataFrame` у світ звичайного Python, використання агрегацій NumPy/pandas, таких як `sum()` або `min()`, на масивах, які містять значення ``None``, зазвичай призведе до помилки:\n" + "Другий побічний ефект випливає з першого. Оскільки `None` фактично повертає `Series` або `DataFrame` у світ звичайного Python, використання агрегатів NumPy/pandas, таких як `sum()` або `min()` на масивах, які містять значення ``None``, зазвичай призведе до помилки:\n" ] }, { @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**Основний висновок**: Додавання (та інші операції) між цілими числами та значеннями `None` є невизначеним, що може обмежити можливості роботи з наборами даних, які їх містять.\n" + ] }, { "cell_type": "markdown", @@ -707,7 +709,7 @@ "source": [ "### `NaN`: відсутні значення типу float\n", "\n", - "На відміну від `None`, NumPy (а отже, і pandas) підтримує `NaN` для швидких, векторизованих операцій та ufuncs. Погана новина полягає в тому, що будь-яка арифметична операція з `NaN` завжди дає результат `NaN`. Наприклад:\n" + "На відміну від `None`, NumPy (а отже і pandas) підтримує `NaN` для швидких, векторизованих операцій та ufuncs. Погана новина полягає в тому, що будь-яка арифметична операція з `NaN` завжди дає результат `NaN`. Наприклад:\n" ] }, { @@ -770,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Хороша новина: агрегації, які виконуються на масивах із `NaN`, не викликають помилок. Погана новина: результати не завжди корисні:\n" + "Хороша новина: агрегації, які виконуються на масивах з `NaN`, не викликають помилок. Погана новина: результати не завжди корисні:\n" ] }, { @@ -806,7 +808,9 @@ "metadata": { "id": "nhlnNJT7gRr_" }, - "source": [] + "source": [ + "### Вправа:\n" + ] }, { "cell_type": "code", @@ -826,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "Пам'ятайте: `NaN` призначений лише для відсутніх значень з плаваючою точкою; немає еквівалента `NaN` для цілих чисел, рядків або булевих значень.\n" + ] }, { "cell_type": "markdown", @@ -834,9 +840,9 @@ "id": "kj6EKdsAgRsA" }, "source": [ - "### `NaN` та `None`: нульові значення в pandas\n", + "### `NaN` і `None`: нульові значення в pandas\n", "\n", - "Хоча `NaN` і `None` можуть поводитися трохи по-різному, pandas все ж створений для роботи з ними як взаємозамінними. Щоб зрозуміти, про що йдеться, розглянемо `Series` цілих чисел:\n" + "Хоча `NaN` і `None` можуть поводитися трохи по-різному, pandas все ж створений для роботи з ними як взаємозамінними. Щоб зрозуміти, що мається на увазі, розглянемо `Series` цілих чисел:\n" ] }, { @@ -875,7 +881,9 @@ "metadata": { "id": "WklCzqb8gRsB" }, - "source": [] + "source": [ + "### Вправа:\n" + ] }, { "cell_type": "code", @@ -898,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "У процесі підвищення типів даних для забезпечення однорідності даних у `Series` та `DataFrame`, pandas охоче змінює відсутні значення між `None` та `NaN`. Через цю особливість дизайну корисно розглядати `None` та `NaN` як два різні варіанти \"нульових\" значень у pandas. Дійсно, деякі основні методи, які ви будете використовувати для роботи з відсутніми значеннями в pandas, відображають цю ідею у своїх назвах:\n", + "У процесі приведення типів даних до однорідності в `Series` та `DataFrame`, pandas легко змінює відсутні значення між `None` та `NaN`. Через цю особливість дизайну корисно розглядати `None` та `NaN` як два різні види \"null\" у pandas. Насправді, деякі основні методи, які ви будете використовувати для роботи з відсутніми значеннями в pandas, відображають цю ідею у своїх назвах:\n", "\n", - "- `isnull()`: Генерує булеву маску, що вказує на відсутні значення\n", + "- `isnull()`: Створює булеву маску, яка вказує на відсутні значення\n", "- `notnull()`: Протилежність `isnull()`\n", "- `dropna()`: Повертає відфільтровану версію даних\n", - "- `fillna()`: Повертає копію даних із заповненими або заміщеними відсутніми значеннями\n", + "- `fillna()`: Повертає копію даних із заповненими або заміненими відсутніми значеннями\n", "\n", - "Це важливі методи, які варто освоїти та навчитися використовувати впевнено, тому давайте розглянемо кожен із них детальніше.\n" + "Це важливі методи, які варто освоїти та використовувати впевнено, тому давайте розглянемо кожен із них детальніше.\n" ] }, { @@ -970,9 +978,9 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Подивіться уважно на результат. Чи щось у ньому вас дивує? Хоча `0` є арифметичним нулем, він все ж таки є цілком коректним цілим числом, і pandas розглядає його саме так. `''` є трохи більш тонким випадком. Хоча ми використовували його в Розділі 1 для позначення порожнього рядка, він все ж таки є об'єктом рядка, а не представленням null з точки зору pandas.\n", + "Уважно подивіться на результат. Чи щось у ньому вас здивувало? Хоча `0` є арифметичним нулем, він все ж таки є цілком коректним цілим числом, і pandas сприймає його саме так. `''` є трохи складнішим випадком. Хоча ми використовували його в Розділі 1 для позначення порожнього рядка, він все ж таки є об'єктом типу рядок, а не представленням null з точки зору pandas.\n", "\n", - "Тепер давайте розглянемо це з іншого боку і використаємо ці методи так, як ви, ймовірно, будете використовувати їх на практиці. Ви можете використовувати булеві маски безпосередньо як індекс для ``Series`` або ``DataFrame``, що може бути корисним, коли ви працюєте з ізольованими відсутніми (або присутніми) значеннями.\n", + "Тепер давайте розглянемо це з іншого боку і використаємо ці методи так, як ви, ймовірно, будете використовувати їх на практиці. Ви можете використовувати булеві маски безпосередньо як індекс для ``Series`` або ``DataFrame``, що може бути корисним, коли потрібно працювати з ізольованими відсутніми (або наявними) значеннями.\n", "\n", "Якщо ми хочемо отримати загальну кількість відсутніх значень, ми можемо просто виконати сумування за маскою, створеною методом `isnull()`.\n" ] @@ -1008,7 +1016,9 @@ "metadata": { "id": "PlBqEo3mgRsC" }, - "source": [] + "source": [ + "### Вправа:\n" + ] }, { "cell_type": "code", @@ -1030,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Основний висновок**: Обидва методи `isnull()` та `notnull()` дають схожі результати, коли ви використовуєте їх у DataFrame: вони показують результати та індекс цих результатів, що значно допоможе вам у роботі з вашими даними.\n" + "**Основний висновок**: Обидва методи `isnull()` та `notnull()` дають схожі результати при використанні в DataFrame: вони показують результати та індекс цих результатів, що значно допоможе вам у роботі з вашими даними.\n" ] }, { @@ -1041,13 +1051,13 @@ "source": [ "### Робота з відсутніми даними\n", "\n", - "> **Ціль навчання:** Після завершення цього підрозділу ви повинні знати, як і коли замінювати або видаляти нульові значення з DataFrame.\n", + "> **Мета навчання:** Після завершення цього підрозділу ви повинні знати, як і коли замінювати або видаляти нульові значення з DataFrames.\n", "\n", - "Моделі машинного навчання не можуть самостійно працювати з відсутніми даними. Тому перед тим, як передати дані в модель, необхідно впоратися з цими відсутніми значеннями.\n", + "Моделі машинного навчання не можуть самостійно працювати з відсутніми даними. Тому перед тим, як передати дані в модель, необхідно вирішити проблему з цими відсутніми значеннями.\n", "\n", - "Те, як ви обробляєте відсутні дані, має свої тонкі компроміси, які можуть вплинути на ваш остаточний аналіз і результати в реальному світі.\n", + "Те, як обробляються відсутні дані, має тонкі компроміси, може вплинути на ваш остаточний аналіз і результати в реальному світі.\n", "\n", - "Існує два основних способи роботи з відсутніми даними:\n", + "Існує два основних способи вирішення проблеми з відсутніми даними:\n", "\n", "1. Видалити рядок, що містить відсутнє значення\n", "2. Замінити відсутнє значення на інше значення\n", @@ -1061,13 +1071,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### Видалення порожніх значень\n", + "### Видалення нульових значень\n", "\n", - "Кількість даних, які ми передаємо нашій моделі, безпосередньо впливає на її продуктивність. Видалення порожніх значень означає, що ми зменшуємо кількість точок даних, а отже, і розмір набору даних. Тому рекомендується видаляти рядки з порожніми значеннями, якщо набір даних є досить великим.\n", + "Кількість даних, які ми передаємо нашій моделі, безпосередньо впливає на її продуктивність. Видалення нульових значень означає, що ми зменшуємо кількість точок даних, а отже, зменшуємо розмір набору даних. Тому рекомендується видаляти рядки з нульовими значеннями, якщо набір даних досить великий.\n", "\n", - "Інший випадок може бути, коли певний рядок або стовпець має багато відсутніх значень. Тоді їх можна видалити, оскільки вони не додадуть великої цінності до нашого аналізу, адже більшість даних для цього рядка/стовпця відсутня.\n", + "Інший випадок може бути, коли певний рядок або стовпець має багато відсутніх значень. Тоді їх можна видалити, оскільки вони не додадуть великої цінності до нашого аналізу, адже більшість даних для цього рядка/стовпця відсутні.\n", "\n", - "Окрім ідентифікації відсутніх значень, pandas надає зручний спосіб видалення порожніх значень із `Series` та `DataFrame`. Щоб побачити це на практиці, повернемося до `example3`. Функція `DataFrame.dropna()` допомагає видаляти рядки з порожніми значеннями.\n" + "Окрім виявлення відсутніх значень, pandas надає зручний спосіб видалення нульових значень із `Series` та `DataFrame`. Щоб побачити це на практиці, повернемося до `example3`. Функція `DataFrame.dropna()` допомагає видаляти рядки з нульовими значеннями.\n" ] }, { @@ -1106,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "Зверніть увагу, що це має виглядати як ваш результат з `example3[example3.notnull()]`. Різниця тут у тому, що, замість просто індексації за замаскованими значеннями, `dropna` видалив ці відсутні значення з `Series` `example3`.\n", + "Зверніть увагу, що це має виглядати як ваш результат з `example3[example3.notnull()]`. Різниця тут полягає в тому, що, замість просто індексації за маскованими значеннями, `dropna` видалив ці відсутні значення з `Series` `example3`.\n", "\n", - "Оскільки DataFrame мають два виміри, вони надають більше можливостей для видалення даних.\n" + "Оскільки DataFrame має два виміри, він надає більше варіантів для видалення даних.\n" ] }, { @@ -1200,7 +1210,7 @@ "source": [ "(Чи помітили ви, що pandas перетворив два стовпці на тип float, щоб врахувати `NaN`?)\n", "\n", - "Ви не можете видалити окреме значення з `DataFrame`, тому доведеться видаляти цілі рядки або стовпці. Залежно від того, що ви робите, вам може знадобитися один або інший варіант, і pandas надає можливості для обох. Оскільки в аналізі даних стовпці зазвичай представляють змінні, а рядки — спостереження, частіше за все ви будете видаляти рядки даних; налаштування за замовчуванням для `dropna()` — видаляти всі рядки, які містять будь-які null-значення:\n" + "Ви не можете видалити окреме значення з `DataFrame`, тому доведеться видаляти цілі рядки або стовпці. Залежно від того, що ви робите, вам може знадобитися одне або інше, і pandas надає вам можливості для обох варіантів. Оскільки в аналізі даних стовпці зазвичай представляють змінні, а рядки — спостереження, частіше за все видаляють рядки даних; налаштування за замовчуванням для `dropna()` — видаляти всі рядки, які містять будь-які null-значення:\n" ] }, { @@ -1273,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "Якщо необхідно, ви можете видалити значення NA зі стовпців. Використовуйте `axis=1`, щоб зробити це:\n" + "Якщо необхідно, ви можете видалити значення NA з колонок. Використовуйте `axis=1`, щоб зробити це:\n" ] }, { @@ -1352,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "Зверніть увагу, що це може призвести до втрати значної кількості даних, які ви, можливо, хотіли б зберегти, особливо у менших наборах даних. Що робити, якщо ви хочете видалити лише ті рядки або стовпці, які містять кілька або навіть усі значення, що дорівнюють null? Ви можете налаштувати ці параметри у `dropna` за допомогою параметрів `how` та `thresh`.\n", + "Зверніть увагу, що це може призвести до втрати великої кількості даних, які ви, можливо, хочете зберегти, особливо у менших наборах даних. Що робити, якщо ви хочете видалити лише ті рядки або стовпці, які містять кілька або навіть усі значення, що дорівнюють null? Ви можете налаштувати ці параметри у `dropna` за допомогою параметрів `how` і `thresh`.\n", "\n", - "За замовчуванням `how='any'` (якщо ви хочете перевірити самостійно або побачити, які інші параметри має цей метод, запустіть `example4.dropna?` у кодовій комірці). Ви також можете вказати `how='all'`, щоб видалити лише ті рядки або стовпці, які містять усі значення, що дорівнюють null. Давайте розширимо наш приклад `DataFrame`, щоб побачити це в дії у наступній вправі.\n" + "За замовчуванням `how='any'` (якщо ви хочете перевірити самостійно або побачити, які інші параметри має цей метод, виконайте `example4.dropna?` у кодовій комірці). Ви також можете вказати `how='all'`, щоб видалити лише ті рядки або стовпці, які містять усі значення null. Давайте розширимо наш приклад `DataFrame`, щоб побачити це в дії у наступній вправі.\n" ] }, { @@ -1446,11 +1456,11 @@ "id": "pNZer7q9JPNC" }, "source": [ - "> Основні висновки: \n", - "1. Видаляти порожні значення доцільно лише тоді, коли набір даних є достатньо великим. \n", - "2. Повні рядки або стовпці можна видаляти, якщо в них відсутня більшість даних. \n", - "3. Метод `DataFrame.dropna(axis=)` допомагає видаляти порожні значення. Аргумент `axis` вказує, чи потрібно видаляти рядки, чи стовпці. \n", - "4. Також можна використовувати аргумент `how`. За замовчуванням він встановлений на `any`. Таким чином, видаляються лише ті рядки/стовпці, які містять будь-які порожні значення. Його можна встановити на `all`, щоб вказати, що будуть видалені лише ті рядки/стовпці, де всі значення є порожніми. \n" + "> Основні моменти:\n", + "1. Видаляти порожні значення варто лише тоді, коли набір даних достатньо великий.\n", + "2. Повні рядки або стовпці можна видаляти, якщо більшість їхніх даних відсутні.\n", + "3. Метод `DataFrame.dropna(axis=)` допомагає видаляти порожні значення. Аргумент `axis` визначає, чи потрібно видаляти рядки, чи стовпці.\n", + "4. Можна також використовувати аргумент `how`. За замовчуванням він встановлений на `any`, тому видаляються лише ті рядки/стовпці, які містять будь-які порожні значення. Його можна встановити на `all`, щоб вказати, що будуть видалені лише ті рядки/стовпці, де всі значення порожні.\n" ] }, { @@ -1458,7 +1468,9 @@ "metadata": { "id": "oXXSfQFHgRsF" }, - "source": [] + "source": [ + "### Вправа:\n" + ] }, { "cell_type": "code", @@ -1480,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "Параметр `thresh` надає вам більш детальний контроль: ви встановлюєте кількість *ненульових* значень, які рядок або стовпець повинні мати, щоб бути збереженими:\n" + "Параметр `thresh` надає вам більш детальний контроль: ви встановлюєте кількість *не-null* значень, які рядок або стовпець повинні мати, щоб бути збереженими:\n" ] }, { @@ -1554,7 +1566,9 @@ "metadata": { "id": "fmSFnzZegRsG" }, - "source": [] + "source": [ + "Тут перший і останній рядки були видалені, оскільки вони містять лише два ненульові значення.\n" + ] }, { "cell_type": "markdown", @@ -1564,9 +1578,9 @@ "source": [ "### Заповнення пропущених значень\n", "\n", - "Іноді має сенс заповнити пропущені значення такими, які можуть бути допустимими. Існує кілька методів для заповнення null-значень. Перший — використання галузевих знань (знання предметної області, на якій базується набір даних) для приблизного визначення пропущених значень.\n", + "Іноді має сенс заповнити пропущені значення такими, які можуть бути дійсними. Існує кілька методів для заповнення null-значень. Перший — використання галузевих знань (знання предметної області, на якій базується набір даних) для приблизного визначення пропущених значень.\n", "\n", - "Ви можете використовувати `isnull` для цього безпосередньо, але це може бути трудомістким, особливо якщо потрібно заповнити багато значень. Оскільки це дуже поширене завдання в аналізі даних, pandas надає метод `fillna`, який повертає копію `Series` або `DataFrame` з пропущеними значеннями, заміненими на ті, які ви обрали. Давайте створимо ще один приклад `Series`, щоб побачити, як це працює на практиці.\n" + "Ви можете використовувати `isnull` для заповнення значень безпосередньо, але це може бути трудомістким, особливо якщо потрібно заповнити багато значень. Оскільки це дуже поширене завдання в аналізі даних, pandas пропонує метод `fillna`, який повертає копію `Series` або `DataFrame` з пропущеними значеннями, заміненими на ті, які ви обрали. Давайте створимо ще один приклад `Series`, щоб побачити, як це працює на практиці.\n" ] }, { @@ -1576,11 +1590,11 @@ }, "source": [ "### Категоричні дані (нечислові)\n", - "Спочатку розглянемо нечислові дані. У наборах даних є стовпці з категоричними даними, наприклад, Стать, Правда чи Неправда тощо.\n", + "Спочатку розглянемо нечислові дані. У наборах даних є стовпці з категоричними даними, наприклад, стать, істина чи хибність тощо.\n", "\n", - "У більшості таких випадків ми замінюємо пропущені значення на `моду` стовпця. Наприклад, у нас є 100 точок даних, з яких 90 відповіли Правда, 8 відповіли Неправда, а 2 не заповнили. Тоді ми можемо заповнити ці 2 значення як Правда, враховуючи весь стовпець.\n", + "У більшості таких випадків ми замінюємо пропущені значення на `моду` стовпця. Наприклад, у нас є 100 точок даних, з яких 90 відповіли \"Істина\", 8 — \"Хибність\", а 2 не заповнили. Тоді ми можемо заповнити ці 2 значення \"Істиною\", враховуючи весь стовпець.\n", "\n", - "Знову ж таки, тут можна використовувати знання домену. Розглянемо приклад заповнення за модою.\n" + "Знову ж таки, тут можна використовувати знання предметної області. Розглянемо приклад заповнення за модою.\n" ] }, { @@ -1685,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Тепер спочатку знайдемо моду перед заповненням значення `None` модою.\n" + ] }, { "cell_type": "code", @@ -1720,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Отже, ми замінимо None на True\n" + ] }, { "cell_type": "code", @@ -1845,7 +1863,7 @@ "1. Замінити на медіану рядка\n", "2. Замінити на середнє значення рядка\n", "\n", - "Медіану використовують у випадку, якщо дані мають перекіс із викидами. Це тому, що медіана стійка до викидів.\n", + "Медіану використовують у випадку, якщо дані мають перекіс і містять викиди. Це тому, що медіана стійка до впливу викидів.\n", "\n", "Коли дані нормалізовані, можна використовувати середнє значення, оскільки в такому випадку середнє і медіана будуть досить близькими.\n", "\n", @@ -1955,7 +1973,7 @@ "id": "ka7-wNfzSxbx" }, "source": [ - "Середнє значення стовпця становить\n" + "Середнє значення стовпця дорівнює\n" ] }, { @@ -1989,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Заповнення середнім значенням\n" + ] }, { "cell_type": "code", @@ -2088,7 +2108,9 @@ "metadata": { "id": "CwpVFCrPTC5z" }, - "source": [] + "source": [ + "Як ми бачимо, відсутнє значення було замінено його середнім значенням.\n" + ] }, { "cell_type": "markdown", @@ -2096,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "Тепер спробуємо інший датафрейм, і цього разу ми замінимо значення None на медіану стовпця.\n" + "Тепер давайте спробуємо інший датафрейм, і цього разу ми замінимо значення None на медіану стовпця.\n" ] }, { @@ -2236,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Заповнення медіаною\n" + ] }, { "cell_type": "code", @@ -2336,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Як ми бачимо, значення NaN було замінено на медіану стовпця\n" + "Як ми можемо бачити, значення NaN було замінено на медіану стовпця\n" ] }, { @@ -2420,9 +2444,9 @@ }, "source": [ "> Основні висновки:\n", - "1. Заповнення відсутніх значень слід виконувати, коли даних недостатньо або є стратегія для заповнення відсутніх даних.\n", + "1. Заповнення відсутніх значень слід виконувати, коли даних недостатньо або є стратегія для заповнення пропусків.\n", "2. Домашні знання можуть бути використані для заповнення відсутніх значень шляхом їх наближення.\n", - "3. Для категоріальних даних найчастіше відсутні значення замінюються модою стовпця.\n", + "3. Для категоріальних даних зазвичай відсутні значення замінюються модою стовпця.\n", "4. Для числових даних відсутні значення зазвичай заповнюються середнім значенням (для нормалізованих наборів даних) або медіаною стовпців.\n" ] }, @@ -2431,7 +2455,9 @@ "metadata": { "id": "FI9MmqFJgRsH" }, - "source": [] + "source": [ + "### Вправа:\n" + ] }, { "cell_type": "code", @@ -2451,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "Ви можете **заповнити вперед** null-значення, використовуючи останнє допустиме значення для заповнення null:\n" + ] }, { "cell_type": "code", @@ -2533,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "Як ви могли здогадатися, це працює так само з DataFrames, але ви також можете вказати `axis`, уздовж якого заповнювати null значення:\n" + "Як ви могли здогадатися, це працює так само з DataFrames, але ви також можете вказати `axis`, уздовж якого заповнювати нульові значення:\n" ] }, { @@ -2705,14 +2733,18 @@ "metadata": { "id": "ZeMc-I1EgRsI" }, - "source": [] + "source": [ + "Зверніть увагу, що коли попереднє значення недоступне для заповнення вперед, нульове значення залишається.\n" + ] }, { "cell_type": "markdown", "metadata": { "id": "eeAoOU0RgRsJ" }, - "source": [] + "source": [ + "### Вправа:\n" + ] }, { "cell_type": "code", @@ -2826,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "Зверніть увагу, що третя колонка все ще порожня: за замовчуванням значення заповнюються по рядках.\n", + "Зверніть увагу, що стовпець 3 все ще не має значень: за замовчуванням значення заповнюються по рядках.\n", "\n", - "> **Висновок:** Існує кілька способів вирішення проблеми з відсутніми значеннями у ваших наборах даних. Конкретна стратегія, яку ви оберете (видалення, заміна або навіть спосіб заміни), повинна залежати від особливостей цих даних. Ви краще зрозумієте, як працювати з відсутніми значеннями, чим більше будете взаємодіяти з наборами даних.\n" + "> **Висновок:** Існує кілька способів вирішення проблеми з відсутніми значеннями у ваших наборах даних. Конкретна стратегія (видалення, заміна або спосіб заміни) повинна залежати від особливостей цих даних. Ви краще зрозумієте, як працювати з відсутніми значеннями, чим більше будете взаємодіяти з наборами даних.\n" ] }, { @@ -2839,7 +2871,7 @@ "source": [ "### Кодування категоріальних даних\n", "\n", - "Моделі машинного навчання працюють лише з числами та будь-якими формами числових даних. Вони не можуть розрізняти \"Так\" і \"Ні\", але можуть відрізнити 0 від 1. Тому, після заповнення відсутніх значень, нам потрібно закодувати категоріальні дані в числову форму, щоб модель могла їх зрозуміти.\n", + "Моделі машинного навчання працюють лише з числами та будь-якою формою числових даних. Вони не зможуть розрізнити \"Так\" і \"Ні\", але зможуть відрізнити 0 від 1. Тому після заповнення пропущених значень необхідно закодувати категоріальні дані в числову форму, щоб модель могла їх зрозуміти.\n", "\n", "Кодування можна виконати двома способами. Ми розглянемо їх далі.\n" ] @@ -2852,7 +2884,7 @@ "source": [ "**КОДУВАННЯ МІТКИ**\n", "\n", - "Кодування мітки — це процес перетворення кожної категорії на число. Наприклад, уявімо, що у нас є набір даних про пасажирів авіаліній, і є стовпець, який містить їхній клас серед наступних ['бізнес-клас', 'економ-клас', 'перший клас']. Якщо виконати кодування мітки, це буде перетворено на [0,1,2]. Давайте розглянемо приклад за допомогою коду. Оскільки ми будемо вивчати `scikit-learn` у наступних блокнотах, тут ми його використовувати не будемо.\n" + "Кодування мітки — це процес перетворення кожної категорії в число. Наприклад, уявімо, що у нас є набір даних про пасажирів авіаліній, і є стовпець, який містить їхній клас серед наступних ['бізнес-клас', 'економ-клас', 'перший клас']. Якщо виконати кодування мітки для цього, то це буде перетворено на [0,1,2]. Давайте розглянемо приклад за допомогою коду. Оскільки ми будемо вивчати `scikit-learn` у наступних блокнотах, тут ми його використовувати не будемо.\n" ] }, { @@ -2960,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Щоб виконати кодування міток для першого стовпця, спочатку потрібно описати відображення кожного класу на число, перед заміною\n" + "Щоб виконати кодування міток для першого стовпця, спочатку потрібно описати відображення кожного класу на число, перед заміною.\n" ] }, { @@ -3062,7 +3094,7 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Як ми бачимо, результат відповідає нашим очікуванням. Отже, коли слід використовувати кодування міток? Кодування міток використовується в одному або обох наступних випадках:\n", + "Як ми бачимо, результат відповідає тому, що ми очікували. Отже, коли слід використовувати кодування міток? Кодування міток використовується в одному або обох наступних випадках:\n", "1. Коли кількість категорій велика\n", "2. Коли категорії мають порядок.\n" ] @@ -3075,9 +3107,9 @@ "source": [ "**КОДУВАННЯ ONE HOT**\n", "\n", - "Інший тип кодування — це One Hot Encoding. У цьому типі кодування кожна категорія стовпця додається як окремий стовпець, і кожна точка даних отримує 0 або 1 залежно від того, чи містить вона цю категорію. Отже, якщо є n різних категорій, до датафрейму буде додано n стовпців.\n", + "Ще одним видом кодування є One Hot Encoding. У цьому типі кодування кожна категорія стовпця додається як окремий стовпець, і кожна точка даних отримує 0 або 1 залежно від того, чи містить вона цю категорію. Отже, якщо є n різних категорій, до датафрейму буде додано n стовпців.\n", "\n", - "Наприклад, візьмемо той самий приклад класів літака. Категорії були: ['бізнес-клас', 'економ-клас', 'перший клас']. Отже, якщо ми виконаємо кодування One Hot, до набору даних будуть додані наступні три стовпці: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Наприклад, візьмемо той самий приклад класів літака. Категорії були: ['бізнес-клас', 'економ-клас', 'перший клас']. Якщо ми виконаємо кодування One Hot, до набору даних будуть додані наступні три стовпці: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3310,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "Кожен закодований стовпець містить 0 або 1, що вказує, чи існує ця категорія для даної точки даних.\n" + "Кожен one-hot закодований стовпець містить 0 або 1, що вказує, чи існує ця категорія для даної точки даних.\n" ] }, { @@ -3319,7 +3351,7 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "Коли ми використовуємо one hot encoding? One hot encoding використовується в одному або обох із наступних випадків:\n", + "Коли ми використовуємо one hot encoding? One hot encoding використовується в одному або обох наступних випадках:\n", "\n", "1. Коли кількість категорій і розмір набору даних є невеликими.\n", "2. Коли категорії не мають певного порядку.\n" @@ -3331,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Основні моменти:\n", + "> Основні висновки:\n", "1. Кодування здійснюється для перетворення ненумеричних даних у числові.\n", - "2. Існує два типи кодування: кодування міток і One Hot кодування, які можна виконувати залежно від потреб набору даних.\n" + "2. Існує два типи кодування: кодування міток і One Hot кодування, які можна виконувати залежно від вимог набору даних.\n" ] }, { @@ -3344,9 +3376,9 @@ "source": [ "## Видалення дубльованих даних\n", "\n", - "> **Мета навчання:** Після завершення цього підрозділу ви повинні впевнено визначати та видаляти дубльовані значення з DataFrame.\n", + "> **Мета навчання:** Після завершення цього підрозділу ви повинні впевнено визначати та видаляти дубльовані значення з DataFrames.\n", "\n", - "Окрім відсутніх даних, у реальних наборах даних ви часто зустрічатимете дубльовані дані. На щастя, pandas надає простий спосіб виявлення та видалення дубльованих записів.\n" + "Окрім відсутніх даних, у реальних наборах даних ви часто зустрічатимете дубльовані дані. На щастя, pandas пропонує простий спосіб виявлення та видалення дубльованих записів.\n" ] }, { @@ -3355,9 +3387,9 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### Виявлення дублювань: `duplicated`\n", + "### Виявлення дублікатів: `duplicated`\n", "\n", - "Ви можете легко знайти дубльовані значення за допомогою методу `duplicated` у pandas, який повертає булеву маску, що вказує, чи є запис у `DataFrame` дубльованим щодо попереднього. Давайте створимо ще один приклад `DataFrame`, щоб побачити це в дії.\n" + "Ви можете легко знайти дублікати за допомогою методу `duplicated` у pandas, який повертає булеву маску, що вказує, чи є запис у `DataFrame` дублікатом попереднього. Давайте створимо ще один приклад `DataFrame`, щоб побачити це в дії.\n" ] }, { @@ -3570,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "Як `duplicated`, так і `drop_duplicates` за замовчуванням враховують усі стовпці, але ви можете вказати, щоб вони перевіряли лише підмножину стовпців у вашому `DataFrame`:\n" + "І `duplicated`, і `drop_duplicates` за замовчуванням враховують усі стовпці, але ви можете вказати, щоб вони перевіряли лише підмножину стовпців у вашому `DataFrame`:\n" ] }, { @@ -3646,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Висновок:** Видалення дубльованих даних є важливою частиною майже кожного проєкту з аналізу даних. Дубльовані дані можуть змінити результати ваших аналізів і надати вам неточні результати!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Перевірка якості даних у реальному світі\n", + "\n", + "> **Мета навчання:** До кінця цього розділу ви повинні впевнено виявляти та виправляти поширені проблеми якості даних у реальному світі, включаючи непослідовні категоріальні значення, аномальні числові значення (викиди) та дублікати сутностей із варіаціями.\n", + "\n", + "Хоча пропущені значення та точні дублікати є поширеними проблемами, реальні набори даних часто містять більш тонкі недоліки:\n", + "\n", + "1. **Непослідовні категоріальні значення**: Одна й та сама категорія записана по-різному (наприклад, \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Аномальні числові значення**: Екстремальні викиди, які вказують на помилки введення даних (наприклад, вік = 999)\n", + "3. **Майже дублікати рядків**: Записи, які представляють одну й ту саму сутність із невеликими варіаціями\n", + "\n", + "Давайте розглянемо методи виявлення та усунення цих проблем.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Створення прикладу \"брудного\" набору даних\n", + "\n", + "Спочатку створимо приклад набору даних, який містить типові проблеми, з якими ми часто стикаємося в реальних даних:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Виявлення непослідовних категоріальних значень\n", + "\n", + "Зверніть увагу, що в стовпці `country` є кілька варіантів представлення одних і тих самих країн. Давайте визначимо ці непослідовності:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Стандартизація категоріальних значень\n", + "\n", + "Ми можемо створити відображення для стандартизації цих значень. Простий підхід — перетворити текст у нижній регістр і створити словник відображення:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Альтернатива: Використання нечіткого порівняння**\n", + "\n", + "Для більш складних випадків ми можемо використовувати нечітке порівняння рядків за допомогою бібліотеки `rapidfuzz`, щоб автоматично знаходити схожі рядки:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Виявлення аномальних числових значень (викидів)\n", + "\n", + "Розглядаючи стовпець `age`, ми бачимо деякі підозрілі значення, такі як 199 і -5. Давайте використаємо статистичні методи для виявлення цих викидів.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Використання методу IQR (міжквартильний розмах)\n", + "\n", + "Метод IQR — це надійний статистичний підхід для виявлення аномалій, який менш чутливий до екстремальних значень:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Використання методу Z-оцінки\n", + "\n", + "Метод Z-оцінки визначає аномалії на основі стандартних відхилень від середнього значення:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Обробка Викидів\n", + "\n", + "Після виявлення викиди можна обробляти кількома способами:\n", + "1. **Видалити**: Видалити рядки з викидами (якщо це помилки)\n", + "2. **Обрізати**: Замінити на граничні значення\n", + "3. **Замінити на NaN**: Розглядати як відсутні дані та використовувати методи імпутації\n", + "4. **Залишити**: Якщо це справжні екстремальні значення\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Виявлення майже дубльованих рядків\n", + "\n", + "Зверніть увагу, що в нашому наборі даних є кілька записів для \"John Smith\" із трохи різними значеннями. Давайте визначимо потенційні дублікати на основі схожості імен.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Пошук майже дубльованих записів за допомогою нечіткого співставлення\n", + "\n", + "Для більш складного виявлення дубльованих записів можна використовувати нечітке співставлення для пошуку схожих імен:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Обробка дублікатів\n", + "\n", + "Після виявлення необхідно вирішити, як обробляти дублікати:\n", + "1. **Залишити перше входження**: Використовуйте `drop_duplicates(keep='first')`\n", + "2. **Залишити останнє входження**: Використовуйте `drop_duplicates(keep='last')`\n", + "3. **Агрегувати інформацію**: Об'єднати інформацію з дубльованих рядків\n", + "4. **Ручний перегляд**: Позначити для перевірки людиною\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Резюме: Повна система очищення даних\n", + "\n", + "Давайте об'єднаємо все в одну комплексну систему очищення даних:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Вправа на виклик\n", + "\n", + "Тепер ваша черга! Нижче наведено новий рядок даних із кількома проблемами якості. Чи можете ви:\n", + "\n", + "1. Визначити всі проблеми в цьому рядку\n", + "2. Написати код для виправлення кожної проблеми\n", + "3. Додати очищений рядок до набору даних\n", + "\n", + "Ось проблемні дані:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Основні моменти\n", + "\n", + "1. **Непослідовні категорії** часто зустрічаються в реальних даних. Завжди перевіряйте унікальні значення та стандартизуйте їх за допомогою відповідностей або нечіткого зіставлення.\n", + "\n", + "2. **Викиди** можуть суттєво вплинути на ваш аналіз. Використовуйте знання предметної області разом зі статистичними методами (IQR, Z-score) для їх виявлення.\n", + "\n", + "3. **Майже дублікати** важче виявити, ніж точні дублікати. Розгляньте використання нечіткого зіставлення та нормалізації даних (перетворення в нижній регістр, видалення пробілів) для їх ідентифікації.\n", + "\n", + "4. **Очищення даних — це ітеративний процес**. Можливо, вам доведеться застосувати кілька методів і переглянути результати перед тим, як завершити очищення набору даних.\n", + "\n", + "5. **Документуйте свої рішення**. Фіксуйте, які кроки очищення ви застосували і чому, оскільки це важливо для відтворюваності та прозорості.\n", + "\n", + "> **Найкраща практика:** Завжди зберігайте копію ваших оригінальних \"брудних\" даних. Ніколи не перезаписуйте вихідні файли даних — створюйте очищені версії з чіткими правилами іменування, наприклад, `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Відмова від відповідальності**: \nЦей документ був перекладений за допомогою сервісу автоматичного перекладу [Co-op Translator](https://github.com/Azure/co-op-translator). Хоча ми прагнемо до точності, будь ласка, майте на увазі, що автоматичні переклади можуть містити помилки або неточності. Оригінальний документ на його рідній мові слід вважати авторитетним джерелом. Для критичної інформації рекомендується професійний людський переклад. Ми не несемо відповідальності за будь-які непорозуміння або неправильні тлумачення, що виникають внаслідок використання цього перекладу.\n" + "\n---\n\n**Відмова від відповідальності**: \nЦей документ було перекладено за допомогою сервісу автоматичного перекладу [Co-op Translator](https://github.com/Azure/co-op-translator). Хоча ми прагнемо до точності, звертаємо вашу увагу, що автоматичні переклади можуть містити помилки або неточності. Оригінальний документ мовою оригіналу слід вважати авторитетним джерелом. Для критично важливої інформації рекомендується професійний людський переклад. Ми не несемо відповідальності за будь-які непорозуміння або неправильні тлумачення, що виникли внаслідок використання цього перекладу.\n" ] } ], @@ -3680,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T22:13:54+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T21:23:48+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "uk" } diff --git a/translations/ur/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/ur/2-Working-With-Data/08-data-preparation/notebook.ipynb index 4503ec2e..439f1a44 100644 --- a/translations/ur/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/ur/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -10,13 +10,13 @@ "\n", "[اصل نوٹ بک کا ماخذ *ڈیٹا سائنس: ڈیٹا سائنس کے لیے مشین لرننگ کا تعارف، پائتھون اور مشین لرننگ اسٹوڈیو از لی اسٹاٹ*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", - "## `DataFrame` معلومات کا جائزہ لینا\n", + "## `DataFrame` کی معلومات کا جائزہ لینا\n", "\n", - "> **سیکھنے کا مقصد:** اس ذیلی حصے کے اختتام تک، آپ pandas DataFrames میں محفوظ ڈیٹا کے بارے میں عمومی معلومات حاصل کرنے میں مہارت حاصل کر لیں گے۔\n", + "> **سیکھنے کا مقصد:** اس ذیلی حصے کے اختتام تک، آپ pandas DataFrames میں محفوظ کردہ ڈیٹا کے بارے میں عمومی معلومات حاصل کرنے میں مہارت حاصل کر لیں گے۔\n", "\n", - "جب آپ نے اپنا ڈیٹا pandas میں لوڈ کر لیا ہو، تو زیادہ امکان ہے کہ یہ `DataFrame` میں ہوگا۔ لیکن اگر آپ کے `DataFrame` میں 60,000 قطاریں اور 400 کالمز ہوں، تو آپ یہ سمجھنا کہاں سے شروع کریں گے کہ آپ کس کے ساتھ کام کر رہے ہیں؟ خوش قسمتی سے، pandas کچھ آسان ٹولز فراہم کرتا ہے جو `DataFrame` کے بارے میں مجموعی معلومات دیکھنے کے ساتھ ساتھ ابتدائی اور آخری چند قطاروں کو جلدی سے دیکھنے میں مدد کرتے ہیں۔\n", + "جب آپ نے اپنا ڈیٹا pandas میں لوڈ کر لیا ہو، تو زیادہ امکان ہے کہ یہ `DataFrame` میں ہوگا۔ لیکن اگر آپ کے `DataFrame` میں موجود ڈیٹا سیٹ میں 60,000 قطاریں اور 400 کالم ہوں، تو آپ کام شروع کرنے کے لیے اس کا اندازہ کیسے لگائیں گے؟ خوش قسمتی سے، pandas کچھ آسان ٹولز فراہم کرتا ہے جو `DataFrame` کے بارے میں مجموعی معلومات کے ساتھ ساتھ ابتدائی اور آخری چند قطاروں کو جلدی دیکھنے میں مدد کرتے ہیں۔\n", "\n", - "اس فنکشنالٹی کو دریافت کرنے کے لیے، ہم Python کی scikit-learn لائبریری کو درآمد کریں گے اور ایک مشہور ڈیٹاسیٹ استعمال کریں گے جسے ہر ڈیٹا سائنسدان سینکڑوں بار دیکھ چکا ہے: برطانوی حیاتیات دان رونالڈ فشر کا *Iris* ڈیٹاسیٹ، جو انہوں نے 1936 کے اپنے مقالے \"The use of multiple measurements in taxonomic problems\" میں استعمال کیا تھا:\n" + "اس فعالیت کو دریافت کرنے کے لیے، ہم Python کی scikit-learn لائبریری درآمد کریں گے اور ایک مشہور ڈیٹا سیٹ استعمال کریں گے جسے ہر ڈیٹا سائنسدان نے سینکڑوں بار دیکھا ہے: برطانوی حیاتیات دان رونالڈ فشر کا *Iris* ڈیٹا سیٹ، جو انہوں نے 1936 کے اپنے مقالے \"The use of multiple measurements in taxonomic problems\" میں استعمال کیا تھا:\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "ہم 150 قطاروں اور 4 کالمز کے ڈیٹا کے ساتھ کام کر رہے ہیں۔ ہر قطار ایک ڈیٹا پوائنٹ کی نمائندگی کرتی ہے اور ہر کالم ڈیٹا فریم سے منسلک ایک خصوصیت کی نمائندگی کرتا ہے۔ تو بنیادی طور پر، یہاں 150 ڈیٹا پوائنٹس ہیں جن میں سے ہر ایک میں 4 خصوصیات شامل ہیں۔\n", + "تو، ہم 150 قطاروں اور 4 کالمز کے ڈیٹا کے ساتھ کام کر رہے ہیں۔ ہر قطار ایک ڈیٹا پوائنٹ کی نمائندگی کرتی ہے اور ہر کالم ڈیٹا فریم سے متعلق ایک خصوصیت کی نمائندگی کرتا ہے۔ تو بنیادی طور پر، یہاں 150 ڈیٹا پوائنٹس ہیں جن میں ہر ایک کے ساتھ 4 خصوصیات موجود ہیں۔\n", "\n", - "`shape` یہاں ڈیٹا فریم کی ایک خصوصیت ہے، نہ کہ کوئی فنکشن، اسی لیے یہ قوسین کے جوڑے کے ساتھ ختم نہیں ہوتا۔\n" + "`shape` یہاں ڈیٹا فریم کی ایک خصوصیت ہے نہ کہ ایک فنکشن، اسی لیے یہ ایک جوڑے قوسین پر ختم نہیں ہوتی۔\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "آئیے اب ڈیٹا کے 4 کالمز کی طرف بڑھتے ہیں۔ ان میں سے ہر ایک کالم اصل میں کیا ظاہر کرتا ہے؟ `columns` ایٹریبیوٹ ہمیں ڈیٹا فریم میں کالمز کے نام فراہم کرے گا۔\n" + "اب ہم ڈیٹا کے 4 کالمز کی طرف بڑھتے ہیں۔ ہر کالم بالکل کس چیز کی نمائندگی کرتا ہے؟ `columns` ایٹریبیوٹ ہمیں ڈیٹا فریم میں کالمز کے نام فراہم کرے گا۔\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "جیسا کہ ہم دیکھ سکتے ہیں، یہاں چار (4) کالم ہیں۔ `columns` وصف ہمیں کالمز کے نام بتاتا ہے اور بنیادی طور پر اس کے علاوہ کچھ نہیں۔ یہ وصف اس وقت اہمیت اختیار کرتا ہے جب ہم یہ شناخت کرنا چاہتے ہیں کہ ایک ڈیٹاسیٹ میں کون سی خصوصیات شامل ہیں۔\n" + "جیسا کہ ہم دیکھ سکتے ہیں، یہاں چار (4) کالم ہیں۔ `columns` خصوصیت ہمیں کالمز کے نام بتاتی ہے اور بنیادی طور پر کچھ اور نہیں۔ یہ خصوصیت اس وقت اہمیت اختیار کرتی ہے جب ہم یہ شناخت کرنا چاہتے ہیں کہ ایک ڈیٹاسیٹ میں کون سی خصوصیات شامل ہیں۔\n" ] }, { @@ -181,8 +181,8 @@ }, "source": [ "یہاں سے، ہم چند مشاہدات کر سکتے ہیں:\n", - "1. ہر کالم کا ڈیٹا ٹائپ: اس ڈیٹا سیٹ میں، تمام ڈیٹا 64-بٹ فلوٹنگ پوائنٹ نمبرز کے طور پر محفوظ کیا گیا ہے۔\n", - "2. نان-نل ویلیوز کی تعداد: نل ویلیوز سے نمٹنا ڈیٹا کی تیاری میں ایک اہم قدم ہے۔ اس پر بعد میں نوٹ بک میں کام کیا جائے گا۔\n" + "1. ہر کالم کا DataType: اس ڈیٹا سیٹ میں، تمام ڈیٹا 64-bit floating-point نمبروں کی صورت میں محفوظ ہے۔\n", + "2. Non-Null ویلیوز کی تعداد: null ویلیوز سے نمٹنا ڈیٹا کی تیاری میں ایک اہم قدم ہے۔ اس پر بعد میں نوٹ بک میں کام کیا جائے گا۔\n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "اوپر دیا گیا نتیجہ ہر کالم کے کل ڈیٹا پوائنٹس، اوسط، معیاری انحراف، کم از کم، نچلا چوتھائی (25٪)، درمیانی (50٪)، اوپر چوتھائی (75٪) اور زیادہ سے زیادہ قدر کو ظاہر کرتا ہے۔\n" + "اوپر دیا گیا نتیجہ ہر کالم کے کل ڈیٹا پوائنٹس، اوسط، معیاری انحراف، کم از کم، نچلا چوتھائی (25٪)، درمیانی (50٪)، اوپری چوتھائی (75٪) اور زیادہ سے زیادہ قدر کو ظاہر کرتا ہے۔\n" ] }, { @@ -334,7 +334,7 @@ "### `DataFrame.head`\n", "تمام مذکورہ فنکشنز اور خصوصیات کے ساتھ، ہمیں ڈیٹا سیٹ کا ایک اعلیٰ سطحی جائزہ مل گیا ہے۔ ہمیں معلوم ہے کہ کتنے ڈیٹا پوائنٹس موجود ہیں، کتنی خصوصیات ہیں، ہر خصوصیت کا ڈیٹا ٹائپ کیا ہے اور ہر خصوصیت کے غیر خالی (non-null) ویلیوز کی تعداد کیا ہے۔\n", "\n", - "اب وقت ہے کہ خود ڈیٹا کو دیکھا جائے۔ آئیے دیکھتے ہیں کہ ہمارے `DataFrame` کی ابتدائی چند قطاریں (ابتدائی چند ڈیٹا پوائنٹس) کیسی نظر آتی ہیں:\n" + "اب وقت ہے کہ خود ڈیٹا کو دیکھیں۔ آئیے دیکھتے ہیں کہ ہمارے `DataFrame` کی ابتدائی چند قطاریں (ابتدائی چند ڈیٹا پوائنٹس) کیسی نظر آتی ہیں:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "جیسا کہ یہاں آؤٹ پٹ میں، ہم ڈیٹاسیٹ کے پانچ (5) اندراجات دیکھ سکتے ہیں۔ اگر ہم بائیں طرف انڈیکس کو دیکھیں، تو ہمیں پتہ چلتا ہے کہ یہ پہلی پانچ قطاریں ہیں۔\n" + "جیسا کہ یہاں آؤٹ پٹ میں، ہم ڈیٹاسیٹ کے پانچ (5) اندراجات دیکھ سکتے ہیں۔ اگر ہم بائیں طرف کے انڈیکس کو دیکھیں، تو ہمیں پتہ چلتا ہے کہ یہ پہلی پانچ قطاریں ہیں۔\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "ڈیٹا کو دیکھنے کا ایک اور طریقہ آخر سے ہو سکتا ہے (شروع کے بجائے)۔ `DataFrame.head` کے برعکس، `DataFrame.tail` آخری پانچ قطاریں `DataFrame` کی واپس کرتا ہے:\n" + "ڈیٹا کو دیکھنے کا ایک اور طریقہ آخر سے ہو سکتا ہے (شروع کے بجائے)۔ `DataFrame.head` کا الٹ `DataFrame.tail` ہے، جو `DataFrame` کی آخری پانچ قطاریں واپس کرتا ہے:\n" ] }, { @@ -584,9 +584,9 @@ "source": [ "عملی طور پر، یہ فائدہ مند ہوتا ہے کہ آپ آسانی سے `DataFrame` کی ابتدائی چند قطاروں یا آخری چند قطاروں کا جائزہ لے سکیں، خاص طور پر جب آپ ترتیب شدہ ڈیٹا سیٹس میں غیر معمولی اقدار تلاش کر رہے ہوں۔\n", "\n", - "تمام فنکشنز اور خصوصیات جو اوپر کوڈ کی مثالوں کی مدد سے دکھائی گئی ہیں، ہمیں ڈیٹا کی جھلک اور احساس حاصل کرنے میں مدد دیتی ہیں۔\n", + "کوڈ کی مثالوں کی مدد سے دکھائی گئی تمام فنکشنز اور خصوصیات ہمیں ڈیٹا کی جھلک اور احساس حاصل کرنے میں مدد دیتی ہیں۔\n", "\n", - "> **خلاصہ:** صرف `DataFrame` میں موجود معلومات کے میٹا ڈیٹا یا اس کی ابتدائی اور آخری چند اقدار کو دیکھ کر، آپ فوری طور پر اس ڈیٹا کے سائز، شکل، اور مواد کے بارے میں ایک اندازہ لگا سکتے ہیں جس کے ساتھ آپ کام کر رہے ہیں۔\n" + "> **خلاصہ:** صرف `DataFrame` میں موجود معلومات کے میٹا ڈیٹا یا اس کی ابتدائی اور آخری چند قدروں کو دیکھ کر ہی آپ فوری طور پر اس ڈیٹا کے حجم، شکل، اور مواد کے بارے میں ایک اندازہ لگا سکتے ہیں جس کے ساتھ آپ کام کر رہے ہیں۔\n" ] }, { @@ -596,17 +596,17 @@ }, "source": [ "### گمشدہ ڈیٹا\n", - "آئیے گمشدہ ڈیٹا کے بارے میں بات کرتے ہیں۔ گمشدہ ڈیٹا اس وقت ہوتا ہے جب کچھ کالمز میں کوئی ویلیو محفوظ نہ ہو۔\n", + "آئیے گمشدہ ڈیٹا کے بارے میں بات کرتے ہیں۔ گمشدہ ڈیٹا تب ہوتا ہے جب کچھ کالمز میں کوئی ویلیو محفوظ نہ ہو۔\n", "\n", - "ایک مثال لیتے ہیں: فرض کریں کہ کوئی شخص اپنے وزن کے بارے میں حساس ہے اور سروے میں وزن کا خانہ خالی چھوڑ دیتا ہے۔ تو اس شخص کے لیے وزن کی ویلیو گمشدہ ہوگی۔\n", + "آئیے ایک مثال لیتے ہیں: فرض کریں کوئی شخص اپنے وزن کے بارے میں حساس ہے اور سروے میں وزن کا خانہ نہیں بھرتا۔ تو اس شخص کے لیے وزن کی ویلیو گمشدہ ہوگی۔\n", "\n", - "زیادہ تر حقیقی دنیا کے ڈیٹاسیٹس میں گمشدہ ویلیوز عام ہوتی ہیں۔\n", + "زیادہ تر وقت، حقیقی دنیا کے ڈیٹا سیٹس میں گمشدہ ویلیوز ہوتی ہیں۔\n", "\n", "**پینڈاز گمشدہ ڈیٹا کو کیسے ہینڈل کرتا ہے**\n", "\n", - "پینڈاز گمشدہ ویلیوز کو دو طریقوں سے ہینڈل کرتا ہے۔ پہلا طریقہ آپ پہلے دیکھ چکے ہیں: `NaN`، یا Not a Number۔ یہ دراصل ایک خاص ویلیو ہے جو IEEE فلوٹنگ پوائنٹ اسپیسفیکیشن کا حصہ ہے اور یہ صرف گمشدہ فلوٹنگ پوائنٹ ویلیوز کو ظاہر کرنے کے لیے استعمال ہوتی ہے۔\n", + "پینڈاز گمشدہ ویلیوز کو دو طریقوں سے ہینڈل کرتا ہے۔ پہلا طریقہ آپ پہلے دیکھ چکے ہیں: `NaN`، یا \"Not a Number\"۔ یہ دراصل ایک خاص ویلیو ہے جو IEEE فلوٹنگ پوائنٹ اسپیسفیکیشن کا حصہ ہے اور یہ صرف گمشدہ فلوٹنگ پوائنٹ ویلیوز کو ظاہر کرنے کے لیے استعمال ہوتی ہے۔\n", "\n", - "فلوٹس کے علاوہ گمشدہ ویلیوز کے لیے، پینڈاز Python کے `None` آبجیکٹ کا استعمال کرتا ہے۔ اگرچہ یہ تھوڑا الجھن پیدا کر سکتا ہے کہ آپ کو دو مختلف قسم کی ویلیوز کا سامنا ہوگا جو بنیادی طور پر ایک ہی بات کہتی ہیں، لیکن اس ڈیزائن کے پیچھے مضبوط پروگرامنگ وجوہات ہیں۔ عملی طور پر، یہ طریقہ پینڈاز کو زیادہ تر کیسز کے لیے ایک اچھا توازن فراہم کرنے کے قابل بناتا ہے۔ اس کے باوجود، `None` اور `NaN` دونوں میں کچھ پابندیاں ہیں جن کا آپ کو ان کے استعمال کے حوالے سے خیال رکھنا ہوگا۔\n" + "فلوٹس کے علاوہ گمشدہ ویلیوز کے لیے، پینڈاز Python کے `None` آبجیکٹ کا استعمال کرتا ہے۔ اگرچہ یہ تھوڑا الجھن پیدا کر سکتا ہے کہ آپ کو دو مختلف قسم کی ویلیوز ملیں گی جو بنیادی طور پر ایک ہی بات کہتی ہیں، لیکن اس ڈیزائن کے انتخاب کے پیچھے مضبوط پروگرامنگ وجوہات ہیں۔ عملی طور پر، یہ طریقہ پینڈاز کو زیادہ تر کیسز کے لیے ایک اچھا حل فراہم کرنے کے قابل بناتا ہے۔ اس کے باوجود، `None` اور `NaN` دونوں میں کچھ پابندیاں ہیں جنہیں آپ کو ذہن میں رکھنا ہوگا کہ انہیں کیسے استعمال کیا جا سکتا ہے۔\n" ] }, { @@ -616,10 +616,9 @@ }, "source": [ "### `None`: غیر فلوٹ گمشدہ ڈیٹا\n", + "چونکہ `None` Python سے آتا ہے، اسے NumPy اور pandas arrays میں استعمال نہیں کیا جا سکتا جو ڈیٹا ٹائپ `'object'` کے نہیں ہیں۔ یاد رکھیں، NumPy arrays (اور pandas میں ڈیٹا اسٹرکچرز) صرف ایک قسم کے ڈیٹا پر مشتمل ہو سکتے ہیں۔ یہی چیز انہیں بڑے پیمانے پر ڈیٹا اور حسابی کام کے لیے زبردست طاقت دیتی ہے، لیکن یہ ان کی لچک کو بھی محدود کرتی ہے۔ ایسے arrays کو \"کم از کم مشترکہ عنصر\" میں تبدیل کرنا پڑتا ہے، یعنی وہ ڈیٹا ٹائپ جو array میں موجود ہر چیز کو شامل کر سکے۔ جب array میں `None` موجود ہو، تو اس کا مطلب ہے کہ آپ Python objects کے ساتھ کام کر رہے ہیں۔\n", "\n", - "چونکہ `None` Python سے آتا ہے، اسے NumPy اور pandas کے ایسے arrays میں استعمال نہیں کیا جا سکتا جن کا ڈیٹا ٹائپ `'object'` نہ ہو۔ یاد رکھیں، NumPy arrays (اور pandas میں موجود ڈیٹا اسٹرکچرز) صرف ایک قسم کے ڈیٹا کو رکھ سکتے ہیں۔ یہی چیز انہیں بڑے پیمانے پر ڈیٹا اور حسابی کاموں کے لیے زبردست طاقت دیتی ہے، لیکن یہ ان کی لچک کو محدود بھی کرتی ہے۔ ایسے arrays کو \"کم از کم مشترکہ عنصر\" کے طور پر اپکاسٹ کرنا پڑتا ہے، یعنی وہ ڈیٹا ٹائپ جو array میں موجود ہر چیز کو شامل کر سکے۔ جب array میں `None` موجود ہو، تو اس کا مطلب ہے کہ آپ Python objects کے ساتھ کام کر رہے ہیں۔\n", - "\n", - "اس کو عملی طور پر دیکھنے کے لیے، درج ذیل مثال کے array پر غور کریں (اس کا `dtype` نوٹ کریں):\n" + "اسے عملی طور پر دیکھنے کے لیے، درج ذیل مثال کے array پر غور کریں (اس کا `dtype` نوٹ کریں):\n" ] }, { @@ -658,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "ڈیٹا ٹائپس کے اپکاسٹ ہونے کی حقیقت کے ساتھ دو اثرات جڑے ہوتے ہیں۔ پہلا یہ کہ آپریشنز انٹرپریٹڈ پائتھون کوڈ کی سطح پر کیے جائیں گے، نہ کہ کمپائلڈ NumPy کوڈ کی سطح پر۔ بنیادی طور پر، اس کا مطلب یہ ہے کہ اگر `Series` یا `DataFrames` میں `None` موجود ہو تو ان کے ساتھ کیے جانے والے آپریشنز سست ہوں گے۔ اگرچہ آپ کو یہ کارکردگی کا فرق شاید محسوس نہ ہو، لیکن بڑے ڈیٹا سیٹس کے لیے یہ مسئلہ بن سکتا ہے۔\n", + "ڈیٹا ٹائپس کے اپکاسٹ ہونے کی حقیقت کے ساتھ دو اثرات جڑے ہوتے ہیں۔ پہلا یہ کہ آپریشنز انٹرپریٹڈ پائتھون کوڈ کی سطح پر انجام دیے جائیں گے، نہ کہ کمپائلڈ NumPy کوڈ کی سطح پر۔ بنیادی طور پر، اس کا مطلب یہ ہے کہ اگر `Series` یا `DataFrames` میں `None` موجود ہو تو ان پر کیے جانے والے آپریشنز سست ہوں گے۔ اگرچہ آپ کو یہ کارکردگی کا فرق شاید محسوس نہ ہو، لیکن بڑے ڈیٹا سیٹس کے لیے یہ مسئلہ بن سکتا ہے۔\n", "\n", - "دوسرا اثر پہلے اثر سے جڑا ہوا ہے۔ کیونکہ `None` بنیادی طور پر `Series` یا `DataFrame`s کو واپس وینیلا پائتھون کی دنیا میں لے جاتا ہے، اس لیے اگر آپ NumPy/pandas کی ایگریگیشنز جیسے `sum()` یا `min()` کو ایسے arrays پر استعمال کریں جن میں `None` ویلیو موجود ہو، تو عام طور پر ایک ایرر پیدا ہوگا:\n" + "دوسرا اثر پہلے اثر سے جڑا ہوا ہے۔ کیونکہ `None` بنیادی طور پر `Series` یا `DataFrame`s کو واپس عام پائتھون کی دنیا میں لے جاتا ہے، اس لیے اگر آپ NumPy/pandas کے ایگریگیشن فنکشنز جیسے `sum()` یا `min()` کو ایسے arrays پر استعمال کریں جن میں ``None`` موجود ہو، تو عام طور پر ایک ایرر پیدا ہوگا:\n" ] }, { @@ -699,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**اہم نکتہ**: عدد صحیح اور `None` اقدار کے درمیان جمع (اور دیگر عملیات) غیر معین ہے، جو ان ڈیٹا سیٹس کے ساتھ کام کرنے کی صلاحیت کو محدود کر سکتا ہے جن میں یہ شامل ہوں۔\n" + "**اہم نکتہ**: عددی اقدار اور `None` کے درمیان جمع (اور دیگر عملیات) غیر معین ہے، جو ایسے ڈیٹا سیٹس کے ساتھ کام کرنے کی صلاحیت کو محدود کر سکتا ہے جن میں یہ موجود ہوں۔\n" ] }, { @@ -708,9 +707,9 @@ "id": "pWvVHvETgRr9" }, "source": [ - "### `NaN`: غائب فلوٹ ویلیوز\n", + "### `NaN`: گمشدہ فلوٹ ویلیوز\n", "\n", - "`None` کے برعکس، NumPy (اور اس کے نتیجے میں pandas) اپنے تیز، ویکٹرائزڈ آپریشنز اور ufuncs کے لیے `NaN` کو سپورٹ کرتا ہے۔ بری خبر یہ ہے کہ `NaN` پر کی جانے والی کوئی بھی ریاضیاتی کارروائی ہمیشہ `NaN` ہی دیتی ہے۔ مثال کے طور پر:\n" + "`None` کے برعکس، NumPy (اور اسی طرح pandas) اپنے تیز، ویکٹرائزڈ آپریشنز اور ufuncs کے لیے `NaN` کو سپورٹ کرتا ہے۔ بری خبر یہ ہے کہ `NaN` پر کی جانے والی کوئی بھی حسابی کارروائی ہمیشہ `NaN` ہی دیتی ہے۔ مثال کے طور پر:\n" ] }, { @@ -773,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "اچھی خبر: ایسے arrays پر aggregations جو `NaN` پر چلتے ہیں، errors نہیں دیتے۔ بری خبر: نتائج یکساں طور پر مفید نہیں ہیں:\n" + "اچھی خبر: ایسے arrays پر aggregations چلانے سے جن میں `NaN` ہو، errors ظاہر نہیں ہوتے۔ بری خبر: نتائج یکساں طور پر مفید نہیں ہوتے:\n" ] }, { @@ -832,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "یاد رکھیں: `NaN` صرف گمشدہ فلوٹنگ پوائنٹ قدروں کے لیے ہے؛ عددی، سٹرنگز، یا بولینز کے لیے کوئی `NaN` متبادل نہیں ہے۔\n" + "یاد رکھیں: `NaN` صرف گمشدہ فلوٹنگ پوائنٹ قدروں کے لیے ہے؛ عددی، سٹرنگز یا بولینز کے لیے کوئی `NaN` متبادل نہیں ہے۔\n" ] }, { @@ -843,7 +842,7 @@ "source": [ "### `NaN` اور `None`: pandas میں null ویلیوز\n", "\n", - "اگرچہ `NaN` اور `None` کچھ حد تک مختلف طریقے سے کام کر سکتے ہیں، pandas پھر بھی انہیں ایک دوسرے کے ساتھ استعمال کرنے کے لیے بنایا گیا ہے۔ اس بات کو سمجھنے کے لیے، ایک `Series` کا تصور کریں جس میں انٹیجرز ہوں:\n" + "اگرچہ `NaN` اور `None` کا رویہ کچھ مختلف ہو سکتا ہے، pandas کو اس طرح بنایا گیا ہے کہ وہ انہیں ایک دوسرے کے ساتھ استعمال کر سکے۔ اس بات کو سمجھنے کے لیے، ایک integers کی `Series` پر غور کریں:\n" ] }, { @@ -907,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "پینڈاز میں `Series` اور `DataFrame`s کے ڈیٹا ٹائپس کو یکساں بنانے کے عمل میں، پینڈاز آسانی سے گمشدہ اقدار کو `None` اور `NaN` کے درمیان تبدیل کر سکتا ہے۔ اس ڈیزائن کی خصوصیت کی وجہ سے، `None` اور `NaN` کو پینڈاز میں \"null\" کی دو مختلف اقسام کے طور پر سوچنا مفید ہو سکتا ہے۔ درحقیقت، وہ بنیادی طریقے جو آپ گمشدہ اقدار کو سنبھالنے کے لیے استعمال کریں گے، اس تصور کو اپنے ناموں میں ظاہر کرتے ہیں:\n", + "پینڈاز میں `Series` اور `DataFrame`s کے ڈیٹا کی یکسانیت قائم کرنے کے لیے ڈیٹا ٹائپس کو اپ کاسٹ کرنے کے عمل میں، پینڈاز آسانی سے گمشدہ اقدار کو `None` اور `NaN` کے درمیان تبدیل کر سکتا ہے۔ اس ڈیزائن فیچر کی وجہ سے، پینڈاز میں `None` اور `NaN` کو \"null\" کی دو مختلف اقسام کے طور پر سوچنا مفید ہو سکتا ہے۔ درحقیقت، پینڈاز میں گمشدہ اقدار سے نمٹنے کے لیے استعمال ہونے والے کچھ بنیادی طریقے اس خیال کو اپنے ناموں میں ظاہر کرتے ہیں:\n", "\n", - "- `isnull()`: ایک Boolean ماسک تیار کرتا ہے جو گمشدہ اقدار کو ظاہر کرتا ہے\n", + "- `isnull()`: گمشدہ اقدار کی نشاندہی کرنے کے لیے ایک Boolean ماسک تیار کرتا ہے\n", "- `notnull()`: `isnull()` کے برعکس کام کرتا ہے\n", "- `dropna()`: ڈیٹا کا فلٹر شدہ ورژن واپس کرتا ہے\n", - "- `fillna()`: ڈیٹا کی ایک کاپی واپس کرتا ہے جس میں گمشدہ اقدار کو بھر دیا گیا ہو یا تخمینہ لگایا گیا ہو\n", + "- `fillna()`: ڈیٹا کی ایک کاپی واپس کرتا ہے جس میں گمشدہ اقدار کو بھر دیا گیا ہو یا ان کی جگہ متبادل دی گئی ہو\n", "\n", - "یہ طریقے سیکھنا اور ان سے مانوس ہونا بہت ضروری ہے، تو آئیے ان میں سے ہر ایک کو تفصیل سے سمجھتے ہیں۔\n" + "یہ طریقے سیکھنا اور ان کے ساتھ مہارت حاصل کرنا بہت ضروری ہے، تو آئیے ان میں سے ہر ایک کو تفصیل سے سمجھتے ہیں۔\n" ] }, { @@ -925,7 +924,7 @@ "source": [ "### خالی اقدار کا پتہ لگانا\n", "\n", - "اب جب کہ ہم نے خالی اقدار کی اہمیت کو سمجھ لیا ہے، ہمیں ان سے نمٹنے سے پہلے اپنے ڈیٹا سیٹ میں ان کا پتہ لگانا ہوگا۔ \n", + "اب جب کہ ہم نے گمشدہ اقدار کی اہمیت کو سمجھ لیا ہے، ہمیں اپنے ڈیٹا سیٹ میں ان کا پتہ لگانا ہوگا، اس سے نمٹنے سے پہلے۔\n", "`isnull()` اور `notnull()` دونوں خالی ڈیٹا کا پتہ لگانے کے لیے آپ کے بنیادی طریقے ہیں۔ دونوں آپ کے ڈیٹا پر Boolean ماسک واپس کرتے ہیں۔\n" ] }, @@ -979,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "کیا آپ کو اس میں کچھ حیرت انگیز لگا؟ اگرچہ `0` ایک ریاضیاتی صفر ہے، یہ پھر بھی ایک مکمل عدد ہے اور pandas اسے اسی طرح سمجھتا ہے۔ `''` تھوڑا زیادہ نازک ہے۔ اگرچہ ہم نے اسے سیکشن 1 میں ایک خالی سٹرنگ ویلیو کی نمائندگی کے لیے استعمال کیا تھا، یہ پھر بھی ایک سٹرنگ آبجیکٹ ہے اور pandas کے نقطہ نظر سے یہ null کی نمائندگی نہیں کرتا۔\n", + "کیا آپ کو نتیجہ دیکھ کر کوئی حیرت ہوئی؟ اگرچہ `0` ایک حسابی خالی قدر ہے، یہ پھر بھی ایک بالکل درست عدد ہے اور pandas اسے اسی طرح سمجھتا ہے۔ `''` تھوڑا زیادہ پیچیدہ ہے۔ اگرچہ ہم نے اسے سیکشن 1 میں خالی سٹرنگ ویلیو کی نمائندگی کے لیے استعمال کیا تھا، یہ پھر بھی ایک سٹرنگ آبجیکٹ ہے اور pandas کے لحاظ سے خالی قدر کی نمائندگی نہیں کرتا۔\n", "\n", - "اب، آئیے اس کو الٹ کر ان طریقوں کو اس انداز میں استعمال کریں جو آپ عملی طور پر کریں گے۔ آپ Boolean ماسک کو براہ راست ``Series`` یا ``DataFrame`` انڈیکس کے طور پر استعمال کر سکتے ہیں، جو الگ تھلگ گمشدہ (یا موجود) ویلیوز کے ساتھ کام کرنے کی کوشش کرتے وقت مفید ہو سکتا ہے۔\n", + "اب، آئیے اس کو الٹ کر دیکھتے ہیں اور ان طریقوں کو اس طرح استعمال کرتے ہیں جیسے آپ انہیں عملی طور پر استعمال کریں گے۔ آپ Boolean ماسک کو براہ راست ``Series`` یا ``DataFrame`` انڈیکس کے طور پر استعمال کر سکتے ہیں، جو الگ تھلگ خالی (یا موجود) قدروں کے ساتھ کام کرنے کی کوشش کرتے وقت مفید ہو سکتا ہے۔\n", "\n", - "اگر ہم گمشدہ ویلیوز کی کل تعداد جاننا چاہتے ہیں، تو ہم صرف `isnull()` طریقے سے پیدا ہونے والے ماسک پر ایک سم کر سکتے ہیں۔\n" + "اگر ہم خالی قدروں کی کل تعداد جاننا چاہتے ہیں، تو ہم صرف `isnull()` طریقے سے پیدا ہونے والے ماسک پر ایک سم کر سکتے ہیں۔\n" ] }, { @@ -1052,15 +1051,15 @@ "source": [ "### گمشدہ ڈیٹا سے نمٹنا\n", "\n", - "> **سیکھنے کا مقصد:** اس حصے کے اختتام تک، آپ کو معلوم ہونا چاہیے کہ ڈیٹا فریمز سے null ویلیوز کو کب اور کیسے تبدیل یا ہٹانا ہے۔\n", + "> **سیکھنے کا مقصد:** اس حصے کے اختتام تک، آپ کو معلوم ہونا چاہیے کہ ڈیٹا فریمز سے null ویلیوز کو کب اور کیسے تبدیل یا ہٹایا جائے۔\n", "\n", - "مشین لرننگ ماڈلز خود گمشدہ ڈیٹا کو نہیں سنبھال سکتے۔ لہذا، ڈیٹا کو ماڈل میں ڈالنے سے پہلے، ہمیں ان گمشدہ ویلیوز سے نمٹنا ہوگا۔\n", + "مشین لرننگ ماڈلز خود گمشدہ ڈیٹا کو نہیں سنبھال سکتے۔ لہذا، ماڈل میں ڈیٹا دینے سے پہلے، ہمیں ان گمشدہ ویلیوز کو حل کرنا ہوگا۔\n", "\n", - "گمشدہ ڈیٹا کو سنبھالنے کا طریقہ اپنے ساتھ باریک بین توازن لاتا ہے، جو آپ کے حتمی تجزیے اور حقیقی دنیا کے نتائج پر اثر ڈال سکتا ہے۔\n", + "گمشدہ ڈیٹا کو سنبھالنے کا طریقہ اپنے ساتھ باریک تجارتی پہلو لے کر آتا ہے، جو آپ کے حتمی تجزیے اور حقیقی دنیا کے نتائج کو متاثر کر سکتا ہے۔\n", "\n", "گمشدہ ڈیٹا سے نمٹنے کے بنیادی طور پر دو طریقے ہیں:\n", "\n", - "1. وہ قطار حذف کریں جس میں گمشدہ ویلیو ہو\n", + "1. گمشدہ ویلیو والی قطار کو حذف کریں\n", "2. گمشدہ ویلیو کو کسی اور ویلیو سے تبدیل کریں\n", "\n", "ہم ان دونوں طریقوں اور ان کے فوائد و نقصانات کو تفصیل سے زیر بحث لائیں گے۔\n" @@ -1072,13 +1071,13 @@ "id": "3VaYC1TvgRsD" }, "source": [ - "### خالی اقدار کو ختم کرنا\n", + "### خالی قدروں کو ہٹانا\n", "\n", - "جو ڈیٹا ہم اپنے ماڈل کو فراہم کرتے ہیں، اس کی مقدار براہ راست اس کی کارکردگی پر اثر ڈالتی ہے۔ خالی اقدار کو ختم کرنے کا مطلب ہے کہ ہم ڈیٹا پوائنٹس کی تعداد کم کر رہے ہیں، اور اس طرح ڈیٹا سیٹ کا سائز بھی کم ہو رہا ہے۔ لہٰذا، جب ڈیٹا سیٹ کافی بڑا ہو تو خالی اقدار والی قطاروں کو ختم کرنا مناسب ہوتا ہے۔\n", + "جو ڈیٹا ہم اپنے ماڈل کو فراہم کرتے ہیں، اس کی مقدار براہ راست اس کی کارکردگی پر اثر ڈالتی ہے۔ خالی قدروں کو ہٹانے کا مطلب یہ ہے کہ ہم ڈیٹا پوائنٹس کی تعداد کم کر رہے ہیں، اور اس طرح ڈیٹاسیٹ کا سائز بھی کم ہو رہا ہے۔ لہٰذا، یہ مشورہ دیا جاتا ہے کہ جب ڈیٹاسیٹ کافی بڑا ہو تو خالی قدروں والی قطاروں کو ہٹا دیا جائے۔\n", "\n", - "ایک اور صورتحال یہ ہو سکتی ہے کہ کسی خاص قطار یا کالم میں بہت زیادہ خالی اقدار ہوں۔ ایسی صورت میں انہیں ختم کیا جا سکتا ہے کیونکہ وہ ہماری تجزیہ میں زیادہ مددگار نہیں ہوں گے، کیونکہ اس قطار/کالم کے زیادہ تر ڈیٹا موجود نہیں ہے۔\n", + "ایک اور صورت یہ ہو سکتی ہے کہ کسی خاص قطار یا کالم میں بہت زیادہ خالی قدریں ہوں۔ تب، انہیں ہٹایا جا سکتا ہے کیونکہ وہ ہماری تجزیے میں زیادہ قدر نہیں ڈالیں گے کیونکہ اس قطار/کالم کے زیادہ تر ڈیٹا غائب ہیں۔\n", "\n", - "خالی اقدار کی شناخت سے آگے، pandas ایک آسان طریقہ فراہم کرتا ہے جس سے `Series` اور `DataFrame`s سے خالی اقدار کو ختم کیا جا سکتا ہے۔ اس کو عملی طور پر دیکھنے کے لیے، آئیے `example3` پر واپس چلتے ہیں۔ `DataFrame.dropna()` فنکشن خالی اقدار والی قطاروں کو ختم کرنے میں مدد کرتا ہے۔\n" + "خالی قدروں کی شناخت سے آگے، pandas ایک آسان طریقہ فراہم کرتا ہے `Series` اور `DataFrame`s سے خالی قدروں کو ہٹانے کا۔ اس کو عملی طور پر دیکھنے کے لیے، آئیے `example3` پر واپس چلتے ہیں۔ `DataFrame.dropna()` فنکشن خالی قدروں والی قطاروں کو ہٹانے میں مدد کرتا ہے۔\n" ] }, { @@ -1117,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "نوٹ کریں کہ یہ آپ کے `example3[example3.notnull()]` کے نتیجے جیسا نظر آنا چاہیے۔ یہاں فرق یہ ہے کہ، صرف ماسک کیے گئے اقدار پر انڈیکسنگ کرنے کے بجائے، `dropna` نے `Series` `example3` سے وہ گمشدہ اقدار ہٹا دی ہیں۔\n", + "نوٹ کریں کہ یہ آپ کے `example3[example3.notnull()]` کے آؤٹ پٹ کی طرح نظر آنا چاہیے۔ یہاں فرق یہ ہے کہ، صرف ماسک شدہ اقدار پر انڈیکسنگ کرنے کے بجائے، `dropna` نے `Series` `example3` سے وہ گمشدہ اقدار ہٹا دی ہیں۔\n", "\n", - "چونکہ DataFrames دو جہتوں پر مشتمل ہوتے ہیں، یہ ڈیٹا ہٹانے کے لیے مزید اختیارات فراہم کرتے ہیں۔\n" + "چونکہ DataFrames دو جہتوں کے حامل ہوتے ہیں، یہ ڈیٹا کو ہٹانے کے لیے مزید اختیارات فراہم کرتے ہیں۔\n" ] }, { @@ -1209,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(کیا آپ نے دیکھا کہ pandas نے `NaN`s کو ایڈجسٹ کرنے کے لیے دو کالمز کو فلوٹس میں تبدیل کر دیا؟)\n", + "(کیا آپ نے دیکھا کہ pandas نے `NaN`s کو ایڈجسٹ کرنے کے لیے دو کالمز کو floats میں تبدیل کر دیا؟)\n", "\n", - "آپ `DataFrame` سے ایک واحد ویلیو کو حذف نہیں کر سکتے، اس لیے آپ کو مکمل قطاریں یا کالمز حذف کرنے ہوں گے۔ یہ اس بات پر منحصر ہے کہ آپ کیا کر رہے ہیں، آپ ایک یا دوسرا طریقہ اختیار کر سکتے ہیں، اور اسی لیے pandas آپ کو دونوں کے لیے آپشنز دیتا ہے۔ کیونکہ ڈیٹا سائنس میں، کالمز عام طور پر متغیرات کی نمائندگی کرتے ہیں اور قطاریں مشاہدات کی، اس لیے آپ زیادہ تر ڈیٹا کی قطاریں حذف کرنے کا رجحان رکھتے ہیں؛ `dropna()` کی ڈیفالٹ سیٹنگ یہ ہے کہ وہ تمام قطاریں حذف کر دے جو کسی بھی null ویلیو پر مشتمل ہوں:\n" + "آپ `DataFrame` سے ایک واحد ویلیو کو نہیں ہٹا سکتے، اس لیے آپ کو مکمل قطاریں یا کالمز ہٹانے ہوں گے۔ جو کام آپ کر رہے ہیں اس پر منحصر ہے، آپ ایک یا دوسرا انتخاب کر سکتے ہیں، اور اسی لیے pandas آپ کو دونوں کے لیے اختیارات دیتا ہے۔ کیونکہ ڈیٹا سائنس میں، کالمز عام طور پر متغیرات کی نمائندگی کرتے ہیں اور قطاریں مشاہدات کی، آپ زیادہ تر ڈیٹا کی قطاریں ہٹانے کو ترجیح دیں گے؛ `dropna()` کی ڈیفالٹ سیٹنگ یہ ہے کہ وہ تمام قطاریں ہٹا دے جو کسی بھی null ویلیو پر مشتمل ہوں:\n" ] }, { @@ -1284,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "اگر ضروری ہو تو آپ کالمز سے NA ویلیوز کو ہٹا سکتے ہیں۔ ایسا کرنے کے لیے `axis=1` استعمال کریں:\n" + "اگر ضروری ہو، تو آپ کالمز سے NA ویلیوز کو ہٹا سکتے ہیں۔ ایسا کرنے کے لیے `axis=1` استعمال کریں:\n" ] }, { @@ -1363,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "یہ بات ذہن میں رکھیں کہ یہ خاص طور پر چھوٹے ڈیٹاسیٹس میں آپ کے مطلوبہ ڈیٹا کا کافی حصہ ختم کر سکتا ہے۔ اگر آپ صرف وہ قطاریں یا کالم حذف کرنا چاہتے ہیں جن میں کچھ یا تمام خالی قدریں ہوں، تو آپ `dropna` میں `how` اور `thresh` پیرامیٹرز کے ذریعے یہ ترتیب دے سکتے ہیں۔\n", + "نوٹ کریں کہ یہ بہت سا ڈیٹا ختم کر سکتا ہے جو آپ رکھنا چاہتے ہیں، خاص طور پر چھوٹے ڈیٹا سیٹس میں۔ اگر آپ صرف وہ قطاریں یا کالم ختم کرنا چاہتے ہیں جن میں کئی یا تمام null ویلیوز ہوں؟ آپ `dropna` میں `how` اور `thresh` پیرامیٹرز کے ذریعے یہ سیٹنگز متعین کرتے ہیں۔\n", "\n", - "ڈیفالٹ کے طور پر، `how='any'` ہوتا ہے (اگر آپ خود چیک کرنا چاہیں یا دیکھنا چاہیں کہ اس میتھڈ کے اور کون سے پیرامیٹرز ہیں، تو کوڈ سیل میں `example4.dropna?` چلائیں)۔ آپ متبادل طور پر `how='all'` بھی استعمال کر سکتے ہیں تاکہ صرف وہ قطاریں یا کالم حذف کیے جائیں جن میں تمام قدریں خالی ہوں۔ آئیے اگلی مشق میں اپنے مثال کے `DataFrame` کو بڑھا کر یہ عمل دیکھتے ہیں۔\n" + "ڈیفالٹ طور پر، `how='any'` ہوتا ہے (اگر آپ خود چیک کرنا چاہتے ہیں یا دیکھنا چاہتے ہیں کہ اس میتھڈ کے دیگر پیرامیٹرز کیا ہیں، تو کوڈ سیل میں `example4.dropna?` چلائیں)۔ آپ متبادل طور پر `how='all'` متعین کر سکتے ہیں تاکہ صرف وہ قطاریں یا کالم ختم کیے جائیں جن میں تمام null ویلیوز ہوں۔ آئیے اپنے مثال کے `DataFrame` کو اگلی مشق میں دیکھتے ہیں تاکہ یہ عمل واضح ہو۔\n" ] }, { @@ -1458,10 +1457,10 @@ }, "source": [ "> اہم نکات:\n", - "1. صرف اسی وقت خالی قدروں کو ہٹانا اچھا خیال ہے جب ڈیٹا سیٹ کافی بڑا ہو۔\n", - "2. مکمل قطاریں یا کالم ہٹائے جا سکتے ہیں اگر ان میں زیادہ تر ڈیٹا غائب ہو۔\n", - "3. `DataFrame.dropna(axis=)` میتھڈ خالی قدروں کو ہٹانے میں مدد کرتا ہے۔ `axis` دلیل یہ ظاہر کرتی ہے کہ قطاریں ہٹانی ہیں یا کالم۔\n", - "4. `how` دلیل بھی استعمال کی جا سکتی ہے۔ ڈیفالٹ میں یہ `any` پر سیٹ ہوتی ہے۔ اس لیے یہ صرف ان قطاروں/کالموں کو ہٹاتی ہے جن میں کوئی بھی خالی قدر ہو۔ اسے `all` پر سیٹ کیا جا سکتا ہے تاکہ یہ ظاہر کیا جا سکے کہ ہم صرف ان قطاروں/کالموں کو ہٹائیں گے جہاں تمام قدریں خالی ہوں۔\n" + "1. null ویلیوز کو ختم کرنا صرف تب ہی اچھا خیال ہے جب ڈیٹا سیٹ کافی بڑا ہو۔\n", + "2. مکمل قطاریں یا کالم ختم کیے جا سکتے ہیں اگر ان میں زیادہ تر ڈیٹا غائب ہو۔\n", + "3. `DataFrame.dropna(axis=)` میتھڈ null ویلیوز کو ختم کرنے میں مدد کرتا ہے۔ `axis` آرگومنٹ بتاتا ہے کہ قطاریں ختم کی جائیں یا کالم۔\n", + "4. `how` آرگومنٹ بھی استعمال کیا جا سکتا ہے۔ ڈیفالٹ میں یہ `any` پر سیٹ ہوتا ہے، اس لیے یہ صرف ان قطاروں/کالموں کو ختم کرتا ہے جن میں کوئی بھی null ویلیو ہو۔ اسے `all` پر سیٹ کیا جا سکتا ہے تاکہ صرف ان قطاروں/کالموں کو ختم کیا جائے جہاں تمام ویلیوز null ہوں۔\n" ] }, { @@ -1568,7 +1567,7 @@ "id": "fmSFnzZegRsG" }, "source": [ - "یہاں، پہلی اور آخری قطار کو ہٹا دیا گیا ہے، کیونکہ ان میں صرف دو غیر خالی اقدار موجود ہیں۔\n" + "یہاں، پہلی اور آخری قطار کو حذف کر دیا گیا ہے، کیونکہ ان میں صرف دو غیر خالی اقدار موجود ہیں۔\n" ] }, { @@ -1577,11 +1576,11 @@ "id": "mCcxLGyUgRsG" }, "source": [ - "### خالی قدروں کو پُر کرنا\n", + "### خالی قدروں کو بھرنا\n", "\n", - "کبھی کبھار خالی قدروں کو ایسی قدروں سے پُر کرنا مناسب ہوتا ہے جو ممکنہ طور پر درست ہو سکتی ہیں۔ خالی قدروں کو پُر کرنے کے لیے چند تکنیکیں موجود ہیں۔ پہلی تکنیک یہ ہے کہ ڈومین نالج (یعنی اس موضوع کا علم جس پر ڈیٹا سیٹ مبنی ہے) کا استعمال کرتے ہوئے کسی طرح خالی قدروں کا اندازہ لگایا جائے۔\n", + "کبھی کبھار خالی قدروں کو ایسی قدروں سے بھرنا مناسب ہوتا ہے جو ممکنہ طور پر درست ہو سکتی ہیں۔ خالی قدروں کو بھرنے کے لیے چند تکنیکیں موجود ہیں۔ پہلی تکنیک یہ ہے کہ موضوع کے علم (جس پر ڈیٹا سیٹ مبنی ہے) کا استعمال کرتے ہوئے خالی قدروں کا اندازہ لگایا جائے۔\n", "\n", - "آپ `isnull` کا استعمال کر کے یہ کام کر سکتے ہیں، لیکن یہ خاصا محنت طلب ہو سکتا ہے، خاص طور پر اگر آپ کے پاس پُر کرنے کے لیے بہت سی قدریں ہوں۔ چونکہ یہ ڈیٹا سائنس میں ایک عام کام ہے، pandas `fillna` فراہم کرتا ہے، جو `Series` یا `DataFrame` کی ایک کاپی واپس کرتا ہے، جس میں خالی قدریں آپ کی منتخب کردہ قدروں سے تبدیل ہو چکی ہوتی ہیں۔ آئیے ایک اور مثال `Series` بناتے ہیں تاکہ دیکھ سکیں کہ یہ عملی طور پر کیسے کام کرتا ہے۔\n" + "آپ `isnull` کا استعمال کر کے یہ کام کر سکتے ہیں، لیکن یہ خاصا محنت طلب ہو سکتا ہے، خاص طور پر اگر آپ کے پاس بھرنے کے لیے بہت سی قدریں ہوں۔ چونکہ یہ کام ڈیٹا سائنس میں بہت عام ہے، pandas `fillna` فراہم کرتا ہے، جو `Series` یا `DataFrame` کی ایک کاپی واپس کرتا ہے جس میں خالی قدریں آپ کی منتخب کردہ قدر سے بدل دی جاتی ہیں۔ آئیے ایک اور مثال `Series` بناتے ہیں تاکہ دیکھ سکیں کہ یہ عملی طور پر کیسے کام کرتا ہے۔\n" ] }, { @@ -1590,12 +1589,12 @@ "id": "CE8S7louLezV" }, "source": [ - "### غیر عددی ڈیٹا (Categorical Data)\n", - "سب سے پہلے غیر عددی ڈیٹا پر غور کرتے ہیں۔ ڈیٹا سیٹس میں ہمارے پاس کالمز ہوتے ہیں جن میں غیر عددی ڈیٹا ہوتا ہے۔ مثلاً جنس، صحیح یا غلط وغیرہ۔\n", + "### زمرہ بندی ڈیٹا (غیر عددی)\n", + "سب سے پہلے، آئیے غیر عددی ڈیٹا پر غور کریں۔ ڈیٹا سیٹس میں، ہمارے پاس زمرہ بندی ڈیٹا والے کالمز ہوتے ہیں۔ مثلاً جنس، صحیح یا غلط وغیرہ۔\n", "\n", - "زیادہ تر ان صورتوں میں، ہم گمشدہ اقدار کو کالم کے `mode` سے بدل دیتے ہیں۔ فرض کریں، ہمارے پاس 100 ڈیٹا پوائنٹس ہیں، جن میں سے 90 نے صحیح کہا، 8 نے غلط کہا اور 2 نے کچھ نہیں بھرا۔ تو ہم ان 2 کو صحیح سے بھر سکتے ہیں، پورے کالم کو مدنظر رکھتے ہوئے۔\n", + "زیادہ تر صورتوں میں، ہم گمشدہ اقدار کو کالم کے `mode` سے بدل دیتے ہیں۔ فرض کریں، ہمارے پاس 100 ڈیٹا پوائنٹس ہیں، جن میں سے 90 نے صحیح کہا، 8 نے غلط کہا اور 2 نے کچھ نہیں بھرا۔ تو ہم ان 2 کو صحیح سے بھر سکتے ہیں، پورے کالم کو مدنظر رکھتے ہوئے۔\n", "\n", - "یہاں دوبارہ ہم ڈومین نالج کا استعمال کر سکتے ہیں۔ آئیے ایک مثال پر غور کرتے ہیں جہاں ہم mode سے بھرائی کرتے ہیں۔\n" + "یہاں بھی ہم ڈومین نالج استعمال کر سکتے ہیں۔ آئیے `mode` سے بھرنے کی ایک مثال پر غور کریں۔\n" ] }, { @@ -1700,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "اب، آئیے پہلے موڈ تلاش کریں اس سے پہلے کہ `None` کی قدر کو موڈ سے بھرا جائے۔\n" + ] }, { "cell_type": "code", @@ -1735,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "تو، ہم None کو True سے بدل دیں گے۔\n" + ] }, { "cell_type": "code", @@ -1845,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "جیسا کہ ہم دیکھ سکتے ہیں، خالی قدر کو تبدیل کر دیا گیا ہے۔ کہنے کی ضرورت نہیں، ہم نے `'True'` کی جگہ کچھ بھی لکھا ہوتا اور وہ تبدیل ہو جاتا۔\n" + "جیسا کہ ہم دیکھ سکتے ہیں، خالی قدر کو تبدیل کر دیا گیا ہے۔ کہنے کی ضرورت نہیں، ہم اس جگہ کچھ بھی لکھ سکتے تھے یا `'True'` اور یہ تبدیل ہو جاتا۔\n" ] }, { @@ -1857,14 +1860,14 @@ "### عددی ڈیٹا\n", "اب، عددی ڈیٹا کی بات کرتے ہیں۔ یہاں، گمشدہ اقدار کو تبدیل کرنے کے دو عام طریقے ہیں:\n", "\n", - "1. قطار کے میڈین سے تبدیل کریں \n", - "2. قطار کے اوسط سے تبدیل کریں \n", + "1. قطار کے میڈین سے تبدیل کریں\n", + "2. قطار کے اوسط سے تبدیل کریں\n", "\n", - "ہم میڈین سے تبدیل کرتے ہیں، جب ڈیٹا میں آؤٹ لائرز کے ساتھ جھکاؤ ہو۔ اس کی وجہ یہ ہے کہ میڈین آؤٹ لائرز کے لیے مضبوط ہوتا ہے۔\n", + "ہم میڈین سے تبدیل کرتے ہیں، جب ڈیٹا میں آؤٹ لائرز کے ساتھ اسکیو ہوتا ہے۔ اس کی وجہ یہ ہے کہ میڈین آؤٹ لائرز کے لیے مضبوط ہے۔\n", "\n", "جب ڈیٹا نارملائز ہو، تو ہم اوسط استعمال کر سکتے ہیں، کیونکہ اس صورت میں اوسط اور میڈین کافی قریب ہوں گے۔\n", "\n", - "سب سے پہلے، آئیے ایک کالم لیتے ہیں جو عام طور پر تقسیم شدہ ہے اور گمشدہ قدر کو کالم کے اوسط سے بھر دیتے ہیں۔\n" + "سب سے پہلے، آئیے ایک کالم لیتے ہیں جو عام طور پر تقسیم شدہ ہے اور گمشدہ قدر کو کالم کے اوسط سے بھرتے ہیں۔\n" ] }, { @@ -2004,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "میان سے بھرنا\n" + ] }, { "cell_type": "code", @@ -2113,7 +2118,7 @@ "id": "jIvF13a1i00Z" }, "source": [ - "آئیے اب ایک اور ڈیٹا فریم آزمائیں، اور اس بار ہم None کی قدروں کو کالم کے درمیانی قدر سے تبدیل کریں گے۔\n" + "آئیے اب ایک اور ڈیٹا فریم آزمائیں، اور اس بار ہم None کی قدروں کو کالم کے درمیانی قدر سے بدل دیں گے۔\n" ] }, { @@ -2219,7 +2224,7 @@ "id": "mM1GpXYmjHnc" }, "source": [ - "دوسرے کالم کا میڈین ہے\n" + "دوسرے ستون کا میڈین ہے\n" ] }, { @@ -2254,7 +2259,7 @@ "id": "z9PLF75Jj_1s" }, "source": [ - "مڈین سے بھرنا\n" + "میڈین کے ساتھ بھرنا\n" ] }, { @@ -2355,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "جیسا کہ ہم دیکھ سکتے ہیں، NaN کی قدر کو کالم کے درمیانی قدر سے بدل دیا گیا ہے۔\n" + "جیسا کہ ہم دیکھ سکتے ہیں، NaN کی قدر کو کالم کے میڈین سے تبدیل کر دیا گیا ہے۔\n" ] }, { @@ -2397,7 +2402,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "آپ تمام خالی اندراجات کو ایک واحد قدر جیسے `0` سے بھر سکتے ہیں۔\n" + "آپ تمام خالی اندراجات کو ایک واحد قدر، جیسے `0` سے بھر سکتے ہیں:\n" ] }, { @@ -2438,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "اہم نکات: \n", - "1. گمشدہ اقدار کو بھرنا تب کیا جانا چاہیے جب یا تو ڈیٹا کم ہو یا گمشدہ ڈیٹا کو بھرنے کے لیے کوئی حکمت عملی موجود ہو۔ \n", - "2. گمشدہ اقدار کو اندازہ لگا کر بھرنے کے لیے ڈومین علم کا استعمال کیا جا سکتا ہے۔ \n", - "3. زمرہ جاتی ڈیٹا کے لیے، زیادہ تر گمشدہ اقدار کو کالم کے موڈ سے تبدیل کیا جاتا ہے۔ \n", - "4. عددی ڈیٹا کے لیے، گمشدہ اقدار کو عام طور پر کالمز کے اوسط (نارملائزڈ ڈیٹا سیٹس کے لیے) یا میڈین سے بھر دیا جاتا ہے۔ \n" + "> اہم نکات:\n", + "1. گمشدہ اقدار کو بھرنا تب ضروری ہوتا ہے جب یا تو ڈیٹا کم ہو یا گمشدہ ڈیٹا کو بھرنے کے لیے کوئی حکمت عملی موجود ہو۔\n", + "2. گمشدہ اقدار کو اندازے سے بھرنے کے لیے ڈومین علم کا استعمال کیا جا سکتا ہے۔\n", + "3. زمرہ جاتی ڈیٹا کے لیے، زیادہ تر گمشدہ اقدار کو کالم کے موڈ سے تبدیل کیا جاتا ہے۔\n", + "4. عددی ڈیٹا کے لیے، گمشدہ اقدار کو عام طور پر کالمز کے اوسط (نارملائزڈ ڈیٹا سیٹس کے لیے) یا میڈین سے بھرا جاتا ہے۔\n" ] }, { @@ -2473,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "آپ خالی قدروں کو **آگے بھر** سکتے ہیں، یعنی آخری درست قدر کو استعمال کرتے ہوئے خالی جگہ کو بھرنا:\n" + "آپ null قدروں کو **آگے بھر** سکتے ہیں، یعنی آخری درست قدر کو استعمال کرتے ہوئے null کو بھرنا:\n" ] }, { @@ -2514,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "آپ اگلے درست قدر کو پیچھے کی طرف پھیلانے کے لیے **بیک فل** بھی کر سکتے ہیں تاکہ ایک خالی جگہ کو بھر سکیں:\n" + "آپ اگلے درست قدر کو پیچھے کی طرف پھیلانے کے لیے **بیک فل** بھی کر سکتے ہیں تاکہ ایک نل کو بھر سکیں۔\n" ] }, { @@ -2729,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "نوٹ کریں کہ جب پچھلی قدر فارورڈ فلنگ کے لیے دستیاب نہ ہو، تو خالی قدر برقرار رہتی ہے۔\n" + "نوٹ کریں کہ جب فارورڈ فلنگ کے لیے پچھلی قدر دستیاب نہیں ہوتی، تو خالی قدر برقرار رہتی ہے۔\n" ] }, { @@ -2853,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "نوٹ کریں کہ کالم 3 ابھی تک خالی ہے: ڈیفالٹ ترتیب یہ ہے کہ قدریں قطار وار بھری جائیں۔\n", + "نوٹ کریں کہ کالم 3 ابھی بھی خالی ہے: ڈیفالٹ سمت یہ ہے کہ اقدار کو قطار کے لحاظ سے بھرا جائے۔\n", "\n", - "> **خلاصہ:** آپ کے ڈیٹا سیٹس میں موجود خالی قدروں سے نمٹنے کے کئی طریقے ہیں۔ جو خاص حکمت عملی آپ اپناتے ہیں (انہیں ہٹانا، تبدیل کرنا، یا یہاں تک کہ کس طرح تبدیل کرنا) اس ڈیٹا کی خصوصیات پر منحصر ہونا چاہیے۔ جتنا زیادہ آپ ڈیٹا سیٹس کے ساتھ کام کریں گے اور ان سے تعامل کریں گے، اتنا ہی بہتر آپ خالی قدروں سے نمٹنے کا طریقہ سمجھ سکیں گے۔\n" + "> **اہم نکتہ:** اپنے ڈیٹا سیٹس میں موجود خالی اقدار سے نمٹنے کے کئی طریقے ہیں۔ جو خاص حکمت عملی آپ اپناتے ہیں (انہیں ہٹانا، تبدیل کرنا، یا یہاں تک کہ کس طرح تبدیل کرنا) وہ ڈیٹا کی خصوصیات پر منحصر ہونا چاہیے۔ جتنا زیادہ آپ ڈیٹا سیٹس کے ساتھ کام کریں گے اور ان سے تعامل کریں گے، اتنا ہی بہتر آپ خالی اقدار سے نمٹنے کا طریقہ سمجھیں گے۔\n" ] }, { @@ -2866,7 +2871,7 @@ "source": [ "### زمرہ وار ڈیٹا کو انکوڈ کرنا\n", "\n", - "مشین لرننگ ماڈلز صرف نمبروں اور کسی بھی قسم کے عددی ڈیٹا کے ساتھ کام کرتے ہیں۔ یہ ہاں اور نہ کے درمیان فرق نہیں بتا سکتے، لیکن یہ 0 اور 1 کے درمیان فرق کر سکتے ہیں۔ لہذا، گمشدہ قدروں کو پُر کرنے کے بعد، ہمیں زمرہ وار ڈیٹا کو کسی عددی شکل میں انکوڈ کرنا ہوگا تاکہ ماڈل اسے سمجھ سکے۔\n", + "مشین لرننگ ماڈلز صرف نمبروں اور کسی بھی قسم کے عددی ڈیٹا کے ساتھ کام کرتے ہیں۔ یہ \"ہاں\" اور \"نہیں\" کے درمیان فرق نہیں بتا سکتے، لیکن یہ 0 اور 1 کے درمیان فرق کر سکتے ہیں۔ لہذا، گمشدہ اقدار کو بھرنے کے بعد، ہمیں زمرہ وار ڈیٹا کو کسی عددی شکل میں انکوڈ کرنا ہوگا تاکہ ماڈل اسے سمجھ سکے۔\n", "\n", "انکوڈنگ دو طریقوں سے کی جا سکتی ہے۔ ہم اگلے حصے میں ان پر بات کریں گے۔\n" ] @@ -2879,7 +2884,7 @@ "source": [ "**لیبل انکوڈنگ**\n", "\n", - "لیبل انکوڈنگ بنیادی طور پر ہر کیٹیگری کو ایک نمبر میں تبدیل کرنے کا عمل ہے۔ مثال کے طور پر، فرض کریں کہ ہمارے پاس ایئرلائن مسافروں کا ایک ڈیٹا سیٹ ہے اور اس میں ایک کالم ہے جو ان کی کلاس کو ظاہر کرتا ہے، جیسے ['بزنس کلاس', 'اکانومی کلاس', 'فرسٹ کلاس']۔ اگر اس پر لیبل انکوڈنگ کی جائے تو یہ [0,1,2] میں تبدیل ہو جائے گا۔ آئیے کوڈ کے ذریعے ایک مثال دیکھتے ہیں۔ چونکہ ہم آنے والے نوٹ بکس میں `scikit-learn` سیکھیں گے، اس لیے ہم اسے یہاں استعمال نہیں کریں گے۔\n" + "لیبل انکوڈنگ بنیادی طور پر ہر زمرے کو ایک نمبر میں تبدیل کرنا ہے۔ مثال کے طور پر، فرض کریں کہ ہمارے پاس ایئر لائن مسافروں کا ایک ڈیٹا سیٹ ہے اور اس میں ایک کالم ہے جو ان کی کلاس کو ظاہر کرتا ہے، جیسے ['بزنس کلاس', 'اکانومی کلاس', 'فرسٹ کلاس']۔ اگر اس پر لیبل انکوڈنگ کی جائے تو یہ [0,1,2] میں تبدیل ہو جائے گا۔ آئیے کوڈ کے ذریعے ایک مثال دیکھتے ہیں۔ چونکہ ہم آنے والے نوٹ بکس میں `scikit-learn` سیکھیں گے، اس لیے ہم اسے یہاں استعمال نہیں کریں گے۔\n" ] }, { @@ -3102,7 +3107,7 @@ "source": [ "**ون ہاٹ انکوڈنگ**\n", "\n", - "ایک اور قسم کی انکوڈنگ ون ہاٹ انکوڈنگ ہے۔ اس قسم کی انکوڈنگ میں، کالم کی ہر کیٹیگری کو ایک الگ کالم کے طور پر شامل کیا جاتا ہے اور ہر ڈیٹا پوائنٹ کو 0 یا 1 دیا جاتا ہے اس بنیاد پر کہ آیا وہ کیٹیگری موجود ہے یا نہیں۔ لہذا، اگر n مختلف کیٹیگریز ہوں، تو n کالمز ڈیٹا فریم میں شامل کیے جائیں گے۔\n", + "ون ہاٹ انکوڈنگ ایک اور قسم کی انکوڈنگ ہے۔ اس قسم کی انکوڈنگ میں، کالم کی ہر کیٹیگری کو ایک الگ کالم کے طور پر شامل کیا جاتا ہے اور ہر ڈیٹا پوائنٹ کو 0 یا 1 دیا جاتا ہے، اس بنیاد پر کہ آیا وہ کیٹیگری موجود ہے یا نہیں۔ لہذا، اگر n مختلف کیٹیگریز ہوں، تو n کالمز ڈیٹا فریم میں شامل کیے جائیں گے۔\n", "\n", "مثال کے طور پر، آئیے وہی ہوائی جہاز کی کلاس کی مثال لیتے ہیں۔ کیٹیگریز تھیں: ['بزنس کلاس', 'اکانومی کلاس', 'فرسٹ کلاس']۔ تو، اگر ہم ون ہاٹ انکوڈنگ کریں، تو درج ذیل تین کالمز ڈیٹا سیٹ میں شامل کیے جائیں گے: ['class_business class', 'class_economy class', 'class_first class']۔\n" ] @@ -3212,7 +3217,7 @@ "id": "aVnZ7paDrWmb" }, "source": [ - "آئیے پہلی کالم پر ون ہاٹ انکوڈنگ کریں۔\n" + "آئیے پہلی کالم پر ون ہاٹ انکوڈنگ انجام دیں۔\n" ] }, { @@ -3337,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "ہر ایک ہاٹ انکوڈڈ کالم میں 0 یا 1 ہوتا ہے، جو یہ بتاتا ہے کہ آیا وہ زمرہ اس ڈیٹا پوائنٹ کے لیے موجود ہے۔\n" + "ہر ایک ہاٹ انکوڈڈ کالم میں 0 یا 1 ہوتا ہے، جو یہ ظاہر کرتا ہے کہ آیا وہ زمرہ اس ڈیٹا پوائنٹ کے لیے موجود ہے۔\n" ] }, { @@ -3346,11 +3351,10 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "ہم ون ہاٹ انکوڈنگ کب استعمال کرتے ہیں؟ \n", - "ون ہاٹ انکوڈنگ درج ذیل میں سے کسی ایک یا دونوں صورتوں میں استعمال کی جاتی ہے:\n", + "ہم ایک ہاٹ انکوڈنگ کب استعمال کرتے ہیں؟ ایک ہاٹ انکوڈنگ درج ذیل میں سے ایک یا دونوں صورتوں میں استعمال کی جاتی ہے:\n", "\n", - "1. جب زمروں کی تعداد اور ڈیٹا سیٹ کا سائز چھوٹا ہو۔ \n", - "2. جب زمرے کسی خاص ترتیب کی پیروی نہ کرتے ہوں۔ \n" + "1. جب زمروں کی تعداد اور ڈیٹا سیٹ کا سائز چھوٹا ہو۔\n", + "2. جب زمرے کسی خاص ترتیب کی پیروی نہ کرتے ہوں۔\n" ] }, { @@ -3359,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> اہم نکات: \n", - "1. انکوڈنگ غیر عددی ڈیٹا کو عددی ڈیٹا میں تبدیل کرنے کے لیے کی جاتی ہے۔ \n", - "2. انکوڈنگ کی دو اقسام ہیں: لیبل انکوڈنگ اور ون ہاٹ انکوڈنگ، اور دونوں کو ڈیٹاسیٹ کی ضروریات کے مطابق انجام دیا جا سکتا ہے۔ \n" + "> اہم نکات:\n", + "1. انکوڈنگ غیر عددی ڈیٹا کو عددی ڈیٹا میں تبدیل کرنے کے لیے کی جاتی ہے۔\n", + "2. انکوڈنگ کی دو اقسام ہیں: لیبل انکوڈنگ اور ون ہاٹ انکوڈنگ، جنہیں ڈیٹا سیٹ کی ضروریات کے مطابق انجام دیا جا سکتا ہے۔\n" ] }, { @@ -3372,9 +3376,9 @@ "source": [ "## ڈپلیکیٹ ڈیٹا کو ہٹانا\n", "\n", - "> **سیکھنے کا مقصد:** اس ذیلی حصے کے اختتام تک، آپ ڈیٹا فریمز سے ڈپلیکیٹ ویلیوز کی شناخت اور انہیں ہٹانے میں مہارت حاصل کر لیں گے۔\n", + "> **سیکھنے کا مقصد:** اس ذیلی حصے کے اختتام تک، آپ کو ڈیٹا فریمز سے ڈپلیکیٹ ویلیوز کی شناخت اور انہیں ہٹانے میں مہارت حاصل ہو جانی چاہیے۔\n", "\n", - "گمشدہ ڈیٹا کے علاوہ، آپ کو حقیقی دنیا کے ڈیٹا سیٹس میں اکثر ڈپلیکیٹ ڈیٹا کا سامنا ہوگا۔ خوش قسمتی سے، pandas ڈپلیکیٹ اندراجات کی شناخت اور انہیں ہٹانے کا ایک آسان طریقہ فراہم کرتا ہے۔\n" + "گمشدہ ڈیٹا کے علاوہ، آپ کو حقیقی دنیا کے ڈیٹا سیٹس میں اکثر ڈپلیکیٹ ڈیٹا کا سامنا کرنا پڑے گا۔ خوش قسمتی سے، pandas ڈپلیکیٹ اندراجات کا پتہ لگانے اور انہیں ہٹانے کا ایک آسان طریقہ فراہم کرتا ہے۔\n" ] }, { @@ -3383,9 +3387,9 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### نقل کی شناخت: `duplicated`\n", + "### ڈپلیکیٹس کی شناخت: `duplicated`\n", "\n", - "آپ pandas میں `duplicated` طریقہ استعمال کرکے آسانی سے نقل شدہ اقدار کو پہچان سکتے ہیں، جو ایک Boolean ماسک واپس کرتا ہے جو ظاہر کرتا ہے کہ آیا `DataFrame` میں کوئی اندراج پہلے والے کا نقل ہے۔ آئیے ایک اور مثال `DataFrame` بناتے ہیں تاکہ اسے عملی طور پر دیکھ سکیں۔\n" + "آپ pandas میں `duplicated` میتھڈ کا استعمال کرکے آسانی سے ڈپلیکیٹ ویلیوز کو پہچان سکتے ہیں، جو ایک Boolean ماسک واپس کرتا ہے جو یہ ظاہر کرتا ہے کہ آیا `DataFrame` میں کوئی اندراج پہلے والے کا ڈپلیکیٹ ہے۔ آئیے ایک اور مثال کے طور پر `DataFrame` بناتے ہیں تاکہ اسے عملی طور پر دیکھ سکیں۔\n" ] }, { @@ -3515,7 +3519,7 @@ }, "source": [ "### ڈپلیکیٹس کو ختم کرنا: `drop_duplicates`\n", - "`drop_duplicates` صرف ڈیٹا کی ایک کاپی واپس کرتا ہے جس کے تمام `duplicated` ویلیوز `False` ہیں:\n" + "`drop_duplicates` صرف ان ڈیٹا کی ایک کاپی واپس کرتا ہے جن کے تمام `duplicated` ویلیوز `False` ہیں:\n" ] }, { @@ -3598,7 +3602,7 @@ "id": "69AqoCZAgRsK" }, "source": [ - "`duplicated` اور `drop_duplicates` دونوں تمام کالمز کو مدنظر رکھنے کے لیے ڈیفالٹ ہیں لیکن آپ مخصوص کر سکتے ہیں کہ وہ آپ کے `DataFrame` میں صرف کالمز کے ایک ذیلی سیٹ کا جائزہ لیں:\n" + "`duplicated` اور `drop_duplicates` دونوں ڈیفالٹ طور پر تمام کالمز کو مدنظر رکھتے ہیں لیکن آپ یہ مخصوص کر سکتے ہیں کہ وہ آپ کے `DataFrame` میں صرف کالمز کے ایک ذیلی سیٹ کا جائزہ لیں:\n" ] }, { @@ -3675,7 +3679,523 @@ "id": "GvX4og1EgRsL" }, "source": [ - "> **حاصل کریں:** نقل شدہ ڈیٹا کو ہٹانا تقریباً ہر ڈیٹا سائنس منصوبے کا ایک لازمی حصہ ہے۔ نقل شدہ ڈیٹا آپ کے تجزیوں کے نتائج کو بدل سکتا ہے اور آپ کو غلط نتائج دے سکتا ہے!\n" + "> **حاصلِ کلام:** نقل شدہ ڈیٹا کو ہٹانا تقریباً ہر ڈیٹا سائنس منصوبے کا ایک لازمی حصہ ہے۔ نقل شدہ ڈیٹا آپ کے تجزیوں کے نتائج کو بدل سکتا ہے اور آپ کو غلط نتائج دے سکتا ہے!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## حقیقی دنیا کے ڈیٹا کے معیار کی جانچ\n", + "\n", + "> **سیکھنے کا مقصد:** اس حصے کے اختتام تک، آپ حقیقی دنیا کے ڈیٹا کے معیار کے عام مسائل جیسے غیر مستقل زمرہ جاتی اقدار، غیر معمولی عددی اقدار (آؤٹ لائرز)، اور معمولی فرق کے ساتھ نقل شدہ اداروں کا پتہ لگانے اور درست کرنے میں مہارت حاصل کر لیں گے۔\n", + "\n", + "اگرچہ گمشدہ اقدار اور بالکل نقل شدہ ڈیٹا عام مسائل ہیں، حقیقی دنیا کے ڈیٹا سیٹس میں اکثر زیادہ پیچیدہ مسائل شامل ہوتے ہیں:\n", + "\n", + "1. **غیر مستقل زمرہ جاتی اقدار**: ایک ہی زمرہ مختلف طریقوں سے لکھا گیا (جیسے \"USA\"، \"U.S.A\"، \"United States\")\n", + "2. **غیر معمولی عددی اقدار**: انتہائی آؤٹ لائرز جو ڈیٹا انٹری کی غلطیوں کی نشاندہی کرتے ہیں (جیسے عمر = 999)\n", + "3. **قریب قریب نقل شدہ قطاریں**: وہ ریکارڈز جو ایک ہی ادارے کی نمائندگی کرتے ہیں لیکن معمولی فرق کے ساتھ\n", + "\n", + "آئیے ان مسائل کا پتہ لگانے اور ان سے نمٹنے کے طریقے دریافت کرتے ہیں۔\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ایک نمونہ \"گندا\" ڈیٹاسیٹ بنانا\n", + "\n", + "سب سے پہلے، آئیے ایک نمونہ ڈیٹاسیٹ بناتے ہیں جس میں وہ مسائل شامل ہوں جو ہم عام طور پر حقیقی دنیا کے ڈیٹا میں دیکھتے ہیں:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. غیر متوازن زمرہ جاتی اقدار کا پتہ لگانا\n", + "\n", + "دھیان دیں کہ `country` کالم میں ایک ہی ممالک کے لیے متعدد نمائندگیاں موجود ہیں۔ آئیے ان بے ترتیبیوں کی نشاندہی کرتے ہیں:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### زمرہ وار اقدار کو معیاری بنانا\n", + "\n", + "ہم ان اقدار کو معیاری بنانے کے لیے ایک نقشہ بنا سکتے ہیں۔ ایک آسان طریقہ یہ ہے کہ انہیں چھوٹے حروف میں تبدیل کریں اور ایک نقشہ سازی کی ڈکشنری بنائیں:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**متبادل: دھندلے مماثلت کا استعمال**\n", + "\n", + "زیادہ پیچیدہ معاملات کے لیے، ہم `rapidfuzz` لائبریری کے ساتھ دھندلے سٹرنگ مماثلت کا استعمال کر سکتے ہیں تاکہ خودکار طور پر مشابہت رکھنے والے سٹرنگز کا پتہ لگایا جا سکے:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. غیر معمولی عددی قدروں کا پتہ لگانا (آؤٹ لائرز)\n", + "\n", + "`age` کالم کو دیکھتے ہوئے، ہمارے پاس کچھ مشکوک قدریں ہیں جیسے 199 اور -5۔ آئیے ان آؤٹ لائرز کا پتہ لگانے کے لیے شماریاتی طریقے استعمال کریں۔\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### آئی کیو آر (Interquartile Range) طریقہ استعمال کرنا\n", + "\n", + "آئی کیو آر طریقہ ایک مضبوط شماریاتی تکنیک ہے جو غیر معمولی اقدار کی شناخت کے لیے استعمال ہوتی ہے اور انتہائی اقدار کے لیے کم حساس ہے:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### زیڈ اسکور طریقہ استعمال کرنا\n", + "\n", + "زیڈ اسکور طریقہ اوسط سے معیاری انحرافات کی بنیاد پر غیر معمولی اقدار کی نشاندہی کرتا ہے:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### آؤٹ لائرز کو سنبھالنا\n", + "\n", + "جب آؤٹ لائرز کا پتہ چل جائے، تو انہیں کئی طریقوں سے سنبھالا جا سکتا ہے:\n", + "1. **ہٹائیں**: آؤٹ لائرز والی قطاریں حذف کریں (اگر وہ غلطیاں ہیں)\n", + "2. **حد مقرر کریں**: حد کے اقدار سے تبدیل کریں\n", + "3. **NaN سے تبدیل کریں**: انہیں گمشدہ ڈیٹا کے طور پر سمجھیں اور امپیوٹیشن تکنیک استعمال کریں\n", + "4. **رکھیں**: اگر وہ جائز انتہائی اقدار ہیں\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. قریب المثل قطاروں کا پتہ لگانا\n", + "\n", + "دھیان دیں کہ ہمارے ڈیٹا سیٹ میں \"John Smith\" کے لیے کئی اندراجات موجود ہیں جن میں قدرے مختلف اقدار ہیں۔ آئیے نام کی مماثلت کی بنیاد پر ممکنہ نقلیں شناخت کریں۔\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### دھندلے مماثلت کے ساتھ قریباً نقلیں تلاش کرنا\n", + "\n", + "زیادہ پیچیدہ نقلیں تلاش کرنے کے لیے، ہم دھندلے مماثلت کا استعمال کر سکتے ہیں تاکہ ملتے جلتے نام تلاش کیے جا سکیں:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### ڈپلیکیٹس کو ہینڈل کرنا\n", + "\n", + "جب ڈپلیکیٹس کی شناخت ہو جائے، تو آپ کو فیصلہ کرنا ہوگا کہ انہیں کیسے ہینڈل کریں:\n", + "1. **پہلی بار وقوع کو رکھیں**: `drop_duplicates(keep='first')` استعمال کریں\n", + "2. **آخری بار وقوع کو رکھیں**: `drop_duplicates(keep='last')` استعمال کریں\n", + "3. **معلومات کو جمع کریں**: ڈپلیکیٹ قطاروں سے معلومات کو یکجا کریں\n", + "4. **دستی جائزہ**: انسانی جائزے کے لیے نشان زد کریں\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### خلاصہ: مکمل ڈیٹا صفائی کا عمل\n", + "\n", + "آئیے اسے ایک جامع صفائی کے عمل میں یکجا کرتے ہیں:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 چیلنج مشق\n", + "\n", + "اب یہ آپ کی باری ہے! نیچے ایک نئی قطار دی گئی ہے جس میں کئی معیار کے مسائل ہیں۔ کیا آپ:\n", + "\n", + "1. اس قطار میں موجود تمام مسائل کی نشاندہی کر سکتے ہیں؟\n", + "2. ہر مسئلے کو صاف کرنے کے لیے کوڈ لکھ سکتے ہیں؟\n", + "3. صاف شدہ قطار کو ڈیٹاسیٹ میں شامل کر سکتے ہیں؟\n", + "\n", + "یہاں مسئلہ زدہ ڈیٹا ہے:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### اہم نکات\n", + "\n", + "1. **غیر مستقل زمروں** کا حقیقی دنیا کے ڈیٹا میں عام ہونا معمول کی بات ہے۔ ہمیشہ منفرد اقدار کو چیک کریں اور انہیں میپنگ یا فزی میچنگ کے ذریعے معیاری بنائیں۔\n", + "\n", + "2. **آؤٹ لائرز** آپ کے تجزیے پر نمایاں اثر ڈال سکتے ہیں۔ انہیں شناخت کرنے کے لیے ڈومین نالج کو شماریاتی طریقوں (IQR، Z-score) کے ساتھ استعمال کریں۔\n", + "\n", + "3. **قریب قریب نقلیں** بالکل نقلوں کی نسبت زیادہ مشکل ہوتی ہیں۔ انہیں پہچاننے کے لیے فزی میچنگ اور ڈیٹا کو نارملائز کرنے (لوئر کیس کرنا، اسپیس ہٹانا) پر غور کریں۔\n", + "\n", + "4. **ڈیٹا کی صفائی ایک تکراری عمل ہے**۔ آپ کو کئی تکنیکیں استعمال کرنی پڑ سکتی ہیں اور نتائج کا جائزہ لینا پڑ سکتا ہے، اس سے پہلے کہ آپ اپنے صاف شدہ ڈیٹا سیٹ کو حتمی شکل دیں۔\n", + "\n", + "5. **اپنے فیصلوں کو دستاویزی بنائیں**۔ یہ یاد رکھیں کہ آپ نے کون سے صفائی کے اقدامات کیے اور کیوں، کیونکہ یہ دوبارہ قابل عمل اور شفافیت کے لیے اہم ہے۔\n", + "\n", + "> **بہترین طریقہ:** ہمیشہ اپنے اصل \"گندے\" ڈیٹا کی ایک کاپی محفوظ رکھیں۔ اپنے سورس ڈیٹا فائلز کو کبھی اوور رائٹ نہ کریں - صاف شدہ ورژنز بنائیں اور واضح نام دینے کے اصول اپنائیں جیسے `data_cleaned.csv`۔\n" ] }, { @@ -3710,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-01T22:16:48+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:12:46+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "ur" } diff --git a/translations/vi/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/vi/2-Working-With-Data/08-data-preparation/notebook.ipynb index 696b5970..eaa1a233 100644 --- a/translations/vi/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/vi/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -6,17 +6,17 @@ "id": "rQ8UhzFpgRra" }, "source": [ - "# Chuẩn bị Dữ liệu\n", + "# Chuẩn bị dữ liệu\n", "\n", - "[Notebook gốc từ *Khoa học Dữ liệu: Giới thiệu về Machine Learning cho Khoa học Dữ liệu Python và Machine Learning Studio của Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[Notebook gốc từ *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio của Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## Khám phá thông tin `DataFrame`\n", "\n", - "> **Mục tiêu học tập:** Sau khi hoàn thành phần này, bạn sẽ cảm thấy thoải mái khi tìm kiếm thông tin tổng quát về dữ liệu được lưu trữ trong pandas DataFrames.\n", + "> **Mục tiêu học tập:** Sau phần này, bạn sẽ cảm thấy thoải mái khi tìm kiếm thông tin tổng quát về dữ liệu được lưu trữ trong pandas DataFrames.\n", "\n", - "Khi bạn đã tải dữ liệu của mình vào pandas, rất có thể nó sẽ ở dạng `DataFrame`. Tuy nhiên, nếu tập dữ liệu trong `DataFrame` của bạn có 60.000 hàng và 400 cột, làm thế nào để bạn bắt đầu hiểu được những gì mình đang làm việc? May mắn thay, pandas cung cấp một số công cụ tiện lợi để nhanh chóng xem thông tin tổng quan về một `DataFrame`, bên cạnh việc xem qua một vài hàng đầu tiên và cuối cùng.\n", + "Khi bạn đã tải dữ liệu vào pandas, rất có thể dữ liệu sẽ được lưu trong một `DataFrame`. Tuy nhiên, nếu tập dữ liệu trong `DataFrame` của bạn có 60.000 dòng và 400 cột, làm thế nào để bạn bắt đầu hiểu được dữ liệu mà mình đang làm việc? May mắn thay, pandas cung cấp một số công cụ tiện lợi để nhanh chóng xem thông tin tổng quát về một `DataFrame` ngoài việc xem vài dòng đầu tiên và cuối cùng.\n", "\n", - "Để khám phá chức năng này, chúng ta sẽ nhập thư viện scikit-learn của Python và sử dụng một tập dữ liệu mang tính biểu tượng mà mọi nhà khoa học dữ liệu đều đã thấy hàng trăm lần: tập dữ liệu *Iris* của nhà sinh học người Anh Ronald Fisher, được sử dụng trong bài báo năm 1936 của ông \"Sử dụng các phép đo đa chiều trong các vấn đề phân loại học\":\n" + "Để khám phá chức năng này, chúng ta sẽ nhập thư viện scikit-learn của Python và sử dụng một tập dữ liệu mang tính biểu tượng mà mọi nhà khoa học dữ liệu đều đã thấy hàng trăm lần: tập dữ liệu *Iris* của nhà sinh học người Anh Ronald Fisher được sử dụng trong bài báo năm 1936 của ông \"The use of multiple measurements in taxonomic problems\":\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "Chúng ta đã tải bộ dữ liệu Iris vào biến `iris_df`. Trước khi đi sâu vào dữ liệu, sẽ rất hữu ích nếu biết số lượng điểm dữ liệu chúng ta có và kích thước tổng thể của bộ dữ liệu. Việc xem xét khối lượng dữ liệu mà chúng ta đang xử lý là rất quan trọng.\n" + "Chúng tôi đã tải bộ dữ liệu Iris vào biến `iris_df`. Trước khi đi sâu vào dữ liệu, sẽ rất hữu ích nếu biết số lượng điểm dữ liệu chúng tôi có và kích thước tổng thể của bộ dữ liệu. Việc xem xét khối lượng dữ liệu mà chúng tôi đang xử lý là rất cần thiết.\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "Vì vậy, chúng ta đang xử lý 150 hàng và 4 cột dữ liệu. Mỗi hàng đại diện cho một điểm dữ liệu và mỗi cột đại diện cho một đặc điểm duy nhất liên quan đến khung dữ liệu. Nói cách khác, có 150 điểm dữ liệu, mỗi điểm chứa 4 đặc điểm.\n", + "Vậy, chúng ta đang xử lý 150 hàng và 4 cột dữ liệu. Mỗi hàng đại diện cho một điểm dữ liệu và mỗi cột đại diện cho một đặc điểm duy nhất liên quan đến khung dữ liệu. Nói cách khác, có 150 điểm dữ liệu, mỗi điểm chứa 4 đặc điểm.\n", "\n", - "`shape` ở đây là một thuộc tính của khung dữ liệu chứ không phải là một hàm, đó là lý do tại sao nó không kết thúc bằng một cặp dấu ngoặc đơn.\n" + "`shape` ở đây là một thuộc tính của khung dữ liệu chứ không phải là một hàm, vì vậy nó không kết thúc bằng một cặp dấu ngoặc đơn.\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "Bây giờ, chúng ta hãy xem xét 4 cột dữ liệu. Mỗi cột thực sự đại diện cho điều gì? Thuộc tính `columns` sẽ cung cấp cho chúng ta tên của các cột trong dataframe.\n" + "Bây giờ chúng ta sẽ tìm hiểu về 4 cột dữ liệu. Mỗi cột thực sự đại diện cho điều gì? Thuộc tính `columns` sẽ cung cấp cho chúng ta tên của các cột trong dataframe.\n" ] }, { @@ -181,8 +181,8 @@ }, "source": [ "Từ đây, chúng ta có thể rút ra một vài quan sát: \n", - "1. Kiểu dữ liệu của mỗi cột: Trong tập dữ liệu này, tất cả dữ liệu đều được lưu trữ dưới dạng số thực dấu phẩy động 64-bit. \n", - "2. Số lượng giá trị không null: Xử lý các giá trị null là một bước quan trọng trong việc chuẩn bị dữ liệu. Việc này sẽ được xử lý sau trong notebook. \n" + "1. Kiểu dữ liệu của mỗi cột: Trong tập dữ liệu này, tất cả dữ liệu đều được lưu dưới dạng số thực 64-bit. \n", + "2. Số lượng giá trị không null: Xử lý các giá trị null là một bước quan trọng trong việc chuẩn bị dữ liệu. Việc này sẽ được thực hiện sau trong notebook. \n" ] }, { @@ -322,7 +322,7 @@ "id": "zjjtW5hPGMuM" }, "source": [ - "Đầu ra ở trên hiển thị tổng số điểm dữ liệu, giá trị trung bình, độ lệch chuẩn, giá trị nhỏ nhất, tứ phân vị dưới (25%), trung vị (50%), tứ phân vị trên (75%) và giá trị lớn nhất của mỗi cột.\n" + "Kết quả trên hiển thị tổng số điểm dữ liệu, giá trị trung bình, độ lệch chuẩn, giá trị nhỏ nhất, tứ phân vị dưới (25%), trung vị (50%), tứ phân vị trên (75%) và giá trị lớn nhất của mỗi cột.\n" ] }, { @@ -332,9 +332,9 @@ }, "source": [ "### `DataFrame.head`\n", - "Với tất cả các hàm và thuộc tính đã đề cập ở trên, chúng ta đã có cái nhìn tổng quan về tập dữ liệu. Chúng ta biết có bao nhiêu điểm dữ liệu, có bao nhiêu đặc trưng, kiểu dữ liệu của từng đặc trưng và số lượng giá trị không null cho mỗi đặc trưng.\n", + "Với tất cả các hàm và thuộc tính đã đề cập ở trên, chúng ta đã có cái nhìn tổng quan về tập dữ liệu. Chúng ta biết có bao nhiêu điểm dữ liệu, có bao nhiêu đặc trưng, kiểu dữ liệu của mỗi đặc trưng và số lượng giá trị không null của mỗi đặc trưng.\n", "\n", - "Bây giờ là lúc xem xét chính dữ liệu. Hãy xem vài hàng đầu tiên (vài điểm dữ liệu đầu tiên) của `DataFrame` của chúng ta trông như thế nào:\n" + "Bây giờ là lúc xem xét chính dữ liệu. Hãy xem những hàng đầu tiên (những điểm dữ liệu đầu tiên) của `DataFrame` trông như thế nào:\n" ] }, { @@ -441,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "Như đầu ra ở đây, chúng ta có thể thấy năm (5) mục của tập dữ liệu. Nếu chúng ta nhìn vào chỉ mục ở bên trái, chúng ta phát hiện ra rằng đây là năm hàng đầu tiên.\n" + "Như đầu ra ở đây, chúng ta có thể thấy năm (5) mục của tập dữ liệu. Nếu chúng ta nhìn vào chỉ số ở bên trái, chúng ta sẽ thấy rằng đây là năm hàng đầu tiên.\n" ] }, { @@ -452,7 +452,7 @@ "source": [ "### Bài tập:\n", "\n", - "Từ ví dụ được đưa ra ở trên, rõ ràng rằng, theo mặc định, `DataFrame.head` trả về năm hàng đầu tiên của một `DataFrame`. Trong ô mã dưới đây, bạn có thể tìm ra cách hiển thị nhiều hơn năm hàng không?\n" + "Từ ví dụ được đưa ra ở trên, rõ ràng rằng mặc định, `DataFrame.head` trả về năm hàng đầu tiên của một `DataFrame`. Trong ô mã dưới đây, bạn có thể tìm ra cách hiển thị nhiều hơn năm hàng không?\n" ] }, { @@ -475,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "Một cách khác để xem dữ liệu là từ cuối (thay vì từ đầu). Đối lập với `DataFrame.head` là `DataFrame.tail`, chức năng này trả về năm hàng cuối cùng của một `DataFrame`:\n" + "Một cách khác để xem dữ liệu là từ cuối (thay vì từ đầu). Đối ngược với `DataFrame.head` là `DataFrame.tail`, nó trả về năm hàng cuối cùng của một `DataFrame`:\n" ] }, { @@ -582,11 +582,11 @@ "id": "31kBWfyLgRr3" }, "source": [ - "Trong thực tế, việc có thể dễ dàng kiểm tra vài hàng đầu tiên hoặc vài hàng cuối cùng của một `DataFrame` rất hữu ích, đặc biệt khi bạn đang tìm kiếm các giá trị ngoại lệ trong các tập dữ liệu có thứ tự.\n", + "Trong thực tế, việc dễ dàng kiểm tra vài hàng đầu tiên hoặc vài hàng cuối cùng của một `DataFrame` rất hữu ích, đặc biệt khi bạn đang tìm kiếm các giá trị ngoại lệ trong các tập dữ liệu có thứ tự.\n", "\n", - "Tất cả các hàm và thuộc tính được trình bày ở trên với sự hỗ trợ của các ví dụ mã đều giúp chúng ta có cái nhìn và cảm nhận về dữ liệu.\n", + "Tất cả các hàm và thuộc tính được trình bày ở trên với sự hỗ trợ của các ví dụ mã đều giúp chúng ta có cái nhìn tổng quan về dữ liệu.\n", "\n", - "> **Điểm rút ra:** Chỉ cần nhìn vào siêu dữ liệu về thông tin trong một DataFrame hoặc vài giá trị đầu tiên và cuối cùng của nó, bạn có thể có ngay một ý tưởng về kích thước, hình dạng và nội dung của dữ liệu mà bạn đang xử lý.\n" + "> **Điểm rút ra:** Chỉ cần nhìn vào siêu dữ liệu về thông tin trong một DataFrame hoặc vài giá trị đầu tiên và cuối cùng của nó, bạn có thể ngay lập tức hình dung về kích thước, hình dạng và nội dung của dữ liệu mà bạn đang xử lý.\n" ] }, { @@ -595,18 +595,18 @@ "id": "TvurZyLSDxq_" }, "source": [ - "### Dữ Liệu Thiếu\n", - "Hãy cùng tìm hiểu về dữ liệu thiếu. Dữ liệu thiếu xảy ra khi không có giá trị nào được lưu trữ trong một số cột.\n", + "### Dữ liệu bị thiếu\n", + "Hãy cùng tìm hiểu về dữ liệu bị thiếu. Dữ liệu bị thiếu xảy ra khi không có giá trị nào được lưu trữ trong một số cột.\n", "\n", - "Hãy lấy một ví dụ: giả sử ai đó rất quan tâm đến cân nặng của mình và không điền vào trường cân nặng trong một khảo sát. Khi đó, giá trị cân nặng của người đó sẽ bị thiếu.\n", + "Hãy lấy một ví dụ: giả sử ai đó rất quan tâm đến cân nặng của mình và không điền vào trường cân nặng trong một cuộc khảo sát. Khi đó, giá trị cân nặng của người đó sẽ bị thiếu.\n", "\n", - "Phần lớn thời gian, trong các tập dữ liệu thực tế, giá trị thiếu thường xuyên xảy ra.\n", + "Phần lớn thời gian, trong các tập dữ liệu thực tế, giá trị bị thiếu thường xảy ra.\n", "\n", - "**Cách Pandas xử lý dữ liệu thiếu**\n", + "**Cách Pandas xử lý dữ liệu bị thiếu**\n", "\n", - "Pandas xử lý giá trị thiếu theo hai cách. Cách đầu tiên bạn đã thấy trong các phần trước: `NaN`, hoặc Not a Number (Không phải là một số). Đây thực chất là một giá trị đặc biệt thuộc về đặc tả số học dấu phẩy động IEEE và nó chỉ được sử dụng để biểu thị các giá trị dấu phẩy động bị thiếu.\n", + "Pandas xử lý giá trị bị thiếu theo hai cách. Cách đầu tiên bạn đã thấy trong các phần trước: `NaN`, hoặc Not a Number. Đây thực chất là một giá trị đặc biệt thuộc về đặc tả số học dấu phẩy động IEEE và chỉ được sử dụng để biểu thị các giá trị dấu phẩy động bị thiếu.\n", "\n", - "Đối với các giá trị thiếu không phải là số dấu phẩy động, pandas sử dụng đối tượng `None` của Python. Mặc dù có thể gây nhầm lẫn khi bạn gặp hai loại giá trị khác nhau nhưng đều biểu thị cùng một ý nghĩa, có những lý do lập trình hợp lý cho lựa chọn thiết kế này. Trên thực tế, cách tiếp cận này cho phép pandas cung cấp một sự cân bằng tốt cho phần lớn các trường hợp. Tuy nhiên, cả `None` và `NaN` đều có những hạn chế mà bạn cần lưu ý liên quan đến cách chúng có thể được sử dụng.\n" + "Đối với các giá trị bị thiếu không phải là số dấu phẩy động, pandas sử dụng đối tượng `None` của Python. Mặc dù có thể gây nhầm lẫn khi bạn gặp hai loại giá trị khác nhau nhưng đều biểu thị cùng một ý nghĩa, có những lý do lập trình hợp lý cho sự lựa chọn thiết kế này. Trên thực tế, cách tiếp cận này cho phép pandas cung cấp một sự thỏa hiệp tốt cho phần lớn các trường hợp. Tuy nhiên, cả `None` và `NaN` đều có những hạn chế mà bạn cần lưu ý liên quan đến cách chúng có thể được sử dụng.\n" ] }, { @@ -616,7 +616,7 @@ }, "source": [ "### `None`: dữ liệu thiếu không phải kiểu float\n", - "Vì `None` xuất phát từ Python, nó không thể được sử dụng trong các mảng NumPy và pandas không có kiểu dữ liệu `'object'`. Hãy nhớ rằng, các mảng NumPy (và các cấu trúc dữ liệu trong pandas) chỉ có thể chứa một loại dữ liệu duy nhất. Đây chính là điều mang lại sức mạnh vượt trội cho chúng trong công việc xử lý dữ liệu và tính toán quy mô lớn, nhưng đồng thời cũng hạn chế sự linh hoạt của chúng. Các mảng như vậy phải được chuyển đổi sang kiểu dữ liệu “mẫu số chung thấp nhất,” tức là kiểu dữ liệu có thể bao gồm tất cả mọi thứ trong mảng. Khi `None` xuất hiện trong mảng, điều đó có nghĩa là bạn đang làm việc với các đối tượng Python.\n", + "Vì `None` xuất phát từ Python, nên nó không thể được sử dụng trong các mảng NumPy và pandas không có kiểu dữ liệu `'object'`. Hãy nhớ rằng, các mảng NumPy (và các cấu trúc dữ liệu trong pandas) chỉ có thể chứa một loại dữ liệu duy nhất. Đây chính là điều mang lại sức mạnh vượt trội cho chúng trong việc xử lý dữ liệu quy mô lớn và tính toán, nhưng đồng thời cũng hạn chế sự linh hoạt của chúng. Những mảng như vậy phải được chuyển đổi lên kiểu dữ liệu “mẫu số chung thấp nhất,” tức là kiểu dữ liệu có thể bao gồm tất cả các phần tử trong mảng. Khi `None` xuất hiện trong mảng, điều đó có nghĩa là bạn đang làm việc với các đối tượng Python.\n", "\n", "Để thấy điều này trong thực tế, hãy xem xét mảng ví dụ sau (lưu ý `dtype` của nó):\n" ] @@ -657,9 +657,9 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "Thực tế của việc nâng cấp kiểu dữ liệu đi kèm với hai tác động phụ. Đầu tiên, các thao tác sẽ được thực hiện ở cấp độ mã Python được diễn giải thay vì mã NumPy được biên dịch. Về cơ bản, điều này có nghĩa là bất kỳ thao tác nào liên quan đến `Series` hoặc `DataFrames` có chứa `None` sẽ chậm hơn. Mặc dù bạn có thể không nhận thấy sự giảm hiệu suất này, nhưng đối với các tập dữ liệu lớn, nó có thể trở thành vấn đề.\n", + "Thực tế của việc nâng cấp kiểu dữ liệu mang theo hai tác động phụ. Thứ nhất, các thao tác sẽ được thực hiện ở mức mã Python được diễn giải thay vì mã NumPy đã biên dịch. Về cơ bản, điều này có nghĩa là bất kỳ thao tác nào liên quan đến `Series` hoặc `DataFrame` có chứa `None` sẽ chậm hơn. Mặc dù bạn có thể không nhận ra sự giảm hiệu suất này, nhưng với các tập dữ liệu lớn, điều này có thể trở thành một vấn đề.\n", "\n", - "Tác động phụ thứ hai xuất phát từ tác động đầu tiên. Vì `None` về cơ bản kéo `Series` hoặc `DataFrame`s trở lại thế giới của Python thuần túy, việc sử dụng các hàm tổng hợp của NumPy/pandas như `sum()` hoặc `min()` trên các mảng chứa giá trị ``None`` thường sẽ gây ra lỗi:\n" + "Tác động phụ thứ hai bắt nguồn từ tác động phụ đầu tiên. Vì `None` về cơ bản kéo `Series` hoặc `DataFrame` trở lại thế giới của Python thuần túy, việc sử dụng các phép tổng hợp của NumPy/pandas như `sum()` hoặc `min()` trên các mảng chứa giá trị ``None`` thường sẽ gây ra lỗi:\n" ] }, { @@ -697,7 +697,9 @@ "metadata": { "id": "LcEwO8UogRr9" }, - "source": [] + "source": [ + "**Điểm chính**: Phép cộng (và các phép toán khác) giữa các số nguyên và giá trị `None` là không xác định, điều này có thể hạn chế những gì bạn có thể làm với các tập dữ liệu chứa chúng.\n" + ] }, { "cell_type": "markdown", @@ -707,7 +709,7 @@ "source": [ "### `NaN`: giá trị float bị thiếu\n", "\n", - "Khác với `None`, NumPy (và do đó cả pandas) hỗ trợ `NaN` để thực hiện các phép toán và ufuncs nhanh, theo vector. Tin xấu là bất kỳ phép toán số học nào thực hiện trên `NaN` đều luôn cho ra kết quả là `NaN`. Ví dụ:\n" + "Khác với `None`, NumPy (và do đó là pandas) hỗ trợ `NaN` cho các thao tác vector hóa nhanh và ufuncs. Tin xấu là bất kỳ phép toán nào thực hiện trên `NaN` luôn cho kết quả là `NaN`. Ví dụ:\n" ] }, { @@ -770,7 +772,7 @@ "id": "fU5IPRcCgRr-" }, "source": [ - "Tin tốt: các phép tổng hợp chạy trên các mảng có `NaN` trong đó không gây ra lỗi. Tin xấu: kết quả không phải lúc nào cũng hữu ích:\n" + "Tin tốt: các phép tổng hợp chạy trên mảng có chứa `NaN` không gây lỗi. Tin xấu: kết quả không phải lúc nào cũng hữu ích:\n" ] }, { @@ -806,7 +808,9 @@ "metadata": { "id": "nhlnNJT7gRr_" }, - "source": [] + "source": [ + "### Bài tập:\n" + ] }, { "cell_type": "code", @@ -826,7 +830,9 @@ "metadata": { "id": "_iDvIRC8gRsA" }, - "source": [] + "source": [ + "Hãy nhớ: `NaN` chỉ dành cho các giá trị dấu phẩy động bị thiếu; không có tương đương `NaN` cho số nguyên, chuỗi hoặc Boolean.\n" + ] }, { "cell_type": "markdown", @@ -836,7 +842,7 @@ "source": [ "### `NaN` và `None`: giá trị null trong pandas\n", "\n", - "Mặc dù `NaN` và `None` có thể hoạt động hơi khác nhau, pandas vẫn được thiết kế để xử lý chúng một cách thay thế cho nhau. Để hiểu rõ hơn, hãy xem xét một `Series` các số nguyên:\n" + "Mặc dù `NaN` và `None` có thể hoạt động hơi khác nhau, pandas vẫn được thiết kế để xử lý chúng thay thế cho nhau. Để hiểu rõ hơn, hãy xem xét một `Series` gồm các số nguyên:\n" ] }, { @@ -875,7 +881,9 @@ "metadata": { "id": "WklCzqb8gRsB" }, - "source": [] + "source": [ + "### Bài tập:\n" + ] }, { "cell_type": "code", @@ -898,12 +906,12 @@ "id": "WjMQwltNgRsB" }, "source": [ - "Trong quá trình nâng cấp kiểu dữ liệu để đảm bảo tính đồng nhất trong `Series` và `DataFrame`, pandas sẽ dễ dàng chuyển đổi giá trị thiếu giữa `None` và `NaN`. Vì đặc điểm thiết kế này, bạn có thể nghĩ về `None` và `NaN` như hai dạng khác nhau của \"null\" trong pandas. Thực tế, một số phương thức cốt lõi mà bạn sẽ sử dụng để xử lý giá trị thiếu trong pandas phản ánh ý tưởng này qua tên gọi của chúng:\n", + "Trong quá trình nâng cấp kiểu dữ liệu để thiết lập tính đồng nhất dữ liệu trong `Series` và `DataFrame`, pandas sẽ sẵn sàng chuyển đổi giá trị thiếu giữa `None` và `NaN`. Do đặc điểm thiết kế này, sẽ hữu ích nếu bạn nghĩ về `None` và `NaN` như hai dạng khác nhau của \"null\" trong pandas. Thực tế, một số phương thức cốt lõi mà bạn sẽ sử dụng để xử lý giá trị thiếu trong pandas phản ánh ý tưởng này qua tên gọi của chúng:\n", "\n", "- `isnull()`: Tạo một mặt nạ Boolean chỉ ra các giá trị thiếu\n", "- `notnull()`: Ngược lại với `isnull()`\n", - "- `dropna()`: Trả về phiên bản dữ liệu đã được lọc\n", - "- `fillna()`: Trả về một bản sao của dữ liệu với các giá trị thiếu được điền hoặc ước tính\n", + "- `dropna()`: Trả về một phiên bản dữ liệu đã được lọc\n", + "- `fillna()`: Trả về một bản sao của dữ liệu với các giá trị thiếu được điền hoặc ước lượng\n", "\n", "Đây là những phương thức quan trọng cần nắm vững và làm quen, vì vậy hãy cùng tìm hiểu chi tiết từng phương thức.\n" ] @@ -916,8 +924,7 @@ "source": [ "### Phát hiện giá trị null\n", "\n", - "Bây giờ chúng ta đã hiểu tầm quan trọng của các giá trị thiếu, chúng ta cần phát hiện chúng trong tập dữ liệu trước khi xử lý.\n", - "\n", + "Sau khi đã hiểu được tầm quan trọng của các giá trị thiếu, chúng ta cần phát hiện chúng trong tập dữ liệu trước khi xử lý. \n", "Cả `isnull()` và `notnull()` đều là các phương pháp chính để phát hiện dữ liệu null. Cả hai đều trả về mặt nạ Boolean trên dữ liệu của bạn.\n" ] }, @@ -971,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "Hãy nhìn kỹ vào kết quả. Có điều gì khiến bạn ngạc nhiên không? Mặc dù `0` là một giá trị số học rỗng, nó vẫn là một số nguyên hợp lệ và pandas xử lý nó như vậy. `''` thì tinh tế hơn một chút. Mặc dù chúng ta đã sử dụng nó trong Phần 1 để biểu thị một chuỗi rỗng, nhưng nó vẫn là một đối tượng chuỗi và không được pandas coi là một biểu diễn của giá trị null.\n", + "Hãy nhìn kỹ vào kết quả. Có điều gì khiến bạn ngạc nhiên không? Mặc dù `0` là một giá trị null trong toán học, nhưng nó vẫn là một số nguyên hoàn toàn hợp lệ và pandas xử lý nó như vậy. `''` thì tinh tế hơn một chút. Mặc dù chúng ta đã sử dụng nó trong Phần 1 để biểu thị một giá trị chuỗi rỗng, nhưng nó vẫn là một đối tượng chuỗi và không được pandas coi là một biểu diễn của null.\n", "\n", - "Bây giờ, hãy đảo ngược tình huống và sử dụng các phương pháp này theo cách giống như bạn sẽ sử dụng chúng trong thực tế. Bạn có thể sử dụng các mặt nạ Boolean trực tiếp làm chỉ mục của ``Series`` hoặc ``DataFrame``, điều này có thể hữu ích khi bạn muốn làm việc với các giá trị bị thiếu (hoặc có mặt) riêng lẻ.\n", + "Bây giờ, hãy đảo ngược lại và sử dụng các phương pháp này theo cách giống như cách bạn sẽ sử dụng chúng trong thực tế. Bạn có thể sử dụng các mặt nạ Boolean trực tiếp như một chỉ mục của ``Series`` hoặc ``DataFrame``, điều này có thể hữu ích khi cố gắng làm việc với các giá trị bị thiếu (hoặc hiện diện) riêng lẻ.\n", "\n", - "Nếu chúng ta muốn tổng số giá trị bị thiếu, chúng ta chỉ cần thực hiện phép cộng trên mặt nạ được tạo bởi phương thức `isnull()`.\n" + "Nếu chúng ta muốn tổng số giá trị bị thiếu, chúng ta chỉ cần thực hiện phép cộng trên mặt nạ được tạo bởi phương pháp `isnull()`.\n" ] }, { @@ -1009,7 +1016,9 @@ "metadata": { "id": "PlBqEo3mgRsC" }, - "source": [] + "source": [ + "### Bài tập:\n" + ] }, { "cell_type": "code", @@ -1031,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**Điểm chính**: Cả hai phương thức `isnull()` và `notnull()` đều tạo ra kết quả tương tự khi bạn sử dụng chúng trong DataFrame: chúng hiển thị kết quả và chỉ mục của những kết quả đó, điều này sẽ giúp bạn rất nhiều khi bạn xử lý dữ liệu của mình.\n" + "**Điểm chính**: Cả hai phương thức `isnull()` và `notnull()` đều tạo ra kết quả tương tự khi bạn sử dụng chúng trong DataFrames: chúng hiển thị kết quả và chỉ mục của những kết quả đó, điều này sẽ giúp bạn rất nhiều khi xử lý dữ liệu của mình.\n" ] }, { @@ -1046,14 +1055,14 @@ "\n", "Các mô hình Machine Learning không thể tự xử lý dữ liệu thiếu. Vì vậy, trước khi đưa dữ liệu vào mô hình, chúng ta cần xử lý các giá trị thiếu này.\n", "\n", - "Cách xử lý dữ liệu thiếu mang theo những sự đánh đổi tinh tế, có thể ảnh hưởng đến phân tích cuối cùng và kết quả thực tế.\n", + "Cách xử lý dữ liệu thiếu mang lại những sự đánh đổi tinh tế, có thể ảnh hưởng đến phân tích cuối cùng và kết quả thực tế.\n", "\n", "Có hai cách chính để xử lý dữ liệu thiếu:\n", "\n", "1. Loại bỏ hàng chứa giá trị thiếu\n", "2. Thay thế giá trị thiếu bằng một giá trị khác\n", "\n", - "Chúng ta sẽ thảo luận cả hai phương pháp này cùng với ưu và nhược điểm của chúng một cách chi tiết.\n" + "Chúng ta sẽ thảo luận chi tiết về cả hai phương pháp này cùng với ưu và nhược điểm của chúng.\n" ] }, { @@ -1064,9 +1073,9 @@ "source": [ "### Loại bỏ giá trị null\n", "\n", - "Số lượng dữ liệu chúng ta đưa vào mô hình có ảnh hưởng trực tiếp đến hiệu suất của nó. Loại bỏ giá trị null có nghĩa là chúng ta đang giảm số lượng điểm dữ liệu, và do đó giảm kích thước của tập dữ liệu. Vì vậy, nên loại bỏ các hàng có giá trị null khi tập dữ liệu khá lớn.\n", + "Lượng dữ liệu chúng ta đưa vào mô hình có ảnh hưởng trực tiếp đến hiệu suất của nó. Việc loại bỏ giá trị null đồng nghĩa với việc giảm số lượng điểm dữ liệu, từ đó giảm kích thước của tập dữ liệu. Vì vậy, nên loại bỏ các hàng có giá trị null khi tập dữ liệu khá lớn.\n", "\n", - "Một trường hợp khác có thể là một hàng hoặc cột nào đó có rất nhiều giá trị bị thiếu. Khi đó, chúng có thể bị loại bỏ vì chúng không mang lại nhiều giá trị cho phân tích của chúng ta do phần lớn dữ liệu bị thiếu ở hàng/cột đó.\n", + "Một trường hợp khác có thể xảy ra là một hàng hoặc cột nào đó có rất nhiều giá trị bị thiếu. Khi đó, chúng có thể bị loại bỏ vì chúng không mang lại nhiều giá trị cho phân tích của chúng ta do phần lớn dữ liệu bị thiếu ở hàng/cột đó.\n", "\n", "Ngoài việc xác định các giá trị bị thiếu, pandas cung cấp một cách tiện lợi để loại bỏ giá trị null từ `Series` và `DataFrame`. Để thấy điều này trong thực tế, hãy quay lại `example3`. Hàm `DataFrame.dropna()` giúp loại bỏ các hàng có giá trị null.\n" ] @@ -1107,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "Lưu ý rằng điều này sẽ giống như kết quả của bạn từ `example3[example3.notnull()]`. Sự khác biệt ở đây là, thay vì chỉ lập chỉ mục trên các giá trị đã được che, `dropna` đã loại bỏ những giá trị bị thiếu khỏi `Series` `example3`.\n", + "Lưu ý rằng điều này nên giống như kết quả từ `example3[example3.notnull()]`. Sự khác biệt ở đây là, thay vì chỉ lập chỉ mục trên các giá trị bị che, `dropna` đã loại bỏ những giá trị bị thiếu khỏi `Series` `example3`.\n", "\n", - "Vì DataFrame có hai chiều, chúng cung cấp nhiều tùy chọn hơn để loại bỏ dữ liệu.\n" + "Vì DataFrames có hai chiều, chúng cung cấp nhiều tùy chọn hơn để loại bỏ dữ liệu.\n" ] }, { @@ -1201,7 +1210,7 @@ "source": [ "(Bạn có nhận thấy rằng pandas đã chuyển đổi hai cột thành kiểu float để phù hợp với các giá trị `NaN` không?)\n", "\n", - "Bạn không thể xóa một giá trị đơn lẻ từ một `DataFrame`, vì vậy bạn phải xóa toàn bộ hàng hoặc cột. Tùy thuộc vào những gì bạn đang làm, bạn có thể muốn chọn một trong hai cách, và do đó pandas cung cấp cho bạn tùy chọn cho cả hai. Vì trong khoa học dữ liệu, các cột thường đại diện cho biến số và các hàng đại diện cho quan sát, bạn có khả năng cao sẽ xóa các hàng dữ liệu; cài đặt mặc định của `dropna()` là xóa tất cả các hàng chứa bất kỳ giá trị null nào:\n" + "Bạn không thể xóa một giá trị đơn lẻ từ một `DataFrame`, vì vậy bạn phải xóa toàn bộ hàng hoặc cột. Tùy thuộc vào những gì bạn đang làm, bạn có thể muốn thực hiện một trong hai cách, và pandas cung cấp cho bạn tùy chọn cho cả hai. Vì trong khoa học dữ liệu, các cột thường đại diện cho biến số và các hàng đại diện cho quan sát, bạn có khả năng sẽ xóa các hàng dữ liệu hơn; cài đặt mặc định của `dropna()` là xóa tất cả các hàng chứa bất kỳ giá trị null nào:\n" ] }, { @@ -1274,7 +1283,7 @@ "id": "TrQRBuTDgRsE" }, "source": [ - "Nếu cần thiết, bạn có thể loại bỏ các giá trị NA từ các cột. Sử dụng `axis=1` để làm như vậy:\n" + "Nếu cần thiết, bạn có thể loại bỏ các giá trị NA từ các cột. Sử dụng `axis=1` để thực hiện điều này:\n" ] }, { @@ -1355,7 +1364,7 @@ "source": [ "Lưu ý rằng điều này có thể loại bỏ rất nhiều dữ liệu mà bạn có thể muốn giữ lại, đặc biệt là trong các tập dữ liệu nhỏ. Vậy nếu bạn chỉ muốn loại bỏ các hàng hoặc cột chứa một số hoặc thậm chí tất cả các giá trị null thì sao? Bạn có thể chỉ định các thiết lập đó trong `dropna` với các tham số `how` và `thresh`.\n", "\n", - "Mặc định, `how='any'` (nếu bạn muốn tự kiểm tra hoặc xem phương thức này có các tham số nào khác, hãy chạy `example4.dropna?` trong một ô mã). Ngoài ra, bạn có thể chỉ định `how='all'` để chỉ loại bỏ các hàng hoặc cột chứa toàn bộ giá trị null. Hãy mở rộng ví dụ `DataFrame` của chúng ta để xem điều này hoạt động như thế nào trong bài tập tiếp theo.\n" + "Theo mặc định, `how='any'` (nếu bạn muốn tự kiểm tra hoặc xem các tham số khác mà phương thức này có, hãy chạy `example4.dropna?` trong một ô mã). Ngoài ra, bạn có thể chỉ định `how='all'` để chỉ loại bỏ các hàng hoặc cột chứa tất cả các giá trị null. Hãy mở rộng ví dụ `DataFrame` của chúng ta để xem điều này hoạt động như thế nào trong bài tập tiếp theo.\n" ] }, { @@ -1448,10 +1457,10 @@ }, "source": [ "> Những điểm chính: \n", - "1. Loại bỏ các giá trị null chỉ là ý tưởng tốt nếu tập dữ liệu đủ lớn. \n", + "1. Chỉ nên loại bỏ các giá trị null nếu tập dữ liệu đủ lớn. \n", "2. Có thể loại bỏ toàn bộ hàng hoặc cột nếu phần lớn dữ liệu của chúng bị thiếu. \n", "3. Phương thức `DataFrame.dropna(axis=)` hỗ trợ loại bỏ các giá trị null. Tham số `axis` xác định liệu sẽ loại bỏ hàng hay cột. \n", - "4. Tham số `how` cũng có thể được sử dụng. Mặc định, nó được đặt là `any`. Vì vậy, nó chỉ loại bỏ những hàng/cột chứa bất kỳ giá trị null nào. Tham số này có thể được đặt là `all` để chỉ định rằng chúng ta sẽ chỉ loại bỏ những hàng/cột mà tất cả các giá trị đều là null. \n" + "4. Tham số `how` cũng có thể được sử dụng. Mặc định, nó được đặt là `any`. Vì vậy, nó chỉ loại bỏ những hàng/cột chứa bất kỳ giá trị null nào. Có thể đặt thành `all` để chỉ định rằng chúng ta sẽ chỉ loại bỏ những hàng/cột mà tất cả các giá trị đều là null. \n" ] }, { @@ -1459,7 +1468,9 @@ "metadata": { "id": "oXXSfQFHgRsF" }, - "source": [] + "source": [ + "### Bài tập:\n" + ] }, { "cell_type": "code", @@ -1481,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "Tham số `thresh` cung cấp cho bạn khả năng kiểm soát chi tiết hơn: bạn đặt số lượng giá trị *không null* mà một hàng hoặc cột cần phải có để được giữ lại:\n" + "Tham số `thresh` cung cấp cho bạn khả năng kiểm soát chi tiết hơn: bạn đặt số lượng giá trị *không null* mà một hàng hoặc cột cần có để được giữ lại:\n" ] }, { @@ -1567,9 +1578,9 @@ "source": [ "### Điền giá trị null\n", "\n", - "Đôi khi việc điền các giá trị thiếu bằng những giá trị có thể hợp lệ là điều hợp lý. Có một vài kỹ thuật để điền giá trị null. Kỹ thuật đầu tiên là sử dụng Kiến Thức Chuyên Môn (kiến thức về chủ đề mà tập dữ liệu dựa trên) để ước lượng các giá trị bị thiếu.\n", + "Đôi khi việc điền các giá trị thiếu bằng những giá trị có thể hợp lệ là điều hợp lý. Có một vài kỹ thuật để điền giá trị null. Kỹ thuật đầu tiên là sử dụng Kiến Thức Chuyên Ngành (kiến thức về chủ đề mà tập dữ liệu dựa trên) để ước lượng giá trị thiếu một cách nào đó.\n", "\n", - "Bạn có thể sử dụng `isnull` để làm điều này trực tiếp, nhưng điều đó có thể tốn công, đặc biệt nếu bạn có nhiều giá trị cần điền. Vì đây là một nhiệm vụ rất phổ biến trong khoa học dữ liệu, pandas cung cấp `fillna`, trả về một bản sao của `Series` hoặc `DataFrame` với các giá trị bị thiếu được thay thế bằng giá trị bạn chọn. Hãy tạo một ví dụ khác về `Series` để xem cách hoạt động này trong thực tế.\n" + "Bạn có thể sử dụng `isnull` để thực hiện việc này trực tiếp, nhưng điều đó có thể rất tốn công, đặc biệt nếu bạn có nhiều giá trị cần điền. Vì đây là một nhiệm vụ phổ biến trong khoa học dữ liệu, pandas cung cấp `fillna`, trả về một bản sao của `Series` hoặc `DataFrame` với các giá trị thiếu được thay thế bằng giá trị bạn chọn. Hãy tạo một ví dụ khác về `Series` để xem cách hoạt động này trong thực tế.\n" ] }, { @@ -1688,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "Bây giờ, hãy tìm giá trị mode trước khi điền giá trị `None` bằng mode.\n" + ] }, { "cell_type": "code", @@ -1723,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "Vì vậy, chúng ta sẽ thay thế None bằng True\n" + ] }, { "cell_type": "code", @@ -1833,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "Như chúng ta có thể thấy, giá trị null đã được thay thế. Không cần phải nói, chúng ta có thể đã viết bất kỳ thứ gì thay cho `'True'` và nó sẽ được thay thế.\n" + "Như chúng ta có thể thấy, giá trị null đã được thay thế. Không cần phải nói, chúng ta có thể viết bất kỳ điều gì thay thế cho `'True'` và nó sẽ được thay thế.\n" ] }, { @@ -1842,17 +1857,17 @@ "id": "heYe1I0dOmQ_" }, "source": [ - "### Dữ liệu Số\n", + "### Dữ liệu số\n", "Bây giờ, chúng ta sẽ nói về dữ liệu số. Ở đây, có hai cách phổ biến để thay thế giá trị bị thiếu:\n", "\n", - "1. Thay thế bằng Trung vị của hàng\n", - "2. Thay thế bằng Giá trị trung bình của hàng\n", + "1. Thay thế bằng giá trị trung vị của hàng\n", + "2. Thay thế bằng giá trị trung bình của hàng\n", "\n", - "Chúng ta thay thế bằng Trung vị trong trường hợp dữ liệu bị lệch với các giá trị ngoại lai. Điều này là do trung vị không bị ảnh hưởng bởi các giá trị ngoại lai.\n", + "Chúng ta sử dụng giá trị trung vị trong trường hợp dữ liệu bị lệch và có các giá trị ngoại lai. Điều này là do trung vị không bị ảnh hưởng bởi các giá trị ngoại lai.\n", "\n", "Khi dữ liệu đã được chuẩn hóa, chúng ta có thể sử dụng giá trị trung bình, vì trong trường hợp này, giá trị trung bình và trung vị sẽ khá gần nhau.\n", "\n", - "Đầu tiên, hãy lấy một cột có phân phối chuẩn và điền giá trị bị thiếu bằng giá trị trung bình của cột đó.\n" + "Đầu tiên, hãy lấy một cột có phân phối chuẩn và điền giá trị bị thiếu bằng giá trị trung bình của cột.\n" ] }, { @@ -1992,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "Điền bằng giá trị trung bình\n" + ] }, { "cell_type": "code", @@ -2241,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "Điền bằng giá trị trung vị\n" + ] }, { "cell_type": "code", @@ -2341,7 +2360,7 @@ "id": "8JtQ53GSkKWC" }, "source": [ - "Như chúng ta có thể thấy, giá trị NaN đã được thay thế bằng giá trị trung vị của cột\n" + "Như chúng ta có thể thấy, giá trị NaN đã được thay thế bằng giá trị trung vị của cột.\n" ] }, { @@ -2383,7 +2402,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "Bạn có thể điền tất cả các mục trống bằng một giá trị duy nhất, chẳng hạn như `0`:\n" + "Bạn có thể điền tất cả các mục null bằng một giá trị duy nhất, chẳng hạn như `0`:\n" ] }, { @@ -2424,11 +2443,11 @@ "id": "RRlI5f_hkfKe" }, "source": [ - "> Những điểm chính cần lưu ý:\n", - "1. Việc điền giá trị thiếu nên được thực hiện khi dữ liệu còn ít hoặc khi có chiến lược để điền vào các giá trị thiếu.\n", - "2. Kiến thức chuyên môn có thể được sử dụng để điền giá trị thiếu bằng cách ước lượng chúng.\n", - "3. Đối với dữ liệu phân loại, thường thì các giá trị thiếu được thay thế bằng giá trị mode của cột.\n", - "4. Đối với dữ liệu số, các giá trị thiếu thường được điền bằng giá trị trung bình (đối với các tập dữ liệu đã được chuẩn hóa) hoặc giá trị trung vị của các cột.\n" + "> Những điểm chính cần ghi nhớ:\n", + "1. Việc điền giá trị thiếu nên được thực hiện khi dữ liệu còn ít hoặc khi có chiến lược để điền giá trị thiếu.\n", + "2. Kiến thức chuyên môn có thể được sử dụng để ước lượng và điền giá trị thiếu.\n", + "3. Đối với dữ liệu phân loại, thường giá trị thiếu được thay thế bằng giá trị mode của cột.\n", + "4. Đối với dữ liệu số, giá trị thiếu thường được điền bằng giá trị trung bình (đối với các tập dữ liệu đã chuẩn hóa) hoặc giá trị trung vị của cột.\n" ] }, { @@ -2436,7 +2455,9 @@ "metadata": { "id": "FI9MmqFJgRsH" }, - "source": [] + "source": [ + "### Bài tập:\n" + ] }, { "cell_type": "code", @@ -2456,7 +2477,9 @@ "metadata": { "id": "kq3hw1kLgRsI" }, - "source": [] + "source": [ + "Bạn có thể **điền trước** các giá trị null, tức là sử dụng giá trị hợp lệ cuối cùng để điền vào null:\n" + ] }, { "cell_type": "code", @@ -2496,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "Bạn cũng có thể **back-fill** để truyền giá trị hợp lệ tiếp theo ngược lại để điền vào một giá trị null:\n" + "Bạn cũng có thể **lấp đầy ngược** để truyền giá trị hợp lệ tiếp theo ngược lại nhằm lấp đầy một giá trị null:\n" ] }, { @@ -2711,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "Lưu ý rằng khi không có giá trị trước đó để điền tiếp, giá trị null sẽ được giữ nguyên.\n" + "Lưu ý rằng khi không có giá trị trước đó để điền tiếp, giá trị null vẫn được giữ nguyên.\n" ] }, { @@ -2719,7 +2742,9 @@ "metadata": { "id": "eeAoOU0RgRsJ" }, - "source": [] + "source": [ + "### Bài tập:\n" + ] }, { "cell_type": "code", @@ -2742,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "Bạn có thể sáng tạo về cách sử dụng `fillna`. Ví dụ, hãy xem lại `example4`, nhưng lần này hãy điền các giá trị bị thiếu bằng giá trị trung bình của tất cả các giá trị trong `DataFrame`:\n" + "Bạn có thể sáng tạo về cách sử dụng `fillna`. Ví dụ, hãy xem lại `example4`, nhưng lần này hãy điền các giá trị thiếu bằng giá trị trung bình của tất cả các giá trị trong `DataFrame`:\n" ] }, { @@ -2835,7 +2860,7 @@ "source": [ "Lưu ý rằng cột 3 vẫn chưa có giá trị: hướng mặc định là điền giá trị theo hàng.\n", "\n", - "> **Điểm cần nhớ:** Có nhiều cách để xử lý giá trị thiếu trong tập dữ liệu của bạn. Chiến lược cụ thể mà bạn sử dụng (loại bỏ, thay thế, hoặc thậm chí cách bạn thay thế) nên được quyết định bởi đặc điểm cụ thể của dữ liệu đó. Bạn sẽ phát triển cảm giác tốt hơn về cách xử lý giá trị thiếu khi bạn làm việc và tương tác nhiều hơn với các tập dữ liệu.\n" + "> **Điểm cần nhớ:** Có nhiều cách để xử lý giá trị thiếu trong tập dữ liệu của bạn. Chiến lược cụ thể mà bạn sử dụng (loại bỏ, thay thế, hoặc thậm chí cách bạn thay thế) nên được quyết định dựa trên đặc điểm cụ thể của dữ liệu đó. Bạn sẽ phát triển cảm giác tốt hơn về cách xử lý giá trị thiếu khi bạn làm việc và tương tác nhiều hơn với các tập dữ liệu.\n" ] }, { @@ -2846,9 +2871,9 @@ "source": [ "### Mã hóa Dữ liệu Phân loại\n", "\n", - "Các mô hình học máy chỉ xử lý được các con số và bất kỳ dạng dữ liệu số nào. Chúng không thể phân biệt giữa \"Yes\" và \"No\", nhưng có thể phân biệt giữa 0 và 1. Vì vậy, sau khi điền các giá trị bị thiếu, chúng ta cần mã hóa dữ liệu phân loại thành một dạng số để mô hình có thể hiểu được.\n", + "Các mô hình học máy chỉ xử lý dữ liệu dạng số và bất kỳ dạng dữ liệu số nào. Nó sẽ không thể phân biệt giữa \"Có\" và \"Không\", nhưng sẽ có thể phân biệt giữa 0 và 1. Vì vậy, sau khi điền các giá trị bị thiếu, chúng ta cần mã hóa dữ liệu phân loại thành một dạng số để mô hình có thể hiểu được.\n", "\n", - "Việc mã hóa có thể được thực hiện theo hai cách. Chúng ta sẽ thảo luận về chúng ngay sau đây.\n" + "Việc mã hóa có thể thực hiện theo hai cách. Chúng ta sẽ thảo luận về chúng ngay sau đây.\n" ] }, { @@ -2859,7 +2884,7 @@ "source": [ "**MÃ HÓA NHÃN**\n", "\n", - "Mã hóa nhãn về cơ bản là chuyển đổi mỗi danh mục thành một số. Ví dụ, giả sử chúng ta có một tập dữ liệu về hành khách hàng không và có một cột chứa hạng ghế của họ trong số các hạng sau ['business class', 'economy class', 'first class']. Nếu thực hiện mã hóa nhãn trên cột này, nó sẽ được chuyển đổi thành [0,1,2]. Hãy cùng xem một ví dụ qua đoạn mã. Vì chúng ta sẽ học `scikit-learn` trong các notebook sắp tới, nên ở đây chúng ta sẽ không sử dụng nó.\n" + "Mã hóa nhãn về cơ bản là chuyển đổi mỗi danh mục thành một số. Ví dụ, giả sử chúng ta có một tập dữ liệu về hành khách hàng không và có một cột chứa hạng ghế của họ trong số các hạng ['business class', 'economy class', 'first class']. Nếu thực hiện mã hóa nhãn, cột này sẽ được chuyển đổi thành [0,1,2]. Hãy cùng xem một ví dụ qua đoạn mã. Vì chúng ta sẽ học `scikit-learn` trong các notebook sắp tới, nên ở đây chúng ta sẽ không sử dụng nó.\n" ] }, { @@ -2967,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "Để thực hiện mã hóa nhãn trên cột đầu tiên, chúng ta phải đầu tiên mô tả một ánh xạ từ mỗi lớp sang một số, trước khi thay thế\n" + "Để thực hiện mã hóa nhãn trên cột thứ nhất, chúng ta phải đầu tiên mô tả một ánh xạ từ mỗi lớp sang một số, trước khi thay thế.\n" ] }, { @@ -3069,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "Như chúng ta có thể thấy, kết quả đầu ra khớp với những gì chúng ta dự đoán. Vậy, khi nào chúng ta sử dụng mã hóa nhãn? Mã hóa nhãn được sử dụng trong một hoặc cả hai trường hợp sau: \n", - "1. Khi số lượng danh mục lớn \n", - "2. Khi các danh mục có thứ tự. \n" + "Như chúng ta có thể thấy, kết quả đầu ra khớp với những gì chúng ta dự đoán sẽ xảy ra. Vậy, khi nào chúng ta sử dụng mã hóa nhãn? Mã hóa nhãn được sử dụng trong một hoặc cả hai trường hợp sau:\n", + "1. Khi số lượng danh mục lớn\n", + "2. Khi các danh mục có thứ tự.\n" ] }, { @@ -3082,9 +3107,9 @@ "source": [ "**MÃ HÓA ONE HOT**\n", "\n", - "Một loại mã hóa khác là Mã Hóa One Hot. Trong loại mã hóa này, mỗi danh mục của cột sẽ được thêm vào như một cột riêng biệt và mỗi điểm dữ liệu sẽ nhận giá trị 0 hoặc 1 dựa trên việc nó có chứa danh mục đó hay không. Vì vậy, nếu có n danh mục khác nhau, n cột sẽ được thêm vào dataframe.\n", + "Một loại mã hóa khác là One Hot Encoding. Trong loại mã hóa này, mỗi danh mục của cột sẽ được thêm vào dưới dạng một cột riêng biệt và mỗi điểm dữ liệu sẽ nhận giá trị 0 hoặc 1 dựa trên việc nó có chứa danh mục đó hay không. Vì vậy, nếu có n danh mục khác nhau, n cột sẽ được thêm vào dataframe.\n", "\n", - "Ví dụ, hãy lấy ví dụ về các hạng ghế máy bay. Các danh mục là: ['business class', 'economy class', 'first class']. Vì vậy, nếu chúng ta thực hiện mã hóa one hot, ba cột sau sẽ được thêm vào tập dữ liệu: ['class_business class', 'class_economy class', 'class_first class'].\n" + "Ví dụ, hãy lấy ví dụ về các hạng ghế máy bay. Các danh mục là: ['business class', 'economy class', 'first class']. Nếu chúng ta thực hiện mã hóa one hot, ba cột sau sẽ được thêm vào tập dữ liệu: ['class_business class', 'class_economy class', 'class_first class'].\n" ] }, { @@ -3326,7 +3351,7 @@ "id": "bDnC4NQOu0qr" }, "source": [ - "Khi nào chúng ta sử dụng one hot encoding? One hot encoding được sử dụng trong một hoặc cả hai trường hợp sau:\n", + "Khi nào chúng ta sử dụng mã hóa one hot? Mã hóa one hot được sử dụng trong một hoặc cả hai trường hợp sau:\n", "\n", "1. Khi số lượng danh mục và kích thước của tập dữ liệu nhỏ.\n", "2. Khi các danh mục không tuân theo thứ tự cụ thể nào.\n" @@ -3338,9 +3363,9 @@ "id": "XnUmci_4uvyu" }, "source": [ - "> Những điểm chính cần ghi nhớ: \n", + "> Những điểm chính:\n", "1. Mã hóa được thực hiện để chuyển đổi dữ liệu không phải số thành dữ liệu số. \n", - "2. Có hai loại mã hóa: Mã hóa nhãn (Label encoding) và Mã hóa One Hot (One Hot encoding), cả hai đều có thể được thực hiện dựa trên yêu cầu của tập dữ liệu. \n" + "2. Có hai loại mã hóa: Mã hóa nhãn và Mã hóa One Hot, cả hai đều có thể được thực hiện dựa trên yêu cầu của tập dữ liệu. \n" ] }, { @@ -3353,7 +3378,7 @@ "\n", "> **Mục tiêu học tập:** Sau khi hoàn thành phần này, bạn sẽ tự tin trong việc xác định và loại bỏ các giá trị trùng lặp từ DataFrames.\n", "\n", - "Ngoài dữ liệu bị thiếu, bạn thường sẽ gặp dữ liệu trùng lặp trong các tập dữ liệu thực tế. May mắn thay, pandas cung cấp một cách dễ dàng để phát hiện và loại bỏ các mục trùng lặp.\n" + "Ngoài dữ liệu bị thiếu, bạn thường gặp phải dữ liệu trùng lặp trong các tập dữ liệu thực tế. May mắn thay, pandas cung cấp một cách dễ dàng để phát hiện và loại bỏ các mục trùng lặp.\n" ] }, { @@ -3362,7 +3387,7 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### Xác định các giá trị trùng lặp: `duplicated`\n", + "### Xác định giá trị trùng lặp: `duplicated`\n", "\n", "Bạn có thể dễ dàng phát hiện các giá trị trùng lặp bằng phương pháp `duplicated` trong pandas, phương pháp này trả về một mặt nạ Boolean cho biết liệu một mục trong `DataFrame` có phải là bản sao của một mục trước đó hay không. Hãy tạo một ví dụ `DataFrame` khác để xem cách hoạt động của nó.\n" ] @@ -3494,7 +3519,7 @@ }, "source": [ "### Loại bỏ các giá trị trùng lặp: `drop_duplicates`\n", - "`drop_duplicates` đơn giản trả về một bản sao của dữ liệu mà tất cả các giá trị `duplicated` là `False`:\n" + "`drop_duplicates` đơn giản trả về một bản sao của dữ liệu mà tất cả các giá trị `duplicated` đều là `False`:\n" ] }, { @@ -3653,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **Điểm chính:** Loại bỏ dữ liệu trùng lặp là một phần thiết yếu của hầu hết mọi dự án khoa học dữ liệu. Dữ liệu trùng lặp có thể làm thay đổi kết quả phân tích của bạn và đưa ra kết quả không chính xác!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Kiểm tra chất lượng dữ liệu thực tế\n", + "\n", + "> **Mục tiêu học tập:** Sau phần này, bạn sẽ tự tin phát hiện và sửa chữa các vấn đề chất lượng dữ liệu phổ biến trong thực tế, bao gồm giá trị phân loại không nhất quán, giá trị số bất thường (ngoại lệ), và các thực thể trùng lặp với biến thể.\n", + "\n", + "Mặc dù giá trị thiếu và các bản sao chính xác là những vấn đề phổ biến, các tập dữ liệu thực tế thường chứa những vấn đề tinh vi hơn:\n", + "\n", + "1. **Giá trị phân loại không nhất quán**: Cùng một danh mục được viết khác nhau (ví dụ: \"USA\", \"U.S.A\", \"United States\")\n", + "2. **Giá trị số bất thường**: Các ngoại lệ cực đoan cho thấy lỗi nhập liệu (ví dụ: tuổi = 999)\n", + "3. **Các hàng gần giống nhau**: Các bản ghi đại diện cho cùng một thực thể nhưng có sự khác biệt nhỏ\n", + "\n", + "Hãy cùng khám phá các kỹ thuật để phát hiện và xử lý những vấn đề này.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tạo một Bộ Dữ Liệu \"Bẩn\" Mẫu\n", + "\n", + "Đầu tiên, hãy tạo một bộ dữ liệu mẫu chứa các loại vấn đề mà chúng ta thường gặp trong dữ liệu thực tế:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Phát hiện các giá trị danh mục không nhất quán\n", + "\n", + "Lưu ý rằng cột `country` có nhiều cách biểu diễn cho cùng một quốc gia. Hãy xác định những điểm không nhất quán này:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Chuẩn hóa các giá trị phân loại\n", + "\n", + "Chúng ta có thể tạo một ánh xạ để chuẩn hóa các giá trị này. Một cách đơn giản là chuyển đổi sang chữ thường và tạo một từ điển ánh xạ:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Lựa chọn khác: Sử dụng khớp chuỗi mờ**\n", + "\n", + "Đối với các trường hợp phức tạp hơn, chúng ta có thể sử dụng khớp chuỗi mờ với thư viện `rapidfuzz` để tự động phát hiện các chuỗi tương tự:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Phát hiện Giá trị Số Bất Thường (Outliers)\n", + "\n", + "Xem xét cột `age`, chúng ta có một số giá trị đáng ngờ như 199 và -5. Hãy sử dụng các phương pháp thống kê để phát hiện những giá trị bất thường này.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Sử dụng phương pháp IQR (Khoảng tứ phân vị)\n", + "\n", + "Phương pháp IQR là một kỹ thuật thống kê mạnh mẽ để phát hiện giá trị ngoại lai, ít nhạy cảm hơn với các giá trị cực đoan:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Sử dụng phương pháp Z-Score\n", + "\n", + "Phương pháp Z-Score xác định các giá trị ngoại lai dựa trên độ lệch chuẩn so với giá trị trung bình:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Xử lý giá trị ngoại lai\n", + "\n", + "Khi đã phát hiện, giá trị ngoại lai có thể được xử lý theo nhiều cách:\n", + "1. **Loại bỏ**: Xóa các hàng chứa giá trị ngoại lai (nếu đó là lỗi)\n", + "2. **Giới hạn**: Thay thế bằng các giá trị biên\n", + "3. **Thay thế bằng NaN**: Xem như dữ liệu thiếu và sử dụng các kỹ thuật bù đắp\n", + "4. **Giữ lại**: Nếu đó là các giá trị cực đoan hợp lệ\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Phát hiện các hàng gần giống nhau\n", + "\n", + "Lưu ý rằng tập dữ liệu của chúng ta có nhiều mục nhập cho \"John Smith\" với các giá trị hơi khác nhau. Hãy xác định các mục có khả năng trùng lặp dựa trên sự tương đồng về tên.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Tìm kiếm các bản sao gần giống bằng cách so khớp mờ\n", + "\n", + "Để phát hiện các bản sao phức tạp hơn, chúng ta có thể sử dụng so khớp mờ để tìm các tên tương tự:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Xử lý các bản sao\n", + "\n", + "Sau khi xác định, bạn cần quyết định cách xử lý các bản sao:\n", + "1. **Giữ lần xuất hiện đầu tiên**: Sử dụng `drop_duplicates(keep='first')`\n", + "2. **Giữ lần xuất hiện cuối cùng**: Sử dụng `drop_duplicates(keep='last')`\n", + "3. **Tổng hợp thông tin**: Kết hợp thông tin từ các hàng bị trùng lặp\n", + "4. **Xem xét thủ công**: Đánh dấu để con người kiểm tra\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tóm tắt: Hoàn thiện Quy trình Làm sạch Dữ liệu\n", + "\n", + "Hãy cùng tổng hợp tất cả thành một quy trình làm sạch dữ liệu toàn diện:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 Bài Tập Thử Thách\n", + "\n", + "Bây giờ đến lượt bạn! Dưới đây là một dòng dữ liệu mới với nhiều vấn đề về chất lượng. Bạn có thể:\n", + "\n", + "1. Xác định tất cả các vấn đề trong dòng dữ liệu này\n", + "2. Viết mã để xử lý từng vấn đề\n", + "3. Thêm dòng dữ liệu đã được làm sạch vào tập dữ liệu\n", + "\n", + "Dưới đây là dữ liệu có vấn đề:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Những điểm chính\n", + "\n", + "1. **Danh mục không đồng nhất** thường xuất hiện trong dữ liệu thực tế. Hãy luôn kiểm tra các giá trị duy nhất và chuẩn hóa chúng bằng cách sử dụng ánh xạ hoặc so khớp mờ.\n", + "\n", + "2. **Giá trị ngoại lai** có thể ảnh hưởng lớn đến phân tích của bạn. Sử dụng kiến thức chuyên môn kết hợp với các phương pháp thống kê (IQR, Z-score) để phát hiện chúng.\n", + "\n", + "3. **Các giá trị gần giống nhau** khó phát hiện hơn các giá trị trùng lặp hoàn toàn. Hãy cân nhắc sử dụng so khớp mờ và chuẩn hóa dữ liệu (chuyển chữ thường, loại bỏ khoảng trắng) để nhận diện chúng.\n", + "\n", + "4. **Làm sạch dữ liệu là một quá trình lặp lại**. Bạn có thể cần áp dụng nhiều kỹ thuật và xem xét kết quả trước khi hoàn thiện tập dữ liệu đã làm sạch.\n", + "\n", + "5. **Ghi lại các quyết định của bạn**. Theo dõi các bước làm sạch bạn đã áp dụng và lý do, vì điều này rất quan trọng để đảm bảo tính tái lập và minh bạch.\n", + "\n", + "> **Thực hành tốt nhất:** Luôn giữ một bản sao của dữ liệu \"bẩn\" ban đầu. Không bao giờ ghi đè lên các tệp dữ liệu nguồn - hãy tạo các phiên bản đã làm sạch với cách đặt tên rõ ràng như `data_cleaned.csv`.\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**Tuyên bố miễn trừ trách nhiệm**: \nTài liệu này đã được dịch bằng dịch vụ dịch thuật AI [Co-op Translator](https://github.com/Azure/co-op-translator). Mặc dù chúng tôi cố gắng đảm bảo độ chính xác, xin lưu ý rằng các bản dịch tự động có thể chứa lỗi hoặc không chính xác. Tài liệu gốc bằng ngôn ngữ bản địa nên được coi là nguồn tham khảo chính thức. Đối với các thông tin quan trọng, chúng tôi khuyến nghị sử dụng dịch vụ dịch thuật chuyên nghiệp từ con người. Chúng tôi không chịu trách nhiệm cho bất kỳ sự hiểu lầm hoặc diễn giải sai nào phát sinh từ việc sử dụng bản dịch này.\n" + "\n---\n\n**Tuyên bố miễn trừ trách nhiệm**: \nTài liệu này đã được dịch bằng dịch vụ dịch thuật AI [Co-op Translator](https://github.com/Azure/co-op-translator). Mặc dù chúng tôi cố gắng đảm bảo độ chính xác, xin lưu ý rằng các bản dịch tự động có thể chứa lỗi hoặc không chính xác. Tài liệu gốc bằng ngôn ngữ bản địa nên được coi là nguồn thông tin chính xác nhất. Đối với thông tin quan trọng, nên sử dụng dịch vụ dịch thuật chuyên nghiệp bởi con người. Chúng tôi không chịu trách nhiệm về bất kỳ sự hiểu lầm hoặc diễn giải sai nào phát sinh từ việc sử dụng bản dịch này.\n" ] } ], @@ -3687,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T08:19:07+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T20:36:21+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "vi" } diff --git a/translations/zh/2-Working-With-Data/08-data-preparation/notebook.ipynb b/translations/zh/2-Working-With-Data/08-data-preparation/notebook.ipynb index 95607674..cb3b969e 100644 --- a/translations/zh/2-Working-With-Data/08-data-preparation/notebook.ipynb +++ b/translations/zh/2-Working-With-Data/08-data-preparation/notebook.ipynb @@ -8,15 +8,15 @@ "source": [ "# 数据准备\n", "\n", - "[原始笔记本来源于 *数据科学:Python和机器学习工作室中的数据科学机器学习入门,作者 Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", + "[原始笔记本来源于 *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n", "\n", "## 探索 `DataFrame` 信息\n", "\n", "> **学习目标:** 在本小节结束时,您应该能够熟练地查找存储在 pandas DataFrame 中的数据的一般信息。\n", "\n", - "当您将数据加载到 pandas 中时,它很可能会以 `DataFrame` 的形式存在。然而,如果您的 `DataFrame` 中的数据集有60,000行和400列,您该如何开始了解您正在处理的内容呢?幸运的是,pandas 提供了一些方便的工具,可以快速查看 `DataFrame` 的整体信息,以及前几行和后几行数据。\n", + "当您将数据加载到 pandas 中时,它很可能会以 `DataFrame` 的形式存在。然而,如果您的 `DataFrame` 数据集有 60,000 行和 400 列,您该如何开始了解您正在处理的数据呢?幸运的是,pandas 提供了一些方便的工具,可以快速查看 `DataFrame` 的整体信息,以及前几行和后几行数据。\n", "\n", - "为了探索这些功能,我们将导入 Python 的 scikit-learn 库,并使用一个每位数据科学家都见过数百次的经典数据集:英国生物学家 Ronald Fisher 在其1936年的论文《多重测量在分类问题中的应用》中使用的 *Iris* 数据集:\n" + "为了探索这些功能,我们将导入 Python 的 scikit-learn 库,并使用一个每位数据科学家都见过无数次的经典数据集:英国生物学家 Ronald Fisher 在其 1936 年论文《多重测量在分类问题中的应用》中使用的 *Iris* 数据集:\n" ] }, { @@ -43,7 +43,7 @@ }, "source": [ "### `DataFrame.shape`\n", - "我们已经将鸢尾花数据集加载到变量 `iris_df` 中。在深入分析数据之前,了解我们拥有的数据点数量以及数据集的整体规模是很有价值的。查看我们正在处理的数据量是很有帮助的。\n" + "我们已经将鸢尾花数据集加载到变量 `iris_df` 中。在深入分析数据之前,了解我们拥有的数据点数量以及数据集的整体规模是非常有价值的。查看我们正在处理的数据量是很有帮助的。\n" ] }, { @@ -78,9 +78,9 @@ "id": "smE7AGzOhxk2" }, "source": [ - "所以,我们正在处理包含150行和4列的数据。每一行代表一个数据点,每一列代表与数据框相关的一个特征。基本上,这里有150个数据点,每个数据点包含4个特征。\n", + "我们正在处理包含150行和4列的数据。每一行代表一个数据点,每一列代表与数据框相关的一个特征。基本上,这里有150个数据点,每个数据点包含4个特征。\n", "\n", - "`shape`在这里是数据框的一个属性,而不是一个函数,这就是为什么它的末尾没有一对括号。\n" + "`shape` 是数据框的一个属性,而不是一个函数,这就是为什么它没有以一对括号结尾。\n" ] }, { @@ -90,7 +90,7 @@ }, "source": [ "### `DataFrame.columns`\n", - "现在让我们来看这4列数据。它们分别具体代表什么呢?`columns` 属性会告诉我们数据框中列的名称。\n" + "现在让我们来看数据的4列。每一列具体代表什么?`columns`属性将为我们提供数据框中列的名称。\n" ] }, { @@ -127,7 +127,7 @@ "id": "TsobcU_VjCC_" }, "source": [ - "正如我们所见,有四(4)列。`columns` 属性告诉我们列的名称,除此之外基本没有其他信息。当我们想要识别数据集包含的特征时,这个属性变得重要。\n" + "正如我们所看到的,有四(4)列。`columns`属性告诉我们列的名称,基本上没有其他信息。当我们想要识别数据集包含的特征时,这个属性显得尤为重要。\n" ] }, { @@ -137,7 +137,7 @@ }, "source": [ "### `DataFrame.info`\n", - "通过 `shape` 属性提供的数据量以及通过 `columns` 属性提供的特征或列名,可以让我们对数据集有一些初步了解。现在,我们希望更深入地探索数据集。`DataFrame.info()` 函数在这方面非常有用。\n" + "通过 `shape` 属性提供的数据量以及通过 `columns` 属性提供的特征或列名,可以让我们对数据集有一些了解。现在,我们希望更深入地探索数据集。`DataFrame.info()` 函数在这方面非常有用。\n" ] }, { @@ -180,10 +180,9 @@ "id": "1XgVMpvigRru" }, "source": [ - "从这里,我们可以得出一些观察:\n", - "\n", + "从这里,我们可以做出以下几点观察:\n", "1. 每列的数据类型:在这个数据集中,所有数据都存储为64位浮点数。\n", - "2. 非空值的数量:处理空值是数据准备中的一个重要步骤。这将在后续的笔记本中处理。\n" + "2. 非空值的数量:处理空值是数据准备中的重要步骤。这将在后续的笔记本中处理。\n" ] }, { @@ -193,7 +192,7 @@ }, "source": [ "### DataFrame.describe()\n", - "假设我们的数据集中有大量的数值数据。可以对每一列单独进行单变量统计计算,例如均值、中位数、四分位数等。`DataFrame.describe()` 函数为数据集的数值列提供统计摘要。\n" + "假设我们的数据集中有大量的数值数据。可以对每一列单独进行单变量统计计算,例如均值、中位数、四分位数等。`DataFrame.describe()`函数为我们提供了数据集中数值列的统计摘要。\n" ] }, { @@ -442,7 +441,7 @@ "id": "EBHEimZuEFQK" }, "source": [ - "在这里的输出中,我们可以看到数据集的五(5)条记录。如果我们查看左侧的索引,我们会发现这些是前五行。\n" + "在这里的输出中,我们可以看到数据集的五(5)条记录。如果查看左侧的索引,我们会发现这些是前五行。\n" ] }, { @@ -453,7 +452,7 @@ "source": [ "### 练习:\n", "\n", - "从上面的例子可以看出,默认情况下,`DataFrame.head` 会返回 `DataFrame` 的前五行。在下面的代码单元中,你能找到一种方法来显示超过五行的数据吗?\n" + "从上面的例子可以看出,默认情况下,`DataFrame.head` 会返回 `DataFrame` 的前五行。在下面的代码单元中,你能找到一种方法来显示超过五行吗?\n" ] }, { @@ -476,7 +475,7 @@ }, "source": [ "### `DataFrame.tail`\n", - "另一种查看数据的方法是从末尾开始(而不是从开头)。`DataFrame.head` 的反面是 `DataFrame.tail`,它会返回 `DataFrame` 的最后五行:\n" + "另一种查看数据的方法是从末尾开始(而不是开头)。`DataFrame.head` 的反面是 `DataFrame.tail`,它返回 `DataFrame` 的最后五行:\n" ] }, { @@ -585,9 +584,9 @@ "source": [ "在实际操作中,能够轻松查看 `DataFrame` 的前几行或后几行非常有用,尤其是在检查有序数据集中的异常值时。\n", "\n", - "上面通过代码示例展示的所有函数和属性,都能帮助我们快速了解数据的外观和特性。\n", + "上面通过代码示例展示的所有函数和属性,都能帮助我们了解数据的整体情况。\n", "\n", - "> **要点:** 仅仅通过查看 `DataFrame` 的元数据,或者查看其前几行和后几行的值,就可以快速了解数据的大小、形状以及内容。\n" + "> **要点:** 仅仅通过查看 `DataFrame` 的元数据或其中的前几行和后几行数据,就可以快速了解所处理数据的大小、形状和内容。\n" ] }, { @@ -597,17 +596,17 @@ }, "source": [ "### 缺失数据\n", - "让我们深入了解缺失数据。缺失数据是指某些列中没有存储任何值的情况。\n", + "让我们深入了解缺失数据。缺失数据是指某些列中没有存储任何值。\n", "\n", - "举个例子:假设某人对自己的体重很敏感,因此在调查中没有填写体重字段。那么,这个人的体重值就会缺失。\n", + "举个例子:假设某人对自己的体重很在意,因此在调查中没有填写体重字段。那么,这个人的体重值就会缺失。\n", "\n", "在现实世界的数据集中,缺失值是非常常见的。\n", "\n", "**Pandas如何处理缺失数据**\n", "\n", - "Pandas处理缺失值有两种方式。第一种方式你在之前的章节中已经见过:`NaN`,即“非数字”。实际上,这是一种特殊值,是IEEE浮点规范的一部分,仅用于表示缺失的浮点值。\n", + "Pandas处理缺失值有两种方式。第一种方式你在之前的章节中已经见过:`NaN`,即“非数字”(Not a Number)。这是一个特殊值,属于IEEE浮点数规范的一部分,仅用于表示缺失的浮点值。\n", "\n", - "对于非浮点类型的缺失值,Pandas使用Python的`None`对象。虽然同时遇到两种不同类型的缺失值可能会让人感到困惑,但这种设计选择有其合理的编程原因。在实际应用中,这种方式使Pandas能够在绝大多数情况下提供一个良好的折中方案。尽管如此,`None`和`NaN`都存在一些限制,需要注意它们在使用时的规则和约束。\n" + "对于非浮点类型的缺失值,Pandas使用Python的`None`对象。虽然遇到两种不同类型的值来表示同样的含义可能会让人感到困惑,但这种设计选择有其合理的编程原因。在实际应用中,这种方式使Pandas能够在绝大多数情况下提供一个良好的折中方案。尽管如此,`None`和`NaN`都存在一些限制,需要注意它们的使用方式。\n" ] }, { @@ -616,8 +615,8 @@ "id": "lOHqUlZFgRr5" }, "source": [ - "### `None`:非浮点类型的缺失数据\n", - "由于 `None` 来自 Python,它不能用于数据类型不是 `'object'` 的 NumPy 和 pandas 数组中。请记住,NumPy 数组(以及 pandas 中的数据结构)只能包含一种类型的数据。这种特性赋予了它们在大规模数据和计算工作中的强大能力,但也限制了它们的灵活性。这类数组必须向“最低公分母”数据类型进行提升,即能够包含数组中所有内容的数据类型。当数组中包含 `None` 时,这意味着你正在处理 Python 对象。\n", + "### `None`:非浮点型缺失数据\n", + "由于 `None` 来源于 Python,它不能用于数据类型不是 `'object'` 的 NumPy 和 pandas 数组。请记住,NumPy 数组(以及 pandas 中的数据结构)只能包含一种数据类型。这赋予了它们在大规模数据和计算工作中的强大能力,但也限制了它们的灵活性。这类数组必须提升为“最低公分母”,即能够包含数组中所有内容的数据类型。当数组中包含 `None` 时,这意味着你正在处理 Python 对象。\n", "\n", "为了更直观地理解这一点,请看以下示例数组(注意它的 `dtype`):\n" ] @@ -658,7 +657,7 @@ "id": "pdlgPNbhgRr7" }, "source": [ - "上升数据类型的现实带来了两个副作用。首先,操作将在解释的 Python 代码层面上进行,而不是编译的 NumPy 代码层面。这基本上意味着,任何涉及包含 `None` 的 `Series` 或 `DataFrame` 的操作都会变得更慢。虽然你可能不会注意到这种性能下降,但对于大型数据集来说,这可能会成为一个问题。\n", + "数据类型向上转换的现实带来了两个副作用。首先,操作将在解释型 Python 代码的层面上进行,而不是编译型 NumPy 代码的层面上。基本上,这意味着任何涉及包含 `None` 的 `Series` 或 `DataFrame` 的操作都会变得更慢。虽然你可能不会注意到这种性能下降,但对于大型数据集来说,这可能会成为一个问题。\n", "\n", "第二个副作用源于第一个副作用。由于 `None` 本质上将 `Series` 或 `DataFrame` 拉回到原生 Python 的世界,因此在包含 `None` 值的数组上使用 NumPy/pandas 的聚合函数(如 `sum()` 或 `min()`)通常会产生错误:\n" ] @@ -699,7 +698,7 @@ "id": "LcEwO8UogRr9" }, "source": [ - "**关键点**:整数与`None`值之间的加法(以及其他操作)是未定义的,这可能会限制您对包含它们的数据集所能执行的操作。\n" + "**关键点**:整数与`None`值之间的加法(以及其他操作)是未定义的,这可能会限制您对包含它们的数据集的操作。\n" ] }, { @@ -710,7 +709,7 @@ "source": [ "### `NaN`:缺失的浮点值\n", "\n", - "与 `None` 不同,NumPy(因此也包括 pandas)支持 `NaN`,以便进行快速的矢量化操作和 ufuncs。坏消息是,任何涉及 `NaN` 的算术运算结果都会是 `NaN`。例如:\n" + "与 `None` 不同,NumPy(因此也包括 pandas)支持 `NaN`,以便进行快速的矢量化操作和 ufuncs。坏消息是,任何对 `NaN` 进行的算术运算结果都会是 `NaN`。例如:\n" ] }, { @@ -810,7 +809,7 @@ "id": "nhlnNJT7gRr_" }, "source": [ - "### 练习:\n" + "### 练习:\n" ] }, { @@ -832,7 +831,7 @@ "id": "_iDvIRC8gRsA" }, "source": [ - "请记住:`NaN` 仅用于表示缺失的浮点值;整数、字符串或布尔值没有 `NaN` 的等价物。\n" + "记住:`NaN`仅用于表示缺失的浮点值;整数、字符串或布尔值没有对应的`NaN`。\n" ] }, { @@ -883,7 +882,7 @@ "id": "WklCzqb8gRsB" }, "source": [ - "### 练习:\n" + "### 练习:\n" ] }, { @@ -907,14 +906,14 @@ "id": "WjMQwltNgRsB" }, "source": [ - "在将数据类型向上转换以实现 `Series` 和 `DataFrame` 数据同质化的过程中,pandas 会自如地在 `None` 和 `NaN` 之间切换缺失值。由于这一设计特性,将 `None` 和 `NaN` 视为 pandas 中两种不同形式的“空值”是很有帮助的。事实上,你会发现 pandas 中一些用于处理缺失值的核心方法在命名上也反映了这一点:\n", + "在将数据类型向上转换以实现 `Series` 和 `DataFrame` 数据同质化的过程中,pandas 会主动在 `None` 和 `NaN` 之间切换缺失值。由于这一设计特性,将 `None` 和 `NaN` 视为 pandas 中两种不同形式的“空值”是很有帮助的。事实上,pandas 中一些处理缺失值的核心方法名称也反映了这一点:\n", "\n", "- `isnull()`:生成一个布尔掩码,用于标识缺失值\n", "- `notnull()`:与 `isnull()` 相反\n", "- `dropna()`:返回过滤后的数据版本\n", - "- `fillna()`:返回填充或插补缺失值后的数据副本\n", + "- `fillna()`:返回一个填充或插补缺失值后的数据副本\n", "\n", - "这些方法非常重要,掌握并熟练使用它们是关键。接下来,我们将深入了解每个方法。\n" + "这些方法非常重要,掌握并熟悉它们是关键。接下来我们将逐一深入了解这些方法。\n" ] }, { @@ -925,8 +924,8 @@ "source": [ "### 检测空值\n", "\n", - "既然我们已经了解了缺失值的重要性,那么在处理它们之前,我们需要先在数据集中检测这些值。 \n", - "`isnull()` 和 `notnull()` 是检测空数据的主要方法。它们都会返回数据上的布尔掩码。\n" + "既然我们已经了解了缺失值的重要性,那么在处理它们之前,我们需要在数据集中检测它们。 \n", + "`isnull()` 和 `notnull()` 是检测空数据的主要方法。两者都会返回数据的布尔掩码。\n" ] }, { @@ -979,11 +978,11 @@ "id": "PaSZ0SQygRsC" }, "source": [ - "仔细看看输出结果,有没有让你感到意外的地方?虽然 `0` 是一个算术上的空值,但它仍然是一个完全合法的整数,pandas 也将其视为整数。`''` 则稍微复杂一些。虽然我们在第1节中用它来表示一个空字符串值,但它仍然是一个字符串对象,而不是 pandas 所认为的空值。\n", + "仔细观察输出结果,有什么让你感到意外吗?虽然 `0` 是一个算术上的空值,但它仍然是一个完全合法的整数,pandas 也将其视为整数。而 `''` 则稍微复杂一些。虽然我们在第 1 节中使用它来表示空字符串值,但它本质上仍然是一个字符串对象,而不是 pandas 所认为的空值。\n", "\n", - "现在,让我们换个角度,用这些方法以更接近实际使用的方式来操作。你可以直接将布尔掩码用作 ``Series`` 或 ``DataFrame`` 的索引,这在处理孤立的缺失值(或存在值)时非常有用。\n", + "现在,让我们换个角度,以更贴近实际使用的方法来应用这些方法。你可以直接将布尔掩码用作 ``Series`` 或 ``DataFrame`` 的索引,这在处理孤立的缺失值(或存在值)时非常有用。\n", "\n", - "如果我们想要缺失值的总数,只需对 `isnull()` 方法生成的掩码进行求和即可。\n" + "如果我们想要统计缺失值的总数,只需对 `isnull()` 方法生成的掩码进行求和即可。\n" ] }, { @@ -1018,7 +1017,7 @@ "id": "PlBqEo3mgRsC" }, "source": [ - "### 练习:\n" + "### 练习:\n" ] }, { @@ -1041,7 +1040,7 @@ "id": "D_jWN7mHgRsD" }, "source": [ - "**关键点**:在使用 DataFrame 时,`isnull()` 和 `notnull()` 方法会产生类似的结果:它们显示结果及其索引,这将在您处理数据时为您提供极大的帮助。\n" + "**关键点**:当在数据框中使用 `isnull()` 和 `notnull()` 方法时,它们会产生类似的结果:显示结果及其索引,这将在处理数据时极大地帮助您。\n" ] }, { @@ -1052,11 +1051,11 @@ "source": [ "### 处理缺失数据\n", "\n", - "> **学习目标:** 在本小节结束时,你应该了解如何以及何时在 DataFrame 中替换或移除空值。\n", + "> **学习目标:** 在本小节结束时,您应该了解如何以及何时替换或删除 DataFrame 中的空值。\n", "\n", "机器学习模型本身无法处理缺失数据。因此,在将数据传入模型之前,我们需要处理这些缺失值。\n", "\n", - "如何处理缺失数据涉及一些微妙的权衡,这可能会影响你的最终分析结果以及实际应用的效果。\n", + "处理缺失数据的方法会带来微妙的权衡,并可能影响您的最终分析结果以及实际应用效果。\n", "\n", "处理缺失数据主要有两种方法:\n", "\n", @@ -1074,11 +1073,11 @@ "source": [ "### 删除空值\n", "\n", - "我们传递给模型的数据量会直接影响其性能。删除空值意味着我们减少了数据点的数量,从而减小了数据集的规模。因此,当数据集相当大时,建议删除包含空值的行。\n", + "我们传递给模型的数据量直接影响其性能。删除空值意味着减少数据点的数量,从而缩小数据集的规模。因此,当数据集较大时,建议删除包含空值的行。\n", "\n", - "另一种情况可能是某一行或某一列有大量缺失值。在这种情况下,它们可能会被删除,因为对于我们的分析来说,这些行/列的大部分数据都缺失,无法提供太多价值。\n", + "另一种情况可能是某一行或列有大量缺失值。在这种情况下,可以删除这些行或列,因为它们的大部分数据都缺失,对我们的分析贡献不大。\n", "\n", - "除了识别缺失值之外,pandas 提供了一种方便的方法来从 `Series` 和 `DataFrame` 中移除空值。为了更好地理解这一点,让我们回到 `example3`。`DataFrame.dropna()` 函数可以帮助删除包含空值的行。\n" + "除了识别缺失值之外,pandas 还提供了一种方便的方法来从 `Series` 和 `DataFrame` 中移除空值。为了更好地理解这一点,我们可以回到 `example3`。`DataFrame.dropna()` 函数可以帮助我们删除包含空值的行。\n" ] }, { @@ -1117,9 +1116,9 @@ "id": "hil2cr64gRsD" }, "source": [ - "请注意,这应该看起来像您的输出 `example3[example3.notnull()]`。这里的区别在于,`dropna` 不只是对掩码值进行索引,而是从 `Series` `example3` 中移除了那些缺失值。\n", + "请注意,这应该看起来像您从 `example3[example3.notnull()]` 的输出。这里的区别在于,`dropna` 不仅仅是基于掩码值进行索引,而是从 `Series` `example3` 中移除了那些缺失值。\n", "\n", - "由于 DataFrame 是二维的,因此在删除数据时提供了更多选项。\n" + "由于 DataFrame 是二维的,因此它提供了更多删除数据的选项。\n" ] }, { @@ -1209,9 +1208,9 @@ "id": "66wwdHZrgRsE" }, "source": [ - "(你注意到 pandas 将两列数据提升为浮点型以容纳 `NaN` 值了吗?)\n", + "(你是否注意到,为了容纳 `NaN` 值,pandas 将两列数据类型提升为浮点型?)\n", "\n", - "你无法从 `DataFrame` 中删除单个值,因此必须删除整行或整列。根据你的需求,你可能会选择其中一种操作,因此 pandas 为你提供了两种选项。在数据科学中,列通常代表变量,行通常代表观测值,因此你更可能会删除数据行;`dropna()` 的默认设置是删除包含任何空值的所有行:\n" + "你无法从 `DataFrame` 中删除单个值,因此必须删除整行或整列。根据你的需求,你可能需要选择其中一种方式,因此 pandas 提供了两种选项。在数据科学中,列通常表示变量,行表示观测值,因此你更可能删除数据的行;`dropna()` 的默认设置是删除所有包含任何空值的行:\n" ] }, { @@ -1363,9 +1362,9 @@ "id": "KWXiKTfMgRsF" }, "source": [ - "请注意,这可能会丢失大量数据,尤其是在较小的数据集中。如果您只想删除包含多个甚至全部空值的行或列,该怎么办?您可以在 `dropna` 中通过设置 `how` 和 `thresh` 参数来指定这些条件。\n", + "请注意,这可能会丢弃许多您可能希望保留的数据,尤其是在较小的数据集中。如果您只想删除包含多个甚至全部空值的行或列,该怎么办?您可以在 `dropna` 中通过 `how` 和 `thresh` 参数来指定这些设置。\n", "\n", - "默认情况下,`how='any'`(如果您想自行检查或查看该方法的其他参数,可以在代码单元中运行 `example4.dropna?`)。您也可以选择指定 `how='all'`,这样只会删除包含所有空值的行或列。让我们扩展示例 `DataFrame`,在接下来的练习中看看这是如何运作的。\n" + "默认情况下,`how='any'`(如果您想自己检查或查看该方法的其他参数,可以在代码单元中运行 `example4.dropna?`)。您也可以选择指定 `how='all'`,这样只会删除包含所有空值的行或列。让我们扩展示例 `DataFrame`,在接下来的练习中看看它的实际效果。\n" ] }, { @@ -1459,9 +1458,9 @@ "source": [ "> 关键要点:\n", "1. 只有在数据集足够大的情况下,删除空值才是一个好主意。\n", - "2. 如果某些行或列的大部分数据缺失,可以将整行或整列删除。\n", + "2. 如果某行或某列的大部分数据缺失,可以直接删除整行或整列。\n", "3. `DataFrame.dropna(axis=)` 方法可以用来删除空值。`axis` 参数表示是删除行还是列。\n", - "4. 还可以使用 `how` 参数。默认情况下,它被设置为 `any`,因此只会删除包含任意空值的行/列。可以将其设置为 `all`,以指定仅删除所有值均为空的行/列。\n" + "4. 还可以使用 `how` 参数。默认情况下,它设置为 `any`,因此只会删除包含任意空值的行或列。可以将其设置为 `all`,以指定仅删除所有值均为空的行或列。\n" ] }, { @@ -1493,7 +1492,7 @@ "id": "38kwAihWgRsG" }, "source": [ - "`thresh` 参数为您提供了更细粒度的控制:您可以设置一行或一列需要具有的 *非空* 值的数量,以便保留:\n" + "`thresh` 参数为您提供了更细粒度的控制:您可以设置一行或一列需要具有的 *非空* 值的数量,以便保留该行或列:\n" ] }, { @@ -1579,9 +1578,9 @@ "source": [ "### 填充空值\n", "\n", - "有时候,用可能有效的值来填充缺失值是有意义的。填充空值有几种方法。第一种是利用领域知识(即对数据集所基于主题的了解)来近似填补缺失值。\n", + "有时,用可能有效的值填充缺失值是合理的。填充空值有几种方法。第一种是使用领域知识(即数据集所基于主题的知识)来近似缺失值。\n", "\n", - "你可以使用 `isnull` 来原地完成这项工作,但如果需要填充的值很多,这可能会非常繁琐。由于这是数据科学中非常常见的任务,pandas 提供了 `fillna` 方法,它会返回一个 `Series` 或 `DataFrame` 的副本,其中的缺失值被替换为你选择的值。让我们创建另一个示例 `Series` 来看看它在实际中的工作方式。\n" + "你可以使用 `isnull` 来直接处理,但这可能会很繁琐,尤其是当你有很多值需要填充时。由于这是数据科学中非常常见的任务,pandas 提供了 `fillna` 方法,它会返回一个 `Series` 或 `DataFrame` 的副本,其中的缺失值被替换为你选择的值。让我们创建另一个示例 `Series` 来看看它在实际中的工作方式。\n" ] }, { @@ -1591,11 +1590,11 @@ }, "source": [ "### 分类数据(非数值型)\n", - "首先,让我们考虑非数值型数据。在数据集中,我们会有一些包含分类数据的列。例如:性别、True 或 False 等。\n", + "首先让我们来看非数值型数据。在数据集中,我们会有一些包含分类数据的列。例如:性别、True 或 False 等。\n", "\n", - "在大多数情况下,我们会用该列的`众数`来替换缺失值。假设我们有100个数据点,其中90个是True,8个是False,还有2个未填写。那么,我们可以用True填补这2个缺失值,因为True是该列的众数。\n", + "在大多数情况下,我们会用该列的`众数`来替换缺失值。比如说,我们有100个数据点,其中90个是True,8个是False,还有2个未填写。那么我们可以将这2个未填写的值填充为True,基于整个列的情况。\n", "\n", - "同样,在这里我们也可以利用领域知识。让我们来看一个用众数填补的例子。\n" + "当然,在这里我们也可以使用领域知识。让我们来看一个用众数填充的例子。\n" ] }, { @@ -1700,7 +1699,9 @@ "metadata": { "id": "MLAoMQOfNPlA" }, - "source": [] + "source": [ + "现在,让我们先找到众数,然后用众数填充 `None` 值。\n" + ] }, { "cell_type": "code", @@ -1735,7 +1736,9 @@ "metadata": { "id": "6iNz_zG_OKrx" }, - "source": [] + "source": [ + "所以,我们将用True替换None\n" + ] }, { "cell_type": "code", @@ -1845,7 +1848,7 @@ "id": "SktitLxxOR16" }, "source": [ - "正如我们所见,空值已被替换。不用说,我们本可以用任何内容替代`'True'`,它都会被替换。\n" + "正如我们所见,空值已被替换。不言而喻,我们本可以在 `'True'` 的位置写任何内容,它都会被替换。\n" ] }, { @@ -1857,12 +1860,12 @@ "### 数值数据\n", "现在来说说数值数据。这里有两种常见的方法来替换缺失值:\n", "\n", - "1. 用行的中位数替换\n", - "2. 用行的平均值替换\n", + "1. 用行的中位数替换 \n", + "2. 用行的平均值替换 \n", "\n", - "当数据存在偏态分布且有异常值时,我们使用中位数替换。这是因为中位数对异常值具有鲁棒性。\n", + "当数据存在偏斜且有异常值时,我们使用中位数替换。这是因为中位数对异常值具有鲁棒性。\n", "\n", - "当数据经过归一化处理后,我们可以使用平均值,因为在这种情况下,平均值和中位数会非常接近。\n", + "当数据是标准化的,我们可以使用平均值,因为在这种情况下,平均值和中位数会非常接近。\n", "\n", "首先,让我们选取一个正态分布的列,并用该列的平均值填充缺失值。\n" ] @@ -1970,7 +1973,7 @@ "id": "ka7-wNfzSxbx" }, "source": [ - "该列的平均值是\n" + "列的平均值是\n" ] }, { @@ -2004,7 +2007,9 @@ "metadata": { "id": "oBSRGxKRS39K" }, - "source": [] + "source": [ + "用均值填充\n" + ] }, { "cell_type": "code", @@ -2253,7 +2258,9 @@ "metadata": { "id": "z9PLF75Jj_1s" }, - "source": [] + "source": [ + "用中位数填充\n" + ] }, { "cell_type": "code", @@ -2395,7 +2402,7 @@ "id": "yrsigxRggRsH" }, "source": [ - "您可以用一个值(例如 `0`)填充所有的空条目:\n" + "您可以使用单个值(例如 `0`)填充所有空条目:\n" ] }, { @@ -2437,10 +2444,10 @@ }, "source": [ "> 关键要点:\n", - "1. 当数据较少或有填补缺失数据的策略时,应进行缺失值填补。\n", - "2. 可以利用领域知识通过近似的方法填补缺失值。\n", - "3. 对于分类数据,缺失值通常用该列的众数替代。\n", - "4. 对于数值型数据,缺失值通常用均值(针对标准化数据集)或该列的中位数填补。\n" + "1. 填补缺失值应在数据较少或有明确填补策略时进行。\n", + "2. 可以利用领域知识通过估算来填补缺失值。\n", + "3. 对于分类数据,通常用列的众数替代缺失值。\n", + "4. 对于数值型数据,缺失值通常用列的平均值(针对归一化数据集)或中位数填补。\n" ] }, { @@ -2449,7 +2456,7 @@ "id": "FI9MmqFJgRsH" }, "source": [ - "### 练习:\n" + "### 练习:\n" ] }, { @@ -2471,7 +2478,7 @@ "id": "kq3hw1kLgRsI" }, "source": [ - "您可以使用**前向填充**空值,即使用上一个有效值来填充空值:\n" + "您可以使用**前向填充**空值,即使用最后一个有效值填充空值:\n" ] }, { @@ -2512,7 +2519,7 @@ "id": "nDXeYuHzgRsI" }, "source": [ - "您还可以**向后填充**,将下一个有效值向后传播以填充空值:\n" + "您还可以**回填**,将下一个有效值向后传播以填充空值:\n" ] }, { @@ -2554,7 +2561,7 @@ "id": "MbBzTom5gRsI" }, "source": [ - "正如你可能猜到的,这与 DataFrame 的工作方式相同,但你还可以指定一个 `axis` 来填充空值:\n" + "正如您可能猜到的,这与DataFrame的操作方式相同,但您也可以指定一个`axis`来填充空值:\n" ] }, { @@ -2727,7 +2734,7 @@ "id": "ZeMc-I1EgRsI" }, "source": [ - "注意,当没有可用于向前填充的先前值时,空值将保留。\n" + "请注意,当没有可用于向前填充的先前值时,空值将保留。\n" ] }, { @@ -2736,7 +2743,7 @@ "id": "eeAoOU0RgRsJ" }, "source": [ - "### 练习:\n" + "### 练习:\n" ] }, { @@ -2760,7 +2767,7 @@ "id": "YHgy0lIrgRsJ" }, "source": [ - "你可以创造性地使用`fillna`。例如,我们再来看`example4`,但这次我们用`DataFrame`中所有值的平均值来填充缺失值:\n" + "你可以创造性地使用 `fillna`。例如,让我们再次查看 `example4`,但这次我们用 `DataFrame` 中所有值的平均值来填充缺失值:\n" ] }, { @@ -2851,9 +2858,9 @@ "id": "zpMvCkLSgRsJ" }, "source": [ - "请注意,第3列仍然没有值:默认的方向是按行填充值。\n", + "注意,第3列仍然没有值:默认方向是按行填充值。\n", "\n", - "> **要点:** 处理数据集中缺失值的方法有很多种。具体采用哪种策略(删除、替换,甚至如何替换)应根据数据的具体情况来决定。随着你处理和接触更多的数据集,你会逐渐培养出更好的直觉来应对缺失值问题。\n" + "> **要点:** 处理数据集中的缺失值有多种方法。具体采用哪种策略(删除、替换,甚至如何替换)应根据数据的具体情况来决定。随着你处理和接触更多的数据集,你会对如何处理缺失值有更好的理解。\n" ] }, { @@ -2877,7 +2884,7 @@ "source": [ "**标签编码**\n", "\n", - "标签编码本质上是将每个类别转换为一个数字。例如,假设我们有一个航空乘客的数据集,其中有一列表示他们的舱位类别,包括以下几种:['商务舱', '经济舱', '头等舱']。如果对其进行标签编码,这些类别将被转换为 [0,1,2]。让我们通过代码来看一个示例。由于我们将在后续的笔记本中学习 `scikit-learn`,这里我们不会使用它。\n" + "标签编码基本上是将每个类别转换为一个数字。例如,假设我们有一个航空乘客的数据集,其中有一列包含他们的舱位类别,类别包括 ['商务舱', '经济舱', '头等舱']。如果对其进行标签编码,它将被转换为 [0,1,2]。让我们通过代码示例来看看。由于我们将在后续笔记本中学习 `scikit-learn`,这里不会使用它。\n" ] }, { @@ -2985,7 +2992,7 @@ "id": "IDHnkwTYov-h" }, "source": [ - "要对第一列进行标签编码,我们必须首先描述从每个类别到数字的映射,然后再进行替换\n" + "要对第一列进行标签编码,我们首先需要描述一个从每个类别到数字的映射,然后进行替换。\n" ] }, { @@ -3087,9 +3094,9 @@ "id": "ftnF-TyapOPt" }, "source": [ - "正如我们所见,输出与我们预期的一致。那么,我们什么时候使用标签编码呢?标签编码在以下一种或两种情况下使用: \n", + "正如我们所见,输出与我们预期的结果一致。那么,我们什么时候使用标签编码呢?标签编码适用于以下一种或两种情况: \n", "1. 当类别数量较多时 \n", - "2. 当类别具有顺序关系时 \n" + "2. 当类别是有序的时 \n" ] }, { @@ -3100,9 +3107,9 @@ "source": [ "**独热编码**\n", "\n", - "另一种编码方式是独热编码。在这种编码方式中,每个列的类别都会作为一个单独的列添加到数据集中,并且每个数据点根据是否包含该类别被赋值为0或1。因此,如果有n个不同的类别,就会向数据框中添加n列。\n", + "另一种编码方式是独热编码。在这种编码方式中,每个列的类别都会作为单独的列添加到数据集中,并且每个数据点根据是否包含该类别会被赋值为0或1。因此,如果有n个不同的类别,就会向数据框中添加n列。\n", "\n", - "例如,我们继续使用飞机舱位的例子。类别是:['business class', 'economy class', 'first class']。如果我们进行独热编码,以下三列将被添加到数据集中:['class_business class', 'class_economy class', 'class_first class']。\n" + "例如,我们仍然使用飞机舱位的例子。类别是:['商务舱', '经济舱', '头等舱']。如果我们进行独热编码,数据集中将会添加以下三列:['class_business class', 'class_economy class', 'class_first class']。\n" ] }, { @@ -3335,7 +3342,7 @@ "id": "_zXRLOjXujdA" }, "source": [ - "每个独热编码列包含0或1,用于指定该数据点是否存在该类别。\n" + "每个独热编码列包含0或1,指定该数据点是否属于该类别。\n" ] }, { @@ -3346,8 +3353,8 @@ "source": [ "我们什么时候使用独热编码?独热编码在以下一种或两种情况下使用:\n", "\n", - "1. 当类别数量较少且数据集规模较小时。\n", - "2. 当类别之间没有特定顺序时。\n" + "1. 当类别数量和数据集规模较小时。\n", + "2. 当类别没有特定顺序时。\n" ] }, { @@ -3358,7 +3365,7 @@ "source": [ "> 关键要点:\n", "1. 编码用于将非数值数据转换为数值数据。\n", - "2. 编码分为两种类型:标签编码和独热编码,可以根据数据集的需求进行选择。\n" + "2. 编码分为两种类型:标签编码和独热编码,可根据数据集的需求进行选择。\n" ] }, { @@ -3371,7 +3378,7 @@ "\n", "> **学习目标:** 在本小节结束时,您应该能够熟练识别并删除 DataFrame 中的重复值。\n", "\n", - "除了缺失数据外,您在处理真实世界的数据集时经常会遇到重复数据。幸运的是,pandas 提供了一种简单的方法来检测和删除重复条目。\n" + "除了缺失数据之外,您在实际数据集中还会经常遇到重复数据。幸运的是,pandas 提供了一种简单的方法来检测和删除重复条目。\n" ] }, { @@ -3380,9 +3387,9 @@ "id": "qrEG-Wa0gRsJ" }, "source": [ - "### 识别重复值:`duplicated`\n", + "### 识别重复项:`duplicated`\n", "\n", - "你可以使用 pandas 中的 `duplicated` 方法轻松识别重复值。该方法会返回一个布尔掩码,指示 `DataFrame` 中某个条目是否是之前条目的重复值。让我们创建另一个示例 `DataFrame` 来实际演示这一点。\n" + "您可以使用 pandas 中的 `duplicated` 方法轻松识别重复值。该方法返回一个布尔掩码,指示 `DataFrame` 中的某个条目是否是之前条目的重复项。让我们创建另一个示例 `DataFrame` 来实际查看这一功能。\n" ] }, { @@ -3511,8 +3518,8 @@ "id": "0eDRJD4SgRsK" }, "source": [ - "### 删除重复值:`drop_duplicates`\n", - "`drop_duplicates` 会返回一个数据副本,其中所有 `duplicated` 值均为 `False`:\n" + "### 删除重复项:`drop_duplicates`\n", + "`drop_duplicates` 仅返回数据的副本,其中所有 `duplicated` 值均为 `False`:\n" ] }, { @@ -3671,13 +3678,531 @@ "metadata": { "id": "GvX4og1EgRsL" }, - "source": [] + "source": [ + "> **要点:** 删除重复数据是几乎每个数据科学项目的重要组成部分。重复数据可能会改变分析结果,并导致不准确的结论!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 真实世界中的数据质量检查\n", + "\n", + "> **学习目标:** 在本节结束时,您应该能够熟练检测和纠正常见的真实世界数据质量问题,包括不一致的分类值、异常的数值(离群值)以及具有变体的重复实体。\n", + "\n", + "虽然缺失值和完全重复是常见问题,但真实世界的数据集通常还包含更为隐蔽的问题:\n", + "\n", + "1. **不一致的分类值**:同一类别的拼写不同(例如,“USA”、“U.S.A”、“United States”)\n", + "2. **异常的数值**:极端的离群值,可能是数据录入错误(例如,年龄 = 999)\n", + "3. **近似重复的行**:表示同一实体但存在细微差异的记录\n", + "\n", + "让我们来探讨检测和处理这些问题的技术。\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 创建一个示例“脏”数据集\n", + "\n", + "首先,让我们创建一个包含我们在实际数据中常见问题类型的示例数据集:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Create a sample dataset with quality issues\n", + "dirty_data = pd.DataFrame({\n", + " 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n", + " 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n", + " 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n", + " 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n", + " 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n", + " 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n", + " 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n", + " 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n", + " 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n", + "})\n", + "\n", + "print(\"Sample 'Dirty' Dataset:\")\n", + "print(dirty_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. 检测不一致的分类值\n", + "\n", + "注意,`country` 列中同一个国家有多种表示方式。让我们来识别这些不一致之处:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check unique values in the country column\n", + "print(\"Unique country values:\")\n", + "print(dirty_data['country'].unique())\n", + "print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n", + "\n", + "# Count occurrences of each variation\n", + "print(\"\\nValue counts:\")\n", + "print(dirty_data['country'].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 标准化分类值\n", + "\n", + "我们可以创建一个映射来标准化这些值。一种简单的方法是将值转换为小写并创建一个映射字典:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a standardization mapping\n", + "country_mapping = {\n", + " 'usa': 'USA',\n", + " 'u.s.a': 'USA',\n", + " 'united states': 'USA',\n", + " 'uk': 'UK',\n", + " 'united kingdom': 'UK',\n", + " 'canada': 'Canada',\n", + " 'mexico': 'Mexico'\n", + "}\n", + "\n", + "# Standardize the country column\n", + "dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n", + "\n", + "print(\"Before standardization:\")\n", + "print(dirty_data['country'].value_counts())\n", + "print(\"\\nAfter standardization:\")\n", + "print(dirty_data[['country_clean']].value_counts())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**替代方法:使用模糊匹配**\n", + "\n", + "对于更复杂的情况,我们可以使用 `rapidfuzz` 库进行模糊字符串匹配,以自动检测相似的字符串:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n", + " process = None\n", + " fuzz = None\n", + "\n", + "# Get unique countries\n", + "unique_countries = dirty_data['country'].unique()\n", + "\n", + "# For each country, find similar matches\n", + "if process is not None and fuzz is not None:\n", + " print(\"Finding similar country names (similarity > 70%):\")\n", + " for country in unique_countries:\n", + " matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n", + " # Filter matches with similarity > 70 and not identical\n", + " similar = [m for m in matches if m[1] > 70 and m[0] != country]\n", + " if similar:\n", + " print(f\"\\n'{country}' is similar to:\")\n", + " for match, score, _ in similar:\n", + " print(f\" - '{match}' (similarity: {score}%)\")\n", + "else:\n", + " print(\"Skipping fuzzy matching because rapidfuzz is not available.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. 检测异常数值(离群值)\n", + "\n", + "查看 `age` 列,我们发现一些可疑的值,比如 199 和 -5。让我们使用统计方法来检测这些离群值。\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display basic statistics\n", + "print(\"Age column statistics:\")\n", + "print(dirty_data['age'].describe())\n", + "\n", + "# Identify impossible values using domain knowledge\n", + "print(\"\\nRows with impossible age values (< 0 or > 120):\")\n", + "impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n", + "print(impossible_ages[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 使用 IQR(四分位距)方法\n", + "\n", + "IQR 方法是一种稳健的统计技术,用于检测异常值,对极端值的敏感性较低:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate IQR for age (excluding impossible values)\n", + "valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n", + "\n", + "Q1 = valid_ages.quantile(0.25)\n", + "Q3 = valid_ages.quantile(0.75)\n", + "IQR = Q3 - Q1\n", + "\n", + "# Define outlier bounds\n", + "lower_bound = Q1 - 1.5 * IQR\n", + "upper_bound = Q3 + 1.5 * IQR\n", + "\n", + "print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n", + "\n", + "# Identify outliers\n", + "age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n", + "print(f\"\\nRows with age outliers:\")\n", + "print(age_outliers[['customer_id', 'name', 'age']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 使用 Z-Score 方法\n", + "\n", + "Z-Score 方法通过与平均值的标准差来识别异常值:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from scipy import stats\n", + "except ImportError:\n", + " print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n", + "else:\n", + " # Calculate Z-scores for age, handling NaN values\n", + " age_nonan = dirty_data['age'].dropna()\n", + " zscores = np.abs(stats.zscore(age_nonan))\n", + " dirty_data['age_zscore'] = np.nan\n", + " dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n", + "\n", + " # Typically, Z-score > 3 indicates an outlier\n", + " print(\"Rows with age Z-score > 3:\")\n", + " zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n", + " print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n", + "\n", + " # Clean up the temporary column\n", + " dirty_data = dirty_data.drop('age_zscore', axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 处理异常值\n", + "\n", + "一旦检测到异常值,可以通过以下几种方式处理:\n", + "1. **删除**:删除包含异常值的行(如果它们是错误数据)\n", + "2. **限制**:用边界值替换\n", + "3. **替换为 NaN**:将其视为缺失数据并使用插补技术处理\n", + "4. **保留**:如果它们是合法的极端值\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a cleaned version by replacing impossible ages with NaN\n", + "dirty_data['age_clean'] = dirty_data['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + ")\n", + "\n", + "print(\"Age column before and after cleaning:\")\n", + "print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. 检测近似重复行\n", + "\n", + "注意,我们的数据集中有多个“John Smith”的条目,且值略有不同。让我们根据名字相似性来识别潜在的重复项。\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's look at exact name matches (ignoring extra whitespace)\n", + "dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n", + "\n", + "print(\"Checking for duplicate names:\")\n", + "duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n", + "print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 使用模糊匹配查找近似重复项\n", + "\n", + "为了进行更复杂的重复检测,我们可以使用模糊匹配来查找相似的名称:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " from rapidfuzz import process, fuzz\n", + "\n", + " # Function to find potential duplicates\n", + " def find_near_duplicates(df, column, threshold=90):\n", + " \"\"\"\n", + " Find near-duplicate entries in a column using fuzzy matching.\n", + " \n", + " Parameters:\n", + " - df: DataFrame\n", + " - column: Column name to check for duplicates\n", + " - threshold: Similarity threshold (0-100)\n", + " \n", + " Returns: List of potential duplicate groups\n", + " \"\"\"\n", + " values = df[column].unique()\n", + " duplicate_groups = []\n", + " checked = set()\n", + " \n", + " for value in values:\n", + " if value in checked:\n", + " continue\n", + " \n", + " # Find similar values\n", + " matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n", + " similar = [m[0] for m in matches if m[1] >= threshold]\n", + " \n", + " if len(similar) > 1:\n", + " duplicate_groups.append(similar)\n", + " checked.update(similar)\n", + " \n", + " return duplicate_groups\n", + "\n", + " # Find near-duplicate names\n", + " duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n", + "\n", + " print(\"Potential duplicate groups:\")\n", + " for i, group in enumerate(duplicate_groups, 1):\n", + " print(f\"\\nGroup {i}:\")\n", + " for name in group:\n", + " matching_rows = dirty_data[dirty_data['name'] == name]\n", + " print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n", + " for _, row in matching_rows.iterrows():\n", + " print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n", + "except ImportError:\n", + " print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 处理重复项\n", + "\n", + "一旦识别出重复项,你需要决定如何处理:\n", + "1. **保留第一次出现**:使用 `drop_duplicates(keep='first')`\n", + "2. **保留最后一次出现**:使用 `drop_duplicates(keep='last')`\n", + "3. **汇总信息**:合并重复行中的信息\n", + "4. **人工审核**:标记以供人工审核\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example: Remove duplicates based on normalized name, keeping first occurrence\n", + "cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n", + "\n", + "print(f\"Original dataset: {len(dirty_data)} rows\")\n", + "print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n", + "print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 总结:完整的数据清洗流程\n", + "\n", + "让我们将所有内容整合成一个全面的清洗流程:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def clean_dataset(df):\n", + " \"\"\"\n", + " Comprehensive data cleaning function.\n", + " \"\"\"\n", + " # Create a copy to avoid modifying the original\n", + " cleaned = df.copy()\n", + " \n", + " # 1. Standardize categorical values (country)\n", + " country_mapping = {\n", + " 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n", + " 'uk': 'UK', 'united kingdom': 'UK',\n", + " 'canada': 'Canada', 'mexico': 'Mexico'\n", + " }\n", + " cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n", + " \n", + " # 2. Clean abnormal age values\n", + " cleaned['age'] = cleaned['age'].apply(\n", + " lambda x: np.nan if (x < 0 or x > 120) else x\n", + " )\n", + " \n", + " # 3. Remove near-duplicate names (normalize whitespace)\n", + " cleaned['name'] = cleaned['name'].str.strip()\n", + " cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n", + " \n", + " return cleaned\n", + "\n", + "# Apply the cleaning pipeline\n", + "final_cleaned_data = clean_dataset(dirty_data)\n", + "\n", + "print(\"Before cleaning:\")\n", + "print(f\" Rows: {len(dirty_data)}\")\n", + "print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nAfter cleaning:\")\n", + "print(f\" Rows: {len(final_cleaned_data)}\")\n", + "print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n", + "print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n", + "\n", + "print(\"\\nCleaned dataset:\")\n", + "print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 🎯 挑战练习\n", + "\n", + "现在轮到你了!下面是一行包含多个质量问题的新数据。你能否:\n", + "\n", + "1. 找出这行数据中的所有问题\n", + "2. 编写代码清理每个问题\n", + "3. 将清理后的数据添加到数据集中\n", + "\n", + "以下是有问题的数据:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# New problematic row\n", + "new_row = pd.DataFrame({\n", + " 'customer_id': [13],\n", + " 'name': [' Diana Prince '], # Extra whitespace\n", + " 'age': [250], # Impossible age\n", + " 'country': ['U.S.A.'], # Inconsistent format\n", + " 'purchase_amount': [150.00]\n", + "})\n", + "\n", + "print(\"New row to clean:\")\n", + "print(new_row)\n", + "\n", + "# TODO: Your code here to clean this row\n", + "# Hints:\n", + "# 1. Strip whitespace from the name\n", + "# 2. Check if the name is a duplicate (Diana Prince already exists)\n", + "# 3. Handle the impossible age value\n", + "# 4. Standardize the country name\n", + "\n", + "# Example solution (uncomment and modify as needed):\n", + "# new_row_cleaned = new_row.copy()\n", + "# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n", + "# new_row_cleaned['age'] = np.nan # Invalid age\n", + "# new_row_cleaned['country'] = 'USA' # Standardized\n", + "# print(\"\\nCleaned row:\")\n", + "# print(new_row_cleaned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 关键要点\n", + "\n", + "1. **类别不一致**在实际数据中很常见。务必检查唯一值,并通过映射或模糊匹配来标准化它们。\n", + "\n", + "2. **异常值**会显著影响你的分析。结合领域知识和统计方法(IQR、Z分数)来检测它们。\n", + "\n", + "3. **近似重复项**比完全重复项更难检测。可以考虑使用模糊匹配并规范化数据(如转换为小写、去除空格)来识别它们。\n", + "\n", + "4. **数据清理是一个迭代过程**。可能需要应用多种技术并审查结果,才能最终确定清理后的数据集。\n", + "\n", + "5. **记录你的决策**。记录你应用了哪些清理步骤以及原因,这对于可重复性和透明性非常重要。\n", + "\n", + "> **最佳实践:**始终保留一份原始“脏”数据的副本。切勿覆盖源数据文件——创建清理后的版本,并使用清晰的命名规则,例如`data_cleaned.csv`。\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n---\n\n**免责声明**: \n本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。对于因使用本翻译而引起的任何误解或误读,我们概不负责。\n" + "\n---\n\n**免责声明**: \n本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们对因使用此翻译而产生的任何误解或误读不承担责任。\n" ] } ], @@ -3705,8 +4230,8 @@ "version": "3.5.4" }, "coopTranslator": { - "original_hash": "8533b3a2230311943339963fc7f04c21", - "translation_date": "2025-09-02T08:22:06+00:00", + "original_hash": "6301339d1c9a301b00639c635dc9b731", + "translation_date": "2025-10-03T19:15:49+00:00", "source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb", "language_code": "zh" }