Introduction

This note aims to introduce QCA package in R by Dusa (2019).

References:

Library

# install.packages("tidyverse")
# install.packages("QCA")
# install.packages("venn")

library(tidyverse)
library(QCA)
library(venn)

Example data

The Lipset dataset used in Rihoux and Ragin (2009=2016)

Call help description.

?LR

csQCA

Rihoux & Ragin (2009=2016, Ch.3)

Initial analysis

LR %>% 
  select(-STB) %>% 
  mutate(
    DEV = if_else(DEV >= 600, 1, 0),
    URB = if_else(URB >= 50, 1, 0),
    LIT = if_else(LIT >= 75, 1, 0),
    IND = if_else(IND >= 30, 1, 0),
    SURV = if_else(SURV >= 0, 1, 0)
  ) -> LCinit

Truth table with contradictions (incl.cut = c(1, 0.01))

LCinit %>% 
  truthTable("SURV", incl.cut = c(1, 0.01),
              show.cases = TRUE, complete = TRUE) -> ttLCinit
ttLCinit
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##      DEV URB LIT IND   OUT    n  incl  PRI   cases         
##  1    0   0   0   0     0     5  0.000 0.000 GR,IT,PT,RO,ES
##  2    0   0   0   1     ?     0    -     -                 
##  3    0   0   1   0     C     4  0.250 0.250 EE,FI,HU,PL   
##  4    0   0   1   1     ?     0    -     -                 
##  5    0   1   0   0     ?     0    -     -                 
##  6    0   1   0   1     ?     0    -     -                 
##  7    0   1   1   0     ?     0    -     -                 
##  8    0   1   1   1     1     1  1.000 1.000 CZ            
##  9    1   0   0   0     ?     0    -     -                 
## 10    1   0   0   1     ?     0    -     -                 
## 11    1   0   1   0     1     1  1.000 1.000 IE            
## 12    1   0   1   1     C     3  0.667 0.667 AU,FR,SE      
## 13    1   1   0   0     ?     0    -     -                 
## 14    1   1   0   1     ?     0    -     -                 
## 15    1   1   1   0     ?     0    -     -                 
## 16    1   1   1   1     C     4  0.750 0.750 BE,DE,NL,UK

Minimization for explaining both 1 and C.

ttLCinit %>% 
  minimize(explain = "1, C", detail = TRUE) -> csLCinit
csLCinit
## 
## M1: ~URB*LIT*~IND + URB*LIT*IND + (DEV*~URB*LIT) <-> SURV 
## M2: ~URB*LIT*~IND + URB*LIT*IND + (DEV*LIT*IND) <-> SURV 
## 
##                                        ------------------- 
##                   inclS   PRI   covS   covU   (M1)   (M2)   cases 
## --------------------------------------------------------------------------------- 
## 1  ~URB*LIT*~IND  0.400  0.400  0.250  0.125  0.125  0.250  EE,FI,HU,PL; IE 
## 2    URB*LIT*IND  0.800  0.800  0.500  0.125  0.500  0.125  CZ; BE,DE,NL,UK 
## --------------------------------------------------------------------------------- 
## 3   DEV*~URB*LIT  0.750  0.750  0.375  0.000  0.250         IE; AU,FR,SE 
## 4    DEV*LIT*IND  0.714  0.714  0.625  0.000         0.250  AU,FR,SE; BE,DE,NL,UK 
## --------------------------------------------------------------------------------- 
##               M1  0.615  0.615  1.000 
##               M2  0.615  0.615  1.000

Prime implicant chart

csLCinit$PIchart
## 
##                 3  8  11 12 16
## DEV*~URB*LIT    -  -  x  x  - 
## DEV*LIT*IND     -  -  -  x  x 
## ~URB*LIT*~IND   x  -  x  -  - 
## URB*LIT*IND     -  x  -  -  x

Venn diagram of the solution

csLCinit %>% venn()

Minimization for explaining 1 and C, including ?, so called parsimonious solution.

ttLCinit %>% 
  minimize(explain = "1, C", include = "?", detail = TRUE) -> psLCinit
psLCinit
## 
## M1: LIT <-> SURV
## 
##         inclS   PRI   covS   covU   cases 
## ------------------------------------------------------------------------------ 
## 1  LIT  0.615  0.615  1.000    -    EE,FI,HU,PL; CZ; IE; AU,FR,SE; BE,DE,NL,UK 
## ------------------------------------------------------------------------------ 
##     M1  0.615  0.615  1.000

Simplifying assumptions

psLCinit$SA
## $M1
##    DEV URB LIT IND
## 4    0   0   1   1
## 7    0   1   1   0
## 15   1   1   1   0
psLCinit$PIchart
## 
##       3  8  11 12 16
## DEV   -  -  x  x  x 
## URB   -  x  -  -  x 
## LIT   x  x  x  x  x 
## IND   -  x  -  x  x
psLCinit$solution[[1]] %>% venn(snames = "DEV, URB, LIT, IND")

Full analysis

LC %>%
  truthTable("SURV", show.cases = TRUE) %>% 
  minimize(details = TRUE) -> csLC

csLC
## 
## M1: DEV*~URB*LIT*STB + DEV*LIT*IND*STB <-> SURV
## 
##                      inclS   PRI   covS   covU   cases 
## ------------------------------------------------------------------- 
## 1  DEV*~URB*LIT*STB  1.000  1.000  0.500  0.250  FI,IE; FR,SE 
## 2   DEV*LIT*IND*STB  1.000  1.000  0.750  0.500  FR,SE; BE,CZ,NL,UK 
## ------------------------------------------------------------------- 
##                  M1  1.000  1.000  1.000
csLC$tt
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##      DEV URB LIT IND STB   OUT    n  incl  PRI   cases      
##  1    0   0   0   0   0     0     3  0.000 0.000 GR,PT,ES   
##  2    0   0   0   0   1     0     2  0.000 0.000 IT,RO      
##  5    0   0   1   0   0     0     2  0.000 0.000 HU,PL      
##  6    0   0   1   0   1     0     1  0.000 0.000 EE         
## 22    1   0   1   0   1     1     2  1.000 1.000 FI,IE      
## 23    1   0   1   1   0     0     1  0.000 0.000 AU         
## 24    1   0   1   1   1     1     2  1.000 1.000 FR,SE      
## 31    1   1   1   1   0     0     1  0.000 0.000 DE         
## 32    1   1   1   1   1     1     4  1.000 1.000 BE,CZ,NL,UK
csLC$PIchart
## 
##                    22 24 32
## DEV*~URB*LIT*STB   x  x  - 
## DEV*LIT*IND*STB    -  x  x
csLC %>% venn()

mvQCA

LM %>% 
  truthTable("SURV", show.cases = TRUE) %>% 
  minimize(details = TRUE)
## 
## M1: DEV[2]*LIT[1]*IND[1]*STB[1] + DEV[1]*URB[0]*LIT[1]*IND[0]*STB[1] +
##     DEV[1]*URB[1]*LIT[1]*IND[1]*STB[1] <-> SURV[1]
## 
##                                        inclS   PRI   covS   covU   cases 
## ---------------------------------------------------------------------------------- 
## 1         DEV[2]*LIT[1]*IND[1]*STB[1]  1.000  1.000  0.625  0.625  FR,SE; BE,NL,UK 
## 2  DEV[1]*URB[0]*LIT[1]*IND[0]*STB[1]  1.000  1.000  0.250  0.250  FI,IE 
## 3  DEV[1]*URB[1]*LIT[1]*IND[1]*STB[1]  1.000  1.000  0.125  0.125  CZ 
## ---------------------------------------------------------------------------------- 
##                                    M1  1.000  1.000  1.000

fsQCA

LF %>% 
  truthTable("SURV", incl.cut = 0.7, show.cases = TRUE) -> ttLF
ttLF
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##      DEV URB LIT IND STB   OUT    n  incl  PRI   cases      
##  1    0   0   0   0   0     0     3  0.216 0.000 GR,PT,ES   
##  2    0   0   0   0   1     0     2  0.278 0.000 IT,RO      
##  5    0   0   1   0   0     0     2  0.521 0.113 HU,PL      
##  6    0   0   1   0   1     0     1  0.529 0.228 EE         
## 22    1   0   1   0   1     1     2  0.804 0.719 FI,IE      
## 23    1   0   1   1   0     0     1  0.378 0.040 AU         
## 24    1   0   1   1   1     1     2  0.709 0.634 FR,SE      
## 31    1   1   1   1   0     0     1  0.445 0.050 DE         
## 32    1   1   1   1   1     1     4  0.904 0.886 BE,CZ,NL,UK

Membership values of cases for existing rows

ttLF$minmat
##       1    2    5    6   22   23   24   31   32
## AU 0.01 0.01 0.19 0.19 0.27 0.57 0.43 0.12 0.12
## BE 0.00 0.00 0.00 0.00 0.00 0.02 0.11 0.02 0.89
## CZ 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.09 0.58
## EE 0.02 0.02 0.09 0.84 0.16 0.01 0.01 0.01 0.01
## FI 0.01 0.01 0.42 0.42 0.58 0.08 0.08 0.03 0.03
## FR 0.01 0.01 0.02 0.02 0.19 0.05 0.81 0.03 0.03
## DE 0.01 0.01 0.04 0.04 0.04 0.21 0.21 0.69 0.31
## GR 0.57 0.43 0.13 0.13 0.04 0.04 0.04 0.04 0.04
## HU 0.12 0.12 0.84 0.13 0.07 0.07 0.07 0.07 0.07
## IE 0.02 0.02 0.05 0.28 0.72 0.01 0.01 0.01 0.01
## IT 0.42 0.53 0.41 0.41 0.34 0.34 0.34 0.10 0.10
## NL 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.01 0.94
## PL 0.41 0.00 0.59 0.00 0.00 0.00 0.00 0.00 0.00
## PT 0.89 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01
## RO 0.16 0.83 0.16 0.17 0.01 0.00 0.00 0.00 0.00
## ES 0.70 0.20 0.09 0.09 0.03 0.03 0.03 0.03 0.03
## SE 0.01 0.01 0.05 0.05 0.33 0.09 0.67 0.09 0.13
## UK 0.00 0.00 0.00 0.00 0.00 0.01 0.01 0.02 0.98

Complex solution

ttLF %>% minimize(details = TRUE) -> csLF
csLF
## 
## M1: DEV*~URB*LIT*STB + DEV*LIT*IND*STB -> SURV
## 
##                      inclS   PRI   covS   covU   cases 
## ------------------------------------------------------------------- 
## 1  DEV*~URB*LIT*STB  0.809  0.761  0.433  0.196  FI,IE; FR,SE 
## 2   DEV*LIT*IND*STB  0.843  0.821  0.622  0.385  FR,SE; BE,CZ,NL,UK 
## ------------------------------------------------------------------- 
##                  M1  0.871  0.851  0.818
csLF %>% venn()

Parsimonious solution

ttLF %>% minimize(details = TRUE, include = "?") -> psLF
psLF
## 
## M1: DEV*STB -> SURV
## 
##             inclS   PRI   covS   covU   cases 
## ----------------------------------------------------------------- 
## 1  DEV*STB  0.869  0.848  0.824    -    FI,IE; FR,SE; BE,CZ,NL,UK 
## ----------------------------------------------------------------- 
##         M1  0.869  0.848  0.824
psLF$solution[[1]] %>% venn(snames = "DEV, URB, LIT, IND, STB")

Simplyfying assumptions

psLF$SA
## $M1
##    DEV URB LIT IND STB
## 18   1   0   0   0   1
## 20   1   0   0   1   1
## 26   1   1   0   0   1
## 28   1   1   0   1   1
## 30   1   1   1   0   1

Intermediate solution

Intermediate solution with direction expectaion. For example, if the existence of condition A is expected, it is employed as one of the simplifying assumption only if the logical reminder with existing condition A can be used for simplification of a term. See Dusa (2024, 8.7)

ttLF %>% 
  minimize(details = TRUE, include = "?",
  dir.exp = "DEV, URB, LIT, IND, STB") -> isLF
isLF
## 
## From C1P1: 
## 
## M1:    DEV*LIT*STB -> SURV 
## 
##                 inclS   PRI   covS   covU   cases 
## --------------------------------------------------------------------- 
## 1  DEV*LIT*STB  0.869  0.848  0.824    -    FI,IE; FR,SE; BE,CZ,NL,UK 
## --------------------------------------------------------------------- 
##             M1  0.869  0.848  0.824
isLF$i.sol$C1P1$solution[[1]] %>% venn(snames = "DEV, URB, LIT, IND, STB")

Employed easy counterfacts which meets the expectation.

isLF$i.sol$C1P1$EC
##    DEV URB LIT IND STB
## 30   1   1   1   0   1