Skip to content

Commit 8ae7de1

Browse files
authored
Merge pull request #5 from m-freitag/dev_mf
Dev mf
2 parents ba71466 + ff61c18 commit 8ae7de1

File tree

7 files changed

+319
-223
lines changed

7 files changed

+319
-223
lines changed

DESCRIPTION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: cjpowR
22
Type: Package
33
Title: A Priori Power Analyses for Conjoint Experiments
4-
Version: 1.0.1
4+
Version: 1.0.2
55
Author: Markus Freitag, Julian Schuessler
66
Maintainer: Markus Freitag <[email protected]>
77
Description: Implements the formulae provided by Schuessler/Freitag (2020) and provides some plotting functions.

R/amce.R

+99-105
Original file line numberDiff line numberDiff line change
@@ -24,54 +24,53 @@
2424
#' @param levels the number of levels of the treatment.
2525
#' @param n effective sample size, default is NULL.
2626
#' @param treat.prob default is 0.5.
27-
#' @param sims number of simulation runs to compute the expected type M error ("exaggeration ratio"), default 100k. If NULL, E(type M) is not computed.
27+
#' @param sims number of simulation runs to compute the expected type M error ("exaggeration ratio"), default 100k. If NULL or, E(type M) is not computed (much faster).
2828
#' @keywords conjoint, power analysis, AMCE
2929
#' @export
3030
#' @export
3131
#' @export
3232
#' @export
3333
#' @examples
3434
#' # This gives the minimum required effective sample size (type S, E(type M)):
35-
#' df = cjpowr_amce(amce = 0.05, power = 0.8, levels = 5)
35+
#' df <- cjpowr_amce(amce = 0.05, power = 0.8, levels = 5)
3636
#'
3737
#' # For example, for a conjoint with 2 profiles and 4 tasks, n becomes:
3838
#'
39-
#' df$n/(2*4)
39+
#' df$n / (2 * 4)
4040
#'
41-
#' #This gives the power (type S, E(type M)):
41+
#' # This gives the power (type S, E(type M)):
4242
#' cjpowr_amce(amce = 0.05, n = 7829.258, levels = 5)
4343
#'
44-
#' #Generating an interactive plot for type M error:
44+
#' # Generating an interactive plot for type M error:
4545
#'
46-
#' d <- expand.grid(amce = c(0.01, 0.02, 0.03, 0.05), n = seq(from = 100, to = 50000, length.out = 1000))
46+
#' d <- expand.grid(
47+
#' amce = c(0.01, 0.02, 0.03, 0.05),
48+
#' n = seq(from = 100, to = 50000, length.out = 1000),
49+
#' alpha = 0.05,
50+
#' levels = 2,
51+
#' treat.prob = 0.5,
52+
#' sims = 10000) #set to 0 if you want to make an interactive plot for something other than Type M error
4753
#'
48-
#' # Purrr Style:
49-
#' library(purrr)
50-
#' set.seed(123)
51-
#' df <- pmap_df(d, function(amce, n) cjpowr_amce(amce = amce, n = n, sims = 1000, levels = 5, alpha = 0.05, treat.prob = 0.5))
52-
#'
53-
#' # Base R:
54-
#' set.seed(123)
55-
#' cjpowr_amce_vec <- Vectorize(cjpowr_amce)
56-
#' df2 <- t(cjpowr_amce_vec(amce = d$amce, n = d$n, sims = 1000, levels = 5, alpha = 0.05, treat.prob = 0.5))
57-
#'
58-
#' df2 <- data.frame(df2)
59-
#' df2[] <- lapply(df2, unlist)
54+
#' df <- list2DF(do.call(cjpowr_amce, d))
6055
#'
6156
#' library(plotly)
62-
#'
63-
#' plot_ly(df, x = ~n, y = ~exp_typeM, type = 'scatter', mode = 'lines', linetype = ~amce) %>%
64-
#' layout(
65-
#' xaxis = list(title = "Effective Sample Size",
66-
#' zeroline = F,
67-
#' hoverformat = '.0f'),
68-
#' yaxis = list(title = "Exaggeration Ratio",
69-
#' range = c(0,10),
70-
#' zeroline = F,
71-
#' hoverformat = '.2f'),
72-
#' legend=list(title=list(text='<b> AMCE </b>')),
73-
#' hovermode = "x unified"
74-
#' )
57+
#'
58+
#' plot_ly(df, x = ~n, y = ~exp_typeM, type = "scatter", mode = "lines", linetype = ~amce) %>%
59+
#' layout(
60+
#' xaxis = list(
61+
#' title = "Effective Sample Size",
62+
#' zeroline = F,
63+
#' hoverformat = ".0f"
64+
#' ),
65+
#' yaxis = list(
66+
#' title = "Exaggeration Ratio",
67+
#' range = c(0, 10),
68+
#' zeroline = F,
69+
#' hoverformat = ".2f"
70+
#' ),
71+
#' legend = list(title = list(text = "<b> AMCE </b>")),
72+
#' hovermode = "x unified"
73+
#' )
7574
#' @section Literature:
7675
#'
7776
#' 1. Schuessler, J. and M. Freitag (2020). Power Analysis for Conjoint Experiments.
@@ -81,126 +80,121 @@
8180
#' British Journal of Mathematical and Statistical Psychology 72(1), 1–17.
8281

8382
cjpowr_amce <- function(amce, alpha = 0.05, power = NULL, levels = 2,
84-
treat.prob = 0.5, n = NULL, sims = 100000){
85-
86-
if (sum(sapply(list(power,n), is.null)) != 1)
83+
treat.prob = 0.5, n = NULL, sims = 100000) {
84+
if (sum(sapply(list(power, n), is.null)) != 1) {
8785
stop("either 'n' or 'power' must be provided")
88-
if (!is.null(alpha) && !is.numeric(alpha) || any(0 > alpha | alpha > 1))
86+
}
87+
if (!is.null(alpha) && !is.numeric(alpha) || any(0 > alpha | alpha > 1)) {
8988
stop("'sig.level' must be numeric in [0, 1]")
89+
}
9090

91-
if (is.null(sims)) {
91+
lengths <- c(length(amce), length(alpha), length(power), length(levels), length(treat.prob), length(n), length(sims))
92+
non_null_lengths <- lengths[lengths > 0]
9293

93-
if (is.null(n)) {
94+
if (length(unique(non_null_lengths)) > 1) {
95+
stop("All non-NULL input parameters must be of the same length.")
96+
}
9497

95-
if (all(sapply(list(length(amce), length(alpha), length(power), length(levels)), function(x) x == 1)) == FALSE) {
96-
stop("Please provide scalar values or apply a functional.")
97-
}
98+
length_output <- unique(non_null_lengths)
9899

99-
delta0 = 0.5 - (amce*treat.prob)
100+
if (is.null(sims) | any(sims == 0) == TRUE) {
101+
if (is.null(n)) {
102+
delta0 <- 0.5 - (amce * treat.prob)
100103

101-
n = (levels/2)/(amce^2) * (qnorm(p = 1- alpha/2) + qnorm(p = power))^2*
104+
n <- (levels / 2) / (amce^2) * (qnorm(p = 1 - alpha / 2) + qnorm(p = power))^2 *
102105
(
103-
((delta0 + amce)*(1 - (delta0 + amce)))/0.5 +
104-
((delta0)*(1 - delta0))/0.5
106+
((delta0 + amce) * (1 - (delta0 + amce))) / 0.5 +
107+
((delta0) * (1 - delta0)) / 0.5
105108
)
106109

107-
se = (sqrt( (
108-
((delta0 + amce)*(1 - (delta0 + amce)))/0.5 +
109-
((delta0)*(1 - delta0))/0.5
110-
))/sqrt(2*(n/levels)))
110+
se <- (sqrt((
111+
((delta0 + amce) * (1 - (delta0 + amce))) / 0.5 +
112+
((delta0) * (1 - delta0)) / 0.5
113+
)) / sqrt(2 * (n / levels)))
111114

112-
z=amce/se
115+
z <- amce / se
113116

114-
pow=pnorm(z-qnorm(1-alpha/2)) + pnorm(-z-qnorm(1-alpha/2))
117+
pow <- pnorm(z - qnorm(1 - alpha / 2)) + pnorm(-z - qnorm(1 - alpha / 2))
115118

116-
type_s = pnorm(-z-qnorm(1-alpha/2))/pow
119+
type_s <- pnorm(-z - qnorm(1 - alpha / 2)) / pow
117120

118-
return(data.frame(amce = amce, n=n, type_s=type_s, power = power, alpha = alpha, levels = levels, delta0 = delta0))
121+
return(data.frame(amce = amce, n = n, type_s = type_s, power = power, alpha = alpha, levels = levels, delta0 = delta0))
119122
}
120123

121124
else if (is.null(power)) {
125+
delta0 <- 0.5 - (amce * treat.prob)
122126

123-
if (all(sapply(list(length(amce), length(alpha), length(n), length(levels)), function(x) x == 1)) == FALSE) {
124-
stop("Please provide scalar values or apply a functional.")
125-
}
127+
se <- (sqrt((
128+
((delta0 + amce) * (1 - (delta0 + amce))) / 0.5 +
129+
((delta0) * (1 - delta0)) / 0.5
130+
)) / sqrt(2 * (n / levels)))
126131

127-
delta0 = 0.5 - (amce * treat.prob)
132+
z <- amce / se
128133

129-
se = (sqrt( (
130-
((delta0 + amce)*(1 - (delta0 + amce)))/0.5 +
131-
((delta0)*(1 - delta0))/0.5
132-
))/sqrt(2*(n/levels)))
134+
power <- pnorm(z - qnorm(1 - alpha / 2)) + pnorm(-z - qnorm(1 - alpha / 2))
133135

134-
z=amce/se
136+
type_s <- pnorm(-z - qnorm(1 - alpha / 2)) / power
135137

136-
power=pnorm(z-qnorm(1-alpha/2)) + pnorm(-z-qnorm(1-alpha/2))
137-
138-
type_s = pnorm(-z-qnorm(1-alpha/2))/power
139-
140-
return(data.frame(power=power, type_s=type_s, amce=amce, n=n, alpha = alpha, levels = levels, delta0 = delta0))
138+
return(data.frame(power = power, type_s = type_s, amce = amce, n = n, alpha = alpha, levels = levels, delta0 = delta0))
141139
}
142140
}
143141
else if (is.null(n)) {
142+
delta0 <- 0.5 - (amce * treat.prob)
144143

145-
if (all(sapply(list(length(amce), length(alpha), length(power), length(levels)), function(x) x == 1)) == FALSE) {
146-
stop("Please provide scalar values or apply a functional.")
147-
}
148-
149-
delta0 = 0.5 - (amce * treat.prob)
150-
151-
n = (levels/2)/(amce^2) * (qnorm(p = 1- alpha/2) + qnorm(p = power))^2*
144+
n <- (levels / 2) / (amce^2) * (qnorm(p = 1 - alpha / 2) + qnorm(p = power))^2 *
152145
(
153-
((delta0 + amce)*(1 - (delta0 + amce)))/0.5 +
154-
((delta0)*(1 - delta0))/0.5
146+
((delta0 + amce) * (1 - (delta0 + amce))) / 0.5 +
147+
((delta0) * (1 - delta0)) / 0.5
155148
)
156149

157-
se = (sqrt( (
158-
((delta0 + amce)*(1 - (delta0 + amce)))/0.5 +
159-
((delta0)*(1 - delta0))/0.5
160-
))/sqrt(2*(n/levels)))
150+
se <- (sqrt((
151+
((delta0 + amce) * (1 - (delta0 + amce))) / 0.5 +
152+
((delta0) * (1 - delta0)) / 0.5
153+
)) / sqrt(2 * (n / levels)))
161154

162-
z=amce/se
155+
z <- amce / se
163156

164-
pow=pnorm(z-qnorm(1-alpha/2)) + pnorm(-z-qnorm(1-alpha/2))
157+
pow <- pnorm(z - qnorm(1 - alpha / 2)) + pnorm(-z - qnorm(1 - alpha / 2))
165158

166-
type_s = pnorm(-z-qnorm(1-alpha/2))/pow
159+
type_s <- pnorm(-z - qnorm(1 - alpha / 2)) / pow
167160

168-
est <- amce + se*rnorm(sims)
161+
exp_typeM <- vector(mode = "numeric", length = length_output)
169162

170-
sig <- abs(est) > se*qnorm(1-alpha/2)
163+
for (i in seq(1, length_output)) {
164+
est <- amce[i] + se[i] * rnorm(sims[i])
171165

172-
exp_typeM <- abs(mean(abs(est)[sig])/amce)
166+
sig <- abs(est) > se[i] * qnorm(1 - alpha[i] / 2)
173167

174-
return(data.frame(n=n, type_s=type_s, exp_typeM=exp_typeM, amce=amce, power=power, alpha = alpha, levels = levels, delta0 = delta0))
168+
exp_typeM[i] <- abs(mean(abs(est)[sig]) / amce[i])
169+
}
175170

171+
return(data.frame(n = n, type_s = type_s, exp_typeM = exp_typeM, amce = amce, power = power, alpha = alpha, levels = levels, delta0 = delta0))
176172
}
177173

178-
else if (is.null(power)){
174+
else if (is.null(power)) {
175+
delta0 <- 0.5 - (amce * treat.prob)
179176

180-
if (all(sapply(list(length(amce), length(alpha), length(n), length(levels)), function(x) x == 1)) == FALSE) {
181-
stop("Please provide scalar values or apply a functional.")
182-
}
183-
184-
delta0 = 0.5 - (amce * treat.prob)
177+
se <- (sqrt((
178+
((delta0 + amce) * (1 - (delta0 + amce))) / 0.5 +
179+
((delta0) * (1 - delta0)) / 0.5
180+
)) / sqrt(2 * (n / levels)))
185181

186-
se = (sqrt( (
187-
((delta0 + amce)*(1 - (delta0 + amce)))/0.5 +
188-
((delta0)*(1 - delta0))/0.5
189-
))/sqrt(2*(n/levels)))
182+
z <- amce / se
190183

191-
z=amce/se
184+
power <- pnorm(z - qnorm(1 - alpha / 2)) + pnorm(-z - qnorm(1 - alpha / 2))
192185

193-
power=pnorm(z-qnorm(1-alpha/2)) + pnorm(-z-qnorm(1-alpha/2))
186+
type_s <- pnorm(-z - qnorm(1 - alpha / 2)) / power
194187

195-
type_s = pnorm(-z-qnorm(1-alpha/2))/power
188+
exp_typeM <- vector(mode = "numeric", length = length_output)
196189

197-
est <- amce + se*rnorm(sims)
190+
for (i in seq(1, length_output)) {
191+
est <- amce[i] + se[i] * rnorm(sims[i])
198192

199-
sig <- abs(est) > se*qnorm(1-alpha/2)
193+
sig <- abs(est) > se[i] * qnorm(1 - alpha[i] / 2)
200194

201-
exp_typeM <- abs(mean(abs(est)[sig])/amce)
195+
exp_typeM[i] <- abs(mean(abs(est)[sig]) / amce[i])
196+
}
202197

203-
return(data.frame(power=power, type_s=type_s, exp_typeM=exp_typeM, amce=amce, n=n, alpha = alpha, levels = levels, delta0 = delta0 ))
198+
return(data.frame(power = power, type_s = type_s, exp_typeM = exp_typeM, amce = amce, n = n, alpha = alpha, levels = levels, delta0 = delta0))
204199
}
205-
206-
}
200+
}

0 commit comments

Comments
 (0)