Author: Eric Wright (University of Florida) & Sanaz Nazari (University of Florida)
Date: 2022-08-30

# A Sensitivity Analysis of Toward a Greater Understanding of How Dissatisfaction Drives Employee Turnover by Peter W. Hom and Angelo J. Kinicki

#### Eric Wright (University of Florida) & Sanaz Nazari (University of Florida)

#### 2022-08-30

# SENSITIVITY ANALYSIS USING SEMsens

BASED ON PAPER: Toward a Greater Understanding of How Dissatisfaction Drives Employee Turnover Author(s): Peter W. Hom and Angelo J. Kinicki.

Source: The Academy of Management Journal, Vol. 44, No. 5 (Oct., 2001), pp. 975-987 Published by: Academy of Management.

Stable URL: https://www.jstor.org/stable/3069441

This example sensitivity analysis uses the published data and model from Hom and Kinicki (2001). We create a covariance matrix from their data, set up lavaan models for their original model and the sensitivity model, run the analysis, and view the results.

    # Load lavaan and SEMsens packages
    require(lavaan)
    require(SEMsens)
    set.seed(1)

## Step 1: Enter the data

Hom and Kinicki (2001) published correlations and standard deviations for all indicator variables, so we use those to create a covariance matrix `covmat`.

    # Correlation matrix from published data
    cormat <- diag(1,29) # start with the diagonal
    cormat[lower.tri(cormat)] <- c( # add lower triangle data
      .46,.22,.30,-.20,-.30,-.20,-.22,-.33,-.19,-.25,-.63,-.60,-.48,-.17,-.42,-.09,-.36,.09,
      .04,-.12,0,-.20,-.20,-.43,-.33,-.49,-.18,-.03,.21,.30,-.15,-.25,-.10,-.20,-.31,-.15,
      -.24,-.40,-.37,-.32,-.08,-.24,-.02,-.27,.06,.07,-.08,0,-.10,-.16,-.25,-.18,-.35,-.06,
      -.05,.04,-.05,-.09,-.12,-.10,-.01,.03,.02,-.18,-.14,-.09,-.02,-.12,-.05,-.08,.03,.07,
      -.08,-.06,-.10,-.07,-.10,-.03,-.11,.04,.03,-.07,-.24,0,-.12,-.50,-.32,-.45,-.38,-.29,
      -.31,-.16,-.24,-.16,-.37,.12,.05,-.28,-.13,-.06,-.03,-.16,-.12,-.23,-.08,.06,.29,.31,
      .10,.08,-.02,.07,.21,.24,.25,.06,.09,.04,.14,-.02,-.01,.10,.04,.04,.13,.19,.03,.18,
      .14,-.04,.38,.41,.23,.13,.22,.36,.35,.35,.09,.14,.11,.14,-.09,-.04,.11,.04,.11,.15,
      .30,.17,.33,.12,-.02,.31,.05,.03,.15,.22,.20,.21,-.05,.10,-.05,.03,-.04,-.06,.03,.05,
      .03,.07,.24,.19,.23,.13,-.08,.17,.15,.19,.28,.23,.23,.04,.18,.08,.10,-.09,-.06,.07,
      .01,.11,.08,.21,.20,.28,.06,-.03,.43,.56,.35,.32,.26,.16,.27,.13,.45,-.04,-.04,.16,
      .07,.14,.15,.23,.12,.29,.09,-.07,.67,.24,.26,.27,.15,.21,.13,.25,-.10,-.02,.12,0,.12,
      .10,.18,.21,.27,.17,-.06,.36,.32,.31,.11,.29,.16,.40,-.10,-.05,.22,.10,.17,.15,.27,
      .23,.33,.17,-.08,.78,.77,.11,.49,.09,.40,-.23,-.14,.19,-.07,.29,.27,.57,.40,.68,.27,0,
      .82,.10,.57,.08,.42,-.29,-.10,.13,-.12,.33,.31,.66,.46,.75,.32,.02,.10,.49,.08,.38,
      -.31,-.11,.18,-.06,.33,.34,.54,.38,.67,.31,-.08,.14,.52,.20,.22,.31,.42,.39,.01,.01,
      .07,.06,.13,-.03,.06,.14,.42,-.29,-.12,.24,-.06,.25,.25,.38,.28,.48,.18,-.01,.16,.16,
      .28,.68,.48,.06,.10,.01,.12,.15,-.05,.04,.02,.03,.24,.11,.14,.16,.31,.22,.32,.09,-.01,
      .37,.12,.18,-.20,-.15,-.22,-.08,-.23,-.11,.07,.13,.18,-.07,0,-.10,.04,-.06,-.03,.15,
      .54,.11,.12,.07,.10,.16,-.01,-.02,-.06,-.01,-.09,-.05,-.10,-.14,.06,.57,.28,.17,.36,
      .27,-.05,.32,.21,.36,.18,.05,.42,.68,.26,-.05,.55,.23,.04,.28,-.03,-.07
    )
    cormat[upper.tri(cormat)] <- t(cormat)[upper.tri(cormat)] # mirror lower to upper

    # Standard deviations from published data
    sds <- diag(c(1,.38,.73,.65,.58,.78,.75,.55,.59,.54,.45,.74,.85,.80,.57,
                  .74,.69,.42,.57,.63,.62,.70,1.01,.94,.65,.37,.73,.40,1))

    # Create covariance matrix covmat with row and column names
    covmat <- sds %*% cormat %*% sds
    rownames(covmat) <- colnames(covmat) <- c(
      "FACES","Duty","Team","Hours","Absent","Effort","Sick","Quality","Family",
      "Community","Personal","Thoughts","SI","QI","Stress","Jobs","Costs",
      "Benefits","Joblessness","Moving","Impact","Interference","V1","V2",
      "Prepare","Look","Intensity","Resign","Unemployed"
    )

## Step 2: Define the models

The SEMsens package requires both an original model and a sensitivity model that adds the phantom variables. These models are defined SEMsens using the lavaan model syntax.

We first define the original model:

    # Original model from Hom and Kinicki (2001)
    model <- "JSat =~ FACES + Duty + Team
      IC =~ Family + Personal + Community
      JAvoid =~ Quality + Absent + Effort + Sick
      WC =~ QI + Thoughts + SI
      WEU =~ Stress + Benefits + Impact + Jobs
      JSearch =~ Prepare + Look + Intensity
      CA =~ V1 + V2
      Turnover =~ Resign
      Resign ~~ 0*Resign
      UR =~ Unemployed
      Unemployed ~~ 0*Unemployed

      JSat ~ IC
      JAvoid ~ JSat
      WC ~ JAvoid + JSat + IC
      WEU ~ WC + JSat + UR
      JSearch ~ WEU
      CA ~ JSearch
      Turnover ~ CA + WC + UR"

For the sensitivity model, we use the same model definition as the original model but add one phantom variable with paths phantom1, phantom2, etc. to each of the latent variables in the original model.

    # Sensitivity model
    sens.model <- "JSat =~ FACES + Duty + Team
      IC =~ Family + Personal + Community
      JAvoid =~ Quality + Absent + Effort + Sick
      WC =~ QI + Thoughts + SI
      WEU =~ Stress + Benefits + Impact + Jobs
      JSearch =~ Prepare + Look + Intensity
      CA =~ V1 + V2
      Turnover =~ Resign
      Resign ~~ 0*Resign
      UR =~ Unemployed
      Unemployed ~~ 0*Unemployed

      JSat ~ IC
      JAvoid ~ JSat
      WC ~ JAvoid + JSat + IC
      WEU ~ WC + JSat + UR
      JSearch ~ WEU
      CA ~ JSearch
      Turnover ~ CA + WC + UR

      IC ~ phantom1*phantom
      UR ~ phantom2*phantom
      JSat ~ phantom3*phantom
      JAvoid ~ phantom4*phantom
      WC ~ phantom5*phantom
      WEU ~ phantom6*phantom
      JSearch ~ phantom7*phantom
      CA ~ phantom8*phantom
      Turnover ~ phantom9*phantom

      phantom =~ 0
      phantom ~~ 1*phantom"

## Step 3: Identify paths of interest

Before running the analysis, we need to identify the rows in a lavaan parameter table that include the paths we are interested in looking at in the analysis. To save space, only the most relevant section of the parameter table is displayed below.

    ptab = lavaanify(model = model, auto = TRUE, model.type="sem")
    ptab[26:40,1:4]

    ##    id        lhs op        rhs
    ## 26 26 Unemployed ~~ Unemployed
    ## 27 27       JSat  ~         IC
    ## 28 28     JAvoid  ~       JSat
    ## 29 29         WC  ~     JAvoid
    ## 30 30         WC  ~       JSat
    ## 31 31         WC  ~         IC
    ## 32 32        WEU  ~         WC
    ## 33 33        WEU  ~       JSat
    ## 34 34        WEU  ~         UR
    ## 35 35    JSearch  ~        WEU
    ## 36 36         CA  ~    JSearch
    ## 37 37   Turnover  ~         CA
    ## 38 38   Turnover  ~         WC
    ## 39 39   Turnover  ~         UR
    ## 40 40      FACES ~~      FACES

For this example, we are interested in all the paths between latent variables. These are located on rows 27 to 39 in the parameter table for this model. That information will be used in the next step for the analysis.

## Step 4: Sensitivity analysis

The `sa.aco` function is used to run the sensitivity analysis.

    my.sa <- sa.aco(model = model, sens.model = sens.model, sample.cov = covmat,
                    sample.nobs = 410, opt.fun = 3, paths = 27:39,
                    seed = 1, k = 5, max.iter = 20)

We specified the original model (`model`), the sensitivity model (`sens.model`), the covariance matrix (`sample.cov`), the number of observations in the sample (`sample.nobs`), the number of sensitivity parameters included (`n.of.sens.pars`), a preset optimization function (`opt.fun`), the paths from the previous step (`paths`), and a seed for reproducibility (`seed`).

Note: We only used `k = 5` and `max.iter = 20` so the analysis would run quickly for illustration purposes. For actual analyses, please specify these parameters as larger numbers (e.g., the default values are `k = 50` and `max.iter = 1000`).

## Step 5: Results

The `sens.tables` function helps summarize the results of a sensitivity analysis. We specify `path = TRUE` to only obtain results for the structural paths.

    my.sa.results = sens.tables(my.sa, path=TRUE) # get results
    my.sa.results = lapply(my.sa.results, round, digits = 3) # round results (optional)

The tables contain several categories of results. Each is displayed below.

The `sens.summary` table contains the estimates and p values for each path in the original model as well as the mean, minimum, and maximum values for the paths that were estimated during the sensitivity analysis.

    my.sa.results$sens.summary

    ##             model.est model.pvalue mean.est.sens min.est.sens max.est.sens
    ## JSat~IC        -0.401        0.000        -0.579       -1.023       -0.336
    ## JAvoid~JSat    -0.529        0.000        -0.499       -0.660       -0.129
    ## WC~JSat        -0.637        0.000        -0.484       -0.645       -0.270
    ## Turnover~UR    -0.065        0.155        -0.075       -0.256        0.129
    ## WEU~UR         -0.018        0.575        -0.039       -0.225        0.028
    ## WC~JAvoid       0.139        0.034         0.080       -0.046        0.141
    ## WEU~JSat       -0.093        0.202         0.112       -1.309        2.226
    ## WC~IC           0.144        0.004         0.154       -0.066        0.551
    ## Turnover~CA     0.190        0.002         0.211        0.129        0.304
    ## Turnover~WC     0.245        0.000         0.414       -0.660        1.628
    ## JSearch~WEU     0.883        0.000         0.588        0.032        2.124
    ## CA~JSearch      0.520        0.000         0.669        0.167        1.004
    ## WEU~WC          0.903        0.000         1.208       -2.875        6.782

The `phan.paths` table contains the mean, minimum, and maximum of the sensitivity parameters from the analysis

    my.sa.results$phan.paths

    ##                  mean.phan min.phan max.phan
    ## WEU~phantom         -2.310   -4.965   -0.670
    ## JSat~phantom        -0.458   -0.837   -0.047
    ## UR~phantom          -0.305   -0.686    0.285
    ## CA~phantom          -0.230   -0.481    0.280
    ## IC~phantom          -0.180   -0.965    0.813
    ## WC~phantom           0.115   -1.103    0.694
    ## JAvoid~phantom       0.277   -0.148    0.805
    ## JSearch~phantom      0.332   -0.894    1.499
    ## Turnover~phantom     0.553   -1.105    1.795

The `phan.min` table provides the set of tested sensitivity parameter values for each path that resulted in the smallest coefficient value for the path.

    my.sa.results$phan.min

    ##             IC~phantom UR~phantom JSat~phantom JAvoid~phantom WC~phantom
    ## JSat~IC         -0.965     -0.595       -0.384          0.123      0.409
    ## JAvoid~JSat     -0.514      0.285       -0.837         -0.148      0.694
    ## WC~JAvoid       -0.514      0.285       -0.837         -0.148      0.694
    ## WC~JSat         -0.965     -0.595       -0.384          0.123      0.409
    ## WC~IC           -0.295      0.001       -0.497          0.151     -1.103
    ## WEU~WC          -0.295      0.001       -0.497          0.151     -1.103
    ## WEU~JSat        -0.295      0.001       -0.497          0.151     -1.103
    ## WEU~UR           0.060     -0.531       -0.524          0.453      0.169
    ## JSearch~WEU     -0.295      0.001       -0.497          0.151     -1.103
    ## CA~JSearch      -0.295      0.001       -0.497          0.151     -1.103
    ## Turnover~CA     -0.514      0.285       -0.837         -0.148      0.694
    ## Turnover~WC     -0.514      0.285       -0.837         -0.148      0.694
    ## Turnover~UR      0.813     -0.686       -0.047          0.805      0.408
    ##             WEU~phantom JSearch~phantom CA~phantom Turnover~phantom
    ## JSat~IC          -0.714           1.499     -0.423           -0.194
    ## JAvoid~JSat      -4.965           0.935     -0.389            1.254
    ## WC~JAvoid        -4.965           0.935     -0.389            1.254
    ## WC~JSat          -0.714           1.499     -0.423           -0.194
    ## WC~IC            -3.900          -0.894     -0.481            1.795
    ## WEU~WC           -3.900          -0.894     -0.481            1.795
    ## WEU~JSat         -3.900          -0.894     -0.481            1.795
    ## WEU~UR           -1.301          -0.675      0.280            1.014
    ## JSearch~WEU      -3.900          -0.894     -0.481            1.795
    ## CA~JSearch       -3.900          -0.894     -0.481            1.795
    ## Turnover~CA      -4.965           0.935     -0.389            1.254
    ## Turnover~WC      -4.965           0.935     -0.389            1.254
    ## Turnover~UR      -0.670           0.794     -0.135           -1.105

Likewise, the `phan.max` table provides the set of tested sensitivity parameter values for each path that resulted in the largest coefficient value for the path.

    my.sa.results$phan.max

    ##             IC~phantom UR~phantom JSat~phantom JAvoid~phantom WC~phantom
    ## JSat~IC          0.060     -0.531       -0.524          0.453      0.169
    ## JAvoid~JSat      0.813     -0.686       -0.047          0.805      0.408
    ## WC~JAvoid        0.060     -0.531       -0.524          0.453      0.169
    ## WC~JSat         -0.295      0.001       -0.497          0.151     -1.103
    ## WC~IC           -0.965     -0.595       -0.384          0.123      0.409
    ## WEU~WC          -0.514      0.285       -0.837         -0.148      0.694
    ## WEU~JSat        -0.514      0.285       -0.837         -0.148      0.694
    ## WEU~UR           0.813     -0.686       -0.047          0.805      0.408
    ## JSearch~WEU     -0.965     -0.595       -0.384          0.123      0.409
    ## CA~JSearch       0.060     -0.531       -0.524          0.453      0.169
    ## Turnover~CA      0.813     -0.686       -0.047          0.805      0.408
    ## Turnover~WC     -0.295      0.001       -0.497          0.151     -1.103
    ## Turnover~UR      0.060     -0.531       -0.524          0.453      0.169
    ##             WEU~phantom JSearch~phantom CA~phantom Turnover~phantom
    ## JSat~IC          -1.301          -0.675      0.280            1.014
    ## JAvoid~JSat      -0.670           0.794     -0.135           -1.105
    ## WC~JAvoid        -1.301          -0.675      0.280            1.014
    ## WC~JSat          -3.900          -0.894     -0.481            1.795
    ## WC~IC            -0.714           1.499     -0.423           -0.194
    ## WEU~WC           -4.965           0.935     -0.389            1.254
    ## WEU~JSat         -4.965           0.935     -0.389            1.254
    ## WEU~UR           -0.670           0.794     -0.135           -1.105
    ## JSearch~WEU      -0.714           1.499     -0.423           -0.194
    ## CA~JSearch       -1.301          -0.675      0.280            1.014
    ## Turnover~CA      -0.670           0.794     -0.135           -1.105
    ## Turnover~WC      -3.900          -0.894     -0.481            1.795
    ## Turnover~UR      -1.301          -0.675      0.280            1.014

The final table `p.paths` provides the sensitivity parameters that lead to a change in significance for each path according to the significance level specified in the `sens.tables` function. We used the default significance level of .05 for that. The first column contains the original p values and the second contains the changed p values that are obtained with the listed phantom variable path coefficients. The NAs occur when there is no change in p value for any of the tested phantom variable path coefficients.

    my.sa.results$p.paths

    ##             p.value p.changed IC~phantom UR~phantom JSat~phantom JAvoid~phantom
    ## WEU~UR        0.575     0.000      0.060     -0.531       -0.524          0.453
    ## WEU~JSat      0.202     0.032      0.813     -0.686       -0.047          0.805
    ## Turnover~UR   0.155     0.048     -0.965     -0.595       -0.384          0.123
    ## WC~IC         0.004     0.053      0.813     -0.686       -0.047          0.805
    ## JSearch~WEU   0.000     0.430     -0.295      0.001       -0.497          0.151
    ## JSat~IC       0.000        NA         NA         NA           NA             NA
    ## JAvoid~JSat   0.000        NA         NA         NA           NA             NA
    ## WC~JAvoid     0.034        NA         NA         NA           NA             NA
    ## WC~JSat       0.000        NA         NA         NA           NA             NA
    ## WEU~WC        0.000        NA         NA         NA           NA             NA
    ## CA~JSearch    0.000        NA         NA         NA           NA             NA
    ## Turnover~CA   0.002        NA         NA         NA           NA             NA
    ## Turnover~WC   0.000        NA         NA         NA           NA             NA
    ##             WC~phantom WEU~phantom JSearch~phantom CA~phantom Turnover~phantom
    ## WEU~UR           0.169      -1.301          -0.675      0.280            1.014
    ## WEU~JSat         0.408      -0.670           0.794     -0.135           -1.105
    ## Turnover~UR      0.409      -0.714           1.499     -0.423           -0.194
    ## WC~IC            0.408      -0.670           0.794     -0.135           -1.105
    ## JSearch~WEU     -1.103      -3.900          -0.894     -0.481            1.795
    ## JSat~IC             NA          NA              NA         NA               NA
    ## JAvoid~JSat         NA          NA              NA         NA               NA
    ## WC~JAvoid           NA          NA              NA         NA               NA
    ## WC~JSat             NA          NA              NA         NA               NA
    ## WEU~WC              NA          NA              NA         NA               NA
    ## CA~JSearch          NA          NA              NA         NA               NA
    ## Turnover~CA         NA          NA              NA         NA               NA
    ## Turnover~WC         NA          NA              NA         NA               NA

# References

Leite, W., Shen, Z., Marcoulides, K., Fish, C., & Harring, J. (2022). Using ant colony optimization for sensitivity analysis in structural equation modeling. Structural Equation Modeling: A Multidisciplinary Journal, 29 (1), 47-56.