Package {specr}


Title: Conducting and Visualizing Specification Curve Analyses
Version: 1.1.0
Description: Provides utilities for conducting specification curve analyses (Simonsohn, Simmons & Nelson, 2020, <doi:10.1038/s41562-020-0912-z>) or multiverse analyses (Steegen, Tuerlinckx, Gelman & Vanpaemel, 2016, <doi:10.1177/1745691616658637>) including functions to setup, run, evaluate, and plot all specifications, as well as to conduct inference on the specification curve based on resampling under the null.
License: GPL-3
URL: https://masurp.github.io/specr/, https://github.com/masurp/specr
BugReports: https://github.com/masurp/specr/issues
Depends: R (≥ 4.1.0)
Imports: broom, cowplot, dplyr (≥ 1.1.0), furrr, future, ggplot2 (≥ 3.4.0), ggraph, igraph, lifecycle (≥ 1.0.2), lme4, magrittr, methods, purrr, rlang, stringr, tibble, tidyr (≥ 1.0.0)
Suggests: broom.mixed, fixest, gapminder, knitr, lavaan, testthat (≥ 3.0.0), tidyverse, performance, rmarkdown, survival, withr
Encoding: UTF-8
LazyData: true
RoxygenNote: 7.3.3
VignetteBuilder: knitr
Config/testthat/edition: 3
NeedsCompilation: no
Packaged: 2026-10-15 13:44:44 UTC; philippmasur
Author: Philipp K. Masur ORCID iD [aut, cre], Michael Scharkow [aut]
Maintainer: Philipp K. Masur <phil.masur@gmail.com>
Repository: CRAN
Date/Publication: 2026-10-16 08:50:08 UTC

Return data.frame from specr.infer

Description

Return data.frame from specr.infer

Usage

## S3 method for class 'specr.infer'
as.data.frame(x, ...)

Arguments

x

An object of class "specr.infer".

...

further arguments passed to as.data.frame().

Value

A data frame with the estimates and p-values under the null (one row per bootstrap sample and specification).


Return data.frame from specr.object

Description

Return data.frame from specr.object

Usage

## S3 method for class 'specr.object'
as.data.frame(x, ...)

Arguments

x

An object of class "specr.object".

...

further arguments passed to as.data.frame().

Value

A data frame with the results (one row per specification).


Return data.frame from specr.setup object

Description

Return data.frame from specr.setup object

Usage

## S3 method for class 'specr.setup'
as.data.frame(x, ...)

Arguments

x

An object of class "specr.setup".

...

further arguments passed to as.data.frame().

Value

A data frame with one row per specification.


Return tibble from specr.infer

Description

Long format with one row per bootstrap sample and specification.

Usage

## S3 method for class 'specr.infer'
as_tibble(x, ...)

Arguments

x

An object of class "specr.infer".

...

further arguments (currently ignored).

Value

A tibble with the estimates and p-values under the null (one row per bootstrap sample and specification).


Return tibble from specr.object

Description

Return tibble from specr.object

Usage

## S3 method for class 'specr.object'
as_tibble(x, ...)

Arguments

x

An object of class "specr.object".

...

further arguments passed to tibble::as_tibble().

Value

A tibble with the results (one row per specification).


Return tibble from specr.setup object

Description

Return tibble from specr.setup object

Usage

## S3 method for class 'specr.setup'
as_tibble(x, ...)

Arguments

x

An object of class "specr.setup".

...

further arguments passed to tibble::as_tibble().

Value

A tibble with one row per specification.


Example data set

Description

This simulated data set can be used to explore the major function of 'specr'. It provides variables that can be used to mimic different independent and dependent variables, control variables, and grouping variables (for subset analyses).

Usage

data(example_data)

Format

A tibble with 1,000 rows and 15 variables (no missing values):

group1

Grouping variable with three groups ("young", "middle", "old"), e.g. for subset analyses.

group2

Grouping variable with two groups ("female", "male").

group3

Grouping variable with three groups ("A", "B", "C").

x1, x2, x3, x4

Numeric variables that can be used as (alternative) independent variables.

c1, c2, c3, c4

Numeric variables that can be used as control variables.

y1, y2, y3, y4

Numeric variables that can be used as (alternative) dependent variables.

Source

Simulated data.

Examples

data(example_data)
head(example_data)

Compute intraclass correlation coefficient

Description

[Deprecated] This function is deprecated because the new version of specr uses a new analytic framework. In this framework, you can decompose the variance simply by using the generic plot() function and adding the argument type = "variance", which also prints the variance components. This function extracts intraclass correlation coefficients (ICC) from a multilevel model. It can be used to decompose the variance in the outcome variable of a specification curve analysis (e.g., the regression coefficients). This approach summarises the relative importance of analytical choices by estimating the share of variance in the outcome (e.g., the regression coefficient) that different analytical choices or combinations therefor account for. To use this approach, one needs to estimate a multilevel model that includes all analytical choices as grouping variables (see examples).

Usage

icc_specs(model, percent = TRUE)

Arguments

model

a multilevel (i.e., mixed effects) model that captures the variances of the specification curve.

percent

a logical value indicating whether the ICC should also be printed as percentage. Defaults to TRUE.

Value

a data frame including the grouping variable, the random effect variances, the raw intraclass correlation coefficient (ICC), and the ICC in percent.

References

See Also

plot_variance() to plot the variance decomposition.

Examples

# Step 1: Run spec curve analysis
results <- run_specs(df = example_data,
                     y = c("y1", "y2"),
                     x = c("x1", "x2"),
                     model = c("lm"))

# Step 2: Estimate a multilevel model without predictors
model <- lme4::lmer(estimate ~ 1 + (1|x)  + (1|y), data = results)

# Step 3: Estimate intra-class correlation
icc_specs(model)


Inference on the specification curve

Description

Tests how inconsistent the specification curve as a whole is with the null hypothesis that the independent variable has no effect in any of the specifications. Following Simonsohn, Simmons and Nelson (2020, section "Inference with non-experimental data"), the function generates the distribution of specification curves that would be expected under the null by resampling data in which the null hypothesis is known to be true. The resulting object of class specr.infer can be summarized with summary() (test statistics and p-values) and plotted with plot() (observed curve against the curves under the null).

Usage

infer_curve(x, data, n_samples = 500, fast = TRUE, ...)

Arguments

x

A specr.object, resulting from running specr() (or the tibble that specr() returns when it is given a tibble of specifications).

data

The data set that was used to fit the specifications, or the specr.setup object created by setup() (whose data set is then used).

n_samples

Number of bootstrap samples drawn under the null. Defaults to 500. Use at least 1,000 for results that are reported.

fast

Logical value indicating whether specifications that were fitted with lm should be refitted with a fast least-squares routine. It gives the same estimates and p-values as lm(), which is checked against the observed results for every specification before it is used. Set to FALSE to refit all specifications with their original model function. Defaults to TRUE.

...

Further arguments passed to furrr::future_map(), e.g. .progress = TRUE. The argument .options cannot be set, because the resampling always uses furrr_options(seed = TRUE).

Details

Procedure

For every specification k, the dependent variable is first modified so that the null hypothesis is true by construction: y^*_k = y_k - b_k x_k, where b_k is the estimate observed in that specification. Then, in each of n_samples bootstrap samples, N rows are drawn with replacement from the data (N being the number of rows of data), and every specification is refitted on these rows with y^*_k as its dependent variable. The same rows are used for all specifications, which preserves the dependence between them. Each specification keeps its own model, control variables, subset, and additions to the formula, so that the curves under the null are based on exactly the same specifications as the observed curve.

Requirements

Because the null is imposed by subtracting b_k x_k from the dependent variable, the procedure is only valid for models that are linear in the dependent variable (e.g., lm, lmer, or glm with a gaussian family and identity link), for numeric independent and dependent variables, and for unstandardized estimates. Before resampling, infer_curve() refits every specification on the full data with y^*_k and stops if the estimate is not zero, which catches models and extraction functions for which this does not hold (e.g., logistic regression). Structural equation models (lavaan) are not supported. Note that rows are resampled independently, which ignores clustering (e.g., in multilevel data).

Interpretation

Joint inference across all specifications is only meaningful if the specifications are genuinely equivalent, arbitrary alternatives (Del Giudice & Gangestad, 2021). See vignette("inferences") for a discussion.

Parallelization

The bootstrap samples are distributed across workers if a parallel plan has been set up front, e.g. future::plan(future::multisession, workers = 4). Results are reproducible with set.seed() and identical whether they are computed sequentially or in parallel. For more information, see vignette("parallelization").

Value

An object of class specr.infer, a list that includes the observed curve (observed), the estimates and p-values under the null (estimates and p_values; matrices with one row per bootstrap sample and one column per specification), and technical information. Use methods(class = "specr.infer") for an overview on available methods.

References

See Also

summary.specr.infer() and plot.specr.infer() to investigate the results.

Examples

# Setup and run specification curve analysis
specs <- setup(data = example_data,
   y = "y1",
   x = c("x1", "x2"),
   model = "lm",
   controls = c("c1", "c2"),
   subsets = list(group2 = c("female", "male")))

results <- specr(specs)

# Resample under the null (better 1,000 or more)
set.seed(42)
inference <- infer_curve(results, specs, n_samples = 200)

# Test statistics and p-values
summary(inference)

# Observed curve against the curves under the null
plot(inference)

# For comparison: the same analysis after shuffling y1, which removes any
# effect of x1 and x2 in all specifications
shuffled <- example_data
shuffled$y1 <- sample(shuffled$y1)
specs_null <- setup(data = shuffled,
   y = "y1",
   x = c("x1", "x2"),
   model = "lm",
   controls = c("c1", "c2"),
   subsets = list(group2 = c("female", "male")))

summary(infer_curve(specr(specs_null), specs_null, n_samples = 200))

Plot specification curve against curves under the null

Description

This function plots the observed specification curve (estimates ranked from lowest to highest) on top of the median and the 2.5% and 97.5% quantiles of the ranked curves under the null (resulting from infer_curve()).

Usage

## S3 method for class 'specr.infer'
plot(x, ...)

Arguments

x

A specr.infer object, resulting from calling infer_curve().

...

further arguments passed to or from other methods (currently ignored).

Value

A ggplot object that can be customized further.

See Also

infer_curve(), summary.specr.infer()

Examples

specs <- setup(data = example_data,
   y = "y1",
   x = c("x1", "x2"),
   model = "lm",
   controls = c("c1", "c2"))

set.seed(42)
inference <- infer_curve(specr(specs), specs, n_samples = 200) # better 1,000 or more

# Observed curve against the curves under the null
plot(inference)

Plot specification curve and analytic choices

Description

This function plots visualizations of the specification curve analysis. The function requires an object of class specr.object, usually the results of calling specr() to create a standard visualization of the specification curve analysis. Several types of visualizations are possible.

Usage

## S3 method for class 'specr.object'
plot(
  x,
  type = "default",
  var = .data$estimate,
  group = NULL,
  choices = c("x", "y", "model", "controls", "subsets"),
  labels = c("A", "B"),
  rel_heights = c(2, 3),
  desc = FALSE,
  null = 0,
  ci = TRUE,
  ribbon = FALSE,
  formula = NULL,
  print = TRUE,
  choice_labels = c("right", "left"),
  ...
)

Arguments

x

A specr.object object, usually resulting from calling specr().

type

What type of figure should be plotted? If type = "default", the standard specification curve analysis plot (the specification curve as the upper panel and an overview of the relevant choices as the lower panel) is created. If type = "curve", only the specification curve (upper panel of the default plot) is plotted. If type = "choices", only the choice panel (lower part of the default plot) is plotted. If type = "boxplot", an alternative visualization of differences between choices is plotted that summarizes results per choice using box-and-whisker plot(s). If type = "variance", the variance of the estimates is decomposed into the shares explained by the analytical choices (see formula). If type = "samplesizes", a barplot of sample sizes per specification is plotted. See examples for more information.

var

Which parameter should be plotted in the curve? Defaults to estimate, but other parameters (e.g., p.value, fit_r.squared,...) can be plotted too. Note that the confidence intervals (ci) and the colors always refer to the estimate, so set ci = FALSE for other parameters.

group

Should the arrangement of the curve be grouped by a particular choice? Defaults to NULL, but can be any of the present choices (e.g., x, y, controls...), given unquoted (group = x) or as a string (group = "x").

choices

A vector specifying which analytic choices should be plotted. By default, all choices (x, y, model, controls, subsets) are plotted.

labels

Labels for the two parts of the plot

rel_heights

vector indicating the relative heights of the plot.

desc

Logical value indicating whether the curve should the arranged in a descending order. Defaults to FALSE.

null

Indicate what value represents the 'null' hypothesis (defaults to zero). Specifications whose confidence intervals exclude this value are highlighted (positive = blue, negative = red).

ci

Logical value indicating whether confidence intervals should be plotted.

ribbon

Logical value indicating whether a ribbon instead should be plotted

formula

In combination with type = "variance", you can provide a specific formula to extract specific variance components. The syntax of the formula is based on lme4::lmer() and thus looks something like, e.g.: "estimate ~ 1 + (1|x) + (1|y)" (to estimate the amount of variance explained by different independent x and dependent variables y). All other choices are then subsumed under residual variance. If no formula is provided, all choices (x, y, model, controls, and subsets) that have more than one alternative are included. See examples for further details.

print

In combination with type = "variance", logical value indicating whether the intra-class correlations (i.e., percentages of variance explained by analytical choices) should be printed or not. Defaults to TRUE.

choice_labels

Where should the names of the analytical choices (x, y, model, ...) be shown in the panel of choices (type = "default" or "choices")? Either "right" (default) or "left", next to their options.

...

further arguments passed to or from other methods (currently ignored).

Value

A ggplot object that can be customized further.

Examples


# Specification Curve analysis ----
# Setup specifications
specs <- setup(data = example_data,
   y = c("y1", "y2"),
   x = c("x1", "x2"),
   model = "lm",
   controls = c("c1", "c2"),
   subsets = list(group1 = unique(example_data$group1),
                  group2 = unique(example_data$group2)))

# Run analysis
results <- specr(specs)

# Resulting data frame with estimates
as_tibble(results)  # This will be used for plotting


# Visualizations ---
# Plot results in various ways
plot(results)                            # default
plot(results, choices = c("x", "y"))     # specific choices
plot(results, ci = FALSE, ribbon = TRUE) # exclude CI and add ribbon instead
plot(results, type = "curve")
plot(results, type = "choices")
plot(results, type = "samplesizes")
plot(results, type = "boxplot")

# Names of the choices on the left, next to their options
plot(results, choice_labels = "left")


# Grouped plot
plot(results, group = controls)

# Alternative and specific visualizations ----
# Other variables in the resulting data set can be plotted too
plot(results,
     type = "curve",
     var = fit_r.squared,   # extract "r-square" instead of "estimate"
     ci = FALSE)

# Such a plot can also be extended (e.g., by again adding the estimates with
# confidence intervals)
library(ggplot2)
plot(results, type = "curve", var = fit_r.squared) +
  geom_point(aes(y = estimate), shape = 5) +
  labs(x = "specifications", y = "r-squared | estimate")

# We can also investigate how much variance is explained by each analytical choice
plot(results, type = "variance")

# By providing a specific formula in `lme4::lmer()`-style, we can extract specific choices
# and also include interactions between choices
plot(results,
     type = "variance",
     formula = "estimate ~ 1 + (1|x) + (1|y) + (1|group1) + (1|x:y)")

## Combining several plots ----
# `specr` also exports the function `plot_grid()` from the package `cowplot`, which
# can be used to combine plots meaningfully
a <- plot(results, "curve")
b <- plot(results, "choices", choices = c("x", "y", "controls"))
c <- plot(results, "samplesizes")
plot_grid(a, b, c,
          align = "v",
          axis = "rbl",
          rel_heights = c(2, 3, 1),
          ncol = 1)


Plot visualization of the specification setup

Description

This function plots a visual summary of the specification setup. It requires an object of class specr.setup, usually the result of calling setup().

Usage

## S3 method for class 'specr.setup'
plot(x, layout = "dendrogram", circular = FALSE, ...)

Arguments

x

A specr.setup object, usually resulting from calling setup().

layout

The type of layout to create for the garden of forking path. Defaults to "dendrogram". See ?ggraph for options.

circular

Should the layout be transformed into a radial representation. Only possible for some layouts. Defaults to FALSE.

...

further arguments passed to or from other methods (currently ignored).

Value

A ggplot object that can be customized further.

Examples


specs <- setup(data = example_data,
   x = c("x1", "x2", "x3"),
   y = c("y1", "y2"),
   model = c("lm", "glm"),
   controls = "c1",
   subsets = list(group2 = unique(example_data$group2)))

plot(specs)
plot(specs, circular = TRUE)


Plot how analytical choices affect results

Description

[Deprecated] This function is deprecated because the new version of specr uses a new analytic framework. In this framework, you can plot a similar figure simply by using the generic plot() function and adding the argument type = "choices". This functions plots how analytic choices affect the obtained results (i.e., the rank within the curve). Significant results are highlighted (negative = red, positive = blue, grey = nonsignificant). This functions creates the lower panel in plot_specs().

Usage

plot_choices(
  df,
  var = .data$estimate,
  group = NULL,
  choices = c("x", "y", "model", "controls", "subsets"),
  desc = FALSE,
  null = 0
)

Arguments

df

a data frame resulting from run_specs().

var

which variable should be evaluated? Defaults to estimate (the effect sizes computed by run_specs()).

group

Should the arrangement of the curve be grouped by a particular choice? Defaults to NULL, but can be any of the present choices (e.g., x, y, controls...)

choices

a vector specifying which analytical choices should be plotted. By default, all choices are plotted.

desc

logical value indicating whether the curve should the arranged in a descending order. Defaults to FALSE.

null

Indicate what value represents the 'null' hypothesis (Defaults to zero).

Value

a ggplot object.

Examples

# Run specification curve analysis
results <- run_specs(df = example_data,
                     y = c("y1", "y2"),
                     x = c("x1", "x2"),
                     model = c("lm"),
                     controls = c("c1", "c2"),
                     subsets = list(group1 = unique(example_data$group1),
                                    group2 = unique(example_data$group2)))

# Plot simple table of choices
plot_choices(results)

# Plot only specific choices
plot_choices(results,
             choices = c("x", "y", "controls"))

Plot ranked specification curve

Description

[Deprecated] This function is deprecated because the new version of specr uses a new analytic framework. In this framework, you can plot a similar figure simply by using the generic plot() function and adding the argument type = "curve". This function plots the a ranked specification curve. Confidence intervals can be included. Significant results are highlighted (negative = red, positive = blue, grey = nonsignificant). This functions creates the upper panel in plot_specs().

Usage

plot_curve(
  df,
  var = .data$estimate,
  group = NULL,
  desc = FALSE,
  ci = TRUE,
  ribbon = FALSE,
  legend = FALSE,
  null = 0
)

Arguments

df

a data frame resulting from run_specs().

var

which variable should be evaluated? Defaults to estimate (the effect sizes computed by run_specs()).

group

Should the arrangement of the curve be grouped by a particular choice? Defaults to NULL, but can be any of the present choices (e.g., x, y, controls...)

desc

logical value indicating whether the curve should the arranged in a descending order. Defaults to FALSE.

ci

logical value indicating whether confidence intervals should be plotted.

ribbon

logical value indicating whether a ribbon instead should be plotted.

legend

logical value indicating whether the legend should be plotted. Defaults to FALSE. Currently has no effect, because the colors are set directly and no legend is created.

null

Indicate what value represents the null hypothesis (Defaults to zero)

Value

a ggplot object.

Examples

# load additional library
library(ggplot2) # for further customization of the plots

# Run specification curve analysis
results <- run_specs(df = example_data,
                     y = c("y1", "y2"),
                     x = c("x1", "x2"),
                     model = c("lm"),
                     controls = c("c1", "c2"),
                     subsets = list(group1 = unique(example_data$group1),
                                    group2 = unique(example_data$group2)))

# Plot simple specification curve
plot_curve(results)

# Ribbon instead of CIs and customize further
plot_curve(results, ci = FALSE, ribbon = TRUE) +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = median(results$estimate),
             linetype = "dashed") +
  theme_linedraw()

Plot decision tree

Description

[Deprecated] This function is deprecated because the new version of specr uses a new analytic framework. In this framework, you can plot a similar figure simply by using the generic plot(). This function plots a simple decision tree that is meant to help understanding how few analytical choices may results in a large number of specifications. It is somewhat useless if the final number of specifications is very high.

Usage

plot_decisiontree(df, label = FALSE, legend = FALSE)

Arguments

df

data frame resulting from run_specs().

label

Logical. Should labels be included? Defaults to FALSE. Produces only a reasonable plot if number of specifications is low.

legend

Logical. Should specific decisions be identifiable. Defaults to FALSE.

Value

a ggplot object.

Examples

results <- run_specs(df = example_data,
                    y = c("y1", "y2"),
                    x = c("x1", "x2"),
                    model = c("lm"),
                    controls = c("c1", "c2"))

# Basic, non-labelled decisions tree
plot_decisiontree(results)

# Labelled decisions tree
plot_decisiontree(results, label = TRUE)

# Add legend
plot_decisiontree(results, label = TRUE, legend = TRUE)

Plot sample sizes

Description

[Deprecated] This function is deprecated because the new version of specr uses a new analytic framework. In this framework, you can plot a similar figure simply by using the generic plot() function and adding the argument type = "samplesizes". This function plots a histogram of sample sizes per specification. It can be added to the overall specification curve plot (see vignettes).

Usage

plot_samplesizes(df, var = .data$estimate, group = NULL, desc = FALSE)

Arguments

df

a data frame resulting from run_specs().

var

which variable should be evaluated? Defaults to estimate (the effect sizes computed by run_specs()).

group

Should the arrangement of the curve be grouped by a particular choice? Defaults to NULL, but can be any of the present choices (e.g., x, y, controls...)

desc

logical value indicating whether the curve should the arranged in a descending order. Defaults to FALSE.

Value

a ggplot object.

Examples

# load additional library
library(ggplot2) # for further customization of the plots

# run specification curve analysis
results <- run_specs(df = example_data,
                     y = c("y1", "y2"),
                     x = c("x1", "x2"),
                     model = c("lm"),
                     controls = c("c1", "c2"),
                     subsets = list(group1 = unique(example_data$group1),
                                    group2 = unique(example_data$group2)))
# plot ranked bar chart of sample sizes
plot_samplesizes(results)

# add a horizontal line for the median sample size
plot_samplesizes(results) +
  geom_hline(yintercept = median(results$fit_nobs),
             color = "darkgrey",
             linetype = "dashed") +
  theme_linedraw()

Plot specification curve and analytical choices

Description

[Deprecated] This function is deprecated because the new version of specr uses a new analytic framework. In this framework, you can plot a similar figure simply by using the generic plot() function and adding the argument type = "default". This function plots an entire visualization of the specification curve analysis. The function uses the entire tibble that is produced by run_specs() to create a standard visualization of the specification curve analysis. Alternatively, one can also pass two separately created ggplot objects to the function. In this case, it simply combines them using cowplot::plot_grid. Significant results are highlighted (negative = red, positive = blue, grey = nonsignificant).

Usage

plot_specs(
  df = NULL,
  plot_a = NULL,
  plot_b = NULL,
  choices = c("x", "y", "model", "controls", "subsets"),
  labels = c("A", "B"),
  rel_heights = c(2, 3),
  desc = FALSE,
  null = 0,
  ci = TRUE,
  ribbon = FALSE,
  ...
)

Arguments

df

a data frame resulting from run_specs().

plot_a

a ggplot object resulting from plot_curve() (or plot_choices() respectively).

plot_b

a ggplot object resulting from plot_choices() (or plot_curve() respectively).

choices

a vector specifying which analytical choices should be plotted. By default, all choices are plotted.

labels

labels for the two parts of the plot

rel_heights

vector indicating the relative heights of the plot.

desc

logical value indicating whether the curve should the arranged in a descending order. Defaults to FALSE.

null

Indicate what value represents the 'null' hypothesis (defaults to zero).

ci

logical value indicating whether confidence intervals should be plotted.

ribbon

logical value indicating whether a ribbon instead should be plotted.

...

additional arguments that can be passed to plot_grid().

Value

a ggplot object.

See Also

Examples

# load additional library
library(ggplot2) # for further customization of the plots

# run spec analysis
results <- run_specs(example_data,
                     y = c("y1", "y2"),
                     x = c("x1", "x2"),
                     model = "lm",
                     controls = c("c1", "c2"),
                     subsets = list(group1 = unique(example_data$group1)))

# plot results directly
plot_specs(results)

# Customize each part and then combine
p1 <- plot_curve(results) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "grey") +
  ylim(-3, 12) +
  labs(x = "", y = "regression coefficient")

p2 <- plot_choices(results) +
  labs(x = "specifications (ranked)")

plot_specs(plot_a = p1,    # arguments must be called directly!
           plot_b = p2,
           rel_heights = c(2, 2))

Create box plots for given analytical choices

Description

[Deprecated] This function is deprecated because the new version of specr uses a new analytic framework. In this framework, you can plot a similar figure simply by using the generic plot() function and adding the argument type = "boxplot". This function provides a convenient way to visually investigate the effect of individual choices on the estimate of interest. It produces box-and-whisker plot(s) for each provided analytical choice.

Usage

plot_summary(df, choices = c("x", "y", "model", "controls", "subsets"))

Arguments

df

a data frame resulting from run_specs().

choices

a vector specifying which analytical choices should be plotted. By default, all choices are plotted.

Value

a ggplot object.

See Also

summarise_specs() to investigate the affect of analytical choices in more detail.

Examples

# run spec analysis
results <- run_specs(example_data,
                     y = c("y1", "y2"),
                     x = c("x1", "x2"),
                     model = "lm",
                     controls = c("c1", "c2"),
                     subsets = list(group1 = unique(example_data$group1)))

# plot boxplot comparing specific choices
plot_summary(results, choices = c("subsets", "controls", "y"))

Plot variance decomposition

Description

[Deprecated] This function is deprecated because the new version of specr uses a new analytic framework. In this framework, you can plot a similar figure simply by using the generic plot() function and adding the argument type = "variance". This functions creates a simple barplot that visually displays how much variance in the outcome (e.g., the regression coefficient) different analytical choices or combinations therefor account for. To use this approach, one needs to estimate a multilevel model that includes all analytical choices as grouping variables (see examples and vignettes). This function uses icc_specs() to compute the intraclass correlation coefficients (ICCs), which provides the data basis for the plot (see examples).

Usage

plot_variance(model)

Arguments

model

a multilevel model that captures the variances of the specification curve (based on the data frame resulting from run_specs).

Value

a ggplot object.

See Also

icc_specs() to produce a tibble that details the variance decomposition.

Examples

# Step 1: Run spec curve analysis
results <- run_specs(df = example_data,
                     y = c("y1", "y2"),
                     x = c("x1", "x2"),
                     model = c("lm"))

# Step 2: Estimate multilevel model
library(lme4, quietly = TRUE)
model <- lmer(estimate ~ 1 + (1|x)  + (1|y), data = results)

# Step 3: Plot model
plot_variance(model)


Print method for S3 class "specr.infer"

Description

Print method for S3 class "specr.infer"

Usage

## S3 method for class 'specr.infer'
print(x, ...)

Arguments

x

An object of class "specr.infer".

...

further arguments passed to or from other methods (currently ignored).

Value

Prints technical details and the test statistics (see summary.specr.infer()) and returns x invisibly.


Print method for S3 class "specr.object"

Description

Print method for S3 class "specr.object"

Usage

## S3 method for class 'specr.object'
print(x, ...)

Arguments

x

An object of class "specr.object".

...

further arguments passed to or from other methods (currently ignored).

Value

Prints a short summary of the specification curve and returns x invisibly.


Print method for S3 class "specr.setup"

Description

Print method for S3 class "specr.setup"

Usage

## S3 method for class 'specr.setup'
print(x, ...)

Arguments

x

An object of class "specr.setup".

...

further arguments passed to or from other methods (currently ignored).

Value

Prints the number of specifications and returns x invisibly.


Objects exported from other packages

Description

These objects are imported from other packages. Follow the links below to see their documentation.

cowplot

plot_grid

magrittr

%>%

tibble

as_tibble


Estimate all specifications

Description

[Deprecated] This function was deprecated because the new version of specr uses different analytical framework. In this framework, you should use the function setup() first and then run all specifications using specr(). This is the central function of the package. It runs the specification curve analysis. It takes the data frame and vectors for analytical choices related to the dependent variable, the independent variable, the type of models that should be estimated, the set of covariates that should be included (none, each individually, and all together), as well as a named list of potential subsets. The function returns a tidy tibble which includes relevant model parameters for each specification. The function tidy is used to extract relevant model parameters. Exactly what tidy considers to be a model component varies across models but is usually self-evident.

Usage

run_specs(
  df,
  x,
  y,
  model = "lm",
  controls = NULL,
  subsets = NULL,
  all.comb = FALSE,
  conf.level = 0.95,
  keep.results = FALSE
)

Arguments

df

a data frame that includes all relevant variables

x

a vector denoting independent variables

y

a vector denoting the dependent variables

model

a vector denoting the model(s) that should be estimated.

controls

a vector denoting which control variables should be included. Defaults to NULL.

subsets

a named list that includes potential subsets that should be evaluated (see examples). Defaults to NULL.

all.comb

a logical value indicating what type of combinations of the control variables should be specified. Defaults to FALSE (i.e., none, all, and each individually). If this argument is set to TRUE, all possible combinations between the control variables are specified (see examples).

conf.level

the confidence level to use for the confidence interval. Must be strictly greater than 0 and less than 1. Defaults to .95, which corresponds to a 95 percent confidence interval.

keep.results

a logical value indicating whether the complete model object should be kept. Defaults to FALSE.

Value

a tibble that includes all specifications and a tidy summary of model components.

References

See Also

plot_specs() to visualize the results of the specification curve analysis.

Examples

# run specification curve analysis
results <- run_specs(df = example_data,
                     y = c("y1", "y2"),
                     x = c("x1", "x2"),
                     model = c("lm"),
                     controls = c("c1", "c2"),
                     subsets = list(group1 = unique(example_data$group1),
                                    group2 = unique(example_data$group2)))

# Check results frame
results


Specifying analytical decisions in a specification setup

Description

Creates all possible specifications as a combination of different dependent and independent variables, model types, control variables, potential subset analyses, as well as potentially other analytic choices. This function represents the first step in the analytic framework implemented in the package specr. The resulting class specr.setup then needs to be passed to the core function of the package called specr(), which fits the specified models across all specifications.

Usage

setup(
  data,
  x,
  y,
  model,
  controls = NULL,
  subsets = NULL,
  add_to_formula = NULL,
  fun1 = function(x) broom::tidy(x, conf.int = TRUE),
  fun2 = function(x) broom::glance(x),
  simplify = FALSE
)

Arguments

data

The data set that should be used for the analysis

x

A character vector denoting the independent variables (which should be numeric variables, see details)

y

A character vector denoting the dependent variables

model

A character vector with the names of the model functions that should be estimated (e.g., "lm" or the name of a custom function), or a named list of functions (e.g., list(ols = lm, robust = MASS::rlm)), in which case the names are used as labels for the models. Any function that accepts the arguments formula and data can be used, including custom wrappers around other model functions (e.g., for survival models, fixed effects models, or weighted regressions; see vignette("different-specifications")).

controls

A vector of the control variables that should be included. Defaults to NULL.

subsets

Specification of potential subsets/groups as list. There are two ways in which these can be specified that both start from the assumption that the "grouping" variable is in the data set. The simplest way is to provide a named vector within the list, whose name is the variable that should be used for subsetting and whose values are the values that reflect the subsets (e.g., list(group2 = c("female", "male"))). In this case, the specifications will include "all", "only female" and "only male". Alternatively, you can also use the unique function to extract that vector directly from the data set (e.g., list(group2 = unique(example_data$group2))). Both approaches lead to the same result. The former, however, has the advantages that one can also remove some of the subgroups (e.g. list(group2 = c("female"))). In this case, the specifications will include "all" (no subset) and "only females". See examples for more details. Missing values (NA) among the subset values are ignored.

add_to_formula

A string specifying aspects that should always be included in the formula (e.g. a constant covariate, random effect structures...)

fun1

A function that extracts the parameters of interest from the fitted models. Defaults to tidy, which works with a large range of different models.

fun2

A function that extracts fit indices of interest from the models. Defaults to glance, which works with a large range of different models. Note: Different models result in different fit indices. Thus, if you use different models within one specification curve analysis, this may not work. In this case, you can simply set fun2 = NULL to not extract any fit indices.

simplify

Logical value indicating what type of combinations between control variables should be included in the specification. If FALSE (default), all combinations between the provided variables are created (none, each individually, each combination between each variable, all variables). If TRUE, only no covariates, each individually, and all covariates are included as specifications (akin to the default in specr version 0.2.1).

Details

Empirical results are often contingent on analytical decisions that are equally defensible, often arbitrary, and motivated by different reasons. These decisions may introduce bias or at least variability. To this end, specification curve analyses (Simonsohn et al., 2020) or multiverse analyses (Steegen et al., 2016) refer to identifying the set of theoretically justified, statistically valid (and potentially also non-redundant) specifications, fitting the "multiverse" of models represented by these specifications and extract relevant parameters often to display the results graphically as a so-called specification curve. This allows readers to identify consequential specifications decisions and how they affect the results or parameter of interest.

Use of this function

A general overview is provided in the vignette vignette("getting-started"). It is assumed that you want to estimate the relationship between two variables (x and y). What varies may be what variables should be used for x and y, what model should be used to estimate the relationship, whether the relationship should be estimated for certain subsets, and whether different combinations of control variables should be included. This allows to (re)produce almost any analytical decision imaginable. See examples below for how a number of typical analytical decision can be implemented. Afterwards you pass the resulting object of a class specr.setup to the function specr() to run the specification curve analysis.

As specr() extracts the estimate whose term equals x, the independent variables should be numeric. For factor or character variables, models return terms such as "xB", so recode them as (dummy) variables instead.

Note, the resulting class of specr.setup allows to use generic functions. Use methods(class = "specr.setup") for an overview on available methods and e.g., ?summary.specr.setup to view the dedicated help page.

Value

An object of class specr.setup which includes all possible specifications based on combinations of the analytic choices. The resulting list includes a specification tibble, the data set, and additional information about the universe of specifications. Use methods(class = "specr.setup") for an overview on available methods.

References

See Also

specr() for the second step of actually running the actual specification curve analysis

summary.specr.setup() for how to summarize and inspect the resulting specifications

plot.specr.setup() for creating a visual summary of the specification setup.

Examples

## Example 1 ----
# Setting up typical specifications
specs <- setup(data = example_data,
   x = c("x1", "x2"),
   y = c("y1", "y2"),
   model = "lm",
   controls = c("c1", "c2", "c3"),
   subsets = list(group1 = c("young", "middle", "old"),
                  group2 = c("female", "male")),
   simplify = TRUE)

# Check specifications
summary(specs, rows = 18)


## Example 2 ----
# Setting up specifications for multilevel models
specs <- setup(data = example_data,
   x = c("x1", "x2"),
   y = c("y1", "y2"),
   model = c("lmer"),                                   # multilevel model
   subsets = list(group1 = c("young", "old"),           # only young and old!
                  group2 = unique(example_data$group2)),# alternative specification
   controls = c("c1", "c2"),
   add_to_formula = "(1|group2)")                       # random effect in all models

# Check specifications
summary(specs)


## Example 3 ----
# Setting up specifications with a different parameter extract functions

# Create custom extract function to extract different parameter and model
tidy_99 <- function(x) {
  fit <- broom::tidy(x,
     conf.int = TRUE,
     conf.level = .99)         # different alpha error rate
  fit$full_model = list(x)     # include entire model fit object as list
  return(fit)
}

# Setup specs
specs <- setup(data = example_data,
   x = c("x1", "x2"),
   y = c("y1", "y2"),
   model = "lm",
   fun1 = tidy_99,             # pass new function to setup
   add_to_formula = "c1 + c2") # set of covariates in all models

# Check specifications
summary(specs)


## Example 4 ----
# Model functions as a named list (the names are used as labels)

# Custom function, e.g. a weighted regression (any function with the
# arguments `formula` and `data` works, e.g. also wrappers around
# fixest::feols() or survival::coxph(), see vignette("different-specifications"))
weighted_lm <- function(formula, data) {
  lm(formula, data = data, weights = rep(1:2, length.out = nrow(data)))
}

specs <- setup(data = example_data,
   x = c("x1", "x2"),
   y = "y1",
   model = list(ols = lm, weighted = weighted_lm),
   controls = "c1")

# Check specifications
summary(specs)

Set up specifications

Description

[Deprecated] This function was deprecated because the new version of specr uses a new analytic framework. In this framework, you should use the function setup() instead. This function creates a tibble that includes all possible specifications based the dependent and independent variables, model types, and control variables that are specified. This function simply produces a tibble of all combinations. It can be used to check the specified analytical choices. This function is called within run_specs(), which estimates all specified models based on the data that are provided.

Usage

setup_specs(x, y, model, controls = NULL, all.comb = FALSE)

Arguments

x

a vector denoting independent variables

y

a vector denoting the dependent variables

model

a vector denoting the model(s) that should be estimated.

controls

a vector of the control variables that should be included. Defaults to NULL.

all.comb

a logical value indicating what type of combinations of the control variables should be specified. Defaults to FALSE (i.e., none, all, and each individually). If this argument is set to TRUE, all possible combinations between the control variables are specified (see examples).

Value

a tibble that includes all possible specifications based on combinations of the analytic choices.

See Also

run_specs() to run the specification curve analysis.

Examples

setup_specs(x = c("x1", "x2"),
            y = "y2",
            model = "lm",
            controls = c("c1", "c2"))


Fit models across all specifications

Description

Runs the specification/multiverse analysis across specified models. This is the central function of the package and represent the second step in the analytic framework implemented in the package specr. It estimates and returns respective parameters and estimates of models that were specified via setup().

Usage

specr(x, data = NULL, ...)

Arguments

x

A specr.setup object resulting from setup or a tibble that contains the relevant specifications (e.g., a tibble resulting from as_tibble(setup(...))).

data

If x is not an object of "specr.setup" and simply a tibble, you need to provide the data set that should be used. Defaults to NULL as it is assumed that most users will create an object of class "specr.setup" that they'll pass to specr().

...

Further arguments that can be passed to future_pmap. This only becomes important if parallelization is used (they are ignored if the specifications are fitted sequentially). For example, furrr_options can be passed to the argument .options. When a plan for parallelization is set, one can also set .progress = TRUE to print a progress bar during the fitting process. See details for more information on parallelization.

Details

Empirical results are often contingent on analytical decisions that are equally defensible, often arbitrary, and motivated by different reasons. These decisions may introduce bias or at least variability. To this end, specification curve analyses (Simonsohn et al., 2020) or multiverse analyses (Steegen et al., 2016) refer to identifying the set of theoretically justified, statistically valid (and potentially also non-redundant) specifications, fitting the "multiverse" of models represented by these specifications and extract relevant parameters often to display the results graphically as a so-called specification curve. This allows readers to identify consequential specifications decisions and how they affect the results or parameter of interest.

Use of this function

A general overview is provided in the vignette vignette("getting-started"). Generally, you create relevant specification using the function setup(). You then pass the resulting object of a class specr.setup to the present function specr() to run the specification curve analysis. Further note that the resulting object of class specr.object allows to use several generic function such as summary() or plot(). Use methods(class = "specr.object") for an overview on available methods and e.g., ?plot.specr.object to view the dedicated help page.

Parallelization

By default, the function fits models across all specifications sequentially (one after the other). If the data set is large, the models complex (e.g., large structural equation models, negative binomial models, or Bayesian models), and the number of specifications is large, it can make sense to parallelize these operations. One simply has to load the package furrr (which in turn, builds on future) up front. Then parallelizing the fitting process works as specified in the package description of furrr/future by setting a "plan" before running specr such as:

plan(multisession, workers = 4)

However, there are many more ways to specifically set up the plan, including different strategy than multisession. For more information, see vignette("parallelization") and the reference page for plan().

Disclaimer

We do see a lot of value in investigating how analytical choices affect a statistical outcome of interest. However, we strongly caution against using specr as a tool to somehow arrive at a better estimate compared to a single model. Running a specification curve analysis does not make your findings any more reliable, valid or generalizable than a single analysis. The method is meant to inform about the effects of analytical choices on results, and not a better way to estimate a correlation or effect.

Value

An object of class specr.object, which includes a data frame with all specifications their respective results along with many other useful information about the model. Parameters are extracted via the function passed to setup. By default this is broom::tidy() and the function broom::glance(). Several other aspects and information are included in the resulting class (e.g., number of specifications, time elapsed, subsets included in the analyses). Use methods(class = "specr.object") for an overview on available methods.

References

See Also

setup() for the first step of setting up the specifications.

summary.specr.object() for how to summarize and inspect the results.

plot.specr.object() for plotting results.

Examples

# Example 1 ----
# Setup up typical specifications
specs <- setup(data = example_data,
   y = c("y1", "y2"),
   x = c("x1", "x2"),
   model = "lm",
   controls = c("c1", "c2"),
   subsets = list(group1 = unique(example_data$group1)))

# Run analysis (not parallelized)
results <- specr(specs)

# Summary of the results
summary(results)


# Example 2 ----
# Working without S3 classes
specs2 <- setup(data = example_data,
    y = c("y1", "y2"),
    x = c("x1", "x2"),
    model = "lm",
    controls = "c1")

# Working with tibbles
specs_tibble <- as_tibble(specs2)      # extract tibble from setup
results2 <- specr(specs_tibble,
                  data = example_data) # need to provide data!

# Results (tibble instead of S3 class)
head(results2)

Summarise specifications

Description

[Deprecated] This function is deprecated because the new version of specr uses a new analytic framework. In this framework, you can obtain a similar summary simply by using the generic summary() function and adding the argument type = "curve". This function allows to inspect results of the specification curves by returning a comparatively simple summary of the results. This summary can be produced for various specific analytical choices and customized summary functions.

Usage

summarise_specs(
  df,
  ...,
  var = .data$estimate,
  stats = list(median = median, mad = mad, min = min, max = max, q25 = function(x)
    quantile(x, prob = 0.25), q75 = function(x) quantile(x, prob = 0.75))
)

Arguments

df

a data frame resulting from run_specs().

...

one or more grouping variables (e.g., subsets, controls,...) that denote the available analytical choices.

var

which variable should be evaluated? Defaults to estimate (the effect sizes computed by run_specs()).

stats

named vector or named list of summary functions (individually defined summary functions can included). If it is not named, placeholders (e.g., "fn1") will be used as column names.

Value

a tibble.

See Also

plot_summary() to visually investigate the affect of analytical choices.

Examples

# Run specification curve analysis
results <- run_specs(df = example_data,
                     y = c("y1", "y2"),
                     x = c("x1", "x2"),
                     model = c("lm"),
                     controls = c("c1", "c2"),
                     subsets = list(group1 = unique(example_data$group1),
                                    group2 = unique(example_data$group2)))

# overall summary
summarise_specs(results)

# Summary of specific analytical choices
summarise_specs(results,    # data frame
                x, y)       # analytical choices

# Summary of other parameters across several analytical choices
summarise_specs(results,
                subsets, controls,
                var = p.value,
                stats = list(median = median,
                             min = min,
                             max = max))

# Named vector instead of named list passed to `stats`
summarise_specs(results,
                controls,
                stats = c(mean = mean,
                          median = median))


Summarizing inference on the specification curve

Description

Computes the three test statistics proposed by Simonsohn et al. (2020) for the observed specification curve and for each curve under the null (resulting from infer_curve()), and tests how extreme the observed statistics are compared to their distribution under the null.

Usage

## S3 method for class 'specr.infer'
summary(
  object,
  direction = c("two.sided", "greater", "less"),
  alpha = 0.05,
  group = NULL,
  ...
)

Arguments

object

A specr.infer object, resulting from calling infer_curve().

direction

Direction of the alternative hypothesis. The default "two.sided" tests for an effect in either direction. Use "greater" or "less" only if the direction of the effect was predicted before the results were known.

alpha

Significance level that is used to count significant specifications. Defaults to .05.

group

Optional character vector with names of analytical choices (e.g., "y" or "subsets") to compute the test statistics separately within each group of specifications.

...

Further arguments passed to or from other methods (currently ignored).

Details

The three test statistics are:

median

The median estimate across all specifications.

share significant

The number of specifications with a significant estimate (p < alpha) in the tested direction: positive for "greater", negative for "less", and the more frequent (dominant) direction for "two.sided".

aggregated z

Stouffer's Z: each p-value is converted into a z-value with the sign of its estimate, and the sum of these z-values is divided by the square root of the number of specifications.

The p-value of each statistic is the share of curves under the null whose statistic is at least as extreme as the observed one, computed as (1 + number of curves at least as extreme) / (1 + number of bootstrap samples), so that it is never zero. For "two.sided", "at least as extreme" refers to the absolute value of the median and of Stouffer's Z, and to the number of significant specifications in the dominant direction of each curve. If the extraction function did not return p-values, only the median can be tested.

Value

A tibble with one row per test statistic (and group), including the observed estimate, the 2.5% and 97.5% quantiles of the statistic under the null (null_lower and null_upper), the p.value, and the number of specifications (n_specs).

References

See Also

infer_curve(), plot.specr.infer()

Examples

specs <- setup(data = example_data,
   y = "y1",
   x = c("x1", "x2"),
   model = "lm",
   controls = c("c1", "c2"))

results <- specr(specs)

set.seed(42)
inference <- infer_curve(results, specs, n_samples = 200) # better 1,000 or more

# Two-sided tests (default)
summary(inference)

# One-sided tests for a predicted positive effect
summary(inference, direction = "greater")

# Separately for each independent variable
summary(inference, group = "x")

Summarizing the Specification Curve Analysis

Description

summary method for class "specr.object". With type = "default", it provides a printed output including technical details (e.g., cores used, duration of the fitting process, number of specifications), a descriptive analysis of the overall specification curve, a descriptive summary of the resulting sample sizes, and a head of the results. With type = "curve", it returns descriptive statistics of the specification curve (overall or for groups of specifications).

Usage

## S3 method for class 'specr.object'
summary(
  object,
  type = "default",
  group = NULL,
  var = .data$estimate,
  stats = list(median = median, mad = mad, min = min, max = max, q25 = function(x)
    quantile(x, prob = 0.25), q75 = function(x) quantile(x, prob = 0.75)),
  digits = 2,
  rows = 6,
  ...
)

Arguments

object

An object of class "specr.object", usually resulting of a call to specr.

type

What should be summarized? Either "default" (printed summary of the whole analysis) or "curve" (tibble with descriptive statistics of the curve).

group

In combination with type = "curve", a character vector of one or more variables (e.g., "subsets", "controls",...) that denote the available analytic choices to group the summary of the estimate.

var

Unquoted name of the parameter to be summarized. Defaults to estimate.

stats

Named vector or named list of summary functions (individually defined summary functions can included). If it is not named, placeholders (e.g., "fn1") will be used as column names.

digits

The number of digits to use when printing the specification table.

rows

The number of rows of the specification tibble that should be printed.

...

further arguments passed to or from other methods (currently ignored).

Value

For type = "default", a printed summary of an object of class specr.object, which is returned invisibly. For type = "curve", a tibble with the descriptive statistics (and the median sample size obs, if available).

See Also

The function used to create the "specr.object" object: specr().

Examples

# Setup up specifications (returns object of class "specr.setup")
specs <- setup(data = example_data,
   y = c("y1", "y2"),
   x = c("x1", "x2"),
   model = "lm",
   controls = c("c1", "c2"),
   subsets = list(group1 = unique(example_data$group1)))

# Run analysis (returns object of class "specr.object")
results <- specr(specs)

# Default summary of the "specr.object"
summary(results)

# Summarize the specification curve descriptively
summary(results, type = "curve")

# Grouping for certain analytical decisions
summary(results,
       type = "curve",
       group = c("x", "y"))

# Using customized functions
summary(results,
        type = "curve",
       group = c("x", "group1"),
       stats = list(median = median,
                    min = min,
                    max = max))

Summarizing the Specifications Setup

Description

summary method for class "specr.setup". Provides a short summary of the created specifications (the "multiverse") that lists all analytic choices, prints the function used to extract the parameters from the model. Finally, if print.specs = TRUE, it also shows the head of the actual specification grid.

Usage

## S3 method for class 'specr.setup'
summary(object, digits = 2, rows = 6, print.specs = TRUE, ...)

Arguments

object

An object of class "specr.setup", usually, a result of a call to setup.

digits

The number of digits to use when printing the specification table.

rows

The number of rows of the specification tibble that should be printed.

print.specs

Logical value; if TRUE, the head of the specification tibble is printed.

...

further arguments passed to or from other methods (currently ignored).

Value

Prints a summary of an object of class specr.setup and returns the object invisibly.

See Also

The function setup(), which creates the "specr.setup" object.

Examples

# Setup specifications
specs <- setup(data = example_data,
  x = c("x1", "x2"),
  y = c("y1", "y2"),
  model = c("lm", "glm"),
  controls = c("c1", "c2", "c3"),
  subsets = list(group3 = unique(example_data$group3)))

# Summarize specifications
summary(specs)