diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000..e62bdbb --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,29 @@ +Package: MetaculR +Title: Analyze Metaculus Predictions and Questions +Version: 0.2.0 +Authors@R: + person(given = "Joseph de la Torre", + family = "Dwyer", + role = c("aut", "cre"), + email = "JosephD@BRdata.com", + comment = c(ORCID = "0000-0002-2717-9077")) +URL: https://ntrlshrp.gitlab.io/metaculr, + https://gitlab.com/ntrlshrp/metaculr +BugReports: https://gitlab.com/ntrlshrp/metaculr/-/issues +Description: Login, download, and analyze questions predicted by you and/or the + Metaculus community by interacting with the Metaculus API, currently + located at . +License: GPL-3 +Encoding: UTF-8 +RoxygenNote: 7.1.1 +Suggests: knitr, rmarkdown +VignetteBuilder: knitr +Imports: magrittr, dplyr, ggplot2, httr, jsonlite, progress, tidyr, + verification, stats +NeedsCompilation: no +Packaged: 2022-03-21 20:19:12 UTC; jtd +Author: Joseph de la Torre Dwyer [aut, cre] + () +Maintainer: Joseph de la Torre Dwyer +Repository: CRAN +Date/Publication: 2022-03-23 09:10:08 UTC diff --git a/MD5 b/MD5 new file mode 100644 index 0000000..0a6e893 --- /dev/null +++ b/MD5 @@ -0,0 +1,39 @@ +c7eb6e1f6102fb485cbefc70ba9faea4 *DESCRIPTION +abc0b7e2e39198047304d6eef4adbb71 *NAMESPACE +ea713468808c5593b19ea1b1e49271d5 *NEWS.md +739035306992ea4d20849bb91fa2ccd1 *R/basics.R +65cef5e0674056f6fc07dd2b3ca85c13 *R/utils-pipe.R +ffba6968739d8d14025a85e5a82e4386 *README.md +c1f87d51b4555a7f07cb51304efae4c7 *build/vignette.rds +eb065d12830ae93cf928b886fae64746 *inst/doc/MetaculR.Rmd +010745fdcec80613bfb4493c2813bccb *inst/doc/MetaculR.html +05c996fb466c5a8fff693a22b82dc9e7 *man/MetaculR_brier.Rd +8d21e69870b2fca59fa22cb5b708b50b *man/MetaculR_excitement.Rd +1abe71f8165d64e635e4705d7323f98b *man/MetaculR_login.Rd +64cea5ff02665bd49347a0f03a16255e *man/MetaculR_myDiff.Rd +e4cf8f749852e58e090e7ad2e05d2a75 *man/MetaculR_myPredictions.Rd +ffabb5a7a472581c2ab9f9aac0925080 *man/MetaculR_myPredictions_Resolved.Rd +4896445083921ec11932885b3e0621d6 *man/MetaculR_plot.Rd +082e06f15f440aacab88e00368196949 *man/MetaculR_questions.Rd +4894ca10756199e25f914bfd34f517b0 *man/pipe.Rd +eb065d12830ae93cf928b886fae64746 *vignettes/MetaculR.Rmd +13dd8116388c92090eef1630a03d2793 *vignettes/MetaculR.Rmd.orig +a083dafdedfe195ddc4735ebca4a11c2 *vignettes/MetaculRRMD_unnamed-chunk-10-1.png +72c1cac22c5f48e97050e705706d631b *vignettes/MetaculRRMD_unnamed-chunk-11-1.png +8a71507824584017854e530f2921f962 *vignettes/MetaculRRMD_unnamed-chunk-14-1.png +6d1fcca217ce43166579559e55d84e25 *vignettes/MetaculRRMD_unnamed-chunk-15-1.png +7a61ce0721540163fc418b730d3c2e58 *vignettes/MetaculRRMD_unnamed-chunk-16-1.png +280155f25e3e1930361a1a5617716129 *vignettes/MetaculRRMD_unnamed-chunk-18-1.png +5e11d3aa809efb9f394d4a5218816b90 *vignettes/MetaculRRMD_unnamed-chunk-19-1.png +45831d3308b4371107c467bb5fc04a89 *vignettes/MetaculRRMD_unnamed-chunk-20-1.png +c2c2151d99b08f04b581bed378af630e *vignettes/MetaculRRMD_unnamed-chunk-23-1.png +af4e193c946ad2e548651564d2f862ac *vignettes/MetaculRRMD_unnamed-chunk-24-1.png +86c93b4d19a9dd7a1d07ae7598b889e8 *vignettes/MetaculRRMD_unnamed-chunk-25-1.png +ae7dd7235e52386d0e99f1e2e9761a52 *vignettes/MetaculRRMD_unnamed-chunk-27-1.png +4ac8ff2f1378b4b9236b23f2e1cb2403 *vignettes/MetaculRRMD_unnamed-chunk-28-1.png +c64564072001a3c80520ef5f67511a54 *vignettes/MetaculRRMD_unnamed-chunk-29-1.png +e15ba1fecfd1208995f05f3d182596cf *vignettes/MetaculRRMD_unnamed-chunk-31-1.png +6b4fd57327337d811bafa472128c8581 *vignettes/MetaculRRMD_unnamed-chunk-33-1.png +f596ec96d2e103f01ab531f8fcb68610 *vignettes/MetaculRRMD_unnamed-chunk-35-1.png +6e1aaeaa8dec107fffcf7c609c70198d *vignettes/MetaculRRMD_unnamed-chunk-38-1.png +5db34fd049dca27a3799cdca1758b9dd *vignettes/MetaculRRMD_unnamed-chunk-8-1.png diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..69e03a2 --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,12 @@ +# Generated by roxygen2: do not edit by hand + +export("%>%") +export(MetaculR_brier) +export(MetaculR_excitement) +export(MetaculR_login) +export(MetaculR_myDiff) +export(MetaculR_myPredictions) +export(MetaculR_myPredictions_Resolved) +export(MetaculR_plot) +export(MetaculR_questions) +importFrom(magrittr,"%>%") diff --git a/NEWS.md b/NEWS.md new file mode 100644 index 0000000..0f33b63 --- /dev/null +++ b/NEWS.md @@ -0,0 +1,74 @@ + + + + +## 0.2.0 +2022-03-21 + +### Breaking changes + +#### **cran:** Update Description field; add examples (e3e2af6b5fa677c73abaaaf773b2bf60a8cfdd64) + +This commit changed functions with capital letters after the underscore to lowercase letters, e.g., + +- `MetaculR_Brier()` --> `MetaculR_brier()` +- `MetaculR_Questions()` --> `MetaculR_questions()` + +# MetaculR 0.1.1 +2022-03-21 + +## Fixes + +- **.rbuildignore:** Add some unnecessary `httptest` files (6ea3a4e8ee95b7e6a4e03a971ab0de1cadc4f84b) +- **news.md:** Added NEWS.md and added to Site (4fff8e9fc037e52f2e1ebf94df892cce23bc60a8) +- **cran-comments.md:** Added more NOTES after `rhub::check_for_cran()` (fb246d2ef7b32f426de64f15b61d9aa2353e36c7) +- **cran:** Add CRAN-RELEASE to .Rbuildignore (0c23c006da8d1b7ddc0edc225a621f6eec7ca9a2) +- **site:** Add Site URL to README; update MetaculR.Rmd (382c6e99cf30f4bf2d2ad02ee4a6827ae8aedff5) +- **functions:** Add return values description (f71805f9c9ea05944c999386f70babd39d68d8f6) +- **metaculr_login:** Add user_agent; trim empty final page (0700722137837bc06731090daa365cebd7235e81) +- **site:** Build vignette and site (9f641bc77034c8b1b240ed4240a9b03bb3e59f95) +- **.gitlab-ci.yml:** Remove extra `devtools::check()` jobs (8690e9d249104c8087be643e495ff208f0ca5f45) +- **cran:** Remove extra test environments and fixed NOTE (1f3f549f8b415334a383c403c581961f2245c0df) +- **.gitlab-ci.yml:** Install pandoc in jobs (5dc7e5a0dd7c236a9cefec020b005942b3ee5a8b) +- **news.md:** Use NEWS.md with automated semantic versioning (cb3a7c488984892d5afc0b7cca7e3a9e7c57f122) +- **news.md:** Add tag for automated semantic versioning (65923936e87598bf779d25a8342f647e3bcfec60) + +# MetaculR 0.1.0 +2022-03-11 + +## Features + +- Initialize project (da01a45c9e39e3bed9493658d78cd8236bcb65df) +- **site:** Add GitLab Pages to .gitlab-ci.yml (1b2f4c5fb056dc1f6d811b8b30c1e79dc40b133f) + +## Fixes + +- **site:** Remove `docs` from .gitignore (de31aa4ff16129d0a62653ad7d705a50988752b7) +- **.gitlab-ci.yml:** Installed devtools to run `devtools::check()` (bebaff5b67e12d6960cd85073922b886a7faa6bf) +- **.gitlab-ci.yml:** Remove `sudo` (ed26fca99eeb19b0d4a0b95e808169034b32eed1) +- **.gitlab-ci.yml:** Install dependencies (c5ca5e55aa713dc2b308e8334759295f2e22958c) +- **.gitlab-ci.yml:** Add rmarkdown to Check (b98b1594d4cdf5015acfaea90384474a34959aa0) +- **.rbuildignore:** Add go-semrel-gitlab files to be ignored (b6087d6c9eb6d47cdb55b565890e23e4397a6745) +- **news.md:** Use NEWS.md rather than CHANGELOG.md (025b2f66e51f9eb65a556ccac60c6a6259d25422) +- **site:** Update title, badges, pkgdown and bug links (751b45686a9141f7bed4f4e5a1f8a62062f07af1) +- **cran-comments:** Updated test images (d48d6e793cdf4a120425d4d74a9232acf9bcca82) +- **.gitlab-ci.yml:** Install dependencies differently (17d3d732643da3a9fa8ffb8325d8d5da83c6b3f8) +- **readme.md:** Update link to lifecyle definitions (77ed4502d940e8671600f9ca695d0ee7975d5fa5) +- **description:** Remove `LazyData: true` (e46f6e965a6339799936350b914830e58a8dbbda) +- **.gitlab-ci.yml:** Add `devtools::check_win_devel()` (c2fa1702db371c1a52033e0a44ac877289e3b177) +- **vignette:** Workaround to mock API calls (34b6f4318acd3a9de81d9705abc4d93dd733ac92) +- **site:** Build website with new vignette file (0efd3fd1871b88825d2b40db33e157859401207e) +- **man:** Updated roxygen notes for all functions (c2a604e204c54b2289a7cd8792dc8e9030c439aa) +- **cran-comments.md:** Added note about API authentication workaround (f7cf6035d07744c9bccf4c5288d092a9ade1ba6b) +- **.gitlab-ci.yml:** Add code coverage job (22dbd70cb89a69be01d70094f7f0901145935839) +- **.gitlab-ci.yml:** Update job dependency name (bc7c332a334a8b8789d9b125a94df47c73593822) +- **.gitlab-ci.yml:** Use `R` in script, not `Rscript` (e2b48bc9873a92908ee6fda4a51496679a7d3127) +- **.gitlab-ci.yml:** Add image to code coverage job (858c5d2da09a892f30890c2b4f425eec7fd9b700) +- **.gitlab-ci.yml:** Install 'covr' in job (11cd866348c86f7360a91e261d7f2e6b6be9a6fc) +- **.gitlab-ci.yml:** Add Debian packages needed for 'covr' (ccca15459245f7d1dc202df9c1b6be5e2a55189c) +- **.gitlab-ci.yml:** Add MetaculR dependencies to job (d041476db5dd9165b4ac2f4fd46c5d56f6e479b2) +- **.gitlab-ci.yml:** Add 'testthat' and 'devtools' to job (cf63056999a94abf0c1ae3fcb0ce6d522595579e) +- **.gitlab-ci.yml:** Use correct path, `/coverage` (2820435ae48c74190d16aac90b5882a28657759d) +- **site:** Updated with new function documentation (4b1a87911362328051de7389f52e85a93d11ea74) + + diff --git a/R/basics.R b/R/basics.R new file mode 100644 index 0000000..dd9373e --- /dev/null +++ b/R/basics.R @@ -0,0 +1,639 @@ +user_agent <- httr::user_agent("https://gitlab.com/ntrlshrp/metaculr") + +#' Retrieve questions from Metaculus API +#' +#' @param api_domain Use "www" unless you have a custom Metaculus domain +#' @param order_by Choose "last_prediction_time", "-activity", "-votes", "-publish_time", "close_time", "resolve_time", "last_prediction_time" +#' @param status Choose "all", "upcoming", "open", "closed", "resolved" +#' @param search Search term(s) +#' @param guessed_by Generally your Metaculus_user_id +#' @param offset Question offset +#' @param pages Number of pages to request +#' +#' @return A list of questions, ordered by last prediction time. +#' @export +#' @family Question Retrieval functions +#' +#' @examples +#' \dontrun{ +#' questions_recent_open <- +#' MetaculR_questions( +#' order_by = "close_time", +#' status = "open", +#' guessed_by = "") +#' } + +MetaculR_questions <- function(api_domain = "www", order_by = "last_prediction_time", status = "all", search = "", guessed_by = "", offset = 0, pages = 10) { + pb <- progress::progress_bar$new( + format = " downloading [:bar] :percent eta: :eta", + total = pages - 1, clear = FALSE, width= 60) + pb$tick(0) + #for (i in 1:100) { + + #} + + endpoint <- paste0("https://", api_domain, ".metaculus.com/api2/questions/?") + extra <- paste0("order_by=", order_by, "&status=", status, "&search=", search, "&guessed_by=", guessed_by, "&limit=20&offset=", offset) + + endpoint <- paste0(endpoint, extra) + message(endpoint) + + get <- httr::GET(url = endpoint, user_agent) + data = jsonlite::fromJSON(rawToChar(get$content)) + data_all <- list(data) + + page <- 1 + offset_base <- 20 + + while(length(data$results$id) == 20) { + pb$tick() + Sys.sleep(0.5) + #print(paste0(page, " ")) + + endpoint <- paste0("https://", api_domain, ".metaculus.com/api2/questions/?") + extra <- paste0("order_by=", order_by, "&status=", status, "&search=", search, "&guessed_by=", guessed_by, "&limit=20&offset=", offset + offset_base) + + endpoint <- paste0(endpoint, extra) + + get <- httr::GET(url = endpoint, user_agent) + data <- jsonlite::fromJSON(rawToChar(get$content)) + if(length(data$results) == 0) break + data_all <- append(data_all, list(data)) + + page <- page + 1 + offset_base <- page * 20 + + if(page == pages) break + } + + return(data_all) +} + + + + + +#' Retrieve questions from Metaculus API (A wrapper for MetaculR_questions()) +#' +#' @param api_domain Use "www" unless you have a custom Metaculus domain +#' @param order_by Default is "last_prediction_time" +#' @param status Choose "all", "upcoming", "open", "closed", "resolved" +#' @param search Search term(s) +#' @param guessed_by Generally your Metaculus_user_id +#' @param offset Question offset +#' @param pages Number of pages to request +#' +#' @return A list of questions that I've predicted, ordered by last prediction time. +#' @export +#' @family Question Retrieval functions +#' +#' @examples +#' \dontrun{ +#' questions_myPredictions <- +#' MetaculR_myPredictions( +#' guessed_by = Metaculus_user_id) +#' } + +MetaculR_myPredictions <- function(api_domain = "www", order_by = "last_prediction_time", status = "all", search = "", guessed_by = "", offset = 0, pages = 10) { + data_all <- MetaculR_questions(api_domain = api_domain, order_by = order_by, status = status, search = search, guessed_by = guessed_by, offset = offset, pages = pages) + + return(data_all) +} + + + + + +#' Retrieve questions from Metaculus API (A wrapper for MetaculR_questions()) +#' +#' @param api_domain Use "www" unless you have a custom Metaculus domain +#' @param order_by Default is "-resolve_time" +#' @param status Default is "resolved" +#' @param search Search term(s) +#' @param guessed_by Generally your Metaculus_user_id +#' @param offset Question offset +#' @param pages Number of pages to request +#' +#' @return A list of questions that I've predicted, ordered by last prediction time, and resolved. +#' @export +#' @family Question Retrieval functions +#' +#' @examples +#' \dontrun{ +#' questions_myPredictions_resolved <- +#' MetaculR_myPredictions_Resolved( +#' guessed_by = Metaculus_user_id) +#' } + +MetaculR_myPredictions_Resolved <- function(api_domain = "www", order_by = "-resolve_time", status = "resolved", search = "", guessed_by = "", offset = 0, pages = 10) { + data_all <- MetaculR_questions(api_domain = "www", order_by = order_by, status = status, search = "", guessed_by = guessed_by, offset = offset, pages = pages) + + return(data_all) +} + + + + + +#' Login to Metaculus +#' +#' @param api_domain Use "www" unless you have a custom Metaculus domain +#' +#' @return Your Metaculus_user_ID. +#' @export +#' +#' @examples +#' \dontrun{ +#' Metaculus_user_id <- +#' MetaculR_login() +#' } + +MetaculR_login <- function(api_domain = "www") { + if(Sys.getenv("Metaculus_username") == "") { + stop("No username in .Renviron!") + } + + endpoint <- paste0("https://", api_domain, ".metaculus.com/api2/accounts/login/") + + response <- httr::POST(url = endpoint, + httr::accept_json(), + httr::content_type_json(), + body = jsonlite::toJSON(list(username = Sys.getenv("Metaculus_username"), password = Sys.getenv("Metaculus_password")), + auto_unbox = TRUE), + encode = "json") + + return(jsonlite::fromJSON(rawToChar(response$content))) +} + + + + + +#' Calculate Brier statistics on MetaculR_questions object +#' +#' @param MetaculR_questions A MetaculR_questions object +#' @param me Show my scores alongside Metaculus scores +#' @param thresholds Thresholds to bin questions +#' +#' @return A list of Brier statistics for you and Metaculus. +#' \item{brier_me, brier_Metaculus}{} +#' \item{baseline.tf}{Logical indicator of whether climatology was provided.} +#' \item{bs}{Brier score} +#' \item{bs.baseline}{Brier Score for climatology} +#' \item{ss}{Skill score} +#' \item{bs.reliability}{Reliability portion of Brier score.} +#' \item{bs.resolution}{Resolution component of Brier score.} +#' \item{bs.uncert}{Uncertainty component of Brier score.} +#' \item{y.i}{Forecast bins -- described as the center value of the bins.} +#' \item{obar.i}{Observation bins -- described as the center value of the bins.} +#' \item{prob.y}{Proportion of time using each forecast.} +#' \item{obar}{Forecast based on climatology or average sample observations.} +#' \item{thresholds}{The thresholds for the forecast bins.} +#' \item{check}{ Reliability - resolution + uncertainty should equal brier score.} +#' \item{Other}{} +#' \item{ss_me_Metaculus}{Skill score, me vs. Metaculus.} +#' \item{count_questions}{Number of total questions included.} +#' \item{brier_df: Used for plotting Brier score statistics}{} +#' \item{ID}{Predictor.} +#' \item{name}{Name of value, see above.} +#' \item{value}{Value.} +#' \item{brier_bins_df: Used for plotting histogram and calibration plots.}{} +#' \item{ID}{Predictor.} +#' \item{centers}{y.i, see above.} +#' \item{freqs}{prob.y, see above.} +#' \item{obars}{obar.i, see above.} +#' \item{ideal}{Ideal calibration where centers equals obars.} +#' \item{ci_low}{Low end of 95% confidence interval for obar.i.} +#' \item{ci_high}{High end of 95% confidence interval for obar.i.} +#' @export +#' +#' @examples +#' \dontrun{ +#' brier_me <- +#' MetaculR_brier( +#' questions_myPredictions_resolved) +#' } + +MetaculR_brier <- function(MetaculR_questions, me = TRUE, thresholds = seq(0,1,0.1)) { + ## no visible binding for global variable solution + ID <- NULL + + my_predictions <- unlist(lapply(MetaculR_questions, function(x) if(is.data.frame(x$results$my_predictions)) {lapply(x$results$my_predictions$predictions[which(x$results$possibilities$type == "binary" & !is.na(x$results$resolution) & x$results$resolution != -1 & unlist(lapply(x$results$metaculus_prediction$full, function(z) !is.null(z))))], function(f) f$x[length(f$x)])})) + + if(is.null(my_predictions) | + me == FALSE) { + binary_questions <- data.frame( + id = unlist(lapply(MetaculR_questions, function(x) x$results$id[which(x$results$possibilities$type == "binary" & !is.na(x$results$resolution) & x$results$resolution != -1 & unlist(lapply(x$results$metaculus_prediction$full, function(z) !is.null(z))))])), + observed = unlist(lapply(MetaculR_questions, function(x) x$results$resolution[which(x$results$possibilities$type == "binary" & !is.na(x$results$resolution) & x$results$resolution != -1 & unlist(lapply(x$results$metaculus_prediction$full, function(z) !is.null(z))))])), + metaculus_prediction = unlist(lapply(MetaculR_questions, function(x) x$results$metaculus_prediction$full[which(x$results$possibilities$type == "binary" & !is.na(x$results$resolution) & x$results$resolution != -1 & unlist(lapply(x$results$metaculus_prediction$full, function(z) !is.null(z))))])) + ) + + brier_me <- NULL + brier_Metaculus <- + verification::brier( + obs = binary_questions$observed, + pred = binary_questions$metaculus_prediction, + thresholds = thresholds) ### c(0, exp(seq(from = -4.59512, to = 4.59512, by = 0.919024)) / (exp(seq(from = -4.59512, to = 4.59512, by = 0.919024)) + 1), 1) + ss_me_Metaculus <- NULL + + brier_df <- + data.frame(ID = c("Me", "Metaculus", "NA"), + bs = c(NA, brier_Metaculus$bs, NA), + bs.baseline = c(NA, brier_Metaculus$bs.baseline, NA), + bs.reliability = c(NA, brier_Metaculus$bs.reliability, NA), + bs.resolution = c(NA, brier_Metaculus$bs.resol, NA), + bs.uncertainty = c(NA, brier_Metaculus$bs.uncert, NA), + skill_baseline = c(NA, brier_Metaculus$ss, NA), + obar = c(NA, NA, brier_Metaculus$obar), + skill_me_Metaculus = c(NA, NA, NA)) %>% + tidyr::pivot_longer(cols = -ID) + + bins_df <- data.frame(x = round(brier_Metaculus$obar.i * brier_Metaculus$prob.y * nrow(binary_questions), 0), + n = round(brier_Metaculus$prob.y * nrow(binary_questions), 0)) + + df_binom.test <- apply(bins_df[which(!is.na(bins_df$x)), ], + MARGIN = 1, + FUN = function(z) stats::binom.test(z[1], z[2])) + + brier_bins_df <- + data.frame(centers = brier_Metaculus$y.i[which(!is.na(bins_df$x))], + freqs = brier_Metaculus$prob.y[which(!is.na(bins_df$x))], + obars = brier_Metaculus$obar.i[which(!is.na(bins_df$x))], + ideal = brier_Metaculus$y.i[which(!is.na(bins_df$x))], + ci_low = unlist(lapply(df_binom.test, function(x) x$conf.int[1])), + ci_high = unlist(lapply(df_binom.test, function(x) x$conf.int[2]))) + } else { + binary_questions <- data.frame( + id = unlist(lapply(MetaculR_questions, function(x) x$results$id[which(x$results$possibilities$type == "binary" & !is.na(x$results$resolution) & x$results$resolution != -1 & unlist(lapply(x$results$metaculus_prediction$full, function(z) !is.null(z))))])), + observed = unlist(lapply(MetaculR_questions, function(x) x$results$resolution[which(x$results$possibilities$type == "binary" & !is.na(x$results$resolution) & x$results$resolution != -1 & unlist(lapply(x$results$metaculus_prediction$full, function(z) !is.null(z))))])), + metaculus_prediction = unlist(lapply(MetaculR_questions, function(x) x$results$metaculus_prediction$full[which(x$results$possibilities$type == "binary" & !is.na(x$results$resolution) & x$results$resolution != -1 & unlist(lapply(x$results$metaculus_prediction$full, function(z) !is.null(z))))])) + ) + + binary_questions_me <- data.frame( + id = unlist(lapply(MetaculR_questions, function(x) if(is.data.frame(x$results$my_predictions)) {x$results$id[which(x$results$possibilities$type == "binary" & !is.na(x$results$resolution) & x$results$resolution != -1 & !is.na(x$results$my_predictions$question) & unlist(lapply(x$results$metaculus_prediction$full, function(z) !is.null(z))))]})), + my_prediction = my_predictions + ) + + binary_questions <- merge(binary_questions, + binary_questions_me) + + brier_me <- + verification::brier( + obs = binary_questions$observed, + pred = binary_questions$my_prediction, + thresholds = thresholds) ### c(0, exp(seq(from = -4.59512, to = 4.59512, by = 0.919024)) / (exp(seq(from = -4.59512, to = 4.59512, by = 0.919024)) + 1), 1) + brier_Metaculus <- + verification::brier( + obs = binary_questions$observed, + pred = binary_questions$metaculus_prediction, + thresholds = thresholds) ### c(0, exp(seq(from = -4.59512, to = 4.59512, by = 0.919024)) / (exp(seq(from = -4.59512, to = 4.59512, by = 0.919024)) + 1), 1) + + brier_df <- + data.frame(ID = c("Me", "Metaculus", "NA"), + bs = c(brier_me$bs, brier_Metaculus$bs, NA), + bs.baseline = c(brier_me$bs.baseline, brier_Metaculus$bs.baseline, NA), + bs.reliability = c(brier_me$bs.reliability, brier_Metaculus$bs.reliability, NA), + bs.resolution = c(brier_me$bs.resol, brier_Metaculus$bs.resol, NA), + bs.uncertainty = c(brier_me$bs.uncert, brier_Metaculus$bs.uncert, NA), + skill_baseline = c(brier_me$ss, brier_Metaculus$ss, NA), + obar = c(NA, NA, brier_me$obar), + skill_me_Metaculus = c(NA, NA, 1 - brier_me$bs / brier_Metaculus$bs)) %>% + tidyr::pivot_longer(cols = -ID) + + bins_df <- data.frame(x = round(brier_me$obar.i * brier_me$prob.y * nrow(binary_questions), 0), + n = round(brier_me$prob.y * nrow(binary_questions), 0)) + + df_binom.test <- apply(bins_df[which(!is.na(bins_df$x)), ], + MARGIN = 1, + FUN = function(z) stats::binom.test(z[1], z[2])) + + brier_me_bins_df <- + data.frame(ID = "Me", + centers = brier_me$y.i[which(!is.na(bins_df$x))], + freqs = brier_me$prob.y[which(!is.na(bins_df$x))], + obars = brier_me$obar.i[which(!is.na(bins_df$x))], + ideal = brier_me$y.i[which(!is.na(bins_df$x))], + ci_low = unlist(lapply(df_binom.test, function(x) x$conf.int[1])), + ci_high = unlist(lapply(df_binom.test, function(x) x$conf.int[2]))) + + bins_df <- data.frame(x = round(brier_Metaculus$obar.i * brier_Metaculus$prob.y * nrow(binary_questions), 0), + n = round(brier_Metaculus$prob.y * nrow(binary_questions), 0)) + + df_binom.test <- apply(bins_df[which(!is.na(bins_df$x)), ], + MARGIN = 1, + FUN = function(z) stats::binom.test(z[1], z[2])) + + brier_Metaculus_bins_df <- + data.frame(ID = "Metaculus", + centers = brier_Metaculus$y.i[which(!is.na(bins_df$x))], + freqs = brier_Metaculus$prob.y[which(!is.na(bins_df$x))], + obars = brier_Metaculus$obar.i[which(!is.na(bins_df$x))], + ideal = brier_Metaculus$y.i[which(!is.na(bins_df$x))], + ci_low = unlist(lapply(df_binom.test, function(x) x$conf.int[1])), + ci_high = unlist(lapply(df_binom.test, function(x) x$conf.int[2]))) + + brier_bins_df <- rbind(brier_me_bins_df, + brier_Metaculus_bins_df) + } + + results <- list(brier_me = brier_me, + brier_Metaculus = brier_Metaculus, + ss_me_Metaculus = 1 - brier_me$bs / brier_Metaculus$bs, + count_questions = nrow(binary_questions), + brier_df = brier_df, + brier_bins_df = brier_bins_df) + + return(results) +} + + + + + +#' Find important changes within MetaculR_questions object +#' +#' @param MetaculR_questions A MetaculR_questions object +#' +#' @return A dataframe of questions with difference measures (your most recent prediction vs. community's most recent prediction, etc.). +#' \item{id}{Question ID.} +#' \item{title}{Question title.} +#' \item{my_prediction}{My most recent prediction.} +#' \item{community_q2}{Community median.} +#' \item{community_ave}{Community average.} +#' \item{community_q2_pre_me}{Community median immediately prior to my_prediction.} +#' \item{community_ave_pre_me}{Community average immediately prior to my_prediction.} +#' \item{diff_me_q2}{Difference between me and the community median, by logodds.} +#' \item{diff_me_ave}{Difference between me and the community average, by logodds.} +#' \item{diff_comm_q2_pre_me}{Difference between community_q2_pre_me and the community average, by logodds.} +#' \item{diff_comm_ave_pre_me}{Difference between community_ave_pre_me and the community average, by logodds.} +#' \item{diff_me_q2_abs}{Absolute difference between me and the community median, by logodds.} +#' \item{diff_me_ave_abs}{Absolute difference between me and the community average, by logodds.} +#' \item{diff_comm_q2_pre_me_abs}{Absolute difference between community_q2_pre_me and the community average, by logodds.} +#' \item{diff_comm_ave_pre_me_abs}{Absolute difference between community_ave_pre_me and the community average, by logodds.} +#' \item{diff_me_q2_abs_odds}{Absolute difference between me and the community median, by odds.} +#' \item{diff_me_ave_abs_odds}{Absolute difference between me and the community average, by odds.} +#' \item{diff_comm_q2_pre_me_abs_odds}{Absolute difference between community_q2_pre_me and the community average, by odds.} +#' \item{diff_comm_ave_pre_me_abs_odds}{Absolute difference between community_ave_pre_me and the community average, by odds.} +#' @export +#' +#' @examples +#' \dontrun{ +#' questions_myPredictions_byDiff <- +#' MetaculR_myDiff( +#' questions_myPredictions) +#' } + +MetaculR_myDiff <- function(MetaculR_questions) { + ## no visible binding for global variable solution + my_prediction <- community_q2 <- community_ave <- community_q2_pre_me <- community_ave_pre_me <- diff_me_q2 <- diff_me_ave <- diff_comm_q2_pre_me <- diff_comm_ave_pre_me <- diff_me_q2_abs <- NULL + + loop_results <- data.frame() + for(l in 1:length(MetaculR_questions)) { + if(is.data.frame(MetaculR_questions[[l]]$results$my_predictions)) { + for(el in which(MetaculR_questions[[l]]$results$possibilities$type == "binary" & is.na(MetaculR_questions[[l]]$results$resolution) & !is.na(MetaculR_questions[[l]]$results$community_prediction$full$q2))) { + loop_results <- + rbind( + loop_results, + data.frame( + community_q2_pre_me = MetaculR_questions[[l]]$results$community_prediction$history[[el]]$x1$q2[max(which(MetaculR_questions[[l]]$results$community_prediction$history[[el]]$t <= MetaculR_questions[[l]]$results$my_predictions$predictions[[el]]$t))], + community_ave_pre_me = MetaculR_questions[[l]]$results$community_prediction$history[[el]]$x2$avg[max(which(MetaculR_questions[[l]]$results$community_prediction$history[[el]]$t <= MetaculR_questions[[l]]$results$my_predictions$predictions[[el]]$t))] ###, + # community_t_pre_me = MetaculR_questions[[l]]$results$community_prediction$history[[el]]$t[max(which(MetaculR_questions[[l]]$results$community_prediction$history[[el]]$t <= MetaculR_questions[[l]]$results$my_predictions$predictions[[el]]$t))] + )) + }}} + + binary_questions <- data.frame( + id = unlist(lapply(MetaculR_questions, function(x) if(is.data.frame(x$results$my_predictions)) {x$results$id[which(x$results$possibilities$type == "binary" & is.na(x$results$resolution) & !is.na(x$results$community_prediction$full$q2))]})), + title = unlist(lapply(MetaculR_questions, function(x) if(is.data.frame(x$results$my_predictions)) {x$results$title[which(x$results$possibilities$type == "binary" & is.na(x$results$resolution) & !is.na(x$results$community_prediction$full$q2))]})), + my_prediction = unlist(lapply(MetaculR_questions, function(x) if(is.data.frame(x$results$my_predictions)) {lapply(x$results$my_predictions$predictions[which(x$results$possibilities$type == "binary" & is.na(x$results$resolution) & !is.na(x$results$community_prediction$full$q2))], function(f) f$x[length(f$x)])})), + community_q2 = unlist(lapply(MetaculR_questions, function(x) if(is.data.frame(x$results$my_predictions)) {x$results$community_prediction$full$q2[which(x$results$possibilities$type == "binary" & is.na(x$results$resolution) & !is.na(x$results$community_prediction$full$q2))]})), + community_ave = unlist(lapply(MetaculR_questions, function(x) if(is.data.frame(x$results$my_predictions)) {lapply(x$results$community_prediction$history[which(x$results$possibilities$type == "binary" & is.na(x$results$resolution) & !is.na(x$results$community_prediction$full$q2))], function(f) f$x2$avg[length(f$x2$avg)])})) + ) %>% + cbind(loop_results) %>% + dplyr::mutate(diff_me_q2 = log(my_prediction / (1 - my_prediction)) - log(community_q2 / (1 - community_q2)), + diff_me_ave = log(my_prediction / (1 - my_prediction)) - log(community_ave / (1 - community_ave)), + diff_comm_q2_pre_me = log(community_q2 / (1 - community_q2)) - log(community_q2_pre_me / (1 - community_q2_pre_me)), + diff_comm_ave_pre_me = log(community_ave / (1 - community_ave)) - log(community_ave_pre_me / (1 - community_ave_pre_me))) %>% + dplyr::mutate(diff_me_q2_abs = abs(diff_me_q2), + diff_me_ave_abs = abs(diff_me_ave), + diff_comm_q2_pre_me_abs = abs(diff_comm_q2_pre_me), + diff_comm_ave_pre_me_abs = abs(diff_comm_ave_pre_me), + diff_me_q2_abs_odds = exp(abs(diff_me_q2)), + diff_me_ave_abs_odds = exp(abs(diff_me_ave)), + diff_comm_q2_pre_me_abs_odds = exp(abs(diff_comm_q2_pre_me)), + diff_comm_ave_pre_me_abs_odds = exp(abs(diff_comm_ave_pre_me))) %>% + dplyr::arrange(dplyr::desc(diff_me_q2_abs)) +} + + + + + +#' Plot the history of a single question +#' +#' @param MetaculR_questions A MetaculR_questions object +#' @param Metacular_id The ID of the question to plot +#' @param scale_binary Choose "prob", "odds", or "logodds" +#' +#' @return A ggplot. +#' @export +#' +#' @examples +#' \dontrun{ +#' MetaculR_plot( +#' MetaculR_questions = questions_myPredictions, +#' Metacular_id = 10004) +#' } + +MetaculR_plot <- function(MetaculR_questions, Metacular_id, scale_binary = "prob") { + ## no visible binding for global variable solution + Date <- q1 <- q2 <- q3 <- x <- community_q2_pre_me <- community_ave_pre_me <- NULL + + community <- data.frame( + cbind(Date = as.POSIXct(unlist(lapply(MetaculR_questions, function(x) if(TRUE) {lapply(x$results$community_prediction$history[which(x$results$id == Metacular_id)], function(f) f$t)})), origin = "1970-01-01 00:00.00 UTC"), + q1 = unlist(lapply(MetaculR_questions, function(x) if(TRUE) {lapply(x$results$community_prediction$history[which(x$results$id == Metacular_id)], function(f) f$x1$q1)})), + q2 = unlist(lapply(MetaculR_questions, function(x) if(TRUE) {lapply(x$results$community_prediction$history[which(x$results$id == Metacular_id)], function(f) f$x1$q2)})), + q3 = unlist(lapply(MetaculR_questions, function(x) if(TRUE) {lapply(x$results$community_prediction$history[which(x$results$id == Metacular_id)], function(f) f$x1$q3)}))) + ) %>% + dplyr::mutate(Date = as.POSIXct(Date, origin = "1970-01-01 00:00.00 UTC")) + + if(is.null(unlist(lapply(MetaculR_questions, function(x) if(is.data.frame(x$results$my_predictions)) {lapply(x$results$my_predictions$predictions[which(x$results$id == Metacular_id)], function(f) f$t)})))) { + me_predict <- FALSE + } else { + me_predict <- TRUE + } + + if(me_predict == TRUE) { + me <- data.frame( + cbind(Date = as.POSIXct(unlist(lapply(MetaculR_questions, function(x) if(is.data.frame(x$results$my_predictions)) {lapply(x$results$my_predictions$predictions[which(x$results$id == Metacular_id)], function(f) f$t)})), origin = "1970-01-01 00:00.00 UTC"), + x = unlist(lapply(MetaculR_questions, function(x) if(is.data.frame(x$results$my_predictions)) {lapply(x$results$my_predictions$predictions[which(x$results$id == Metacular_id)], function(f) f$x)}))) + ) %>% + dplyr::mutate(Date = as.POSIXct(Date, origin = "1970-01-01 00:00.00 UTC")) + + loop_results <- data.frame() + for(l in 1:length(MetaculR_questions)) { + if(is.data.frame(MetaculR_questions[[l]]$results$my_predictions)) { + for(el in which(MetaculR_questions[[l]]$results$id == Metacular_id)) { + loop_results <- + rbind( + loop_results, + data.frame( + community_q2_pre_me = MetaculR_questions[[l]]$results$community_prediction$history[[el]]$x1$q2[max(which(MetaculR_questions[[l]]$results$community_prediction$history[[el]]$t <= MetaculR_questions[[l]]$results$my_predictions$predictions[[el]]$t[length(MetaculR_questions[[l]]$results$my_predictions$predictions[[el]]$t)]))], + community_ave_pre_me = MetaculR_questions[[l]]$results$community_prediction$history[[el]]$x2$avg[max(which(MetaculR_questions[[l]]$results$community_prediction$history[[el]]$t <= MetaculR_questions[[l]]$results$my_predictions$predictions[[el]]$t[length(MetaculR_questions[[l]]$results$my_predictions$predictions[[el]]$t)]))], + Date = MetaculR_questions[[l]]$results$community_prediction$history[[el]]$t[max(which(MetaculR_questions[[l]]$results$community_prediction$history[[el]]$t <= MetaculR_questions[[l]]$results$my_predictions$predictions[[el]]$t[length(MetaculR_questions[[l]]$results$my_predictions$predictions[[el]]$t)]))] + )) %>% + dplyr::mutate(Date = as.POSIXct(Date, origin = "1970-01-01 00:00.00 UTC")) + }}} + + diff_comm_q2_pre_me_abs_odds <- + round(exp(abs(log(community$q2[length(community$q2)] / (1 - community$q2[length(community$q2)])) - log(loop_results$community_q2_pre_me / (1 - loop_results$community_q2_pre_me)))), 2) + diff_me_q2_abs_odds <- + round(exp(abs(log(community$q2[length(community$q2)] / (1 - community$q2[length(community$q2)])) - log(me$x[length(me$x)] / (1 - me$x[length(me$x)])))), 2) + } + + ylim <- c(0, 1) + + if(scale_binary == "odds") { + community <- community %>% + dplyr::mutate(q1 = ifelse(q1 >= 0.5, + q1 / (1- q1), + -(1 - q1) / q1), + q2 = ifelse(q2 >= 0.5, + q2 / (1- q2), + -(1 - q2) / q2), + q3 = ifelse(q3 >= 0.5, + q3 / (1- q3), + -(1 - q3) / q3)) + + if(me_predict == TRUE) { + me <- me %>% + dplyr::mutate(x = ifelse(x >= 0.5, + x / (1 - x), + -(1 - x) / x)) + + loop_results <- loop_results %>% + dplyr::mutate(community_q2_pre_me = ifelse(community_q2_pre_me >= 0.5, + community_q2_pre_me / (1 - community_q2_pre_me), + -(1 - community_q2_pre_me) / community_q2_pre_me), + community_ave_pre_me = ifelse(community_ave_pre_me >= 0.5, + community_ave_pre_me / (1 - community_ave_pre_me), + -(1 - community_ave_pre_me) / community_ave_pre_me)) + } + + ylim <- c(-99, 99) + } + if(scale_binary == "logodds") { + community <- community %>% + dplyr::mutate(q1 = log(q1 / (1 - q1)), + q2 = log(q2 / (1 - q2)), + q3 = log(q3 / (1 - q3))) + + if(me_predict == TRUE) { + me <- me %>% + dplyr::mutate(x = log(x / (1 - x))) + + loop_results <- loop_results %>% + dplyr::mutate(community_q2_pre_me = log(community_q2_pre_me / (1 - community_q2_pre_me)), + community_ave_pre_me = log(community_ave_pre_me / (1 - community_ave_pre_me))) + } + + + ylim <- c(log(1 / 99), log(99)) + } + + gg <- community %>% + ggplot2::ggplot() + + ggplot2::geom_line( + ggplot2::aes(x = Date, + y = q2) + ) + + ggplot2::geom_ribbon( + ggplot2::aes(x = Date, + ymin = q1, + ymax = q3), + alpha = 0.1) + + if(me_predict == TRUE) { + gg <- gg + + ggplot2::geom_point( + data = me, + ggplot2::aes(x = Date, + y = x), + shape = 21 + ) + + ggplot2::geom_point( + data = loop_results, + ggplot2::aes(x = Date, + y = community_q2_pre_me), + shape = 21, + fill = "black" + ) + + ggplot2::geom_segment( + ggplot2::aes(x = loop_results$Date, + y = loop_results$community_q2_pre_me, + xend = loop_results$Date, + yend = q2[length(q2)], + color = "red")) + + ggplot2::annotate("text", + x = loop_results$Date, + y = community$q2[length(community$q2)], + label = paste0("Odds diff: ", diff_comm_q2_pre_me_abs_odds), + size = 3) + + ggplot2::geom_segment( + ggplot2::aes(x = Date[length(Date)], + y = q2[length(q2)], + xend = Date[length(Date)], + yend = me$x[length(me$x)], + color = "red")) + + ggplot2::annotate("text", + x = me$Date[length(me$Date)], ###community$Date[length(community$Date)], + y = me$x[length(me$x)] - (ylim[2] - ylim[1]) * 0.04, + label = paste0("Odds diff: ", diff_me_q2_abs_odds), + size = 3) + } + + gg + + ggplot2::theme_classic() + + ggplot2::coord_cartesian( + ylim = ylim + ) + + ggplot2::ggtitle(label = paste0(Metacular_id, ": ", unlist(lapply(MetaculR_questions, function(x) if(TRUE) {x$results$title[which(x$results$id == Metacular_id)]})))) + + ggplot2::labs(y = "Community prediction") + + ggplot2::guides(color = FALSE) +} + + + + + +#' Find exciting questions +#' +#' @param MetaculR_questions A MetaculR_questions object +#' +#' @return A dataframe of questions with excitement measures. +#' \item{id}{Question ID.} +#' \item{title}{Question title.} +#' \item{Total_Change}{Cumulative delta in time period, by probability.} +#' \item{Total_logodds_Change}{Cumulative delta in time period, by logodds.} +#' \item{Total_Change_Even}{Cumulative delta toward even odds in time period, by probability.} +#' \item{Total_logodds_Change_Even}{Cumulative delta toward even odds in time period, by logodds.} +#' @export +#' +#' @examples +#' \dontrun{ +#' questions_myPredictions_byExcitement <- +#' MetaculR_excitement( +#' questions_myPredictions) +#' } + +MetaculR_excitement <- function(MetaculR_questions) { + ## no visible binding for global variable solution + x1 <- Date <- q2_delta <- q2_logodds_delta <- q2_delta_even <- q2_logodds_delta_even <- NULL + + binary_questions <- data.frame( + id = unlist(lapply(MetaculR_questions, function(x) if(TRUE) {x$results$id[which(x$results$possibilities$type == "binary" & as.Date(x$results$close_time) >= as.Date(Sys.time()) - 30 & unlist(lapply(x$results$community_prediction$history, function(z) nrow(z) > 0)))]})), + title = unlist(lapply(MetaculR_questions, function(x) if(TRUE) {x$results$title[which(x$results$possibilities$type == "binary" & as.Date(x$results$close_time) >= as.Date(Sys.time()) - 30 & unlist(lapply(x$results$community_prediction$history, function(z) nrow(z) > 0)))]})), + Total_Change = unlist(lapply(MetaculR_questions, function(x) lapply(x$results$community_prediction$history[which(x$results$possibilities$type == "binary" & as.Date(x$results$close_time) >= as.Date(Sys.time()) - 30)], function(z) if(nrow(z) > 0) {z %>% dplyr::mutate(Date = as.POSIXct(t, origin = "1970-01-01 00:00.00 UTC"), q2_delta = x1$q2 - dplyr::lag(x1$q2)) %>% dplyr::filter(as.Date(Date) >= as.Date(Sys.time()) - 30) %>% dplyr::summarize(Total_Change = sum(abs(q2_delta)))}))), + Total_logodds_Change = unlist(lapply(MetaculR_questions, function(x) lapply(x$results$community_prediction$history[which(x$results$possibilities$type == "binary" & as.Date(x$results$close_time) >= as.Date(Sys.time()) - 30)], function(z) if(nrow(z) > 0) {z %>% dplyr::mutate(Date = as.POSIXct(t, origin = "1970-01-01 00:00.00 UTC"), q2_logodds_delta = log(x1$q2 / (1 - x1$q2)) - log(dplyr::lag(x1$q2) / (1 - dplyr::lag(x1$q2)))) %>% dplyr::filter(as.Date(Date) >= as.Date(Sys.time()) - 30) %>% dplyr::summarize(Total_logodds_Change = sum(abs(q2_logodds_delta)))}))), + Total_Change_Even = unlist(lapply(MetaculR_questions, function(x) lapply(x$results$community_prediction$history[which(x$results$possibilities$type == "binary" & as.Date(x$results$close_time) >= as.Date(Sys.time()) - 30)], function(z) if(nrow(z) > 0) {z %>% dplyr::mutate(Date = as.POSIXct(t, origin = "1970-01-01 00:00.00 UTC"), q2_delta_even = ifelse(x1$q2 > 0.5 & x1$q2 - dplyr::lag(x1$q2) < 0, x1$q2 - dplyr::lag(x1$q2), ifelse(x1$q2 < 0.5 & x1$q2 - dplyr::lag(x1$q2) > 0, x1$q2 - dplyr::lag(x1$q2), 0))) %>% dplyr::filter(as.Date(Date) >= as.Date(Sys.time()) - 30) %>% dplyr::summarize(Total_Change_Even = sum(abs(q2_delta_even)))}))), + Total_logodds_Change_Even = unlist(lapply(MetaculR_questions, function(x) lapply(x$results$community_prediction$history[which(x$results$possibilities$type == "binary" & as.Date(x$results$close_time) >= as.Date(Sys.time()) - 30)], function(z) if(nrow(z) > 0) {z %>% dplyr::mutate(Date = as.POSIXct(t, origin = "1970-01-01 00:00.00 UTC"), q2_logodds_delta_even = ifelse(x1$q2 > 0.5 & x1$q2 - dplyr::lag(x1$q2) < 0, log(x1$q2 / (1 - x1$q2)) - log(dplyr::lag(x1$q2) / (1 - dplyr::lag(x1$q2))), ifelse(x1$q2 < 0.5 & x1$q2 - dplyr::lag(x1$q2) > 0, log(x1$q2 / (1 - x1$q2)) - log(dplyr::lag(x1$q2) / (1 - dplyr::lag(x1$q2))), 0))) %>% dplyr::filter(as.Date(Date) >= as.Date(Sys.time()) - 30) %>% dplyr::summarize(Total_logodds_Change_Even = sum(abs(q2_logodds_delta_even)))})))) +} diff --git a/R/utils-pipe.R b/R/utils-pipe.R new file mode 100644 index 0000000..e79f3d8 --- /dev/null +++ b/R/utils-pipe.R @@ -0,0 +1,11 @@ +#' Pipe operator +#' +#' See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. +#' +#' @name %>% +#' @rdname pipe +#' @keywords internal +#' @export +#' @importFrom magrittr %>% +#' @usage lhs \%>\% rhs +NULL diff --git a/README.md b/README.md new file mode 100644 index 0000000..f799471 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ + +# MetaculR + + +[![CRAN status](https://www.r-pkg.org/badges/version/MetaculR)](https://CRAN.R-project.org/package=MetaculR) +[![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html) +[![pipeline status](https://gitlab.com/ntrlshrp/metaculr/badges/master/pipeline.svg)](https://gitlab.com/ntrlshrp/metaculr/-/commits/master) +[![coverage report](https://gitlab.com/ntrlshrp/metaculr/badges/master/coverage.svg)](https://gitlab.com/ntrlshrp/metaculr/-/commits/master) +[![Latest Release](https://gitlab.com/ntrlshrp/metaculr/-/badges/release.svg)](https://gitlab.com/ntrlshrp/metaculr/-/releases) + + +The goal of MetaculR is to enable [Metaculus](https://www.metaculus.com/questions/) users to easily login, download, and analyze questions predicted by you and/or the Metaculus community. +See vignettes, changelogs, and other documentation at [https://ntrlshrp.gitlab.io/metaculr/](https://ntrlshrp.gitlab.io/metaculr/). + +## Installation + +You can install the released version of MetaculR from [CRAN](https://CRAN.R-project.org) with: + +``` r +install.packages("MetaculR") +``` + +You can install the development version with: + +``` r +remotes::install_gitlab("ntrlshrp/metaculr") +``` diff --git a/build/vignette.rds b/build/vignette.rds new file mode 100644 index 0000000..4b4ba0e Binary files /dev/null and b/build/vignette.rds differ diff --git a/inst/doc/MetaculR.Rmd b/inst/doc/MetaculR.Rmd new file mode 100644 index 0000000..ef7e62a --- /dev/null +++ b/inst/doc/MetaculR.Rmd @@ -0,0 +1,704 @@ +--- +title: "MetaculR" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{MetaculR} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + + + + + + + + +```r +library(MetaculR) +``` + +# Login + +Add the following lines to `.Renviron` using `usethis::edit_r_environ()`: + +``` +Metaculus_username="yourUsername" +Metaculus_password="yourPassword" +``` + +Then, login: + + +```r +Metaculus_user_id <- MetaculR_login() +``` + +# Download Your Predictions + + +```r +questions_myPredictions <- MetaculR_myPredictions(guessed_by = Metaculus_user_id) +``` + +# Analyze Your Predictions + +## How different is my last prediction from current community? + + +```r +questions_myPredictions_byDiff <- MetaculR_myDiff(questions_myPredictions) +``` + + + +```r +questions_myPredictions_byDiff %>% + dplyr::select(id, title, my_prediction, community_q2, community_q2_pre_me, diff_me_q2_abs_odds) %>% + dplyr::mutate(diff_me_q2_abs_odds = round(diff_me_q2_abs_odds, 1)) %>% + dplyr::arrange(dplyr::desc(diff_me_q2_abs_odds)) %>% + head() %>% + knitr::kable() +``` + + + +| id|title | my_prediction| community_q2| community_q2_pre_me| diff_me_q2_abs_odds| +|----:|:-------------------------------------------------------------------------------------|-------------:|------------:|-------------------:|-------------------:| +| 1634|Will US Income Inequality Increase by 2025? | 0.02| 0.53| 0.47| 55.3| +| 9933|Will any NATO country invoke Article 5 by March 31, 2022? | 0.13| 0.01| 0.02| 14.8| +| 5407|If Starlink offers an IPO before 2030, will it set a record for the largest IPO? | 0.03| 0.24| 0.30| 10.2| +| 9937|Will more than 50,000 people be killed in the Russo-Ukrainian War in 2022? | 0.15| 0.60| 0.45| 8.5| +| 2605|Will any country's military expenditure exceed that of the United States before 2030? | 0.01| 0.07| 0.08| 7.5| +| 7977|Will US core CPI inflation rise by more than 3% from December 2021 to December 2022? | 0.94| 0.70| 0.68| 6.7| + +### Plot those differences + + +```r +questions_myPredictions_byDiff %>% + dplyr::arrange(dplyr::desc(diff_me_q2_abs_odds)) %>% + dplyr::slice_head(n = 10) %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = reorder(factor(id), -diff_me_q2_abs_odds), + y = diff_me_q2_abs_odds, + fill = reorder(factor(id), -diff_me_q2_abs_odds)) + ) + + ggplot2::theme_classic() + + ggplot2::labs(x = "ID", + y = "Odds difference between me and community q2") + + ggplot2::guides(fill = FALSE) + + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1)) +``` + +![plot of chunk unnamed-chunk-8](MetaculRRMD_unnamed-chunk-8-1.png) + +## Where has community moved most since my last prediction? + + +```r +questions_myPredictions_byDiff %>% + dplyr::select(id, title, my_prediction, community_q2, community_q2_pre_me, diff_comm_q2_pre_me_abs_odds) %>% + dplyr::mutate(diff_comm_q2_pre_me_abs_odds = round(diff_comm_q2_pre_me_abs_odds, 1)) %>% + dplyr::arrange(dplyr::desc(diff_comm_q2_pre_me_abs_odds)) %>% + head() %>% + knitr::kable() +``` + + + +| id|title | my_prediction| community_q2| community_q2_pre_me| diff_comm_q2_pre_me_abs_odds| +|-----:|:-----------------------------------------------------------------------------|-------------:|------------:|-------------------:|----------------------------:| +| 10004|Will a major nuclear power plant in Germany be operational on June 1, 2023? | 0.10| 0.20| 0.56| 5.1| +| 9939|Will Kyiv fall to Russian forces by April 2022? | 0.01| 0.02| 0.09| 4.8| +| 6604|Will annual U.S. inflation reach 100% in any year before 2050? | 0.01| 0.02| 0.08| 4.3| +| 8766|Will the Omicron variant be less lethal than Delta? | 0.98| 0.98| 0.94| 3.1| +| 9933|Will any NATO country invoke Article 5 by March 31, 2022? | 0.13| 0.01| 0.02| 2.0| +| 6725|Will a large American city fully abolish their police department before 2035? | 0.01| 0.02| 0.04| 2.0| + +### Plot those differences + + +```r +MetaculR_plot(MetaculR_questions = questions_myPredictions, + Metacular_id = 10004) +``` + +![plot of chunk unnamed-chunk-10](MetaculRRMD_unnamed-chunk-10-1.png) + + +```r +MetaculR_plot(MetaculR_questions = questions_myPredictions, + Metacular_id = 6604, + scale_binary = "logodds") +``` + +![plot of chunk unnamed-chunk-11](MetaculRRMD_unnamed-chunk-11-1.png) + +## Score Predictions + +Let's see some Brier statistics on resolved questions: + + +```r +questions_myPredictions_resolved <- MetaculR_myPredictions_Resolved(guessed_by = Metaculus_user_id) +``` + + +```r +brier_me <- MetaculR_brier(questions_myPredictions_resolved) +``` + +### Plot scores + + +```r +brier_me$brier_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = name, + y = value, + fill = ID), + position = "dodge2" + ) + + ggplot2::geom_text( + ggplot2::aes(x = name, + y = value, + label = round(value, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 1), #"dodge2", + vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::labs(x = "Statistic", + y = "Value") + + ggplot2::coord_cartesian(ylim = c(0, 1)) + + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1)) +#> Warning: Removed 10 rows containing missing values (geom_col). +#> Warning: Removed 10 rows containing missing values (geom_text). +``` + +![plot of chunk unnamed-chunk-14](MetaculRRMD_unnamed-chunk-14-1.png) + +#### Histogram + + +```r +brier_me$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = centers, + y = freqs, + fill = ID), + position = ggplot2::position_dodge2(width = 0.1, preserve = "single") + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = freqs, + label = round(freqs, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + # vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, 1)) +``` + +![plot of chunk unnamed-chunk-15](MetaculRRMD_unnamed-chunk-15-1.png) + +#### Calibration + + +```r +brier_me$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_pointrange( + ggplot2::aes(x = centers, + y = obars, + ymin = ci_low, + ymax = ci_high, + color = ID), + position = ggplot2::position_dodge2(width = 0.02) + ) + + ggplot2::geom_line( + ggplot2::aes(x = centers, + y = ideal) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = obars, + label = format(round(obars, 3), nsmall = 3)), + size = 2, + position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + vjust = -0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_me$brier_bins_df $obars) * 1.1)) +``` + +![plot of chunk unnamed-chunk-16](MetaculRRMD_unnamed-chunk-16-1.png) + +## Score Predictions (Equivalent Evidentiary Bins) + +What if question bins were not 5 percentage points each, but were based on logodds? + + +```r +brier_me <- MetaculR_brier(questions_myPredictions_resolved, + thresholds = c(0, exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) / (exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) + 1), 1)) +``` + + +```r +brier_me$brier_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = name, + y = value, + fill = ID), + position = "dodge2" + ) + + ggplot2::geom_text( + ggplot2::aes(x = name, + y = value, + label = round(value, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 1), #"dodge2", + vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::labs(x = "Statistic", + y = "Value") + + ggplot2::coord_cartesian(ylim = c(0, 1)) + + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1)) +#> Warning: Removed 10 rows containing missing values (geom_col). +#> Warning: Removed 10 rows containing missing values (geom_text). +``` + +![plot of chunk unnamed-chunk-18](MetaculRRMD_unnamed-chunk-18-1.png) + +#### Histogram (Equivalent Evidentiary Bins) + + +```r +brier_me$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = centers, + y = freqs, + fill = ID), + position = ggplot2::position_dodge2(width = 0.1, preserve = "single") + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = freqs, + label = round(freqs, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 0.05), #"dodge2", + # vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, 1)) +``` + +![plot of chunk unnamed-chunk-19](MetaculRRMD_unnamed-chunk-19-1.png) + +#### Calibration (Equivalent Evidentiary Bins) + + +```r +brier_me$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_pointrange( + ggplot2::aes(x = centers, + y = obars, + ymin = ci_low, + ymax = ci_high, + color = ID), + position = ggplot2::position_dodge2(width = 0.02) + ) + + ggplot2::geom_line( + ggplot2::aes(x = centers, + y = ideal) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = obars, + label = format(round(obars, 3), nsmall = 3)), + size = 2, + position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + vjust = -0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_me$brier_bins_df$obars) * 1.1)) +``` + +![plot of chunk unnamed-chunk-20](MetaculRRMD_unnamed-chunk-20-1.png) + +# Analyze community predictions + +For questions you may not have predicted. + +## Score, Community Predictions + +Let's see some Brier statistics on resolved questions: + + +```r +questions_recent_resolved <- + MetaculR_questions( + order_by = "-resolve_time", + status= "resolved", + guessed_by = "", + pages = 32, + offset = 0) +``` + + +```r +brier_recent_resolved <- + MetaculR_brier( + questions_recent_resolved, + me = FALSE) +``` + +### Plot scores, Community Predictions + + +```r +brier_recent_resolved$brier_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = name, + y = value, + fill = ID), + position = "dodge2" + ) + + ggplot2::geom_text( + ggplot2::aes(x = name, + y = value, + label = round(value, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 1), #"dodge2", + vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::labs(x = "Statistic", + y = "Value") + + ggplot2::coord_cartesian(ylim = c(0, 1)) + + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1)) +#> Warning: Removed 17 rows containing missing values (geom_col). +#> Warning: Removed 17 rows containing missing values (geom_text). +``` + +![plot of chunk unnamed-chunk-23](MetaculRRMD_unnamed-chunk-23-1.png) + +#### Histogram, Community Predictions + + +```r +brier_recent_resolved$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = centers, + y = freqs) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = freqs, + label = round(freqs, 3)), + size = 2, + # position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + # vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$freqs) * 1.1)) +``` + +![plot of chunk unnamed-chunk-24](MetaculRRMD_unnamed-chunk-24-1.png) + +#### Calibration, Community Predictions + + +```r +brier_recent_resolved$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_pointrange( + ggplot2::aes(x = centers, + y = obars, + ymin = ci_low, + ymax = ci_high) + ) + + ggplot2::geom_line( + ggplot2::aes(x = centers, + y = ideal) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = obars, + label = format(round(obars, 3), nsmall = 3)), + size = 2, + # position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + vjust = -0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$obars) * 1.1)) +``` + +![plot of chunk unnamed-chunk-25](MetaculRRMD_unnamed-chunk-25-1.png) + +## Score Predictions, Community Predictions (Equivalent Evidentiary Bins) + + +```r +brier_recent_resolved <- + MetaculR_brier( + questions_recent_resolved, + me = FALSE, + thresholds = c(0, exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) / (exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) + 1), 1)) +``` + + +```r +brier_recent_resolved$brier_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = name, + y = value, + fill = ID), + position = "dodge2" + ) + + ggplot2::geom_text( + ggplot2::aes(x = name, + y = value, + label = round(value, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 1), #"dodge2", + vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::labs(x = "Statistic", + y = "Value") + + ggplot2::coord_cartesian(ylim = c(0, 1)) + + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1)) +#> Warning: Removed 17 rows containing missing values (geom_col). +#> Warning: Removed 17 rows containing missing values (geom_text). +``` + +![plot of chunk unnamed-chunk-27](MetaculRRMD_unnamed-chunk-27-1.png) + +#### Histogram, Community Predictions (Equivalent Evidentiary Bins) + + +```r +brier_recent_resolved$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = centers, + y = freqs) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = freqs, + label = round(freqs, 3)), + size = 2, + # position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + # vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$freqs) * 1.1)) +``` + +![plot of chunk unnamed-chunk-28](MetaculRRMD_unnamed-chunk-28-1.png) + +#### Calibration, Community Predictions (Equivalent Evidentiary Bins) + + +```r +brier_recent_resolved$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_pointrange( + ggplot2::aes(x = centers, + y = obars, + ymin = ci_low, + ymax = ci_high) + ) + + ggplot2::geom_line( + ggplot2::aes(x = centers, + y = ideal) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = obars, + label = format(round(obars, 3), nsmall = 3)), + size = 2, + # position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + vjust = -0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$obars) * 1.1)) +``` + +![plot of chunk unnamed-chunk-29](MetaculRRMD_unnamed-chunk-29-1.png) + +# Find Exciting Questions + +Various sports now have an "Excitement Index" to identify games that interest fans--maybe we can do the same for predictions? + +## Among your predictions + + +```r +questions_myPredictions_byExcitement <- MetaculR_excitement(questions_myPredictions) + +questions_myPredictions_byExcitement %>% + dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2), + Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>% + dplyr::arrange(dplyr::desc(Total_Change)) %>% + head() %>% + knitr::kable() +``` + + + +| id|title | Total_Change| Total_logodds_Change| Total_Change_Even| Total_logodds_Change_Even| +|----:|:---------------------------------------------------------------------------------|------------:|--------------------:|-----------------:|-------------------------:| +| 9790|Will Éric Zemmour be in the 2nd round of the 2022 French presidential election? | 1.12| 5.38| 0.50| 2.32| +| 8944|Will Boris Johnson be Prime Minister of the UK on June 1, 2022? | 0.35| 2.00| 0.00| 0.00| +| 8882|Will 2022 be the hottest year on record? | 0.22| 1.60| 0.11| 0.80| +| 8554|Will women receive at least 70% of bachelor's degrees in the US in the year 2050? | 0.19| 1.49| 0.10| 0.79| +| 2511|Will Emmanuel Macron be re-elected President of France in 2022? | 0.18| 1.40| 0.00| 0.00| +| 6330|Will Donald J. Trump be a candidate for President in the 2024 cycle? | 0.15| 0.79| 0.05| 0.25| + + +```r +MetaculR_plot(MetaculR_questions = questions_myPredictions, + Metacular_id = 9790) +``` + +![plot of chunk unnamed-chunk-31](MetaculRRMD_unnamed-chunk-31-1.png) + + +```r +questions_myPredictions_byExcitement %>% + dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2), + Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>% + dplyr::arrange(dplyr::desc(Total_logodds_Change)) %>% + head() %>% + knitr::kable() +``` + + + +| id|title | Total_Change| Total_logodds_Change| Total_Change_Even| Total_logodds_Change_Even| +|----:|:---------------------------------------------------------------------------------|------------:|--------------------:|-----------------:|-------------------------:| +| 9790|Will Éric Zemmour be in the 2nd round of the 2022 French presidential election? | 1.12| 5.38| 0.50| 2.32| +| 8944|Will Boris Johnson be Prime Minister of the UK on June 1, 2022? | 0.35| 2.00| 0.00| 0.00| +| 8882|Will 2022 be the hottest year on record? | 0.22| 1.60| 0.11| 0.80| +| 8554|Will women receive at least 70% of bachelor's degrees in the US in the year 2050? | 0.19| 1.49| 0.10| 0.79| +| 6604|Will annual U.S. inflation reach 100% in any year before 2050? | 0.06| 1.45| 0.00| 0.00| +| 2511|Will Emmanuel Macron be re-elected President of France in 2022? | 0.18| 1.40| 0.00| 0.00| + + +```r +MetaculR_plot(MetaculR_questions = questions_myPredictions, + Metacular_id = 6725) +``` + +![plot of chunk unnamed-chunk-33](MetaculRRMD_unnamed-chunk-33-1.png) + +## Among community predictions + +### Resolved questions + +What were the most exciting resolved questions? + + +```r +questions_recent_byExcitement <- MetaculR_excitement(questions_recent_resolved) + +questions_recent_byExcitement %>% + dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2), + Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>% + dplyr::arrange(dplyr::desc(Total_Change_Even)) %>% + head() %>% + knitr::kable() +``` + + + +| id|title | Total_Change| Total_logodds_Change| Total_Change_Even| Total_logodds_Change_Even| +|----:|:--------------------------------------------------------------------------------------------------------------------|------------:|--------------------:|-----------------:|-------------------------:| +| 8859|Will Ukraine ban wheat export before April 2023? | 0.17| 1.37| 0.11| 0.92| +| 9517|Will Russian troops enter Mariupol, Ukraine by December 31, 2022? | 0.52| 4.86| 0.09| 0.44| +| 9590|Will there be a Pi variant of COVID by Pi Day (March 14, 2022)? | 0.41| 1.95| 0.07| 0.30| +| 8898|Will Russia invade Ukrainian territory before 2023? | 0.38| 2.97| 0.06| 0.32| +| 7211|Will any body of the US federal government conclude that COVID-19 originated in a lab in Hubei before June 1st 2022? | 0.02| 0.08| 0.02| 0.08| +| 9693|Will the gray wolf be relisted as Threatened or Endangered by the US before 2030? | 0.00| 0.00| 0.00| 0.00| + + +```r +MetaculR_plot(MetaculR_questions = questions_recent_resolved, + Metacular_id = 8898) +``` + +![plot of chunk unnamed-chunk-35](MetaculRRMD_unnamed-chunk-35-1.png) + +### Open questions + +What are the most exciting questions that are still open? + + +```r +questions_recent_open <- + MetaculR_questions( + order_by = "close_time", + status = "open", + guessed_by = "") +``` + + +```r +questions_recent_open_byExcitement <- MetaculR_excitement(questions_recent_open) + +questions_recent_open_byExcitement %>% + dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2), + Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>% + dplyr::arrange(dplyr::desc(Total_logodds_Change_Even)) %>% + head() %>% + knitr::kable() +``` + + + +| id|title | Total_Change| Total_logodds_Change| Total_Change_Even| Total_logodds_Change_Even| +|----:|:------------------------------------------------------------------------------------------------------|------------:|--------------------:|-----------------:|-------------------------:| +| 9746|Will Ukraine fulfill its Minsk-II obligations in Donetsk and Luhansk Oblast by 2023? | 0.57| 11.73| 0.14| 4.72| +| 9566|Will Russian troops enter Odessa, Ukraine before December 31, 2022? | 1.18| 10.03| 0.48| 4.56| +| 9791|Will Éric Zemmour win the French presidential election in 2022? | 0.15| 9.40| 0.07| 4.35| +| 9743|Will Volodymyr Zelensky remain President of Ukraine by 2023? | 1.66| 8.13| 0.74| 3.70| +| 7237|Will Coinbase default on an obligation to hand over their users’ assets on request by the end of 2022? | 0.13| 5.05| 0.07| 2.67| +| 9584|Will Ketanji Brown Jackson be confirmed as an Associate Justice of the Supreme Court before 2023? | 0.67| 8.62| 0.12| 2.46| + + +```r +MetaculR_plot(MetaculR_questions = questions_recent_open, + Metacular_id = 9566) +``` + +![plot of chunk unnamed-chunk-38](MetaculRRMD_unnamed-chunk-38-1.png) + + diff --git a/inst/doc/MetaculR.html b/inst/doc/MetaculR.html new file mode 100644 index 0000000..f12bd5c --- /dev/null +++ b/inst/doc/MetaculR.html @@ -0,0 +1,1361 @@ + + + + + + + + + + + + + + +MetaculR + + + + + + + + + + + + + + + + + + + + + + + + +

MetaculR

+ + + +
library(MetaculR)
+
+

Login

+

Add the following lines to .Renviron using usethis::edit_r_environ():

+
Metaculus_username="yourUsername"
+Metaculus_password="yourPassword"
+

Then, login:

+
Metaculus_user_id <- MetaculR_login()
+
+
+

Download Your Predictions

+
questions_myPredictions <- MetaculR_myPredictions(guessed_by = Metaculus_user_id)
+
+
+

Analyze Your Predictions

+
+

How different is my last prediction from current community?

+
questions_myPredictions_byDiff <- MetaculR_myDiff(questions_myPredictions)
+
questions_myPredictions_byDiff %>%
+  dplyr::select(id, title, my_prediction, community_q2, community_q2_pre_me, diff_me_q2_abs_odds) %>%
+  dplyr::mutate(diff_me_q2_abs_odds = round(diff_me_q2_abs_odds, 1)) %>%
+  dplyr::arrange(dplyr::desc(diff_me_q2_abs_odds)) %>%
+  head() %>%
+  knitr::kable()
+ ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
idtitlemy_predictioncommunity_q2community_q2_pre_mediff_me_q2_abs_odds
1634Will US Income Inequality Increase by 2025?0.020.530.4755.3
9933Will any NATO country invoke Article 5 by March 31, 2022?0.130.010.0214.8
5407If Starlink offers an IPO before 2030, will it set a record for the largest IPO?0.030.240.3010.2
9937Will more than 50,000 people be killed in the Russo-Ukrainian War in 2022?0.150.600.458.5
2605Will any country’s military expenditure exceed that of the United States before 2030?0.010.070.087.5
7977Will US core CPI inflation rise by more than 3% from December 2021 to December 2022?0.940.700.686.7
+
+

Plot those differences

+
questions_myPredictions_byDiff %>%
+  dplyr::arrange(dplyr::desc(diff_me_q2_abs_odds)) %>%
+  dplyr::slice_head(n = 10) %>%
+  ggplot2::ggplot() +
+  ggplot2::geom_col(
+    ggplot2::aes(x = reorder(factor(id), -diff_me_q2_abs_odds),
+                 y = diff_me_q2_abs_odds,
+                 fill = reorder(factor(id), -diff_me_q2_abs_odds))
+  ) +
+  ggplot2::theme_classic() +
+  ggplot2::labs(x = "ID",
+                y = "Odds difference between me and community q2") +
+  ggplot2::guides(fill = FALSE) +
+  ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1))
+
+ +

plot of chunk unnamed-chunk-8

+
+
+
+
+

Where has community moved most since my last prediction?

+
questions_myPredictions_byDiff %>%
+  dplyr::select(id, title, my_prediction, community_q2, community_q2_pre_me, diff_comm_q2_pre_me_abs_odds) %>%
+  dplyr::mutate(diff_comm_q2_pre_me_abs_odds = round(diff_comm_q2_pre_me_abs_odds, 1)) %>%
+  dplyr::arrange(dplyr::desc(diff_comm_q2_pre_me_abs_odds)) %>%
+  head() %>%
+  knitr::kable()
+ ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
idtitlemy_predictioncommunity_q2community_q2_pre_mediff_comm_q2_pre_me_abs_odds
10004Will a major nuclear power plant in Germany be operational on June 1, 2023?0.100.200.565.1
9939Will Kyiv fall to Russian forces by April 2022?0.010.020.094.8
6604Will annual U.S. inflation reach 100% in any year before 2050?0.010.020.084.3
8766Will the Omicron variant be less lethal than Delta?0.980.980.943.1
9933Will any NATO country invoke Article 5 by March 31, 2022?0.130.010.022.0
6725Will a large American city fully abolish their police department before 2035?0.010.020.042.0
+
+

Plot those differences

+
MetaculR_plot(MetaculR_questions = questions_myPredictions,
+              Metacular_id = 10004)
+
+ +

plot of chunk unnamed-chunk-10

+
+
MetaculR_plot(MetaculR_questions = questions_myPredictions,
+              Metacular_id = 6604,
+              scale_binary = "logodds")
+
+ +

plot of chunk unnamed-chunk-11

+
+
+
+
+

Score Predictions

+

Let’s see some Brier statistics on resolved questions:

+
questions_myPredictions_resolved <- MetaculR_myPredictions_Resolved(guessed_by = Metaculus_user_id)
+
brier_me <- MetaculR_brier(questions_myPredictions_resolved)
+
+

Plot scores

+
brier_me$brier_df %>%
+  ggplot2::ggplot() +
+  ggplot2::geom_col(
+    ggplot2::aes(x = name,
+                 y = value,
+                 fill = ID),
+    position = "dodge2"
+  ) +
+  ggplot2::geom_text(
+    ggplot2::aes(x = name,
+                 y = value,
+                 label = round(value, 3)),
+    size = 2,
+    position = ggplot2::position_dodge2(width = 1), #"dodge2",
+    vjust = 0.5,
+    hjust = -0.25,
+    angle = 90) +
+  ggplot2::theme_classic() +
+  ggplot2::labs(x = "Statistic",
+                y = "Value") +
+  ggplot2::coord_cartesian(ylim = c(0, 1)) +
+  ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1))
+#> Warning: Removed 10 rows containing missing values (geom_col).
+#> Warning: Removed 10 rows containing missing values (geom_text).
+
+ +

plot of chunk unnamed-chunk-14

+
+
+

Histogram

+
brier_me$brier_bins_df %>%
+  ggplot2::ggplot() +
+  ggplot2::geom_col(
+    ggplot2::aes(x = centers,
+                 y = freqs,
+                 fill = ID),
+    position = ggplot2::position_dodge2(width = 0.1, preserve = "single")
+  ) +
+  ggplot2::geom_text(
+    ggplot2::aes(x = centers,
+                 y = freqs,
+                 label = round(freqs, 3)),
+    size = 2,
+    position = ggplot2::position_dodge2(width = 0.1), #"dodge2",
+    # vjust = 0.5,
+    hjust = -0.25,
+    angle = 90) +
+  ggplot2::theme_classic() +
+  ggplot2::coord_cartesian(ylim = c(0, 1))
+
+ +

plot of chunk unnamed-chunk-15

+
+
+
+

Calibration

+
brier_me$brier_bins_df %>%
+  ggplot2::ggplot() +
+  ggplot2::geom_pointrange(
+    ggplot2::aes(x = centers,
+                 y = obars,
+                 ymin = ci_low,
+                 ymax = ci_high,
+                 color = ID),
+    position = ggplot2::position_dodge2(width = 0.02)
+  ) +
+  ggplot2::geom_line(
+    ggplot2::aes(x = centers,
+                 y = ideal)
+  ) +
+  ggplot2::geom_text(
+    ggplot2::aes(x = centers,
+                 y = obars,
+                 label = format(round(obars, 3), nsmall = 3)),
+    size = 2,
+    position = ggplot2::position_dodge2(width = 0.1), #"dodge2",
+    vjust = -0.5,
+    hjust = -0.25,
+    angle = 90) +
+  ggplot2::theme_classic() +
+  ggplot2::coord_cartesian(ylim = c(0, max(brier_me$brier_bins_df $obars) * 1.1))
+
+ +

plot of chunk unnamed-chunk-16

+
+
+
+
+
+

Score Predictions (Equivalent Evidentiary Bins)

+

What if question bins were not 5 percentage points each, but were based on logodds?

+
brier_me <- MetaculR_brier(questions_myPredictions_resolved,
+                           thresholds = c(0, exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) / (exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) + 1), 1))
+
brier_me$brier_df  %>%
+  ggplot2::ggplot() +
+  ggplot2::geom_col(
+    ggplot2::aes(x = name,
+                 y = value,
+                 fill = ID),
+    position = "dodge2"
+  ) +
+  ggplot2::geom_text(
+    ggplot2::aes(x = name,
+                 y = value,
+                 label = round(value, 3)),
+    size = 2,
+    position = ggplot2::position_dodge2(width = 1), #"dodge2",
+    vjust = 0.5,
+    hjust = -0.25,
+    angle = 90) +
+  ggplot2::theme_classic() +
+  ggplot2::labs(x = "Statistic",
+                y = "Value") +
+  ggplot2::coord_cartesian(ylim = c(0, 1)) +
+  ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1))
+#> Warning: Removed 10 rows containing missing values (geom_col).
+#> Warning: Removed 10 rows containing missing values (geom_text).
+
+ +

plot of chunk unnamed-chunk-18

+
+
+

Histogram (Equivalent Evidentiary Bins)

+
brier_me$brier_bins_df %>%
+  ggplot2::ggplot() +
+  ggplot2::geom_col(
+    ggplot2::aes(x = centers,
+                 y = freqs,
+                 fill = ID),
+    position = ggplot2::position_dodge2(width = 0.1, preserve = "single")
+  ) +
+  ggplot2::geom_text(
+    ggplot2::aes(x = centers,
+                 y = freqs,
+                 label = round(freqs, 3)),
+    size = 2,
+    position = ggplot2::position_dodge2(width = 0.05), #"dodge2",
+    # vjust = 0.5,
+    hjust = -0.25,
+    angle = 90) +
+  ggplot2::theme_classic() +
+  ggplot2::coord_cartesian(ylim = c(0, 1))
+
+ +

plot of chunk unnamed-chunk-19

+
+
+
+

Calibration (Equivalent Evidentiary Bins)

+
brier_me$brier_bins_df %>%
+  ggplot2::ggplot() +
+  ggplot2::geom_pointrange(
+    ggplot2::aes(x = centers,
+                 y = obars,
+                 ymin = ci_low,
+                 ymax = ci_high,
+                 color = ID),
+    position = ggplot2::position_dodge2(width = 0.02)
+  ) +
+  ggplot2::geom_line(
+    ggplot2::aes(x = centers,
+                 y = ideal)
+  ) +
+  ggplot2::geom_text(
+    ggplot2::aes(x = centers,
+                 y = obars,
+                 label = format(round(obars, 3), nsmall = 3)),
+    size = 2,
+    position = ggplot2::position_dodge2(width = 0.1), #"dodge2",
+    vjust = -0.5,
+    hjust = -0.25,
+    angle = 90) +
+  ggplot2::theme_classic() +
+  ggplot2::coord_cartesian(ylim = c(0, max(brier_me$brier_bins_df$obars) * 1.1))
+
+ +

plot of chunk unnamed-chunk-20

+
+
+
+
+
+

Analyze community predictions

+

For questions you may not have predicted.

+
+

Score, Community Predictions

+

Let’s see some Brier statistics on resolved questions:

+
questions_recent_resolved <-
+  MetaculR_questions(
+    order_by = "-resolve_time",
+    status= "resolved",
+    guessed_by = "",
+    pages = 32,
+    offset = 0)
+
brier_recent_resolved <-
+  MetaculR_brier(
+    questions_recent_resolved,
+    me = FALSE)
+
+

Plot scores, Community Predictions

+
brier_recent_resolved$brier_df %>%
+    ggplot2::ggplot() +
+  ggplot2::geom_col(
+    ggplot2::aes(x = name,
+                 y = value,
+                 fill = ID),
+    position = "dodge2"
+  ) +
+  ggplot2::geom_text(
+    ggplot2::aes(x = name,
+                 y = value,
+                 label = round(value, 3)),
+    size = 2,
+    position = ggplot2::position_dodge2(width = 1), #"dodge2",
+    vjust = 0.5,
+    hjust = -0.25,
+    angle = 90) +
+  ggplot2::theme_classic() +
+  ggplot2::labs(x = "Statistic",
+                y = "Value") +
+  ggplot2::coord_cartesian(ylim = c(0, 1)) +
+  ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1))
+#> Warning: Removed 17 rows containing missing values (geom_col).
+#> Warning: Removed 17 rows containing missing values (geom_text).
+
+ +

plot of chunk unnamed-chunk-23

+
+
+

Histogram, Community Predictions

+
brier_recent_resolved$brier_bins_df %>%
+  ggplot2::ggplot() +
+  ggplot2::geom_col(
+    ggplot2::aes(x = centers,
+                 y = freqs)
+  ) +
+  ggplot2::geom_text(
+    ggplot2::aes(x = centers,
+                 y = freqs,
+                 label = round(freqs, 3)),
+    size = 2,
+    # position = ggplot2::position_dodge2(width = 0.1), #"dodge2",
+    # vjust = 0.5,
+    hjust = -0.25,
+    angle = 90) +
+  ggplot2::theme_classic() +
+  ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$freqs) * 1.1))
+
+ +

plot of chunk unnamed-chunk-24

+
+
+
+

Calibration, Community Predictions

+
brier_recent_resolved$brier_bins_df %>%
+  ggplot2::ggplot() +
+  ggplot2::geom_pointrange(
+    ggplot2::aes(x = centers,
+                 y = obars,
+                 ymin = ci_low,
+                 ymax = ci_high)
+  ) +
+  ggplot2::geom_line(
+    ggplot2::aes(x = centers,
+                 y = ideal)
+  ) +
+  ggplot2::geom_text(
+    ggplot2::aes(x = centers,
+                 y = obars,
+                 label = format(round(obars, 3), nsmall = 3)),
+    size = 2,
+    # position = ggplot2::position_dodge2(width = 0.1), #"dodge2",
+    vjust = -0.5,
+    hjust = -0.25,
+    angle = 90) +
+  ggplot2::theme_classic() +
+  ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$obars) * 1.1))
+
+ +

plot of chunk unnamed-chunk-25

+
+
+
+
+
+

Score Predictions, Community Predictions (Equivalent Evidentiary Bins)

+
brier_recent_resolved <-
+  MetaculR_brier(
+    questions_recent_resolved,
+    me = FALSE,
+    thresholds = c(0, exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) / (exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) + 1), 1))
+
brier_recent_resolved$brier_df %>%
+  ggplot2::ggplot() +
+  ggplot2::geom_col(
+    ggplot2::aes(x = name,
+                 y = value,
+                 fill = ID),
+    position = "dodge2"
+  ) +
+  ggplot2::geom_text(
+    ggplot2::aes(x = name,
+                 y = value,
+                 label = round(value, 3)),
+    size = 2,
+    position = ggplot2::position_dodge2(width = 1), #"dodge2",
+    vjust = 0.5,
+    hjust = -0.25,
+    angle = 90) +
+  ggplot2::theme_classic() +
+  ggplot2::labs(x = "Statistic",
+                y = "Value") +
+  ggplot2::coord_cartesian(ylim = c(0, 1)) +
+  ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1))
+#> Warning: Removed 17 rows containing missing values (geom_col).
+#> Warning: Removed 17 rows containing missing values (geom_text).
+
+ +

plot of chunk unnamed-chunk-27

+
+
+

Histogram, Community Predictions (Equivalent Evidentiary Bins)

+
brier_recent_resolved$brier_bins_df %>%
+  ggplot2::ggplot() +
+  ggplot2::geom_col(
+    ggplot2::aes(x = centers,
+                 y = freqs)
+  ) +
+  ggplot2::geom_text(
+    ggplot2::aes(x = centers,
+                 y = freqs,
+                 label = round(freqs, 3)),
+    size = 2,
+    # position = ggplot2::position_dodge2(width = 0.1), #"dodge2",
+    # vjust = 0.5,
+    hjust = -0.25,
+    angle = 90) +
+  ggplot2::theme_classic() +
+  ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$freqs) * 1.1))
+
+ +

plot of chunk unnamed-chunk-28

+
+
+
+

Calibration, Community Predictions (Equivalent Evidentiary Bins)

+
brier_recent_resolved$brier_bins_df %>%
+  ggplot2::ggplot() +
+  ggplot2::geom_pointrange(
+    ggplot2::aes(x = centers,
+                 y = obars,
+                 ymin = ci_low,
+                 ymax = ci_high)
+  ) +
+  ggplot2::geom_line(
+    ggplot2::aes(x = centers,
+                 y = ideal)
+  ) +
+  ggplot2::geom_text(
+    ggplot2::aes(x = centers,
+                 y = obars,
+                 label = format(round(obars, 3), nsmall = 3)),
+    size = 2,
+    # position = ggplot2::position_dodge2(width = 0.1), #"dodge2",
+    vjust = -0.5,
+    hjust = -0.25,
+    angle = 90) +
+  ggplot2::theme_classic() +
+  ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$obars) * 1.1))
+
+ +

plot of chunk unnamed-chunk-29

+
+
+
+
+
+

Find Exciting Questions

+

Various sports now have an “Excitement Index” to identify games that interest fans–maybe we can do the same for predictions?

+
+

Among your predictions

+
questions_myPredictions_byExcitement <- MetaculR_excitement(questions_myPredictions)
+
+questions_myPredictions_byExcitement %>%
+  dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2),
+                Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>%
+  dplyr::arrange(dplyr::desc(Total_Change)) %>%
+  head() %>%
+  knitr::kable()
+ ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
idtitleTotal_ChangeTotal_logodds_ChangeTotal_Change_EvenTotal_logodds_Change_Even
9790Will Éric Zemmour be in the 2nd round of the 2022 French presidential election?1.125.380.502.32
8944Will Boris Johnson be Prime Minister of the UK on June 1, 2022?0.352.000.000.00
8882Will 2022 be the hottest year on record?0.221.600.110.80
8554Will women receive at least 70% of bachelor’s degrees in the US in the year 2050?0.191.490.100.79
2511Will Emmanuel Macron be re-elected President of France in 2022?0.181.400.000.00
6330Will Donald J. Trump be a candidate for President in the 2024 cycle?0.150.790.050.25
+
MetaculR_plot(MetaculR_questions = questions_myPredictions,
+              Metacular_id = 9790)
+
+ +

plot of chunk unnamed-chunk-31

+
+
questions_myPredictions_byExcitement %>%
+  dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2),
+                Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>%
+  dplyr::arrange(dplyr::desc(Total_logodds_Change)) %>%
+  head() %>%
+  knitr::kable()
+ ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
idtitleTotal_ChangeTotal_logodds_ChangeTotal_Change_EvenTotal_logodds_Change_Even
9790Will Éric Zemmour be in the 2nd round of the 2022 French presidential election?1.125.380.502.32
8944Will Boris Johnson be Prime Minister of the UK on June 1, 2022?0.352.000.000.00
8882Will 2022 be the hottest year on record?0.221.600.110.80
8554Will women receive at least 70% of bachelor’s degrees in the US in the year 2050?0.191.490.100.79
6604Will annual U.S. inflation reach 100% in any year before 2050?0.061.450.000.00
2511Will Emmanuel Macron be re-elected President of France in 2022?0.181.400.000.00
+
MetaculR_plot(MetaculR_questions = questions_myPredictions,
+              Metacular_id = 6725)
+
+ +

plot of chunk unnamed-chunk-33

+
+
+
+

Among community predictions

+
+

Resolved questions

+

What were the most exciting resolved questions?

+
questions_recent_byExcitement <- MetaculR_excitement(questions_recent_resolved)
+
+questions_recent_byExcitement %>%
+  dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2),
+                Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>%
+  dplyr::arrange(dplyr::desc(Total_Change_Even)) %>%
+  head() %>%
+  knitr::kable()
+ ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
idtitleTotal_ChangeTotal_logodds_ChangeTotal_Change_EvenTotal_logodds_Change_Even
8859Will Ukraine ban wheat export before April 2023?0.171.370.110.92
9517Will Russian troops enter Mariupol, Ukraine by December 31, 2022?0.524.860.090.44
9590Will there be a Pi variant of COVID by Pi Day (March 14, 2022)?0.411.950.070.30
8898Will Russia invade Ukrainian territory before 2023?0.382.970.060.32
7211Will any body of the US federal government conclude that COVID-19 originated in a lab in Hubei before June 1st 2022?0.020.080.020.08
9693Will the gray wolf be relisted as Threatened or Endangered by the US before 2030?0.000.000.000.00
+
MetaculR_plot(MetaculR_questions = questions_recent_resolved,
+              Metacular_id = 8898)
+
+ +

plot of chunk unnamed-chunk-35

+
+
+
+

Open questions

+

What are the most exciting questions that are still open?

+
questions_recent_open <-
+  MetaculR_questions(
+    order_by = "close_time",
+    status = "open",
+    guessed_by = "")
+
questions_recent_open_byExcitement <- MetaculR_excitement(questions_recent_open)
+
+questions_recent_open_byExcitement %>%
+  dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2),
+                Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>%
+  dplyr::arrange(dplyr::desc(Total_logodds_Change_Even)) %>%
+  head() %>%
+  knitr::kable()
+ ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
idtitleTotal_ChangeTotal_logodds_ChangeTotal_Change_EvenTotal_logodds_Change_Even
9746Will Ukraine fulfill its Minsk-II obligations in Donetsk and Luhansk Oblast by 2023?0.5711.730.144.72
9566Will Russian troops enter Odessa, Ukraine before December 31, 2022?1.1810.030.484.56
9791Will Éric Zemmour win the French presidential election in 2022?0.159.400.074.35
9743Will Volodymyr Zelensky remain President of Ukraine by 2023?1.668.130.743.70
7237Will Coinbase default on an obligation to hand over their users’ assets on request by the end of 2022?0.135.050.072.67
9584Will Ketanji Brown Jackson be confirmed as an Associate Justice of the Supreme Court before 2023?0.678.620.122.46
+
MetaculR_plot(MetaculR_questions = questions_recent_open,
+              Metacular_id = 9566)
+
+ +

plot of chunk unnamed-chunk-38

+
+
+
+
+ + + + + + + + + + + diff --git a/man/MetaculR_brier.Rd b/man/MetaculR_brier.Rd new file mode 100644 index 0000000..2a1616f --- /dev/null +++ b/man/MetaculR_brier.Rd @@ -0,0 +1,57 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/basics.R +\name{MetaculR_brier} +\alias{MetaculR_brier} +\title{Calculate Brier statistics on MetaculR_questions object} +\usage{ +MetaculR_brier(MetaculR_questions, me = TRUE, thresholds = seq(0, 1, 0.1)) +} +\arguments{ +\item{MetaculR_questions}{A MetaculR_questions object} + +\item{me}{Show my scores alongside Metaculus scores} + +\item{thresholds}{Thresholds to bin questions} +} +\value{ +A list of Brier statistics for you and Metaculus. +\item{brier_me, brier_Metaculus}{} +\item{baseline.tf}{Logical indicator of whether climatology was provided.} +\item{bs}{Brier score} +\item{bs.baseline}{Brier Score for climatology} +\item{ss}{Skill score} +\item{bs.reliability}{Reliability portion of Brier score.} +\item{bs.resolution}{Resolution component of Brier score.} +\item{bs.uncert}{Uncertainty component of Brier score.} +\item{y.i}{Forecast bins -- described as the center value of the bins.} +\item{obar.i}{Observation bins -- described as the center value of the bins.} +\item{prob.y}{Proportion of time using each forecast.} +\item{obar}{Forecast based on climatology or average sample observations.} +\item{thresholds}{The thresholds for the forecast bins.} +\item{check}{ Reliability - resolution + uncertainty should equal brier score.} +\item{Other}{} +\item{ss_me_Metaculus}{Skill score, me vs. Metaculus.} +\item{count_questions}{Number of total questions included.} +\item{brier_df: Used for plotting Brier score statistics}{} +\item{ID}{Predictor.} +\item{name}{Name of value, see above.} +\item{value}{Value.} +\item{brier_bins_df: Used for plotting histogram and calibration plots.}{} +\item{ID}{Predictor.} +\item{centers}{y.i, see above.} +\item{freqs}{prob.y, see above.} +\item{obars}{obar.i, see above.} +\item{ideal}{Ideal calibration where centers equals obars.} +\item{ci_low}{Low end of 95\% confidence interval for obar.i.} +\item{ci_high}{High end of 95\% confidence interval for obar.i.} +} +\description{ +Calculate Brier statistics on MetaculR_questions object +} +\examples{ +\dontrun{ +brier_me <- + MetaculR_brier( + questions_myPredictions_resolved) +} +} diff --git a/man/MetaculR_excitement.Rd b/man/MetaculR_excitement.Rd new file mode 100644 index 0000000..8056747 --- /dev/null +++ b/man/MetaculR_excitement.Rd @@ -0,0 +1,30 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/basics.R +\name{MetaculR_excitement} +\alias{MetaculR_excitement} +\title{Find exciting questions} +\usage{ +MetaculR_excitement(MetaculR_questions) +} +\arguments{ +\item{MetaculR_questions}{A MetaculR_questions object} +} +\value{ +A dataframe of questions with excitement measures. +\item{id}{Question ID.} +\item{title}{Question title.} +\item{Total_Change}{Cumulative delta in time period, by probability.} +\item{Total_logodds_Change}{Cumulative delta in time period, by logodds.} +\item{Total_Change_Even}{Cumulative delta toward even odds in time period, by probability.} +\item{Total_logodds_Change_Even}{Cumulative delta toward even odds in time period, by logodds.} +} +\description{ +Find exciting questions +} +\examples{ +\dontrun{ +questions_myPredictions_byExcitement <- + MetaculR_excitement( + questions_myPredictions) +} +} diff --git a/man/MetaculR_login.Rd b/man/MetaculR_login.Rd new file mode 100644 index 0000000..81487a5 --- /dev/null +++ b/man/MetaculR_login.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/basics.R +\name{MetaculR_login} +\alias{MetaculR_login} +\title{Login to Metaculus} +\usage{ +MetaculR_login(api_domain = "www") +} +\arguments{ +\item{api_domain}{Use "www" unless you have a custom Metaculus domain} +} +\value{ +Your Metaculus_user_ID. +} +\description{ +Login to Metaculus +} +\examples{ +\dontrun{ +Metaculus_user_id <- + MetaculR_login() +} +} diff --git a/man/MetaculR_myDiff.Rd b/man/MetaculR_myDiff.Rd new file mode 100644 index 0000000..373397c --- /dev/null +++ b/man/MetaculR_myDiff.Rd @@ -0,0 +1,43 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/basics.R +\name{MetaculR_myDiff} +\alias{MetaculR_myDiff} +\title{Find important changes within MetaculR_questions object} +\usage{ +MetaculR_myDiff(MetaculR_questions) +} +\arguments{ +\item{MetaculR_questions}{A MetaculR_questions object} +} +\value{ +A dataframe of questions with difference measures (your most recent prediction vs. community's most recent prediction, etc.). +\item{id}{Question ID.} +\item{title}{Question title.} +\item{my_prediction}{My most recent prediction.} +\item{community_q2}{Community median.} +\item{community_ave}{Community average.} +\item{community_q2_pre_me}{Community median immediately prior to my_prediction.} +\item{community_ave_pre_me}{Community average immediately prior to my_prediction.} +\item{diff_me_q2}{Difference between me and the community median, by logodds.} +\item{diff_me_ave}{Difference between me and the community average, by logodds.} +\item{diff_comm_q2_pre_me}{Difference between community_q2_pre_me and the community average, by logodds.} +\item{diff_comm_ave_pre_me}{Difference between community_ave_pre_me and the community average, by logodds.} +\item{diff_me_q2_abs}{Absolute difference between me and the community median, by logodds.} +\item{diff_me_ave_abs}{Absolute difference between me and the community average, by logodds.} +\item{diff_comm_q2_pre_me_abs}{Absolute difference between community_q2_pre_me and the community average, by logodds.} +\item{diff_comm_ave_pre_me_abs}{Absolute difference between community_ave_pre_me and the community average, by logodds.} +\item{diff_me_q2_abs_odds}{Absolute difference between me and the community median, by odds.} +\item{diff_me_ave_abs_odds}{Absolute difference between me and the community average, by odds.} +\item{diff_comm_q2_pre_me_abs_odds}{Absolute difference between community_q2_pre_me and the community average, by odds.} +\item{diff_comm_ave_pre_me_abs_odds}{Absolute difference between community_ave_pre_me and the community average, by odds.} +} +\description{ +Find important changes within MetaculR_questions object +} +\examples{ +\dontrun{ +questions_myPredictions_byDiff <- + MetaculR_myDiff( + questions_myPredictions) +} +} diff --git a/man/MetaculR_myPredictions.Rd b/man/MetaculR_myPredictions.Rd new file mode 100644 index 0000000..e2acca4 --- /dev/null +++ b/man/MetaculR_myPredictions.Rd @@ -0,0 +1,50 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/basics.R +\name{MetaculR_myPredictions} +\alias{MetaculR_myPredictions} +\title{Retrieve questions from Metaculus API (A wrapper for MetaculR_questions())} +\usage{ +MetaculR_myPredictions( + api_domain = "www", + order_by = "last_prediction_time", + status = "all", + search = "", + guessed_by = "", + offset = 0, + pages = 10 +) +} +\arguments{ +\item{api_domain}{Use "www" unless you have a custom Metaculus domain} + +\item{order_by}{Default is "last_prediction_time"} + +\item{status}{Choose "all", "upcoming", "open", "closed", "resolved"} + +\item{search}{Search term(s)} + +\item{guessed_by}{Generally your Metaculus_user_id} + +\item{offset}{Question offset} + +\item{pages}{Number of pages to request} +} +\value{ +A list of questions that I've predicted, ordered by last prediction time. +} +\description{ +Retrieve questions from Metaculus API (A wrapper for MetaculR_questions()) +} +\examples{ +\dontrun{ +questions_myPredictions <- + MetaculR_myPredictions( + guessed_by = Metaculus_user_id) +} +} +\seealso{ +Other Question Retrieval functions: +\code{\link{MetaculR_myPredictions_Resolved}()}, +\code{\link{MetaculR_questions}()} +} +\concept{Question Retrieval functions} diff --git a/man/MetaculR_myPredictions_Resolved.Rd b/man/MetaculR_myPredictions_Resolved.Rd new file mode 100644 index 0000000..1258d96 --- /dev/null +++ b/man/MetaculR_myPredictions_Resolved.Rd @@ -0,0 +1,50 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/basics.R +\name{MetaculR_myPredictions_Resolved} +\alias{MetaculR_myPredictions_Resolved} +\title{Retrieve questions from Metaculus API (A wrapper for MetaculR_questions())} +\usage{ +MetaculR_myPredictions_Resolved( + api_domain = "www", + order_by = "-resolve_time", + status = "resolved", + search = "", + guessed_by = "", + offset = 0, + pages = 10 +) +} +\arguments{ +\item{api_domain}{Use "www" unless you have a custom Metaculus domain} + +\item{order_by}{Default is "-resolve_time"} + +\item{status}{Default is "resolved"} + +\item{search}{Search term(s)} + +\item{guessed_by}{Generally your Metaculus_user_id} + +\item{offset}{Question offset} + +\item{pages}{Number of pages to request} +} +\value{ +A list of questions that I've predicted, ordered by last prediction time, and resolved. +} +\description{ +Retrieve questions from Metaculus API (A wrapper for MetaculR_questions()) +} +\examples{ +\dontrun{ +questions_myPredictions_resolved <- + MetaculR_myPredictions_Resolved( + guessed_by = Metaculus_user_id) +} +} +\seealso{ +Other Question Retrieval functions: +\code{\link{MetaculR_myPredictions}()}, +\code{\link{MetaculR_questions}()} +} +\concept{Question Retrieval functions} diff --git a/man/MetaculR_plot.Rd b/man/MetaculR_plot.Rd new file mode 100644 index 0000000..b84eca3 --- /dev/null +++ b/man/MetaculR_plot.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/basics.R +\name{MetaculR_plot} +\alias{MetaculR_plot} +\title{Plot the history of a single question} +\usage{ +MetaculR_plot(MetaculR_questions, Metacular_id, scale_binary = "prob") +} +\arguments{ +\item{MetaculR_questions}{A MetaculR_questions object} + +\item{Metacular_id}{The ID of the question to plot} + +\item{scale_binary}{Choose "prob", "odds", or "logodds"} +} +\value{ +A ggplot. +} +\description{ +Plot the history of a single question +} +\examples{ +\dontrun{ +MetaculR_plot( + MetaculR_questions = questions_myPredictions, + Metacular_id = 10004) +} +} diff --git a/man/MetaculR_questions.Rd b/man/MetaculR_questions.Rd new file mode 100644 index 0000000..947b071 --- /dev/null +++ b/man/MetaculR_questions.Rd @@ -0,0 +1,52 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/basics.R +\name{MetaculR_questions} +\alias{MetaculR_questions} +\title{Retrieve questions from Metaculus API} +\usage{ +MetaculR_questions( + api_domain = "www", + order_by = "last_prediction_time", + status = "all", + search = "", + guessed_by = "", + offset = 0, + pages = 10 +) +} +\arguments{ +\item{api_domain}{Use "www" unless you have a custom Metaculus domain} + +\item{order_by}{Choose "last_prediction_time", "-activity", "-votes", "-publish_time", "close_time", "resolve_time", "last_prediction_time"} + +\item{status}{Choose "all", "upcoming", "open", "closed", "resolved"} + +\item{search}{Search term(s)} + +\item{guessed_by}{Generally your Metaculus_user_id} + +\item{offset}{Question offset} + +\item{pages}{Number of pages to request} +} +\value{ +A list of questions, ordered by last prediction time. +} +\description{ +Retrieve questions from Metaculus API +} +\examples{ +\dontrun{ +questions_recent_open <- + MetaculR_questions( + order_by = "close_time", + status = "open", + guessed_by = "") +} +} +\seealso{ +Other Question Retrieval functions: +\code{\link{MetaculR_myPredictions_Resolved}()}, +\code{\link{MetaculR_myPredictions}()} +} +\concept{Question Retrieval functions} diff --git a/man/pipe.Rd b/man/pipe.Rd new file mode 100644 index 0000000..0eec752 --- /dev/null +++ b/man/pipe.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-pipe.R +\name{\%>\%} +\alias{\%>\%} +\title{Pipe operator} +\usage{ +lhs \%>\% rhs +} +\description{ +See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. +} +\keyword{internal} diff --git a/vignettes/MetaculR.Rmd b/vignettes/MetaculR.Rmd new file mode 100644 index 0000000..ef7e62a --- /dev/null +++ b/vignettes/MetaculR.Rmd @@ -0,0 +1,704 @@ +--- +title: "MetaculR" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{MetaculR} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + + + + + + + + +```r +library(MetaculR) +``` + +# Login + +Add the following lines to `.Renviron` using `usethis::edit_r_environ()`: + +``` +Metaculus_username="yourUsername" +Metaculus_password="yourPassword" +``` + +Then, login: + + +```r +Metaculus_user_id <- MetaculR_login() +``` + +# Download Your Predictions + + +```r +questions_myPredictions <- MetaculR_myPredictions(guessed_by = Metaculus_user_id) +``` + +# Analyze Your Predictions + +## How different is my last prediction from current community? + + +```r +questions_myPredictions_byDiff <- MetaculR_myDiff(questions_myPredictions) +``` + + + +```r +questions_myPredictions_byDiff %>% + dplyr::select(id, title, my_prediction, community_q2, community_q2_pre_me, diff_me_q2_abs_odds) %>% + dplyr::mutate(diff_me_q2_abs_odds = round(diff_me_q2_abs_odds, 1)) %>% + dplyr::arrange(dplyr::desc(diff_me_q2_abs_odds)) %>% + head() %>% + knitr::kable() +``` + + + +| id|title | my_prediction| community_q2| community_q2_pre_me| diff_me_q2_abs_odds| +|----:|:-------------------------------------------------------------------------------------|-------------:|------------:|-------------------:|-------------------:| +| 1634|Will US Income Inequality Increase by 2025? | 0.02| 0.53| 0.47| 55.3| +| 9933|Will any NATO country invoke Article 5 by March 31, 2022? | 0.13| 0.01| 0.02| 14.8| +| 5407|If Starlink offers an IPO before 2030, will it set a record for the largest IPO? | 0.03| 0.24| 0.30| 10.2| +| 9937|Will more than 50,000 people be killed in the Russo-Ukrainian War in 2022? | 0.15| 0.60| 0.45| 8.5| +| 2605|Will any country's military expenditure exceed that of the United States before 2030? | 0.01| 0.07| 0.08| 7.5| +| 7977|Will US core CPI inflation rise by more than 3% from December 2021 to December 2022? | 0.94| 0.70| 0.68| 6.7| + +### Plot those differences + + +```r +questions_myPredictions_byDiff %>% + dplyr::arrange(dplyr::desc(diff_me_q2_abs_odds)) %>% + dplyr::slice_head(n = 10) %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = reorder(factor(id), -diff_me_q2_abs_odds), + y = diff_me_q2_abs_odds, + fill = reorder(factor(id), -diff_me_q2_abs_odds)) + ) + + ggplot2::theme_classic() + + ggplot2::labs(x = "ID", + y = "Odds difference between me and community q2") + + ggplot2::guides(fill = FALSE) + + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1)) +``` + +![plot of chunk unnamed-chunk-8](MetaculRRMD_unnamed-chunk-8-1.png) + +## Where has community moved most since my last prediction? + + +```r +questions_myPredictions_byDiff %>% + dplyr::select(id, title, my_prediction, community_q2, community_q2_pre_me, diff_comm_q2_pre_me_abs_odds) %>% + dplyr::mutate(diff_comm_q2_pre_me_abs_odds = round(diff_comm_q2_pre_me_abs_odds, 1)) %>% + dplyr::arrange(dplyr::desc(diff_comm_q2_pre_me_abs_odds)) %>% + head() %>% + knitr::kable() +``` + + + +| id|title | my_prediction| community_q2| community_q2_pre_me| diff_comm_q2_pre_me_abs_odds| +|-----:|:-----------------------------------------------------------------------------|-------------:|------------:|-------------------:|----------------------------:| +| 10004|Will a major nuclear power plant in Germany be operational on June 1, 2023? | 0.10| 0.20| 0.56| 5.1| +| 9939|Will Kyiv fall to Russian forces by April 2022? | 0.01| 0.02| 0.09| 4.8| +| 6604|Will annual U.S. inflation reach 100% in any year before 2050? | 0.01| 0.02| 0.08| 4.3| +| 8766|Will the Omicron variant be less lethal than Delta? | 0.98| 0.98| 0.94| 3.1| +| 9933|Will any NATO country invoke Article 5 by March 31, 2022? | 0.13| 0.01| 0.02| 2.0| +| 6725|Will a large American city fully abolish their police department before 2035? | 0.01| 0.02| 0.04| 2.0| + +### Plot those differences + + +```r +MetaculR_plot(MetaculR_questions = questions_myPredictions, + Metacular_id = 10004) +``` + +![plot of chunk unnamed-chunk-10](MetaculRRMD_unnamed-chunk-10-1.png) + + +```r +MetaculR_plot(MetaculR_questions = questions_myPredictions, + Metacular_id = 6604, + scale_binary = "logodds") +``` + +![plot of chunk unnamed-chunk-11](MetaculRRMD_unnamed-chunk-11-1.png) + +## Score Predictions + +Let's see some Brier statistics on resolved questions: + + +```r +questions_myPredictions_resolved <- MetaculR_myPredictions_Resolved(guessed_by = Metaculus_user_id) +``` + + +```r +brier_me <- MetaculR_brier(questions_myPredictions_resolved) +``` + +### Plot scores + + +```r +brier_me$brier_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = name, + y = value, + fill = ID), + position = "dodge2" + ) + + ggplot2::geom_text( + ggplot2::aes(x = name, + y = value, + label = round(value, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 1), #"dodge2", + vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::labs(x = "Statistic", + y = "Value") + + ggplot2::coord_cartesian(ylim = c(0, 1)) + + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1)) +#> Warning: Removed 10 rows containing missing values (geom_col). +#> Warning: Removed 10 rows containing missing values (geom_text). +``` + +![plot of chunk unnamed-chunk-14](MetaculRRMD_unnamed-chunk-14-1.png) + +#### Histogram + + +```r +brier_me$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = centers, + y = freqs, + fill = ID), + position = ggplot2::position_dodge2(width = 0.1, preserve = "single") + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = freqs, + label = round(freqs, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + # vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, 1)) +``` + +![plot of chunk unnamed-chunk-15](MetaculRRMD_unnamed-chunk-15-1.png) + +#### Calibration + + +```r +brier_me$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_pointrange( + ggplot2::aes(x = centers, + y = obars, + ymin = ci_low, + ymax = ci_high, + color = ID), + position = ggplot2::position_dodge2(width = 0.02) + ) + + ggplot2::geom_line( + ggplot2::aes(x = centers, + y = ideal) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = obars, + label = format(round(obars, 3), nsmall = 3)), + size = 2, + position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + vjust = -0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_me$brier_bins_df $obars) * 1.1)) +``` + +![plot of chunk unnamed-chunk-16](MetaculRRMD_unnamed-chunk-16-1.png) + +## Score Predictions (Equivalent Evidentiary Bins) + +What if question bins were not 5 percentage points each, but were based on logodds? + + +```r +brier_me <- MetaculR_brier(questions_myPredictions_resolved, + thresholds = c(0, exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) / (exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) + 1), 1)) +``` + + +```r +brier_me$brier_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = name, + y = value, + fill = ID), + position = "dodge2" + ) + + ggplot2::geom_text( + ggplot2::aes(x = name, + y = value, + label = round(value, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 1), #"dodge2", + vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::labs(x = "Statistic", + y = "Value") + + ggplot2::coord_cartesian(ylim = c(0, 1)) + + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1)) +#> Warning: Removed 10 rows containing missing values (geom_col). +#> Warning: Removed 10 rows containing missing values (geom_text). +``` + +![plot of chunk unnamed-chunk-18](MetaculRRMD_unnamed-chunk-18-1.png) + +#### Histogram (Equivalent Evidentiary Bins) + + +```r +brier_me$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = centers, + y = freqs, + fill = ID), + position = ggplot2::position_dodge2(width = 0.1, preserve = "single") + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = freqs, + label = round(freqs, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 0.05), #"dodge2", + # vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, 1)) +``` + +![plot of chunk unnamed-chunk-19](MetaculRRMD_unnamed-chunk-19-1.png) + +#### Calibration (Equivalent Evidentiary Bins) + + +```r +brier_me$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_pointrange( + ggplot2::aes(x = centers, + y = obars, + ymin = ci_low, + ymax = ci_high, + color = ID), + position = ggplot2::position_dodge2(width = 0.02) + ) + + ggplot2::geom_line( + ggplot2::aes(x = centers, + y = ideal) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = obars, + label = format(round(obars, 3), nsmall = 3)), + size = 2, + position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + vjust = -0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_me$brier_bins_df$obars) * 1.1)) +``` + +![plot of chunk unnamed-chunk-20](MetaculRRMD_unnamed-chunk-20-1.png) + +# Analyze community predictions + +For questions you may not have predicted. + +## Score, Community Predictions + +Let's see some Brier statistics on resolved questions: + + +```r +questions_recent_resolved <- + MetaculR_questions( + order_by = "-resolve_time", + status= "resolved", + guessed_by = "", + pages = 32, + offset = 0) +``` + + +```r +brier_recent_resolved <- + MetaculR_brier( + questions_recent_resolved, + me = FALSE) +``` + +### Plot scores, Community Predictions + + +```r +brier_recent_resolved$brier_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = name, + y = value, + fill = ID), + position = "dodge2" + ) + + ggplot2::geom_text( + ggplot2::aes(x = name, + y = value, + label = round(value, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 1), #"dodge2", + vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::labs(x = "Statistic", + y = "Value") + + ggplot2::coord_cartesian(ylim = c(0, 1)) + + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1)) +#> Warning: Removed 17 rows containing missing values (geom_col). +#> Warning: Removed 17 rows containing missing values (geom_text). +``` + +![plot of chunk unnamed-chunk-23](MetaculRRMD_unnamed-chunk-23-1.png) + +#### Histogram, Community Predictions + + +```r +brier_recent_resolved$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = centers, + y = freqs) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = freqs, + label = round(freqs, 3)), + size = 2, + # position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + # vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$freqs) * 1.1)) +``` + +![plot of chunk unnamed-chunk-24](MetaculRRMD_unnamed-chunk-24-1.png) + +#### Calibration, Community Predictions + + +```r +brier_recent_resolved$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_pointrange( + ggplot2::aes(x = centers, + y = obars, + ymin = ci_low, + ymax = ci_high) + ) + + ggplot2::geom_line( + ggplot2::aes(x = centers, + y = ideal) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = obars, + label = format(round(obars, 3), nsmall = 3)), + size = 2, + # position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + vjust = -0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$obars) * 1.1)) +``` + +![plot of chunk unnamed-chunk-25](MetaculRRMD_unnamed-chunk-25-1.png) + +## Score Predictions, Community Predictions (Equivalent Evidentiary Bins) + + +```r +brier_recent_resolved <- + MetaculR_brier( + questions_recent_resolved, + me = FALSE, + thresholds = c(0, exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) / (exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) + 1), 1)) +``` + + +```r +brier_recent_resolved$brier_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = name, + y = value, + fill = ID), + position = "dodge2" + ) + + ggplot2::geom_text( + ggplot2::aes(x = name, + y = value, + label = round(value, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 1), #"dodge2", + vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::labs(x = "Statistic", + y = "Value") + + ggplot2::coord_cartesian(ylim = c(0, 1)) + + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1)) +#> Warning: Removed 17 rows containing missing values (geom_col). +#> Warning: Removed 17 rows containing missing values (geom_text). +``` + +![plot of chunk unnamed-chunk-27](MetaculRRMD_unnamed-chunk-27-1.png) + +#### Histogram, Community Predictions (Equivalent Evidentiary Bins) + + +```r +brier_recent_resolved$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = centers, + y = freqs) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = freqs, + label = round(freqs, 3)), + size = 2, + # position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + # vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$freqs) * 1.1)) +``` + +![plot of chunk unnamed-chunk-28](MetaculRRMD_unnamed-chunk-28-1.png) + +#### Calibration, Community Predictions (Equivalent Evidentiary Bins) + + +```r +brier_recent_resolved$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_pointrange( + ggplot2::aes(x = centers, + y = obars, + ymin = ci_low, + ymax = ci_high) + ) + + ggplot2::geom_line( + ggplot2::aes(x = centers, + y = ideal) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = obars, + label = format(round(obars, 3), nsmall = 3)), + size = 2, + # position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + vjust = -0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$obars) * 1.1)) +``` + +![plot of chunk unnamed-chunk-29](MetaculRRMD_unnamed-chunk-29-1.png) + +# Find Exciting Questions + +Various sports now have an "Excitement Index" to identify games that interest fans--maybe we can do the same for predictions? + +## Among your predictions + + +```r +questions_myPredictions_byExcitement <- MetaculR_excitement(questions_myPredictions) + +questions_myPredictions_byExcitement %>% + dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2), + Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>% + dplyr::arrange(dplyr::desc(Total_Change)) %>% + head() %>% + knitr::kable() +``` + + + +| id|title | Total_Change| Total_logodds_Change| Total_Change_Even| Total_logodds_Change_Even| +|----:|:---------------------------------------------------------------------------------|------------:|--------------------:|-----------------:|-------------------------:| +| 9790|Will Éric Zemmour be in the 2nd round of the 2022 French presidential election? | 1.12| 5.38| 0.50| 2.32| +| 8944|Will Boris Johnson be Prime Minister of the UK on June 1, 2022? | 0.35| 2.00| 0.00| 0.00| +| 8882|Will 2022 be the hottest year on record? | 0.22| 1.60| 0.11| 0.80| +| 8554|Will women receive at least 70% of bachelor's degrees in the US in the year 2050? | 0.19| 1.49| 0.10| 0.79| +| 2511|Will Emmanuel Macron be re-elected President of France in 2022? | 0.18| 1.40| 0.00| 0.00| +| 6330|Will Donald J. Trump be a candidate for President in the 2024 cycle? | 0.15| 0.79| 0.05| 0.25| + + +```r +MetaculR_plot(MetaculR_questions = questions_myPredictions, + Metacular_id = 9790) +``` + +![plot of chunk unnamed-chunk-31](MetaculRRMD_unnamed-chunk-31-1.png) + + +```r +questions_myPredictions_byExcitement %>% + dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2), + Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>% + dplyr::arrange(dplyr::desc(Total_logodds_Change)) %>% + head() %>% + knitr::kable() +``` + + + +| id|title | Total_Change| Total_logodds_Change| Total_Change_Even| Total_logodds_Change_Even| +|----:|:---------------------------------------------------------------------------------|------------:|--------------------:|-----------------:|-------------------------:| +| 9790|Will Éric Zemmour be in the 2nd round of the 2022 French presidential election? | 1.12| 5.38| 0.50| 2.32| +| 8944|Will Boris Johnson be Prime Minister of the UK on June 1, 2022? | 0.35| 2.00| 0.00| 0.00| +| 8882|Will 2022 be the hottest year on record? | 0.22| 1.60| 0.11| 0.80| +| 8554|Will women receive at least 70% of bachelor's degrees in the US in the year 2050? | 0.19| 1.49| 0.10| 0.79| +| 6604|Will annual U.S. inflation reach 100% in any year before 2050? | 0.06| 1.45| 0.00| 0.00| +| 2511|Will Emmanuel Macron be re-elected President of France in 2022? | 0.18| 1.40| 0.00| 0.00| + + +```r +MetaculR_plot(MetaculR_questions = questions_myPredictions, + Metacular_id = 6725) +``` + +![plot of chunk unnamed-chunk-33](MetaculRRMD_unnamed-chunk-33-1.png) + +## Among community predictions + +### Resolved questions + +What were the most exciting resolved questions? + + +```r +questions_recent_byExcitement <- MetaculR_excitement(questions_recent_resolved) + +questions_recent_byExcitement %>% + dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2), + Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>% + dplyr::arrange(dplyr::desc(Total_Change_Even)) %>% + head() %>% + knitr::kable() +``` + + + +| id|title | Total_Change| Total_logodds_Change| Total_Change_Even| Total_logodds_Change_Even| +|----:|:--------------------------------------------------------------------------------------------------------------------|------------:|--------------------:|-----------------:|-------------------------:| +| 8859|Will Ukraine ban wheat export before April 2023? | 0.17| 1.37| 0.11| 0.92| +| 9517|Will Russian troops enter Mariupol, Ukraine by December 31, 2022? | 0.52| 4.86| 0.09| 0.44| +| 9590|Will there be a Pi variant of COVID by Pi Day (March 14, 2022)? | 0.41| 1.95| 0.07| 0.30| +| 8898|Will Russia invade Ukrainian territory before 2023? | 0.38| 2.97| 0.06| 0.32| +| 7211|Will any body of the US federal government conclude that COVID-19 originated in a lab in Hubei before June 1st 2022? | 0.02| 0.08| 0.02| 0.08| +| 9693|Will the gray wolf be relisted as Threatened or Endangered by the US before 2030? | 0.00| 0.00| 0.00| 0.00| + + +```r +MetaculR_plot(MetaculR_questions = questions_recent_resolved, + Metacular_id = 8898) +``` + +![plot of chunk unnamed-chunk-35](MetaculRRMD_unnamed-chunk-35-1.png) + +### Open questions + +What are the most exciting questions that are still open? + + +```r +questions_recent_open <- + MetaculR_questions( + order_by = "close_time", + status = "open", + guessed_by = "") +``` + + +```r +questions_recent_open_byExcitement <- MetaculR_excitement(questions_recent_open) + +questions_recent_open_byExcitement %>% + dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2), + Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>% + dplyr::arrange(dplyr::desc(Total_logodds_Change_Even)) %>% + head() %>% + knitr::kable() +``` + + + +| id|title | Total_Change| Total_logodds_Change| Total_Change_Even| Total_logodds_Change_Even| +|----:|:------------------------------------------------------------------------------------------------------|------------:|--------------------:|-----------------:|-------------------------:| +| 9746|Will Ukraine fulfill its Minsk-II obligations in Donetsk and Luhansk Oblast by 2023? | 0.57| 11.73| 0.14| 4.72| +| 9566|Will Russian troops enter Odessa, Ukraine before December 31, 2022? | 1.18| 10.03| 0.48| 4.56| +| 9791|Will Éric Zemmour win the French presidential election in 2022? | 0.15| 9.40| 0.07| 4.35| +| 9743|Will Volodymyr Zelensky remain President of Ukraine by 2023? | 1.66| 8.13| 0.74| 3.70| +| 7237|Will Coinbase default on an obligation to hand over their users’ assets on request by the end of 2022? | 0.13| 5.05| 0.07| 2.67| +| 9584|Will Ketanji Brown Jackson be confirmed as an Associate Justice of the Supreme Court before 2023? | 0.67| 8.62| 0.12| 2.46| + + +```r +MetaculR_plot(MetaculR_questions = questions_recent_open, + Metacular_id = 9566) +``` + +![plot of chunk unnamed-chunk-38](MetaculRRMD_unnamed-chunk-38-1.png) + + diff --git a/vignettes/MetaculR.Rmd.orig b/vignettes/MetaculR.Rmd.orig new file mode 100644 index 0000000..4d15f08 --- /dev/null +++ b/vignettes/MetaculR.Rmd.orig @@ -0,0 +1,569 @@ +--- +title: "MetaculR" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{MetaculR} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r eval=FALSE, include=FALSE} +# Use `knitr::knit("vignettes/MetaculR.Rmd.orig", output = "vignettes/MetaculR.Rmd")` in the Console to pre-build the .Rmd, move the `/figure` directory into `/vignettes`, and anyone can build the .Rmd without my credentials. +``` + +```{r eval=FALSE, include=FALSE} +library(httptest) +httptest::start_vignette("MetaculR") +``` + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + fig.path = "MetaculRRMD_" +) +``` + +```{r setup} +library(MetaculR) +``` + +# Login + +Add the following lines to `.Renviron` using `usethis::edit_r_environ()`: + +``` +Metaculus_username="yourUsername" +Metaculus_password="yourPassword" +``` + +Then, login: + +```{r message=FALSE} +Metaculus_user_id <- MetaculR_login() +``` + +# Download Your Predictions + +```{r message=FALSE} +questions_myPredictions <- MetaculR_myPredictions(guessed_by = Metaculus_user_id) +``` + +# Analyze Your Predictions + +## How different is my last prediction from current community? + +```{r message=FALSE, warning=FALSE} +questions_myPredictions_byDiff <- MetaculR_myDiff(questions_myPredictions) +``` + + +```{r} +questions_myPredictions_byDiff %>% + dplyr::select(id, title, my_prediction, community_q2, community_q2_pre_me, diff_me_q2_abs_odds) %>% + dplyr::mutate(diff_me_q2_abs_odds = round(diff_me_q2_abs_odds, 1)) %>% + dplyr::arrange(dplyr::desc(diff_me_q2_abs_odds)) %>% + head() %>% + knitr::kable() +``` + +### Plot those differences + +```{r} +questions_myPredictions_byDiff %>% + dplyr::arrange(dplyr::desc(diff_me_q2_abs_odds)) %>% + dplyr::slice_head(n = 10) %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = reorder(factor(id), -diff_me_q2_abs_odds), + y = diff_me_q2_abs_odds, + fill = reorder(factor(id), -diff_me_q2_abs_odds)) + ) + + ggplot2::theme_classic() + + ggplot2::labs(x = "ID", + y = "Odds difference between me and community q2") + + ggplot2::guides(fill = FALSE) + + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1)) +``` + +## Where has community moved most since my last prediction? + +```{r} +questions_myPredictions_byDiff %>% + dplyr::select(id, title, my_prediction, community_q2, community_q2_pre_me, diff_comm_q2_pre_me_abs_odds) %>% + dplyr::mutate(diff_comm_q2_pre_me_abs_odds = round(diff_comm_q2_pre_me_abs_odds, 1)) %>% + dplyr::arrange(dplyr::desc(diff_comm_q2_pre_me_abs_odds)) %>% + head() %>% + knitr::kable() +``` + +### Plot those differences + +```{r} +MetaculR_plot(MetaculR_questions = questions_myPredictions, + Metacular_id = 10004) +``` + +```{r} +MetaculR_plot(MetaculR_questions = questions_myPredictions, + Metacular_id = 6604, + scale_binary = "logodds") +``` + +## Score Predictions + +Let's see some Brier statistics on resolved questions: + +```{r message=FALSE} +questions_myPredictions_resolved <- MetaculR_myPredictions_Resolved(guessed_by = Metaculus_user_id) +``` + +```{r} +brier_me <- MetaculR_brier(questions_myPredictions_resolved) +``` + +### Plot scores + +```{r} +brier_me$brier_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = name, + y = value, + fill = ID), + position = "dodge2" + ) + + ggplot2::geom_text( + ggplot2::aes(x = name, + y = value, + label = round(value, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 1), #"dodge2", + vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::labs(x = "Statistic", + y = "Value") + + ggplot2::coord_cartesian(ylim = c(0, 1)) + + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1)) +``` + +#### Histogram + +```{r} +brier_me$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = centers, + y = freqs, + fill = ID), + position = ggplot2::position_dodge2(width = 0.1, preserve = "single") + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = freqs, + label = round(freqs, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + # vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, 1)) +``` + +#### Calibration + +```{r} +brier_me$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_pointrange( + ggplot2::aes(x = centers, + y = obars, + ymin = ci_low, + ymax = ci_high, + color = ID), + position = ggplot2::position_dodge2(width = 0.02) + ) + + ggplot2::geom_line( + ggplot2::aes(x = centers, + y = ideal) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = obars, + label = format(round(obars, 3), nsmall = 3)), + size = 2, + position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + vjust = -0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_me$brier_bins_df $obars) * 1.1)) +``` + +## Score Predictions (Equivalent Evidentiary Bins) + +What if question bins were not 5 percentage points each, but were based on logodds? + +```{r} +brier_me <- MetaculR_brier(questions_myPredictions_resolved, + thresholds = c(0, exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) / (exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) + 1), 1)) +``` + +```{r} +brier_me$brier_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = name, + y = value, + fill = ID), + position = "dodge2" + ) + + ggplot2::geom_text( + ggplot2::aes(x = name, + y = value, + label = round(value, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 1), #"dodge2", + vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::labs(x = "Statistic", + y = "Value") + + ggplot2::coord_cartesian(ylim = c(0, 1)) + + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1)) +``` + +#### Histogram (Equivalent Evidentiary Bins) + +```{r} +brier_me$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = centers, + y = freqs, + fill = ID), + position = ggplot2::position_dodge2(width = 0.1, preserve = "single") + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = freqs, + label = round(freqs, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 0.05), #"dodge2", + # vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, 1)) +``` + +#### Calibration (Equivalent Evidentiary Bins) + +```{r} +brier_me$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_pointrange( + ggplot2::aes(x = centers, + y = obars, + ymin = ci_low, + ymax = ci_high, + color = ID), + position = ggplot2::position_dodge2(width = 0.02) + ) + + ggplot2::geom_line( + ggplot2::aes(x = centers, + y = ideal) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = obars, + label = format(round(obars, 3), nsmall = 3)), + size = 2, + position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + vjust = -0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_me$brier_bins_df$obars) * 1.1)) +``` + +# Analyze community predictions + +For questions you may not have predicted. + +## Score, Community Predictions + +Let's see some Brier statistics on resolved questions: + +```{r message=FALSE} +questions_recent_resolved <- + MetaculR_questions( + order_by = "-resolve_time", + status= "resolved", + guessed_by = "", + pages = 32, + offset = 0) +``` + +```{r} +brier_recent_resolved <- + MetaculR_brier( + questions_recent_resolved, + me = FALSE) +``` + +### Plot scores, Community Predictions + +```{r} +brier_recent_resolved$brier_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = name, + y = value, + fill = ID), + position = "dodge2" + ) + + ggplot2::geom_text( + ggplot2::aes(x = name, + y = value, + label = round(value, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 1), #"dodge2", + vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::labs(x = "Statistic", + y = "Value") + + ggplot2::coord_cartesian(ylim = c(0, 1)) + + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1)) +``` + +#### Histogram, Community Predictions + +```{r} +brier_recent_resolved$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = centers, + y = freqs) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = freqs, + label = round(freqs, 3)), + size = 2, + # position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + # vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$freqs) * 1.1)) +``` + +#### Calibration, Community Predictions + +```{r} +brier_recent_resolved$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_pointrange( + ggplot2::aes(x = centers, + y = obars, + ymin = ci_low, + ymax = ci_high) + ) + + ggplot2::geom_line( + ggplot2::aes(x = centers, + y = ideal) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = obars, + label = format(round(obars, 3), nsmall = 3)), + size = 2, + # position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + vjust = -0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$obars) * 1.1)) +``` + +## Score Predictions, Community Predictions (Equivalent Evidentiary Bins) + +```{r} +brier_recent_resolved <- + MetaculR_brier( + questions_recent_resolved, + me = FALSE, + thresholds = c(0, exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) / (exp(seq(from = -log(99), to = log(99), by = log(99) / 5)) + 1), 1)) +``` + +```{r} +brier_recent_resolved$brier_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = name, + y = value, + fill = ID), + position = "dodge2" + ) + + ggplot2::geom_text( + ggplot2::aes(x = name, + y = value, + label = round(value, 3)), + size = 2, + position = ggplot2::position_dodge2(width = 1), #"dodge2", + vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::labs(x = "Statistic", + y = "Value") + + ggplot2::coord_cartesian(ylim = c(0, 1)) + + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, vjust = 1, hjust = 1)) +``` + +#### Histogram, Community Predictions (Equivalent Evidentiary Bins) + +```{r} +brier_recent_resolved$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_col( + ggplot2::aes(x = centers, + y = freqs) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = freqs, + label = round(freqs, 3)), + size = 2, + # position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + # vjust = 0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$freqs) * 1.1)) +``` + +#### Calibration, Community Predictions (Equivalent Evidentiary Bins) + +```{r} +brier_recent_resolved$brier_bins_df %>% + ggplot2::ggplot() + + ggplot2::geom_pointrange( + ggplot2::aes(x = centers, + y = obars, + ymin = ci_low, + ymax = ci_high) + ) + + ggplot2::geom_line( + ggplot2::aes(x = centers, + y = ideal) + ) + + ggplot2::geom_text( + ggplot2::aes(x = centers, + y = obars, + label = format(round(obars, 3), nsmall = 3)), + size = 2, + # position = ggplot2::position_dodge2(width = 0.1), #"dodge2", + vjust = -0.5, + hjust = -0.25, + angle = 90) + + ggplot2::theme_classic() + + ggplot2::coord_cartesian(ylim = c(0, max(brier_recent_resolved$brier_bins_df$obars) * 1.1)) +``` + +# Find Exciting Questions + +Various sports now have an "Excitement Index" to identify games that interest fans--maybe we can do the same for predictions? + +## Among your predictions + +```{r} +questions_myPredictions_byExcitement <- MetaculR_excitement(questions_myPredictions) + +questions_myPredictions_byExcitement %>% + dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2), + Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>% + dplyr::arrange(dplyr::desc(Total_Change)) %>% + head() %>% + knitr::kable() +``` + +```{r} +MetaculR_plot(MetaculR_questions = questions_myPredictions, + Metacular_id = 9790) +``` + +```{r} +questions_myPredictions_byExcitement %>% + dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2), + Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>% + dplyr::arrange(dplyr::desc(Total_logodds_Change)) %>% + head() %>% + knitr::kable() +``` + +```{r} +MetaculR_plot(MetaculR_questions = questions_myPredictions, + Metacular_id = 6725) +``` + +## Among community predictions + +### Resolved questions + +What were the most exciting resolved questions? + +```{r} +questions_recent_byExcitement <- MetaculR_excitement(questions_recent_resolved) + +questions_recent_byExcitement %>% + dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2), + Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>% + dplyr::arrange(dplyr::desc(Total_Change_Even)) %>% + head() %>% + knitr::kable() +``` + +```{r} +MetaculR_plot(MetaculR_questions = questions_recent_resolved, + Metacular_id = 8898) +``` + +### Open questions + +What are the most exciting questions that are still open? + +```{r message=FALSE} +questions_recent_open <- + MetaculR_questions( + order_by = "close_time", + status = "open", + guessed_by = "") +``` + +```{r} +questions_recent_open_byExcitement <- MetaculR_excitement(questions_recent_open) + +questions_recent_open_byExcitement %>% + dplyr::mutate(Total_logodds_Change = round(Total_logodds_Change, 2), + Total_logodds_Change_Even = round(Total_logodds_Change_Even, 2)) %>% + dplyr::arrange(dplyr::desc(Total_logodds_Change_Even)) %>% + head() %>% + knitr::kable() +``` + +```{r} +MetaculR_plot(MetaculR_questions = questions_recent_open, + Metacular_id = 9566) +``` + +```{r eval=FALSE, include=FALSE} +httptest::end_vignette() +``` diff --git a/vignettes/MetaculRRMD_unnamed-chunk-10-1.png b/vignettes/MetaculRRMD_unnamed-chunk-10-1.png new file mode 100644 index 0000000..fdb8514 Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-10-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-11-1.png b/vignettes/MetaculRRMD_unnamed-chunk-11-1.png new file mode 100644 index 0000000..af09849 Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-11-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-14-1.png b/vignettes/MetaculRRMD_unnamed-chunk-14-1.png new file mode 100644 index 0000000..c3d69b3 Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-14-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-15-1.png b/vignettes/MetaculRRMD_unnamed-chunk-15-1.png new file mode 100644 index 0000000..b6a9db6 Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-15-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-16-1.png b/vignettes/MetaculRRMD_unnamed-chunk-16-1.png new file mode 100644 index 0000000..1bf33bd Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-16-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-18-1.png b/vignettes/MetaculRRMD_unnamed-chunk-18-1.png new file mode 100644 index 0000000..00dd2c5 Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-18-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-19-1.png b/vignettes/MetaculRRMD_unnamed-chunk-19-1.png new file mode 100644 index 0000000..7f6ea30 Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-19-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-20-1.png b/vignettes/MetaculRRMD_unnamed-chunk-20-1.png new file mode 100644 index 0000000..7ec020b Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-20-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-23-1.png b/vignettes/MetaculRRMD_unnamed-chunk-23-1.png new file mode 100644 index 0000000..1eccff2 Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-23-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-24-1.png b/vignettes/MetaculRRMD_unnamed-chunk-24-1.png new file mode 100644 index 0000000..1edefc8 Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-24-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-25-1.png b/vignettes/MetaculRRMD_unnamed-chunk-25-1.png new file mode 100644 index 0000000..b1b2f17 Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-25-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-27-1.png b/vignettes/MetaculRRMD_unnamed-chunk-27-1.png new file mode 100644 index 0000000..a290cb7 Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-27-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-28-1.png b/vignettes/MetaculRRMD_unnamed-chunk-28-1.png new file mode 100644 index 0000000..a8464a7 Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-28-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-29-1.png b/vignettes/MetaculRRMD_unnamed-chunk-29-1.png new file mode 100644 index 0000000..c2bf779 Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-29-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-31-1.png b/vignettes/MetaculRRMD_unnamed-chunk-31-1.png new file mode 100644 index 0000000..cd4b426 Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-31-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-33-1.png b/vignettes/MetaculRRMD_unnamed-chunk-33-1.png new file mode 100644 index 0000000..1ab47ab Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-33-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-35-1.png b/vignettes/MetaculRRMD_unnamed-chunk-35-1.png new file mode 100644 index 0000000..ef0ea8c Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-35-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-38-1.png b/vignettes/MetaculRRMD_unnamed-chunk-38-1.png new file mode 100644 index 0000000..fae3e03 Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-38-1.png differ diff --git a/vignettes/MetaculRRMD_unnamed-chunk-8-1.png b/vignettes/MetaculRRMD_unnamed-chunk-8-1.png new file mode 100644 index 0000000..9bcce8e Binary files /dev/null and b/vignettes/MetaculRRMD_unnamed-chunk-8-1.png differ