{"id":308,"date":"2026-05-02T20:18:52","date_gmt":"2026-05-02T13:18:52","guid":{"rendered":"https:\/\/medytic.blog\/?p=308"},"modified":"2026-05-09T19:07:31","modified_gmt":"2026-05-09T12:07:31","slug":"learning-pharmacovigilance-faers-data-analysis-personal-project","status":"publish","type":"post","link":"https:\/\/medytic.blog\/en\/2026\/05\/02\/learning-pharmacovigilance-faers-data-analysis-personal-project\/","title":{"rendered":"Pharmacovigilance Pipeline: FAERS Data Analysis"},"content":{"rendered":"\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<blockquote class=\"wp-block-quote has-medium-font-size is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><em><strong>Disclaimer<\/strong>:<\/em><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><em>The findings from this project are for educational purposes only and should not be used for clinical decision-making.<\/em><\/li>\n\n\n\n<li><em>Analysis scripts are provided at the bottom of the page and are written for the purpose of learning and should not be used for production without further testing<\/em><\/li>\n<\/ol>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Key Achievements \ud83c\udfc6\u200b<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Processed 20+ years of FAERS XML data (2004\u20132025) across 84 quarterly releases <\/li>\n\n\n\n<li>Detected 111,918 drug-reaction signals; identified GLP-1 class-wide GI safety profile<\/li>\n\n\n\n<li>Built multi-dimensional interactive visualizations filterable by gender, age, and indication<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Tools &amp; Skills <\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Layer<\/strong><\/td><td><strong>Tools<\/strong><\/td><\/tr><tr><td>1. ETL<\/td><td><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"30\" height=\"30\" data-attachment-id=\"516\" data-permalink=\"https:\/\/medytic.blog\/en\/portfolio\/python-logo-notext-svg\/\" data-orig-file=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/Python-logo-notext.svg_.png?fit=960%2C960&amp;ssl=1\" data-orig-size=\"960,960\" data-comments-opened=\"1\" data-image-title=\"Python-logo-notext.svg\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/Python-logo-notext.svg_.png?fit=960%2C960&amp;ssl=1\" class=\"wp-image-516\" style=\"width: 30px;\" src=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/Python-logo-notext.svg_.png?resize=30%2C30&#038;ssl=1\" alt=\"\" srcset=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/Python-logo-notext.svg_.png?w=960&amp;ssl=1 960w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/Python-logo-notext.svg_.png?resize=300%2C300&amp;ssl=1 300w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/Python-logo-notext.svg_.png?resize=150%2C150&amp;ssl=1 150w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/Python-logo-notext.svg_.png?resize=768%2C768&amp;ssl=1 768w\" sizes=\"auto, (max-width: 30px) 100vw, 30px\" \/> Python (xml.tree)<\/td><\/tr><tr><td>2. Data Cleaning<\/td><td><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"30\" height=\"31\" data-attachment-id=\"530\" data-permalink=\"https:\/\/medytic.blog\/en\/portfolio\/postgresql_elephant-svg\/\" data-orig-file=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/Postgresql_elephant.svg_.png?fit=1280%2C1320&amp;ssl=1\" data-orig-size=\"1280,1320\" data-comments-opened=\"1\" data-image-title=\"Postgresql_elephant.svg\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/Postgresql_elephant.svg_.png?fit=993%2C1024&amp;ssl=1\" class=\"wp-image-530\" style=\"width: 30px;\" src=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/Postgresql_elephant.svg_.png?resize=30%2C31&#038;ssl=1\" alt=\"\" srcset=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/Postgresql_elephant.svg_.png?w=1280&amp;ssl=1 1280w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/Postgresql_elephant.svg_.png?resize=291%2C300&amp;ssl=1 291w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/Postgresql_elephant.svg_.png?resize=993%2C1024&amp;ssl=1 993w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/Postgresql_elephant.svg_.png?resize=150%2C150&amp;ssl=1 150w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/Postgresql_elephant.svg_.png?resize=768%2C792&amp;ssl=1 768w\" sizes=\"auto, (max-width: 30px) 100vw, 30px\" \/>PostgreSQL<\/td><\/tr><tr><td>3. Analysis<\/td><td><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"30\" height=\"23\" data-attachment-id=\"528\" data-permalink=\"https:\/\/medytic.blog\/en\/portfolio\/r_logo-svg\/\" data-orig-file=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/R_logo.svg_.png?fit=960%2C744&amp;ssl=1\" data-orig-size=\"960,744\" data-comments-opened=\"1\" data-image-title=\"R_logo.svg\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/R_logo.svg_.png?fit=960%2C744&amp;ssl=1\" class=\"wp-image-528\" style=\"width: 30px;\" src=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/R_logo.svg_.png?resize=30%2C23&#038;ssl=1\" alt=\"\" srcset=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/R_logo.svg_.png?w=960&amp;ssl=1 960w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/R_logo.svg_.png?resize=300%2C233&amp;ssl=1 300w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/R_logo.svg_.png?resize=768%2C595&amp;ssl=1 768w\" sizes=\"auto, (max-width: 30px) 100vw, 30px\" \/> R (Tidyverse, DBI, RPostgres)<\/td><\/tr><tr><td>4. Visualization<\/td><td><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"30\" height=\"35\" data-attachment-id=\"521\" data-permalink=\"https:\/\/medytic.blog\/en\/portfolio\/logo\/\" data-orig-file=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/logo.png?fit=240%2C277&amp;ssl=1\" data-orig-size=\"240,277\" data-comments-opened=\"1\" data-image-title=\"logo\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/logo.png?fit=240%2C277&amp;ssl=1\" class=\"wp-image-521\" style=\"width: 30px;\" src=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/logo.png?resize=30%2C35&#038;ssl=1\" alt=\"\">ggplot, <img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"30\" height=\"30\" data-attachment-id=\"520\" data-permalink=\"https:\/\/medytic.blog\/en\/portfolio\/7da59672ed3a377055117f7dd706e2b8\/\" data-orig-file=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/7da59672ed3a377055117f7dd706e2b8.png?fit=300%2C297&amp;ssl=1\" data-orig-size=\"300,297\" data-comments-opened=\"1\" data-image-title=\"7da59672ed3a377055117f7dd706e2b8\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/7da59672ed3a377055117f7dd706e2b8.png?fit=300%2C297&amp;ssl=1\" class=\"wp-image-520\" style=\"width: 30px;\" src=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/7da59672ed3a377055117f7dd706e2b8.png?resize=30%2C30&#038;ssl=1\" alt=\"\" srcset=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/7da59672ed3a377055117f7dd706e2b8.png?w=300&amp;ssl=1 300w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/7da59672ed3a377055117f7dd706e2b8.png?resize=150%2C150&amp;ssl=1 150w\" sizes=\"auto, (max-width: 30px) 100vw, 30px\" \/>Plotly<\/td><\/tr><tr><td>5. Methods<\/td><td>PRR, ROR, Chi-square, IC<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">What you will find in this project<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"#Pharmacovigilance\">1. What is pharmacovigilance?<\/a><\/h3>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"#FAERS\">2. Introducing to the US crucial database for Pharmacovigilance: FAERS<\/a><\/h3>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"#method\">3. FAERS data analysis methodology<\/a>.<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>ETL (Extract, Transform, Load) using Python<\/li>\n\n\n\n<li>Data cleaning using PostgreSQL<\/li>\n\n\n\n<li>Descriptive profiling using R (tidyverse, DBI, RPostgres)<\/li>\n\n\n\n<li>Signal detection using R<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"#viz\">4. Findings &amp; Conclusion<\/a><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Discriptive profiling findings<\/li>\n\n\n\n<li>Statistical signal detection findings using R (ggplot2+plotly)\n<ul class=\"wp-block-list\">\n<li>Heatmaps to explore drug-reaction matrices<\/li>\n\n\n\n<li>Interactive volcano plots of the Information Component lower bound (IC025) against the Log10 Chi-square statistic<\/li>\n\n\n\n<li>Interactive GLP-1 Safety Signals forest plot<\/li>\n\n\n\n<li>Interactive GLP-1 Safety Signals by sub-population<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"#dis\">5. Discussions<\/a><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Limitations and future work<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"#scripts\">6. Full analysis scripts on GitHub<\/a><\/h3>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Introduction<\/h1>\n\n\n\n<div class=\"wp-block-group is-vertical is-layout-flex wp-container-core-group-is-layout-831b2db5 wp-block-group-is-layout-flex\">\n<p class=\"wp-block-paragraph\">This project applies ent-to-end pharmacovigilance analysis to the FDS&#8217;s FAERS database, 20+ years of real-world adverse event data to detect and characterize drug safety signals<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As a pharmacist transitioning into healthcare data, I built this pipeline from scratch: raw XML ingestion, SQK-based normalization, and signal detection in R,culninating in interactive clinical visualizations. <\/p>\n<\/div>\n\n\n\n<h2 id=\"Pharmacovigilance\" class=\"wp-block-heading\">What is pharmacovigilance?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Pharmacovigilance is the science of monitoring the safety of medicines after they reach the market. As part of this, the U.S. Food and Drug Administration (FDA) maintains the Adverse Event Reporting System (FAERS), a massive database tracking reported drug side effects.<\/p>\n\n\n\n<h2 id=\"FAERS\" class=\"wp-block-heading\">What is FAERS database?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The FDA Adverse Event Reporting System (FAERS) is a publicly available, national database containing millions of reports on adverse events (side effects) and medication errors.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These reports are submitted voluntarily by healthcare professionals and consumers, as well as mandatorily by pharmaceutical manufacturers.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What would be expected from this analysis?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">FAERS data can uncover hidden safety patterns that wern&#8217;t caught during initial clinical trials. For example, drug combination side effects or rare side effects in specific demographics. But this analysis focuses solely on drug-reaction pairs. Because I want to start with simple task first, which will lead to more complex analysis later on.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 id=\"method\" class=\"wp-block-heading\">Methodology<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">FAERS Analysis pipeline workflow:<\/p>\n\n\n\n<div style=\"width: 100%; margin: 0; padding: 0; display: block;\">\n    <iframe loading=\"lazy\" src=\"https:\/\/medytic.blog\/wp-content\/uploads\/2026\/05\/faers_pipeline_diagram-1.html\" \n            width=\"100%\" \n            height=\"800px\" \n            style=\"border: none; display: block;\">\n    <\/iframe>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Data source<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The raw data comes from the FDA&#8217;s FAERS quarterly data releases, provided as massive, deeply nested XML files containing millions of patient and drug records from 2004Q1-2025Q4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Data available here: <a href=\"https:\/\/www.fda.gov\/drugs\/drug-approvals-and-databases\/fda-adverse-event-reporting-system-faers-database\">FAERS Database<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Data preprocessing and cleaning<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. ETL (Extract, Transform, Load)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">I started with reading related documentations and sampling XML files to understand the structure and content of the data. Then, with the help of AIs, I developed `faers_etl.py` script using `xml.etree.ElementTree` library. I tested it on small subsets of the data first, and increased the data size to handle the massive XML files without crashing. Finally, I loaded the processed data into a structured PostgreSQL database.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The primary challenge with FAERS XML files is their size (2.2 GBs in total). Loading the entire DOM into memory would cause a crash (I had already crashed and burned my quota on Colab). My solution uses `iterparse` to process the file report-by-report, clearing the memory immediately after each insertion:<\/p>\n\n\n<div class=\"wp-block-code\">\n\t<div class=\"cm-editor\">\n\t\t<div class=\"cm-scroller\">\n\t\t\t\n<pre>\n<code class=\"language-python\"><div class=\"cm-line\"><span class=\"tok-keyword\">def<\/span> <span class=\"tok-variableName tok-definition\">process_file<\/span><span class=\"tok-punctuation\">(<\/span><span class=\"tok-variableName\">xml_path<\/span>: <span class=\"tok-variableName\">Path<\/span><span class=\"tok-punctuation\">,<\/span> <span class=\"tok-variableName\">conn<\/span><span class=\"tok-punctuation\">)<\/span>:<\/div><div class=\"cm-line\">    <span class=\"tok-comment\"># Stream-parse one XML file \u2014 memory-safe for large files<\/span><\/div><div class=\"cm-line\">    <span class=\"tok-variableName\">context<\/span> <span class=\"tok-operator\">=<\/span> <span class=\"tok-variableName\">ET<\/span><span class=\"tok-operator\">.<\/span><span class=\"tok-propertyName\">iterparse<\/span><span class=\"tok-punctuation\">(<\/span><span class=\"tok-variableName\">xml_path<\/span><span class=\"tok-punctuation\">,<\/span> <span class=\"tok-variableName\">events<\/span><span class=\"tok-operator\">=<\/span><span class=\"tok-punctuation\">(<\/span><span class=\"tok-string\">&quot;end&quot;<\/span><span class=\"tok-punctuation\">,<\/span><span class=\"tok-punctuation\">)<\/span><span class=\"tok-punctuation\">)<\/span><\/div><div class=\"cm-line\">    <\/div><div class=\"cm-line\">    <span class=\"tok-keyword\">for<\/span> <span class=\"tok-variableName\">event<\/span><span class=\"tok-punctuation\">,<\/span> <span class=\"tok-variableName\">elem<\/span> <span class=\"tok-keyword\">in<\/span> <span class=\"tok-variableName\">context<\/span>:<\/div><div class=\"cm-line\">        <span class=\"tok-keyword\">if<\/span> <span class=\"tok-variableName\">elem<\/span><span class=\"tok-operator\">.<\/span><span class=\"tok-propertyName\">tag<\/span> <span class=\"tok-operator\">!=<\/span> <span class=\"tok-string\">&quot;safetyreport&quot;<\/span>:<\/div><div class=\"cm-line\">            <span class=\"tok-keyword\">continue<\/span><\/div><div class=\"cm-line\">            <\/div><div class=\"cm-line\">        <span class=\"tok-comment\"># Parse and insert into DB<\/span><\/div><div class=\"cm-line\">        <span class=\"tok-variableName\">report<\/span> <span class=\"tok-operator\">=<\/span> <span class=\"tok-variableName\">parse_safety_report<\/span><span class=\"tok-punctuation\">(<\/span><span class=\"tok-variableName\">elem<\/span><span class=\"tok-punctuation\">)<\/span><\/div><div class=\"cm-line\">        <span class=\"tok-variableName\">_insert<\/span><span class=\"tok-punctuation\">(<\/span><span class=\"tok-variableName\">cur<\/span><span class=\"tok-punctuation\">,<\/span> <span class=\"tok-string\">&quot;safety_report&quot;<\/span><span class=\"tok-punctuation\">,<\/span> <span class=\"tok-variableName\">report<\/span><span class=\"tok-punctuation\">)<\/span><\/div><div class=\"cm-line\">        <\/div><div class=\"cm-line\">        <span class=\"tok-comment\"># CRITICAL: Discard the element from memory immediately<\/span><\/div><div class=\"cm-line\">        <span class=\"tok-variableName\">elem<\/span><span class=\"tok-operator\">.<\/span><span class=\"tok-propertyName\">clear<\/span><span class=\"tok-punctuation\">(<\/span><span class=\"tok-punctuation\">)<\/span><\/div><\/code><\/pre>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\">2. Data cleaning<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Utilizing SQL (`faers_clean.sql`), I performed extensive data normalization and cleaning:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Date &amp; Age Standardization: <\/strong>Converted string dates to standard formats, handled low-precision dates, and normalized various age units (months, days) into a single `ageyears` column.<\/li>\n\n\n\n<li><strong>Label Decoding:<\/strong> Translated cryptic numeric codes into readable text (e.g., patient sex, reaction outcomes).<\/li>\n\n\n\n<li><strong>Drug &amp; Indication Normalization:<\/strong> Extracted missing active ingredients from product names using regex, stripped chemical salt suffixes, and standardized medical indications.<\/li>\n\n\n\n<li><strong>Sender Normalization:<\/strong> Consolidated various pharmaceutical company subsidiaries into standardized parent company names.<\/li>\n\n\n\n<li><strong>Severity Reconciliation: <\/strong>Created a reliable master &#8220;seriousness&#8221; flag to fix logical inconsistencies in the raw FDA data.<\/li>\n\n\n\n<li><strong>Deduplication:<\/strong> Built a clinical &#8220;fingerprint&#8221; (matching demographics, dates, drugs, and reactions) to identify and remove duplicate reports submitted by multiple sources.<\/li>\n\n\n\n<li><strong>Final Analytical View:<\/strong> Compiled all the cleaned and filtered data into a final view (`v_analysis`) to serve as a reliable source of truth for the next statistical phase.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">One of the most complex tasks was identifying duplicate reports sent by different sources (e.g., a doctor and a manufacturer). I developed a &#8220;clinical fingerprint&#8221; strategy that matches reports based on a combination of demographics and medical data:<\/p>\n\n\n<div class=\"wp-block-code\">\n\t<div class=\"cm-editor\">\n\t\t<div class=\"cm-scroller\">\n\t\t\t\n<pre>\n<code class=\"language-sql\"><div class=\"cm-line\"><span class=\"tok-comment\">-- 10.1 Create a clinical fingerprint for each safety_report<\/span><\/div><div class=\"cm-line\"><span class=\"tok-comment\">-- A fingerprint consists of demographics, country, date, and aggregated suspect drugs + reactions.<\/span><\/div><div class=\"cm-line\"><span class=\"tok-keyword\">CREATE<\/span> TEMP <span class=\"tok-keyword\">TABLE<\/span> report_fingerprint <span class=\"tok-keyword\">AS<\/span><\/div><div class=\"cm-line\"><span class=\"tok-keyword\">SELECT<\/span><\/div><div class=\"cm-line\">    sr.safetyreportid<span class=\"tok-punctuation\">,<\/span><\/div><div class=\"cm-line\">    sr.occurcountry<span class=\"tok-punctuation\">,<\/span><\/div><div class=\"cm-line\">    sr.receivedate<span class=\"tok-punctuation\">,<\/span><\/div><div class=\"cm-line\">    p.patientsex<span class=\"tok-punctuation\">,<\/span><\/div><div class=\"cm-line\">    p.ageyears<span class=\"tok-punctuation\">,<\/span><\/div><div class=\"cm-line\">    <span class=\"tok-comment\">-- Aggregate suspect drugs into a single sorted string<\/span><\/div><div class=\"cm-line\">    <span class=\"tok-punctuation\">(<\/span><span class=\"tok-keyword\">SELECT<\/span> STRING_AGG<span class=\"tok-punctuation\">(<\/span><span class=\"tok-keyword\">DISTINCT<\/span> d.substance_std<span class=\"tok-punctuation\">,<\/span> <span class=\"tok-string\">&apos;|&apos;<\/span> <span class=\"tok-keyword\">ORDER<\/span> <span class=\"tok-keyword\">BY<\/span> d.substance_std<span class=\"tok-punctuation\">)<\/span> <\/div><div class=\"cm-line\">     <span class=\"tok-keyword\">FROM<\/span> drug d <\/div><div class=\"cm-line\">     <span class=\"tok-keyword\">WHERE<\/span> d.safetyreportid <span class=\"tok-operator\">=<\/span> sr.safetyreportid <span class=\"tok-keyword\">AND<\/span> d.drugcharacterization <span class=\"tok-operator\">=<\/span> <span class=\"tok-number\">1<\/span><span class=\"tok-punctuation\">)<\/span> <span class=\"tok-keyword\">AS<\/span> suspect_drugs<span class=\"tok-punctuation\">,<\/span><\/div><div class=\"cm-line\">    <span class=\"tok-comment\">-- Aggregate reactions into a single sorted string<\/span><\/div><div class=\"cm-line\">    <span class=\"tok-punctuation\">(<\/span><span class=\"tok-keyword\">SELECT<\/span> STRING_AGG<span class=\"tok-punctuation\">(<\/span><span class=\"tok-keyword\">DISTINCT<\/span> r.reactionmeddrapt<span class=\"tok-punctuation\">,<\/span> <span class=\"tok-string\">&apos;|&apos;<\/span> <span class=\"tok-keyword\">ORDER<\/span> <span class=\"tok-keyword\">BY<\/span> r.reactionmeddrapt<span class=\"tok-punctuation\">)<\/span><\/div><div class=\"cm-line\">     <span class=\"tok-keyword\">FROM<\/span> reaction r<\/div><div class=\"cm-line\">     <span class=\"tok-keyword\">WHERE<\/span> r.safetyreportid <span class=\"tok-operator\">=<\/span> sr.safetyreportid<span class=\"tok-punctuation\">)<\/span> <span class=\"tok-keyword\">AS<\/span> reactions<\/div><div class=\"cm-line\"><span class=\"tok-keyword\">FROM<\/span> safety_report sr<\/div><div class=\"cm-line\"><span class=\"tok-keyword\">JOIN<\/span> patient p <span class=\"tok-keyword\">ON<\/span> sr.safetyreportid <span class=\"tok-operator\">=<\/span> p.safetyreportid<\/div><div class=\"cm-line\"><span class=\"tok-keyword\">WHERE<\/span> sr.duplicate <span class=\"tok-keyword\">IS<\/span> <span class=\"tok-keyword\">NULL<\/span>; <span class=\"tok-comment\">-- Ignore already flagged duplicates<\/span><\/div><div class=\"cm-line\"><\/div><\/code><\/pre>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\">Descriptive profiling<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">I utilized R with packages (tidyverse, DBI, RPostgres) to plot descriptive profiling for better understanding of the dataset. Key insights from the data profiling include:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-slideshow has-custom-css wp-custom-css-eaede474\" data-effect=\"slide\" style=\"--aspect-ratio:calc(1024 \/ 742)\"><div class=\"wp-block-jetpack-slideshow_container swiper\"><ul class=\"wp-block-jetpack-slideshow_swiper-wrapper swiper-wrapper\"><li class=\"wp-block-jetpack-slideshow_slide swiper-slide\"><figure><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"742\" alt=\"\" class=\"wp-block-jetpack-slideshow_image wp-image-365\" data-id=\"365\" data-aspect-ratio=\"1024 \/ 742\" src=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_sex_distribution-1.png?resize=1024%2C742&#038;ssl=1\" srcset=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_sex_distribution-1.png?resize=1024%2C742&amp;ssl=1 1024w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_sex_distribution-1.png?resize=300%2C218&amp;ssl=1 300w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_sex_distribution-1.png?resize=768%2C557&amp;ssl=1 768w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_sex_distribution-1.png?resize=1536%2C1114&amp;ssl=1 1536w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_sex_distribution-1.png?w=2037&amp;ssl=1 2037w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/><figcaption class=\"wp-block-jetpack-slideshow_caption gallery-caption\">A pie chart showing the breakdown of reports by patient sex to observe reporting imbalances.<\/figcaption><\/figure><\/li><li class=\"wp-block-jetpack-slideshow_slide swiper-slide\"><figure><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"642\" alt=\"\" class=\"wp-block-jetpack-slideshow_image wp-image-392\" data-id=\"392\" data-aspect-ratio=\"1024 \/ 642\" src=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/plot_age_distribution-1.png?resize=1024%2C642&#038;ssl=1\" srcset=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/plot_age_distribution-1.png?resize=1024%2C642&amp;ssl=1 1024w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/plot_age_distribution-1.png?resize=300%2C188&amp;ssl=1 300w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/plot_age_distribution-1.png?resize=768%2C481&amp;ssl=1 768w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/plot_age_distribution-1.png?resize=1536%2C963&amp;ssl=1 1536w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/plot_age_distribution-1.png?w=2037&amp;ssl=1 2037w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/><figcaption class=\"wp-block-jetpack-slideshow_caption gallery-caption\">A bar chart illustrating the distribution of adverse event reports across different patient age groups.<\/figcaption><\/figure><\/li><li class=\"wp-block-jetpack-slideshow_slide swiper-slide\"><figure><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"717\" alt=\"\" class=\"wp-block-jetpack-slideshow_image wp-image-378\" data-id=\"378\" data-aspect-ratio=\"1024 \/ 717\" src=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_global_choropleth_moved.png?resize=1024%2C717&#038;ssl=1\" srcset=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_global_choropleth_moved.png?resize=1024%2C717&amp;ssl=1 1024w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_global_choropleth_moved.png?resize=300%2C210&amp;ssl=1 300w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_global_choropleth_moved.png?resize=768%2C538&amp;ssl=1 768w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_global_choropleth_moved.png?resize=1536%2C1075&amp;ssl=1 1536w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_global_choropleth_moved.png?resize=2048%2C1434&amp;ssl=1 2048w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_global_choropleth_moved.png?w=3000&amp;ssl=1 3000w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/><figcaption class=\"wp-block-jetpack-slideshow_caption gallery-caption\">A global choropleth map displaying the volume of adverse event reports by country of origin.<\/figcaption><\/figure><\/li><li class=\"wp-block-jetpack-slideshow_slide swiper-slide\"><figure><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"742\" alt=\"\" class=\"wp-block-jetpack-slideshow_image wp-image-366\" data-id=\"366\" data-aspect-ratio=\"1024 \/ 742\" src=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_severity_breakdown-1.png?resize=1024%2C742&#038;ssl=1\" srcset=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_severity_breakdown-1.png?resize=1024%2C742&amp;ssl=1 1024w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_severity_breakdown-1.png?resize=300%2C218&amp;ssl=1 300w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_severity_breakdown-1.png?resize=768%2C557&amp;ssl=1 768w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_severity_breakdown-1.png?resize=1536%2C1114&amp;ssl=1 1536w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_severity_breakdown-1.png?w=2037&amp;ssl=1 2037w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/><figcaption class=\"wp-block-jetpack-slideshow_caption gallery-caption\">A chart detailing the proportion of seriousness in serious adverse event reports.<\/figcaption><\/figure><\/li><li class=\"wp-block-jetpack-slideshow_slide swiper-slide\"><figure><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"742\" alt=\"\" class=\"wp-block-jetpack-slideshow_image wp-image-370\" data-id=\"370\" data-aspect-ratio=\"1024 \/ 742\" src=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_top_senders-1.png?resize=1024%2C742&#038;ssl=1\" srcset=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_top_senders-1.png?resize=1024%2C742&amp;ssl=1 1024w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_top_senders-1.png?resize=300%2C218&amp;ssl=1 300w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_top_senders-1.png?resize=768%2C557&amp;ssl=1 768w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_top_senders-1.png?resize=1536%2C1114&amp;ssl=1 1536w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_top_senders-1.png?w=2037&amp;ssl=1 2037w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/><figcaption class=\"wp-block-jetpack-slideshow_caption gallery-caption\">A ranking of the organizations that submit the highest volume of adverse event reports.<\/figcaption><\/figure><\/li><li class=\"wp-block-jetpack-slideshow_slide swiper-slide\"><figure><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"742\" alt=\"\" class=\"wp-block-jetpack-slideshow_image wp-image-369\" data-id=\"369\" data-aspect-ratio=\"1024 \/ 742\" src=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_fatal_reactions-1.png?resize=1024%2C742&#038;ssl=1\" srcset=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_fatal_reactions-1.png?resize=1024%2C742&amp;ssl=1 1024w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_fatal_reactions-1.png?resize=300%2C218&amp;ssl=1 300w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_fatal_reactions-1.png?resize=768%2C557&amp;ssl=1 768w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_fatal_reactions-1.png?resize=1536%2C1114&amp;ssl=1 1536w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_fatal_reactions-1.png?w=2037&amp;ssl=1 2037w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/><figcaption class=\"wp-block-jetpack-slideshow_caption gallery-caption\">A breakdown of the most common adverse reactions that resulted in a fatal outcome.<\/figcaption><\/figure><\/li><\/ul><a class=\"wp-block-jetpack-slideshow_button-prev swiper-button-prev swiper-button-white\" role=\"button\"><\/a><a class=\"wp-block-jetpack-slideshow_button-next swiper-button-next swiper-button-white\" role=\"button\"><\/a><a aria-label=\"Pause Slideshow\" class=\"wp-block-jetpack-slideshow_button-pause\" role=\"button\"><\/a><div class=\"wp-block-jetpack-slideshow_pagination swiper-pagination swiper-pagination-white\"><\/div><\/div><\/div>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><ul>\n<li><strong>Sex Distribution:<\/strong> Females report adverse events significantly more often than males (47.3% vs 31.0%). A notable portion (21.8%) of reports are missing sex data.<\/li>\n<li><strong>Age Distribution:<\/strong> Among reports with known ages, Adults (18-64) are the largest affected group (31.3%), followed by the Elderly (65-74) and Very elderly (&gt;75). A large proportion (41.9%) of reports unfortunately lack age data.<\/li>\n<li><strong>Geographic Mapping:<\/strong> Since FAERS database collects data in the US, the vast majority of adverse event reports originate from the United States, with secondary reporting clusters in Europe and East Asia.<\/li>\n<li><strong>Severity Breakdown:<\/strong> While many serious reports fall under a non-specific \u201cOther\u201d category (38.8%), a substantial portion resulted in Hospitalization (18.6%) and Death (6.5%), emphasizing the critical nature of the reported events.<\/li>\n<li><strong>Top Senders:<\/strong> Pharmaceutical companies <strong>SANOFI<\/strong> and <strong>ABBVIE<\/strong> are the top reporting organizations by a wide margin in this dataset. Sanofi and AbbVie top FAERS reporting primarily due to their massive patient volumes and market dominance in biologics, particularly with flagship drugs like Dupixent and Humira.<\/li>\n<li><strong>Fatal Reactions:<\/strong> The most frequent reactions associated with fatal outcomes range from severe acute conditions like \u201cDuodenal ulcer perforation\u201d and broader systemic issues like \u201cSystemic lupus erythematosus\u201d.<\/li>\n<\/ul>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Signal detection<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In pharmacovigilance, we look for &#8220;disproportionate signals&#8221;: when a specific side effect is reported for a drug more often than expected by chance.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For readers who are not familiar with pharmacovigilance, here is a quick guide:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Signal detection principle<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Important question:<\/strong> Is this drug-event combination reported more than expected? <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To answer this, we construct a 2&#215;2 contingency table:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td class=\"has-text-align-center\" data-align=\"center\"><strong>Drug-event pair<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>Target Reaction<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>Other Reactions<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>Total<\/strong><\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\"><strong>Target Drug<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\">a<\/td><td class=\"has-text-align-center\" data-align=\"center\">b<\/td><td class=\"has-text-align-center\" data-align=\"center\">a +b<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\"><strong>Other Drugs<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\">c<\/td><td class=\"has-text-align-center\" data-align=\"center\">d<\/td><td class=\"has-text-align-center\" data-align=\"center\">c + d<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\"><strong>Total<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\">a + c<\/td><td class=\"has-text-align-center\" data-align=\"center\">b + d<\/td><td class=\"has-text-align-center\" data-align=\"center\">n<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Where:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>a:<\/strong> Number of reports for the target drug with the target reaction<\/li>\n\n\n\n<li><strong>b:<\/strong> Number of reports for the target drug with other reactions<\/li>\n\n\n\n<li><strong>c:<\/strong> Number of reports for other drugs with the target reaction<\/li>\n\n\n\n<li><strong>d:<\/strong> Number of reports for other drugs with other reactions<\/li>\n\n\n\n<li><strong>n:<\/strong> Total number of reports<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s apply these variables to the metrics for signal detection.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Metrics for signal detection<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>1. PRR (Proportional Reporting Ratio)<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">PRR asks: &#8220;Is this side effect reported proportionally more for this drug than for all others?&#8221;<\/p>\n\n\n\n<div class=\"wp-block-math\"><math display=\"block\"><semantics><mrow><mi>P<\/mi><mi>R<\/mi><mi>R<\/mi><mo>=<\/mo><mfrac><mi>a<\/mi><mrow><mo form=\"prefix\" stretchy=\"false\" lspace=\"0em\" rspace=\"0em\">(<\/mo><mi>a<\/mi><mo>+<\/mo><mi>b<\/mi><mo form=\"postfix\" stretchy=\"false\" lspace=\"0em\" rspace=\"0em\">)<\/mo><\/mrow><\/mfrac><mo>\u00f7<\/mo><mfrac><mi>c<\/mi><mrow><mo form=\"prefix\" stretchy=\"false\" lspace=\"0em\" rspace=\"0em\">(<\/mo><mi>c<\/mi><mo>+<\/mo><mi>d<\/mi><mo form=\"postfix\" stretchy=\"false\" lspace=\"0em\" rspace=\"0em\">)<\/mo><\/mrow><\/mfrac><\/mrow><annotation encoding=\"application\/x-tex\">PRR=\\frac{a}{(a+b)}\\div\\frac{c}{(c+d)}<\/annotation><\/semantics><\/math><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">PRR is the ratio between:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Proportion of reports for a specific drug-event pair<\/li>\n\n\n\n<li>Proportion of reports for other drugs with the same event<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Interpret as:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>PRR = 1:<\/strong> No association<\/li>\n\n\n\n<li><strong>PRR &gt; 1:<\/strong> signal detected<\/li>\n\n\n\n<li><strong>PRR &lt; 1:<\/strong> signal not detected\/protective effect (rare)<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>2. ROR (Reporting Odds Ratio)<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">ROR asks: &#8220;How much more likely is this drug-reaction pair to appear in the data compared to any other drug-reaction combination?&#8221;<\/p>\n\n\n\n<div class=\"wp-block-math\"><math display=\"block\"><semantics><mrow><mi>R<\/mi><mi>O<\/mi><mi>R<\/mi><mo>=<\/mo><mfrac><mi>a<\/mi><mi>b<\/mi><\/mfrac><mo>\u00f7<\/mo><mfrac><mi>c<\/mi><mi>d<\/mi><\/mfrac><\/mrow><annotation encoding=\"application\/x-tex\">ROR=\\frac{a}{b}\\div\\frac{c}{d}<\/annotation><\/semantics><\/math><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Is a cross-product ratio<\/li>\n\n\n\n<li>From the case-control perspective<\/li>\n\n\n\n<li>Interpret as:\n<ul class=\"wp-block-list\">\n<li>ROR = 1: No association<\/li>\n\n\n\n<li>ROR &gt; 1: signal detected<\/li>\n\n\n\n<li>ROR &lt; 1: signal not detected\/protective effect (rare)<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>3. Chi-square \u03c7\u00b2 (with Yates&#8217; continuity correction): Test of independence<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong> \u03c7\u00b2<\/strong> asks: &#8220;Is the association between this drug and this reaction statistically real, or could it just be random chance?&#8221;<\/p>\n\n\n\n<div class=\"wp-block-math\"><math display=\"block\"><semantics><mrow><msup><mi>\u03c7<\/mi><mn>2<\/mn><\/msup><mo>=<\/mo><mfrac><mrow><mi>N<\/mi><mo>\u00d7<\/mo><mo form=\"prefix\" stretchy=\"false\">(<\/mo><mi>|<\/mi><mi>a<\/mi><mi>d<\/mi><mo>\u2212<\/mo><mi>b<\/mi><mi>c<\/mi><mi>|<\/mi><mo>\u2212<\/mo><mi>N<\/mi><mi>\/<\/mi><mn>2<\/mn><msup><mo form=\"postfix\" stretchy=\"false\">)<\/mo><mn>2<\/mn><\/msup><\/mrow><mrow><mo form=\"prefix\" stretchy=\"false\" lspace=\"0em\" rspace=\"0em\">(<\/mo><mi>a<\/mi><mo>+<\/mo><mi>b<\/mi><mo form=\"postfix\" stretchy=\"false\">)<\/mo><mo form=\"prefix\" stretchy=\"false\">(<\/mo><mi>c<\/mi><mo>+<\/mo><mi>d<\/mi><mo form=\"postfix\" stretchy=\"false\">)<\/mo><mo form=\"prefix\" stretchy=\"false\">(<\/mo><mi>a<\/mi><mo>+<\/mo><mi>c<\/mi><mo form=\"postfix\" stretchy=\"false\">)<\/mo><mo form=\"prefix\" stretchy=\"false\">(<\/mo><mi>b<\/mi><mo>+<\/mo><mi>d<\/mi><mo form=\"postfix\" stretchy=\"false\" lspace=\"0em\" rspace=\"0em\">)<\/mo><\/mrow><\/mfrac><\/mrow><annotation encoding=\"application\/x-tex\">\u03c7\u00b2 = \\frac{N \u00d7 (|ad &#8211; bc| &#8211; N\/2)\u00b2}{(a+b)(c+d)(a+c)(b+d)}<\/annotation><\/semantics><\/math><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Test whether a,b,c,d are independent (null hypothesis)<\/li>\n\n\n\n<li>Interpret as:\n<ul class=\"wp-block-list\">\n<li><strong>\u03c7\u00b2 &lt;= 4:<\/strong> fail to reject null hypothesis at ~95% confidence level -&gt; signal is not statistically significant<\/li>\n\n\n\n<li><strong>\u03c7\u00b2 &gt;   4:<\/strong> reject null hypothesis at ~95% confidence level -&gt; signal is statistically significant<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>4. Information Component (IC; with Bayesian correction): Test of disproportionality<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">IC asks: &#8220;How much more often is this drug-reaction pair reported than we&#8217;d expect if the two were completely unrelated?&#8221;<\/p>\n\n\n\n<div class=\"wp-block-math\"><math display=\"block\"><semantics><mrow><mi>I<\/mi><mi>C<\/mi><mo>=<\/mo><mi>l<\/mi><mi>o<\/mi><msub><mi>g<\/mi><mn>2<\/mn><\/msub><mo form=\"prefix\" stretchy=\"false\">[<\/mo><mo form=\"prefix\" stretchy=\"false\">(<\/mo><mi>a<\/mi><mo>+<\/mo><mn>0.5<\/mn><mo form=\"postfix\" stretchy=\"false\">)<\/mo><mi>\/<\/mi><mfrac><mrow><mo form=\"prefix\" stretchy=\"false\" lspace=\"0em\" rspace=\"0em\">(<\/mo><mi>a<\/mi><mo>+<\/mo><mi>b<\/mi><mo>+<\/mo><mn>0.5<\/mn><mo form=\"postfix\" stretchy=\"false\">)<\/mo><mo>\u00d7<\/mo><mo form=\"prefix\" stretchy=\"false\">(<\/mo><mi>a<\/mi><mo>+<\/mo><mi>c<\/mi><mo>+<\/mo><mn>0.5<\/mn><mo form=\"postfix\" stretchy=\"false\" lspace=\"0em\" rspace=\"0em\">)<\/mo><\/mrow><mrow><mi>N<\/mi><mo>+<\/mo><mn>1<\/mn><\/mrow><\/mfrac><mo form=\"postfix\" stretchy=\"false\">]<\/mo><\/mrow><annotation encoding=\"application\/x-tex\">IC = log\u2082[(a + 0.5) \/ \\frac{(a+b+0.5) \u00d7 (a+c+0.5)}{N+1}]<\/annotation><\/semantics><\/math><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Measures information gain from the observation (Log2 ratio between observed and expected counts of the event-drug pair)<\/li>\n\n\n\n<li>Interpret as:\n<ul class=\"wp-block-list\">\n<li><strong>IC = 0:<\/strong> no information gain (Observed = Expected)<\/li>\n\n\n\n<li><strong>IC &gt; 0:<\/strong> signal detected, IC = 1: 2x more than expected, IC = 2: 4x more than expected, &#8230;<\/li>\n\n\n\n<li><strong>IC &lt; 0:<\/strong> signal not detected\/protective effect (rare)<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>5. IC025: Signal Stability<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">IC025 asks: &#8220;Even in the worst-case statistical scenario, is this signal still strong enough to be considered real and not a random chance from small sample sizes?&#8221;<\/p>\n\n\n\n<div class=\"wp-block-math\"><math display=\"block\"><semantics><mrow><mi>I<\/mi><msub><mi>C<\/mi><mrow><mi>v<\/mi><mi>a<\/mi><mi>r<\/mi><\/mrow><\/msub><mo>=<\/mo><mfrac><mn>1<\/mn><mrow><mi>l<\/mi><mi>o<\/mi><mi>g<\/mi><mo form=\"prefix\" stretchy=\"false\">(<\/mo><mn>2<\/mn><msup><mo form=\"postfix\" stretchy=\"false\">)<\/mo><mn>2<\/mn><\/msup><\/mrow><\/mfrac><mo>\u00d7<\/mo><mfrac><mn>1<\/mn><mrow><mi>a<\/mi><mo>+<\/mo><mn>0.5<\/mn><\/mrow><\/mfrac><mo>\u2212<\/mo><mfrac><mn>1<\/mn><mrow><mi>N<\/mi><mo>+<\/mo><mn>1<\/mn><\/mrow><\/mfrac><\/mrow><annotation encoding=\"application\/x-tex\">IC_{var} = \\frac{1}{log(2)\u00b2} \u00d7 \\frac{1}{a+0.5} &#8211; \\frac{1}{N+1}<\/annotation><\/semantics><\/math><\/div>\n\n\n\n<div class=\"wp-block-math\"><math display=\"block\"><semantics><mrow><mi>I<\/mi><msub><mi>C<\/mi><mn>0<\/mn><\/msub><msub><mi>.<\/mi><mn>025<\/mn><\/msub><mo>=<\/mo><mi>I<\/mi><mi>C<\/mi><mo>\u2212<\/mo><mn>1.96<\/mn><mo>\u00d7<\/mo><msqrt><mrow><mi>I<\/mi><msub><mi>C<\/mi><mrow><mi>v<\/mi><mi>a<\/mi><mi>r<\/mi><\/mrow><\/msub><\/mrow><\/msqrt><\/mrow><annotation encoding=\"application\/x-tex\">IC\u2080.\u2080\u2082\u2085 = IC &#8211; 1.96 \u00d7 \\sqrt{IC_{var}}<\/annotation><\/semantics><\/math><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Lower bound of 95% Confidence Interval of IC<\/li>\n\n\n\n<li>Interpret as:\n<ul class=\"wp-block-list\">\n<li><strong>IC025   &lt;   0:<\/strong> signal are not statistically significant at 95% confidence level<\/li>\n\n\n\n<li><strong>IC025 &gt;= 0:<\/strong> signal detected with 95% confidence level<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For signal detection methods selection, I borrowed methodology from many organizations for robustness:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>PRR, ROR,<\/strong> and<strong> \u03c7\u00b2<\/strong> from European Medicines Agency (EMA)<\/li>\n\n\n\n<li><strong>IC\/BCPNN,<\/strong> and <strong>IC025<\/strong> from WHO Uppsala Monitoring Centre (VigiBase)<\/li>\n\n\n\n<li><strong>Thresholds: PRR \u2265 2, \u03c7\u00b2 \u2265 4<\/strong> from UK MHRA (Medicines and Healthcare products Regulatory Agency), added: a &gt;= 3 &amp; IC025 &gt; 0 in this analysis<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">I utilized R to apply these statistical methods to find strong associations.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Confounding control<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Confouding by indication is when the indication of the drug is filled as an adverse effect of the drug. For example, a diabetes drug will have high reports of high blood sugar simply because the patients have diabetes. I built a filter to significantly reduce these logical overlaps so we only flag unexpected side effects.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To ensure the detection of new safety signals rather than symptoms of the underlying disease, I implemented a string-matching filter in R. This removes any case where the reported reaction is already mentioned as the reason for taking the drug:<\/p>\n\n\n<div class=\"wp-block-code\">\n\t<div class=\"cm-editor\">\n\t\t<div class=\"cm-scroller\">\n\t\t\t\n<pre>\n<code class=\"language-r\"><div class=\"cm-line\"><span class=\"tok-comment\"># Indication Overlap Logic (Confounding Control)<\/span><\/div><div class=\"cm-line\"><span class=\"tok-variableName\">df_filtered<\/span> <span class=\"tok-operator\">&lt;-<\/span> <span class=\"tok-variableName\">df_raw<\/span> <span class=\"tok-variableName2\">%&gt;%<\/span><\/div><div class=\"cm-line\">  <span class=\"tok-variableName\">mutate<\/span>(<\/div><div class=\"cm-line\">    <span class=\"tok-variableName\">rxn_clean<\/span> <span class=\"tok-operator\">=<\/span> <span class=\"tok-variableName\">str_to_lower<\/span>(<span class=\"tok-variableName\">str_trim<\/span>(<span class=\"tok-variableName\">reactionmeddrapt<\/span>)),<\/div><div class=\"cm-line\">    <span class=\"tok-variableName\">ind_clean<\/span> <span class=\"tok-operator\">=<\/span> <span class=\"tok-variableName\">str_to_lower<\/span>(<span class=\"tok-variableName\">str_trim<\/span>(<span class=\"tok-variableName\">indication_std<\/span>))<\/div><div class=\"cm-line\">  ) <span class=\"tok-variableName2\">%&gt;%<\/span><\/div><div class=\"cm-line\">  <span class=\"tok-variableName\">filter<\/span>(<\/div><div class=\"cm-line\">    <span class=\"tok-variableName\">is.na<\/span>(<span class=\"tok-variableName\">ind_clean<\/span>) <span class=\"tok-operator\">|<\/span> <\/div><div class=\"cm-line\">    (<span class=\"tok-variableName\">rxn_clean<\/span> <span class=\"tok-operator\">!=<\/span> <span class=\"tok-variableName\">ind_clean<\/span> <span class=\"tok-operator\">&amp;<\/span> <span class=\"tok-operator\">!<\/span><span class=\"tok-variableName\">str_detect<\/span>(<span class=\"tok-variableName\">ind_clean<\/span>, <span class=\"tok-variableName\">fixed<\/span>(<span class=\"tok-variableName\">rxn_clean<\/span>)))<\/div><div class=\"cm-line\">  )<\/div><\/code><\/pre>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 id=\"viz\" class=\"wp-block-heading\">Visualization &amp; Findings<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">I created interactive visualizations using R (ggplot, Plotly) to make the findings accessible. This includes:<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Heatmaps of drug-reaction matrices<\/h2>\n\n\n\n<figure class=\"wp-block-image alignwide size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"592\" data-attachment-id=\"343\" data-permalink=\"https:\/\/medytic.blog\/en\/2026\/05\/02\/learning-pharmacovigilance-faers-data-analysis-personal-project\/plot_signal_heatmap_annotated\/\" data-orig-file=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_signal_heatmap_annotated.png?fit=3600%2C2080&amp;ssl=1\" data-orig-size=\"3600,2080\" data-comments-opened=\"1\" data-image-title=\"plot_signal_heatmap_annotated\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_signal_heatmap_annotated.png?fit=1024%2C592&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_signal_heatmap_annotated.png?resize=1024%2C592&#038;ssl=1\" alt=\"\" class=\"wp-image-343\" srcset=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_signal_heatmap_annotated.png?resize=1024%2C592&amp;ssl=1 1024w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_signal_heatmap_annotated.png?resize=300%2C173&amp;ssl=1 300w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_signal_heatmap_annotated.png?resize=768%2C444&amp;ssl=1 768w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_signal_heatmap_annotated.png?resize=1536%2C887&amp;ssl=1 1536w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_signal_heatmap_annotated.png?resize=2048%2C1183&amp;ssl=1 2048w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_signal_heatmap_annotated.png?resize=1200%2C693&amp;ssl=1 1200w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_signal_heatmap_annotated.png?w=3000&amp;ssl=1 3000w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The <strong>Safety Signal Intensity Heatmap<\/strong> visualizes the association strength (IC025) between the top 40 drugs and the top 40 reported adverse reactions. Darker blue cells indicate a higher lower bound of the Information Component (IC), representing a statistically robust signal. Findings from this heatmap include:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><ul>\n<li><strong>GLP-1 Agonist Cluster:<\/strong> The heatmap highlights a distinct gastrointestinal (GI) safety profile for GLP-1 receptor agonists like <strong>Semaglutide<\/strong> and <strong>Tirzepatide<\/strong>. Both drugs show strong positive associations with <strong>Nausea<\/strong>, <strong>Vomiting<\/strong>, <strong>Diarrhoea<\/strong>, <strong>Constipation<\/strong>, and <strong>Abdominal pain<\/strong>.<\/li>\n<li><strong>Tirzepatide &amp; Injection Site Reactions:<\/strong> While sharing the GI profile, <strong>Tirzepatide<\/strong> stands out with a particularly intense signal for <strong>Injection site pain<\/strong>, reflecting its delivery method and potentially higher localized reactivity compared to other substances in the top 40.<\/li>\n<li><strong>Disease-Signal Overlap:<\/strong> The dark signals for <strong>Type 2 diabetes mellitus<\/strong> associated with these drugs exemplify \u2018Confounding by Indication\u2019 where the underlying condition being treated is reported as an adverse event. Although \u2018Indication Filtering\u2019 step is applied, there are still some signals for underlying conditions left.<\/li>\n<\/ul>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">2. Interactive volcano plots<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This visualization displays safety signals by plotting the <strong>Information Component lower bound (IC025)<\/strong> against the <strong>Log10 Chi-square statistic<\/strong>.<\/p>\n\n\n\n<div style=\"width: 100%; margin: 0; padding: 0; display: block;\">\n    <iframe loading=\"lazy\" src=\"https:\/\/medytic.blog\/wp-content\/uploads\/2026\/04\/signal_interactive_volcano_atc-1.html\" \n            width=\"100%\" \n            height=\"400px\" \n            style=\"border: none; display: block;\">\n    <\/iframe>\n<\/div>\n\n\n\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-3a88641f wp-block-columns-is-layout-flex\" style=\"border-top-left-radius:0px;border-top-right-radius:0px;border-bottom-left-radius:0px;border-bottom-right-radius:0px\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:100%\">\n<div class=\"wp-block-jetpack-markdown\"><ul>\n<li><strong>Signal Stability (X-axis):<\/strong> The IC025 represents the Bayesian lower bound of signal strength; values above 0 indicate a stable signal.<\/li>\n<li><strong>Statistical Significance (Y-axis):<\/strong> The Chi-square statistic identifies signals that deviate significantly from expected background reporting.<\/li>\n<li><strong>Magnitude &amp; Risk:<\/strong> Bubble size represents the <strong>total case count<\/strong>, while the color gradient (from wheat to indianred) represents the <strong>Proportional Reporting Ratio (PRR)<\/strong>.<\/li>\n<li><strong>Interactive Filtering:<\/strong> Users can filter signals by WHO ATC Level 1 drug classes using the built-in dropdown menu.<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Key Findings:<\/strong> The plot clearly isolates a &#8220;Strong Signals&#8221; quadrant (top-right) where drug-reaction pairs meet both rigorous Bayesian and Frequentist criteria. By filtering for the &#8220;Alimentary tract and metabolism&#8221; ATC class, <strong>GLP-1 receptor agonists<\/strong> (such as Semaglutide and Tirzepatide) stand out in the upper-right quadrant. Their data points appear as massive, red bubbles representing high case volumes and PRR values for gastrointestinal adverse events. This immediate visual confirmation justifies selecting GLP-1 agonists for a targeted deep-dive analysis.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Interactive GLP-1 Safety Signals<\/h2>\n\n\n\n<div style=\"width: 100%; margin: 0; padding: 0; display: block;\">\n    <iframe loading=\"lazy\" src=\"https:\/\/medytic.blog\/wp-content\/uploads\/2026\/04\/glp1_interactive_forest-1.html\" \n            width=\"100%\" \n            height=\"400px\" \n            style=\"border: none; display: block;\">\n    <\/iframe>\n<\/div>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>The <strong>Interactive GLP-1 Safety Signal Forest Plot<\/strong> provides a granular, drug-by-drug comparison of safety signals within the GLP-1 agonist class. This visualization utilizes the <strong>Information Component (IC)<\/strong>: A Bayesian measure of disproportionate reporting, along with its <strong>95% Confidence Interval<\/strong> to illustrate signal stability.<\/p>\n<ul>\n<li><strong>Comparative Profiling:<\/strong> A built-in dropdown menu allows users to toggle between different reactions (e.g., Nausea, Vomiting, Constipation), revealing how drugs like <strong>Semaglutide<\/strong>, <strong>Tirzepatide<\/strong>, and <strong>Dulaglutide<\/strong> perform relative to one another.<\/li>\n<li><strong>Hover Metadata:<\/strong> The interactive Plotly interface allows users to hover over data points to see exact IC values, confidence bounds (IC025 to IC975), and specific case counts, making it a powerful tool for deep-dive safety assessment.<\/li>\n<li><strong>Precision &amp; Volume:<\/strong> For common GI reactions like \u2018Nausea\u2019, \u2018Diarrhoea\u2019, \u2018Vomiting\u2019, and \u2018Constipation\u2019, <strong>Semaglutide<\/strong>, <strong>Liraglutide<\/strong>, <strong>Dulaglutide<\/strong> and <strong>Tirzepatide<\/strong> show high-intensity, stable signals (IC 1 &#8211; 3.5), while some newer agents show insufficient reporting volumes. For injection site pain, <strong>Tirzepatide<\/strong> shows the highest intensity, stable signal (IC &gt; 4), followed by <strong>dulaglutide<\/strong> (IC ~ 3), while other GLP-1 agonists show 0 reports for this reaction. This finding agree with adverse reaction information from Lexidrug showing 3-8% of mild injection site pain in <strong>Tirzepatide<\/strong> users, but no such adverse reaction in <strong>Semaglutide<\/strong> and <strong>Liraglutide<\/strong> users.<\/li>\n<\/ul>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">4. Interactive GLP-1 Safety Signals by sub-population<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The <strong>Sub-population Safety Signal Heatmap<\/strong> is a multi-dimensional tool designed to uncover how safety signals vary across different patient demographics.<\/p>\n\n\n\n<div style=\"width: 100%; display: flex; justify-content: center; margin: 0; padding: 0;\">\n    <iframe loading=\"lazy\" src=\"https:\/\/medytic.blog\/wp-content\/uploads\/2026\/04\/glp1_interactive_heatmap_filtered-1.html\" \n            width=\"70%\" \n            height=\"800px\" \n            style=\"border: none; display: block;\">\n    <\/iframe>\n<\/div>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><ul>\n<li><strong>Multi-Dimensional Filtering:<\/strong> Three dropdown menus allow users to slice the data by <strong>Gender<\/strong>, <strong>Age Group<\/strong> (e.g., Adult 18-64 vs. Elderly 65+), and <strong>Clinical Indication<\/strong> (e.g., Diabetes vs. Weight Management).<\/li>\n<li><strong>Evidence-Based Visualization:<\/strong> Each cell displays the <strong>IC025<\/strong> value, with visual markers denoting statistical significance levels. (***: IC025&gt;2, **:IC025&gt;1, *:IC025&gt;0)<\/li>\n<li><strong>Demographic Insights:<\/strong>\n<ul>\n<li><strong>Weight Management Cohort:<\/strong> For patients taking medications for weight loss, signals for <strong>\u201cImpaired gastric emptying\u201d<\/strong> and <strong>\u201cAbdominal pain\u201d<\/strong> are significantly more pronounced compared to those taking the same drugs for diabetes, especially for <strong>Dulaglutide<\/strong>.<\/li>\n<li><strong>Injection-Site Cluster:<\/strong> <strong>Tirzepatide<\/strong> displays a uniquely intense and consistent cluster of injection-site reactions (pain, bruising, erythema) that persists across all age and gender filters, distinguishing it from other GLP-1s.<\/li>\n<li><strong>Indication-Driven Reporting:<\/strong> In the diabetes population, signals like <strong>\u201cBlood glucose increased\u201d<\/strong> and <strong>\u201cDrug ineffective\u201d<\/strong> often appear, reflecting clinical reporting patterns where uncontrolled underlying disease is flagged as an adverse event.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/div>\n\n\n\n<h1 id=\"con\" class=\"wp-block-heading\">Conclusion<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">This FAERS data analysis pipeline effectively demonstrates how statistical pharmacovigilance techniques combined with interactive visualizations can isolate and interpret genuine drug safety signals from background noise.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">By applying both Bayesian (IC) and Frequentist methods (PRR, ROR), I identified <strong>GLP-1 receptor agonists<\/strong> as a drug class of exceptionally high interest due to their overwhelmingly strong safety signals. Through our targeted deep-dive visualizations, several key clinical insights emerged:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><ol>\n<li><strong>Class-wide Gastrointestinal Signals:<\/strong> GLP-1 agonists (particularly Semaglutide, Tirzepatide, Liraglutide, and Dulaglutide) consistently exhibit high-intensity, stable signals for GI adverse events like nausea, vomiting, diarrhoea, and constipation.<\/li>\n<li><strong>Drug-Specific Variances:<\/strong> While sharing the GI profile, <strong>Tirzepatide<\/strong> and <strong>Dulaglutide<\/strong> present uniquely intense, robust signals for injection-site reactions (such as pain, bruising, and erythema) that are virtually absent in reports for other GLP-1 drugs, a finding that corroborates established medical literature.<\/li>\n<li><strong>Sub-population Differences:<\/strong> The adverse event profile shifts significantly based on the patient\u2019s clinical indication. Notably, patients utilizing these medications for <strong>weight management<\/strong> report pronounced rates of impaired gastric emptying and abdominal pain compared to those treating diabetes, especially with Dulaglutide.<\/li>\n<li><strong>Confounding by Indication:<\/strong> Despite applying logical filtering steps, the persistent overlap of disease symptoms (e.g., increased blood glucose in diabetes patients) being reported as adverse events highlights the inherent complexities of analyzing real-world, post-marketing data.<\/li>\n<\/ol>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Ultimately, this project showcases the power of transforming massive, complex raw data into granular, actionable clinical insights that can inform personalized patient care and enhance drug safety monitoring.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 id=\"dis\" class=\"wp-block-heading\">Discussion<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">While this pipeline successfully extracts actionable insights from raw FAERS data, analyzing real-world pharmacovigilance data presents several inherent challenges that leave room for future improvement:<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Drug Name Standardization<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Raw adverse event reports use tens of thousands of different names, misspellings, or abbreviations for the same drug. In this iteration, I implemented a custom fuzzy matching algorithm to standardize medicinal product names into generic active substances. Initial explorations using external APIs (like OpenFDA and RxNorm) yielded inconsistent results: such as erroneously mapping &#8220;0.9 % Normal saline&#8221; to &#8220;tolnaftate&#8221;. Moving forward, integrating flexible methods like Retrieval-Augmented Generation (RAG) or Large Language Models (LLMs) could provide the contextual understanding necessary for highly accurate, automated drug mapping.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Cross-sender deduplication<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The FAERS database frequently contains duplicate reports submitted by different entities (e.g., a physician, a pharmacist, and the manufacturer reporting the same single event). Although this project employs duplication flag and clinical fingerprinting to identify and exclude overlapping reports across different senders, this deduplication strategy is not perfect due to sparse patient-specific identifiers such as age, bodyweight, etc. This may lead to inflated case counts and biased statistical signals. Future enhancements could explore probabilistic record linkage to improve accuracy.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Indication Filtering and Confounding<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">&#8220;Confounding by indication&#8221; is a persistent hurdle. While my custom Indication filtering successfully reduces direct logical overlaps. However, some disease-driven signals still occasionally slip through (such as &#8220;Blood glucose increased&#8221; or &#8220;Drug ineffective&#8221;). Developing more nuanced clinical ontologies to filter downstream disease complications, or accurately accounting for off-label usage, would help isolate only the truly unexpected adverse drug reactions.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Advanced Signal Detection Methods<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The current pipeline utilizes a robust blend of Frequentist (PRR, ROR, Chi-square) and Bayesian (Information Component via BCPNN) methodologies. However, the signal detection capabilities can be further enhanced by incorporating more sophisticated empirical Bayes methods, such as the <strong>Multi-item Gamma Poisson Shrinker (MGPS)<\/strong> to calculate the <strong>Empirical Bayes Geometric Mean (EBGM)<\/strong>. These algorithms, frequently utilized by the FDA, are particularly effective at minimizing false positives in extremely sparse data and detecting complex multi-drug interactions (polypharmacy).<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 id=\"scripts\" class=\"wp-block-heading\">Analysis scripts<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/eettirk\/FAERS.git\">My GitHub repo<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Thank you for making it this far, this is my first complete health data analysis project. This project taught me many things. I will make sharper analysis, stay tuned for my next project!<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"673\" data-attachment-id=\"450\" data-permalink=\"https:\/\/medytic.blog\/en\/img_7124\/\" data-orig-file=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/IMG_7124.jpeg?fit=4032%2C2650&amp;ssl=1\" data-orig-size=\"4032,2650\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;1.8&quot;,&quot;camera&quot;:&quot;iPhone 11&quot;,&quot;created_timestamp&quot;:&quot;1775252172&quot;,&quot;focal_length&quot;:&quot;4.25&quot;,&quot;iso&quot;:&quot;640&quot;,&quot;shutter_speed&quot;:&quot;0.03030303030303&quot;,&quot;orientation&quot;:&quot;1&quot;}\" data-image-title=\"IMG_7124\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/IMG_7124.jpeg?fit=1024%2C673&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/IMG_7124.jpeg?resize=1024%2C673&#038;ssl=1\" alt=\"\" class=\"wp-image-450\" srcset=\"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/IMG_7124.jpeg?resize=1024%2C673&amp;ssl=1 1024w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/IMG_7124.jpeg?resize=300%2C197&amp;ssl=1 300w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/IMG_7124.jpeg?resize=768%2C505&amp;ssl=1 768w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/IMG_7124.jpeg?resize=1536%2C1010&amp;ssl=1 1536w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/IMG_7124.jpeg?resize=2048%2C1346&amp;ssl=1 2048w, https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/05\/IMG_7124.jpeg?w=3000&amp;ssl=1 3000w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\"><em><strong>Disclaimer (again!?): <\/strong>This project is for educational purposes. Findings should not be used for clinical decision-making.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This project focuses on pharmacovigilance using the FDA&#8217;s FAERS database to analyze drug safety signals. It details methodologies for data extraction, cleaning, and statistical analysis using R and Python. Key findings highlight significant adverse event patterns, particularly for GLP-1 receptor agonists, with insights on demographic variations and ongoing challenges in data interpretation.<\/p>\n","protected":false},"author":273023487,"featured_media":343,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_seo_schema_type":"","_jetpack_newsletter_access":"everybody","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_wpcom_ai_launchpad_first_post":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[34555906,413477,231379257,10189],"tags":[231379282,231379271,231379277,231379267,231379276,231379266,231379269,231379280,231379274,231379281,231379275,231379279,832,231379255,231379272,231379283,231379273,231379270,231379268,231379278],"class_list":["post-308","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-healthcare-analysis","category-personal-project","category-portfolio","category-r","tag-adverse-drug-reactions","tag-data-science","tag-data-visualization","tag-drug-safety","tag-etl","tag-faers","tag-glp-1-agonists","tag-medical-informatics","tag-pharmacovigilance","tag-plotly","tag-postgresql","tag-public-health","tag-python","tag-r","tag-real-world-evidence","tag-rstats","tag-semaglutide","tag-signal-detection","tag-sql","tag-tirzepatide"],"jetpack_publicize_connections":[],"jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pgTbA2-4Y","jetpack-related-posts":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/medytic.blog\/wp-content\/uploads\/2026\/04\/plot_signal_heatmap_annotated.png?fit=3600%2C2080&ssl=1","_links":{"self":[{"href":"https:\/\/medytic.blog\/en\/wp-json\/wp\/v2\/posts\/308","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/medytic.blog\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/medytic.blog\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/medytic.blog\/en\/wp-json\/wp\/v2\/users\/273023487"}],"replies":[{"embeddable":true,"href":"https:\/\/medytic.blog\/en\/wp-json\/wp\/v2\/comments?post=308"}],"version-history":[{"count":100,"href":"https:\/\/medytic.blog\/en\/wp-json\/wp\/v2\/posts\/308\/revisions"}],"predecessor-version":[{"id":603,"href":"https:\/\/medytic.blog\/en\/wp-json\/wp\/v2\/posts\/308\/revisions\/603"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/medytic.blog\/en\/wp-json\/wp\/v2\/media\/343"}],"wp:attachment":[{"href":"https:\/\/medytic.blog\/en\/wp-json\/wp\/v2\/media?parent=308"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/medytic.blog\/en\/wp-json\/wp\/v2\/categories?post=308"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/medytic.blog\/en\/wp-json\/wp\/v2\/tags?post=308"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}