From 3acbd4ee5ebdb1eea25801dbdef59ec02eaadd3c Mon Sep 17 00:00:00 2001 From: Louis Lacoste Date: Fri, 6 Sep 2024 14:25:22 +0200 Subject: [PATCH 1/2] BipartiteSBM_fit: unnaming penalty and modifying test accordingly --- R/R6Class-BipartiteSBM_fit.R | 87 ++++++++-------- tests/testthat/test-BipartiteSBM_fit.R | 137 ++++++++++++------------- 2 files changed, 113 insertions(+), 111 deletions(-) diff --git a/R/R6Class-BipartiteSBM_fit.R b/R/R6Class-BipartiteSBM_fit.R index 0c15dc14..cc56e8fa 100644 --- a/R/R6Class-BipartiteSBM_fit.R +++ b/R/R6Class-BipartiteSBM_fit.R @@ -9,14 +9,14 @@ BipartiteSBM_fit <- classname = "BipartiteSBM_fit", inherit = BipartiteSBM, private = list( - J = NULL, # approximation of the log-likelihood - vICL = NULL, # approximation of the ICL - BMobject = NULL, # blockmodels output (used to stored the optimization results when blockmodels is used) + J = NULL, # approximation of the log-likelihood + vICL = NULL, # approximation of the ICL + BMobject = NULL, # blockmodels output (used to stored the optimization results when blockmodels is used) import_from_BM = function(index = which.max(private$BMobject$ICL)) { - private$J <- private$BMobject$PL[index] - private$vICL <- private$BMobject$ICL[index] - parameters <- private$BMobject$model_parameters[[index]] - private$beta <- parameters$beta ## NULL if no covariates + private$J <- private$BMobject$PL[index] + private$vICL <- private$BMobject$ICL[index] + parameters <- private$BMobject$model_parameters[[index]] + private$beta <- parameters$beta ## NULL if no covariates private$theta <- switch(private$BMobject$model_name, "bernoulli" = list(mean = parameters$pi), "bernoulli_covariates" = list(mean = .logistic(parameters$m)), @@ -32,7 +32,6 @@ BipartiteSBM_fit <- col = private$BMobject$memberships[[index]]$Z2 ) private$pi <- lapply(private$Z, colMeans) - } ), public = list( @@ -41,10 +40,9 @@ BipartiteSBM_fit <- #' @param model character (\code{'bernoulli'}, \code{'poisson'}, \code{'gaussian'}) #' @param dimLabels labels of each dimension (in row, in columns) #' @param covarList and optional list of covariates, each of whom must have the same dimension as \code{incidenceMatrix} - initialize = function(incidenceMatrix, model, dimLabels=c(row="row", col="col"), covarList=list()) { - + initialize = function(incidenceMatrix, model, dimLabels = c(row = "row", col = "col"), covarList = list()) { ## SANITY CHECKS on data - stopifnot(is.matrix(incidenceMatrix)) # must be a matrix + stopifnot(is.matrix(incidenceMatrix)) # must be a matrix stopifnot(all(sapply(covarList, nrow) == nrow(incidenceMatrix))) # consistency of the covariates stopifnot(all(sapply(covarList, ncol) == ncol(incidenceMatrix))) # with the network data @@ -57,37 +55,38 @@ BipartiteSBM_fit <- ) ## INITIALIZE THE SBM OBJECT ACCORDING TO THE DATA - super$initialize(model = model, - nbNodes = dim(incidenceMatrix), - blockProp = rep(list(vector("numeric", 0)), 2), - connectParam = connectParam, - dimLabels = dimLabels, - covarList = covarList) + super$initialize( + model = model, + nbNodes = dim(incidenceMatrix), + blockProp = rep(list(vector("numeric", 0)), 2), + connectParam = connectParam, + dimLabels = dimLabels, + covarList = covarList + ) private$Y <- incidenceMatrix }, #' @description function to perform optimization #' @param estimOptions a list of parameters controlling the inference algorithm and model selection. See details. #' @inherit estimateSimpleSBM details - optimize = function(estimOptions = list()){ - - if(private$model == 'ZIgaussian') stop("Inference not yet implemented for Bipartite ZI gaussian network") + optimize = function(estimOptions = list()) { + if (private$model == "ZIgaussian") stop("Inference not yet implemented for Bipartite ZI gaussian network") currentOptions <- list( - verbosity = 3, - plot = TRUE, - exploreFactor = 1.5, - exploreMin = 4, - exploreMax = Inf, - nbBlocksRange = c(4,Inf), - nbCores = 2, - fast = TRUE + verbosity = 3, + plot = TRUE, + exploreFactor = 1.5, + exploreMin = 4, + exploreMax = Inf, + nbBlocksRange = c(4, Inf), + nbCores = 2, + fast = TRUE ) currentOptions[names(estimOptions)] <- estimOptions ## Transform estimOptions to a suited for blockmodels list of options blockmodelsOptions <- list( verbosity = currentOptions$verbosity, - plotting = if(currentOptions$plot) character(0) else "", + plotting = if (currentOptions$plot) character(0) else "", explore_min = currentOptions$exploreMin, explore_max = currentOptions$exploreMax, ncores = currentOptions$nbCores, @@ -103,8 +102,8 @@ BipartiteSBM_fit <- ## model construction - model_type <- ifelse(self$nbCovariates > 0, paste0(private$model,"_covariates"), private$model) - if (model_type == 'bernoulli_covariates' & fast == TRUE) model_type <- 'bernoulli_covariates_fast' + model_type <- ifelse(self$nbCovariates > 0, paste0(private$model, "_covariates"), private$model) + if (model_type == "bernoulli_covariates" & fast == TRUE) model_type <- "bernoulli_covariates_fast" private$BMobject <- do.call(paste0("BM_", model_type), args) ## performing estimation @@ -137,7 +136,7 @@ BipartiteSBM_fit <- }, #' @description show method #' @param type character used to specify the type of SBM - show = function(type = "Fit of a Bipartite Stochastic Block Model"){ + show = function(type = "Fit of a Bipartite Stochastic Block Model") { super$show(type) cat("* Additional fields\n") cat(" $probMemberships, $loglik, $ICL, $storedModels, \n") @@ -147,13 +146,21 @@ BipartiteSBM_fit <- ), active = list( #' @field loglik double: approximation of the log-likelihood (variational lower bound) reached - loglik = function(value) {private$J}, + loglik = function(value) { + private$J + }, #' @field ICL double: value of the integrated classification log-likelihood - ICL = function(value) {private$vICL}, + ICL = function(value) { + private$vICL + }, #' @field penalty double, value of the penalty term in ICL - penalty = function(value) {(self$nbConnectParam + self$nbCovariates) * log(self$nbDyads) + (self$nbBlocks[1]-1) * log(private$dim[1]) + (self$nbBlocks[2]-1) * log(private$dim[2])}, + penalty = function(value) { + unname((self$nbConnectParam + self$nbCovariates) * log(self$nbDyads) + (self$nbBlocks[1] - 1) * log(private$dim[1]) + (self$nbBlocks[2] - 1) * log(private$dim[2])) + }, #' @field entropy double, value of the entropy due to the clustering distribution - entropy = function(value) {-sum(.xlogx(private$Z[[1]]))-sum(.xlogx(private$Z[[2]]))}, + entropy = function(value) { + -sum(.xlogx(private$Z[[1]])) - sum(.xlogx(private$Z[[2]])) + }, #' @field storedModels data.frame of all models fitted (and stored) during the optimization storedModels = function(value) { rowBlocks <- c(0, unlist(sapply(private$BMobject$memberships, function(m) ncol(m$Z1)))) @@ -161,12 +168,12 @@ BipartiteSBM_fit <- nbConnectParam <- c(NA, unlist(sapply(private$BMobject$model_parameters, function(param) param$n_parameters))) U <- data.frame( indexModel = rowBlocks + colBlocks, - nbParams = nbConnectParam + rowBlocks + colBlocks - 2, + nbParams = nbConnectParam + rowBlocks + colBlocks - 2, rowBlocks = rowBlocks, colBlocks = colBlocks, - nbBlocks = rowBlocks + colBlocks, - ICL = private$BMobject$ICL, - loglik = private$BMobject$PL + nbBlocks = rowBlocks + colBlocks, + ICL = private$BMobject$ICL, + loglik = private$BMobject$PL ) U[!is.na(U$nbParams), , drop = FALSE] } diff --git a/tests/testthat/test-BipartiteSBM_fit.R b/tests/testthat/test-BipartiteSBM_fit.R index 5edfac5a..c2281c85 100644 --- a/tests/testthat/test-BipartiteSBM_fit.R +++ b/tests/testthat/test-BipartiteSBM_fit.R @@ -1,26 +1,27 @@ set.seed(1234) -rmse <- function(theta, theta_star) { sqrt(sum((theta - theta_star)^2)/sum(theta_star^2)) } +rmse <- function(theta, theta_star) { + sqrt(sum((theta - theta_star)^2) / sum(theta_star^2)) +} ## Common parameters -nbNodes <- c(100, 120) -blockProp <- list(row = c(.5, .5), col = c(1/3, 1/3, 1/3)) # group proportions +nbNodes <- c(100, 120) +blockProp <- list(row = c(.5, .5), col = c(1 / 3, 1 / 3, 1 / 3)) # group proportions nbBlocks <- sapply(blockProp, length) test_that("BipartiteSBM_fit 'Bernoulli' model, undirected, no covariate", { - ## BIPARTITE UNDIRECTED BERNOULLI SBM - means <- matrix(c(0.05, 0.95, 0.4, 0.75, 0.15, 0.6), 2, 3) # connectivity matrix + means <- matrix(c(0.05, 0.95, 0.4, 0.75, 0.15, 0.6), 2, 3) # connectivity matrix connectParam <- list(mean = means) ## Basic construction - check for wrong specifications - mySampler <- BipartiteSBM$new('bernoulli', nbNodes, blockProp, connectParam) + mySampler <- BipartiteSBM$new("bernoulli", nbNodes, blockProp, connectParam) mySampler$rMemberships(store = TRUE) mySampler$rEdges(store = TRUE) ## Construction---------------------------------------------------------------- - mySBM <- BipartiteSBM_fit$new(mySampler$networkData, 'bernoulli') - expect_error(BipartiteSBM_fit$new(SamplerBernoulli$networkData, 'bernouilli')) + mySBM <- BipartiteSBM_fit$new(mySampler$networkData, "bernoulli") + expect_error(BipartiteSBM_fit$new(SamplerBernoulli$networkData, "bernouilli")) ## Checking class expect_true(inherits(mySBM, "SBM")) @@ -29,9 +30,9 @@ test_that("BipartiteSBM_fit 'Bernoulli' model, undirected, no covariate", { ## Checking field access and format prior to estimation ## parameters - expect_equal(mySBM$modelName, 'bernoulli') + expect_equal(mySBM$modelName, "bernoulli") expect_equal(unname(mySBM$nbNodes), nbNodes) - expect_equal(mySBM$nbDyads, nbNodes[1]*nbNodes[2]) + expect_equal(mySBM$nbDyads, nbNodes[1] * nbNodes[2]) expect_true(is.matrix(mySBM$connectParam$mean)) ## covariates @@ -41,18 +42,18 @@ test_that("BipartiteSBM_fit 'Bernoulli' model, undirected, no covariate", { expect_equal(mySBM$covarParam, numeric(0)) ## S3 methods - expect_equal(coef(mySBM, 'connectivity'), mySBM$connectParam) - expect_equal(coef(mySBM, 'block') , mySBM$blockProp) - expect_equal(coef(mySBM, 'covariates') , mySBM$covarParam) + expect_equal(coef(mySBM, "connectivity"), mySBM$connectParam) + expect_equal(coef(mySBM, "block"), mySBM$blockProp) + expect_equal(coef(mySBM, "covariates"), mySBM$covarParam) ## Estimation----------------------------------------------------------------- - BM_out <- mySBM$optimize(estimOptions=list(verbosity = 0)) + BM_out <- mySBM$optimize(estimOptions = list(verbosity = 0)) mySBM$setModel(4) expect_equal(mySBM$nbConnectParam, unname(nbBlocks[1] * nbBlocks[2])) - expect_equal(mySBM$penalty, nbBlocks[1] * nbBlocks[2] * log(nbNodes[1] * nbNodes[2]) + (nbBlocks[1] - 1) * log(nbNodes[1]) + (nbBlocks[2] - 1) * log(nbNodes[2])) + expect_equal(mySBM$penalty, unname(nbBlocks[1] * nbBlocks[2] * log(nbNodes[1] * nbNodes[2]) + (nbBlocks[1] - 1) * log(nbNodes[1]) + (nbBlocks[2] - 1) * log(nbNodes[2]))) expect_equal(mySBM$entropy, -sum(mySBM$probMemberships[[1]] * log(mySBM$probMemberships[[1]])) - -sum(mySBM$probMemberships[[2]] * log(mySBM$probMemberships[[2]]))) + - sum(mySBM$probMemberships[[2]] * log(mySBM$probMemberships[[2]]))) ## Expectation expect_equal(dim(mySBM$expectation), nbNodes) @@ -68,9 +69,9 @@ test_that("BipartiteSBM_fit 'Bernoulli' model, undirected, no covariate", { expect_equal(sort(unique(mySBM$memberships[[2]])), 1:nbBlocks[2]) ## S3 methods - expect_equal(coef(mySBM, 'connectivity'), mySBM$connectParam) - expect_equal(coef(mySBM, 'block') , mySBM$blockProp) - expect_equal(coef(mySBM, 'covariates') , mySBM$covarParam) + expect_equal(coef(mySBM, "connectivity"), mySBM$connectParam) + expect_equal(coef(mySBM, "block"), mySBM$blockProp) + expect_equal(coef(mySBM, "covariates"), mySBM$covarParam) expect_equal(mySBM$predict(), predict(mySBM)) expect_equal(fitted(mySBM), predict(mySBM)) @@ -81,28 +82,26 @@ test_that("BipartiteSBM_fit 'Bernoulli' model, undirected, no covariate", { ## prediction wrt BM for (Q in mySBM$storedModels$indexModel) { - pred_bm <- BM_out$prediction(Q = Q) - mySBM$setModel(Q-1) + pred_bm <- BM_out$prediction(Q = Q) + mySBM$setModel(Q - 1) pred_sbm <- predict(mySBM) - expect_lt( rmse(pred_bm, pred_sbm), 1e-12) + expect_lt(rmse(pred_bm, pred_sbm), 1e-12) } - }) test_that("BipartiteSBM_fit 'Poisson' model, undirected, no covariate", { - ## SIMPLE DIRECTED POISSON SBM - means <- matrix(c(10, 5, 7, 15, 20, 8), 2, 3) # connectivity matrix + means <- matrix(c(10, 5, 7, 15, 20, 8), 2, 3) # connectivity matrix connectParam <- list(mean = means) ## Basic construction - check for wrong specifications - mySampler <- BipartiteSBM$new('poisson', nbNodes, blockProp, connectParam) + mySampler <- BipartiteSBM$new("poisson", nbNodes, blockProp, connectParam) mySampler$rMemberships(store = TRUE) mySampler$rEdges(store = TRUE) ## Construction---------------------------------------------------------------- - mySBM <- BipartiteSBM_fit$new(mySampler$networkData, 'poisson') - expect_error(BipartiteSBM_fit$new(SamplerBernoulli$networkData, 'poison')) + mySBM <- BipartiteSBM_fit$new(mySampler$networkData, "poisson") + expect_error(BipartiteSBM_fit$new(SamplerBernoulli$networkData, "poison")) ## Checking class expect_true(inherits(mySBM, "SBM")) @@ -111,9 +110,9 @@ test_that("BipartiteSBM_fit 'Poisson' model, undirected, no covariate", { ## Checking field access and format prior to estimation ## parameters - expect_equal(mySBM$modelName, 'poisson') + expect_equal(mySBM$modelName, "poisson") expect_equal(unname(mySBM$nbNodes), nbNodes) - expect_equal(mySBM$nbDyads, nbNodes[1]*nbNodes[2]) + expect_equal(mySBM$nbDyads, nbNodes[1] * nbNodes[2]) expect_true(is.matrix(mySBM$connectParam$mean)) ## covariates @@ -123,12 +122,12 @@ test_that("BipartiteSBM_fit 'Poisson' model, undirected, no covariate", { expect_equal(mySBM$covarParam, numeric(0)) ## S3 methods - expect_equal(coef(mySBM, 'connectivity'), mySBM$connectParam) - expect_equal(coef(mySBM, 'block') , mySBM$blockProp) - expect_equal(coef(mySBM, 'covariates') , mySBM$covarParam) + expect_equal(coef(mySBM, "connectivity"), mySBM$connectParam) + expect_equal(coef(mySBM, "block"), mySBM$blockProp) + expect_equal(coef(mySBM, "covariates"), mySBM$covarParam) ## Estimation----------------------------------------------------------------- - BM_out <- mySBM$optimize(estimOptions=list(verbosity = 0)) + BM_out <- mySBM$optimize(estimOptions = list(verbosity = 0)) mySBM$setModel(4) ## Expectation @@ -144,9 +143,9 @@ test_that("BipartiteSBM_fit 'Poisson' model, undirected, no covariate", { expect_equal(sort(unique(mySBM$memberships[[2]])), 1:nbBlocks[2]) ## S3 methods - expect_equal(coef(mySBM, 'connectivity'), mySBM$connectParam) - expect_equal(coef(mySBM, 'block') , mySBM$blockProp) - expect_equal(coef(mySBM, 'covariates') , mySBM$covarParam) + expect_equal(coef(mySBM, "connectivity"), mySBM$connectParam) + expect_equal(coef(mySBM, "block"), mySBM$blockProp) + expect_equal(coef(mySBM, "covariates"), mySBM$covarParam) expect_equal(mySBM$predict(), predict(mySBM)) expect_equal(fitted(mySBM), predict(mySBM)) @@ -157,28 +156,26 @@ test_that("BipartiteSBM_fit 'Poisson' model, undirected, no covariate", { ## prediction wrt BM for (Q in mySBM$storedModels$indexModel) { - pred_bm <- BM_out$prediction(Q = Q) - mySBM$setModel(Q-1) + pred_bm <- BM_out$prediction(Q = Q) + mySBM$setModel(Q - 1) pred_sbm <- predict(mySBM) - expect_lt( rmse(pred_bm, pred_sbm), 1e-12) + expect_lt(rmse(pred_bm, pred_sbm), 1e-12) } - }) test_that("BipartiteSBM_fit 'Gaussian' model, undirected, no covariate", { - ## SIMPLE UNDIRECTED GAUSSIAN SBM - means <- matrix(c(0.05, 0.95, 0.4, 0.98, 0.15, 0.6), 2, 3) # connectivity matrix + means <- matrix(c(0.05, 0.95, 0.4, 0.98, 0.15, 0.6), 2, 3) # connectivity matrix connectParam <- list(mean = means, var = .1) ## Basic construction - check for wrong specifications - mySampler <- BipartiteSBM$new('gaussian', nbNodes, blockProp, connectParam) + mySampler <- BipartiteSBM$new("gaussian", nbNodes, blockProp, connectParam) mySampler$rMemberships(store = TRUE) mySampler$rEdges(store = TRUE) ## Construction---------------------------------------------------------------- - mySBM <- BipartiteSBM_fit$new(mySampler$networkData, 'gaussian') - expect_error(BipartiteSBM_fit$new(SamplerBernoulli$networkData, 'groß')) + mySBM <- BipartiteSBM_fit$new(mySampler$networkData, "gaussian") + expect_error(BipartiteSBM_fit$new(SamplerBernoulli$networkData, "groß")) ## Checking class expect_true(inherits(mySBM, "SBM")) @@ -187,9 +184,9 @@ test_that("BipartiteSBM_fit 'Gaussian' model, undirected, no covariate", { ## Checking field access and format prior to estimation ## parameters - expect_equal(mySBM$modelName, 'gaussian') + expect_equal(mySBM$modelName, "gaussian") expect_equal(unname(mySBM$nbNodes), nbNodes) - expect_equal(mySBM$nbDyads, nbNodes[1]*nbNodes[2]) + expect_equal(mySBM$nbDyads, nbNodes[1] * nbNodes[2]) expect_true(is.matrix(mySBM$connectParam$mean)) ## covariates @@ -199,12 +196,12 @@ test_that("BipartiteSBM_fit 'Gaussian' model, undirected, no covariate", { expect_equal(mySBM$covarParam, numeric(0)) ## S3 methods - expect_equal(coef(mySBM, 'connectivity'), mySBM$connectParam) - expect_equal(coef(mySBM, 'block') , mySBM$blockProp) - expect_equal(coef(mySBM, 'covariates') , mySBM$covarParam) + expect_equal(coef(mySBM, "connectivity"), mySBM$connectParam) + expect_equal(coef(mySBM, "block"), mySBM$blockProp) + expect_equal(coef(mySBM, "covariates"), mySBM$covarParam) ## Estimation----------------------------------------------------------------- - BM_out <- mySBM$optimize(estimOptions=list(verbosity = 0)) + BM_out <- mySBM$optimize(estimOptions = list(verbosity = 0)) mySBM$setModel(4) ## Expectation @@ -219,9 +216,9 @@ test_that("BipartiteSBM_fit 'Gaussian' model, undirected, no covariate", { expect_equal(sort(unique(mySBM$memberships[[2]])), 1:nbBlocks[2]) ## S3 methods - expect_equal(coef(mySBM, 'connectivity'), mySBM$connectParam) - expect_equal(coef(mySBM, 'block') , mySBM$blockProp) - expect_equal(coef(mySBM, 'covariates') , mySBM$covarParam) + expect_equal(coef(mySBM, "connectivity"), mySBM$connectParam) + expect_equal(coef(mySBM, "block"), mySBM$blockProp) + expect_equal(coef(mySBM, "covariates"), mySBM$covarParam) expect_equal(mySBM$predict(), predict(mySBM)) expect_equal(fitted(mySBM), predict(mySBM)) @@ -232,31 +229,29 @@ test_that("BipartiteSBM_fit 'Gaussian' model, undirected, no covariate", { ## prediction wrt BM for (Q in mySBM$storedModels$indexModel) { - pred_bm <- BM_out$prediction(Q = Q) - mySBM$setModel(Q-1) + pred_bm <- BM_out$prediction(Q = Q) + mySBM$setModel(Q - 1) pred_sbm <- predict(mySBM) - expect_lt( rmse(pred_bm, pred_sbm), 1e-12) + expect_lt(rmse(pred_bm, pred_sbm), 1e-12) } - }) test_that("active bindings are working in the class", { - A <- matrix(rbinom(200,1,.2),20,10) + A <- matrix(rbinom(200, 1, .2), 20, 10) - myBipartite <- BipartiteSBM_fit$new(incidenceMatrix = A,model = "bernoulli",dimLabels = c("Actor","Stuff")) + myBipartite <- BipartiteSBM_fit$new(incidenceMatrix = A, model = "bernoulli", dimLabels = c("Actor", "Stuff")) - tau1 <- matrix(runif(20*2),20,2) + tau1 <- matrix(runif(20 * 2), 20, 2) tau1 <- tau1 / rowSums(tau1) - tau2 <- matrix(runif(10*3),10,3) + tau2 <- matrix(runif(10 * 3), 10, 3) tau2 <- tau2 / rowSums(tau2) - myBipartite$probMemberships <- list(tau1,tau2) - myBipartite$blockProp <- list(colMeans(tau1),colMeans(tau2)) - myBipartite$connectParam <- list(mean = matrix(runif(3*2),3,2)) - - expect_equal(unname(myBipartite$nbNodes),c(20,10)) + myBipartite$probMemberships <- list(tau1, tau2) + myBipartite$blockProp <- list(colMeans(tau1), colMeans(tau2)) + myBipartite$connectParam <- list(mean = matrix(runif(3 * 2), 3, 2)) - expect_equal(myBipartite$memberships[[1]], 1+(tau1[,1]<.5)*1) - expect_equal(dim(myBipartite$connectParam$mean),c(3,2)) - expect_equal(length(myBipartite$blockProp),2) + expect_equal(unname(myBipartite$nbNodes), c(20, 10)) + expect_equal(myBipartite$memberships[[1]], 1 + (tau1[, 1] < .5) * 1) + expect_equal(dim(myBipartite$connectParam$mean), c(3, 2)) + expect_equal(length(myBipartite$blockProp), 2) }) From d494e8c19059b40bf340f1f32a3f2e7c61985e7b Mon Sep 17 00:00:00 2001 From: Louis Lacoste Date: Fri, 6 Sep 2024 14:31:57 +0200 Subject: [PATCH 2/2] readme: fixing CRAN status badge --- README.Rmd | 2 +- README.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.Rmd b/README.Rmd index 06319128..f74de1ed 100644 --- a/README.Rmd +++ b/README.Rmd @@ -18,7 +18,7 @@ knitr::opts_chunk$set( [![website](https://github.com/GrossSBM/sbm/workflows/pkgdown/badge.svg)](https://grosssbm.github.io/sbm/) ![R-CMD-check](https://github.com/GrossSBM/sbm/workflows/R-CMD-check/badge.svg?branch=master) -[![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/sbm)](https://cran.r-project.org/package=sbm) +[![CRAN status](https://www.r-pkg.org/badges/version/sbm)](https://CRAN.R-project.org/package=sbm) [![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) [![](https://img.shields.io/github/last-commit/grossSBM/sbm.svg)](https://github.com/GrossSBM/sbm/commits/master) [![Codecov test coverage](https://codecov.io/gh/GrossSBM/sbm/branch/master/graph/badge.svg)]( diff --git a/README.md b/README.md index 6d9a6a5b..b157944f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ [![website](https://github.com/GrossSBM/sbm/workflows/pkgdown/badge.svg)](https://grosssbm.github.io/sbm/) ![R-CMD-check](https://github.com/GrossSBM/sbm/workflows/R-CMD-check/badge.svg?branch=master) -[![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/sbm)](https://cran.r-project.org/package=sbm) +[![CRAN +status](https://www.r-pkg.org/badges/version/sbm)](https://CRAN.R-project.org/package=sbm) [![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) [![](https://img.shields.io/github/last-commit/grossSBM/sbm.svg)](https://github.com/GrossSBM/sbm/commits/master)