View on GitHub

ESG Risk Analysis

Download this project as a .zip file Download this project as a tar.gz file

ESG-Risk-Analysis: Uncovering Hidden Risks in Corporate Responsibility

To identify ESG risk patterns across sectors, company sizes, and governance practices using Python-based data analysis and visualization, delivering insights that could support sustainable investing decisions and risk mitigation strategies.

Table of Contents


About the Project

This project provides a comprehensive analysis of Environmental, Social, and Governance (ESG) risks across companies and industries, leveraging Python, SQL, and Power BI to uncover hidden patterns and support informed decision-making.

Built to assist investors, financial analysts, ESG strategists, and regulatory teams, the project aggregates and visualizes ESG performance data, controversy indicators, and governance quality metrics. It identifies high-risk entities, industry-level ESG benchmarks, and compliance red flags, enabling stakeholders to align investments and business decisions with sustainability, ethics, and long-term risk management goals.

The analysis focuses on three core ESG dimensions:

Environmental: Carbon footprint, resource usage, and environmental violations

Social: Labor practices, human rights, diversity, and public controversies

Governance: Board independence, executive compensation, transparency, and audit integrity

Why it matters: In today’s ESG-conscious world, companies with poor ESG performance face regulatory pressure, reputational damage, and declining investor confidence. This project helps stakeholders proactively manage those risks by translating ESG data into actionable business and investment intelligence.

Objectives

The objectives of the project are to analyze and discover:

Tools Used

Data Source

This project uses sample data that simulates typical ESG data:

Executive Summary

This ESG Risk Analysis uncovers key risk signals that inform smarter, sustainable investment decisions. Notably, Occidental Petroleum and Exxon Mobil emerge as the highest-risk entities, driven largely by elevated environmental risk, positioning them at the top of ESG concern for energy sector exposure.

Analysis confirms that environmental risk is the most influential driver of total ESG scores — a critical insight for investors managing climate-linked asset exposure. The Energy and Materials sectors, in particular, present consistently high ESG risk, requiring focused monitoring and engagement.

Larger companies (15,000+ employees) show a reduced environmental footprint per risk score, yet face heightened governance and social risks, likely due to operational complexity and reputational exposure.

Additionally, the presence of ESG controversies significantly elevates overall risk perception, underscoring the need for real-time tracking of red flags, not just static risk ratings.

These insights enable investors to identify high-risk holdings, adjust sector allocations, and apply ESG filters with greater precision, aligning portfolios with long-term sustainability and compliance goals.

Business Questions Answered

Technical Analysis

SQL Queries

Column names and their data types

SELECT COLUMN_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'SP_500_ESG_Risk_Ratings'; 

Cleaning and changing the datatypes of columns

UPDATE SP_500_ESG_Risk_Ratings
SET Environment_Risk_Score = NULLIF(LTRIM(RTRIM(REPLACE(Environment_Risk_Score, ',', ''))), '');;

UPDATE SP_500_ESG_Risk_Ratings
SET Governance_Risk_Score = NULLIF(LTRIM(RTRIM(REPLACE(Governance_Risk_Score, ',', ''))), '');

--
UPDATE SP_500_ESG_Risk_Ratings
SET Social_Risk_Score = NULLIF(LTRIM(RTRIM(REPLACE(Social_Risk_Score, ',', ''))), '');

--
UPDATE SP_500_ESG_Risk_Ratings
SET Total_ESG_Risk_score = NULLIF(LTRIM(RTRIM(REPLACE(Total_ESG_Risk_score, ',', ''))), '');

--
UPDATE SP_500_ESG_Risk_Ratings
SET Controversy_Score = NULLIF(LTRIM(RTRIM(REPLACE(Controversy_Score, ',', ''))), '');

UPDATE SP_500_ESG_Risk_Ratings
SET Controversy_Score = REPLACE(Controversy_Score, 'N/A', '0');

UPDATE SP_500_ESG_Risk_Ratings
SET Controversy_Score = Coalesce(Controversy_Score, '0');

ALTER TABLE SP_500_ESG_Risk_Ratings
ALTER COLUMN Controversy_Score Integer;

Industry-wide average ESG component scores

SELECT
    Industry,
    Round(AVG(Environment_Risk_Score), 2) AS Avg_Environment,
    Round(AVG(Governance_Risk_Score), 2) AS Avg_Governance,
    Round(AVG(Social_Risk_Score), 2) AS Avg_Social
FROM SP_500_ESG_Risk_Ratings
GROUP BY Industry
ORDER BY Industry;

page No. of companies by ESG risk level

SELECT ESG_Risk_Level, COUNT(*) AS Company_Count
FROM SP_500_ESG_Risk_Ratings
WHERE ESG_Risk_Level IS NOT NULL
GROUP BY ESG_Risk_Level
ORDER BY Company_Count DESC;

page ESG score by risk category

SELECT ESG_Risk_Level,
       AVG(Total_ESG_Risk_score) AS Avg_Total_ESG
FROM SP_500_ESG_Risk_Ratings
GROUP BY ESG_Risk_Level;

page

Governance vs ESG score

SELECT ROUND(AVG(Governance_Risk_Score), 2) AS Avg_Gov,
       ROUND(AVG(Total_ESG_Risk_Score), 2) AS Avg_Total
FROM SP_500_ESG_Risk_Ratings;

page

Python Code

Importing all the necessary library

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
import plotly.express as px
import warnings
warnings.filterwarnings('ignore')

Importing the CSV data

df = pd.read_csv('SP 500 ESG Risk Ratings.csv')

Plotting histogram and boxplot of Each ESG score column

esg_cols = ['Total ESG Risk score', 'Environment Risk Score', 'Governance Risk Score', 'Social Risk Score']

sns.set_style("whitegrid")  

for col in esg_cols:
    fig, axes = plt.subplots(1, 2, figsize=(12, 5))

    # Histogram with KDE
    sns.histplot(df[col], kde=True, ax=axes[0], color='skyblue')
    axes[0].set_title(f'Distribution of {col}')
    axes[0].set_xlabel(col)
    axes[0].set_ylabel('Frequency')

    # Boxplot
    sns.boxplot(y=df[col], ax=axes[1], color='lightgreen')
    axes[1].set_title(f'Boxplot of {col}')
    axes[1].set_xlabel('')
    axes[1].set_ylabel(col)

    plt.tight_layout()
    plt.show()

page page page page

Plotting distribution of ESG components in a single diagram

colors = ["#6528F7", "#00DFA2", "#0079FF", "#EF2F88"]

plt.figure(figsize=(13.6, 6))
for i, col in enumerate(esg_cols):
    sns.kdeplot(df[col], label=col, fill=True, color=colors[i])
    
plt.title("Combined Distribution of ESG Scores")
plt.xlabel("ESG Scores")
plt.ylabel("Density")
plt.legend()
plt.tight_layout()
plt.show()

page

Removing outlier using IQR

df_no_outliers = df.copy()
for col in esg_cols:
    Q1 = df[col].quantile(0.25)
    Q3 = df[col].quantile(0.75)
    IQR = Q3 - Q1
    lower = Q1 - 1.5 * IQR
    upper = Q3 + 1.5 * IQR
    df_no_outliers = df_no_outliers[(df_no_outliers[col] >= lower) & (df_no_outliers[col] <= upper)]

Plotting no. of companies by sector

sector_counts = df['Sector'].value_counts().reset_index()
sector_counts.columns = ['Sector', 'Frequency']

# Create a bar chart using Plotly Express
fig = px.bar(sector_counts, x='Frequency', y='Sector', orientation='h', 
             title='Sectors', text='Frequency',
             labels={'Frequency': 'Frequency Count', 'Sector': 'Sector'},
             color='Sector',
            template='plotly_dark')

# Customize the layout
fig.update_traces(texttemplate='%{text}', textposition='outside')
fig.update_layout(showlegend=False)

# Show the plot
fig.show()

page

Plotting ESG risk level distribution

sns.countplot(data=df, x='ESG Risk Level', order=df['ESG Risk Level'].value_counts().index)
plt.title("Distribution of ESG Risk Levels")
plt.show()

page

ESG Component Correlation Heatmap

corr = df[esg_cols].corr()
sns.heatmap(corr, annot=True, cmap="Greens")
plt.title("Correlation Heatmap of ESG Scores")
plt.show()

page

Governance Score vs. Total ESG Risk (Trend Insight)

sns.scatterplot(data=df, x='Governance Risk Score', y='Total ESG Risk score')
sns.regplot(data=df, x='Governance Risk Score', y='Total ESG Risk score', scatter=False, color='red')
plt.title("Governance vs Total ESG Risk Score")
plt.show()

page

Power BI Dashboard

Overview Page:
Overview-page

Inudstry Benchmark:

Environment-page

Company Risk Profile:

Social-page

** Dashboard:** ESG-Risk-Analysis-Dashboard

Recommendation

Reduce Exposure to High-Risk Energy Holdings Given the elevated total and environmental risk scores of companies like Occidental Petroleum and Exxon Mobil, investors should consider:

Prioritize Environmental Risk as a Leading Indicator Since environmental risk is the strongest predictor of overall ESG performance, ESG investment strategies should:

Apply Sector-Specific Risk Weighting The Energy and Materials sectors show systemic ESG vulnerabilities. Consider:

Reassess Governance and Social Oversight in Large-Cap Holdings Large companies (>15,000 employees) show lower environmental risk but higher governance and social risks. Investors should:

Integrate Real-Time Controversy Tracking into Risk Monitoring Controversies have a strong influence on ESG perception and can lead to sudden reputational and regulatory risks. Mitigation steps include:

Contact

Sahil Patra
GitHub: Github-page
Email: sahilpatra1004@gmail.com Ph no.: +91 7735367833 —

Thank you for checking out this project!