No description has been provided for this image

RepRisk Due Diligence Scores

Methodology documentation


1. Introduction
2. Calculation
3. Examples
4. Appendix
$\rightarrow$ Python code

1. Introduction

RepRisk Due Diligence Scores measure a company's compliance risk related to business conduct issues. The score calculation is based on the RepRisk Dataset, the world’s largest database of risk incidents associated with companies and projects. The RepRisk Dataset provides curated information on incidents reported by public sources and stakeholders, and intentionally excludes company self-disclosures. The Due Diligence Scores therefore provide an outside-in assessment of business conduct risks and serves as a reality check for how companies conduct their business.

The Due Diligence Scores range from zero (lowest) to 100 (highest), with higher values indicating higher risk exposure:

  • 0-24: low risk
  • 25-49: medium risk
  • 50-59: high risk
  • 60-74: very high risk
  • 75-100: extreme risk

Read RepRisk’s full methodology.


2. Calculation

The Due Diligence Scores quantify the compliance risk of a company with regard to business conduct issues, i.e., the risk of violating norms and standards.

A company's risk exposure correlates with the likelihood of such risks materializing in the form of incidents. Increased risk exposure is linked to more frequent incidents and incidents of greater magnitude.

The Due Diligence Scores therefore quantify compliance risk by considering both the observed frequency and magnitude of incidents. Their calculation incorporates these two key factors:

\begin{align} \text{RepRisk Due Diligence Score} = \text{ Average Incident Score } \times \text{Normalized Incident Count }\\ \end{align}

The first factor, the Average Incident Score, captures the average magnitude of non-compliance incidents. The second factor, the Normalized Incident Count, measures the frequency / prevalence of the incidents.

2.1. Average Incident Score

The magnitude of an incident is determined by considering its severity, reach, and recency (time of publication). A higher score is assigned to more recent incidents, incidents of greater severity, and those reported in sources with higher reach. The calculation involves the following weighted factors:

\begin{align} \text{Incident Score} &= \text{Severity weight} \times \text{Reach weight} \times \text{Time weight}\\ \end{align}


Severity weights: The impact of an incident on the environment and society grows exponentially with the assigned severity level. The severity weights therefore increase exponentially with each level (1, 10, 100).

Severity level Severity weight
3 (Very severe incident) 100
2 (Severe incident) 10
1 (Less severe incident) 1

Reach weights: Incidents reported in less credible sources are underweighted. Sources with medium and high reach (reach 2 and 3) have a higher credibility than low reach sources (reach 1). Thus, reach 1 sources are assigned a weight of 1, while reach 2 and 3 sources receive a weight of 2.​

Reach level Reach weight
3 (High reach source) 2
2 (Medium reach source) 2
1 (Limited reach source) 1

Time weights: It commonly takes at least two years for a company to significantly reduce its business conduct risk exposure, either through strategic, organizational, or managerial measures. Therefore, incidents are fully weighted in the first two years and then decay to a weight of 0 in years 2 to 4. Incidents older than four years receive a weight of 0 - i.e., they do not contribute to the Average Incident Score. (see graph below).

In [1]:
# calculate and plot time weights
import pandas as pd
import numpy as np
import plotly.express as px
import math
from IPython.display import display, HTML
import warnings
import plotly.io as pio

pio.renderers.default = "notebook_connected"
warnings.filterwarnings('ignore')

n_years = 4
n_days = 365*n_years

period1 = math.floor(n_days/2)
period2 = n_days - period1
weights2 = np.array([1]*period2)

curvature_ = 1
weights1 = np.arange(1,period1 + 1)
weights1 = weights1/weights1.max()
weights1 = ((2**weights1) - 1)**curvature_

weights = np.concatenate((weights1, weights2), axis=0)
time_weights = pd.Series(weights)

fig = px.line(x=time_weights.index, y=time_weights.iloc[::-1].values)
fig.update_layout(font=dict(color='#231F20', family='UnitWeb, UnitOT, Verdana'),
                  xaxis=dict(title="Day in four-year window"),
                  yaxis=dict(title="Time weight"),
                  template="plotly_white",
                  margin=dict(l=200, r=200),
                  height=400)
fig.show()

The Average Incident Score is calculated based on the Incident Scores:

\begin{align} \text{Average Incident Score} &= \frac{\sum_{i}\text{Incident Score}_i}{\text{Incident Count}}\\ \end{align}


In [2]:
# load risk incident data
from tools import fetch_data, incident_query, Due_Diligence_Score_Calculator

incident_data = fetch_data(incident_query)
incident_data["Incident Date"] = pd.to_datetime(incident_data["Incident Date"])

# calculate incident scores
severity_weights = {1: 1, 
                    2: 10, 
                    3: 100}
reach_weights = {1: 1, 
                 2: 2, 
                 3: 2}
tweights = (time_weights.index.max() - (pd.Timestamp("2023-01-01") - incident_data['Incident Date']).dt.days)
tweights = tweights.where(tweights.isin(time_weights.index), None)
tweights = tweights.replace(time_weights)
incident_data_sample = incident_data[tweights.notna()].copy()
incident_data_sample['time_weight'] = tweights
incident_data_sample['incident_score'] = (incident_data_sample['Severity'].replace(severity_weights)
                                         *incident_data_sample['Reach'].replace(reach_weights)
                                         *incident_data_sample['time_weight'])
cols = ["Story ID", "Company ID", "Incident Date", 
        "issue_groups", "Severity", "Reach", "time_weight", "incident_score"]
incident_data_sample[cols].sample(10)
Out[2]:
Story ID Company ID Incident Date issue_groups Severity Reach time_weight incident_score
618966 8198582 2480027 2021-11-15 CROSS_CUTTING 2 1 1.000000 10.000000
665805 8267672 66876 2022-06-03 GOVERNANCE 1 1 1.000000 1.000000
627148 8211796 2453284 2021-12-28 ENVIRONMENT;SOCIAL;CROSS_CUTTING;GOVERNANCE 1 2 1.000000 2.000000
449617 944903 109 2019-09-10 ENVIRONMENT;GOVERNANCE 2 2 0.269126 5.382525
685825 8293911 1658 2022-08-28 CROSS_CUTTING 1 2 1.000000 2.000000
639062 8230743 286 2022-02-16 CROSS_CUTTING 2 1 1.000000 10.000000
498520 2239372 107025 2020-05-27 CROSS_CUTTING;GOVERNANCE 1 2 0.624505 1.249010
561128 7825230 2263625 2021-03-18 CROSS_CUTTING;GOVERNANCE 1 2 1.000000 2.000000
544399 3305670 2106669 2020-12-22 CROSS_CUTTING;GOVERNANCE 1 1 0.981100 0.981100
458125 1071468 76089 2019-10-25 CROSS_CUTTING 2 3 0.324529 6.490580

Note: The time weights in the table apply January 1, 2023 as the score calculation date.

2.2. Normalized Incident Count

The Normalized Incident Count quantifies the frequency of incidents with which the company has been associated in the last four years. It aggregates the number of less severe (severity 1), severe (severity 2), and very severe (severity 3) incidents.

The calculation applies a normalization factor to the count of less severe incidents. This corrects for potential selection bias (e.g., due to company size or location) and downscales the severity 1 incident count if it would overly inflate the score (see section on bias correction).

\begin{align} \text{Normalized Incident Count } = &\text{Normalization Factor } \times \text{Severity 1 Incident Count} \\ &+ \text{Severity 2 Incident Count} \nonumber \\ &+ \text{Severity 3 Incident Count} \nonumber \\ \end{align}

2.3. Scaling

Since the product of the Average Incident Score and the Normalized Incident Count may take any positive value, we use an exponential cumulative distribution function to scale the score to the range $[0, 100]$.

The scaling is calibrated so that Due Diligence Scores follow the risk scale:

  • 0-24: low risk
  • 25-49: medium risk
  • 50-59: high risk
  • 60-74: very high risk
  • 75-100: extreme risk

The scaling also ensures that Due Diligence Scores reach certain risk levels at the first risk incident. E.g., a company with a very severe risk incident (severity 3) reported in a high or medium reach source (reach 3 or reach 2) is classified as high-risk:

Severity level Reach level Due Diligence Score at first incident
3 3 50 (high risk)
3 2 50 (high risk)
3 1 44 (medium risk)
2 3 33 (medium risk)
2 2 33 (medium risk)
2 1 29 (medium risk)
1 3 22 (low risk)
1 2 22 (low risk)
1 1 19 (low risk)

While the exponential scaling effectively aligns the Due Diligence Scores with the 0-100 risk scale, it causes an acceleration in the score decay. This acceleration occurs as the product of the Average Incident Score and Normalized Incident Count decreases, resulting in the scaled score decreasing at an increasing rate.

To mitigate high decay rates towards the end of the decay process and to allow for a more gradual phase-out, we implement a constraint on the decay. Specifically, we limit the score decay to a maximum of 50% per year, corresponding to a minimum half-life period of one year.

In [3]:
# exponential cumulative distribution function
def scale(series, lambda_=0.000105 * 1.0431, curvature=5.3 * 1.0431):
    return 100*((1 - np.exp(-lambda_*series))**(1/curvature))

scaling = scale(pd.Series(range(750)))
fig = px.line(x=scaling.index, y=scaling)
fig.update_layout(font=dict(color='#231F20', family='UnitWeb, UnitOT, Verdana'),
                  xaxis=dict(title="Average Incident Score x Normalized Incident Count"),
                  yaxis=dict(title="RepRisk Due Diligence Score"),
                  template="plotly_white",
                  margin=dict(l=200, r=200),
                  height=400)
fig.show()

3. Examples

Back to top

In [4]:
import plotly.graph_objects as go

companies = {"Volkswagen AG": 370,
              "Lloyds Banking Group PLC": 5159,
              "PG&E Corp (PGE)": 2988,
              "Home Depot Inc": 1010,
              "Costco": 665,
              "Campbell Soup": 393,
              "Apple Inc": 16,
              "Tesla Inc": 24952,
              "Philip Morris International Inc": 476,
              "Alphabet": 178517,
              "Jiangsu Nijiaxiang Group Co Ltd": 542719,
              "Hacienda HealthCare": 523097,
              "Ethiopian Airlines Enterprise": 76089,
              "Changchun Changsheng Life Sciences Ltd": 449828,
              "Lao Holding State Enterprise (LHSE)": 137624,
              "1Malaysia Development Berhad (1MDB)": 24948,
              "Amazon Inc": 3173,
              "Tiong Tat Printing Industry Sdn Bhd": 956145,
              "Equifax Inc": 9105,
              "Indika Energy": 6765}

# the Due_Diligence_Score_Calculator class is specified below
calculator = Due_Diligence_Score_Calculator()

colors = px.colors.qualitative.Dark24*2
fig = go.Figure()
for name, id_ in companies.items():
    color=colors.pop()
    company_incidents = incident_data[incident_data['Company ID'] == id_].copy()
    series = calculator.get_due_diligence_score(company_incidents)
    visible = True if id_ in (16, 370, 2988) else "legendonly"
    fig.add_trace(go.Scatter(x=series.index, y=series.values, name=name,
                  line=dict(color=color), legendgroup=name, visible=visible))
    
fig.update_layout(font=dict(color='#231F20', family='UnitWeb, UnitOT, Verdana'),
                  xaxis_rangeslider_visible=True,
                  legend_orientation="h",
                  legend=dict(x=0, y=0.94),
                  template="plotly_white",
                  margin=dict(l=20, r=20, t=130, b=10),
                  height=600,
                  title=dict(text='<b>Due Diligence Scores</b>',
                             y=0.998,
                             x=0,
                             xanchor='left',
                             yanchor='top'))

fig.show()

3.1. Sub-scores

Each incident is distinctly mapped to one or more characteristics such as:

  • Environmental, Social, Governance, or cross-cutting characteristics
  • 28 issues
  • over 73 topics
  • Frameworks such as:
    • SDGs
    • SASB
    • German Supply Chain Act
    • Modern Slavery Acts (UK, Australia, California)
    • SFDR

Therefore, it is possible to construct customized sub-scores based on individual or a combination of characteristics.

The example below uses Volkswagen and shows Due Diligence Scores for the All Issues, Environmental, Social, Governance, and cross-cutting characteristics.

Sub-scores are calculated based on the incidents linked to the selected characteristics. The normalization factor, however, applies to the company as a whole and is thus shared across sub-scores and the company's overall score.

In [5]:
name, company = "Volkswagen AG", 370

incidents = incident_data[incident_data['Company ID'] == company].copy()
incidents["ENVIRONMENT"] = incidents.issue_groups.str.find("ENVIRONMENT") > -1
incidents["SOCIAL"] = incidents.issue_groups.str.find("SOCIAL") > -1
incidents["GOVERNANCE"] = incidents.issue_groups.str.find("GOVERNANCE") > -1
incidents["CROSS_CUTTING"] = incidents.issue_groups.str.find("CROSS_CUTTING") > -1

colors = ["#2E91E5", "#449847", "#FBC82D", "#003755", "#CCCCCC"]

fig = go.Figure()
series_all = calculator.get_due_diligence_score(incidents)

for group in ["CROSS_CUTTING", "GOVERNANCE", "SOCIAL", "ENVIRONMENT"]:
    series = calculator.get_due_diligence_score(incidents, subset_col=group)
    fig.add_trace(go.Scatter(x=series.index, y=series.values, name=group,
                  line=dict(color=colors.pop())))
fig.add_trace(go.Scatter(x=series_all.index, y=series_all.values, name="All Issues",
                  line=dict(color=colors.pop(), width=1, dash='dot')))

fig.update_layout(font=dict(color='#231F20', family='UnitWeb, UnitOT, Verdana'),
                  xaxis_rangeslider_visible=True,
                  legend_orientation="h",
                  legend=dict(x=0, y=1, traceorder="reversed"),
                  template="plotly_white",
                  margin=dict(l=20, r=20, t=60, b=10),
                  autosize=True,
                  title=dict(text='<b>' + name + ': Due Diligence Sub-Scores</b>',
                             y=0.99,
                             x=0,
                             xanchor='left',
                             yanchor='top'))
fig.show()

4. Appendix

Back to top

Due Diligence Scores are calculated based on incidents that have been publicly reported. Whether an incident is made public depends on various factors. For example, larger companies receive more attention and media coverage than smaller ones. In addition, companies in countries with high business conduct awareness and countries where freedom of the press is guaranteed are more likely to be scrutinized. Therefore, some incidents are more likely to be reported, e.g., if they are associated with large companies or companies based in certain countries.

This difference in reporting likelihood can potentially lead to selection bias, since we solely rely on publicly reported incidents and lack information about unreported ones. To address this potential bias, Due Diligence Scores undergo a normalization factor to the count of less severe incidents. This downscales the severity 1 incident count if it would overly inflate the score.

The downscaling depends on how many less severe incidents a company has in relation to its severe incidents (low severity excess). The greater the low severity excess, the greater the downscaling. This allows the Due Diligence Scores to reliably identify high-risk companies: the score identifies companies as high-risk if they have a significant and credible risk exposure due to associations with severe incidents. Companies that are only associated with less severe incidents, on the other hand, are not classified as high-risk.

Measures to reduce bias involve estimations, which carry a potential risk of overcorrection. By specifically focusing on the severity 1 incident count – the component with the greatest risk of bias - the Due Diligence Score effectively correct for bias without overcorrecting.

The increased risk of bias associated with severity 1 incidents results from the dependence of reporting likelihood on the severity of the incident. The more severe the incidents, the more likely they are to be reported, as they have a greater impact on society and the environment and generate greater public interest. This discrepancy in reporting likelihood results in a greater risk of bias for less severe incidents compared to severe ones.

4.1. Low severity excess

Due Diligence Scores draw on low severity excess as a measure of the media and stakeholder attention a company receives, e.g., due to its size, location or other company-specific factors. We calculate a company's low severity excess as the difference between its count of less severe incidents (severity 1) and severe incidents (severity 2 and 3). The incidents are time-weighted (analogous to the Average Incident Score).

Companies that receive a high level of attention have a higher probability that their incidents will be reported. They therefore tend to have more reported incidents, and in particular more less severe incidents in relation to severe incidents, leading to a high low severity excess.

As mentioned above, the risk of bias is greater for less severe incidents. Severe incidents are more likely to be reported since they have a greater impact on society and the environment and generate greater public interest. The impact of attention is therefore more pronounced for less severe than for severe incidents. This means that as attention increases, the number of less severe and severe incidents tends to diverge.

To validate low severity excess as a measure of media and stakeholder attention, we empirically assess its relationship with three factors that can be expected to correlate with the level of attention:

  1. the company size;
    • Low severity excess increases with size as larger companies receive more attention from media and stakeholders.

  2. the World Press Freedom Index of the company's headquarters;
    • Low severity excess increases with the World Press Freedom Index as companies in countries where freedom of the media is guaranteed are more scrutinized by media and stakeholders.

  3. the Human Development Index of the company's headquarters (as a proxy for country-specific business conduct risk awareness).
    • Low severity excess increases with the Human Development Index as companies in countries with high business conduct risk awareness are more likely to be scrutinized by media and stakeholders.

The three regressions below show that these correlations are observed in the data, validating low severity excess as an indicator of media and stakeholder attention to issues. All three correlations are statistically significant with a p-value of $< 0.001$.

In [6]:
import plotly.graph_objects as go
import statsmodels.api as sm

incident_data = incident_data[incident_data["Unsharp Incident"] == 0].copy()
tweights = (time_weights.index.max() - (pd.Timestamp("2022-12-31") - incident_data['Incident Date']).dt.days)
tweights = tweights.where(tweights.isin(time_weights.index), None)
tweights = tweights.replace(time_weights)
incident_data_subset = incident_data[tweights.notna()].copy()
incident_data_subset["time_weight"] = tweights
weighted_counts = incident_data_subset.groupby(["Company ID", "Severity"])["time_weight"].sum().unstack(1).fillna(0)

s1_excess = (weighted_counts[1] - weighted_counts[2] - weighted_counts[3])
s1_excess.name = "low_severity_excess"
df = pd.DataFrame(s1_excess)
df["severity_1_count"] = weighted_counts[1]
df = df[df["low_severity_excess"]>= 1]

df["log(Low severity excess)"] = np.log(df["low_severity_excess"])
df["log(Severity 1 incident count)"] = np.log(df["severity_1_count"])

df_ = df.join(pd.read_csv("correlation_data/2022_correlation_data.csv"
                         ).set_index("company")[["HDI", "WPF", "company_size_category"]]).copy()
df_.company_size_category = df_.company_size_category.where(df_.company_size_category >= 1, None)
df_ = df_[["log(Low severity excess)", "HDI", "WPF", "company_size_category"]]

factors = {"company_size_category": "company size category",
           "WPF": "World Press Freedom Index",
           "HDI": "Human Development Index"}
df_ = df_.rename(columns=factors)
for column, name in factors.items():
    plot_data = df_[["log(Low severity excess)", name]]
    fig = go.Figure()
    fig.add_trace(go.Histogram(histfunc="avg", x=plot_data["log(Low severity excess)"], 
                               y=plot_data[name], name=name, nbinsx=6, autobinx=False))
    fig.update_layout(font=dict(color='#231F20', family='UnitWeb, UnitOT, Verdana'),
                      xaxis=dict(title="log(Low severity excess)"), yaxis=dict(title="Mean " + name),
                      yaxis_type="log",  margin=dict(l=300, r=300, t=10, b=10), height=300, template="plotly_white")
    fig.show()
    
    df_model = plot_data.dropna()
    y = df_model["log(Low severity excess)"]
    X = df_model[[name]]
    model = sm.OLS(y, X)
    results = model.fit()
    res = results.summary().as_html()
    display(HTML(res[:res.find('Notes')-10].replace('Regression Results', 
                                                    'Regression Results: ' + name + ' ~ ' + 'log(Low severity excess)')))
OLS Regression Results: company size category ~ log(Low severity excess)
Dep. Variable: log(Low severity excess) R-squared (uncentered): 0.451
Model: OLS Adj. R-squared (uncentered): 0.451
Method: Least Squares F-statistic: 2.351e+04
Date: Thu, 11 Dec 2025 Prob (F-statistic): 0.00
Time: 15:18:35 Log-Likelihood: -31379.
No. Observations: 28603 AIC: 6.276e+04
Df Residuals: 28602 BIC: 6.277e+04
Df Model: 1
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
company size category 0.1567 0.001 153.337 0.000 0.155 0.159
Omnibus: 8726.541 Durbin-Watson: 1.663
Prob(Omnibus): 0.000 Jarque-Bera (JB): 28720.506
Skew: 1.552 Prob(JB): 0.00
Kurtosis: 6.803 Cond. No. 1.00
OLS Regression Results: World Press Freedom Index ~ log(Low severity excess)
Dep. Variable: log(Low severity excess) R-squared (uncentered): 0.242
Model: OLS Adj. R-squared (uncentered): 0.242
Method: Least Squares F-statistic: 2.032e+04
Date: Thu, 11 Dec 2025 Prob (F-statistic): 0.00
Time: 15:18:35 Log-Likelihood: -62543.
No. Observations: 63668 AIC: 1.251e+05
Df Residuals: 63667 BIC: 1.251e+05
Df Model: 1
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
World Press Freedom Index 0.0058 4.04e-05 142.532 0.000 0.006 0.006
Omnibus: 32773.784 Durbin-Watson: 1.357
Prob(Omnibus): 0.000 Jarque-Bera (JB): 231109.959
Skew: 2.420 Prob(JB): 0.00
Kurtosis: 10.980 Cond. No. 1.00
OLS Regression Results: Human Development Index ~ log(Low severity excess)
Dep. Variable: log(Low severity excess) R-squared (uncentered): 0.241
Model: OLS Adj. R-squared (uncentered): 0.241
Method: Least Squares F-statistic: 2.019e+04
Date: Thu, 11 Dec 2025 Prob (F-statistic): 0.00
Time: 15:18:35 Log-Likelihood: -62328.
No. Observations: 63416 AIC: 1.247e+05
Df Residuals: 63415 BIC: 1.247e+05
Df Model: 1
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
Human Development Index 0.4272 0.003 142.086 0.000 0.421 0.433
Omnibus: 33828.397 Durbin-Watson: 1.330
Prob(Omnibus): 0.000 Jarque-Bera (JB): 251237.040
Skew: 2.512 Prob(JB): 0.00
Kurtosis: 11.358 Cond. No. 1.00

Note:

  • The figures are based on all companies in the RepRisk Dataset that had a low severity excess of 1 or larger as of December 31, 2022 ($N=64'102$)
  • The company size categories [1, 8] are defined as follows:
Size category Market capitalization [USD] Revenue [USD] Number of employees
8 ≥ 100 billion
7 ≥ 5 billion or ≥ 5 billion or ≥ 10'000
6 ≥ 1 billion or ≥ 1 billion or ≥ 5'000
5 ≥ 500 billion or ≥ 500 million or ≥ 3'000
4 ≥ 100 million or ≥ 100 million or ≥ 1'000
3 ≥ 10 million or ≥ 10 million or ≥ 150
2 ≥ 1 million or ≥ 1 million or ≥ 15
1 else
  • The World Press Freedom Index ranges [0, 100] (the higher the values, the greater the freedom of the press)
  • The Human Development Index ranges from [0, 1] (the higher the values, the higher the human development)

4.2. Estimation of normalization factors

To determine the amount of downscaling, we estimate the impact of low severity excess on the severity 1 incident count. This indicates the extent of bias caused by attention from media and stakeholders. Based on this estimate, we derive the normalization parameter (as a function of low severity excess) to correct for the bias.

In [7]:
import plotly.express as px
from linearmodels.panel import PanelOLS

df = pd.read_csv("correlation_data/5ypaneldata_per240101.zip")
df.set_index(["company", "year"], inplace=True)
mod = PanelOLS.from_formula("logsev1count ~ constant+loglowsevexcess+EntityEffects+TimeEffects", df)
result = mod.fit(cov_type='clustered', cluster_entity=True, cluster_time=True)
result = result.summary.as_html()
display(HTML(result[:result.find('F-test')-6].replace('PanelOLS Estimation Summary', 
                                                'PanelOLS Regression: log(Sev-1 incident count) ~ log(Low severity excess) + EntityFE + TimeFE')))
PanelOLS Regression: log(Sev-1 incident count) ~ log(Low severity excess) + EntityFE + TimeFE
Dep. Variable: logsev1count R-squared: 0.8732
Estimator: PanelOLS R-squared (Between): 0.9154
No. Observations: 276979 R-squared (Within): 0.8766
Date: Thu, Dec 11 2025 R-squared (Overall): 0.9254
Time: 15:18:35 Log-likelihood 3.091e+05
Cov. Estimator: Clustered
F-statistic: 9.646e+05
Entities: 136945 P-value 0.0000
Avg Obs: 2.0226 Distribution: F(1,140029)
Min Obs: 1.0000
Max Obs: 5.0000 F-statistic (robust): 9339.4
P-value 0.0000
Time periods: 5 Distribution: F(1,140029)
Avg Obs: 5.54e+04
Min Obs: 3.708e+04
Max Obs: 7.115e+04
Parameter Estimates
Parameter Std. Err. T-stat P-value Lower CI Upper CI
constant 0.0764 0.0033 23.027 0.0000 0.0699 0.0829
loglowsevexcess 0.9073 0.0094 96.641 0.0000 0.8889 0.9257

Note: The displayed panel OLS regression results are based on all companies in the RepRisk Dataset that had a low severity excess of 1 or larger between 2020 and 2024 (Number of entities in panel: $N=136'945$). For each company entity we have between one and five time periods on our panel dataset (Number of time periods: $t\in[1,5]$). In the panel OLS regression, we use both entity and time fixed effects. For the calculation of Due Diligence Scores, we regularly re-estimate the normalization factors based on current data.
Based on the panel OLS regression results, the normalization factors are calculated as follows:

\begin{align} \text{Normalization factor(Low severity excess)} &= \frac{\text{Severity 1 count estimate(Low severity excess = 1)}}{\text{Severity 1 count estimate(Low severity excess)}}\\ \end{align}

The factor follows the function above if the low severity excess is larger or equal to 1. Otherwise, a factor of 1 applies.

In [8]:
def get_normalization_factor(low_severity_excess):
    if low_severity_excess >= 1:
        return np.exp(0.9073*(np.log(1/low_severity_excess)))
    else:
        return 1

norm_factors = pd.Series(np.arange(1, 20, 0.2), index=np.arange(1, 20, 0.2)).apply(get_normalization_factor)

fig = px.line(x=norm_factors.index, y=norm_factors)
fig.update_layout(font=dict(color='#231F20', family='UnitWeb, UnitOT, Verdana'),
                  xaxis=dict(title="Low severity excess"),
                  yaxis=dict(title="Normalization factor"),
                  template="plotly_white",
                  margin=dict(l=200, r=200),
                  height=400)
fig.show()

A low severity excess of 1 is used as a baseline. The normalization parameter quantifies the bias relative to this baseline, with a lower parameter value indicating a greater bias. It signifies how much the company's low severity excess is expected to inflate its severity 1 incident count beyond what would be expected with only a low severity excess of 1. To address this bias through downscaling, we compute the normalization as the reciprocal of the estimated bias. Due to the log-log regression specification, the normalization parameter is determined through division rather than subtraction.


Copyright, User Agreement, and other general information related to this website

Copyright 2026 RepRisk AG. All rights reserved. The information provided on this website is not intended to be relied upon as, nor to be a substitute for, specific financial, legal, or other professional advice. RepRisk expressly disclaims and will not accept any responsibility for loss or damages to any individual or legal entity with regard to any action or inaction related to or connected with any material on this website.

RepRisk AG retains copyright and all originators’ rights to the content on this website. The material on it may not be sold, reproduced, republished, distributed, or transmitted, in whole or in part, in any form or manner, without the express written consent of RepRisk AG. Any unauthorized use is prohibited. Use of this website constitutes your agreement not to sell, reproduce, republish, redistribute, or retransmit the contents, opinions, conclusions, or information contained on this website without first obtaining express permission from RepRisk AG.

The information herein (other than disclosed information relating to RepRisk AG) was obtained from various public sources. RepRisk AG does not guarantee its accuracy. In particular, materials prepared by RepRisk AG research analysts are based on public information. Facts and views presented in this material have not been reviewed by and may not reflect information known to professionals in other business areas of RepRisk AG.

This website may contain links to third-party websites. RepRisk AG is not responsible for the content of any third-party website, or any linked content contained in a third-party website. Content contained on such third-party websites is not part of this website and is not incorporated by reference into this website. The inclusion of a link on this website does not imply the endorsement by or any affiliation with RepRisk AG. Access to any third-party website is at your own risk, and you should always review the terms and privacy policies at third-party websites before submitting any personal information to them. RepRisk AG is not responsible for such terms and privacy policies and expressly disclaims any liability for them. 

Neither RepRisk AG nor any officer or employee of RepRisk AG accepts any liability whatsoever for any direct, indirect, or consequential damages or losses arising from any use of this website or its contents. 

The information on this site is provided on a discretionary basis. RepRisk AG makes no warranty that access to the site will be error free or continuously available. It is possible that defects and errors occur. RepRisk AG reserves the right to discontinue operating this site or to restrict access at any time. 

In no event, including (without limitation) negligence, will RepRisk AG be liable for any loss or damage of any kind, including (without limitation) any direct, indirect, or consequential damages, even if expressly advised of the possibility of such damages, arising out of or in connection with the access of, use of or link to other sites from this website. 

Should the use of this website result in the creation of any relationship under the law between the user and RepRisk AG, any such relationship and any disputes arising in connection therewith will be subject to Swiss law, and the exclusive forum for any disputes will be Zurich, Switzerland. 

This disclaimer is modified from time to time. Make sure that you check these terms every time you access this website. 

© RepRisk AG

In [9]:
%%html
<style id=hide>div.input{display:none;}</style>
In [10]:
%%javascript
document.title='RepRisk | Due Diligence Scores'

window.onload=function(){
    var mobile = (/iphone|ipod|android|blackberry|mini|windows\sce|palm/i.test(navigator.userAgent.toLowerCase()));
    if (mobile) {
        alert("For an improved user experience, we recommend that you switch to a desktop device.");              
    } else {

    }
  }