Skip to content

Commit 686670d

Browse files
committed
flip2sss function for second stage summary statistics via flipscores
1 parent 47809fa commit 686670d

12 files changed

+324
-41
lines changed

NAMESPACE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ S3method(p.adjust,jointest)
55
S3method(plot,jointest)
66
S3method(summary,jointest)
77
export(combine)
8+
export(flip2sss)
89
export(join_flipscores)
10+
import(dplyr)
911
import(flipscores)
1012
import(ggplot2)
13+
import(magrittr)
1114
importFrom(flip,flip.adjust)
1215
importFrom(stats,median)
1316
importFrom(stats,qnorm)

R/anova_jointest.R

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#' anova.jointest
2+
#' @description This is the \code{anova} method for \code{jointest} object. Remark: it performs type III deviance decomposition as in \code{car::Anova}.
3+
#' @param object (the object) \code{glm} (or \code{jointest}) object with the model under the null hypothesis (i.e. the covariates, the nuisance parameters).
4+
#' @param model1 a \code{glm} (or \code{jointest}) or a \code{matrix} (or \code{vector}). If it is a \code{glm} object, it has the model under the alternative hypothesis. The variables in \code{model1} are the same variables in \code{object} plus one or more variables to be tested. Alternatively, if
5+
#' \code{model1} is a \code{matrix}, it contains the tested variables column-wise.
6+
#' @param score_type The type of score that is computed. It can be "orthogonalized", "effective" or "basic".
7+
#' Default is "orthogonalized". "effective" and "orthogonalized" take into account the nuisance estimation. The default is \code{NULL}, in this case the value is taken from \code{object}.
8+
#' @param n_flips The number of random flips of the score contributions.
9+
#' When \code{n_flips} is equal or larger than the maximum number of possible flips (i.e. n^2), all possible flips are performed.
10+
#' Default is 5000.
11+
#' @param id a \code{vector} identifying the clustered observations. If \code{NULL} (default) observations are assumed to be independent. NOTE: if \code{object} is a \code{jointest} and \code{model$flip_param_call$id} is not \code{NULL}, this is considered in the inference.
12+
#' @param ... other parameters allowed in \code{stats::anova}.
13+
#' @examples
14+
#' set.seed(1)
15+
#'
16+
#'
17+
#'
18+
19+
20+
anova.jointest <- function(object,
21+
...){
22+
23+
if(is.null(object$x)||(length(object$x)==0)) object=update(object,x=TRUE)
24+
25+
if(is.null(score_type)) score_type = object$score_type
26+
27+
anova_temp=get("anova.glm", envir = asNamespace("stats"),
28+
inherits = FALSE)
29+
30+
## comparison of 2 nested models
31+
if(!is.null(model1)){
32+
scores=compute_scores(model0 = object,
33+
model1 = model1,
34+
score_type = score_type)
35+
mf <- match.call(expand.dots = TRUE)
36+
if(!is.null(mf$flip_param_call$id))
37+
scores=rowsum(scores,group = id)
38+
39+
Tspace=sapply(1:ncol(scores), function(id_col){
40+
score1=scores[,id_col,drop=FALSE]
41+
attributes(score1)$scale_objects=attributes(scores)$scale_objects[[id_col]]
42+
attributes(score1)$score_type=attributes(scores)$score_type
43+
as.matrix(.flip_test_no_pval(score1, precompute_flips = FALSE,
44+
.score_fun = .score_std,n_flips = n_flips))
45+
})
46+
dst=mahalanobis_npc(Tspace)
47+
48+
out_param=anova_temp(object,model1,test="Rao")
49+
heading2=attributes(out_param)$heading[2]
50+
out_param = out_param[-1,]
51+
out_param = out_param[,-c(1:2,4)]
52+
names(out_param)[2]="Score"
53+
out_param[[2]]=dst[1]
54+
names(out_param)[3]="Pr(>Score)"
55+
out_param[[3]]=.t2p(dst)
56+
rownames(out_param)[1]="Model 2 vs Model 1"
57+
58+
} else { ## one anova for all variables
59+
60+
varlist <- attr(object$terms, "variables")
61+
if (!is.matrix(object[["x"]]))
62+
object$x = model.matrix(object)
63+
varseq <- attr(object$x, "assign")
64+
65+
############################
66+
subsets_npc=lapply(unique(varseq[varseq!=0]),function(i)which(varseq==i))
67+
68+
res=mahalanobis_npc_multi(ids_list = subsets_npc,permT = as.matrix(object$Tspace))
69+
# flip::npc(ps@permT,comb.funct = "mahalanobist",subsets = subsets_npc)
70+
# res@res[, 3]=res@res[, 3]*nrow(ps@permT)
71+
72+
out_param = anova_temp(object,test="Rao")
73+
heading2=paste0("Model: ",deparse1(formula(object)))
74+
out_param = out_param[-1,]
75+
out_param = out_param[,-(2:4)]
76+
names(out_param)[2]="Score"
77+
out_param[[2]]=res[1,]
78+
names(out_param)[3]="Pr(>Score)"
79+
out_param[[3]]=apply(res,2,.t2p)
80+
} # closes if
81+
#make up
82+
title <- paste0("Analysis of Deviance Table (Type III test)",
83+
"\n\nModel: ",
84+
object$family$family, ", link: ", object$family$link,"\n")
85+
attr(out_param,"heading")=c(title,heading2)
86+
87+
88+
attr(out_param,"heading")[[1]]= paste(attr(out_param,"heading")[[1]],sep="",
89+
"\nInference is provided by jointest approach (",object$flip_param_call$n_flips," sign flips).\n")
90+
return(out_param)
91+
}

R/combine.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ combine <- function (mods, comb_funct = "maxT", combined = NULL, by=NULL, tail =
4545
comb_name = names(combined)[id]
4646
if (is.null(comb_name))
4747
comb_name = "Combined"
48-
Tspace = npc(mods$Tspace[, combined[[id]]], comb_funct = comb_funct,
48+
Tspace = npc(mods$Tspace[, combined[[id]],drop=FALSE], comb_funct = comb_funct,
4949
tail = tail)
5050
colnames(Tspace) = comb_name
5151
Coeff=mods$summary_table[combined[[id]],"Coeff"]

R/desktop.ini

-244 Bytes
Binary file not shown.

R/flip2sss.R

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#' flip2sss
2+
#'
3+
#' This function fits a model based on the provided formula and data, accounting for clusters and summary statistics within the model.
4+
#'
5+
#' @param formula A formula or a list of formulas. It can be a complete model as.formula or a list of formulas, one for each element produced by the function.
6+
#' @param data The dataset to be used for fitting the model.
7+
#' @param cluster A vector or a formula evaluated on the data that defines the clusters.
8+
#' @param summstats_within A vector of summary statistics model within the data or a function with argument data.
9+
#' @param ... Other arguments passed to the `flipscores` function.
10+
#'
11+
#' @return A jointest object containing the model results. Note that the flipscores models for each coefficient within are also included in the jointest object.
12+
#' @export
13+
#'
14+
#' @examples
15+
#' formula <- SALUTE ~ GENERE * TIME + PROV_BAMB + ETA_B_ARRIVO
16+
#' data <- adolong
17+
#' cluster <- adolong$SOGG
18+
#' library(logistf)
19+
#' temp=logistf::logistf(SALUTE ~ TIME, family = binomial(link = "logit"),data=data,control=logistf.control(maxit=100))
20+
#' summstats_within <- 'logistf::logistf(SALUTE ~ TIME, family = binomial(link = "logit"),control=logistf::logistf.control(maxit=100))'
21+
#' res <- flip2sss(formula, data, cluster, summstats_within)
22+
#'attr(model.matrix(mods[[1]]),"assign")
23+
#' @import dplyr
24+
#' @import magrittr
25+
#'
26+
flip2sss <- function(formula=NULL,
27+
data=NULL,
28+
cluster=NULL,
29+
summstats_within=NULL,
30+
...){
31+
32+
# if(is(cluster,"formula")){
33+
# cluster=eval(cluster,data)
34+
# }
35+
36+
37+
###################
38+
39+
vars_between = .get_sets_vars_between(formula, data, cluster)
40+
41+
## make the second level dataset
42+
set_between = unique(unlist(vars_between))
43+
vars_between_formulas = lapply(vars_between, paste0, collapse = "+")
44+
vars_between_formulas = paste(names(vars_between_formulas), vars_between_formulas, sep = "~")
45+
vars_between_formulas = as.list(vars_between_formulas)
46+
names(vars_between_formulas) = names(vars_between)
47+
48+
#####################
49+
data2lev = data %>%
50+
group_by(adolong[,set_between[-1]]) %>%
51+
summarise(as.data.frame(t(coefficients(eval(parse(text=summstats_within))))))
52+
names(data2lev) = gsub("\\W", ".", names(data2lev))
53+
54+
mods = lapply(vars_between_formulas, function(frm) glm(eval(frm, parent.frame()), data = data2lev))
55+
56+
for(i in 1:length(mods)){
57+
mods[[i]]$call$data = eval(data2lev)
58+
mods[[i]]$call$formula = eval(as.formula(vars_between_formulas[[i]]))
59+
}
60+
61+
res = join_flipscores(mods, n_flips = 5000, seed = 1)
62+
# summary(res)
63+
64+
res$summary_table$Coeff = apply(res$summary_table[, 2:1], 1, paste, collapse = ":")
65+
res$summary_table$Coeff = gsub(":\\.Intercept\\.$", "", res$summary_table$Coeff)
66+
res$summary_table$Coeff = gsub("\\(Intercept\\):", "", res$summary_table$Coeff)
67+
68+
# res$summary_table$Model = "flip2sss"
69+
colnames(res$Tspace) = apply(res$summary_table[, 2:1], 1, paste, collapse = "_model.")
70+
res$mods=mods
71+
res
72+
}
73+
74+
######################
75+
.get_sets_vars_between <- function(formula, data, cluster){
76+
clst_vals = unique(cluster)
77+
D = model.matrix(formula, data = data)
78+
79+
## find constant cols within cluster
80+
const_id = do.call(rbind, by(D, cluster, function(D) as.data.frame(t(apply(D, 2, is.constant)))))
81+
vars_between_intercept = apply(const_id, 2, all)
82+
83+
terms = labels(terms(reformulate(as.character(formula))))
84+
ids_const = unique(attributes(D)$assign[vars_between_intercept])
85+
if(0 %in% ids_const){
86+
ids_const = ids_const + 1
87+
terms = c("1", terms)
88+
}
89+
vars_between_names = list(.Intercept. = terms[ids_const])
90+
91+
cors = suppressWarnings(by(D[, !vars_between_intercept], cluster, cor))
92+
dim3 = c(dim(cors[[1]]), length(cors))
93+
cors = array(unlist(cors), dim3)
94+
cors = apply(cors, c(1, 2), min, na.rm = TRUE)
95+
ei = eigen(cors)
96+
vars_between_others = lapply(which(ei$values > .1), function(cls) terms[-ids_const][which(ei$vectors[, cls] != 0)])
97+
within_coeffs = sapply(vars_between_others, function(preds_vars) Reduce(intersect, strsplit(preds_vars, ":")))
98+
99+
vars_between_others = lapply(1:length(within_coeffs), function(i) gsub(within_coeffs, "1", vars_between_others[[i]]))
100+
vars_between_others = lapply(1:length(within_coeffs), function(i) gsub(":1$", "", vars_between_others[[i]]))
101+
vars_between_others = lapply(1:length(within_coeffs), function(i) gsub("^1:", "", vars_between_others[[i]]))
102+
103+
names(vars_between_others) = within_coeffs
104+
vars_between_names = c(vars_between_names, vars_between_others)
105+
vars_between_names
106+
}
107+
108+
is.constant <- function(x) length(unique(x)) == 1

R/join_flipscores.R

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,36 @@ join_flipscores <- function (mods, tested_coeffs = NULL, n_flips = 5000, score_t
7878
} else
7979
names(mods) = mods_names
8080

81-
81+
assign=sapply(mods,function(mod)attr(model.matrix(mod),"assign"))
82+
vars_orig=sapply(mods,function(mod)terms(mod$formula[[3]]))
83+
names(vars_orig)=mods_names
84+
85+
for(i in 1:length(assign)){
86+
if(min(assign[[i]])==0){
87+
assign[[i]]=assign[[i]]+1
88+
vars_orig[[i]]=c(".Intercept.",vars_orig[[i]])
89+
}
90+
}
91+
92+
if(length(assign)>1){
93+
for(i in 2:length(assign)){
94+
cnt=max(assign[[i-1]])
95+
assign[[i]]=cnt+assign[[i]]
96+
}
97+
}
98+
99+
100+
temp=lapply(1:length(vars_orig),
101+
function(i) paste0("mod_",names(vars_orig)[i],"_",vars_orig[[i]]))
102+
names_vars_orig=unlist(temp)
103+
assign=unlist(assign)
104+
names(assign)=NULL
105+
temp=lapply(unique(assign),function(i) which(assign==i))
106+
names(temp)=names_vars_orig
82107
out=list(Tspace=.get_all_Tspace(mods),
83108
summary_table=.get_all_summary_table(mods),
84109
mods=mods)
110+
attr(out$Tspace,"orig_var")=temp
85111
class(out) <- unique(c("jointest", class(out)))
86112
out
87113
}

R/methods.R

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,18 @@
5757

5858
NULL
5959
#
60+
#' non funziona e non funziona neppure summary se lo uso:
61+
#' #' print.jointest print method for a jointest object.
62+
#' #' @rdname jointest-method
63+
#' #' @param object an object of class \code{jointest}.
64+
#' #' @param ... additional arguments to be passed
65+
#' #' @method print jointest
66+
#' #' @docType methods
67+
#' #' @export
68+
#' print.jointest <- function (object, ...) {
69+
#' #summary.jointest(object, ...)
70+
#' }
6071

61-
# #' print.jointest print method for a jointest object.
62-
# #' @param x a jointest object
63-
# #' @method print jointest
64-
# #' @docType methods
65-
# #' @rdname jointest-method
66-
# #' @export
67-
#
6872
#
6973

7074
#' summary.jointest summary method for a jointest object.
@@ -133,6 +137,7 @@ plot.jointest <- function(object,
133137
if(p.values =="raw"){
134138
if(!is.null(D$`Pr(>|z|)`)) D$p.vals=D$`Pr(>|z|)` else
135139
D$p.vals=D$`Pr(>|t|)`
140+
if(is.null(D$p.vals)) D$p.vals=D$p
136141
} else
137142
if(p.values=="adjusted")
138143
D$p.vals=D$p.adj

R/npc.R

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,40 @@
11

22
npc <- function (Tspace, comb_funct = "Fisher", tail = 0)
33
{
4-
if (!(comb_funct %in% c("mean", "median")))
5-
Tspace = .set_tail(Tspace, tail = tail)
6-
if (comb_funct %in% c("Fisher", "Liptak", "Stoufer",
7-
"Tippet", "minp")) {
4+
if(is.character(comb_funct)){
5+
implemented_comb_funcs=c("mean", "median","Fisher",
6+
"Liptak", "Stoufer",
7+
"Tippet", "minp","Mahalanobis")
8+
comb_funct=match.arg(comb_funct,implemented_comb_funcs)
9+
if (comb_funct %in% c("mean", "median"))
10+
Tspace = .set_tail(Tspace, tail = tail)
11+
if (comb_funct %in% c("Fisher",
12+
"Liptak", "Stoufer",
13+
"Tippet", "minp"))
814
Tspace = .t2p(Tspace, tail = 1)
9-
}
10-
if (comb_funct == "minp")
11-
Tspace = -Tspace
12-
if (comb_funct == "mean") {
13-
Tspace = rowMeans(Tspace)
14-
Tspace = .set_tail(Tspace, tail = tail)
15-
}
16-
else if (comb_funct %in% c("minp", "maxT")) {
17-
Tspace = .rowMax(Tspace)
18-
}
19-
else if (comb_funct == "median") {
20-
Tspace = .rowMedians(Tspace)
21-
Tspace = .set_tail(Tspace, tail = tail)
22-
}
23-
else if (comb_funct == "Fisher") {
24-
Tspace = rowSums(.comb_funct_fisher(Tspace))
25-
}
26-
else if (comb_funct %in% c("Liptak", "Stoufer")) {
27-
Tspace = rowSums(.comb_funct_liptak(Tspace))
28-
}
29-
else if (is.function(comb_funct)) {
15+
16+
if (comb_funct == "minp")
17+
Tspace = -Tspace
18+
if (comb_funct == "mean") {
19+
Tspace = rowMeans(Tspace)
20+
Tspace = .set_tail(Tspace, tail = tail)
21+
}
22+
else if (comb_funct %in% c("minp", "maxT")) {
23+
Tspace = .rowMax(Tspace)
24+
}
25+
else if (comb_funct == "median") {
26+
Tspace = .rowMedians(Tspace)
27+
Tspace = .set_tail(Tspace, tail = tail)
28+
}
29+
else if (comb_funct == "Fisher") {
30+
Tspace = rowSums(.comb_funct_fisher(Tspace))
31+
}
32+
else if (comb_funct %in% c("Liptak", "Stoufer")) {
33+
Tspace = rowSums(.comb_funct_liptak(Tspace))
34+
} else if (comb_funct %in% c("Mahalanobis")) {
35+
Tspace = flipscores:::mahalanobis_npc(Tspace)
36+
}
37+
} else if (is.function(comb_funct)) {
3038
Tspace = comb_funct(Tspace)
3139
comb_funct = "custom"
3240
}

R/utils_internal.R

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55
tab=lapply(mods,function(x){
66
if(is.null(x$Tspace)){stop("At least one Tspace is missing")}
77
x$Tspace})
8+
nms = sapply(tab,colnames)
89
tab=do.call(cbind,tab)
9-
colnames(tab) = paste0("S", 1:ncol(tab))
10-
# tab=mods[[1]]$Tspace
11-
# for (i in 2:length(mods)){
12-
# tab=cbind(tab,mods[[i]]$Tspace)
13-
# }
10+
colnames(tab)=nms
11+
if(is.null(colnames(tab))) colnames(tab)=paste0("S", 1:ncol(tab))
12+
1413
tab
1514
}
1615

0 commit comments

Comments
 (0)