Chapter 2 Testing Facilitation Assumptions in OR Analysis

Loading Packages and Importing Data

#Load packages
library(QCA)
library(dplyr)
library(tidyr)
library(ggplot2)
library(UpSetR)
library(DT)
library(extrafont) # Note: If you have not used this package before, you will need to install + load, then use functions:
#fort_import()
#loadfonts()

#Download the datafile and save to the same folder as this file before attempting to import.
data <- read.csv("Chapter 2 Review OSF.csv")

Data coding

Creating new variables

Facilitator Reflections Only

# If only facilitator reflections used for evaluation, Evaluation_Method_Facilitator_Reflection= 1, else = 0
data$Evaluation_Method_Facilitator_Reflection <- with(data,
  ifelse(
    is.na(Evaluation_Method_Questionnaires) &
    is.na(Evaluation_Method_Stakeholder_Feedback_Unspecified) &
    is.na(Evaluation_Method_Populated_Workshop_Materials) &
    is.na(Evaluation_Method_Transcripts_or_Recordings) &
    is.na(Evaluation_Method_Populated_Workshop_Materials) &
    is.na(Evaluation_Method_Expert_Review) &
    is.na(Evaluation_Method_Post_Workshop_Meetings_or_Interviews) &
    is.na(Evaluation_Method_Obs),
    1, 0
  )
)

Stakeholder Feedback

#If stakeholder feedback sought, SH_Feedback= 1, else= 0
data$SH_Feedback <- with(data,
  ifelse(
    is.na(Evaluation_Method_Questionnaires) &
    is.na(Evaluation_Method_Stakeholder_Feedback_Unspecified) &
    is.na(Evaluation_Method_Post_Workshop_Meetings_or_Interviews),
    0, 1
  )
)

Active Listening

(Summarising Information from Stakeholders, Facilitator Asking Questions, Facilitator Neutrality)

# Creating a function to recode multiple variables. Recoding variables so Present= 2, Partial = 1 and Absent= 0. This is to produce an integer composite measure. 
recode_AL_component <- function(x) {
  ifelse(is.na(x), NA,
         ifelse(x == 1, 2,
         ifelse(x == 0, 1,
         ifelse(x == -1, 0, NA))))
}

AL_vars <- c("CH_Ask_Qs", "CH_Fac_Neutral", "CH_Info_Summary")
for (var in AL_vars) {
  data[[paste0(var, "_score")]] <- recode_AL_component(data[[var]])
}

data$CH_AL_score <- rowSums(data[paste0(AL_vars, "_score")], na.rm = TRUE)
  ##New scale ranging from 0-6, where 0= No active listening reported and 6= Very strong active listening reported

  ##To include in other composite measures, weighting must be set to 2 (in line with other variables in composite measures, see below)

data$CH_AL_rescale <- data$CH_AL_score / length(AL_vars) ##Rescaled measure ranging from 0-2, where 0= No active listening reported and 2= Very strong active listening reported

Procedural Justice

(Active Listening, Egalitarianism, Minimising Judgement)

pj_vars <- c("CH_Egal", "CH_Min_Judgement", "CH_AL_rescale")

#Can reuse same recoding function

for (var in pj_vars) {
  data[[paste0(var, "_score")]] <- recode_AL_component(data[[var]])
}


data$CH_PJ_score <- rowSums(data[paste0(pj_vars, "_score")], na.rm = TRUE)
##New procedural justice score ranging from 0-6, where 0= No procedural justice reported and 6= Very strong procedural justice reported


data$CH_PJ_rescale <- data$CH_PJ_score / length(pj_vars) ##Rescaled procedural justice score ranging from 0-2, where 0= No procedural justice reported and 2= Very strong procedural justice reported

Participative Environment

(Structured Discussion Activities, Collaborative Model Building)

pe_vars <- c("CH_Structured_Discussion", "CH_Int_Model_Dev")

# Can reuse recode function from PJ composite measure
for (var in pe_vars) {
  data[[paste0(var, "_score")]] <- recode_AL_component(data[[var]])
}

data$CH_PE_score <- rowSums(data[paste0(pe_vars, "_score")], na.rm = TRUE) 
##New participative environment score ranging from 0-6, where 0= No participative environment reported and 6= Very strong participative environment reported


data$CH_PE_rescale <- data$CH_PE_score / length(pe_vars) ##Rescaled participative environment score ranging from 0-2, where 0= No participative environment reported and 2= Very strong participative environment reported

Action Plan Commitment/ Implementation

#Take highest value from both variables
data$Outcome_AP_Com_Imp <- pmax(
  data$Outcome_AP_Commitment,
  data$Outcome_AP_Implementation,
  na.rm = TRUE
)

# Set result to NA when both are NA
both_na <- is.na(data$Outcome_AP_Commitment) & is.na(data$Outcome_AP_Implementation)
data$Outcome_AP_Com_Imp[both_na] <- NA

# Renaming variables so they are not included in later functions that select all variables beginning with 'Outcome_', preventing duplication.

data <- data %>%
  rename(Composite_AP_Commitment = Outcome_AP_Commitment) %>% 
rename(Composite_AP_Implementation = Outcome_AP_Implementation) 

Positive Model Attitude

(Perceived Relevance of Model, Agreement with Model, Trust/ Confidence in Model)

# If input variables are mixed (not including NAs), model attitude= 0 (partial), otherwise, model attitude= input variable value
data <- data %>%
  rowwise() %>%
  mutate(Outcome_Model_Pos = {
    values <- c_across(c(Outcome_Model_Trust_Conf, Outcome_Model_Agree, Outcome_Model_Relevance))
    values <- values[!is.na(values)]
    
    if (length(values) == 0) {
      NA_real_  # All missing
    } else if (length(unique(values)) == 1) {
      unique(values)  # All same (or only 1 value)
    } else {
      0  # Mixed values
    }
  }) %>%
  ungroup()

#Renaming variables to prevent duplication
data <- data %>%
  rename(Composite_Model_Trust_Conf = Outcome_Model_Trust_Conf) %>% 
rename(Composite_Model_Agree = Outcome_Model_Agree) %>% 
  rename(Composite_Model_Relevance = Outcome_Model_Relevance) 

Perceived Project Ownership

(Project ownership [existing variable], Solution ownership, System ownership)

# If input variables are mixed (excluding NA), Perceived project ownership= 0 (partial), otherwise, Perceived project ownership = input variable value
data <- data %>%
  rowwise() %>%
  mutate(Outcome_Proj_Ownership = {
    values <- c_across(c(Outcome_Project_Ownership, Outcome_Solution_Ownership, Outcome_System_Ownership))
    values <- values[!is.na(values)]
    
    if (length(values) == 0) {
      NA_real_  # All missing
    } else if (length(unique(values)) == 1) {
      unique(values)  # All same (or only 1 value)
    } else {
      0  # Mixed values
    }
  }) %>%
  ungroup()

#Renaming input variables to prevent duplication
data <- data %>%
  rename(Composite_Project_Ownership = Outcome_Project_Ownership) %>% 
rename(Composite_Solution_Ownership = Outcome_Solution_Ownership) %>% 
  rename(Composite_System_Ownership = Outcome_System_Ownership) 

Intragroup Relationships

(Intragroup trust, Social identity, Interpersonal Relationships)

# If input variables are mixed (excluding NAs), Intragroup relationships= 0 (partial), otherwise, Intragroup relationships= input variable value
data <- data %>%
  rowwise() %>%
  mutate(Outcome_Relationships = {
    values <- c_across(c(Outcome_SH_Trust, Outcome_Interpersonal_Relationships, Outcome_Identity))
    values <- values[!is.na(values)]
    
    if (length(values) == 0) {
      NA_real_  # All missing
    } else if (length(unique(values)) == 1) {
      unique(values)  # All same (or only 1 value)
    } else {
      0  # Mixed values
    }
  }) %>%
  ungroup()

#Renaming input variables to prevent duplication
data <- data %>%
  rename(Composite_Interpersonal_Relationships = Outcome_Interpersonal_Relationships) %>% 
rename(Composite_SH_Trust = Outcome_SH_Trust) %>% 
  rename(Composite_Identity = Outcome_Identity) 

Stakeholder Response

(Positive Affect/ Response, Stakeholder Satisfaction)

# If input variables are mixed (excluding NAs), Positive response= 0 (partial), otherwise, Positive response= input variable value
data <- data %>%
  rowwise() %>%
  mutate(Outcome_Pos_Response = {
    values <- c_across(c(Outcome_Positive_Affect_Response, Outcome_SH_Satisfaction))
    values <- values[!is.na(values)]
    
    if (length(values) == 0) {
      NA_real_  # All missing
    } else if (length(unique(values)) == 1) {
      unique(values)  # All same (or only 1 value)
    } else {
      0  # Mixed values
    }
  }) %>%
  ungroup()

#Renaming input variables to prevent duplication
data <- data %>%
  rename(Composite_Positive_Affect_Response = Outcome_Positive_Affect_Response) %>%
  rename(Composite_SH_Satisfaction = Outcome_SH_Satisfaction) 

Analysis

Descriptives

Workshop Frequencies

Summary Table

#Workshop Frequencies
No_Workshops <- data$No_Workshops
## Frequency table including unspecified cases
WS_freq_with_na <- table(No_Workshops, useNA = "ifany")
## Proportions excluding unspecified cases
WS_prop_excl_na <- prop.table(table(No_Workshops, useNA = "no"))
## Combined dataframe
WS_Overview <- data.frame(
  Value = names(WS_freq_with_na),
  Frequency = as.vector(WS_freq_with_na),
  Proportion = c(signif(as.vector(WS_prop_excl_na), 2), rep(NA, length(WS_freq_with_na) - length(WS_prop_excl_na)))
)

datatable(WS_Overview, caption = 'Workshop Frequencies', options = list(pageLength = 10, autoWidth=TRUE))

Mean workshop frequency

##Mean number of workshops
No_WS_mean <- mean(data$No_Workshops, na.rm= TRUE)
No_WS_mean
## [1] 3.890411

Frequency plot

##Workshop frequencies histogram
Workshops_Histogram <- ggplot(data, aes(x = No_Workshops)) +
  geom_histogram(binwidth = 2, color = "black", fill = "grey") +
  labs(
    title = "Histogram of Workshop Frequency",
    x = "Number of Workshops",
    y = "Frequency"
  ) +
  theme_minimal(base_family = "Times New Roman") +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14),  # Centered, bold
    axis.title = element_text(size = 12),
    axis.text = element_text(size = 10)
  )

Workshops_Histogram

##Save as image for importing into thesis chapter (hashtagged to prevent automatic saving)
#ggsave("Workshop frequency histogram.png", width = 6, height = 4, dpi = 300)

Stakeholder Group Size

Summary Table

#Stakeholder Group Size Frequencies
No_Stakeholders <- data$No_Stakeholders
## Frequency table including unspecified cases
SH_freq_with_na <- table(No_Stakeholders, useNA = "ifany")
## Proportions excluding unspecified cases
SH_prop_excl_na <- prop.table(table(No_Stakeholders, useNA = "no"))
## Combined dataframe
SH_Overview <- data.frame(
  Value = names(SH_freq_with_na),
  Frequency = as.vector(SH_freq_with_na),
  Proportion = c(signif(as.vector(SH_prop_excl_na), 2), rep(NA, length(SH_freq_with_na) - length(SH_prop_excl_na)))
)


datatable(SH_Overview, caption = 'Stakeholder Group Sizes', options = list(pageLength = 10, autoWidth=TRUE))

Mean Group Size

data$No_Stakeholders <- as.numeric(data$No_Stakeholders)
No_SH_mean <- mean(data$No_Stakeholders, na.rm= TRUE)
No_SH_mean
## [1] 12.36842

Frequency Plot

##Stakeholder group size histogram
Stakeholder_Group_Size_Histogram <- ggplot(data, aes(x = No_Stakeholders)) +
  geom_histogram(binwidth = 2, color = "black", fill = "grey") +
    scale_y_continuous(breaks = seq(0, 10, by = 2)) +
  labs(
    title = "Histogram of Stakeholder Group Size",
    x = "Number of Stakeholders Per Workshop",
    y = "Frequency"
  ) +
  theme_minimal(base_family = "Times New Roman") +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14),  # Centered, bold
    axis.title = element_text(size = 12),
    axis.text = element_text(size = 10)
  )

Stakeholder_Group_Size_Histogram

##Save as image for importing into thesis chapter (hashtagged to prevent automatic saving)
##ggsave("Stakeholder Group Size histogram.png", width = 6, height = 4, dpi = 300)

Facilitation Method

Categories and Examples

Facilitation Category Key Properties Examples
Facilitated Problem Structuring ( Facilitated_PS)
  • Assumptions of

subjectivity

  • Groups as key

d ecision-makers

  • Limited use of

quantitative methods

Cognitive mapping, SODA, VSM
Facilitated System Dynamics
( Facilitated_SD)
  • Modelling of systems with critical dynamics and feedback loops
GMB, WASAN
Facilitated Decision Analysis
( Facilitated_DA)
  • Modelling decisions with multiple objectives and/ or

uncertainties

MCDA, MACBETH, GDSS, Simulation

Summary Table

# Frequency of single vs. multiple facilitation methods
Facilitation_Method_Total <- table(data$No_Method_Categories)
Facilitation_Method_Total 
## 
##  1  2  3 
## 56 26  2
facilitation_method_counts <- sapply(
  c("Facilitated_PS", "Facilitated_DA", "Facilitated_SD"),
  function(var) sum(data[[var]] == 1, na.rm = TRUE)
)

## Convert to data frame
facilitation_methods_table <- data.frame(
  Variable = names(facilitation_method_counts),
  Count_1 = as.vector(facilitation_method_counts)
)

datatable(facilitation_methods_table, caption = 'Faciltation Methods', options = list(pageLength = 10, autoWidth=TRUE))

Frequencies Plot

## Generating dataframe for plot
fac_plot_data <- data[, c("Facilitated_PS", "Facilitated_DA", "Facilitated_SD")]

## Replace NAs with 0 (method not used)
fac_plot_data[is.na(fac_plot_data)] <- 0
fac_plot_data <- as.data.frame(fac_plot_data)

#Producing plot
upset(
  fac_plot_data,
  sets = c("Facilitated_PS", "Facilitated_DA", "Facilitated_SD"),
  order.by = "freq",
  main.bar.color = "grey30",
  sets.bar.color = "grey60",
  text.scale = c(1.6, 1.2, 1.2, 1.2, 1.4, 1.2),
  point.size = 4,
  line.size = 0.6,
  keep.order = TRUE,
  number.angles = 0,
  sets.x.label = "Number of Cases per Method",
  mainbar.y.label = "Cases per Combination"
)

##Upset has known issues with exporting graphs which prevents font changes. Manual export required. 

Evaluation Method

Summary Table

#Create list of all variables starting with "Evaluation_" and set NAs to 0s (Method not used)
eval_vars <- grep("^Evaluation_", names(data), value = TRUE)
eval_matrix <- data[eval_vars]
eval_matrix[is.na(eval_matrix)] <- 0 

#Count number of facilitation method categories used for each case. Then create variables for whether methods were used alone (method_counts= 1) or in combination (method_counts= 2 or 3)
method_counts <- rowSums(eval_matrix)
evaluation_method_summary_table <- sapply(eval_vars, function(var) {
  used <- eval_matrix[[var]] == 1
  only_used <- used & (method_counts == 1)
  with_others <- used & (method_counts > 1)
  
  #Create dataframe showing ns and %s of cases using each method alone and in combination with others 
  total_used <- sum(used)
  only_count <- sum(only_used)
  with_others_count <- sum(with_others)
  proportion_used <- total_used / nrow(data)
  
  c(
    Only_Method = only_count,
    With_Others = with_others_count,
    Total_Used = total_used,
    Proportion_Used = round(proportion_used, 3)
  )
})
evaluation_method_summary_table <- as.data.frame(t(evaluation_method_summary_table))
evaluation_method_summary_table$Variable <- rownames(evaluation_method_summary_table)
rownames(evaluation_method_summary_table) <- NULL
evaluation_method_summary_table <- evaluation_method_summary_table[, c("Variable", "Only_Method", "With_Others", "Total_Used", "Proportion_Used")]


datatable(evaluation_method_summary_table, caption = 'Evaluation Methods', options = list(pageLength = 10, autoWidth=TRUE))

Frequencies plot

# Creating graph
#Regenerating plot data (to ensure compatible structure) that only retains configurations with more than 3 cases
eval_plot_data <- data %>% select(starts_with("Evaluation_"))
eval_plot_data[is.na(eval_plot_data)] <- 0
eval_plot_data <- as.data.frame(eval_plot_data)
colnames(eval_plot_data)
## [1] "Evaluation_Method_Facilitator_Reflection"              
## [2] "Evaluation_Method_Questionnaires"                      
## [3] "Evaluation_Method_Stakeholder_Feedback_Unspecified"    
## [4] "Evaluation_Method_Populated_Workshop_Materials"        
## [5] "Evaluation_Method_Transcripts_or_Recordings"           
## [6] "Evaluation_Method_Expert_Review"                       
## [7] "Evaluation_Method_Post_Workshop_Meetings_or_Interviews"
## [8] "Evaluation_Method_Obs"
# Create a new column with a combination key (e.g., "10110")
eval_plot_data$combo <- apply(eval_plot_data, 1, paste0, collapse = "")

# Count combinations
combo_freq <- eval_plot_data %>%
  count(combo) %>%
  filter(n >= 3)

# Keep only rows with a combo that appears at least 3 times
eval_plot_filtered <- eval_plot_data %>%
  filter(combo %in% combo_freq$combo) %>%
  select(-combo)  # remove combo column if you want


upset(
  eval_plot_filtered,
  sets = colnames(eval_plot_filtered),
  order.by = "freq",
  keep.order = TRUE,
  main.bar.color = "grey30",
  sets.bar.color = "grey60",
  text.scale = c(1.6, 1.2, 1.2, 1.2, 1.4, 1.2),
  point.size = 3,
  line.size = 1,
  sets.x.label = "Cases using each method",
  mainbar.y.label = "Method combinations",
)

Workshop Characteristics

# Identify characteristic variables
CH_vars <- grep("^CH_", names(data), value = TRUE)

# Create an empty list to store results
CH_summary <- list()

# Loop through each outcome variable and compute n and % of cases reporting characteristic
for (var in CH_vars) {
  values <- data[[var]]
  total_cases <- nrow(data)
  n_present <- sum(values == 1, na.rm = TRUE)
  n_partial <- sum(values == 0, na.rm = TRUE)
  n_absent <- sum(values == -1, na.rm = TRUE)
  n_na <- sum(is.na(values))
  
  valid_cases <- total_cases - n_na # Excludes non-reporting cases
  
  prop_present <- n_present / valid_cases # Proportion of all reporting cases reporting variable as present
  prop_partial <- n_partial / valid_cases # Proportion of all reporting cases reporting variable as partially present
  prop_absent <- n_absent / valid_cases # Proportion of all reporting cases reporting variable as absent (or where absence could be identified based on information that was reported)
  prop_na <- n_na / total_cases # Proportion of all cases that did not report the variable
  
  #Create summary dataframe to output results
  CH_summary[[var]] <- data.frame(
    CH_Variable = var,
    N_Present = n_present,
    N_Partial = n_partial,
    N_Absent = n_absent,
    N_Not_Reported = n_na,
    Prop_Present = round(prop_present, 2),
    Prop_Partial = round(prop_partial, 2),
    Prop_Absent = round(prop_absent, 2),
    Prop_Not_Reported = signif(prop_na, 3)  # 3 significant figures to convert to %
  )
}

## Combine into single data frame
CH_summary_df <- do.call(rbind, CH_summary)


datatable(CH_summary_df, caption = 'Workshop Characteristics', options = list(pageLength = 10, autoWidth=TRUE))

Workshop Outcomes

# Identify outcome variables
outcome_vars <- grep("^Outcome_", names(data), value = TRUE)

# Create an empty list to store results
outcome_summary <- list()

# Loop through each outcome variable and compute n and % of cases reporting each outcome
for (var in outcome_vars) {
  values <- data[[var]]
  
  total_cases <- nrow(data)
  
  n_pos <- sum(values == 1, na.rm = TRUE)
  n_partial <- sum(values == 0, na.rm = TRUE)
  n_no_effect <- sum(values == -1, na.rm = TRUE)
  n_na <- sum(is.na(values))
  
  valid_cases <- total_cases - n_na #excludes non-reporting cases
  
  prop_pos <- n_pos / valid_cases # proportion of all reporting cases reporting positive effect
  prop_partial <- n_partial / valid_cases # proportion of all reporting cases reporting partial effect 
  prop_no_effect <- n_no_effect / valid_cases # proportion of all reporting cases reporting no effect
  prop_na <- n_na / total_cases # proportion of all cases that did not report variable
  
  # Create summary table
  outcome_summary[[var]] <- data.frame(
    Outcome_Variable = var,
    N_Positive = n_pos,
    N_Partial = n_partial,
    N_No_Effect = n_no_effect,
    N_Not_Reported = n_na,
    Prop_Positive = round(prop_pos, 2),
    Prop_Partial = round(prop_partial, 2),
    Prop_No_Effect = round(prop_no_effect, 2),
    Prop_Not_Reported = signif(prop_na, 3)  # 3 significant figures to convert to %
  )
}

## Combine into single data frame
outcome_summary_df <- do.call(rbind, outcome_summary)


datatable(outcome_summary_df, caption = 'Workshop Outcomes', options = list(pageLength = 10, autoWidth=TRUE))

Exploratory analysis: Does Stakeholder Feedback Influence Reported Outcomes?

Reporting Positive Outcomes

#Regenerate list of outcome variables then run function to create contingency tables showing ns and proportions of positive effects reported for each outcome, categorised by use/non-use of stakeholder feedback (i.e., questionnaires, unspecified feedback methods, post-workshop meetings/interviews)
outcome_vars <- grep("^Outcome_", names(data), value = TRUE)
for (var in outcome_vars) {
  cat("\n---", var, "---\n")
  
  # Create contingency table
  tab <- table(data[[var]], data$SH_Feedback, useNA = "no")
  
  # Show raw counts
  print(tab)
  
  # Calculate proportions (by SH_Feedback group)
  prop_tab <- prop.table(tab, margin = 2)  # 2 = column-wise: SH_Feedback = 0 (not used) and 1 (used)
  
  cat("\nProportions by SH_Feedback (column-wise):\n")
  print(round(prop_tab, 2))
}
## 
## --- Outcome_Shared_Understanding ---
##    
##      0  1
##   0  4  3
##   1 13 35
## 
## Proportions by SH_Feedback (column-wise):
##    
##        0    1
##   0 0.24 0.08
##   1 0.76 0.92
## 
## --- Outcome_Cog_Change ---
##    
##      0  1
##   0  1  3
##   1  9 25
## 
## Proportions by SH_Feedback (column-wise):
##    
##        0    1
##   0 0.10 0.11
##   1 0.90 0.89
## 
## --- Outcome_Consensus ---
##    
##      0  1
##   0  2  5
##   1 13 31
## 
## Proportions by SH_Feedback (column-wise):
##    
##        0    1
##   0 0.13 0.14
##   1 0.87 0.86
## 
## --- Outcome_AP_Generation ---
##     
##       0  1
##   -1  2  4
##   0   2  2
##   1  16 39
## 
## Proportions by SH_Feedback (column-wise):
##     
##         0    1
##   -1 0.10 0.09
##   0  0.10 0.04
##   1  0.80 0.87
## 
## --- Outcome_Efficiency_Independence ---
##    
##      0  1
##   0  0  1
##   1  3 18
## 
## Proportions by SH_Feedback (column-wise):
##    
##        0    1
##   0 0.00 0.05
##   1 1.00 0.95
## 
## --- Outcome_Positive_Org_Change ---
##     
##       0  1
##   -1  2  1
##   0   0  6
##   1   5 18
## 
## Proportions by SH_Feedback (column-wise):
##     
##         0    1
##   -1 0.29 0.04
##   0  0.00 0.24
##   1  0.71 0.72
## 
## --- Outcome_Learning_Ind ---
##    
##     0 1
##   0 1 2
##   1 3 8
## 
## Proportions by SH_Feedback (column-wise):
##    
##        0    1
##   0 0.25 0.20
##   1 0.75 0.80
## 
## --- Outcome_Decision_Confidence ---
##    
##     0 1
##   1 4 3
## 
## Proportions by SH_Feedback (column-wise):
##    
##     0 1
##   1 1 1
## 
## --- Outcome_Learning_Collective ---
##    
##      0  1
##   0  1  2
##   1 15 42
## 
## Proportions by SH_Feedback (column-wise):
##    
##        0    1
##   0 0.06 0.05
##   1 0.94 0.95
## 
## --- Outcome_Motivations ---
##     
##       0  1
##   -1  2  1
##   0   3  2
##   1   3 11
## 
## Proportions by SH_Feedback (column-wise):
##     
##         0    1
##   -1 0.25 0.07
##   0  0.38 0.14
##   1  0.38 0.79
## 
## --- Outcome_Model_Output_Conf ---
##    
##      0  1
##   0  1  5
##   1  0 11
## 
## Proportions by SH_Feedback (column-wise):
##    
##        0    1
##   0 1.00 0.31
##   1 0.00 0.69
## 
## --- Outcome_Project_Commitment ---
##    
##      0  1
##   0  1  6
##   1  2 14
## 
## Proportions by SH_Feedback (column-wise):
##    
##        0    1
##   0 0.33 0.30
##   1 0.67 0.70
## 
## --- Outcome_Model_Ownership_Responsibility ---
##     
##      0 1
##   -1 1 1
##   0  0 1
##   1  4 7
## 
## Proportions by SH_Feedback (column-wise):
##     
##         0    1
##   -1 0.20 0.11
##   0  0.00 0.11
##   1  0.80 0.78
## 
## --- Outcome_Collective_Efficacy ---
##    
##     0 1
##   1 1 3
## 
## Proportions by SH_Feedback (column-wise):
##    
##     0 1
##   1 1 1
## 
## --- Outcome_Dec_Quality ---
##    
##     0 1
##   1 2 8
## 
## Proportions by SH_Feedback (column-wise):
##    
##     0 1
##   1 1 1
## 
## --- Outcome_Missing_Dat ---
##    
##      0  1
##   1  3 17
## 
## Proportions by SH_Feedback (column-wise):
##    
##     0 1
##   1 1 1
## 
## --- Outcome_Trust_In_Process ---
##     
##      0 1
##   -1 1 0
##   0  1 5
##   1  1 8
## 
## Proportions by SH_Feedback (column-wise):
##     
##         0    1
##   -1 0.33 0.00
##   0  0.33 0.38
##   1  0.33 0.62
## 
## --- Outcome_Opinion_Exp ---
##    
##      0  1
##   0  1  1
##   1  9 26
## 
## Proportions by SH_Feedback (column-wise):
##    
##        0    1
##   0 0.10 0.04
##   1 0.90 0.96
## 
## --- Outcome_Info_Share ---
##    
##      0  1
##   0  1  4
##   1  8 18
## 
## Proportions by SH_Feedback (column-wise):
##    
##        0    1
##   0 0.11 0.18
##   1 0.89 0.82
## 
## --- Outcome_Creative_Idea_Gen ---
##    
##      0  1
##   0  1  0
##   1 15 27
## 
## Proportions by SH_Feedback (column-wise):
##    
##        0    1
##   0 0.06 0.00
##   1 0.94 1.00
## 
## --- Outcome_Shared_Language ---
##    
##     0 1
##   0 0 2
##   1 2 7
## 
## Proportions by SH_Feedback (column-wise):
##    
##        0    1
##   0 0.00 0.22
##   1 1.00 0.78
## 
## --- Outcome_AP_Com_Imp ---
##     
##       0  1
##   -1  4  9
##   0   1  3
##   1   9 22
## 
## Proportions by SH_Feedback (column-wise):
##     
##         0    1
##   -1 0.29 0.26
##   0  0.07 0.09
##   1  0.64 0.65
## 
## --- Outcome_Model_Pos ---
##     
##       0  1
##   -1  0  1
##   0   5  8
##   1   7 23
## 
## Proportions by SH_Feedback (column-wise):
##     
##         0    1
##   -1 0.00 0.03
##   0  0.42 0.25
##   1  0.58 0.72
## 
## --- Outcome_Proj_Ownership ---
##     
##      0 1
##   -1 1 0
##   0  0 1
##   1  2 8
## 
## Proportions by SH_Feedback (column-wise):
##     
##         0    1
##   -1 0.33 0.00
##   0  0.00 0.11
##   1  0.67 0.89
## 
## --- Outcome_Relationships ---
##     
##       0  1
##   -1  1  0
##   0   0  2
##   1   8 14
## 
## Proportions by SH_Feedback (column-wise):
##     
##         0    1
##   -1 0.11 0.00
##   0  0.00 0.12
##   1  0.89 0.88
## 
## --- Outcome_Pos_Response ---
##     
##       0  1
##   -1  1  0
##   0   3 16
##   1  11 33
## 
## Proportions by SH_Feedback (column-wise):
##     
##         0    1
##   -1 0.07 0.00
##   0  0.20 0.33
##   1  0.73 0.67

Number of Outcomes Reported

# Count number of non-NA Outcome_ variables per case
data$N_Reported_Outcomes <- rowSums(!is.na(data[outcome_vars]))

# T-test comparing stakeholder feedback conditions
t_test_result <- t.test(N_Reported_Outcomes ~ SH_Feedback, data = data)

# View results
print(t_test_result)
## 
##  Welch Two Sample t-test
## 
## data:  N_Reported_Outcomes by SH_Feedback
## t = -2.5349, df = 64.636, p-value = 0.01368
## alternative hypothesis: true difference in means between group 0 and group 1 is not equal to 0
## 95 percent confidence interval:
##  -3.9348890 -0.4666704
## sample estimates:
## mean in group 0 mean in group 1 
##        7.851852       10.052632

Testing Assumptions

ASSUMPTION 1: Facilitation Enhances Information Sharing Behaviour

Step 1: Diversity + Active Participation + Procedural Justice → Information Sharing

# Create dataframe for qca
qca_IN <- data.frame(
  PJ = data$CH_PJ_rescale,
  AP = data$CH_SH_Engagement,
  DIV= data$CH_Diverse_SH_Recruitment,
  IN= data$Outcome_Info_Share
)

# Recalibrate PJ and DIV into binary variables due to low ns. 
  ## Stricter recalibration of DIV retains only cases of high diversity as successful outcome. 
  ## More lenient callibration of PJ is necessary here due to low frequency of cases with PJ > 1. 

qca_IN <- qca_IN %>%
  mutate(
    PJ = case_when(
      PJ <= 0.67 ~ 0,
      PJ == 1 ~ 1,
      PJ >= 1.33 ~ 1
    ),
    DIV = case_when(
      DIV == -1 ~ 0,
      DIV == 0 ~ 0,
      DIV == 1 ~ 1
    )
  )

#Remove NAs
qca_IN_exclusions <- qca_IN%>% 
  drop_na(AP, PJ, IN, DIV)

#Generate truth table
tt_IN <- truthTable(qca_IN_exclusions, outcome = "IN", conditions = c("AP", "PJ", "DIV"), type = "mv", incl.cut = 0.8, n.cut= 3, show.cases = TRUE)
tt_IN
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     AP PJ DIV   OUT    n  incl  PRI   cases            
## 2   0  0   1     0     3  0.667 0.667 10,13,16         
## 5   1  0   0     0     3  0.667 0.667 21,22,23         
## 6   1  0   1     1     7  0.857 0.857 1,6,9,12,14,17,19
## 8   1  1   1     1     3  1.000 1.000 3,4,5
solution_IN <- minimize(tt_IN, details= TRUE)
solution_IN
## 
## M1: AP*DIV -> IN
## 
##            inclS   PRI   covS   covU   cases 
## --------------------------------------------------------------- 
## 1  AP*DIV  0.900  0.900  0.474    -    1,6,9,12,14,17,19; 3,4,5 
## --------------------------------------------------------------- 
##        M1  0.900  0.900  0.474

Conclusion: AP and Diversity in combination sufficiently predict positive effects on information sharing behaviour. PJ is not associated with information sharing behaviour

Step 2: Participative Environment → Active Participation + Procedural Justice

Participative Environment → Procedural Justice
# Create dataframe for qca
qca_PE_PJ <- data.frame(
  PE = data$CH_PE_rescale,
  PJ = data$CH_PJ_rescale
)

# Recalibrate PE and PJ. 
  ## More lenient callibration of PJ is necessary here due to low frequency of cases with PJ > 1. 

qca_PE_PJ <- qca_PE_PJ %>%
    mutate(
    PE = case_when(
      PE <= 0.5 ~ 0,
      PE == 1 ~ 1,
      PE >= 1.5 ~ 2
    ),
    PJ = case_when(
      PJ <= 0.67 ~ 0,
      PJ == 1 ~ 1,
      PJ >= 1.33 ~ 1
    )
  )

# Remove NAs
qca_PE_PJ_exclusions <- qca_PE_PJ%>% 
  drop_na(PE, PJ)

# Generate truth table
tt_PE_PJ <- truthTable(qca_PE_PJ_exclusions, outcome = "PJ", conditions = c("PE"), incl.cut = 0.8, n.cut = 3, show.cases = TRUE)
tt_PE_PJ
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     PE   OUT    n   incl  PRI  
## 1   0     0     25  0.080 0.080
## 2   1     0     12  0.083 0.083
## 3   2     0     47  0.234 0.234
##     cases                                                                                                                                 
## 1   1,7,8,11,12,19,28,29,34,40,41,44,48,49,58,59,61,62,63,65,67,76,78,79,84                                                               
## 2   30,31,35,37,38,39,47,53,57,68,74,81                                                                                                   
## 3   2,3,4,5,6,9,10,13,14,15,16,17,18,20,21,22,23,24,25,26,27,32,33,36,42,43,45,46,50,51,52,54,55,56,60,64,66,69,70,71,72,73,75,77,80,82,83
## 
## It seems that all output values have been coded to zero.
## Suggestion: lower the inclusion score for the presence of the outcome,
## the relevant argument is "incl.cut" which now has a value of 0.8.

Conclusion: PE did not sufficiently predict PJ at any level.

Participative Environment → Active Participation
# Create dataframe for qca
qca_PE_AP <- data.frame(
  PE = data$CH_PE_rescale,
  AP = data$CH_SH_Engagement
)

# Recalibrate PE
qca_PE_AP <- qca_PE_AP %>%
    mutate(
    PE = case_when(
      PE <= 0.5 ~ 0,
      PE == 1 ~ 1,
      PE >= 1.5 ~ 2
    )
  )

# Remove NAs
qca_PE_AP_exclusions <- qca_PE_AP%>% 
  drop_na(PE, AP)


# Generate truth table
tt_PE_AP <- truthTable(qca_PE_AP_exclusions, outcome = "AP", conditions = c("PE"), incl.cut = 0.8, n.cut = 3, show.cases = TRUE)
tt_PE_AP
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     PE   OUT    n   incl  PRI  
## 1   0     0     17  0.588 0.588
## 2   1     1     6   0.833 0.833
## 3   2     0     40  0.775 0.775
##     cases                                                                                                            
## 1   1,7,8,11,12,27,30,31,34,36,44,45,47,48,49,51,60                                                                  
## 2   24,28,35,43,58,62                                                                                                
## 3   2,3,4,5,6,9,10,13,14,15,16,17,18,19,20,21,22,23,25,26,29,32,33,37,38,39,40,41,42,46,50,52,53,54,55,56,57,59,61,63
### Note: High PE fell just below threshold of 0.8 but very high N (40)
solution_PE_AP <- minimize(tt_PE_AP, details= TRUE)
solution_PE_AP
## 
## M1: PE[1] -> AP[1]
## 
##           inclS   PRI   covS   covU   cases 
## ------------------------------------------------------- 
## 1  PE[1]  0.833  0.833  0.109    -    24,28,35,43,58,62 
## ------------------------------------------------------- 
##       M1  0.833  0.833  0.109

Conclusion: Association between participative environments and active participation is supported.

Step 3: Active Participation + Procedural Justice → Information Sharing

(Testing mechanism without influence of diversity)

# Generate dataframe for qca
qca_AP_PJ_IN <- data.frame(
  PJ = data$CH_PJ_rescale,
  IN= data$Outcome_Info_Share,
  AP = data$CH_SH_Engagement
)

#Recalibrate PJ. 
  ## More lenient, binary calibration required due to low frequency of cases where PJ > 1.
qca_AP_PJ_IN  <- qca_AP_PJ_IN  %>%
  mutate(
    PJ = case_when(
      PJ <= 0.67 ~ 0,
      PJ == 1 ~ 1,
      PJ >= 1.33 ~ 1
    )
  )

# Drop nas
qca_AP_PJ_IN_exclusions <- qca_AP_PJ_IN%>% 
  drop_na(PJ, IN, AP)

#Generate truth table
  ##Note: n.cut not used here due to low variance of IN
tt_AP_PJ_IN <- truthTable(qca_AP_PJ_IN_exclusions, outcome = "IN", conditions = c("AP", "PJ"), type = "mv", incl.cut = 0.8, show.cases = TRUE)
tt_AP_PJ_IN
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     AP PJ   OUT    n   incl  PRI   cases                           
## 1   0  0     1     5   0.800 0.800 8,9,11,14,17                    
## 2   0  1     0     3   0.667 0.667 2,12,16                         
## 3   1  0     1     12  0.833 0.833 1,6,7,10,13,15,18,20,22,23,24,25
## 4   1  1     1     5   1.000 1.000 3,4,5,19,21
solution_AP_PJ_IN <- minimize(tt_AP_PJ_IN, details= TRUE)
solution_AP_PJ_IN 
## 
## M1: AP + ~PJ -> IN
## 
##         inclS   PRI   covS   covU   cases 
## ---------------------------------------------------------------------------------- 
## 1   AP  0.882  0.882  0.714  0.238  1,6,7,10,13,15,18,20,22,23,24,25; 3,4,5,19,21 
## 2  ~PJ  0.824  0.824  0.667  0.190  8,9,11,14,17; 1,6,7,10,13,15,18,20,22,23,24,25 
## ---------------------------------------------------------------------------------- 
##     M1  0.864  0.864  0.905

Conclusion: Active participation is sufficient but not necessary for enhanced information sharing, and may compensate for low procedural justice in some cases. Procedural justice did not emerge as a meaningful differentiator overall.

Step 4: Diversity + Participative Environment → Information Sharing

# Create dataframe for qca
qca_PE_DIV_IN <- data.frame(
  PE = data$CH_PE_rescale,
  DIV = data$CH_Diverse_SH_Recruitment,
  IN= data$Outcome_Info_Share
)

#Recalibrate PE and DIV.
  ## Again, strict recalibration of DIV means only cases of high diversity are coded as 1.
qca_PE_DIV_IN <- qca_PE_DIV_IN %>%
    mutate(
    PE = case_when(
      PE <= 0.5 ~ 0,
      PE == 1 ~ 1,
      PE >= 1.5 ~ 2
    ),
    DIV = case_when(
      DIV == -1 ~ 0,
      DIV == 0 ~ 0,
      DIV == 1 ~ 1
    )
  )

#Remove NAs
qca_PE_DIV_IN_exclusions <- qca_PE_DIV_IN%>% 
  drop_na(PE, DIV, IN)

#Generate truth table
  ##Note: n.cut not used here due to low frequency of IN=0. 
tt_PE_DIV_IN <- truthTable(qca_PE_DIV_IN_exclusions, outcome = "IN", conditions = c("PE", "DIV"), incl.cut = 0.8, show.cases = TRUE)
tt_PE_DIV_IN
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     PE DIV   OUT    n   incl  PRI   cases                         
## 1   0   0     0     1   0.000 0.000 7                             
## 2   0   1     1     4   1.000 1.000 5,15,26,28                    
## 3   1   0     1     1   1.000 1.000 25                            
## 4   1   1     0     2   0.500 0.500 12,16                         
## 5   2   0     0     8   0.750 0.750 2,9,10,17,21,23,24,27         
## 6   2   1     1     12  0.917 0.917 1,3,4,6,8,11,13,14,18,19,20,22
solution_PE_DIV_IN <- minimize(tt_PE_DIV_IN, details= TRUE)
solution_PE_DIV_IN 
## 
## M1: PE[1]*DIV[0] + PE[2]*DIV[1] + PE[0]*DIV[1] -> IN[1]
## 
##                  inclS   PRI   covS   covU   cases 
## --------------------------------------------------------------------------- 
## 1  PE[1]*DIV[0]  1.000  1.000  0.043  0.043  25 
## 2  PE[2]*DIV[1]  0.917  0.917  0.478  0.478  1,3,4,6,8,11,13,14,18,19,20,22 
## 3  PE[0]*DIV[1]  1.000  1.000  0.174  0.174  5,15,26,28 
## --------------------------------------------------------------------------- 
##              M1  0.941  0.941  0.696

Conclusion: Claims for the interactive effect of diversity and participative environments on information sharing are thus supported.

ASSUMPTION 2: Facilitation Enhances Collective Knowledge of the Problem

Step 1: Collaborative Model Building + Collective Learning → Shared Understanding

# Create dataframe for qca
qca_CMB_CLEARN_UND <- data.frame(
  CMB = data$CH_Int_Model_Dev,
  UND = data$Outcome_Shared_Understanding,
  CLEARN = data$Outcome_Learning_Collective
)

#Remove NAs
qca_CMB_CLEARN_UND_exclusions <- qca_CMB_CLEARN_UND%>% 
  drop_na(CMB, UND, CLEARN)

#Recalibrate MB
qca_CMB_CLEARN_UND_exclusions <- qca_CMB_CLEARN_UND_exclusions %>%
    mutate(
    CMB = case_when(
      CMB == 1 ~ 2,
      CMB == 0 ~ 1,
      CMB == -1 ~ 0
    )
 )

##Generate truth table
##Note: n.cut not used here due to low variance of shared understanding
tt_CMB_CLEARN_UND <- truthTable(qca_CMB_CLEARN_UND_exclusions,
  outcome = "UND",
  conditions = c("CMB", "CLEARN"),
  incl.cut = 0.95,
  show.cases = TRUE
)

tt_CMB_CLEARN_UND
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     CMB CLEARN   OUT    n   incl  PRI  
## 2    0    1       0     2   0.500 0.500
## 3    1    0       0     1   0.000 0.000
## 4    1    1       0     18  0.944 0.944
## 5    2    0       1     1   1.000 1.000
## 6    2    1       1     22  0.955 0.955
##     cases                                                     
## 2   20,41                                                     
## 3   23                                                        
## 4   5,9,12,13,14,15,18,19,21,24,25,26,30,31,32,34,38,44       
## 5   29                                                        
## 6   1,2,3,4,6,7,8,10,11,16,17,22,27,28,33,35,36,37,39,40,42,43
solution_CMB_CLEARN_UND <- minimize (tt_CMB_CLEARN_UND, details= TRUE)
solution_CMB_CLEARN_UND
## 
## M1: CMB[2] -> UND[1]
## 
##            inclS   PRI   covS   covU  
## ------------------------------------- 
## 1  CMB[2]  0.957  0.957  0.550    -   
## ------------------------------------- 
##        M1  0.957  0.957  0.550 
## 
##            cases 
## ---------------- 
## 1  CMB[2]  29; 1,2,3,4,6,7,8,10,11,16,17,22,27,28,33,35,36,37,39,40,42,43
## ----------------

Conclusion: Collaborative model building is sufficient but not necessary for development of shared understanding. Collective learning emerges as a sufficient predictor only under cases of fully collaborative model building

Step 2: Collaborative Model Building → Collective Learning

# generate dataframe for qca
qca_CMB_CLEARN <- data.frame(
  CLEARN = data$Outcome_Learning_Collective,
  CMB = data$CH_Int_Model_Dev
)

#Remove NAs
qca_CMB_CLEARN_exclusions <- qca_CMB_CLEARN%>% 
  drop_na(CLEARN, CMB)

#Recalibrate model building variable
qca_CMB_CLEARN_exclusions <- qca_CMB_CLEARN_exclusions %>%
    mutate(
    CMB = case_when(
      CMB == 1 ~ 2,
      CMB == 0 ~ 1,
      CMB == -1 ~ 0
    )
 )

#Generate truth table. Low variance of collective learning means n.cut not used and analysis limited to descriptive only.
tt_CMB_CLEARN <- truthTable(
  qca_CMB_CLEARN_exclusions,
  outcome = "CLEARN",
  conditions = c("CMB"),
  incl.cut = 0.95,
  show.cases = TRUE
)
tt_CMB_CLEARN
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     CMB   OUT    n   incl  PRI  
## 1    0     1     2   1.000 1.000
## 2    1     0     28  0.929 0.929
## 3    2     1     28  0.964 0.964
##     cases                                                                             
## 1   24,55                                                                             
## 2   6,10,14,15,16,17,21,22,23,25,27,28,29,30,31,32,33,34,38,39,40,43,44,45,46,47,52,58
## 3   1,2,3,4,5,7,8,9,11,12,13,18,19,20,26,35,36,37,41,42,48,49,50,51,53,54,56,57

Conclusion: Only two cases of no collaborative model building that reported collective learning- too low to draw conclusions. Only fully collaborative model building was a sufficient predictor of collective learning.

ASSUMPTION 3: Facilitation Enhances Commitment to Implement Action Plans

Procedural Justice Mechanism

Step 1: Participative Environment Procedural Justice

Analysis previously conducted, with no support found: [Participative Environment → Procedural Justice]

Step 2: Procedural Justice Interpersonal Relationship Improvement + Decision Outcome Confidence
Procedural Justice → Interpersonal Relationship Improvement
# Generate dataframe for qca
qca_PJ_IR <- data.frame(
  PJ = data$CH_PJ_rescale,
  IR = data$Outcome_Relationships
)

#Remove NAs
qca_PJ_IR_exclusions <- qca_PJ_IR%>% 
  drop_na(PJ, IR)

#Recalibrate PJ and IR
  ## Strict calibration of IR means only cases of fully positive effects = 1
qca_PJ_IR_exclusions <- qca_PJ_IR_exclusions %>%
    mutate(
    PJ = case_when(
      PJ <= 0.67 ~ 0,
      PJ == 1 ~ 1,
      PJ >= 1.33 ~ 2
    ),
    IR= case_when(
      IR == -1 ~ 0,
      IR == 0 ~ 0,
      IR == 1 ~ 1
    )
  )
#Generate truthtable
  ##Note: n.cut not used due to low variance of IR
tt_PJ_IR <- truthTable(
  qca_PJ_IR_exclusions,
  outcome = "IR",
  conditions = c("PJ"),
  incl.cut = 0.8,
  type= "mv",
  show.cases = TRUE,
  complete= TRUE
)

tt_PJ_IR
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     PJ   OUT    n   incl  PRI   cases                                        
## 1   0     1     17  0.824 0.824 2,5,7,8,9,10,12,13,14,15,16,18,19,20,23,24,25
## 2   1     1     2   1.000 1.000 1,17                                         
## 3   2     1     6   1.000 1.000 3,4,6,11,21,22

Conclusion: Low variance prevents configurational analysis. Descriptive analysis shows low levels of procedural justice may occasionally lead to weak/non-improvement of interpersonal relationships, but the association between the two variables is not generally supported by the data.

Procedural Justice → Decision Outcome Confidence
# Generate qca df
  ## Exploratory approach due to limited frequency of decision confidence outcome reporting: Combine confidence in model outputs + dec confidence
qca_PJ_CONF <- data.frame(
  PJ = data$CH_PJ_rescale,
  DEC = data$Outcome_Decision_Confidence,
  OUT = data$Outcome_Model_Output_Conf
)

qca_PJ_CONF <- qca_PJ_CONF %>%
  rowwise() %>%
  mutate(CONF = {
    values <- c_across(c("DEC", "OUT"))
    values <- values[!is.na(values)]

    if (length(values) == 0) {
      NA_real_
    } else if (length(unique(values)) == 1) {
      unique(values)
    } else {
      0
    }
  }) %>%
  ungroup()

      ## Delete old variables
      qca_PJ_CONF$DEC <- NULL
      qca_PJ_CONF$OUT <- NULL

# Remove NAs
qca_PJ_CONF_exclusions <- qca_PJ_CONF%>% 
  drop_na(PJ, CONF)


# Recalibrate PJ. 
## Low frequencies of PJ > 1 necessitate lenient binary callibration, where mid and high levels of PJ= 1
qca_PJ_CONF_exclusions <- qca_PJ_CONF_exclusions %>%
    mutate(
    PJ = case_when(
      PJ <= 0.67 ~ 0,
      PJ == 1 ~ 1,
      PJ >= 1.33 ~ 1
    )
  )

#Generate truth table
tt_PJ_CONF <- truthTable(
  qca_PJ_CONF_exclusions,
  outcome = "CONF",
  conditions = c("PJ"),
  incl.cut = 0.8,
  n.cut = 3,
  type= "cs",
  show.cases = TRUE,
  complete= TRUE
)

tt_PJ_CONF
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     PJ   OUT    n   incl  PRI   cases                                        
## 1   0     0     18  0.722 0.722 1,2,3,4,6,7,8,9,11,13,15,16,17,18,20,21,22,23
## 2   1     1     5   0.800 0.800 5,10,12,14,19

Conclusion: Similar inclusion values for procedural justice at all levels does not support role of procedural justice.

Step 3: Decision Outcome Confidence + Interpersonal Relationship Improvement Action Plan Commitment

Low sample sizes for combined qca necessitate separate tests of decision outcome confidence and relationships

Decision Outcome Confidence Action Plan Commitment / Implementation
#Create qca df. 
  ## As before, combine indicators of outcome confidence.  
qca_CONF_COM <- data.frame(
  CONF1= data$Outcome_Decision_Confidence,
  CONF2= data$Outcome_Model_Output_Conf,
  COM = data$Outcome_AP_Com_Imp
)

qca_CONF_COM <- qca_CONF_COM %>%
  rowwise() %>%
  mutate(CONF = {
    values <- c_across(c("CONF1", "CONF2"))
    values <- values[!is.na(values)]

    if (length(values) == 0) {
      NA_real_
    } else if (length(unique(values)) == 1) {
      unique(values)
    } else {
      0
    }
  }) %>%
  ungroup()  

    ### Delete old variables
      qca_CONF_COM$CONF1 <- NULL
      qca_CONF_COM$CONF2 <- NULL

#Remove NAs
qca_CONF_COM_exclusions <- qca_CONF_COM%>% 
  drop_na(CONF, COM)

# Recalibrate AP commitment/implementation into binary outcome. 
  ## Strict callibration means only cases of positive effects = 1, partial effects = 0
qca_CONF_COM_exclusions <- qca_CONF_COM_exclusions %>%
    mutate(
    COM = case_when(
      COM == -1 ~ 0,
      COM == 0 ~ 0,
      COM == 1 ~ 1
    )
  )

#Generate truth table
tt_CONF_COM <- truthTable(
  qca_CONF_COM_exclusions,
  outcome = "COM",
  conditions = c("CONF"),
  incl.cut = 0.8,
  n.cut = 3,
  type= "cs",
  show.cases = TRUE,
  complete= TRUE
)

tt_CONF_COM
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     CONF   OUT    n   incl  PRI   cases                   
## 1    0      0     6   0.500 0.500 3,5,6,7,10,16           
## 2    1      1     10  0.800 0.800 1,2,4,8,9,11,12,13,14,15
solution_CONF_COM <- minimize(tt_CONF_COM, details = TRUE, method = "QMC", type = "cs")
solution_CONF_COM
## 
## M1: CONF -> COM
## 
##          inclS   PRI   covS   covU   cases 
## ------------------------------------------------------------- 
## 1  CONF  0.800  0.800  0.727    -    1,2,4,8,9,11,12,13,14,15 
## ------------------------------------------------------------- 
##      M1  0.800  0.800  0.727

Conclusion: Decision confidence is a sufficient predictor of commitment/ implementation.

Interpersonal Relationship Improvement → Action Plan Commitment / Implementation
# Create qca df. 
qca_IR_COM <- data.frame(
  IR= data$Outcome_Relationships,
  COM = data$Outcome_AP_Com_Imp
)

# Remove NAs
qca_IR_COM_exclusions <- qca_IR_COM%>% 
  drop_na(IR, COM)

# Recalibrate IR and AP commitment/implementation into binary variables due to low ns. 
  ##Strict callibration means only present/positive variables = 1, partials = 0
qca_IR_COM_exclusions <- qca_IR_COM_exclusions %>%
    mutate(
    COM = case_when(
      COM == -1 ~ 0,
      COM == 0 ~ 0,
      COM == 1 ~ 1
    ),
    IR = case_when(
      IR == -1 ~ 0,
      IR == 0 ~ 0,
      IR == 1 ~ 1
    )
  )

# Generate truth table
  # Note: n.cut not used due to low ns. Configurational analysis not conducted.
tt_IR_COM <- truthTable(
  qca_IR_COM_exclusions,
  outcome = "COM",
  conditions = c("IR"),
  incl.cut = 0.8,
  type= "cs",
  show.cases = TRUE,
  complete= TRUE
)

tt_IR_COM
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     IR   OUT    n   incl  PRI   cases                         
## 1   0     0     2   0.000 0.000 3,11                          
## 2   1     0     13  0.692 0.692 1,2,4,5,6,7,8,9,10,12,13,14,15
## 
## It seems that all output values have been coded to zero.
## Suggestion: lower the inclusion score for the presence of the outcome,
## the relevant argument is "incl.cut" which now has a value of 0.8.

Conclusion: Low frequency of cases where IR = 0 prevent solution configuration. Descriptive analysis does not clearly support association between relationship improvement and commitment.

Procedural Rationality Mechanism

Step 1: Collaborative Model Building+ Experimentation Procedural Rationality
# Create qca df. 
qca_MOD_PR <- data.frame(
  CMB= data$CH_Int_Model_Dev,
  EXP = data$CH_Model_Experiment,
  PR = data$CH_Proc_Rat_Transparency
)

#Remove NAs
qca_MOD_PR_exclusions <- qca_MOD_PR%>% 
  drop_na(CMB, EXP, PR)


# Recalibrate CMB
qca_MOD_PR_exclusions <- qca_MOD_PR_exclusions %>%
    mutate(
    CMB = case_when(
      CMB == -1 ~ 0,
      CMB == 0 ~ 1,
      CMB == 1 ~ 2
    )
  )

#Generate truth table
  ## Note: n.cut not used here due to low frequencies of 0s. Configurational analysis not conducted.
tt_MOD_PR <- truthTable(
  qca_MOD_PR_exclusions,
  outcome = "PR",
  conditions = c("CMB", "EXP"),
  incl.cut = 0.9,
  type= "mv",
  show.cases = TRUE
)

tt_MOD_PR
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     CMB EXP   OUT    n   incl  PRI   cases                             
## 2    0   1     0     2   0.500 0.500 9,15                              
## 3    1   0     1     7   1.000 1.000 3,7,8,10,18,22,26                 
## 4    1   1     0     12  0.833 0.833 4,11,12,13,14,16,19,20,21,23,27,28
## 6    2   1     1     7   1.000 1.000 1,2,5,6,17,24,25

Conclusion: Combination of Collaborative model building and experimentation at full and partial levels sufficiently predict procedural rationality. Two out of three cases of partial procedural rationality had no collaborative model building, suggesting the experimentation on models that have no input from stakeholders may not reliably elicit high perceived procedural rationality. This further supports the value of the model building process in procedural rationality.

Step 2: Procedural Rationality + Collaborative Model Building + Experimentation Action Plan Commitment / Implementation
# Create qca df. 
qca_PR_MODEL_COM <- data.frame(
  PR = data$CH_Proc_Rat_Transparency,
  CMB = data$CH_Int_Model_Dev,
  COM = data$AP_Com_Imp_Rescale,
  EXP= data$CH_Model_Experiment
)

#Remove NAs
qca_PR_MODEL_COM_exclusions <- qca_PR_MODEL_COM %>% 
  drop_na(PR, COM, CMB, EXP)

#Generate truth table
  ## Note: n.cut not used here due to low frequencies of 0s
tt_PR_MODEL_COM <- truthTable(
  qca_PR_MODEL_COM_exclusions,
  outcome = "COM",
  conditions = c("PR", "CMB", "EXP"),
  incl.cut = 0.9,
  type= "cs",
  show.cases = TRUE
)
tt_PR_MODEL_COM
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     PR CMB EXP   OUT    n  incl  PRI   cases         
## 2   0   0   1     1     2  1.000 1.000 2,7           
## 5   1   0   0     0     6  0.667 0.667 4,5,6,10,13,15
## 6   1   0   1     1     3  1.000 1.000 8,11,12       
## 8   1   1   1     1     4  1.000 1.000 1,3,9,14
solution_PR_MODEL_COM <- minimize(tt_PR_MODEL_COM, details= TRUE, method= "QMC", negate= TRUE)
solution_PR_MODEL_COM
## 
## M1: PR*EXP + ~CMB*EXP -> COM
## 
##              inclS   PRI   covS   covU   cases 
## ---------------------------------------------------------- 
## 1    PR*EXP  1.000  1.000  0.538  0.308  8,11,12; 1,3,9,14 
## 2  ~CMB*EXP  1.000  1.000  0.385  0.154  2,7; 8,11,12 
## ---------------------------------------------------------- 
##          M1  1.000  1.000  0.692

Conclusion: Experimentation of partially or fully collaboratively developed models is sufficient, but not necessary, to elicit high perceived procedural rationality. Procedural rationality is sufficient in the presence of full model experimentation to elicit commitment to implement action plans, regardless of the presence of collaborative model building. Therefore, negotiation using collaboratively developed models may enhance the probability of procedural rationality, but procedural rationality elicited through other facilitation processes may still reliably lead to action plan commitment.

ASSUMPTION 4: Facilitation Promotes Consensus

# Create qca df. 
qca_CON <- data.frame(
  CONFLICT = data$CH_Conflict_Man,
  CONSENSUS = data$Outcome_Consensus,
  COG = data$Outcome_Cog_Change
)

# Remove NAs
qca_CON_exclusions <- qca_CON %>% 
  drop_na(COG, CONFLICT, CONSENSUS)

#Generate truth table
  ## Note: n.cut not used here due to limited variance. 
tt_CON <- truthTable(
  qca_CON_exclusions,
  outcome = "CONSENSUS",
  conditions = c("COG", "CONFLICT"),
  incl.cut = 0.8,
  type= "cs",
  show.cases = TRUE
)
tt_CON
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     COG CONFLICT   OUT    n   incl  PRI  
## 1    0     0        0     2   0.500 0.500
## 3    1     0        0     4   0.500 0.500
## 4    1     1        1     16  0.938 0.938
##     cases                                    
## 1   6,21                                     
## 3   4,9,18,22                                
## 4   1,2,3,5,7,8,10,11,12,13,14,15,16,17,19,20
solution_CON <- minimize(tt_CON, details= TRUE, method= "QMC", negate= TRUE)
solution_CON
## 
## M1: COG*CONFLICT -> CONSENSUS
## 
##                  inclS   PRI   covS   covU  
## ------------------------------------------- 
## 1  COG*CONFLICT  0.938  0.938  0.833    -   
## ------------------------------------------- 
##              M1  0.938  0.938  0.833 
## 
##                  cases 
## ---------------------- 
## 1  COG*CONFLICT  1,2,3,5,7,8,10,11,12,13,14,15,16,17,19,20
## ----------------------

ASSUMPTION 5: Facilitation Promotes Positive Organisational Change

Step 1. Commitment Implementation of Action Plans

# Create qca df. 
qca_COM_IMP <- data.frame(
  IMP = data$Composite_AP_Implementation,
  COM = data$Composite_AP_Commitment
)

#Remove NAs
qca_COM_IMP_exclusions <- qca_COM_IMP %>% 
  drop_na(COM, IMP)

#Recalibrate COM AND IMP. 
  ## Low ns necessitate binary calibration. Strict calibration means partial values = 0
qca_COM_IMP_exclusions <- qca_COM_IMP_exclusions %>%
    mutate(
    IMP = case_when(
      IMP == -1 ~ 0,
      IMP == 0 ~ 0,
      IMP == 1 ~ 1
    ),
    COM = case_when(
      COM == -1 ~ 0,
      COM == 0 ~ 0,
      COM == 1 ~ 1
    )
  )

#Generate truth table
  ## Note: n.cut not used here due to low frequencies of 0s. Configurational analysis not conducted.
tt_COM_IMP <- truthTable(
  qca_COM_IMP_exclusions,
  outcome = "IMP",
  conditions = c("COM"),
  incl.cut = 0.8,
  type= "cs",
  show.cases = TRUE
)
tt_COM_IMP
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     COM   OUT    n   incl  PRI   cases                    
## 1    0     0     2   0.000 0.000 4,6                      
## 2    1     0     11  0.727 0.727 1,2,3,5,7,8,9,10,11,12,13
## 
## It seems that all output values have been coded to zero.
## Suggestion: lower the inclusion score for the presence of the outcome,
## the relevant argument is "incl.cut" which now has a value of 0.8.

Conclusion: Whilst no cases of non- or weak commitment reported implementation, high commitment fell just short of the sufficiency threshold. This likely reflects cases where implementation did not occur due to external factors.

Step 2. Implementation + Decision Quality Positive Organisational Change

# Create qca df. 
qca_DEC_IMP <- data.frame(
  IMP = data$Composite_AP_Implementation,
  DEC = data$Outcome_Dec_Quality,
  POS = data$Outcome_Positive_Org_Change
)

# Remove NAs
qca_DEC_IMP_exclusions <- qca_DEC_IMP %>% 
  drop_na(IMP, POS)

# Recalibrate DEC, IMP and POS
## EXPLORATORY: Retain cases not mentioning decision quality due to low n and variance
qca_DEC_IMP_exclusions <- qca_DEC_IMP_exclusions %>%
    mutate(
    DEC = case_when(
      is.na(qca_DEC_IMP_exclusions$DEC) ~ 0,
      DEC == 1 ~ 1
    ),
    IMP = case_when(
      IMP == -1 ~ 0,
      IMP == 0 ~ 0,
      IMP == 1 ~ 1
    ),
    POS = case_when(
      POS == -1 ~ 0,
      POS == 0 ~ 0,
      POS == 1 ~ 1
    )
  )

#Generate truth table
  ## Note: n.cut not used here due to low frequencies of 0s
tt_DEC_IMP <- truthTable(
  qca_DEC_IMP_exclusions,
  outcome = "POS",
  conditions = c("DEC", "IMP"),
  incl.cut = 0.8,
  type= "cs",
  show.cases = TRUE
)
tt_DEC_IMP
## 
##   OUT: output value
##     n: number of cases in configuration
##  incl: sufficiency inclusion score
##   PRI: proportional reduction in inconsistency
## 
##     DEC IMP   OUT    n   incl  PRI   cases                       
## 1    0   0     0     9   0.444 0.444 1,3,6,8,10,13,16,19,22      
## 2    0   1     1     11  0.909 0.909 4,5,7,9,11,12,17,18,20,21,23
## 3    1   0     0     1   0.000 0.000 15                          
## 4    1   1     1     2   1.000 1.000 2,14
solution_DEC_IMP <- minimize(tt_DEC_IMP, details= TRUE, method= "QMC", negate= TRUE)
solution_DEC_IMP
## 
## M1: IMP -> POS
## 
##         inclS   PRI   covS   covU   cases 
## ---------------------------------------------------------------------- 
## 1  IMP  0.923  0.923  0.750    -    4,5,7,9,11,12,17,18,20,21,23; 2,14 
## ---------------------------------------------------------------------- 
##     M1  0.923  0.923  0.750

Conclusion: Whilst commitment may increase the likelihood of implementation, successful implementation does not always occur, commonly due to external barriers that were not accounted for during the facilitation process. When implementation does occur, positive organisational change reliably occurs, regardless of whether decision quality is explicitly reported.

Summary of Findings

Assumption Findings Conclusion

Facilitation enhances information sharing:

  • Diverse

stakeholder

recruitment

  • Participative

    Environment Active

    Participation +
    Procedural Justice

Diversity and participative environments are sufficient predictors of enhanced information sharing.

The active participation mechanism showed sufficiency, whilst the procedural justice mechanism did not.

Assumption mechanism partially supported.

Facilitation enhances collective knowledge of the problem

  • Collaborative model building Shared language + Collective learning Shared

    understanding

Unable to test shared language mechanism.

Fully collaborative model building was sufficient predictor of collective learning and shared understanding.

Collective learning was sufficient predictor of shared understanding only under cases of fully collaborative model building.

Support for collective learning assumption mechanism.

More research needed on shared language assumption mechanism.

Facilitation enhances commitment to implement action plans:

  • Participative

    environment Procedural Justice

    Interpersonal

    relationship

    improvement + Confidence in decision outcomes

  • Collaborative model building +

e xperimentation Procedural rationality

Participative environment was not a sufficient predictor of procedural justice.

Procedural justice was not a reliable predictor of interpersonal relationship improvement nor decision outcome confidence.

Decision confidence was a sufficient predictor of action plan commitment/ implementation, whilst interpersonal relationship improvement was not.

Collaborative model development and experimentation were sufficient predictors of procedural rationality.

Procedural rationality with full experimentation was a sufficient predictor of commitment/ implementation, regardless of collaborative model building.

Procedural justice assumption mechanism not supported.

Partial support for procedural rationality assumption mechanism.

Facilitation promotes consensus:

  • Conflict management Cognitive change Consensus
Cognitive change under conflict management was a sufficient predictor of consensus, whilst cognitive change in the absence of conflict management was not. Assumption supported.

Facilitation promotes positive organisational change:

  • Commitment to implement action plans

Implementation

  • I m plementation + Decision quality Positive

organisational change

Commitment was not a sufficient predictor of implementation, though this was just below sufficiency threshold and no cases reporting weak or non-commitment reported full implementation. Indicative of an association but consistency is limited.

implementation was sufficient predictor of positive organisational change regardless of whether decision quality was reported.

Partial support for commitment predicting implementation.

Support for role of implementation but not decision quality- more research needed.