Association rules is an unsupervised learning algorithm which is sharpened for the purpose of finding patterns in data such as market basket analysis or customer preferences to create recommendation systems.
Despite the fact that those are the most popular applications, this study shows how the association rules algorithms may help to analyze survey data, and namely, psychological and behavioral questionnaires for mental disorder diagnosis. The current dataset is collected from a private psychology clinic. This dataset comprised 30 samples for each of the Normal, Mania Bipolar Disorder, Depressive Bipolar Disorder, and Major Depressive Disorder categories summing up to 120 patiants. The dataset contains the 17 essential symptoms psychiatrists use to diagnose the described disorders.
Source of dataset: https://dataverse.harvard.edu/dataset.xhtml?persistentId=doi:10.7910/DVN/0FNET5
This implementation may help to better understand the causalities between the patients’ characteristics and symptom patterns, extending beyond simple correlation analysis.
Step-by-step, the work will look as follows:
The data covers four diagnostic categories:
The responses were provided on various scales (Likert-type, YES/NO, and 1-10 ratings). Let us load the data first and look at how it looks like.
# Loading the data
df <- read.csv("Dataset-Mental-Disorders.csv",
stringsAsFactors = FALSE, check.names = FALSE)
# Clean column names
colnames(df) <- gsub("", "", colnames(df))
colnames(df) <- trimws(colnames(df))
# Limiting the data to symptoms and diagnosis
df <- df[complete.cases(df), -1] # Remove patient number
head(df)
## Sadness Euphoric Exhausted Sleep dissorder Mood Swing Suicidal thoughts
## 1 Usually Seldom Sometimes Sometimes YES YES
## 2 Usually Seldom Usually Sometimes NO YES
## 3 Sometimes Most-Often Sometimes Sometimes YES NO
## 4 Usually Seldom Usually Most-Often YES YES
## 5 Usually Usually Sometimes Sometimes NO NO
## 6 Usually Sometimes Sometimes Most-Often NO YES
## Anorxia Authority Respect Try-Explanation Aggressive Response
## 1 NO NO YES NO
## 2 NO NO NO NO
## 3 NO NO YES YES
## 4 YES NO YES NO
## 5 NO NO NO NO
## 6 YES YES NO NO
## Ignore & Move-On Nervous Break-down Admit Mistakes Overthinking
## 1 NO YES YES YES
## 2 NO NO NO NO
## 3 NO YES YES NO
## 4 NO NO NO NO
## 5 NO YES YES YES
## 6 NO NO YES NO
## Sexual Activity Concentration Optimisim Expert Diagnose
## 1 3 From 10 3 From 10 4 From 10 Bipolar Type-2
## 2 4 From 10 2 From 10 5 From 10 Depression
## 3 6 From 10 5 From 10 7 From 10 Bipolar Type-1
## 4 3 From 10 2 From 10 2 From 10 Bipolar Type-2
## 5 5 From 10 5 From 10 6 From 10 Normal
## 6 3 From 10 5 From 10 5 From 10 Depression
str(df)
## 'data.frame': 120 obs. of 18 variables:
## $ Sadness : chr "Usually" "Usually" "Sometimes" "Usually" ...
## $ Euphoric : chr "Seldom" "Seldom" "Most-Often" "Seldom" ...
## $ Exhausted : chr "Sometimes" "Usually" "Sometimes" "Usually" ...
## $ Sleep dissorder : chr "Sometimes" "Sometimes" "Sometimes" "Most-Often" ...
## $ Mood Swing : chr "YES" "NO" "YES" "YES" ...
## $ Suicidal thoughts : chr "YES " "YES" "NO" "YES" ...
## $ Anorxia : chr "NO" "NO" "NO" "YES" ...
## $ Authority Respect : chr "NO" "NO" "NO" "NO" ...
## $ Try-Explanation : chr "YES" "NO" "YES" "YES" ...
## $ Aggressive Response: chr "NO" "NO" "YES" "NO" ...
## $ Ignore & Move-On : chr "NO" "NO" "NO" "NO" ...
## $ Nervous Break-down : chr "YES" "NO" "YES" "NO" ...
## $ Admit Mistakes : chr "YES" "NO" "YES" "NO" ...
## $ Overthinking : chr "YES" "NO" "NO" "NO" ...
## $ Sexual Activity : chr "3 From 10" "4 From 10" "6 From 10" "3 From 10" ...
## $ Concentration : chr "3 From 10" "2 From 10" "5 From 10" "2 From 10" ...
## $ Optimisim : chr "4 From 10" "5 From 10" "7 From 10" "2 From 10" ...
## $ Expert Diagnose : chr "Bipolar Type-2" "Depression" "Bipolar Type-1" "Bipolar Type-2" ...
summary(df)
## Sadness Euphoric Exhausted Sleep dissorder
## Length:120 Length:120 Length:120 Length:120
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
## Mood Swing Suicidal thoughts Anorxia Authority Respect
## Length:120 Length:120 Length:120 Length:120
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
## Try-Explanation Aggressive Response Ignore & Move-On Nervous Break-down
## Length:120 Length:120 Length:120 Length:120
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
## Admit Mistakes Overthinking Sexual Activity Concentration
## Length:120 Length:120 Length:120 Length:120
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
## Optimisim Expert Diagnose
## Length:120 Length:120
## Class :character Class :character
## Mode :character Mode :character
As we see, we have 120 patients with 17 symptom variables and 1 diagnosis variable. The variables are a mix of categorical responses (Seldom, Sometimes, Usually, Most-Often, YES, NO) and rating scales (X From 10).
Following best practices for association rules on psychological data, we need to discretize and prepare the features.
First, let’s examine our target variable:
table(df$`Expert Diagnose`)
##
## Bipolar Type-1 Bipolar Type-2 Depression Normal
## 28 31 31 30
The dataset is fairly balanced across the four diagnostic categories, which is excellent for association rule mining.
We need to:
# Create clean dataset
data <- df
# Clean column names - replace spaces and special characters
colnames(data) <- gsub(" ", "_", colnames(data))
colnames(data) <- gsub("-", "_", colnames(data))
# Trim whitespace from all character columns
data <- data %>%
mutate(across(where(is.character), str_trim))
# Function to categorize ratings from "X From 10" format
# Following psychological survey discretization practices
categorize_rating <- function(x) {
numeric_val <- as.numeric(gsub(" From 10", "", x))
case_when(
numeric_val <= 3 ~ "Low",
numeric_val >= 7 ~ "High",
TRUE ~ "Medium"
)
}
# Apply categorization to rating columns
data <- data %>%
mutate(
Sexual_Activity = categorize_rating(Sexual_Activity),
Concentration = categorize_rating(Concentration),
Optimisim = categorize_rating(Optimisim)
) %>%
rename(
Sleep_Disorder = Sleep_dissorder,
Anorexia = Anorxia,
Ignore_Move_On = `Ignore_&_Move_On`,
Nervous_Breakdown = Nervous_Break_down,
Diagnosis = Expert_Diagnose
)
Now we have preprocessed data ready for transaction format conversion.
For association rules, we need to convert each patient’s symptom profile into a format where each symptom-value combination becomes an analyzable element.
For example, a patient with Bipolar Type-2 might have characteristics
like:
{Mood_Swing=YES, Sadness=Usually, Suicidal_thoughts=YES, Nervous_Breakdown=YES, Diagnosis=Bipolar Type-2, ...}
This allows us to discover patterns such as: “Patients with {Mood Swings=YES, Sadness=Usually} → often have {Diagnosis=Bipolar Type-2}.”
# Create patient profile format for analysis
create_patient_profiles <- function(df) {
profile_list <- list()
for (i in 1:nrow(df)) {
characteristics <- character()
for (col in colnames(df)) {
value <- df[i, col]
if (!is.na(value) && value != "") {
characteristics <- c(characteristics, paste0(col, "=", value))
}
}
profile_list[[i]] <- characteristics
}
return(profile_list)
}
# Convert patient data to analyzable format
patient_profiles <- create_patient_profiles(data)
patient_data <- as(patient_profiles, "transactions")
# Inspect sample patient profiles
inspect(patient_data[1:5])
## items
## [1] {Admit_Mistakes=YES,
## Aggressive_Response=NO,
## Anorexia=NO,
## Authority_Respect=NO,
## Concentration=Low,
## Diagnosis=Bipolar Type-2,
## Euphoric=Seldom,
## Exhausted=Sometimes,
## Ignore_Move_On=NO,
## Mood_Swing=YES,
## Nervous_Breakdown=YES,
## Optimisim=Medium,
## Overthinking=YES,
## Sadness=Usually,
## Sexual_Activity=Low,
## Sleep_Disorder=Sometimes,
## Suicidal_thoughts=YES,
## Try_Explanation=YES}
## [2] {Admit_Mistakes=NO,
## Aggressive_Response=NO,
## Anorexia=NO,
## Authority_Respect=NO,
## Concentration=Low,
## Diagnosis=Depression,
## Euphoric=Seldom,
## Exhausted=Usually,
## Ignore_Move_On=NO,
## Mood_Swing=NO,
## Nervous_Breakdown=NO,
## Optimisim=Medium,
## Overthinking=NO,
## Sadness=Usually,
## Sexual_Activity=Medium,
## Sleep_Disorder=Sometimes,
## Suicidal_thoughts=YES,
## Try_Explanation=NO}
## [3] {Admit_Mistakes=YES,
## Aggressive_Response=YES,
## Anorexia=NO,
## Authority_Respect=NO,
## Concentration=Medium,
## Diagnosis=Bipolar Type-1,
## Euphoric=Most-Often,
## Exhausted=Sometimes,
## Ignore_Move_On=NO,
## Mood_Swing=YES,
## Nervous_Breakdown=YES,
## Optimisim=High,
## Overthinking=NO,
## Sadness=Sometimes,
## Sexual_Activity=Medium,
## Sleep_Disorder=Sometimes,
## Suicidal_thoughts=NO,
## Try_Explanation=YES}
## [4] {Admit_Mistakes=NO,
## Aggressive_Response=NO,
## Anorexia=YES,
## Authority_Respect=NO,
## Concentration=Low,
## Diagnosis=Bipolar Type-2,
## Euphoric=Seldom,
## Exhausted=Usually,
## Ignore_Move_On=NO,
## Mood_Swing=YES,
## Nervous_Breakdown=NO,
## Optimisim=Low,
## Overthinking=NO,
## Sadness=Usually,
## Sexual_Activity=Low,
## Sleep_Disorder=Most-Often,
## Suicidal_thoughts=YES,
## Try_Explanation=YES}
## [5] {Admit_Mistakes=YES,
## Aggressive_Response=NO,
## Anorexia=NO,
## Authority_Respect=NO,
## Concentration=Medium,
## Diagnosis=Normal,
## Euphoric=Usually,
## Exhausted=Sometimes,
## Ignore_Move_On=NO,
## Mood_Swing=NO,
## Nervous_Breakdown=YES,
## Optimisim=Medium,
## Overthinking=YES,
## Sadness=Usually,
## Sexual_Activity=Medium,
## Sleep_Disorder=Sometimes,
## Suicidal_thoughts=NO,
## Try_Explanation=NO}
summary(patient_data)
## transactions as itemMatrix in sparse format with
## 120 rows (elements/itemsets/transactions) and
## 49 columns (items) and a density of 0.3673469
##
## most frequent items:
## Anorexia=NO Authority_Respect=NO Ignore_Move_On=NO
## 74 73 70
## Overthinking=YES Concentration=Medium (Other)
## 65 64 1814
##
## element (itemset/transaction) length distribution:
## sizes
## 18
## 120
##
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 18 18 18 18 18 18
##
## includes extended item information - examples:
## labels
## 1 Admit_Mistakes=NO
## 2 Admit_Mistakes=YES
## 3 Aggressive_Response=NO
So, now we have 120 patient profiles encoded as symptom-value combinations.
Next, we check the most frequent symptom-value combinations in our dataset:
sort(round(itemFrequency(patient_data), 3), decreasing = TRUE)[1:20]
## Anorexia=NO Authority_Respect=NO Ignore_Move_On=NO
## 0.617 0.608 0.583
## Overthinking=YES Concentration=Medium Mood_Swing=NO
## 0.542 0.533 0.525
## Suicidal_thoughts=NO Try_Explanation=NO Aggressive_Response=NO
## 0.525 0.525 0.517
## Nervous_Breakdown=YES Admit_Mistakes=NO Optimisim=Medium
## 0.517 0.508 0.500
## Admit_Mistakes=YES Aggressive_Response=YES Nervous_Breakdown=NO
## 0.492 0.483 0.483
## Mood_Swing=YES Sexual_Activity=Medium Suicidal_thoughts=YES
## 0.475 0.475 0.475
## Try_Explanation=YES Overthinking=NO
## 0.475 0.458
itemFrequencyPlot(patient_data, topN = 30, type = "relative",
main = "Top 30 Most Common Symptom-Value Combinations",
cex.names = 0.7, las = 2)
So, we can see the distribution of the most common symptom characteristics in our patient population.
A useful way to examine symptom co-occurrence is through cross-tabulation tables showing both support and lift measures for symptom pairs.
# Support cross-table: How often do symptom pairs occur together?
sup_tab <- crossTable(patient_data, measure = "support", sort = TRUE)
round(sup_tab[1:10, 1:10], 3)
## Anorexia=NO Authority_Respect=NO Ignore_Move_On=NO
## Anorexia=NO 0.617 0.367 0.350
## Authority_Respect=NO 0.367 0.608 0.417
## Ignore_Move_On=NO 0.350 0.417 0.583
## Overthinking=YES 0.325 0.333 0.308
## Concentration=Medium 0.367 0.325 0.283
## Mood_Swing=NO 0.375 0.308 0.275
## Suicidal_thoughts=NO 0.358 0.292 0.317
## Try_Explanation=NO 0.350 0.275 0.283
## Aggressive_Response=NO 0.367 0.283 0.267
## Nervous_Breakdown=YES 0.283 0.325 0.292
## Overthinking=YES Concentration=Medium Mood_Swing=NO
## Anorexia=NO 0.325 0.367 0.375
## Authority_Respect=NO 0.333 0.325 0.308
## Ignore_Move_On=NO 0.308 0.283 0.275
## Overthinking=YES 0.542 0.258 0.283
## Concentration=Medium 0.258 0.533 0.300
## Mood_Swing=NO 0.283 0.300 0.525
## Suicidal_thoughts=NO 0.267 0.300 0.317
## Try_Explanation=NO 0.292 0.308 0.292
## Aggressive_Response=NO 0.283 0.292 0.333
## Nervous_Breakdown=YES 0.308 0.250 0.217
## Suicidal_thoughts=NO Try_Explanation=NO
## Anorexia=NO 0.358 0.350
## Authority_Respect=NO 0.292 0.275
## Ignore_Move_On=NO 0.317 0.283
## Overthinking=YES 0.267 0.292
## Concentration=Medium 0.300 0.308
## Mood_Swing=NO 0.317 0.292
## Suicidal_thoughts=NO 0.525 0.300
## Try_Explanation=NO 0.300 0.525
## Aggressive_Response=NO 0.250 0.267
## Nervous_Breakdown=YES 0.233 0.258
## Aggressive_Response=NO Nervous_Breakdown=YES
## Anorexia=NO 0.367 0.283
## Authority_Respect=NO 0.283 0.325
## Ignore_Move_On=NO 0.267 0.292
## Overthinking=YES 0.283 0.308
## Concentration=Medium 0.292 0.250
## Mood_Swing=NO 0.333 0.217
## Suicidal_thoughts=NO 0.250 0.233
## Try_Explanation=NO 0.267 0.258
## Aggressive_Response=NO 0.517 0.258
## Nervous_Breakdown=YES 0.258 0.517
# Lift cross-table: How much more often than random do pairs occur?
lift_tab <- crossTable(patient_data, measure = "lift", sort = TRUE)
round(lift_tab[1:10, 1:10], 3)
## Anorexia=NO Authority_Respect=NO Ignore_Move_On=NO
## Anorexia=NO NA 0.977 0.973
## Authority_Respect=NO 0.977 NA 1.174
## Ignore_Move_On=NO 0.973 1.174 NA
## Overthinking=YES 0.973 1.012 0.976
## Concentration=Medium 1.115 1.002 0.911
## Mood_Swing=NO 1.158 0.965 0.898
## Suicidal_thoughts=NO 1.107 0.913 1.034
## Try_Explanation=NO 1.081 0.861 0.925
## Aggressive_Response=NO 1.151 0.901 0.885
## Nervous_Breakdown=YES 0.889 1.034 0.968
## Overthinking=YES Concentration=Medium Mood_Swing=NO
## Anorexia=NO 0.973 1.115 1.158
## Authority_Respect=NO 1.012 1.002 0.965
## Ignore_Move_On=NO 0.976 0.911 0.898
## Overthinking=YES NA 0.894 0.996
## Concentration=Medium 0.894 NA 1.071
## Mood_Swing=NO 0.996 1.071 NA
## Suicidal_thoughts=NO 0.938 1.071 1.149
## Try_Explanation=NO 1.026 1.101 1.058
## Aggressive_Response=NO 1.012 1.058 1.229
## Nervous_Breakdown=YES 1.102 0.907 0.799
## Suicidal_thoughts=NO Try_Explanation=NO
## Anorexia=NO 1.107 1.081
## Authority_Respect=NO 0.913 0.861
## Ignore_Move_On=NO 1.034 0.925
## Overthinking=YES 0.938 1.026
## Concentration=Medium 1.071 1.101
## Mood_Swing=NO 1.149 1.058
## Suicidal_thoughts=NO NA 1.088
## Try_Explanation=NO 1.088 NA
## Aggressive_Response=NO 0.922 0.983
## Nervous_Breakdown=YES 0.860 0.952
## Aggressive_Response=NO Nervous_Breakdown=YES
## Anorexia=NO 1.151 0.889
## Authority_Respect=NO 0.901 1.034
## Ignore_Move_On=NO 0.885 0.968
## Overthinking=YES 1.012 1.102
## Concentration=Medium 1.058 0.907
## Mood_Swing=NO 1.229 0.799
## Suicidal_thoughts=NO 0.922 0.860
## Try_Explanation=NO 0.983 0.952
## Aggressive_Response=NO NA 0.968
## Nervous_Breakdown=YES 0.968 NA
These tables show us how frequently symptom pairs occur together (support) and how their co-occurrence compares to what we’d expect if symptoms were independent (lift).
Lets check the symptoms by Diagnosis.
par(mfrow = c(2, 2), mar = c(8, 4, 3, 1))
for (d in c("Bipolar Type-1", "Bipolar Type-2", "Depression", "Normal")) {
s <- subset(patient_data, items %in% paste0("Diagnosis=", d))[, !grepl("Diagnosis", itemLabels(patient_data))]
itemFrequencyPlot(s, topN = 5, main = d, cex.names = 0.9, las = 2)
}
par(mfrow = c(1, 1))
For discovering associations in psychological characteristics, we use
the Apriori algorithm. In R, the arules
and arulesViz packages are used.
To determine which symptom patterns are clinically relevant, we focus on 3 key measures:
Support indicates how frequently a symptom pattern appears in the patient population:
\[\text{Support}(X) = \frac{\text{frequency}(X)}{n}\]
Confidence tells us the conditional probability - what proportion of patients with symptom pattern X also have outcome Y:
\[\text{Confidence}(X \Rightarrow Y) = \frac{P(X \cap Y)}{P(X)} = P(Y|X)\]
Lift compares observed co-occurrence vs. expected co-occurrence if symptoms were independent:
\[\text{Lift}(X \Rightarrow Y) = \frac{P(X \cap Y)}{P(X) \times P(Y)}\]
To identify clinically meaningful associations: - Support: Should be substantial enough (we use >= 10% for general patterns, >= 5% for diagnosis-specific) - Confidence: Higher is better (we use >= 60% for reliable patterns) - Lift: Greater than 1 indicates positive association (the higher, the stronger)
We begin by mining general patterns with moderate parameters to identify the most common and reliable symptom associations across all patients.
# Mining symptom patterns with moderate parameters
rules_general <- apriori(patient_data, parameter = list(supp = 0.1, conf = 0.7))
## Apriori
##
## Parameter specification:
## confidence minval smax arem aval originalSupport maxtime support minlen
## 0.7 0.1 1 none FALSE TRUE 5 0.1 1
## maxlen target ext
## 10 rules TRUE
##
## Algorithmic control:
## filter tree heap memopt load sort verbose
## 0.1 TRUE TRUE FALSE TRUE 2 TRUE
##
## Absolute minimum support count: 12
##
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[49 item(s), 120 transaction(s)] done [0.00s].
## sorting and recoding items ... [48 item(s)] done [0.00s].
## creating transaction tree ... done [0.00s].
## checking subsets of size 1 2 3 4 5 6 7 done [0.00s].
## writing ... [6156 rule(s)] done [0.00s].
## creating S4 object ... done [0.00s].
rules_byconf <- sort(rules_general, by = "confidence", decreasing = TRUE)
inspect(head(rules_byconf, 10), digits = 2, linebreak = FALSE)
## lhs
## [1] {Diagnosis=Bipolar Type-2} =>
## [2] {Diagnosis=Depression} =>
## [3] {Diagnosis=Bipolar Type-1, Optimisim=High} =>
## [4] {Authority_Respect=NO, Optimisim=High} =>
## [5] {Diagnosis=Depression, Sadness=Most-Often} =>
## [6] {Mood_Swing=NO, Sadness=Most-Often} =>
## [7] {Diagnosis=Bipolar Type-1, Sexual_Activity=High} =>
## [8] {Sexual_Activity=High, Suicidal_thoughts=YES} =>
## [9] {Ignore_Move_On=NO, Sexual_Activity=High} =>
## [10] {Diagnosis=Bipolar Type-1, Sadness=Sometimes} =>
## rhs support confidence coverage lift count
## [1] {Mood_Swing=YES} 0.2583333 1 0.2583333 2.105263 31
## [2] {Mood_Swing=NO} 0.2583333 1 0.2583333 1.904762 31
## [3] {Aggressive_Response=YES} 0.1000000 1 0.1000000 2.068966 12
## [4] {Aggressive_Response=YES} 0.1166667 1 0.1166667 2.068966 14
## [5] {Mood_Swing=NO} 0.1000000 1 0.1000000 1.904762 12
## [6] {Diagnosis=Depression} 0.1000000 1 0.1000000 3.870968 12
## [7] {Mood_Swing=YES} 0.1166667 1 0.1166667 2.105263 14
## [8] {Authority_Respect=NO} 0.1000000 1 0.1000000 1.643836 12
## [9] {Authority_Respect=NO} 0.1416667 1 0.1416667 1.643836 17
## [10] {Ignore_Move_On=NO} 0.1000000 1 0.1000000 1.714286 12
rules_bylift <- head(sort(rules_general, by = "lift", decreasing = TRUE), 10)
inspect(rules_bylift, digits = 2, linebreak = FALSE)
## lhs
## [1] {Exhausted=Sometimes, Mood_Swing=NO, Optimisim=Medium, Suicidal_thoughts=NO}
## [2] {Authority_Respect=YES, Mood_Swing=NO, Nervous_Breakdown=NO, Sadness=Sometimes}
## [3] {Anorexia=NO, Authority_Respect=YES, Mood_Swing=NO, Sadness=Sometimes}
## [4] {Mood_Swing=NO, Overthinking=NO, Sadness=Sometimes, Suicidal_thoughts=NO}
## [5] {Mood_Swing=NO, Nervous_Breakdown=NO, Sadness=Sometimes, Suicidal_thoughts=NO}
## [6] {Concentration=Medium, Mood_Swing=NO, Sadness=Sometimes, Suicidal_thoughts=NO}
## [7] {Anorexia=NO, Mood_Swing=NO, Sadness=Sometimes, Suicidal_thoughts=NO}
## [8] {Authority_Respect=YES, Mood_Swing=NO, Overthinking=NO, Suicidal_thoughts=NO}
## [9] {Authority_Respect=YES, Mood_Swing=NO, Nervous_Breakdown=NO, Suicidal_thoughts=NO}
## [10] {Anorexia=NO, Authority_Respect=YES, Mood_Swing=NO, Optimisim=Medium}
## rhs support confidence coverage lift count
## [1] => {Diagnosis=Normal} 0.1000000 1 0.1000000 4 12
## [2] => {Diagnosis=Normal} 0.1000000 1 0.1000000 4 12
## [3] => {Diagnosis=Normal} 0.1083333 1 0.1083333 4 13
## [4] => {Diagnosis=Normal} 0.1083333 1 0.1083333 4 13
## [5] => {Diagnosis=Normal} 0.1083333 1 0.1083333 4 13
## [6] => {Diagnosis=Normal} 0.1000000 1 0.1000000 4 12
## [7] => {Diagnosis=Normal} 0.1166667 1 0.1166667 4 14
## [8] => {Diagnosis=Normal} 0.1000000 1 0.1000000 4 12
## [9] => {Diagnosis=Normal} 0.1166667 1 0.1166667 4 14
## [10] => {Diagnosis=Normal} 0.1000000 1 0.1000000 4 12
As we see, some strong patterns are emerging. Let’s visualize these rules.
# Parallel coordinates plot (limit to top 25 for performance)
plot(rules_bylift, method = "paracoord", control = list(reorder = TRUE),
main = paste("Parallel Coordinates Plot -", length(rules_bylift), "Rules"))
# Graph visualization
rules_graph <- head(sort(rules_general, by = "lift", decreasing = TRUE), 40)
plot(rules_graph, method = "graph",
measure = "support", shading = "lift",
main = "Network Graph of Association Rules")
## Available control parameters (with default values):
## layout = stress
## circular = FALSE
## ggraphdots = NULL
## edges = <environment>
## nodes = <environment>
## nodetext = <environment>
## colors = c("#EE0000FF", "#EEEEEEFF")
## engine = ggplot2
## max = 100
## verbose = FALSE
However, to better understand the diagnostic patterns, we need to check specific consequents (diagnoses).
Now we will examine rules that predict each specific diagnosis.
What symptom combinations are characteristic of patients diagnosed with Bipolar Type-1? We mine rules where the diagnosis appears as the consequent.
rules_bipolar1 <- apriori(data = patient_data,
parameter = list(supp = 0.1, conf = 0.6),
appearance = list(default = "lhs",
rhs = "Diagnosis=Bipolar Type-1"),
control = list(verbose = FALSE))
cat("Found", length(rules_bipolar1), "rules for Bipolar Type-1\n\n")
## Found 24 rules for Bipolar Type-1
inspect(sort(rules_bipolar1, by = "confidence", decreasing = TRUE)[1:10], digits = 2, linebreak = FALSE)
## lhs
## [1] {Aggressive_Response=YES, Mood_Swing=YES, Sexual_Activity=High}
## [2] {Mood_Swing=YES, Sexual_Activity=High}
## [3] {Authority_Respect=NO, Mood_Swing=YES, Sexual_Activity=High}
## [4] {Aggressive_Response=YES, Mood_Swing=YES, Suicidal_thoughts=NO}
## [5] {Aggressive_Response=YES, Optimisim=High}
## [6] {Aggressive_Response=YES, Authority_Respect=NO, Ignore_Move_On=NO, Mood_Swing=YES}
## [7] {Aggressive_Response=YES, Authority_Respect=NO, Mood_Swing=YES}
## [8] {Authority_Respect=NO, Mood_Swing=YES, Suicidal_thoughts=NO}
## [9] {Anorexia=YES, Authority_Respect=NO, Ignore_Move_On=NO, Mood_Swing=YES}
## [10] {Admit_Mistakes=NO, Authority_Respect=NO, Ignore_Move_On=NO, Mood_Swing=YES}
## rhs support confidence coverage lift
## [1] => {Diagnosis=Bipolar Type-1} 0.1000000 0.8571429 0.1166667 3.673469
## [2] => {Diagnosis=Bipolar Type-1} 0.1166667 0.8235294 0.1416667 3.529412
## [3] => {Diagnosis=Bipolar Type-1} 0.1083333 0.8125000 0.1333333 3.482143
## [4] => {Diagnosis=Bipolar Type-1} 0.1166667 0.7777778 0.1500000 3.333333
## [5] => {Diagnosis=Bipolar Type-1} 0.1000000 0.7500000 0.1333333 3.214286
## [6] => {Diagnosis=Bipolar Type-1} 0.1250000 0.7500000 0.1666667 3.214286
## [7] => {Diagnosis=Bipolar Type-1} 0.1416667 0.7083333 0.2000000 3.035714
## [8] => {Diagnosis=Bipolar Type-1} 0.1000000 0.7058824 0.1416667 3.025210
## [9] => {Diagnosis=Bipolar Type-1} 0.1000000 0.7058824 0.1416667 3.025210
## [10] => {Diagnosis=Bipolar Type-1} 0.1000000 0.7058824 0.1416667 3.025210
## count
## [1] 12
## [2] 14
## [3] 13
## [4] 14
## [5] 12
## [6] 15
## [7] 17
## [8] 12
## [9] 12
## [10] 12
inspect(sort(rules_bipolar1, by = "lift", decreasing = TRUE)[1:10], digits = 2, linebreak = FALSE)
## lhs
## [1] {Aggressive_Response=YES, Mood_Swing=YES, Sexual_Activity=High}
## [2] {Mood_Swing=YES, Sexual_Activity=High}
## [3] {Authority_Respect=NO, Mood_Swing=YES, Sexual_Activity=High}
## [4] {Aggressive_Response=YES, Mood_Swing=YES, Suicidal_thoughts=NO}
## [5] {Aggressive_Response=YES, Optimisim=High}
## [6] {Aggressive_Response=YES, Authority_Respect=NO, Ignore_Move_On=NO, Mood_Swing=YES}
## [7] {Aggressive_Response=YES, Authority_Respect=NO, Mood_Swing=YES}
## [8] {Authority_Respect=NO, Mood_Swing=YES, Suicidal_thoughts=NO}
## [9] {Anorexia=YES, Authority_Respect=NO, Ignore_Move_On=NO, Mood_Swing=YES}
## [10] {Admit_Mistakes=NO, Authority_Respect=NO, Ignore_Move_On=NO, Mood_Swing=YES}
## rhs support confidence coverage lift
## [1] => {Diagnosis=Bipolar Type-1} 0.1000000 0.8571429 0.1166667 3.673469
## [2] => {Diagnosis=Bipolar Type-1} 0.1166667 0.8235294 0.1416667 3.529412
## [3] => {Diagnosis=Bipolar Type-1} 0.1083333 0.8125000 0.1333333 3.482143
## [4] => {Diagnosis=Bipolar Type-1} 0.1166667 0.7777778 0.1500000 3.333333
## [5] => {Diagnosis=Bipolar Type-1} 0.1000000 0.7500000 0.1333333 3.214286
## [6] => {Diagnosis=Bipolar Type-1} 0.1250000 0.7500000 0.1666667 3.214286
## [7] => {Diagnosis=Bipolar Type-1} 0.1416667 0.7083333 0.2000000 3.035714
## [8] => {Diagnosis=Bipolar Type-1} 0.1000000 0.7058824 0.1416667 3.025210
## [9] => {Diagnosis=Bipolar Type-1} 0.1000000 0.7058824 0.1416667 3.025210
## [10] => {Diagnosis=Bipolar Type-1} 0.1000000 0.7058824 0.1416667 3.025210
## count
## [1] 12
## [2] 14
## [3] 13
## [4] 14
## [5] 12
## [6] 15
## [7] 17
## [8] 12
## [9] 12
## [10] 12
rules_viz <- head(sort(rules_bipolar1, by = "lift", decreasing = TRUE), 10)
plot(rules_viz, method = "paracoord", control = list(reorder = TRUE), main = "Symptom Patterns Leading to Bipolar Type-1")
plot(rules_bipolar1, method="grouped")
Interpretation: Looking at the rules, we can see that Bipolar Type-1 is strongly associated with mood swings, no authority respect and **aggressive responses.
What distinguishes Bipolar Type-2 from other diagnoses?
rules_bipolar2 <- apriori(data = patient_data,
parameter = list(supp = 0.1, conf = 0.6),
appearance = list(default = "lhs",
rhs = "Diagnosis=Bipolar Type-2"),
control = list(verbose = FALSE))
cat("Found", length(rules_bipolar2), "rules for Bipolar Type-2\n\n")
## Found 35 rules for Bipolar Type-2
inspect(sort(rules_bipolar2, by = "confidence", decreasing = TRUE)[1:10], digits = 2, linebreak = FALSE)
## lhs
## [1] {Mood_Swing=YES, Sadness=Usually, Sexual_Activity=Low} =>
## [2] {Mood_Swing=YES, Optimisim=Low, Suicidal_thoughts=YES} =>
## [3] {Ignore_Move_On=YES, Mood_Swing=YES, Suicidal_thoughts=YES} =>
## [4] {Mood_Swing=YES, Sexual_Activity=Low} =>
## [5] {Euphoric=Seldom, Mood_Swing=YES, Suicidal_thoughts=YES} =>
## [6] {Mood_Swing=YES, Sexual_Activity=Low, Suicidal_thoughts=YES} =>
## [7] {Authority_Respect=YES, Mood_Swing=YES, Suicidal_thoughts=YES} =>
## [8] {Mood_Swing=YES, Optimisim=Low} =>
## [9] {Aggressive_Response=NO, Mood_Swing=YES, Suicidal_thoughts=YES} =>
## [10] {Aggressive_Response=NO, Mood_Swing=YES, Nervous_Breakdown=YES} =>
## rhs support confidence coverage lift count
## [1] {Diagnosis=Bipolar Type-2} 0.1000000 1.0000000 0.1000000 3.870968 12
## [2] {Diagnosis=Bipolar Type-2} 0.1000000 1.0000000 0.1000000 3.870968 12
## [3] {Diagnosis=Bipolar Type-2} 0.1000000 1.0000000 0.1000000 3.870968 12
## [4] {Diagnosis=Bipolar Type-2} 0.1500000 0.9473684 0.1583333 3.667233 18
## [5] {Diagnosis=Bipolar Type-2} 0.1166667 0.9333333 0.1250000 3.612903 14
## [6] {Diagnosis=Bipolar Type-2} 0.1083333 0.9285714 0.1166667 3.594470 13
## [7] {Diagnosis=Bipolar Type-2} 0.1000000 0.9230769 0.1083333 3.573201 12
## [8] {Diagnosis=Bipolar Type-2} 0.1333333 0.8888889 0.1500000 3.440860 16
## [9] {Diagnosis=Bipolar Type-2} 0.1083333 0.8666667 0.1250000 3.354839 13
## [10] {Diagnosis=Bipolar Type-2} 0.1083333 0.8666667 0.1250000 3.354839 13
inspect(sort(rules_bipolar2, by = "lift", decreasing = TRUE)[1:10], digits = 2, linebreak = FALSE)
## lhs
## [1] {Mood_Swing=YES, Sadness=Usually, Sexual_Activity=Low} =>
## [2] {Mood_Swing=YES, Optimisim=Low, Suicidal_thoughts=YES} =>
## [3] {Ignore_Move_On=YES, Mood_Swing=YES, Suicidal_thoughts=YES} =>
## [4] {Mood_Swing=YES, Sexual_Activity=Low} =>
## [5] {Euphoric=Seldom, Mood_Swing=YES, Suicidal_thoughts=YES} =>
## [6] {Mood_Swing=YES, Sexual_Activity=Low, Suicidal_thoughts=YES} =>
## [7] {Authority_Respect=YES, Mood_Swing=YES, Suicidal_thoughts=YES} =>
## [8] {Mood_Swing=YES, Optimisim=Low} =>
## [9] {Aggressive_Response=NO, Mood_Swing=YES, Suicidal_thoughts=YES} =>
## [10] {Aggressive_Response=NO, Mood_Swing=YES, Nervous_Breakdown=YES} =>
## rhs support confidence coverage lift count
## [1] {Diagnosis=Bipolar Type-2} 0.1000000 1.0000000 0.1000000 3.870968 12
## [2] {Diagnosis=Bipolar Type-2} 0.1000000 1.0000000 0.1000000 3.870968 12
## [3] {Diagnosis=Bipolar Type-2} 0.1000000 1.0000000 0.1000000 3.870968 12
## [4] {Diagnosis=Bipolar Type-2} 0.1500000 0.9473684 0.1583333 3.667233 18
## [5] {Diagnosis=Bipolar Type-2} 0.1166667 0.9333333 0.1250000 3.612903 14
## [6] {Diagnosis=Bipolar Type-2} 0.1083333 0.9285714 0.1166667 3.594470 13
## [7] {Diagnosis=Bipolar Type-2} 0.1000000 0.9230769 0.1083333 3.573201 12
## [8] {Diagnosis=Bipolar Type-2} 0.1333333 0.8888889 0.1500000 3.440860 16
## [9] {Diagnosis=Bipolar Type-2} 0.1083333 0.8666667 0.1250000 3.354839 13
## [10] {Diagnosis=Bipolar Type-2} 0.1083333 0.8666667 0.1250000 3.354839 13
rules_viz <- head(sort(rules_bipolar2, by = "lift", decreasing = TRUE), 10)
plot(rules_viz, method = "paracoord", control = list(reorder = TRUE),
main = "Symptom Patterns Leading to Bipolar Type-2")
plot(rules_bipolar2, method="grouped")
Interpretation: Bipolar Type-2 shows a distinct pattern characterized by mood swings with low optimism and suicidal thoughts, along with nervous breakdowns.
What symptom combinations differentiate Major Depressive Disorder from bipolar disorders?
rules_depression <- apriori(data = patient_data,
parameter = list(supp = 0.1, conf = 0.6),
appearance = list(default = "lhs",
rhs = "Diagnosis=Depression"),
control = list(verbose = FALSE))
cat("Found", length(rules_depression), "rules for Depression\n\n")
## Found 107 rules for Depression
inspect(sort(rules_depression, by = "confidence", decreasing = TRUE)[1:10], digits = 2, linebreak = FALSE)
## lhs
## [1] {Mood_Swing=NO, Sadness=Most-Often}
## [2] {Mood_Swing=NO, Optimisim=Low, Suicidal_thoughts=YES}
## [3] {Mood_Swing=NO, Optimisim=Low, Overthinking=YES}
## [4] {Euphoric=Seldom, Mood_Swing=NO, Suicidal_thoughts=YES}
## [5] {Euphoric=Seldom, Mood_Swing=NO, Overthinking=YES}
## [6] {Euphoric=Seldom, Mood_Swing=NO, Optimisim=Low, Overthinking=YES}
## [7] {Aggressive_Response=NO, Mood_Swing=NO, Optimisim=Low, Suicidal_thoughts=YES}
## [8] {Mood_Swing=NO, Optimisim=Low, Overthinking=YES, Suicidal_thoughts=YES}
## [9] {Authority_Respect=NO, Mood_Swing=NO, Optimisim=Low, Suicidal_thoughts=YES}
## [10] {Anorexia=NO, Mood_Swing=NO, Optimisim=Low, Suicidal_thoughts=YES}
## rhs support confidence coverage lift count
## [1] => {Diagnosis=Depression} 0.1000000 1 0.1000000 3.870968 12
## [2] => {Diagnosis=Depression} 0.1333333 1 0.1333333 3.870968 16
## [3] => {Diagnosis=Depression} 0.1333333 1 0.1333333 3.870968 16
## [4] => {Diagnosis=Depression} 0.1000000 1 0.1000000 3.870968 12
## [5] => {Diagnosis=Depression} 0.1333333 1 0.1333333 3.870968 16
## [6] => {Diagnosis=Depression} 0.1000000 1 0.1000000 3.870968 12
## [7] => {Diagnosis=Depression} 0.1083333 1 0.1083333 3.870968 13
## [8] => {Diagnosis=Depression} 0.1083333 1 0.1083333 3.870968 13
## [9] => {Diagnosis=Depression} 0.1000000 1 0.1000000 3.870968 12
## [10] => {Diagnosis=Depression} 0.1000000 1 0.1000000 3.870968 12
inspect(sort(rules_depression, by = "lift", decreasing = TRUE)[1:10], digits = 2, linebreak = FALSE)
## lhs
## [1] {Mood_Swing=NO, Sadness=Most-Often}
## [2] {Mood_Swing=NO, Optimisim=Low, Suicidal_thoughts=YES}
## [3] {Mood_Swing=NO, Optimisim=Low, Overthinking=YES}
## [4] {Euphoric=Seldom, Mood_Swing=NO, Suicidal_thoughts=YES}
## [5] {Euphoric=Seldom, Mood_Swing=NO, Overthinking=YES}
## [6] {Euphoric=Seldom, Mood_Swing=NO, Optimisim=Low, Overthinking=YES}
## [7] {Aggressive_Response=NO, Mood_Swing=NO, Optimisim=Low, Suicidal_thoughts=YES}
## [8] {Mood_Swing=NO, Optimisim=Low, Overthinking=YES, Suicidal_thoughts=YES}
## [9] {Authority_Respect=NO, Mood_Swing=NO, Optimisim=Low, Suicidal_thoughts=YES}
## [10] {Anorexia=NO, Mood_Swing=NO, Optimisim=Low, Suicidal_thoughts=YES}
## rhs support confidence coverage lift count
## [1] => {Diagnosis=Depression} 0.1000000 1 0.1000000 3.870968 12
## [2] => {Diagnosis=Depression} 0.1333333 1 0.1333333 3.870968 16
## [3] => {Diagnosis=Depression} 0.1333333 1 0.1333333 3.870968 16
## [4] => {Diagnosis=Depression} 0.1000000 1 0.1000000 3.870968 12
## [5] => {Diagnosis=Depression} 0.1333333 1 0.1333333 3.870968 16
## [6] => {Diagnosis=Depression} 0.1000000 1 0.1000000 3.870968 12
## [7] => {Diagnosis=Depression} 0.1083333 1 0.1083333 3.870968 13
## [8] => {Diagnosis=Depression} 0.1083333 1 0.1083333 3.870968 13
## [9] => {Diagnosis=Depression} 0.1000000 1 0.1000000 3.870968 12
## [10] => {Diagnosis=Depression} 0.1000000 1 0.1000000 3.870968 12
rules_viz <- head(sort(rules_depression, by = "lift", decreasing = TRUE), 10)
plot(rules_viz, method = "paracoord", control = list(reorder = TRUE),
main = "Symptom Patterns Leading to Depression")
plot(rules_depression, method="grouped")
Interpretation: Depression is characterized by the ABSENCE of mood swings (a key differentiator from bipolar disorders), combined with suicidal thoughts and overthinking. The high confidence rules show that when mood swings are absent but suicidal ideation is present, depression is highly likely.
What patterns characterize individuals without mental health disorders?
rules_normal <- apriori(data = patient_data,
parameter = list(supp = 0.1, conf = 0.6),
appearance = list(default = "lhs",
rhs = "Diagnosis=Normal"),
control = list(verbose = FALSE))
cat("Found", length(rules_normal), "rules for Normal\n\n")
## Found 372 rules for Normal
inspect(sort(rules_normal, by = "confidence", decreasing = TRUE)[1:10], digits = 2, linebreak = FALSE)
## lhs
## [1] {Exhausted=Sometimes, Mood_Swing=NO, Optimisim=Medium, Suicidal_thoughts=NO}
## [2] {Authority_Respect=YES, Mood_Swing=NO, Nervous_Breakdown=NO, Sadness=Sometimes}
## [3] {Anorexia=NO, Authority_Respect=YES, Mood_Swing=NO, Sadness=Sometimes}
## [4] {Mood_Swing=NO, Overthinking=NO, Sadness=Sometimes, Suicidal_thoughts=NO}
## [5] {Mood_Swing=NO, Nervous_Breakdown=NO, Sadness=Sometimes, Suicidal_thoughts=NO}
## [6] {Concentration=Medium, Mood_Swing=NO, Sadness=Sometimes, Suicidal_thoughts=NO}
## [7] {Anorexia=NO, Mood_Swing=NO, Sadness=Sometimes, Suicidal_thoughts=NO}
## [8] {Authority_Respect=YES, Mood_Swing=NO, Overthinking=NO, Suicidal_thoughts=NO}
## [9] {Authority_Respect=YES, Mood_Swing=NO, Nervous_Breakdown=NO, Suicidal_thoughts=NO}
## [10] {Anorexia=NO, Authority_Respect=YES, Mood_Swing=NO, Optimisim=Medium}
## rhs support confidence coverage lift count
## [1] => {Diagnosis=Normal} 0.1000000 1 0.1000000 4 12
## [2] => {Diagnosis=Normal} 0.1000000 1 0.1000000 4 12
## [3] => {Diagnosis=Normal} 0.1083333 1 0.1083333 4 13
## [4] => {Diagnosis=Normal} 0.1083333 1 0.1083333 4 13
## [5] => {Diagnosis=Normal} 0.1083333 1 0.1083333 4 13
## [6] => {Diagnosis=Normal} 0.1000000 1 0.1000000 4 12
## [7] => {Diagnosis=Normal} 0.1166667 1 0.1166667 4 14
## [8] => {Diagnosis=Normal} 0.1000000 1 0.1000000 4 12
## [9] => {Diagnosis=Normal} 0.1166667 1 0.1166667 4 14
## [10] => {Diagnosis=Normal} 0.1000000 1 0.1000000 4 12
inspect(sort(rules_normal, by = "lift", decreasing = TRUE)[1:10], digits = 2, linebreak = FALSE)
## lhs
## [1] {Exhausted=Sometimes, Mood_Swing=NO, Optimisim=Medium, Suicidal_thoughts=NO}
## [2] {Authority_Respect=YES, Mood_Swing=NO, Nervous_Breakdown=NO, Sadness=Sometimes}
## [3] {Anorexia=NO, Authority_Respect=YES, Mood_Swing=NO, Sadness=Sometimes}
## [4] {Mood_Swing=NO, Overthinking=NO, Sadness=Sometimes, Suicidal_thoughts=NO}
## [5] {Mood_Swing=NO, Nervous_Breakdown=NO, Sadness=Sometimes, Suicidal_thoughts=NO}
## [6] {Concentration=Medium, Mood_Swing=NO, Sadness=Sometimes, Suicidal_thoughts=NO}
## [7] {Anorexia=NO, Mood_Swing=NO, Sadness=Sometimes, Suicidal_thoughts=NO}
## [8] {Authority_Respect=YES, Mood_Swing=NO, Overthinking=NO, Suicidal_thoughts=NO}
## [9] {Authority_Respect=YES, Mood_Swing=NO, Nervous_Breakdown=NO, Suicidal_thoughts=NO}
## [10] {Anorexia=NO, Authority_Respect=YES, Mood_Swing=NO, Optimisim=Medium}
## rhs support confidence coverage lift count
## [1] => {Diagnosis=Normal} 0.1000000 1 0.1000000 4 12
## [2] => {Diagnosis=Normal} 0.1000000 1 0.1000000 4 12
## [3] => {Diagnosis=Normal} 0.1083333 1 0.1083333 4 13
## [4] => {Diagnosis=Normal} 0.1083333 1 0.1083333 4 13
## [5] => {Diagnosis=Normal} 0.1083333 1 0.1083333 4 13
## [6] => {Diagnosis=Normal} 0.1000000 1 0.1000000 4 12
## [7] => {Diagnosis=Normal} 0.1166667 1 0.1166667 4 14
## [8] => {Diagnosis=Normal} 0.1000000 1 0.1000000 4 12
## [9] => {Diagnosis=Normal} 0.1166667 1 0.1166667 4 14
## [10] => {Diagnosis=Normal} 0.1000000 1 0.1000000 4 12
rules_viz <- head(sort(rules_normal, by = "lift", decreasing = TRUE), 10)
plot(rules_viz, method = "paracoord", control = list(reorder = TRUE),
main = "Characteristics of Normal (Healthy) Individuals")
plot(rules_normal, method="grouped")
Interpretation: Normal individuals are characterized by the absence of both mood swings AND suicidal thoughts, combined with positive behavioral traits like authority respect and ability to admit mistakes. These patterns represent emotional stability and healthy psychological functioning.
Let us examine one of the most critical findings from our analysis. The presence or absence of mood swings.
# Cross-tabulation
mood_diag <- table(data$Mood_Swing, data$Diagnosis)
print(mood_diag)
##
## Bipolar Type-1 Bipolar Type-2 Depression Normal
## NO 3 0 31 29
## YES 25 31 0 1
mood_pct <- prop.table(mood_diag, margin = 1) * 100
print(round(mood_pct, 1))
##
## Bipolar Type-1 Bipolar Type-2 Depression Normal
## NO 4.8 0.0 49.2 46.0
## YES 43.9 54.4 0.0 1.8
The presence or absence of mood swings achieves over 95% accuracy in differentiating bipolar disorders from depression and normal individuals.
To conclude, association rules is a very powerful tool for discovering patterns in psychological survey data. This research uncovered distinct symptom profiles for each mental health condition—patterns.
Clear Diagnostic Signatures for each diagnosis:
Bipolar Type-1: Mood swings + euphoria + aggressive behavior. Classic manic presentation.
Bipolar Type-2: Mood swings + deep sadness + suicidal thoughts. Bipolar Type-2 have suicidal ideation—higher than Type-1.
Depression: No mood swings + low optimism + suicidal thoughts + overthinking. The absence of mood swings is the key differentiator from bipolar.
Normal/Healthy: No mood swings + no suicidal thoughts + positive behaviors like respect and self-awareness. Emotional stability, not just absence of symptoms.
Mood swings is the most critical symptom in determination of Bipolar disorder.