4. Estimate corrected MMs or AMCEs
04-estimate.Rmd
Due to IRR-induced measurement error, default MMs and AMCEs in
conjoint analysis are biased. By default, projoint
produces
bias-corrected estimates automatically.
4.2 Why do we recommend you use IDs?
To estimate and visualize the quantities of your interest using our
package (at least in the current version), you need to set the
attributes and levels using the IDs, such as att1
and
level2
, rather than their actual labels, such as “Housing
Cost” (for att1
) and “15% of pre-tax income” (for
level1
of att1
). We think that this approach
is prone to error because some applications may include foreign
characters (e.g., 2-byte Japanese characters) or special characters.
Sometimes, your design may include the same levels for more than one
attribute; for example, “Teaching quality” = {“High”, “Low”} and
“Research quality” = {“High”, “Low”)). To avoid any possible strange
result, we use the unique identifiers for each attribute-level.
To check which IDs correspond to which attributes and levels, you can type the following line in your script:
out1@labels
## # A tibble: 24 × 4
## attribute level attribute_id level_id
## <chr> <chr> <chr> <chr>
## 1 Housing Cost 15% of pre-tax income att1 att1:leve…
## 2 Housing Cost 30% of pre-tax income att1 att1:leve…
## 3 Housing Cost 40% of pre-tax income att1 att1:leve…
## 4 Presidential Vote (2020) 30% Democrat, 70% Republican att2 att2:leve…
## 5 Presidential Vote (2020) 50% Democrat, 50% Republican att2 att2:leve…
## 6 Presidential Vote (2020) 70% Democrat, 30% Republican att2 att2:leve…
## 7 Racial Composition 50% White, 50% Nonwhite att3 att3:leve…
## 8 Racial Composition 75% White, 25% Nonwhite att3 att3:leve…
## 9 Racial Composition 90% White, 10% Nonwhite att3 att3:leve…
## 10 Racial Composition 96% White, 4% Nonwhite att3 att3:leve…
## # ℹ 14 more rows
You can also save_labels()
and save a CSV file for your
reference.
4.3 Estimate MMs
There are two main setups for which projoint
can produce
estimates. The profile-level is the most common approach in the
literature, while the choice-level is more flexible and powerful.
MM (profile-level) – all levels
The default method in projoint
is to estimate marginal
means (MMs) at the profile-level. If you run
projoint(out1)
, it will conduct this analysis. We expand
all those arguments below for clarity:
mm0 <- projoint(.data = out1,
.qoi = NULL,
.by_var = NULL,
.structure = "profile_level",
.estimand = "mm",
.se_method = "analytical",
.irr = NULL,
.remove_ties = TRUE,
.ignore_position = NULL,
.n_sims = NULL,
.n_boot = NULL,
.weights_1 = NULL,
.clusters_1 = NULL,
.se_type_1 = "classical",
.weights_2 = NULL,
.clusters_2 = NULL,
.se_type_2 = "classical")
print(mm0)
## [A projoint output]
## Estimand: mm
## Structure: profile_level
## IRR: Estimated
## Tau: 0.1721281
## Remove ties: TRUE
## SE methods: analytical
summary(mm0)
## # A tibble: 48 × 6
## estimand estimate se conf.low conf.high att_level_choose
## <chr> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 mm_uncorrected 0.574 0.0134 0.548 0.601 att1:level1
## 2 mm_corrected 0.614 0.0207 0.573 0.654 att1:level1
## 3 mm_uncorrected 0.485 0.0134 0.458 0.511 att1:level2
## 4 mm_corrected 0.477 0.0204 0.437 0.517 att1:level2
## 5 mm_uncorrected 0.445 0.0131 0.419 0.470 att1:level3
## 6 mm_corrected 0.416 0.0203 0.376 0.455 att1:level3
## 7 mm_uncorrected 0.489 0.0133 0.463 0.515 att2:level1
## 8 mm_corrected 0.483 0.0202 0.443 0.522 att2:level1
## 9 mm_uncorrected 0.524 0.0130 0.498 0.549 att2:level2
## 10 mm_corrected 0.536 0.0200 0.497 0.575 att2:level2
## # ℹ 38 more rows
MM (profile-level) – specific level
However, it is also possible to specify the precise attributes, and
attribute levels, of interest using the set_qoi
function as
below. The set_qoi
function is the main way for users to
specify more complex estimands in conjoint analysis. Al arguments for
qoi()
are expanded for clarity, but the default arguments
in projoint()
are dropped for simplicity:
qoi_1 <- set_qoi(
.structure = "profile_level",
.estimand = "mm",
.att_choose = "att1",
.lev_choose = "level1")
mm1 <- projoint(.data = out1,
.qoi = qoi_1)
print(mm1)
## [A projoint output]
## Estimand: mm
## Structure: profile_level
## IRR: Estimated
## Tau: 0.1721281
## Remove ties: TRUE
## SE methods: analytical
summary(mm1)
## # A tibble: 2 × 7
## estimand estimate se conf.low conf.high att_level_choose
## <chr> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 mm_uncorrected 0.574 0.0134 0.548 0.601 att1:level1
## 2 mm_corrected 0.614 0.0207 0.573 0.654 att1:level1
## # ℹ 1 more variable: att_level_notchoose <chr>
MM (profile-level) – specific level, using the predicted IRR
If your conjoint survey design does not include the recommended
repeated task, you can use the specific value for .irr
,
which you can estimate using the predict_tau()
function or
specify the value based on prior knowledge. In the following, we use
0.75, which is most likely IRR we find in our test data sets. The
default arguments for both set_qoi()
and
projoint()
are dropped hereafter.
## [A projoint output]
## Estimand: mm
## Structure: profile_level
## IRR: Assumed (0.75)
## Tau: 0.1464466
## Remove ties: TRUE
## SE methods: analytical
summary(mm1b)
## # A tibble: 2 × 7
## estimand estimate se conf.low conf.high att_level_choose
## <chr> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 mm_uncorrected 0.574 0.0134 0.548 0.601 att1:level1
## 2 mm_corrected 0.605 0.0190 0.568 0.643 att1:level1
## # ℹ 1 more variable: att_level_notchoose <chr>
MM (choice-level) – specific level
As soon as users wish to switch from profile-level to choice-level
analysis, the set_qoi
function is required. There are
exponentially more choice-level estimands than there are profile-level
estimands, so it is impractical to view all of them. Here we specify
that we want to return the marginal mean of attribute 1, levels 1 and 3
at the choice-level.
qoi_2 <- set_qoi(
.structure = "choice_level",
.att_choose = "att1",
.lev_choose = "level3",
.att_notchoose = "att1",
.lev_notchoose = "level1"
)
mm2 <- projoint(.data = out1,
.qoi = qoi_2,
.structure = "choice_level",
.ignore_position = FALSE)
print(mm2)
## [A projoint output]
## Estimand: mm
## Structure: choice_level
## IRR: Estimated
## Tau: 0.1721281
## Remove ties: TRUE
## SE methods: analytical
summary(mm2)
## # A tibble: 2 × 7
## estimand estimate se conf.low conf.high att_level_choose
## <chr> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 mm_uncorrected 0.402 0.0258 0.352 0.453 att1:level3
## 2 mm_corrected 0.351 0.0408 0.271 0.431 att1:level3
## # ℹ 1 more variable: att_level_notchoose <chr>
4.4 Estimate AMCEs
Note that we can replicate all above analyses using the AMCE instead
of the MM just by specifying that the .estimand = "amce"
rather than the default "mm"
.
AMCE (profile-level) – all levels
## [A projoint output]
## Estimand: amce
## Structure: profile_level
## IRR: Estimated
## Tau: 0.1721281
## Remove ties: TRUE
## SE methods: analytical
summary(amce0)
## # A tibble: 34 × 7
## estimand estimate se conf.low conf.high att_level_choose
## <chr> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 amce_uncorrected -0.0899 0.0190 -0.127 -0.0527 att1:level2
## 2 amce_corrected -0.137 0.0290 -0.194 -0.0801 att1:level2
## 3 amce_uncorrected -0.130 0.0188 -0.167 -0.0931 att1:level3
## 4 amce_corrected -0.198 0.0294 -0.256 -0.140 att1:level3
## 5 amce_uncorrected 0.0348 0.0186 -0.00170 0.0713 att2:level2
## 6 amce_corrected 0.0530 0.0284 -0.00258 0.109 att2:level2
## 7 amce_uncorrected -0.00177 0.0188 -0.0386 0.0350 att2:level3
## 8 amce_corrected -0.00270 0.0286 -0.0589 0.0535 att2:level3
## 9 amce_uncorrected 0.0240 0.0204 -0.0159 0.0640 att3:level2
## 10 amce_corrected 0.0366 0.0312 -0.0246 0.0979 att3:level2
## # ℹ 24 more rows
## # ℹ 1 more variable: att_level_choose_baseline <chr>
AMCE (profile-level) – specific level
qoi_3 <- set_qoi(
.structure = "profile_level",
.estimand = "amce",
.att_choose = "att1",
.lev_choose = "level3",
.att_choose_b = "att1",
.lev_choose_b = "level1"
)
amce1 <- projoint(.data = out1,
.qoi = qoi_3,
.estimand = "amce")
print(amce1)
## [A projoint output]
## Estimand: amce
## Structure: profile_level
## IRR: Estimated
## Tau: 0.1721281
## Remove ties: TRUE
## SE methods: analytical
summary(amce1)
## # A tibble: 2 × 9
## estimand estimate se conf.low conf.high att_level_choose
## <chr> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 amce_uncorrected -0.130 0.0188 -0.167 -0.0931 att1:level3
## 2 amce_corrected -0.198 0.0294 -0.256 -0.140 att1:level3
## # ℹ 3 more variables: att_level_notchoose <chr>,
## # att_level_choose_baseline <chr>, att_level_notchoose_baseline <chr>
AMCE (profile-level) – specific level, using the predicted IRR
## [A projoint output]
## Estimand: amce
## Structure: profile_level
## IRR: Assumed (0.75)
## Tau: 0.1464466
## Remove ties: TRUE
## SE methods: analytical
summary(amce1b)
## # A tibble: 2 × 9
## estimand estimate se conf.low conf.high att_level_choose
## <chr> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 amce_uncorrected -0.130 0.0188 -0.167 -0.0931 att1:level3
## 2 amce_corrected -0.184 0.0266 -0.236 -0.132 att1:level3
## # ℹ 3 more variables: att_level_notchoose <chr>,
## # att_level_choose_baseline <chr>, att_level_notchoose_baseline <chr>
AMCE (choice-level) – specific level
qoi_4 <- set_qoi(
.structure = "choice_level",
.estimand = "amce",
.att_choose = "att1",
.lev_choose = "level3",
.att_notchoose = "att1",
.lev_notchoose = "level1",
.att_choose_b = "att1",
.lev_choose_b = "level2",
.att_notchoose_b = "att1",
.lev_notchoose_b = "level1"
)
amce2 <- projoint(.data = out1,
.qoi = qoi_4,
.structure = "choice_level",
.estimand = "amce",
.ignore_position = TRUE)
print(amce2)
## [A projoint output]
## Estimand: amce
## Structure: choice_level
## IRR: Estimated
## Tau: 0.1721281
## Remove ties: TRUE
## SE methods: analytical
summary(amce2)
## # A tibble: 2 × 9
## estimand estimate se conf.low conf.high att_level_choose
## <chr> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 amce_uncorrected -0.0484 0.0270 -0.101 0.00448 att1:level3
## 2 amce_corrected -0.0739 0.0414 -0.155 0.00727 att1:level3
## # ℹ 3 more variables: att_level_notchoose <chr>,
## # att_level_choose_baseline <chr>, att_level_notchoose_baseline <chr>