4 PDA Software Development
[This section is for users with R software experience]
All the PDA models are implemented in the R package ‘pda’. The package provides a function to choose the PDA model based on the Task, followed by an automatic streamline of the steps in Figure 4. The package is available on Github (https://github.com/Penncil/pda) and CRAN (https://CRAN.R-project.org/package=pda). We recommend using the Github version for the most recent updates. To conduct a federated learning analysis with multiple sites, We recommend combining this package (for analysis) with the PDA-OTA platform (for data-transferring), see details in Section 5.
4.1 Install the package
- In RStudio, create a new project: File -> New Project… -> New Directory -> New Project.
- Execute the following R code:
4.2 PDA functions
The pda package contains the following functions
- Catalog function
pdaCatalog(): decide appropriate PDA model based on applicational Task and study settings. Running this function will present the tree diagram in Figure 5, and step-by-step guide to obtain thecontrolfile (in .json format) that sets up the PDA model. - Utility functions:
pdaGet(),pdaPut(),pdaList(),pdaSync(). Only used by fluent R users for testing purpose. - Model_step functions (e.g.
ODAL_initialize(),ODAL_derive(),ODAL_estimate()for ODAL model): model-specific functions to conduct analysis at each step. Only used by fluent R users for testing purpose. - Synthetic data sets: …
- Main function
pda(): to be executed by the lead site and collaborative sites. This function is designed to calculate and generate intermediate AD files (in .json format), read in AD files from other sites, and automatically synchronize the PDA steps. The function essentially depends on the control file to progress to the next PDA step.
4.3 License and Maintenance
Copyright 2025 Penn Computing Inference Learning (PennCIL) lab (https://penncil.med.upenn.edu/team/). Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
The pda package is maintained by the PennCIL team. Users are encouraged to report any bugs or issues at https://github.com/Penncil/pda/issues, or email to Dr. Yong Chen (ychen123@upenn.edu) or Dr. Chongliang Luo (chongliang@wustl.edu).
4.4 PDA demo examples
In this subsection we present the demo example for all the PDA models in the package. These examples run the pda algorithm with multi-site IPD data but in a single local machine. You can run the demo in Rstudio with e.g. demo(ODAL) to see the results below.
4.4.1 PDA demo examples: ODAL
Step 0: load related R packages and prepare sample data
# load packages
require(survival)
require(data.table)
require(pda)
# sample data, lung, from "survival" package
data(lung)
# create 3 sites, split the lung data amongst them
sites = c('site1', 'site2', 'site3')
set.seed(42)
lung2 <- lung[,c('time', 'status', 'age', 'sex')]
lung2$sex <- lung2$sex-1
lung2$status <- ifelse(lung2$status == 2, 1, 0)
lung_split<-split(lung2, sample(1:length(sites), nrow(lung), replace=TRUE))
## fit logistic reg using pooled data
fit.pool <- glm(status ~ age + sex, family = 'binomial', data = lung2)Step 1: Initialization
# ############################ STEP 1: initialize ###############################
## lead site1: please review and enter "1" to allow putting the control file to the server
control <- list(project_name = 'Lung cancer study',
step = 'initialize',
sites = sites,
heterogeneity = FALSE,
model = 'ODAL',
family = 'binomial',
outcome = "status",
variables = c('age', 'sex'),
optim_maxit = 100,
lead_site = 'site1',
upload_date = as.character(Sys.time()) )
## run the example in local directory:
## assume lead site1: enter "1" to allow transferring the control file
pda(site_id = 'site1', control = control, dir = getwd())
##' assume remote site3: enter "1" to allow tranferring your local estimate
pda(site_id = 'site3', ipdata = lung_split[[3]], dir=getwd())
##' assume remote site2: enter "1" to allow tranferring your local estimate
pda(site_id = 'site2', ipdata = lung_split[[2]], dir=getwd())
##' assume lead site1: enter "1" to allow tranferring your local estimate
##' control.json is also automatically updated
pda(site_id = 'site1', ipdata = lung_split[[1]], dir=getwd())Step 2: Calculate derivatives at each site
#' ############################' STEP 2: derivative ###############################
##' assume remote site3: enter "1" to allow tranferring your derivatives
pda(site_id = 'site3', ipdata = lung_split[[3]], dir=getwd())
##' assume remote site2: enter "1" to allow tranferring your derivatives
pda(site_id = 'site2', ipdata = lung_split[[2]], dir=getwd())
##' assume lead site1: enter "1" to allow tranferring your derivatives
pda(site_id = 'site1', ipdata = lung_split[[1]], dir=getwd())Step 3: Surrogate estimate
#' ############################' STEP 3: estimate ###############################
##' assume lead site1: enter "1" to allow tranferring the surrogate estimate
pda(site_id = 'site1', ipdata = lung_split[[1]], dir=getwd())
##' the PDA ODAL is now completed!
##' All the sites can still run their own surrogate estimates and broadcast them.Compare with the pooled and meta estimators
##' compare the surrogate estimate with the pooled estimate
config <- getCloudConfig(site_id = 'site1', dir=getwd())
fit.odal <- pdaGet(name = 'site1_estimate', config = config)
control <- pdaGet(name = 'control', config)
cbind(b.pool=fit.pool$coef,
b.meta=control$beta_init,
b.odal=fit.odal$btilde )