{ "cells": [ { "cell_type": "markdown", "id": "5f831876", "metadata": {}, "source": [ "# Week 5: Exploratory Data Analysis and Visualisation\n", "\n", "*Kmex Consult — Data Science Fundamentals Course*\n", "\n", "Work through each code cell in order. Edit and re-run to experiment." ] }, { "cell_type": "markdown", "id": "80ac1ae7", "metadata": {}, "source": [ "*Data Science Fundamentals Course*" ] }, { "cell_type": "markdown", "id": "69ce4898", "metadata": {}, "source": [ "## Week 5 Overview\n", "Exploratory Data Analysis (EDA) is the critical phase where you get to know your data deeply before building any models. It involves using statistics and visualizations to understand patterns, distributions, relationships, and anomalies in your data. Effective EDA can reveal insights, inform feature engineering decisions, and prevent costly mistakes in modeling.\n", "\n", "This week focuses on:\n", "- Calculating descriptive statistics (mean, median, mode, variance, etc.)\n", "- Understanding distributions and their properties\n", "- Creating compelling visualizations with Matplotlib and Seaborn\n", "- Analyzing relationships between variables\n", "- Creating professional-quality plots suitable for reports and presentations\n", "\n", "By the end of Week 5, you will be able to:\n", "- Calculate and interpret comprehensive summary statistics\n", "- Create distributions and identify skewness and outliers\n", "- Build beautiful, informative visualizations\n", "- Analyze correlations between variables\n", "- Communicate data insights through effective visualizations\n", "- Create publication-quality plots for reports and presentations\n", "\n", "Week 5 is divided into three 2-hour sessions:\n", "- Session 1: Descriptive Statistics and Univariate Analysis\n", "- Session 2: Matplotlib and Seaborn for Data Visualization\n", "- Session 3: Correlation Analysis, Advanced Visualizations, and Plotly" ] }, { "cell_type": "markdown", "id": "757e391a", "metadata": {}, "source": [ "## SESSION 1: Descriptive Statistics and Univariate Analysis" ] }, { "cell_type": "markdown", "id": "d80213a8", "metadata": {}, "source": [ "### Duration: 2 hours" ] }, { "cell_type": "markdown", "id": "0d2a4840", "metadata": {}, "source": [ "### 1.1 What is Exploratory Data Analysis?\n", "EDA is the process of analyzing datasets to summarize their main characteristics, often using statistical graphics and other data visualization methods. The goals of EDA are to:\n", "\n", "- Understand data structure and content\n", "- Identify patterns, trends, and anomalies\n", "- Check data quality (missing values, outliers)\n", "- Generate hypotheses for testing\n", "- Inform feature engineering decisions\n", "- Detect relationships between variables\n", "- Prepare data for modeling\n", "\n", "EDA is NOT about finding the final answer, but about asking questions and exploring what the data tells you." ] }, { "cell_type": "markdown", "id": "62d4f16e", "metadata": {}, "source": [ "### 1.2 Descriptive Statistics" ] }, { "cell_type": "code", "execution_count": null, "id": "d625fc8e", "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "\n", "# Create sample dataset\n", "df = pd.DataFrame({\n", "'Age': [22, 25, 28, 30, 32, 35, 38, 40, 42, 45, 48, 50],\n", "'Salary': [35000, 42000, 48000, 52000, 58000, 62000, 68000, 72000, 78000, 85000, 92000, 100000],\n", "'YearsExp': [1, 2, 3, 4, 5, 7, 8, 10, 12, 15, 18, 20]\n", "})\n", "\n", "print(\"Dataset:\")\n", "print(df)\n", "print()\n", "\n", "# Basic statistics\n", "print(\"=\"*50)\n", "print(\"DESCRIPTIVE STATISTICS\")\n", "print(\"=\"*50)\n", "\n", "# Mean (average)\n", "print(f\"Mean Age: {df['Age'].mean():.2f}\")\n", "print(f\"Mean Salary: {df['Salary'].mean():.2f}\")\n", "\n", "# Median (middle value)\n", "print(f\"Median Age: {df['Age'].median():.2f}\")\n", "print(f\"Median Salary: {df['Salary'].median():.2f}\")\n", "\n", "# Mode (most frequent value)\n", "print(f\"Mode Age: {df['Age'].mode().values[0] if len(df['Age'].mode()) > 0 else 'No mode'}\")\n", "\n", "# Standard deviation (spread)\n", "print(f\"Std Dev Age: {df['Age'].std():.2f}\")\n", "print(f\"Std Dev Salary: {df['Salary'].std():.2f}\")\n", "\n", "# Variance (squared standard deviation)\n", "print(f\"Variance Age: {df['Age'].var():.2f}\")\n", "\n", "# Range\n", "print(f\"Range Age: {df['Age'].max() - df['Age'].min()}\")\n", "\n", "# Min and Max\n", "print(f\"Min Age: {df['Age'].min()}\")\n", "print(f\"Max Age: {df['Age'].max()}\")\n", "\n", "# Quartiles\n", "print(f\"\\n25th percentile (Q1) Age: {df['Age'].quantile(0.25):.2f}\")\n", "print(f\"50th percentile (Q2/Median) Age: {df['Age'].quantile(0.50):.2f}\")\n", "print(f\"75th percentile (Q3) Age: {df['Age'].quantile(0.75):.2f}\")\n", "\n", "# IQR (Interquartile Range)\n", "Q1 = df['Age'].quantile(0.25)\n", "Q3 = df['Age'].quantile(0.75)\n", "IQR = Q3 - Q1\n", "print(f\"IQR Age: {IQR:.2f}\")\n", "\n", "# Use pandas describe() for quick summary\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"PANDAS describe() METHOD\")\n", "print(\"=\"*50)\n", "print(df.describe())\n", "# Shows: count, mean, std, min, 25%, 50%, 75%, max\n", "\n", "# describe() with more percentiles\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"WITH CUSTOM PERCENTILES\")\n", "print(\"=\"*50)\n", "print(df.describe(percentiles=[0.1, 0.25, 0.5, 0.75, 0.9]))\n", "\n", "# Correlation matrix\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"CORRELATION\")\n", "print(\"=\"*50)\n", "print(df.corr())\n", "\n", "# Data types and memory\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"DATA INFO\")\n", "print(\"=\"*50)\n", "print(df.info())\n", "\n", "# Value counts (for categorical)\n", "df_cat = pd.DataFrame({\n", "'Department': ['Sales', 'IT', 'Finance', 'Sales', 'IT', 'Sales', 'HR', 'Finance', 'Sales', 'IT'],\n", "'Performance': ['Good', 'Excellent', 'Good', 'Fair', 'Excellent', 'Good', 'Fair', 'Excellent', 'Good', 'Excellent']\n", "})\n", "\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"VALUE COUNTS\")\n", "print(\"=\"*50)\n", "print(df_cat['Department'].value_counts())\n", "print(\"\\nDepartment percentages:\")\n", "print(df_cat['Department'].value_counts(normalize=True) * 100)" ] }, { "cell_type": "markdown", "id": "ad52556b", "metadata": {}, "source": [ "### 1.3 Understanding Distributions" ] }, { "cell_type": "code", "execution_count": null, "id": "b91fbe40", "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "from scipy import stats\n", "\n", "# Create datasets with different distributions\n", "np.random.seed(42)\n", "\n", "# Normal distribution\n", "normal_data = np.random.normal(loc=100, scale=15, size=1000)\n", "\n", "# Right-skewed distribution (e.g., income)\n", "right_skewed = np.random.exponential(scale=2, size=1000)\n", "\n", "# Left-skewed distribution\n", "left_skewed = -np.random.exponential(scale=2, size=1000)\n", "\n", "df = pd.DataFrame({\n", "'Normal': normal_data,\n", "'Right_Skewed': right_skewed,\n", "'Left_Skewed': left_skewed\n", "})\n", "\n", "# Skewness (measure of asymmetry)\n", "# Positive skew: tail on right (mean > median)\n", "# Negative skew: tail on left (mean < median)\n", "# Skewness ~ 0: fairly symmetric\n", "print(\"=\"*50)\n", "print(\"SKEWNESS\")\n", "print(\"=\"*50)\n", "print(f\"Normal Skewness: {stats.skew(df['Normal']):.3f}\")\n", "print(f\"Right-Skewed Skewness: {stats.skew(df['Right_Skewed']):.3f}\")\n", "print(f\"Left-Skewed Skewness: {stats.skew(df['Left_Skewed']):.3f}\")\n", "\n", "# Kurtosis (measure of tail weight/peakedness)\n", "# High kurtosis: heavy tails (more outliers)\n", "# Low kurtosis: light tails (fewer outliers)\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"KURTOSIS\")\n", "print(\"=\"*50)\n", "print(f\"Normal Kurtosis: {stats.kurtosis(df['Normal']):.3f}\")\n", "print(f\"Right-Skewed Kurtosis: {stats.kurtosis(df['Right_Skewed']):.3f}\")\n", "print(f\"Left-Skewed Kurtosis: {stats.kurtosis(df['Left_Skewed']):.3f}\")\n", "\n", "# Real-world example: Analyze test scores\n", "scores = pd.DataFrame({\n", "'Test1': np.random.normal(75, 10, 100),\n", "'Test2': np.array([45]*10 + [90]*50 + [75]*40), # Bimodal\n", "'Test3': np.random.normal(85, 5, 100) # Most pass\n", "})\n", "\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"TEST SCORES ANALYSIS\")\n", "print(\"=\"*50)\n", "print(scores.describe())\n", "print(\"\\nSkewness:\")\n", "print(scores.skew())\n", "print(\"\\nKurtosis:\")\n", "print(scores.kurtosis())\n", "\n", "# Interpretation\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"INTERPRETATION\")\n", "print(\"=\"*50)\n", "print(\"Skewness > 0: Right-skewed (positive skew)\")\n", "print(\"Skewness < 0: Left-skewed (negative skew)\")\n", "print(\"Skewness ~ 0: Symmetric/Normal\")\n", "print()\n", "print(\"Kurtosis > 0: Heavy-tailed (leptokurtic)\")\n", "print(\"Kurtosis < 0: Light-tailed (platykurtic)\")\n", "print(\"Kurtosis ~ 0: Normal-like (mesokurtic)\")" ] }, { "cell_type": "markdown", "id": "0c236ce7", "metadata": {}, "source": [ "### 1.4 Bivariate and Multivariate Analysis" ] }, { "cell_type": "code", "execution_count": null, "id": "d3434425", "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "\n", "# Create sample data\n", "df = pd.DataFrame({\n", "'Age': [22, 25, 28, 30, 32, 35, 38, 40, 42, 45],\n", "'Salary': [35000, 42000, 48000, 52000, 58000, 62000, 68000, 72000, 78000, 85000],\n", "'YearsExp': [1, 2, 3, 4, 5, 7, 8, 10, 12, 15],\n", "'Department': ['Sales', 'IT', 'Sales', 'Finance', 'IT', 'Sales', 'HR', 'Finance', 'IT', 'Sales']\n", "})\n", "\n", "print(\"Dataset:\")\n", "print(df)\n", "\n", "# Correlation between two variables\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"BIVARIATE ANALYSIS: CORRELATION\")\n", "print(\"=\"*50)\n", "\n", "correlation = df['Age'].corr(df['Salary'])\n", "print(f\"Correlation between Age and Salary: {correlation:.3f}\")\n", "\n", "correlation2 = df['YearsExp'].corr(df['Salary'])\n", "print(f\"Correlation between Experience and Salary: {correlation2:.3f}\")\n", "\n", "# Covariance\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"COVARIANCE\")\n", "print(\"=\"*50)\n", "cov = df[['Age', 'Salary']].cov()\n", "print(cov)\n", "\n", "# Correlation matrix (all numeric columns)\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"CORRELATION MATRIX\")\n", "print(\"=\"*50)\n", "print(df.corr())\n", "\n", "# Group by analysis\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"GROUP ANALYSIS\")\n", "print(\"=\"*50)\n", "\n", "# Average salary by department\n", "dept_stats = df.groupby('Department')['Salary'].agg(['mean', 'std', 'count', 'min', 'max'])\n", "print(\"\\nSalary statistics by Department:\")\n", "print(dept_stats)\n", "\n", "# Multiple aggregations\n", "agg_stats = df.groupby('Department').agg({\n", "'Salary': ['mean', 'min', 'max'],\n", "'Age': ['mean', 'std'],\n", "'YearsExp': 'mean'\n", "})\n", "print(\"\\nMultiple statistics by Department:\")\n", "print(agg_stats)\n", "\n", "# Pivot table\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"PIVOT TABLE\")\n", "print(\"=\"*50)\n", "\n", "# Create sample with more data\n", "df_large = pd.DataFrame({\n", "'Month': ['Jan', 'Jan', 'Feb', 'Feb', 'Mar', 'Mar'] * 2,\n", "'Region': ['North', 'South', 'North', 'South', 'North', 'South'] * 2,\n", "'Sales': [1000, 1200, 1500, 1300, 1800, 1600, 1100, 1250, 1550, 1350, 1850, 1650]\n", "})\n", "\n", "pivot = df_large.pivot_table(values='Sales', index='Region', columns='Month', aggfunc='mean')\n", "print(pivot)\n", "\n", "# Real-world: Customer analysis\n", "customers = pd.DataFrame({\n", "'CustomerID': range(1, 11),\n", "'Age': [25, 32, 28, 45, 38, 52, 29, 35, 41, 48],\n", "'Spending': [1000, 2500, 1800, 5000, 3500, 6000, 2000, 2800, 4200, 5500],\n", "'Region': ['North', 'South', 'North', 'South', 'East', 'West', 'North', 'South', 'East', 'West'],\n", "'Visits': [5, 10, 8, 15, 12, 20, 6, 9, 14, 18]\n", "})\n", "\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"CUSTOMER ANALYSIS\")\n", "print(\"=\"*50)\n", "\n", "# Correlation with spending\n", "print(f\"\\nAge vs Spending correlation: {customers['Age'].corr(customers['Spending']):.3f}\")\n", "print(f\"Visits vs Spending correlation: {customers['Visits'].corr(customers['Spending']):.3f}\")\n", "\n", "# By region\n", "print(\"\\nAverage spending by region:\")\n", "print(customers.groupby('Region')['Spending'].agg(['mean', 'count']))" ] }, { "cell_type": "markdown", "id": "ff0cdcf3", "metadata": {}, "source": [ "## SESSION 2: Matplotlib and Seaborn for Data Visualization" ] }, { "cell_type": "markdown", "id": "fc7eba3a", "metadata": {}, "source": [ "### Duration: 2 hours" ] }, { "cell_type": "markdown", "id": "2341494d", "metadata": {}, "source": [ "### 2.1 Introduction to Matplotlib" ] }, { "cell_type": "code", "execution_count": null, "id": "ada60550", "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import pandas as pd\n", "import numpy as np\n", "\n", "# Create sample data\n", "np.random.seed(42)\n", "data = pd.DataFrame({\n", "'Month': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],\n", "'Sales': [1000, 1200, 950, 1400, 1600, 1800],\n", "'Expenses': [600, 700, 650, 800, 900, 950]\n", "})\n", "\n", "# Basic line plot\n", "plt.figure(figsize=(10, 6))\n", "plt.plot(data['Month'], data['Sales'], marker='o', linewidth=2, markersize=8)\n", "plt.title('Monthly Sales', fontsize=16, fontweight='bold')\n", "plt.xlabel('Month', fontsize=12)\n", "plt.ylabel('Sales ($)', fontsize=12)\n", "plt.grid(True, alpha=0.3)\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Multiple lines\n", "plt.figure(figsize=(10, 6))\n", "plt.plot(data['Month'], data['Sales'], marker='o', label='Sales', linewidth=2)\n", "plt.plot(data['Month'], data['Expenses'], marker='s', label='Expenses', linewidth=2)\n", "plt.title('Sales vs Expenses', fontsize=16, fontweight='bold')\n", "plt.xlabel('Month', fontsize=12)\n", "plt.ylabel('Amount ($)', fontsize=12)\n", "plt.legend(loc='best')\n", "plt.grid(True, alpha=0.3)\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Scatter plot\n", "np.random.seed(42)\n", "x = np.random.randn(100)\n", "y = 2 * x + np.random.randn(100)\n", "\n", "plt.figure(figsize=(10, 6))\n", "plt.scatter(x, y, alpha=0.6, s=100, edgecolors='black', linewidth=0.5)\n", "plt.title('Relationship between X and Y', fontsize=16, fontweight='bold')\n", "plt.xlabel('X values', fontsize=12)\n", "plt.ylabel('Y values', fontsize=12)\n", "plt.grid(True, alpha=0.3)\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Bar plot\n", "categories = ['A', 'B', 'C', 'D', 'E']\n", "values = [25, 45, 30, 50, 35]\n", "\n", "plt.figure(figsize=(10, 6))\n", "bars = plt.bar(categories, values, color=['red', 'blue', 'green', 'orange', 'purple'], alpha=0.7)\n", "plt.title('Sales by Category', fontsize=16, fontweight='bold')\n", "plt.xlabel('Category', fontsize=12)\n", "plt.ylabel('Sales ($)', fontsize=12)\n", "# Add value labels on bars\n", "for bar, value in zip(bars, values):\n", "height = bar.get_height()\n", "plt.text(bar.get_x() + bar.get_width()/2., height,\n", "f'{int(value)}', ha='center', va='bottom', fontsize=10)\n", "plt.grid(True, alpha=0.3, axis='y')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Histogram\n", "np.random.seed(42)\n", "data = np.random.normal(100, 15, 1000)\n", "\n", "plt.figure(figsize=(10, 6))\n", "plt.hist(data, bins=30, color='skyblue', edgecolor='black', alpha=0.7)\n", "plt.title('Distribution of Test Scores', fontsize=16, fontweight='bold')\n", "plt.xlabel('Score', fontsize=12)\n", "plt.ylabel('Frequency', fontsize=12)\n", "plt.axvline(np.mean(data), color='red', linestyle='--', linewidth=2, label=f'Mean: {np.mean(data):.1f}')\n", "plt.axvline(np.median(data), color='green', linestyle='--', linewidth=2, label=f'Median: {np.median(data):.1f}')\n", "plt.legend()\n", "plt.grid(True, alpha=0.3, axis='y')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Subplots\n", "fig, axes = plt.subplots(2, 2, figsize=(12, 10))\n", "\n", "# Subplot 1: Line plot\n", "axes[0, 0].plot(data['Month'], data['Sales'], marker='o')\n", "axes[0, 0].set_title('Sales Over Time')\n", "axes[0, 0].grid(True, alpha=0.3)\n", "\n", "# Subplot 2: Bar plot\n", "axes[0, 1].bar(data['Month'], data['Expenses'])\n", "axes[0, 1].set_title('Expenses by Month')\n", "axes[0, 1].grid(True, alpha=0.3, axis='y')\n", "\n", "# Subplot 3: Histogram\n", "axes[1, 0].hist(np.random.randn(1000), bins=30, color='skyblue', edgecolor='black')\n", "axes[1, 0].set_title('Distribution')\n", "\n", "# Subplot 4: Scatter\n", "axes[1, 1].scatter(np.random.randn(100), np.random.randn(100))\n", "axes[1, 1].set_title('Scatter Plot')\n", "\n", "plt.suptitle('Dashboard Overview', fontsize=16, fontweight='bold')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Save figure\n", "plt.figure(figsize=(10, 6))\n", "plt.plot(data['Month'], data['Sales'], marker='o')\n", "plt.title('Sales')\n", "plt.savefig('sales_plot.png', dpi=300, bbox_inches='tight')\n", "print(\"Figure saved as 'sales_plot.png'\")" ] }, { "cell_type": "markdown", "id": "a912a396", "metadata": {}, "source": [ "### 2.2 Advanced Visualization with Seaborn" ] }, { "cell_type": "code", "execution_count": null, "id": "e17f6d7c", "metadata": {}, "outputs": [], "source": [ "import seaborn as sns\n", "import matplotlib.pyplot as plt\n", "import pandas as pd\n", "import numpy as np\n", "\n", "# Set style\n", "sns.set_style(\"whitegrid\")\n", "sns.set_palette(\"husl\")\n", "\n", "# Load built-in dataset\n", "iris = sns.load_dataset(\"iris\")\n", "print(iris.head())\n", "\n", "# Histogram with KDE\n", "plt.figure(figsize=(10, 6))\n", "sns.histplot(data=iris, x=\"sepal_length\", kde=True, bins=20)\n", "plt.title(\"Sepal Length Distribution\", fontsize=14, fontweight='bold')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Box plot (shows quartiles and outliers)\n", "plt.figure(figsize=(10, 6))\n", "sns.boxplot(data=iris, x=\"species\", y=\"sepal_length\")\n", "plt.title(\"Sepal Length by Species\", fontsize=14, fontweight='bold')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Violin plot (shows full distribution)\n", "plt.figure(figsize=(10, 6))\n", "sns.violinplot(data=iris, x=\"species\", y=\"sepal_length\")\n", "plt.title(\"Sepal Length Distribution by Species\", fontsize=14, fontweight='bold')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Strip plot (individual points)\n", "plt.figure(figsize=(10, 6))\n", "sns.stripplot(data=iris, x=\"species\", y=\"sepal_length\", size=8, jitter=True)\n", "plt.title(\"Sepal Length by Species (Individual Points)\", fontsize=14, fontweight='bold')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Count plot (categorical frequencies)\n", "plt.figure(figsize=(10, 6))\n", "sns.countplot(data=iris, x=\"species\")\n", "plt.title(\"Count of Each Species\", fontsize=14, fontweight='bold')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Scatter plot with hue\n", "plt.figure(figsize=(10, 6))\n", "sns.scatterplot(data=iris, x=\"sepal_length\", y=\"sepal_width\", hue=\"species\", s=100)\n", "plt.title(\"Sepal Length vs Width by Species\", fontsize=14, fontweight='bold')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Regression plot (scatter + trend line)\n", "plt.figure(figsize=(10, 6))\n", "sns.regplot(data=iris, x=\"sepal_length\", y=\"sepal_width\")\n", "plt.title(\"Sepal Length vs Width (with Trend)\", fontsize=14, fontweight='bold')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Multiple plots with hue and col\n", "plt.figure(figsize=(14, 6))\n", "sns.lmplot(data=iris, x=\"sepal_length\", y=\"sepal_width\", hue=\"species\", col=\"species\")\n", "plt.suptitle(\"Sepal Relationships by Species\", fontsize=14, fontweight='bold', y=1.01)\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Real-world: Sales analysis\n", "sales_data = pd.DataFrame({\n", "'Date': pd.date_range('2023-01-01', periods=100),\n", "'Region': np.random.choice(['North', 'South', 'East', 'West'], 100),\n", "'Sales': np.random.randint(1000, 5000, 100),\n", "'Category': np.random.choice(['Electronics', 'Clothing', 'Food'], 100)\n", "})\n", "\n", "# Box plot by region\n", "plt.figure(figsize=(10, 6))\n", "sns.boxplot(data=sales_data, x=\"Region\", y=\"Sales\")\n", "plt.title(\"Sales Distribution by Region\", fontsize=14, fontweight='bold')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Violin plot with split\n", "plt.figure(figsize=(12, 6))\n", "sns.violinplot(data=sales_data, x=\"Region\", y=\"Sales\", hue=\"Category\", split=False)\n", "plt.title(\"Sales by Region and Category\", fontsize=14, fontweight='bold')\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "e495d457", "metadata": {}, "source": [ "## SESSION 3: Correlation Analysis, Advanced Visualizations, and Plotly" ] }, { "cell_type": "markdown", "id": "491ed116", "metadata": {}, "source": [ "### Duration: 2 hours" ] }, { "cell_type": "markdown", "id": "0ea2318c", "metadata": {}, "source": [ "### 3.1 Correlation Analysis and Heatmaps" ] }, { "cell_type": "code", "execution_count": null, "id": "57088e8a", "metadata": {}, "outputs": [], "source": [ "import seaborn as sns\n", "import matplotlib.pyplot as plt\n", "import pandas as pd\n", "import numpy as np\n", "\n", "# Create sample data\n", "np.random.seed(42)\n", "df = pd.DataFrame({\n", "'Age': np.random.randint(20, 60, 100),\n", "'Salary': np.random.randint(30000, 150000, 100),\n", "'YearsExp': np.random.randint(0, 30, 100),\n", "'Performance': np.random.randint(1, 5, 100),\n", "'Satisfaction': np.random.randint(1, 5, 100)\n", "})\n", "\n", "# Add correlation between some variables\n", "df['Salary'] = df['Age'] * 2000 + df['YearsExp'] * 3000 + np.random.randint(-10000, 10000, 100)\n", "df['Performance'] = (df['YearsExp'] / 2 + np.random.randint(-2, 2, 100)).astype(int)\n", "df['Satisfaction'] = (df['Performance'] + np.random.randint(-1, 1, 100)).astype(int)\n", "\n", "print(\"Data shape:\", df.shape)\n", "print(df.head())\n", "\n", "# Correlation matrix\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"CORRELATION MATRIX\")\n", "print(\"=\"*50)\n", "corr_matrix = df.corr()\n", "print(corr_matrix)\n", "\n", "# Heatmap of correlations\n", "plt.figure(figsize=(10, 8))\n", "sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='coolwarm', center=0,\n", "square=True, linewidths=1, cbar_kws={\"shrink\": 0.8})\n", "plt.title(\"Correlation Heatmap\", fontsize=14, fontweight='bold')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Focused correlation with one variable\n", "salary_corr = df.corr()['Salary'].sort_values(ascending=False)\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"CORRELATION WITH SALARY\")\n", "print(\"=\"*50)\n", "print(salary_corr)\n", "\n", "# Plot correlation with salary\n", "plt.figure(figsize=(10, 6))\n", "salary_corr.drop('Salary').plot(kind='barh', color=['green' if x > 0 else 'red' for x in salary_corr.drop('Salary')])\n", "plt.title(\"Correlation with Salary\", fontsize=14, fontweight='bold')\n", "plt.xlabel(\"Correlation Coefficient\", fontsize=12)\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Pairplot (all relationships)\n", "print(\"\\nGenerating pairplot (takes a moment)...\")\n", "# Using iris dataset for cleaner example\n", "iris = sns.load_dataset(\"iris\")\n", "pairplot = sns.pairplot(iris, hue=\"species\", diag_kind=\"kde\")\n", "pairplot.fig.suptitle(\"Pairplot of Iris Dataset\", fontsize=16, fontweight='bold', y=0.995)\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Real-world: Employee dataset\n", "employees = pd.DataFrame({\n", "'Age': [25, 28, 32, 35, 38, 42, 45, 48, 52, 55],\n", "'Salary': [45000, 52000, 60000, 68000, 75000, 85000, 95000, 105000, 120000, 135000],\n", "'YearsExp': [1, 3, 5, 8, 10, 15, 18, 20, 25, 28],\n", "'Performance': [3, 3.5, 4, 4, 4.5, 4, 4.5, 5, 5, 4.5],\n", "'Absences': [8, 6, 4, 3, 2, 1, 0, 1, 0, 1]\n", "})\n", "\n", "plt.figure(figsize=(10, 8))\n", "corr = employees.corr()\n", "sns.heatmap(corr, annot=True, fmt='.3f', cmap='RdYlGn', center=0,\n", "square=True, linewidths=1, cbar_kws={\"shrink\": 0.8})\n", "plt.title(\"Employee Data Correlation Matrix\", fontsize=14, fontweight='bold')\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "75eedec5", "metadata": {}, "source": [ "### 3.2 Advanced Visualization Techniques" ] }, { "cell_type": "code", "execution_count": null, "id": "d0dd3d87", "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "import pandas as pd\n", "import numpy as np\n", "\n", "# Faceted plot (multiple subplots by category)\n", "iris = sns.load_dataset(\"iris\")\n", "\n", "g = sns.FacetGrid(iris, col=\"species\", height=4)\n", "g.map(sns.scatterplot, \"sepal_length\", \"sepal_width\")\n", "plt.suptitle(\"Sepal Dimensions by Species\", fontsize=14, fontweight='bold', y=1.00)\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Distribution plot with categorization\n", "sales_data = pd.DataFrame({\n", "'Region': np.repeat(['North', 'South', 'East', 'West'], 50),\n", "'Sales': np.concatenate([\n", "np.random.normal(5000, 1000, 50),\n", "np.random.normal(4500, 1200, 50),\n", "np.random.normal(6000, 800, 50),\n", "np.random.normal(5200, 1100, 50)\n", "])\n", "})\n", "\n", "plt.figure(figsize=(12, 6))\n", "for region in sales_data['Region'].unique():\n", "data = sales_data[sales_data['Region'] == region]['Sales']\n", "plt.hist(data, alpha=0.5, label=region, bins=20)\n", "plt.title(\"Sales Distribution by Region\", fontsize=14, fontweight='bold')\n", "plt.xlabel(\"Sales ($)\")\n", "plt.ylabel(\"Frequency\")\n", "plt.legend()\n", "plt.grid(True, alpha=0.3)\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Joint plot (bivariate + marginal distributions)\n", "plt.figure()\n", "joint = sns.jointplot(data=iris, x=\"sepal_length\", y=\"sepal_width\", kind=\"hex\")\n", "joint.fig.suptitle(\"Sepal Dimensions Joint Distribution\", fontsize=14, fontweight='bold', y=0.995)\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Clustermap (hierarchical clustering visualization)\n", "np.random.seed(42)\n", "data = np.random.rand(10, 12)\n", "df_cluster = pd.DataFrame(data, columns=[f'Feature_{i}' for i in range(12)])\n", "\n", "plt.figure(figsize=(10, 8))\n", "sns.clustermap(df_cluster.corr(), cmap='coolwarm', center=0, figsize=(8, 8))\n", "plt.suptitle(\"Hierarchical Clustering of Features\", fontsize=14, fontweight='bold')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# KDE plot (kernel density estimation)\n", "np.random.seed(42)\n", "x = np.random.normal(100, 15, 1000)\n", "y = np.random.normal(100, 15, 1000)\n", "\n", "plt.figure(figsize=(10, 6))\n", "sns.kdeplot(x=x, y=y, cmap=\"YlOrRd\", fill=True, thresh=0, levels=10)\n", "plt.title(\"2D Density Plot\", fontsize=14, fontweight='bold')\n", "plt.xlabel(\"X values\")\n", "plt.ylabel(\"Y values\")\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# Real-world: Business analytics dashboard\n", "np.random.seed(42)\n", "months = pd.date_range('2023-01-01', periods=12, freq='M')\n", "dashboard_data = pd.DataFrame({\n", "'Month': months,\n", "'Revenue': np.random.randint(50000, 150000, 12),\n", "'Customers': np.random.randint(1000, 5000, 12),\n", "'Expenses': np.random.randint(30000, 80000, 12),\n", "'Region': np.random.choice(['North', 'South', 'East', 'West'], 12)\n", "})\n", "\n", "fig, axes = plt.subplots(2, 2, figsize=(14, 10))\n", "\n", "# Revenue trend\n", "axes[0, 0].plot(dashboard_data['Month'], dashboard_data['Revenue'], marker='o', linewidth=2)\n", "axes[0, 0].set_title('Monthly Revenue', fontweight='bold')\n", "axes[0, 0].grid(True, alpha=0.3)\n", "axes[0, 0].set_ylabel('Revenue ($)')\n", "\n", "# Customer count\n", "axes[0, 1].bar(dashboard_data['Month'].dt.month, dashboard_data['Customers'], color='skyblue')\n", "axes[0, 1].set_title('Monthly Customers', fontweight='bold')\n", "axes[0, 1].set_ylabel('Customer Count')\n", "axes[0, 1].grid(True, alpha=0.3, axis='y')\n", "\n", "# Profit\n", "profit = dashboard_data['Revenue'] - dashboard_data['Expenses']\n", "axes[1, 0].fill_between(range(len(dashboard_data)), profit, alpha=0.3, color='green')\n", "axes[1, 0].plot(profit, marker='o', color='green', linewidth=2)\n", "axes[1, 0].set_title('Monthly Profit', fontweight='bold')\n", "axes[1, 0].set_ylabel('Profit ($)')\n", "axes[1, 0].grid(True, alpha=0.3)\n", "\n", "# Revenue by region\n", "region_revenue = dashboard_data.groupby('Region')['Revenue'].sum().sort_values(ascending=False)\n", "axes[1, 1].barh(region_revenue.index, region_revenue.values, color=['red', 'blue', 'green', 'orange'])\n", "axes[1, 1].set_title('Total Revenue by Region', fontweight='bold')\n", "axes[1, 1].set_xlabel('Revenue ($)')\n", "\n", "plt.suptitle('Business Dashboard', fontsize=16, fontweight='bold', y=0.995)\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "83ba3e1c", "metadata": {}, "source": [ "### 3.3 Interactive Visualizations with Plotly" ] }, { "cell_type": "code", "execution_count": null, "id": "f5f4309c", "metadata": {}, "outputs": [], "source": [ "# Install plotly: pip install plotly\n", "\n", "import plotly.express as px\n", "import plotly.graph_objects as go\n", "import pandas as pd\n", "import numpy as np\n", "\n", "# Load sample data\n", "iris = px.data.iris()\n", "\n", "# Interactive scatter plot\n", "fig = px.scatter(iris, x=\"sepal_width\", y=\"sepal_length\",\n", "color=\"species\", size=\"petal_length\",\n", "hover_name=\"species\",\n", "title=\"Iris Dataset - Interactive Scatter Plot\",\n", "labels={\"sepal_width\": \"Sepal Width\", \"sepal_length\": \"Sepal Length\"})\n", "fig.show()\n", "\n", "# Interactive box plot\n", "fig = px.box(iris, x=\"species\", y=\"sepal_length\",\n", "title=\"Sepal Length by Species\",\n", "color=\"species\")\n", "fig.show()\n", "\n", "# Interactive line chart\n", "df_stocks = pd.DataFrame({\n", "'Date': pd.date_range('2023-01-01', periods=100),\n", "'Stock_A': np.cumsum(np.random.randn(100)) + 100,\n", "'Stock_B': np.cumsum(np.random.randn(100)) + 100,\n", "'Stock_C': np.cumsum(np.random.randn(100)) + 100\n", "})\n", "\n", "fig = px.line(df_stocks, x='Date', y=['Stock_A', 'Stock_B', 'Stock_C'],\n", "title=\"Stock Price Trends\",\n", "labels={'value': 'Price ($)'})\n", "fig.show()\n", "\n", "# Interactive bar chart\n", "fruit_data = pd.DataFrame({\n", "'Fruit': ['Apple', 'Banana', 'Orange', 'Grape', 'Mango'],\n", "'Sales': [1000, 1500, 1200, 800, 1100],\n", "'Region': ['North', 'South', 'North', 'East', 'West']\n", "})\n", "\n", "fig = px.bar(fruit_data, x='Fruit', y='Sales', color='Region',\n", "title=\"Fruit Sales by Region\",\n", "barmode='group')\n", "fig.show()\n", "\n", "# 3D scatter plot\n", "fig = px.scatter_3d(iris, x='sepal_length', y='sepal_width', z='petal_length',\n", "color='species', size='petal_width',\n", "title=\"3D Iris Dataset\")\n", "fig.show()\n", "\n", "# Animated visualization\n", "gapminder = px.data.gapminder().query(\"year >= 2000\")\n", "fig = px.scatter(gapminder, x=\"gdpPercap\", y=\"lifeExp\",\n", "animation_frame=\"year\", animation_group=\"country\",\n", "size=\"pop\", color=\"continent\", hover_name=\"country\",\n", "log_x=True, size_max=60,\n", "range_x=[100, 100000], range_y=[25, 90],\n", "title=\"Economic Growth and Life Expectancy Over Time\")\n", "fig.show()\n", "\n", "# Custom plotly figure\n", "fig = go.Figure()\n", "\n", "# Add trace 1\n", "x = np.linspace(0, 10, 100)\n", "y1 = np.sin(x)\n", "y2 = np.cos(x)\n", "\n", "fig.add_trace(go.Scatter(x=x, y=y1, mode='lines', name='sin(x)'))\n", "fig.add_trace(go.Scatter(x=x, y=y2, mode='lines', name='cos(x)'))\n", "\n", "fig.update_layout(\n", "title='Trigonometric Functions',\n", "xaxis_title='X values',\n", "yaxis_title='Y values',\n", "hovermode='x unified',\n", "height=600,\n", "width=1000\n", ")\n", "fig.show()\n", "\n", "# Real-world: Sales dashboard\n", "np.random.seed(42)\n", "sales_data = pd.DataFrame({\n", "'Date': pd.date_range('2023-01-01', periods=365),\n", "'Sales': np.random.randint(1000, 5000, 365),\n", "'Region': np.random.choice(['North', 'South', 'East', 'West'], 365),\n", "'Category': np.random.choice(['Electronics', 'Clothing', 'Food'], 365)\n", "})\n", "\n", "# Daily sales trend\n", "daily_sales = sales_data.groupby('Date')['Sales'].sum()\n", "fig = px.line(x=daily_sales.index, y=daily_sales.values,\n", "title='Daily Sales Trend',\n", "labels={'x': 'Date', 'y': 'Sales ($)'})\n", "fig.show()\n", "\n", "# Sales by region\n", "region_sales = sales_data.groupby('Region')['Sales'].sum()\n", "fig = px.pie(values=region_sales.values, names=region_sales.index,\n", "title='Sales Distribution by Region')\n", "fig.show()\n", "\n", "# Sales by category\n", "category_sales = sales_data.groupby('Category')['Sales'].sum()\n", "fig = px.bar(x=category_sales.index, y=category_sales.values,\n", "title='Sales by Category',\n", "labels={'x': 'Category', 'y': 'Total Sales ($)'})\n", "fig.show()" ] }, { "cell_type": "markdown", "id": "a2a95159", "metadata": {}, "source": [ "#### Best Practices for Data Visualization\n", "- Choose appropriate chart type for your data: use bar charts for categories, line charts for time series, scatter plots for relationships\n", "- Keep it simple: avoid clutter and unnecessary elements\n", "- Use clear titles and labels: make sure axes are labeled and units are clear\n", "- Choose colors wisely: use contrasting colors, avoid red-green combinations for colorblind viewers\n", "- Include legends when necessary: explain what colors/shapes represent\n", "- Highlight key insights: use annotations, trends, or highlighting to draw attention to important findings\n", "- Maintain consistency: use same colors, fonts, and styles across related visualizations\n", "- Consider your audience: technical reports need different style than business presentations\n", "- Provide context: show baselines, averages, or benchmarks for comparison\n", "- Test readability: ensure text is large enough and colors are distinguishable" ] }, { "cell_type": "markdown", "id": "7f233ce2", "metadata": {}, "source": [ "## Week 5 Summary\n", "By completing Week 5, you have learned:\n", "- What EDA is and why it's critical in data science\n", "- Descriptive statistics: mean, median, mode, std, variance, range\n", "- Understanding distributions: skewness, kurtosis\n", "- Quartiles, percentiles, and IQR for understanding data spread\n", "- Bivariate analysis: correlations, covariance, group statistics\n", "- Pivot tables for summarizing data by categories\n", "- Matplotlib basics: line plots, scatter plots, bar charts, histograms\n", "- Subplots for creating multi-chart figures\n", "- Seaborn for statistical visualizations: box plots, violin plots, distribution plots\n", "- Heatmaps for visualizing correlations\n", "- Pairplots for exploring all relationships in dataset\n", "- Advanced plots: faceted plots, joint plots, density plots\n", "- Business dashboards combining multiple visualizations\n", "- Interactive visualizations with Plotly\n", "- Best practices for effective data visualization" ] }, { "cell_type": "markdown", "id": "6d3e8871", "metadata": {}, "source": [ "## Week 5 Assignments" ] }, { "cell_type": "markdown", "id": "f8837691", "metadata": {}, "source": [ "### Assignment 1: Comprehensive EDA Report\n", "Perform complete exploratory analysis on a dataset:\n", "- Calculate all descriptive statistics (mean, median, std, quartiles, etc.)\n", "- Analyze distributions: skewness, kurtosis\n", "- Create 10+ visualizations using Matplotlib and Seaborn\n", "- Include: histograms, box plots, scatter plots, distribution plots\n", "- Analyze correlations and create heatmap\n", "- Group analysis by categories\n", "- Generate a written report with key insights and findings\n", "- Suggest features for modeling based on EDA findings" ] }, { "cell_type": "markdown", "id": "5da1231a", "metadata": {}, "source": [ "### Assignment 2: Interactive Dashboard with Plotly\n", "Create an interactive dashboard:\n", "- Load a multi-dimensional dataset (sales, customer, or similar)\n", "- Create at least 5 interactive visualizations with Plotly\n", "- Include different chart types: line, bar, scatter, pie, box\n", "- Make visualizations interactive: hover info, filters, etc.\n", "- Create a narrative that tells a story with the data\n", "- Include annotations and highlights for key findings\n", "- Save as HTML file for sharing" ] }, { "cell_type": "markdown", "id": "9e690a27", "metadata": {}, "source": [ "### Assignment 3: Exploratory Analysis Report\n", "Download a real dataset and produce professional analysis:\n", "- Use a dataset from Kaggle or similar with 500+ rows\n", "- Perform complete EDA with statistics and visualizations\n", "- Create a professional PDF/HTML report with:\n", "- Executive summary\n", "- Descriptive statistics\n", "- 10-15 high-quality visualizations\n", "- Correlation analysis\n", "- Key findings and recommendations\n", "- Data quality assessment\n", "- Format for business presentation" ] }, { "cell_type": "markdown", "id": "fea73e37", "metadata": {}, "source": [ "## Recommended Practice Problems\n", "- Create visualizations using only Matplotlib (no Seaborn)\n", "- Replicate publication-quality figures from research papers\n", "- Create effective dashboards for different audiences (executives, analysts, technical)\n", "- Practice color palettes for different data types and contexts\n", "- Create animated visualizations showing data changes over time\n", "- Build multi-level interactive dashboards with Plotly\n", "- Practice statistical plot interpretation and presentation\n", "- Create infographics-style visualizations\n", "- Build automated EDA reports" ] }, { "cell_type": "markdown", "id": "566465c3", "metadata": {}, "source": [ "## Additional Resources" ] }, { "cell_type": "markdown", "id": "a076ff31", "metadata": {}, "source": [ "### Books\n", "- Chapter 9: Plotting and Visualization - "Python for Data Analysis" by Wes McKinney\n", "- Fundamentals of Data Visualization by Claus Wilke (free online)\n", "- The Visual Display of Quantitative Information by Edward Tufte" ] }, { "cell_type": "markdown", "id": "da83c31d", "metadata": {}, "source": [ "### Online Documentation\n", "- Matplotlib Documentation: https://matplotlib.org/\n", "- Seaborn Documentation: https://seaborn.pydata.org/\n", "- Plotly Documentation: https://plotly.com/python/\n", "- pandas Visualization: https://pandas.pydata.org/docs/user_guide/visualization.html" ] }, { "cell_type": "markdown", "id": "abec587f", "metadata": {}, "source": [ "### Gallery and Examples\n", "- Matplotlib Gallery: https://matplotlib.org/stable/gallery/index\n", "- Seaborn Gallery: https://seaborn.pydata.org/examples.html\n", "- Plotly Gallery: https://plotly.com/python/" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.11" } }, "nbformat": 4, "nbformat_minor": 5 }