Last active
October 20, 2021 22:38
-
-
Save grosscol/bc40383a3de09987548757208d4d75fb to your computer and use it in GitHub Desktop.
Refactor nested for loop into smaller testable functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### Refactored Birds in Trees code | |
library(dplyr) | |
library(mefa4) | |
# Function to create list of list of args for outer calculation function | |
# returns List of list(stand_id, species_list, stand_data) | |
make_stand_args <- function(stand_id, data){ | |
splist <- data %>% | |
filter(StandID == stand_id) %>% | |
dplyr::select(Species) %>% | |
distinct()%>% | |
pull(Species) | |
result <- list(stand_id = stand_id, | |
species_list = splist) | |
return(result) | |
} | |
# Function to do the inner calculation | |
# calc the mden of single species, | |
# given duration and distance intervals of all species, and tau lookup table | |
calc_mden <- function(species_id, dur_intervals, dis_intervals, tau_ref){ | |
# duration variable phi for species | |
y_dur <- as.matrix(dur_intervals[[species_id]]) | |
d_dur <- matrix(c(3, 5, 10), nrow(y_dur), 3, byrow=TRUE, | |
dimnames=dimnames(y_dur)) | |
# distance variable tau | |
y_dis <- as.matrix(dis_intervals[[species_id]]) | |
d_dis <- matrix(c(0.5, 1), nrow(y_dis), 2, byrow=TRUE, | |
dimnames=dimnames(y_dis)) | |
# grab tau for specific species | |
tau <- tau_ref[which(tau_ref$Sp == species_id),3] | |
rmax <- apply(d_dis, 1, max) | |
q <- (tau^2 / rmax^2) * (1-exp(-(rmax/tau)^2)) | |
A <- pi * rmax^2 | |
a_q <- A * q | |
y_total <- rowSums(y_dur) | |
m_den <- mean(y_total/a_q$tau_best) | |
return(m_den) | |
} | |
# Outer calculation function | |
# return a list of mdens for each stand | |
# Each list of mdens would have one entry for each species. | |
calc_stand_mdens <- function(stand_id, species_list, tau_ref, all_dis, all_dur){ | |
names(species_list) <- species_list | |
species_mdens <- lapply(X=species_list, FUN=calc_mden, | |
dur_intervals=all_dur, dis_intervals=all_dis, | |
tau_ref=tau_ref) | |
return(species_mdens) | |
} | |
# Wrap do.call because I hate trying to stuff it into lapply directly. | |
# Combine dynamic and static args into single arguments list | |
splat_wrapper <- function(dynamic_args, static_args){ | |
args <- c(dynamic_args, static_args) | |
do.call(what=calc_stand_mdens, args=args) | |
} | |
# Input Parameters | |
raw_data <- source('~/Downloads/SampleBirdData.txt')$value | |
tau_ref <- source('~/Downloads/tau_ref.txt')$value | |
stand_list <- source('~/Downloads/sample_standlist.txt')$value | |
# Correct column is a list of lists issue in source data | |
qpadbirdData <- raw_data | |
qpadbirdData$Species <- unlist(raw_data$Species, use.names=F) | |
# Calculate the crosstabs for distance and duration for all species | |
# time Intervals | |
all_dur <- mefa4::Xtab(~ VisitID + Dur + Species, qpadbirdData) | |
# distance intervals | |
all_dis <- mefa4::Xtab(~ VisitID + Dis + Species, qpadbirdData) | |
# Create static args list of the tau_refs and crosstabs | |
static_args <- list(tau_ref=tau_ref, | |
all_dur=all_dur, | |
all_dis=all_dis) | |
# Given a list of stands and the source data, | |
# make a list of arguments lists for the calculation function | |
dynamic_args <- lapply(X = stand_list, | |
FUN = make_stand_args, | |
data = qpadbirdData) | |
# Now run the foo function once for each element (set of args) from stand_args | |
names(stand_args) <- stand_list | |
stand_calcs <- lapply(X = dynamic_args, | |
FUN = splat_wrapper, | |
static_args = static_args) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
c("BEF 15", "NUL 10", "BEF 16", "NUL 2", "BEF 17", "NUL 8", "BEF 14", | |
"NUL 14", "NUL 1", "NUL 13", "NUL 15", "NUL 6", "BEF 11", "BEF 3", | |
"NUL 3", "BEF 2", "BEF 8", "NUL 4", "BEF 9", "BEF 7", "NUL 9", | |
"NUL 7", "NUL 5", "BEF 1", "NUL 12", "NUL 11", "BEF 6", "BEF 12" | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
structure(list(StandID = c("BEF 15", "NUL 10", "BEF 16", "NUL 2", | |
"BEF 17", "NUL 8", "BEF 17", "BEF 17", "BEF 14", "NUL 14", "NUL 1", | |
"NUL 13", "NUL 15", "NUL 6", "NUL 13", "BEF 11", "BEF 14", "NUL 15", | |
"BEF 16", "BEF 3", "NUL 14", "BEF 3", "BEF 14", "NUL 3", "BEF 11", | |
"BEF 2", "NUL 2", "BEF 16", "BEF 8", "BEF 3", "BEF 8", "NUL 4", | |
"BEF 9", "BEF 17", "BEF 7", "NUL 14", "BEF 17", "NUL 10", "NUL 4", | |
"NUL 13", "NUL 9", "NUL 10", "BEF 3", "BEF 2", "BEF 3", "NUL 13", | |
"NUL 15", "NUL 6", "NUL 4", "NUL 7", "BEF 11", "NUL 10", "NUL 5", | |
"NUL 9", "BEF 1", "NUL 12", "NUL 5", "BEF 8", "NUL 7", "NUL 8", | |
"BEF 9", "BEF 1", "NUL 2", "NUL 8", "BEF 7", "BEF 8", "BEF 9", | |
"NUL 8", "BEF 8", "NUL 15", "NUL 5", "NUL 14", "BEF 9", "NUL 13", | |
"NUL 10", "NUL 13", "BEF 14", "NUL 8", "NUL 6", "NUL 10", "BEF 17", | |
"BEF 8", "NUL 11", "BEF 6", "BEF 16", "BEF 2", "NUL 7", "NUL 14", | |
"BEF 16", "NUL 5", "NUL 1", "BEF 15", "NUL 9", "BEF 12", "BEF 11", | |
"BEF 14", "NUL 12", "NUL 5", "NUL 14", "NUL 3"), Species = structure(list( | |
Species = c("NOPA", "HETH", "REVI", "RBNU", "BTNW", "MYWA", | |
"OVEN", "BTNW", "WIWR", "BLBW", "BTNW", "HETH", "SCTA", "YBSA", | |
"RBNU", "BLBW", "GCKI", "BTBW", "REVI", "REVI", "REVI", "REVI", | |
"RBNU", "REVI", "OVEN", "OVEN", "HETH", "REVI", "BLBW", "RCKI", | |
"BTBW", "OVEN", "VEER", "BTNW", "BCCH", "REVI", "WIWR", "BCCH", | |
"OVEN", "BLJA", "YBSA", "MYWA", "BTNW", "BCCH", "PAWA", "BTBW", | |
"NOFL", "REVI", "YBSA", "REVI", "CSWA", "SOSP", "BTNW", "REVI", | |
"BTBW", "BOCH", "YBSA", "CAWA", "BTNW", "HETH", "DEJU", "HETH", | |
"WTSP", "YBSA", "BTBW", "BLJA", "VEER", "REVI", "BTBW", "BTNW", | |
"REVI", "BTBW", "BTBW", "YBSA", "AMRE", "RUGR", "BBCU", "RBNU", | |
"BLBW", "REVI", "BTBW", "NAWA", "BTBW", "GCKI", "BCCH", "RBNU", | |
"HETH", "OVEN", "BTNW", "BLBW", "REVI", "REVI", "REVI", "ALFL", | |
"COYE", "HETH", "REVI", "SWTH", "OVEN", "REVI")), row.names = c(NA, | |
-100L), class = c("tbl_df", "tbl", "data.frame")), Dur = c("5-10min", | |
"0-3min", "0-3min", "5-10min", "5-10min", "5-10min", "0-3min", | |
"5-10min", "0-3min", "3-5min", "5-10min", "0-3min", "0-3min", | |
"3-5min", "0-3min", "0-3min", "5-10min", "0-3min", "0-3min", | |
"5-10min", "3-5min", "5-10min", "0-3min", "0-3min", "0-3min", | |
"0-3min", "3-5min", "5-10min", "0-3min", "0-3min", "0-3min", | |
"0-3min", "0-3min", "0-3min", "0-3min", "0-3min", "0-3min", "3-5min", | |
"0-3min", "0-3min", "3-5min", "0-3min", "0-3min", "0-3min", "3-5min", | |
"0-3min", "5-10min", "0-3min", "3-5min", "0-3min", "0-3min", | |
"0-3min", "0-3min", "3-5min", "0-3min", "0-3min", "5-10min", | |
"0-3min", "0-3min", "0-3min", "0-3min", "0-3min", "0-3min", "5-10min", | |
"0-3min", "5-10min", "3-5min", "5-10min", "3-5min", "3-5min", | |
"5-10min", "0-3min", "0-3min", "0-3min", "0-3min", "0-3min", | |
"3-5min", "5-10min", "3-5min", "0-3min", "0-3min", "0-3min", | |
"0-3min", "0-3min", "0-3min", "0-3min", "0-3min", "0-3min", "5-10min", | |
"0-3min", "0-3min", "0-3min", "0-3min", "0-3min", "0-3min", "5-10min", | |
"0-3min", "0-3min", "0-3min", "0-3min"), Dis = c("0-50m", "50-100m", | |
"50-100m", "0-50m", "50-100m", "50-100m", "0-50m", "0-50m", "50-100m", | |
"50-100m", "0-50m", "50-100m", "0-50m", "50-100m", "50-100m", | |
"0-50m", "50-100m", "50-100m", "50-100m", "50-100m", "50-100m", | |
"50-100m", "0-50m", "0-50m", "0-50m", "50-100m", "50-100m", "0-50m", | |
"50-100m", "0-50m", "50-100m", "50-100m", "0-50m", "50-100m", | |
"50-100m", "50-100m", "50-100m", "50-100m", "50-100m", "50-100m", | |
"50-100m", "50-100m", "50-100m", "0-50m", "50-100m", "0-50m", | |
"0-50m", "50-100m", "50-100m", "0-50m", "50-100m", "50-100m", | |
"50-100m", "50-100m", "50-100m", "0-50m", "0-50m", "0-50m", "0-50m", | |
"0-50m", "0-50m", "50-100m", "50-100m", "0-50m", "0-50m", "50-100m", | |
"0-50m", "50-100m", "50-100m", "50-100m", "50-100m", "50-100m", | |
"0-50m", "0-50m", "0-50m", "50-100m", "0-50m", "0-50m", "50-100m", | |
"0-50m", "0-50m", "50-100m", "0-50m", "0-50m", "0-50m", "0-50m", | |
"0-50m", "50-100m", "0-50m", "50-100m", "0-50m", "50-100m", "50-100m", | |
"50-100m", "50-100m", "0-50m", "0-50m", "50-100m", "0-50m", "50-100m" | |
), VisitID = c("BEF 15 A 182", "NUL 10 A 154", "BEF 16 B 160", | |
"NUL 2 D 172", "BEF 17 D 158", "NUL 8 B 154", "BEF 17 B 182", | |
"BEF 17 C 202", "BEF 14 B 158", "NUL 14 B 193", "NUL 1 B 197", | |
"NUL 13 D 152", "NUL 15 B 150", "NUL 6 D 173", "NUL 13 A 152", | |
"BEF 11 A 159", "BEF 14 A 182", "NUL 15 B 150", "BEF 16 C 160", | |
"BEF 3 A 179", "NUL 14 F 152", "BEF 3 D 179", "BEF 14 B 182", | |
"NUL 3 D 197", "BEF 11 E 159", "BEF 2 E 162", "NUL 2 C 172", | |
"BEF 16 C 180", "BEF 8 A 180", "BEF 3 B 179", "BEF 8 A 180", | |
"NUL 4 A 196", "BEF 9 C 160", "BEF 17 F 158", "BEF 7 E 180", | |
"NUL 14 D 176", "BEF 17 F 182", "NUL 10 D 194", "NUL 4 A 196", | |
"NUL 13 E 193", "NUL 9 C 195", "NUL 10 F 194", "BEF 3 F 179", | |
"BEF 2 E 162", "BEF 3 C 162", "NUL 13 C 193", "NUL 15 D 150", | |
"NUL 6 C 173", "NUL 4 C 196", "NUL 7 A 154", "BEF 11 C 159", | |
"NUL 10 D 154", "NUL 5 B 196", "NUL 9 A 154", "BEF 1 D 202", | |
"NUL 12 B 153", "NUL 5 D 196", "BEF 8 F 180", "NUL 7 B 154", | |
"NUL 8 C 154", "BEF 9 C 204", "BEF 1 E 179", "NUL 2 A 155", "NUL 8 D 174", | |
"BEF 7 D 180", "BEF 8 E 180", "BEF 9 A 180", "NUL 8 A 195", "BEF 8 C 160", | |
"NUL 15 E 150", "NUL 5 B 155", "NUL 14 B 176", "BEF 9 A 180", | |
"NUL 13 D 193", "NUL 10 B 175", "NUL 13 F 176", "BEF 14 A 158", | |
"NUL 8 C 154", "NUL 6 C 155", "NUL 10 E 194", "BEF 17 D 202", | |
"BEF 8 F 180", "NUL 11 F 194", "BEF 6 A 178", "BEF 16 C 160", | |
"BEF 2 B 162", "NUL 7 B 174", "NUL 14 D 193", "BEF 16 D 180", | |
"NUL 5 B 196", "NUL 1 D 172", "BEF 15 C 158", "NUL 9 D 154", | |
"BEF 12 F 159", "BEF 11 D 159", "BEF 14 B 201", "NUL 12 E 153", | |
"NUL 5 A 155", "NUL 14 C 193", "NUL 3 E 172")), row.names = c(NA, | |
-100L), class = c("tbl_df", "tbl", "data.frame")) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
structure(list(Sp = c("RTHU", "BLBW", "GCKI", "BOCH", "BTBW", | |
"BRCR", "MAWA", "CMWA", "BAWW", "AMRE", "BHVI", "NOPA", "CSWA", | |
"CAWA", "BTNW", "MOWA", "WIWR", "REVI", "YBFL", "RBGR", "LEFL", | |
"PAWA", "BLPW", "DOWO", "YBSA", "OVEN", "DEJU", "CEDW", "SCTA", | |
"VEER", "SOSP", "MYWA", "EAWP", "BCCH", "WBNU", "SWSP", "INBU", | |
"BEKI", "NAWA", "HAWO", "ALFL", "GCFL", "AMGO", "WTSP", "SWTH", | |
"LISP", "PUFI", "RCKI", "AMRO", "BLJA", "RBNU", "COYE", "RUGR", | |
"NOWA", "HETH", "BBCU", "NOFL", "PIWO"), tau = c(0.298999, 0.470045, | |
0.388122, 0.474593, 0.452795, 0.464176, 0.607747, 0.5223915, | |
0.615874, 0.6017003, 0.560901, 0.563834, 0.747081, 0.625857, | |
0.595276, 0.777684, 0.590151, 0.69453, 0.633242, 0.931138, 0.769924, | |
0.631699821, 0.631699821, 0.6087145, 0.802057, 0.798386, 0.618904, | |
0.7378935, 0.676319, 0.918361, 0.603962, 0.681626, 0.837621, | |
0.8056039, 0.743488, 0.932883, 0.702112, 0.818148, 0.689438, | |
0.782298, 0.978404, 0.914948, 0.836709, 1.169883, 0.7810633, | |
0.777799, 0.794372, 0.898033, 0.929143, 1.074654, 0.932979, 0.770593, | |
1.10043, 0.723556, 1.27119, 1.88797, 1.37911, 1.45686), tau_best = c(0.2110982, | |
0.364099, 0.379388, 0.409157, 0.447038, 0.449505, 0.452729, 0.460238, | |
0.461154, 0.4969422, 0.513969, 0.535236, 0.535671, 0.536698, | |
0.537636, 0.537947, 0.545593, 0.550853, 0.58209, 0.58465, 0.589032, | |
0.595738, 0.595738, 0.601205, 0.608763, 0.612224, 0.621086, 0.62365, | |
0.631127, 0.666315, 0.66755, 0.677063, 0.706598, 0.7102644, 0.713479, | |
0.719708, 0.747621, 0.751698, 0.753327, 0.7644505, 0.7648203, | |
0.767414, 0.780721, 0.792044, 0.7953055, 0.811148, 0.83448, 0.879949, | |
0.918185, 0.918586, 0.93674, 0.942806, 0.955041, 1.09869, 1.22448, | |
1.25339, 1.41392, 1.43079)), class = c("tbl_df", "tbl", "data.frame" | |
), row.names = c(NA, -58L)) |
ok I just uploaded a sample. I am getting an error that says this when you show traceback. it doesn't like the fact that all_dur is a list but if I get stand_calc_mdens
to return all_dur
and then run it seperately and use as.matrix(all_dur[[species_id]]
manually it works fine
Error in h(simpleError(msg, call)) :
error in evaluating the argument 'x' in selecting a method for function 'as.matrix': invalid subscript type 'list'
9.
h(simpleError(msg, call))
8.
.handleSimpleError(function (cond)
.Internal(C_tryCatchHelper(addr, 1L, cond)), "invalid subscript type 'list'",
base::quote(dur_intervals[[species_id]]))
7.
as.matrix(dur_intervals[[species_id]])
6.
FUN(X[[i]], ...)
5.
lapply(X = species_list, FUN = calc_mden, dur_intervals = all_dur,
dis_intervals = all_dis, tau_ref = tau_ref)
4.
(function (stand_id, species_list, stand_data, tau_ref)
{
all_dur <- Xtab(~VisitID + Dur + Species$Species, stand_data)
all_dis <- Xtab(~VisitID + Dis + Species$Species, stand_data) ...
3.
do.call(what = calc_stand_mdens, args = args)
2.
FUN(X[[i]], ...)
1.
lapply(X = stand_args, FUN = splat_wrapper)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Good catch. The invariant argument would need to be added to
splat_wrapper
, and the static args added to the dynamic ones. Derp.Adding it to the args list works. I usually keep those args lists for things that change with each call invocation, but in this case I think your way is simpler.
As for uploading a sample data set, you could upload the output of
dput
for a sample of the data as your own gist. The r-help-readme channel probably has a bunch of tips about that.