When we get sick, we tend to think of the illness as bunch of random
symptoms, but viruses don’t behave randomly. They attack the body’s
systems in specific, mathematical patterns. To understand how COVID-19
manifests, data scientists use a technique called Market Basket
Analysis, a technique used initially to figure what items are bought
together. By analyzing thousands of these baskets, hidden connections in
the virus’s behavior are brought to light.
Before running the Apriori algorithm, it is important to analyze the frequencies (Support) of individual symptoms. Fatigue was the dominant complaint, affecting nearly 42% of patients, closely followed by headaches (37%) and body aches (36%). On the other end of the spectrum, severe symptoms like shortness of breath only affected about 8% of individuals. But looking at symptoms in isolation only tells half the story. The real breakthrough comes when we ask which symptoms travel together
itemFrequencyPlot(covid_transactions, topN = 12, type = "relative", col = "darkgreen", main = "Top 10 Most Frequent Items")
After running the Apriori algorithm with the chosen thresholds (supp = 0.05, conf = 0.5), I applied a strict criteria to find the most interesting rules: I looked for combinations that yielded a Lift greater than 2.0 or a Confidence greater than 70%.
Minimum Support = 0.05 (5%): If we set the support threshold too high (e.g., 15%), the algorithm will completely ignore highly specific indicator symptoms like Loss of smell/taste. If we set it too low (e.g., 1%), the model will be overwhelmed by rare, coincidental symptoms . 5% is the perfect balance that captures specific clinical combinations without generating spurious rules.
Minimum Confidence = 0.50 (50%): We only want to look at rules where the there is at least a 50/50 chance that the symptom is also present. This ensures clinical relevance.
inspect(head(rules_sorted, 7))
## lhs rhs support confidence coverage lift count
## [1] {loss_smell_taste,
## aching_body} => {high_temp_or_chills} 0.056 0.6511628 0.086 2.429712 28
## [2] {loss_smell_taste,
## fatigue} => {high_temp_or_chills} 0.066 0.6000000 0.110 2.238806 33
## [3] {new_continuous_cough,
## loss_smell_taste} => {high_temp_or_chills} 0.050 0.5681818 0.088 2.120081 25
## [4] {fatigue,
## aching_body,
## headache} => {high_temp_or_chills} 0.056 0.5600000 0.100 2.089552 28
## [5] {loss_smell_taste} => {high_temp_or_chills} 0.092 0.5542169 0.166 2.067973 46
## [6] {new_continuous_cough,
## fatigue,
## headache} => {high_temp_or_chills} 0.054 0.5400000 0.100 2.014925 27
## [7] {fatigue,
## aching_body} => {high_temp_or_chills} 0.098 0.5384615 0.182 2.009185 49
Here are the two most interesting rules discovered.
Rule 1: {Loss of smell/taste, Aching body} \(\Rightarrow\) {High temp or chills}
Support (5.6%): 5.6% of all patients in the entire dataset experienced all three of these symptoms together.
Confidence (65.1%): If a patient reports a loss of smell/taste and an aching body, there is a 65.1% probability they also have a high temperature or chills.
Lift (2.43): This is the key metric. A lift of 2.43 means that a patient with smell loss and body aches is 2.43 times more likely to have a fever compared to the average patient. This indicates a deeply interconnected viral cluster rather than a coincidence.
Rule 2: {Fatigue, Aching body} \(\Rightarrow\) {High temp or chills}
Support (9.8%): A very solid 9.8% of the dataset shows this exact trio of symptoms, making it a highly prevalent pattern.
Confidence (53.8%): If a patient is experiencing both fatigue and an aching body, there is a greater than 50% chance they are also running a fever.
Lift (2.01): A lift of 2.01 means that a patient with fatigue and body aches is twice as likely to have a high temperature compared to a random patient in the baseline population.
This graph-based visualization is often easier for people to understand quickly how one symptom leads to another:
The text labels are the individual symptoms
The arrows pointing into the dot are the antecedents
The arrows pointing out of a dot are the consequents
The dots themselves represent the actual rules. 10 dots in the graph indicate 10 different rules.
For example:”Loss of smell/taste” and Aching body with arrows pointing into a dark, medium-sized dot. From that dot, an arrow points out to High temp or chills. We would read this as: “When a patient has a loss of smell/taste and an aching body, they are highly likely to also have a high temperature. This is a moderately common pattern (medium dot) and the connection is extremely strong (dark color).”
plot(head(rules_sorted, 10), method = "graph")
Why do these mathematical rules matter outside of a spreadsheet? Because in the real world, predictive data saves time and resources.
If medical professionals know these exact statistical connections they can predict patient deterioration before it happens. If a patient goes to emergency complaining of no taste and body aches, the professionals know a fever is highly probable and can advise the patient accordingly, staying one step ahead of the virus.