Eudra-Vigilance Data Project
By Craig Paardekooper(September 13th 2024)

WHAT IS EUDRA-VIGILANCE ?
Eudra-vigilance is the European equivalent of VAERS – it is a database of adverse
reaction reports for all vaccines, substances and products used in the European
Union (includes Astazeneca data) since 2001.
URL : https://www.adrreports.eu/en/disclaimer.html

PURPOSE OF THE EUDRA-VIGILANCE DATA PROJECT
The purpose of this project is to provide public access to Eudra-vigilance data
for analysis of drug safety. The resulting CSV dataset is the largest publicly
available dataset of its kind in the world, consisting of input from 4,497,850
unique people, covering 19,265 unique symptoms relating to 4122 unique drug brandnames, and 4387 unique ingredient lists, some being variations for the same drug.

SINGLE DRUG EFFECTS
The dataset consists of 7,044,225 individuals who submitted reports.
However, I only look at those reports where a single drug was administered to anindividual .There are 5,333,575 reports where only 1 drug is administered.
And I only look at reports where the name of the drug is provided. There are4,497,850 reports where the name of the drug is provided.
Finally, I applied a minimal sample size of 100 symptom records per drug, andexcluded all drugs with fewer records. This was so I could draw reliable
statistical conclusions.
The final dataset has –1. 4,486,467 individual people records
2. 14,987,664 drug-symptom associations –3. 19,247 unique symptoms
4. 1,504 unique drug brand names, and
5. 3,163 unique ingredient lists.
6. Each drug is represented by a name consisting of a single word
This dataset will empower analysts to rank many drugs by the incidence of any
adverse symptom – and aide informed choice.
Several practical examples will be provided to demonstrate the reliability ofthis dataset in identifying drugs with high adverse outcomes.

Downloads
Original set of 4088 csv files - here
Data files concatenated into one big file - here
One big file after data has been cleaned and organised – here
A fourth dataset is available. It is a pivot table showing the safety signals
for any of 19,245 symptoms for 1504 different drugs. It also shows every drug
sorted in order of its safety signal for any chosen symptom. This dataset has asize of only 4Mb (zipped).
Download

SearchA search engine has been created that ranks drugs by the incidence of any chosen
symptom or provides a list of all symptoms for any drug.
Search Dataset - here

AUTHENTICITY OF EACH RECORDICSR means “Individual Case Safety Report” – showing that each row is anindividual person. There are 4,486,467 unique case reports in the final
dataset.
You can view the report hosted on the EMA website, by putting the ID number
into the URL below.
https://dap.ema.europa.eu/xmlpserver/PHV%20DAP/Reports/ICSR.xdo?_xpf=&_xt=form&
SR_ID=10011128660&_xpt=1&_xf=pdf

This is the URL for the report with ID 10011128660. It is a pdf hosted on theEuropean Medical Association website.
This shows that the downloaded data is not made up. Rather, each row of data
has a report that you can verify using the link provided.
Each downloaded report looks like this –WHO INPUT THE DATA ?

In the original dataset consisting of 7,044,225 individual reports, there is a
QUALIF column that provides the credentials of the inputers.

So most reporters were healthcare professionals

NOTE : 63% of reports in Eudra were submitted by healthcare professionals, anda further 35% of reports were submitted by non-healthcare professionals - most
likely admin staff in the employ of hospitals, private medical practices, orcare services. So this data is to be taken seriously.

This is the date when the report was received. Reports cover a time span from
5th July 2002 till 1st June 2024, a period of 22 years.
The spread of dates is interesting –The graph appears to split into two streams, alower one and an upper one. The lower one ismade up of weekend dates when input was less,and the upper is made of weekday dates, when
input was greater.
I have created a spreadsheet of the frequency ofreports for each date from 2022 till 2024. You
can download the spreadsheet here.
Notice that the high frequency of reports comesin clusters of 5 days. This is because data
inputting mainly occurs during weekdays rather
than at weekends.
This is further evidence that data is being
input by professionals working in the healthindustry, rather than by ordinary members of the
public, who would tend to input during out-ofwork hours or at the weekend.

STEPS FOR THE CREATION OF THE DATASETAll the data is publicly available, but the following steps automate the gatheringof it and the organising of it into useful fields. I have completed all the steps
for you. I am describing the steps in case you wish to repeat / confirm them foryourself.

Step 1 : Data Download
Wouter Aukema (http://www.aukema.org/) wrote code for automatically reading anddownloading the data from Eudra-Vigilance. The download takes about 4 hours using
high speed internet (30 mb / sec). The python code used for downloading isavailable here - python . The downloaded data consisted of 4088 csv files.
If you are not a Python programmer, you can skip downloading all the files
yourself, since I have already done that and made all 4088 files available as adownloadable zip file here - Dropbox (complete unformatted tables)

Step 2 : Reading the Files with Python
Once I had the files downloaded, the next stage was to read them. They were all.csv files, however the files did not all use the same encoding. Some csv files
used “ISO-8859-1” encoding, other files used “UTF-8” encoding, others used“windows 1292” encoding, and for some files the encoding was unknown.
To find out which ones I could open, I looped through the files, trying to readeach one with one encoding, then another – here - file reading.
In many cases the files would not open in Python, so I had to open each one
manually by importing it into an excel spreadsheet, then saving the sheet as acsv. The csv files were then read into Python and concatenated into one large
file. The method of concatenation is shown here - manual conversion
You can skip these step too, if you wish, since I have done it for you.
Here is the code I used find out which encoding each file had -Otherwise I used this process for detecting encoding –As you can see, this code told me which files could be opened using a specificencoding, and which files could not. In addition, it concatenated the files that
could be opened into one big file.
Repeating this with other encodings eventually led to the creation of one big
file out of the many.

STEP 3 Concatenating the files into one massive file
Concatenation of the files was performed when reading the files. You can see thatas each file is read, it is appended to a framelist, and this is eventually
written to a csv file - file reading.

However, I could also do the concatenation separately like this I create a master dataframe

Then I loop through, reading each file into a dataframe of its own, andconcatenating them to the master dataframe.

The final master dataframe is then saved to a csv fileStep 4 : Looking at the Data Fields

Here are all the fields in the original downloaded csvs.

Here is a list of the columns
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•

Unnamed: 0
EU Local Number
Report TypeEV Gateway Receipt Date
Primary Source Qualification
Primary Source Country for Regulatory Purposes
Literature Reference
Patient Age Group
Patient Age Group (as per reporter)
Parent Child Report
Patient Sex
Reaction List PT (Duration – Outcome - Seriousness Criteria)
Suspect/interacting Drug List (Drug Char - Indication PT - Action taken [Duration - Dose - Route])
Concomitant/Not Administered Drug List (Drug Char - Indication PT - Action
taken - [Duration - Dose - Route])
ICSR Form
Reaction List PT (Duration – Outcome - Seriousness Criteria)

Step 5 : Identifying Null Values

As you can see, every other row contained null values.

Counting Not-Nulls

There are 10,882,388 rows in the initial dataset.

So, the number of records in each column where the valueby –is not null is given

Step 6 : Removing Null Values

The EU Local Number is the report identification number. When we drop all NaN
values from this column, we get

The counts

for this column now match that for the other columns

Merging the 4 REACTION Columns

So, there are 4 columns where Reaction is specified, which contain thefollowing numbers of records ••••208771647471
13819135277572

Totalling 8,794,672
These 4 separate columns should be merged into a single column.
Before we can work with this data, we must merge the 4 reaction columns into asingle column called REACTION, and then drop the 4 original reaction columns.
Here, I created a new dataframe called frame1, in case there were any issues
with the merge, I did not want it to effect the original frame.

I confirmed that there were no longer any nulls in any of the columns

All columns were now of the same length

Step 7 : Renaming Columns

To facilitate coding, I renamed these columns with easier names.

There were no issues with this stage, so I updated the original frame
frame = frame1.copy()****
The concatenated data-frame is available as a download from Dropbox here.

Step 8 : Removing Duplicates

So we have 8,794,672 reports. I wanted to see if any records have been
duplicated, which might happen when I was concatenating so many separate files.
Duplicates may have arisen during the process of combining the 4088 csv files,
if these csv files had any overlap.
In order to remove duplicates I used –Each individual person has a unique ID. There are 7,044,225 unique IDs in thedataset.

So 7,044,225 reports remained after duplicates were removed.

Step 9 : Dropping Unnecessary Columns
My aim in this analysis is to rank all drugs according to the incidence of theireffects. So to do this analysis, I only needed the ID column, DRUG column andthe REACTION column. I drop all the other columns. This is done to save memory
and avoid the computer crashing.
frame = frame[[frame.columns[1], frame.columns[10],frame.columns[13]]].copy()

Step 10 : Filtering for Single-drug Administrations
All rows where the DRUG column contains multiple drugs are removed. This is done
to enable clearer identification of relationships between symptom and drug.
frame = frame[ frame['DRUG'].str.contains('<br><br>')==False ]There are 5,333,575 reports where only 1 drug is administered

Step 11 : Splitting the DRUGS column into INGREDIENTS and DRUGSThe original DRUG column contains the drug name and its ingredients, so I split
the DRUG column into 2 columns – DRUG and INGREDIENTS
frame['NAME'] = frame['DRUG'].str.split('\[', expand = True)[0]frame['INGREDIENTS'] = frame['DRUG'].str.split('\[', expand = True)[1]Step 12 : Splitting the INGREDIENTS column into PATHOLOGY and INGREDIENTSThen the INGREDIENTS column is further split into 2 columns – PATHOLOGY and
INGREDIENTS
frame['INGREDIENT-LIST']=frame['INGREDIENTS'].str.split('\]', expand = True)[0]frame['PATHOLOGY'] = frame['INGREDIENTS'].str.split('\]', expand = True)[1]

The initial columns are then dropped to eliminate duplication.
frame = frame.drop(['DRUG'], axis=1)
frame = df.frame(['INGREDIENTS'], axis=1)

Step 13 : Putting each SYMPTOM in a separate ROW
The REACTION column contains several symptoms all on one line, which makes it
difficult to count the symptom frequencies. So I created a new row for each
symptom –Step 14 : Splitting the REACTION column into SYMPTOM and SEVERITY
Each symptom record in the REACTION column also contains information on theoutcome. So I split the REACTION column into 2 columns – SYMPTOM and SEVERITY
frame['SYMPTOM'] = frame['REACTION'].str.split('\(', expand = True)[0]frame['SEVERITY'] = frame['REACTION'].str.split('\(', expand = True)[1]
The initial REACTION column is then dropped to eliminate duplication
Frame = frame.drop(['REACTION'], axis=1)
Finally, the columns are tidied up by removing unnecessary brackets frame['PATHOLOGY'] = frame['PATHOLOGY'].str.replace('\(S -',"")

frame['SEVERITY'] = frame['SEVERITY'].str.replace('\),',"")
frame['SEVERITY'] = frame['SEVERITY'].str.replace('\)',"")

Before proceeding I saved the existing frame under a new name Eudra. Doing thisintermittently is a way of saving preceding work in case proceding steps haveissues. I also saved frame as a csv, so I would not have to redo all steps eachtime I opened the project but could simply load the current csv.
Eudra = frame.copy()

Step 15 : Removing Rows where DRUG name is null
The DRUG column is null for some records, even though the INGREDIENTS column
shows the ingredients. Consequently, if we are looking at DRUG-SYMPTOM
associations, then the rows with no drug name should be removed first.

Step 16 : Cleaning the DRUG Column
The DRUGS column contain the name of the drug together with additional punctuationand other info such as dosage. These variations must be combined if the same drugname occurs in each variation.

Since almost all of the drug names are the first word in the DRUG column, thenI could remove all the superfluous information by selecting the first word as
the drug name.
I used a loop, rather than trying to do this with a single line of code such as–

Instead I used this loop. The loop uses much less memory

I also removed any commas

Step 17 : Tidying up SYMPTOMS Column
Here I am tidying up the SYMPTOM column by removing unwanted spaces and text,
and converting all to lower case.

Step 18 : Tidying up PATHOLOGY Column
I also tidied up the PATHOLOGY column by removing unwanted text after thehyphen.
I also wanted to remove null values, but did not want to remove entire rows
with null values, since this would delete drug-symptom associations in theother columns, so I used fillna() instead of dropna()

I looped through the column because simply using split() on the entire column
at once used too much memory.

Step 19 : Splitting the SEVERITY Column into DURATION, EFFICACY and SAFETY
I decided to split this column into 3 separate columns – DURATION, EFFICACY and
SAFETY.
EFFICACY indicated whether the recipient of the drug had full or partial or norecovery.
SAFETY indicated whether the symptom was life-threatening, disabling, resulted
in hospitalization, resulted in death, resulted in another medically importantcondition, or a congenital anomaly.

The original SEVERITY column was then dropped to eliminate duplication –Statistical Restrictions
Some of these drugs had very few symptom records. Small samples lead toinaccurate statistic, so I decided to exclude all drugs with less than 100
symptom records in total.
A sample size of 30 is fairly common across statistics as the minimum forapplying the central limit theorem.6 The higher your sample size, themore likely the sample will be representative of your population set.
https://www.investopedia.com/terms/c/central_limit_theorem.asp
100 was chosen because there is an average of 3.34 symptoms per person report,
and I want to base calculations on a minimum of 30 reports, which equates to aminimum of 100 symptom records for each drug.
After applying this restriction, the number of drugs remaining in the dataset
was 1504.

The Resulting Dataset
The resulting dataset is for DRUG-SYMPTOM associations.
It is called – drugversion.csv
The final dataset after removal of records where there was no drug name, has –1. 4,486,467 individual people records
2. 14,987,664 drug-symptom associations –3. 19,247 unique symptoms
4. 1,504 unique drug brand names, and
5. 3,163 unique ingredient lists.
Note : Each row is NOT a unique person. Rather it is a drug-symptom association.
The ID column indicates the person. Each person takes a single drug. But that
drug can have many symptoms and hence many rows. Each symptom has a different
duration (DURATION), recovery rate (EFFICACY) and severity (SAFETY).

Files for Download

1. The 4088 original csv files are found in a master folder called - “eudravigilance3”, with a size of 6.63 Gb uncompressed, and 690 Mb compressed.
Download (original 4088 files)

2. The 4088 files combined into a single file called – “total-08-06-2024” of size
4.78
Gb
uncompressed,butcompressed
is
318
Mb.
Download (all columns - concatenated)

3. The dataset prepared and organized for analysis – “1504drugversion.csv”
Download (only columns for drug-reaction analysis – one symptom per row)

4. A fourth dataset is available. It is a pivot table showing the safety signals
for any of 19,245 symptoms for 1504 different drugs. It also shows every drug
sorted in order of its safety signal for any chosen symptom. This dataset has asize of only 4Mb.
DownloadEXPLORING THE DATA – OTHER COLUMNS IN THE ORIGINAL DATASET

Who submitted these reports ?

So most reporters were healthcare professionals

NOTE : 63% of reports in Eudra were submitted by healthcare professionals, anda further 35% of reports were submitted by non-healthcare professionals - most
likely admin staff in the employ of hospitals, private medical practices, orcare services. So this data is to be taken seriously.

The DATE Column

This is the date when the report was received. Reports cover a time span from
5th July 2002 till 1st June 2024, a period of 22 years.
The spread of dates is interesting –As you can see, there is a gradual rise in number of reports from 2002 to 2024.
There are also some sharp increases – in 2008 (Swine Flu Jab) and in 2021
(Covid Jab).
The incidence jumps up suddenly. It reached a peak on 27th March 2021
(Passover). It remains high for 1 whole year, then starts to drop in March 2022
By December 2022 it has returned to 2020 level. Both the abrupt beginning andabrupt end do not seem very virus-like.

The graph appears to split into two streams, alower one and an upper one. The lower one ismade up of weekend dates when input was less,and the upper is made of weekday dates, when
input was greater. Notice that weekend input
also has a raised peak.
I have created a spreadsheet of the frequency ofreports for each date from 2022 till 2024. You
can download the spreadsheet here.
Notice that the high frequency of reports comesin clusters of 5 days. This is because data
inputting mainly occurs during weekdays rather
than at weekends.
This is further evidence that data is being
input by professionals working in the healthindustry, rather than by ordinary members of the
public, who would tend to input during out-ofwork hours or at the weekend.

There is a surge in reports soon after the rollout of the Covid Jab. The surge
is abrupt – rising to 2 x the 2020 rate of reports in a single month. andreaching a peak on March 27th. Then it remains high until March 2022. Afterthat it begins to descend at a slower rate.
There is no surge evident during the 2020 “pandemic” period !! This suggeststhat the reports relate to adverse effects of the jab rather than adverse
effects that preceded the jab.
Do viruses behave like this?
The magnitude of the explosion is about 2 times higher than the level
immediately preceding it in 2020.

The COUNTRY Column

The data is equally split between the European Economic Area, and the NonEuropean Economic Area.
It will be interesting to see how western Europe differs from eastern Europe.

The AGE Column

These numbers of records are large, so an analysis of childhood effects ispossible.

The REP-AGE Column

The REP-AGE column provides slightly different categories –It will be interesting to look at effects on foetus and neonates.

The PARENT-REPORT Column

This is where parents submit a report on behalf of a child. There are 135586
such reports. Since these reports relate to children, this will be a valuable
dataset for analysing effects on children.

The GENDER Column

Adverse effects are reported more frequently for females. Does this apply for
all drugs, or only for the Covid jab?
The ratio of female to male is approximately 1 : 1.5, or 2 : 3. It will beinteresting to see if this ratio varies for different drugs.

The DRUG Column

This column lists the drugs suspected of causing the adverse reactions. In mostcases only a single drug is listed.
••

Number of reports with a single drug listed =Number of reports with multiple drugs listed =5,333,575
1,710,650

=
=

75%
25%

When multiple drugs are administered, it is harder to attribute adverse effects
to a particular drug. For this reason, I will analyse effects from single drug
administration first.
Cases of multiple drug administration are mostly multiple doses of the Covid
jab. It will be interesting to analyse this to see if there are dose dependent
effects.

The CONCOM Column

This is similar to the DRUGS column, except it is for concomitant drugs taken,
rather than for the suspected drug. These are drugs that are administeredconcomitantly with the suspected drug. Each drug entry also lists its PATHOLOGYTREATED, INGREDIENTS, DURATION and DOSE AMOUNT. These will have to be split out
into separate columns, just as is needed for the DRUG column.
Concomitant drugs may suggest 1. co-morbidities
2. additional drugs used to overcome the adverse effects of the suspected
medicine.
3. Additional drugs used to compliment the suspected medicine
As with the DRUG column, reports with no concomitant drugs make for a clearer
attribution of effects to the suspected drug. Such reports can be identified
by “Not reported” or “NOT AVAILABLE”.

The most common concomitant drugs are “anti-retro-virals”. During the Covid“pandemic” anti-retro-virals were heavily prescribed as an anti-viral treatment
for early onset of “Covid”. This included •••REMDESIVIRPAXLOVID (Ritonavir)
TAMIFLU (Oseltamivir)

It is highly controversial why these drugs were used, since they have sideeffects that are very serious including kidney damage, liver damage and bonedamage. It is unclear why Tenofovir was being administered…

The ICSR Column

ICSR means “Individual Case Safety Report” – showing that each row is anindividual person. There are 7,044,225 unique case reports in the dataset.
The ICSR column lists the URL for each report. For example –https://dap.ema.europa.eu/xmlpserver/PHV%20DAP/Reports/ICSR.xdo?_xpf=&_xt=form&
SR_ID=10011128660&_xpt=1&_xf=pdf

This is the URL for the report with ID 10011128660. It is a pdf hosted on theEuropean Medical Association website.
This shows that the downloaded data is not made up. Rather, each row of data
has a report that you can verify using the link provided.
Each downloaded report looks like this –Comparing Cancer Drugs - an example of drug analysis

I used the Version 2 dataset to determine the safety and efficacy of 152 cancer
drugs.

Safety was measured by the number of associations with•••

A fatal outcome
A hospital outcome
A life threatening event

each expressed as a percentage of the total number of associations

Efficacy was measured by the number of associations with•••

An outcome of complete recovery
An outcome of improvement
An outcome of no recovery

each expressed as a percentage of the total number of associations

In addition I looked at the incidence of symptoms related to well-being during
treatment –
•
•
•
•
•
•
•
•
•

Pain
NauseaFatigue
Diarrhea
HairlossAnaemia
Neutropenia
Cardiomyopathy
Neuropathy

A high association did not mean that the drug caused the symptom – it could also
arise if the drug was used to treat a pathology with the symptom. A high incidence
simply identified POSSIBLE cause, and would require further research of clinicaland experimental literature to determine if it was an ACTUAL cause.

The write-up for this study can be found here –cancer-drugs-compared
And the downloadable spreadsheet can be found here –cancer-drug-ratings-updated.csv