Skip to content

Commit a360732

Browse files
author
Joshua Loftus
committed
Merge branch 'master' of github.com:selective-inference/R-software
2 parents 79a5563 + 5dcf3e2 commit a360732

20 files changed

+1313
-70
lines changed

selectiveInference/DESCRIPTION

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ Author: Ryan Tibshirani, Rob Tibshirani, Jonathan Taylor,
88
Maintainer: Rob Tibshirani <[email protected]>
99
Depends:
1010
glmnet,
11-
intervals
11+
intervals,
12+
survival
1213
Suggests:
1314
Rmpfr
1415
Description: New tools for post-selection inference, for use

selectiveInference/NAMESPACE

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
export(lar,fs,
2-
larInf,fsInf,
2+
larInf,fsInf,fsInf_maxZ,
33
coef.lar,coef.fs,
44
predict.lar,predict.fs,
55
print.lar,print.fs,
66
print.larInf,print.fsInf,
77
plot.lar,plot.fs,
88
fixedLassoInf,print.fixedLassoInf,
9+
# fixedLogitLassoInf,print.fixedLogitLassoInf,
10+
# fixedCoxLassoInf,print.fixedCoxLassoInf,
911
forwardStop,
1012
estimateSigma,
1113
manyMeans,print.manyMeans,
1214
groupfs,groupfsInf,
13-
scaleGroups,factorDesign
15+
scaleGroups,factorDesign,
16+
sample_from_constraints
1417
)
1518

1619
S3method("coef", "lar")
@@ -23,7 +26,10 @@ S3method("predict", "fs")
2326
S3method("print", "fs")
2427
S3method("plot", "fs")
2528
S3method("print", "fsInf")
29+
S3method("print", "fsInf_maxZ")
2630
S3method("print", "fixedLassoInf")
31+
S3method("print", "fixedLogitLassoInf")
32+
S3method("print", "fixedCoxLassoInf")
2733
S3method("print", "manyMeans")
2834
S3method("print", "groupfs")
2935
S3method("print", "groupfsInf")
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
#
2+
# Some utilities for affine constraints
3+
#
4+
5+
#
6+
# compute the square-root and inverse square-root of a non-negative
7+
# definite matrix
8+
#
9+
10+
factor_covariance = function(S, rank=NA) {
11+
if (is.na(rank)) {
12+
rank = nrow(S)
13+
}
14+
svd_X = svd(S, nu=rank, nv=rank)
15+
sqrt_cov = t(sqrt(svd_X$d[1:rank]) * t(svd_X$u[,1:rank]))
16+
sqrt_inv = t((1. / sqrt(svd_X$d[1:rank])) * t(svd_X$u[,1:rank]))
17+
18+
return(list(sqrt_cov=sqrt_cov, sqrt_inv=sqrt_inv))
19+
}
20+
21+
#
22+
# from a constraint, return an equivalent
23+
# constraint and a whitening and inverse
24+
# whitening map
25+
#
26+
27+
# law is Z \sim N(mean_param, covariance) subject to constraints linear_part %*% Z \leq offset
28+
29+
whiten_constraint = function(linear_part, offset, mean_param, covariance) {
30+
31+
factor_cov = factor_covariance(covariance)
32+
sqrt_cov = factor_cov$sqrt_cov
33+
sqrt_inv = factor_cov$sqrt_inv
34+
35+
new_A = linear_part %*% sqrt_cov
36+
new_b = offset - linear_part %*% mean_param
37+
38+
# rescale rows to have length 1
39+
40+
scaling = sqrt(apply(new_A^2, 1, sum))
41+
new_A = new_A / scaling
42+
new_b = new_b / scaling
43+
44+
# TODO: check these functions will behave when Z is a matrix.
45+
46+
inverse_map = function(Z) {
47+
# broadcasting here
48+
# the columns of Z are same length as mean_param
49+
return(sqrt_cov %*% Z + as.numeric(mean_param))
50+
}
51+
52+
forward_map = function(W) {
53+
return(sqrt_inv %*% (W - mean_param))
54+
}
55+
56+
return(list(linear_part=new_A,
57+
offset=new_b,
58+
inverse_map=inverse_map,
59+
forward_map=forward_map))
60+
}
61+
62+
#
63+
# sample from the law
64+
#
65+
# Z \sim N(mean_param, covariance) subject to constraints linear_part %*% Z \leq offset
66+
67+
sample_from_constraints = function(linear_part,
68+
offset,
69+
mean_param,
70+
covariance,
71+
initial_point, # point must be feasible for constraints
72+
ndraw=8000,
73+
burnin=2000,
74+
accept_reject_params=NA) #TODO: implement accept reject check
75+
{
76+
77+
whitened_con = whiten_constraint(linear_part,
78+
offset,
79+
mean_param,
80+
covariance)
81+
white_initial = whitened_con$forward_map(initial_point)
82+
83+
# # try 100 draws of accept reject
84+
# # if we get more than 50 good draws, then just return a smaller sample
85+
# # of size (burnin+ndraw)/5
86+
87+
# if accept_reject_params:
88+
# use_hit_and_run = False
89+
# num_trial, min_accept, num_draw = accept_reject_params
90+
91+
# def _accept_reject(sample_size, linear_part, offset):
92+
# Z_sample = np.random.standard_normal((100, linear_part.shape[1]))
93+
# constraint_satisfied = (np.dot(Z_sample, linear_part.T) -
94+
# offset[None,:]).max(1) < 0
95+
# return Z_sample[constraint_satisfied]
96+
97+
# Z_sample = _accept_reject(100,
98+
# white_con.linear_part,
99+
# white_con.offset)
100+
101+
# if Z_sample.shape[0] >= min_accept:
102+
# while True:
103+
# Z_sample = np.vstack([Z_sample,
104+
# _accept_reject(num_draw / 5,
105+
# white_con.linear_part,
106+
# white_con.offset)])
107+
# if Z_sample.shape[0] > num_draw:
108+
# break
109+
# white_samples = Z_sample
110+
# else:
111+
# use_hit_and_run = True
112+
# else:
113+
# use_hit_and_run = True
114+
115+
use_hit_and_run = TRUE
116+
117+
if (use_hit_and_run) {
118+
119+
white_linear = whitened_con$linear_part
120+
white_offset = whitened_con$offset
121+
122+
# Inf cannot be used in C code
123+
# In theory, these rows can be dropped
124+
125+
rows_to_keep = white_offset < Inf
126+
white_linear = white_linear[rows_to_keep,,drop=FALSE]
127+
white_offset = white_offset[rows_to_keep]
128+
129+
nstate = length(white_initial)
130+
if (sum(rows_to_keep) > 0) {
131+
if (ncol(white_linear) > 1) {
132+
nconstraint = nrow(white_linear)
133+
134+
directions = rbind(diag(rep(1, nstate)),
135+
matrix(rnorm(nstate^2), nstate, nstate))
136+
137+
# normalize rows to have length 1
138+
139+
scaling = apply(directions, 1, function(x) { return(sqrt(sum(x^2))) })
140+
directions = directions / scaling
141+
ndirection = nrow(directions)
142+
143+
alphas = directions %*% t(white_linear)
144+
U = white_linear %*% white_initial - white_offset
145+
Z_sample = matrix(rep(0, nstate * ndraw), nstate, ndraw)
146+
147+
result = .C("sample_truncnorm_white",
148+
as.numeric(white_initial),
149+
as.numeric(U),
150+
as.numeric(t(directions)),
151+
as.numeric(t(alphas)),
152+
output=Z_sample,
153+
as.integer(nconstraint),
154+
as.integer(ndirection),
155+
as.integer(nstate),
156+
as.integer(burnin),
157+
as.integer(ndraw),
158+
package="selectiveInference")
159+
Z_sample = result$output
160+
} else { # the distribution is univariate
161+
# we can just work out upper and lower limits
162+
163+
white_linear = as.numeric(white_linear)
164+
pos = (white_linear * white_offset) >= 0
165+
neg = (white_linear * white_offset) <= 0
166+
if (sum(pos) > 0) {
167+
U = min((white_offset / white_linear)[pos])
168+
} else {
169+
U = Inf
170+
}
171+
if (sum(neg) < 0) {
172+
L = max((white_offset / white_linear)[neg])
173+
} else {
174+
L = -Inf
175+
}
176+
Z_sample = matrix(qnorm((pnorm(U) - pnorm(L)) * runif(ndraw) + pnorm(L)), 1, ndraw)
177+
}
178+
} else {
179+
Z_sample = matrix(rnorm(nstate * ndraw), nstate, ndraw)
180+
}
181+
}
182+
183+
Z = t(whitened_con$inverse_map(Z_sample))
184+
return(Z)
185+
}
186+

selectiveInference/R/funs.fixed.R

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,32 @@
22
# for the solution of
33
# min 1/2 || y - \beta_0 - X \beta ||_2^2 + \lambda || \beta ||_1
44

5-
fixedLassoInf <- function(x, y, beta, lambda, intercept=TRUE, sigma=NULL, alpha=0.1,
5+
fixedLassoInf <- function(x, y, beta, lambda, family=c("gaussian","binomial","cox"),intercept=TRUE, status=NULL,
6+
sigma=NULL, alpha=0.1,
67
type=c("partial","full"), tol.beta=1e-5, tol.kkt=0.1,
78
gridrange=c(-100,100), bits=NULL, verbose=FALSE) {
8-
9+
10+
family = match.arg(family)
911
this.call = match.call()
1012
type = match.arg(type)
13+
14+
if(family=="binomial") {
15+
if(type!="partial") stop("Only type= partial allowed with binomial family")
16+
out=fixedLogitLassoInf(x,y,beta,lambda,alpha=alpha, type="partial", tol.beta=tol.beta, tol.kkt=tol.kkt,
17+
gridrange=gridrange, bits=bits, verbose=verbose,this.call=this.call)
18+
return(out)
19+
}
20+
else if(family=="cox") {
21+
if(type!="partial") stop("Only type= partial allowed with Cox family")
22+
out=fixedCoxLassoInf(x,y,status,beta,lambda,alpha=alpha, type="partial",tol.beta=tol.beta,
23+
tol.kkt=tol.kkt, gridrange=gridrange, bits=bits, verbose=verbose,this.call=this.call)
24+
return(out)
25+
}
26+
27+
else{
28+
29+
30+
1131
checkargs.xy(x,y)
1232
if (missing(beta) || is.null(beta)) stop("Must supply the solution beta")
1333
if (missing(lambda) || is.null(lambda)) stop("Must supply the tuning parameter value lambda")
@@ -106,7 +126,7 @@ fixedLassoInf <- function(x, y, beta, lambda, intercept=TRUE, sigma=NULL, alpha=
106126
pv[j] = a$pv
107127
vlo[j] = a$vlo * mj # Unstandardize (mult by norm of vj)
108128
vup[j] = a$vup * mj # Unstandardize (mult by norm of vj)
109-
vmat[j,] = vj * mj # Unstandardize (mult by norm of vj)
129+
vmat[j,] = vj * mj * sign[j] # Unstandardize (mult by norm of vj)
110130

111131
a = poly.int(y,G,u,vj,sigma,alpha,gridrange=gridrange,
112132
flip=(sign[j]==-1),bits=bits)
@@ -117,10 +137,13 @@ fixedLassoInf <- function(x, y, beta, lambda, intercept=TRUE, sigma=NULL, alpha=
117137
out = list(type=type,lambda=lambda,pv=pv,ci=ci,
118138
tailarea=tailarea,vlo=vlo,vup=vup,vmat=vmat,y=y,
119139
vars=vars,sign=sign,sigma=sigma,alpha=alpha,
140+
sd=sigma*sqrt(rowSums(vmat^2)),
141+
coef0=vmat%*%y,
120142
call=this.call)
121143
class(out) = "fixedLassoInf"
122144
return(out)
123145
}
146+
}
124147

125148
#############################
126149

@@ -176,8 +199,8 @@ print.fixedLassoInf <- function(x, tailarea=TRUE, ...) {
176199
cat(sprintf("\nTesting results at lambda = %0.3f, with alpha = %0.3f\n",x$lambda,x$alpha))
177200
cat("",fill=T)
178201
tab = cbind(x$vars,
179-
round(x$sign*x$vmat%*%x$y,3),
180-
round(x$sign*x$vmat%*%x$y/(x$sigma*sqrt(rowSums(x$vmat^2))),3),
202+
round(x$coef0,3),
203+
round(x$coef0 / x$sd,3),
181204
round(x$pv,3),round(x$ci,3))
182205
colnames(tab) = c("Var", "Coef", "Z-score", "P-value", "LowConfPt", "UpConfPt")
183206
if (tailarea) {

0 commit comments

Comments
 (0)