Introduction
The qca_solutions
function is designed to streamline the
process of consolidating Conservative, Intermediate, and Parsimonious
solutions from the QCA
Package (Dușa, 2019) into a unified dataframe. This function allows
you to easily handle multiple types of solutions, apply filtering based
on consistency thresholds, round numeric values, and save results to an
Excel file.
Full documentation, example usage, and source code on GitHub: https://github.com/marisguia/qca_solutions
Function Usage
qca_solutions(c = NULL, i = NULL, icp = NULL, p = NULL, verbose = TRUE, save = NULL, round = NULL, incl.cut = NULL)
Arguments
c
A conservative solution object of class"QCA_min"
.i
An intermediate solution object of class"QCA_min"
.icp
A character vector specifying which CnPn (configurations of necessary and possible necessary conditions) to include for intermediate solutions.p
A parsimonious solution object of class"QCA_min"
.verbose
Logical. IfTRUE
(default), progress messages are displayed.save
A character string specifying the file path to save the results. IfNULL
(default), no file is saved.round
An integer specifying the number of decimal places to round numeric columns (e.g.,2
for two decimal places). IfNULL
, no rounding is applied.incl.cut
A numeric value specifying the threshold for Consistency_PI. Prime implicants with Consistency_PI below this value are excluded. IfNULL
, no filtering is applied.
Example
Truth Table. Lipset dataset (1959).
library(QCA)
tt <- truthTable(LF, outcome = SURV, incl.cut = .5) # Low incl.cut to generate multiple models for this example
DEV | URB | LIT | IND | STB | OUT | n | incl | PRI | cases |
---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 | 4 | 0.90 | 0.89 | BE,CZ,NL,UK |
1 | 0 | 1 | 0 | 1 | 1 | 2 | 0.80 | 0.72 | FI,IE |
1 | 0 | 1 | 1 | 1 | 1 | 2 | 0.71 | 0.63 | FR,SE |
0 | 0 | 1 | 0 | 1 | 1 | 1 | 0.53 | 0.23 | EE |
0 | 0 | 1 | 0 | 0 | 1 | 2 | 0.52 | 0.11 | HU,PL |
1 | 1 | 1 | 1 | 0 | 0 | 1 | 0.45 | 0.05 | DE |
1 | 0 | 1 | 1 | 0 | 0 | 1 | 0.38 | 0.04 | AU |
0 | 0 | 0 | 0 | 1 | 0 | 2 | 0.28 | 0.00 | IT,RO |
0 | 0 | 0 | 0 | 0 | 0 | 3 | 0.22 | 0.00 | GR,PT,ES |
# Solutions
c_solution <- minimize(tt) # Conservative
i_solution <- minimize(tt, include = "?", dir.exp = "1, 1, 1, 1, 1") # Intermediate
p_solution <- minimize(tt, include = "?") # Parsimonious
Conservative solution
qca_c_solution <- qca_solutions(c = c_solution, round = 2)
print(qca_c_solution)
Solution | Model | Intermediate_CnPn | Prime_Implicants | Consistency_PI | PRI_PI | Raw_Coverage_PI | Unique_Coverage_PI | Solution_Consistency | Solution_PRI | Solution_Coverage | Cases |
---|---|---|---|---|---|---|---|---|---|---|---|
Conservative | 1 |
|
~DEV*~URB*LIT*~IND | 0.46 | 0.15 | 0.22 | 0.08 | 0.73 | 0.68 | 0.90 | EE, HU, PL |
Conservative | 1 |
|
DEV*~URB*LIT*STB | 0.81 | 0.76 | 0.43 | 0.11 | 0.73 | 0.68 | 0.90 | FI, FR, IE, SE |
Conservative | 1 |
|
DEV*LIT*IND*STB | 0.84 | 0.82 | 0.62 | 0.38 | 0.73 | 0.68 | 0.90 | BE, CZ, FR, NL, SE, UK |
Conservative | 2 |
|
~DEV*~URB*LIT*~IND | 0.46 | 0.15 | 0.22 | 0.05 | 0.72 | 0.67 | 0.88 | EE, HU, PL |
Conservative | 2 |
|
DEV*LIT*IND*STB | 0.84 | 0.82 | 0.62 | 0.51 | 0.72 | 0.67 | 0.88 | BE, CZ, FR, NL, SE, UK |
Conservative | 2 |
|
~URB*LIT*~IND*STB | 0.65 | 0.52 | 0.32 | 0.09 | 0.72 | 0.67 | 0.88 | EE, FI, IE |
Intermediate solution
qca_i_solution <- qca_solutions(i = i_solution, icp = "C1P1", round = 2)
print(qca_i_solution)
Solution | Model | Intermediate_CnPn | Prime_Implicants | Consistency_PI | PRI_PI | Raw_Coverage_PI | Unique_Coverage_PI | Solution_Consistency | Solution_PRI | Solution_Coverage | Cases |
---|---|---|---|---|---|---|---|---|---|---|---|
Intermediate |
|
C1P1 | ~DEV*LIT | 0.50 | 0.23 | 0.28 | 0.05 | 0.73 | 0.68 | 0.96 | HU,PL; EE |
Intermediate |
|
C1P1 | LIT*STB | 0.79 | 0.76 | 0.92 | 0.69 | 0.73 | 0.68 | 0.96 | EE; FI,IE; FR,SE; BE,CZ,NL,UK |
Parsimonious solution
qca_p_solution <- qca_solutions(p = p_solution, round = 2)
print(qca_p_solution)
Solution | Model | Intermediate_CnPn | Prime_Implicants | Consistency_PI | PRI_PI | Raw_Coverage_PI | Unique_Coverage_PI | Solution_Consistency | Solution_PRI | Solution_Coverage | Cases |
---|---|---|---|---|---|---|---|---|---|---|---|
Parsimonious | 1 |
|
~DEV*LIT | 0.50 | 0.23 | 0.28 | 0.08 | 0.73 | 0.68 | 0.90 | EE, HU, PL |
Parsimonious | 1 |
|
DEV*STB | 0.87 | 0.85 | 0.82 | 0.63 | 0.73 | 0.68 | 0.90 | BE, CZ, FI, FR, IE, NL, SE, UK |
Parsimonious | 2 |
|
~DEV*LIT | 0.50 | 0.23 | 0.28 | 0.05 | 0.73 | 0.68 | 0.96 | EE, HU, PL |
Parsimonious | 2 |
|
LIT*STB | 0.79 | 0.76 | 0.92 | 0.69 | 0.73 | 0.68 | 0.96 | BE, CZ, EE, FI, FR, IE, NL, SE, UK |
Parsimonious | 3 |
|
DEV*STB | 0.87 | 0.85 | 0.82 | 0.54 | 0.72 | 0.66 | 0.95 | BE, CZ, FI, FR, IE, NL, SE, UK |
Parsimonious | 3 |
|
LIT*~IND | 0.56 | 0.40 | 0.41 | 0.13 | 0.72 | 0.66 | 0.95 | EE, FI, HU, IE, PL |
Parsimonious | 4 |
|
LIT*~IND | 0.56 | 0.40 | 0.41 | 0.07 | 0.72 | 0.67 | 0.99 | EE, FI, HU, IE, PL |
Parsimonious | 4 |
|
LIT*STB | 0.79 | 0.76 | 0.92 | 0.58 | 0.72 | 0.67 | 0.99 | BE, CZ, EE, FI, FR, IE, NL, SE, UK |
Parsimonious | 5 |
|
LIT*~IND | 0.56 | 0.40 | 0.41 | 0.28 | 0.69 | 0.64 | 0.94 | EE, FI, HU, IE, PL |
Parsimonious | 5 |
|
IND*STB | 0.78 | 0.76 | 0.66 | 0.53 | 0.69 | 0.64 | 0.94 | BE, CZ, FR, NL, SE, UK |
Full usage, all solutions
qca_results <- qca_solutions(
c = c_solution, # Conservative solution object
i = i_solution, # Intermediate solution object
icp = c("C1P3", "C2P1"), # CnPn to include for intermediate solutions
p = p_solution, # Parsimonious solution object
verbose = TRUE, # Display progress messages
round = 3, # Round numeric values to 3 decimal places
incl.cut = 0.8, # Set a consistency threshold for prime implicants
save = "qca_results.xlsx" # Save results to an Excel file
)
Solution | Model | Intermediate_CnPn | Prime_Implicants | Consistency_PI | PRI_PI | Raw_Coverage_PI | Unique_Coverage_PI | Solution_Consistency | Solution_PRI | Solution_Coverage | Cases |
---|---|---|---|---|---|---|---|---|---|---|---|
Conservative | 1 |
|
DEV*~URB*LIT*STB | 0.809 | 0.761 | 0.433 | 0.110 | 0.734 | 0.679 | 0.898 | FI, FR, IE, SE |
Conservative | 1 |
|
DEV*LIT*IND*STB | 0.843 | 0.821 | 0.622 | 0.385 | 0.734 | 0.679 | 0.898 | BE, CZ, FR, NL, SE, UK |
Conservative | 2 |
|
DEV*LIT*IND*STB | 0.843 | 0.821 | 0.622 | 0.513 | 0.724 | 0.666 | 0.881 | BE, CZ, FR, NL, SE, UK |
Parsimonious | 1 |
|
DEV*STB | 0.869 | 0.848 | 0.824 | 0.628 | 0.731 | 0.676 | 0.904 | BE, CZ, FI, FR, IE, NL, SE, UK |
Parsimonious | 3 |
|
DEV*STB | 0.869 | 0.848 | 0.824 | 0.542 | 0.717 | 0.664 | 0.950 | BE, CZ, FI, FR, IE, NL, SE, UK |
Intermediate |
|
C1P3 | DEV*LIT*STB | 0.869 | 0.848 | 0.824 | 0.542 | 0.717 | 0.664 | 0.950 | FI,IE; FR,SE; BE,CZ,NL,UK |
Intermediate |
|
C2P1 | LIT*IND*STB | 0.829 | 0.806 | 0.664 | 0.371 | 0.736 | 0.686 | 0.958 | FR,SE; BE,CZ,NL,UK |
Bonus: nifty trick to save truth tables to Excel
library(dplyr)
library(tidyr)
library(writexl)
tt$tt %>%
mutate(across(c(1:9), ~round(as.numeric(.), 2))) %>% # Fix numerical columns 1 to 9 and rounding
arrange(desc(incl), desc(PRI)) %>% # Sort by consistency and PRI
replace(is.na(.), "-") %>% # Replace empty cells with "-"
write_xlsx("tt_file_name.xlsx") # Write to .xlsx file