Skip to content

Commit d11fc14

Browse files
committed
Working on pscore and auc
1 parent 8f0205d commit d11fc14

File tree

7 files changed

+163
-35
lines changed

7 files changed

+163
-35
lines changed

DESCRIPTION

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Authors@R: c(person("George", "Vega Yon", role=c("aut","cre"),
77
5P01CA196569-02"),
88
person("USC Biostatistics", role = "cph")
99
)
10-
Version: 0.3-3
10+
Version: 0.3-4
1111
Description: Implements a parsimonious evolutionary model to analyze and
1212
predict gene-functional annotations in phylogenetic trees as described in Vega
1313
Yon et al. (2021) <doi:10.1371/journal.pcbi.1007948>. Focusing on

NAMESPACE

+2
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ S3method(predict_pre_order,aphylo)
6969
S3method(predict_pre_order,aphylo_estimates)
7070
S3method(prediction_score,aphylo_estimates)
7171
S3method(prediction_score,default)
72+
S3method(prediction_score,list)
73+
S3method(prediction_score,matrix)
7274
S3method(print,aphylo)
7375
S3method(print,aphylo_auc)
7476
S3method(print,aphylo_estimates)

R/prediction_score.R

+98-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
#' Calculate prediction score (quality of prediction)
22
#'
3-
#' @param x An object of class [aphylo_estimates] or a numeric matrix.
4-
#' @param expected Integer vector of length \eqn{n}. Expected values (either 0 or 1).
3+
#' @param x An object of class [aphylo_estimates] or other numeric vector-like
4+
#' object (see details).
5+
#' @param expected Numeric vector-like object length \eqn{n} (see details).
6+
#' Expected values (either 0 or 1).
57
#' @param alpha0,alpha1 Probability of observing a zero an a one, respectively.
68
#' @param W A square matrix. Must have as many rows as genes in `expected`.
79
#' @param ... Further arguments passed to [predict.aphylo_estimates]
810
#' @export
911
#' @details In the case of `prediction_score`, `...` are passed to
1012
#' `predict.aphylo_estimates`.
13+
#' The function will accept `x` as a numeric vector, list of vectors, or matrix.
14+
#' Otherwise, it will try to coerce it to a matrix. If it fails, it will throw
15+
#' an error.
1116
#' @returns
1217
#' A list of class `aphylo_prediction_score`:
1318
#' - obs : Observed 1 - MAE.
@@ -53,7 +58,66 @@ prediction_score <- function(
5358
) UseMethod("prediction_score")
5459

5560
#' @export
56-
#' @rdname prediction_score
61+
prediction_score.matrix <- function(
62+
x,
63+
expected,
64+
alpha0 = NULL,
65+
alpha1 = NULL,
66+
W = NULL,
67+
...
68+
) {
69+
70+
# Both x and expected should be numeric
71+
if (!is.numeric(x) || !is.numeric(expected))
72+
stop("`x` and `expected` must be numeric.", call.=FALSE)
73+
74+
# Checking that it has a single column
75+
if (ncol(x) != 1L || ncol(expected) != 1L)
76+
stop("`x` and `y` must have a single column.", call.=FALSE)
77+
78+
# Checking dimensions
79+
if (any(dim(x) != dim(expected)))
80+
stop("`x` and `expected` differ in length. These must match.", call.=FALSE)
81+
82+
# Vectorizing
83+
x <- as.vector(x)
84+
expected <- as.vector(expected)
85+
86+
# Passing to default method
87+
prediction_score_backend(
88+
x = matrix(x, ncol = 1),
89+
expected = matrix(expected, ncol = 1),
90+
alpha0 = alpha0,
91+
alpha1 = alpha1,
92+
W = W,
93+
...
94+
)
95+
96+
}
97+
98+
#' @export
99+
prediction_score.list <- function(
100+
x,
101+
expected,
102+
alpha0 = NULL,
103+
alpha1 = NULL,
104+
W = NULL,
105+
...
106+
) {
107+
108+
# Passing to default method
109+
prediction_score.matrix(
110+
x = do.call(rbind, x),
111+
expected = do.call(rbind, expected),
112+
alpha0 = alpha0,
113+
alpha1 = alpha1,
114+
W = W,
115+
...
116+
)
117+
118+
}
119+
120+
#' @export
57121
prediction_score.default <- function(
58122
x,
59123
expected,
@@ -62,7 +126,33 @@ prediction_score.default <- function(
62126
W = NULL,
63127
...
64128
) {
65-
129+
130+
x <- tryCatch(as.matrix(x), error = function(e) e)
131+
expected <- tryCatch(as.matrix(expected), error = function(e) e)
132+
133+
if (inherits(x, "error") || inherits(expected, "error"))
134+
stop("If not list or matrix, `x` and `expected` must be numeric.", call.=FALSE)
135+
136+
prediction_score.matrix(
137+
x = x,
138+
expected = expected,
139+
alpha0 = alpha0,
140+
alpha1 = alpha1,
141+
W = W,
142+
...
143+
)
144+
145+
}
146+
147+
prediction_score_backend <- function(
148+
x,
149+
expected,
150+
alpha0 = NULL,
151+
alpha1 = NULL,
152+
W = NULL,
153+
...
154+
) {
155+
66156
# Checking dimensions
67157
if (length(x) != length(expected))
68158
stop("`x` and `expected` differ in length. These must match.", call.=FALSE)
@@ -81,7 +171,7 @@ prediction_score.default <- function(
81171
# score.
82172
if (!length(alpha0))
83173
alpha0 <- 1 - mean(expected)
84-
if (is.null(alpha1))
174+
if (!length(alpha1))
85175
alpha1 <- 1 - alpha0
86176

87177
if (is.null(W))
@@ -227,20 +317,20 @@ prediction_score.aphylo_estimates <- function(
227317
# Adjusting alphas according to loo logic. To make the benchmark fair, we need
228318
# to exclude one annotation from each type for the loo
229319
n <- length(ids)
230-
if (is.null(alpha0) && loo) {
320+
if (!length(alpha0) && loo) {
231321

232322
alpha0 <- max(sum(expected[ids,] == 0) - ncol(expected), 0)
233323
alpha0 <- alpha0/((nrow(expected[ids,]) - 1) * ncol(expected))
234324

235325
}
236-
if (is.null(alpha1) && loo) {
326+
if (!length(alpha1) && loo) {
237327

238328
alpha1 <- max(sum(expected[ids,]) - ncol(expected), 0)
239329
alpha1 <- alpha1/((nrow(expected[ids,]) - 1) * ncol(expected))
240330

241331
}
242332

243-
ans <- prediction_score(
333+
ans <- prediction_score_backend(
244334
x = pred[ids,,drop=FALSE],
245335
expected = expected[ids,,drop = FALSE],
246336
alpha0 = alpha0,

inst/tinytest/test-auc.r

+50-16
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,52 @@
1-
# context("Area Under the Curve")
2-
3-
# test_that("Coincides with what the AUC::auc(roc()) function returns.", {
4-
5-
set.seed(1231)
6-
x <- rnorm(100)
7-
y <- as.integer((.2*x + rnorm(100)) > 0)
8-
p <- stats::predict(stats::glm(y~0+x, family=binomial("probit")), type="response")
9-
10-
11-
ans0 <- auc(p, y, 100)
12-
ans1 <- AUC::auc(AUC::roc(p, as.factor(y)))
13-
14-
expect_equal(ans0$auc, ans1, tol=0.01)
15-
16-
# })
171

2+
set.seed(1231)
3+
x <- rnorm(100)
4+
y <- as.integer((.2*x + rnorm(100)) > 0)
5+
p <- stats::predict(stats::glm(y~0+x, family=binomial("probit")), type="response")
6+
7+
8+
ans0 <- auc(p, y, 100)
9+
ans1 <- AUC::auc(AUC::roc(p, as.factor(y)))
10+
11+
# Default way
12+
expect_equal(ans0$auc, ans1, tol=0.01)
13+
14+
# Now using lists
15+
pscore0 <- prediction_score(
16+
as.list(x),
17+
as.list(y)
18+
)
19+
20+
# Now using vectors
21+
pscore1 <- prediction_score(
22+
x,
23+
y
24+
)
25+
26+
pscore2 <- # Now using matrix
27+
prediction_score(
28+
cbind(x),
29+
cbind(y)
30+
)
31+
32+
pscore3 <- # Now using a data frame
33+
prediction_score(
34+
data.frame(x),
35+
data.frame(y)
36+
)
37+
38+
expect_equal(
39+
pscore0$auc,
40+
pscore1$auc
41+
)
42+
43+
expect_equal(
44+
pscore0$auc,
45+
pscore2$auc
46+
)
47+
48+
expect_equal(
49+
pscore0$auc,
50+
pscore3$auc
51+
)
1852

man/prediction_score.Rd

+7-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/RcppExports.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,13 @@ BEGIN_RCPP
158158
END_RCPP
159159
}
160160
// auc
161-
List auc(NumericVector pred, IntegerVector labels, int nc, bool nine_na);
161+
List auc(const NumericVector& pred, const IntegerVector& labels, int nc, bool nine_na);
162162
RcppExport SEXP _aphylo_auc(SEXP predSEXP, SEXP labelsSEXP, SEXP ncSEXP, SEXP nine_naSEXP) {
163163
BEGIN_RCPP
164164
Rcpp::RObject rcpp_result_gen;
165165
Rcpp::RNGScope rcpp_rngScope_gen;
166-
Rcpp::traits::input_parameter< NumericVector >::type pred(predSEXP);
167-
Rcpp::traits::input_parameter< IntegerVector >::type labels(labelsSEXP);
166+
Rcpp::traits::input_parameter< const NumericVector& >::type pred(predSEXP);
167+
Rcpp::traits::input_parameter< const IntegerVector& >::type labels(labelsSEXP);
168168
Rcpp::traits::input_parameter< int >::type nc(ncSEXP);
169169
Rcpp::traits::input_parameter< bool >::type nine_na(nine_naSEXP);
170170
rcpp_result_gen = Rcpp::wrap(auc(pred, labels, nc, nine_na));

src/auc.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ using namespace Rcpp;
2828
//' plot(ans_auc)
2929
// [[Rcpp::export]]
3030
List auc(
31-
NumericVector pred,
32-
IntegerVector labels,
31+
const NumericVector & pred,
32+
const IntegerVector & labels,
3333
int nc = 200,
3434
bool nine_na = true
3535
) {

0 commit comments

Comments
 (0)