Calculation of RECIST Best Overall Response in grstat
Alexis COCHARD
Source:vignettes/BOR.Rmd
BOR.RmdIntroduction
This vignette illustrates the calculation of RECIST endpoints in R
using the grstat package.
RECIST definition
RECIST (Response Evaluation Criteria in Solid Tumors) is a standardized way to quantify how solid tumors respond to therapy by comparing changes in tumor burden on imaging. The four possible responses are:
- Complete Response (CR): disappearance of all target lesions,
- Partial Response (PR): ≥ 30% decrease in the sum of longest diameters from baseline,
- Stable Disease (SD): neither sufficient shrinkage for PR nor sufficient increase for progression,
- Progressive Disease (PD): ≥ 20% increase in the sum from the smallest measured value (the “nadir”) or the appearance of new lesions.
We follow the RECIST 1.1 guideline, DOI: 10.1016/j.ejca.2008.10.026, available here.
Endpoint definition
The Best Overall Response (BOR) is defined as the best response observed for a patient during follow-up. BOR captures the maximum tumor shrinkage achieved under treatment, reflecting the patient’s best observed benefit, although it does not account for its duration.
Several summary endpoints are then defined as proportions derived from BOR:
- Objective Response Rate (ORR): proportion of patients with BOR equal to complete response (CR) or partial response (PR).
- Clinical Benefit Rate (CBR): proportion of patients with BOR equal to CR, PR, or stable disease (SD) lasting at least a predefined duration (e.g., 6 months).
- Disease Control Rate (DCR): proportion of patients with BOR equal to CR, PR, or SD.
Note that ORR is sometimes defined at a specific time point rather than based on BOR. Such definitions depend on follow-up duration and may introduce ambiguity due to censoring and incomplete assessments.
Confirmed and Unconfirmed Response
Most of the time, BOR is calculated based on the unconfirmed response, but sometimes a confirmed response is required. We define unconfirmed and confirmed responses as follows:
- An unconfirmed best response is defined as the best categorical response observed from treatment start until progression or end of follow-up.
- A confirmed best response is defined as the best categorical
consecutive response (with a minimum delay of 28 days) observed from
treatment start until progression or end of follow-up. For example:
- A CR-CR-SD-PD sequence corresponds to a confirmed CR best response;
- A PR-SD-SD-PR sequence corresponds to a confirmed SD best response;
- A single NE (and a single SD if you follow the PharmaSUG recommendation) between two CR or two PR responses does not prevent confirmation.
See the RECIST 1.1 guidelines for more information.
Data Preparation
To calculate BOR, we need a RECIST dataset in long format (one row per patient assessment) containing at least the following columns:
-
subjid, patient ID -
rcdt, evaluation date -
rcresp, global response -
rctlsum, sum of target lesions
In this vignette, we use grstat_example() to simulate
such data.
Note that warnings about your RECIST data may appear, so be sure to take them into account.
library(grstat)
library(tidyverse)
library(flextable)
db = grstat_example(N=200)
recist = db$recist %>% select(subjid, rcdt, rctlsum, rcresp)
recist %>% filter(subjid < 4)## # A tibble: 10 × 4
## subjid rcdt rctlsum rcresp
## <int> <date> <dbl> <fct>
## 1 1 2023-01-22 91.1 NA
## 2 1 2023-03-07 46.2 Partial response
## 3 1 2023-04-16 0 Complete response
## 4 1 2023-05-31 0 Complete response
## 5 1 2023-07-04 0 Complete response
## 6 2 2023-03-12 17.4 NA
## 7 2 2023-04-23 40.6 Progressive disease
## 8 3 2023-03-30 70.4 NA
## 9 3 2023-05-13 79 Stable disease
## 10 3 2023-06-29 144. Progressive disease
Calculation of BOR
The calculation of the Best Overall Response is performed using
calc_best_response(), which takes the following
parameters:
-
data_recist, the RECIST data.frame -
confirmed, for a confirmed or unconfirmed response -
cols, a vector with column names (subjid,rc_resp,rc_date, andrc_sum, corresponding respectively to patient ID, global response, evaluation date, and sum of target lesions)
Unconfirmed response
best_resp = calc_best_response(recist)## Warning: Target Lesions Length Sum is missing at baseline. (2 patients:
## #72 and #193)
head(best_resp, n= 7L)## # A tibble: 7 × 7
## subjid best_response date target_sum target_sum_diff_first
## <int> <fct> <date> <dbl> <dbl>
## 1 1 Complete response 2023-04-16 0 -1
## 2 2 Progressive disease 2023-04-23 40.6 1.33
## 3 3 Stable disease 2023-05-13 79 0.122
## 4 4 Complete response 2023-05-17 0 -1
## 5 5 Complete response 2023-07-05 0 -1
## 6 6 Complete response 2023-08-31 0 -1
## 7 7 Partial response 2023-09-16 50.5 -0.512
## # ℹ 2 more variables: target_sum_diff_min <dbl>, six_months_confirmation <lgl>
As you can see, warnings may appear. You can use
check_recist() for more information.
If your column names aren’t recognized, you can specify them using
the cols parameter :
best_resp = calc_best_response(recist, cols = c(rc_resp="Glb_resp", subjid="Pat_Num"),)Confirmed response
confirmed_best_resp = calc_best_response(recist, confirmed = TRUE)## Warning: Target Lesions Length Sum is missing at baseline. (2 patients:
## #72 and #193)
head(confirmed_best_resp, n = 7L)## # A tibble: 7 × 7
## subjid best_response date target_sum target_sum_diff_first
## <int> <fct> <date> <dbl> <dbl>
## 1 1 Complete response 2023-04-16 0 -1
## 2 2 Progressive disease 2023-04-23 40.6 1.33
## 3 3 Stable disease 2023-05-13 79 0.122
## 4 4 Complete response 2023-05-17 0 -1
## 5 5 Complete response 2023-07-05 0 -1
## 6 6 Complete response 2023-08-31 0 -1
## 7 7 Stable disease 2023-08-04 119. 0.148
## # ℹ 2 more variables: target_sum_diff_min <dbl>, six_months_confirmation <lgl>
#To illustrate the difference between confirmed and unconfirmed responses, let's focus on patient 7.
recist %>% filter(subjid ==7)## # A tibble: 4 × 4
## subjid rcdt rctlsum rcresp
## <int> <date> <dbl> <fct>
## 1 7 2023-06-22 103. NA
## 2 7 2023-08-04 119. Stable disease
## 3 7 2023-09-16 50.5 Partial response
## 4 7 2023-11-01 134. Progressive disease
With the confirmed method, patient 7’s best response becomes Stable Disease instead of Partial Response. The reason is that patient 7 has Progressive Disease after the Partial Response. According to the definition, the Partial Response cannot be confirmed. Therefore, the confirmed best response is Stable Disease rather than Partial Response
Calculate the different RECIST rates
To summarize patient-level responses and compute derived rates, we
use the aggregate_recist_rates() function which consists of
two parameters:
-
data, the data.frame containing the best response obtained after using the functioncalc_best_response()(confirmed or unconfirmed) -
derived_endpoints=c("ORR", "CBR", "DCR"), to specify the endpoints to display
tbl = aggregate_recist_rates(best_resp, derived_endpoints=c("ORR", "CBR", "DCR"))
tbl## # A tibble: 8 × 4
## best_response n p ic_95
## * <chr> <int> <dbl> <glue>
## 1 Complete response 98 49 [41.9;56.1]
## 2 Partial response 27 13.5 [9.1;19]
## 3 Stable disease 16 8 [4.6;12.7]
## 4 Progressive disease 59 29.5 [23.3;36.3]
## 5 Not evaluable 0 0 [0;1.8]
## 6 Objective Response Rate (ORR) 125 62.5 [55.4;69.2]
## 7 Clinical Benefit Rate (CBR) 125 62.5 [55.4;69.2]
## 8 Disease Control Rate (DCR) 141 70.5 [63.7;76.7]
Since aggregate_recist_rates() returns a classed data
frame, we can use as_flextable() (instead of simply
flextable()) to convert it into a formatted flextable, on
which you can apply any modifier. Here, for example, we apply bold
formatting to row 4 and add a footnote to the third row of the CI
column.
#Exampel with flextable modification:
tbl %>%
as_flextable() %>%
bold(i=4)%>%
footnote(i = 3, j = 4,
value = as_paragraph("This is note number 8"),
ref_symbols ="8", part = "body")Unconfirmed Best Response during treatment |
N=200 |
% |
IC 95%* |
|---|---|---|---|
Complete response |
98 |
49.0 |
[41.9;56.1] |
Partial response |
27 |
13.5 |
[9.1;19] |
Stable disease |
16 |
8.0 |
[4.6;12.7]8 |
Progressive disease |
59 |
29.5 |
[23.3;36.3] |
Not evaluable |
0 |
0.0 |
[0;1.8] |
Objective Response Rate (ORR)ORR |
125 |
62.5 |
[55.4;69.2] |
Clinical Benefit Rate (CBR)CBR |
125 |
62.5 |
[55.4;69.2] |
Disease Control Rate (DCR)DCR |
141 |
70.5 |
[63.7;76.7] |
*Clopper-Pearson (Exact) method was used for confidence interval | |||
ORRORR was defined as the presence of a partial response (PR) or a complete response (CR). | |||
CBRCBR was defined as the presence of a partial response (PR), a complete response (CR), or a stable disease (SD) lasting at least six months. | |||
DCRDCR was defined as the presence of a partial response (PR), a complete response (CR), or a stable disease (SD). | |||
8This is note number 8 | |||