Effect of background noise on schroeder structure detection
Fine scale acoustic perception in zebra finches
Source code and data found at https://github.com/maRce10/acoustic-fine-features-zebra-finch
1 Purpose
- Evaluate the effect of degradation on the detection of acoustic fine structural variation in Schroeders
2 Data analysis workflow
flowchart LR A[Raw Schroeder\nrecordings] --> B(Aritfically\nDecrease SNR) B --> C(measure\nSchroeder\nsimilarity) C --> D(Matrix\nregression\nmodels) style A fill:#44015466 style B fill:#3E4A894D style C fill:#6DCD594D style D fill:#FDE7254D
3 Degradation as a function of signal-to-noise ratio
- Adding synthetic noise to the master sound file annotations to decrease the signal-to-noise
- Evaluate at which signal-to-noise ratio Schroeder sign can still be distinguished
3.1 On 200ms schroeders
3.1.1 Add synthetic noise
3.1.1.1 Repeated Schroeders
Code
master_annotations <- imp_raven(path = "./data/processed", files = "200ms_schroeders.txt",
warbler.format = TRUE, all.data = TRUE)
master_annotations$sound.id <- paste0("f0:", master_annotations$f0,
"_comp:", master_annotations$label)
master_annotations$sound.id[1] <- "start_marker"
master_annotations$sound.id[nrow(master_annotations)] <- "end_marker"
est_master <- selection_table(master_annotations[grep("marker", master_annotations$sound.id,
invert = TRUE), ], extended = TRUE, mar = 0.1, path = "./data/processed")
# est_schr <-
# readRDS('./data/processed/extended_selection_table_schroeders.RDS')
# est_schr <- readRDS(file.path(path,
# 'extended_sel_table_degradation_exp.RDS')) est_schr$treatment
# <- ifelse(grepl('inside', est_schr$sound.files), 'inside',
# 'outside') est_schr$sound.id <- 1:nrow(est_schr) est_in <-
# est_schr[est_schr$treatment == 'inside', ]
est_master <- signal_to_noise_ratio(est_master, mar = 0.07, cores = 20)
hist(est_master$signal.to.noise.ratio)
adj_snr_schroeder_white <- lapply(30:1, function(i) {
print(i)
est_schr_adj <- baRulho::add_noise(X = est_master, target.snr = i,
precision = 0.1, mar = 0.07, cores = 20, kind = "white", seed = NULL)
est_schr_adj$target.snr <- i
return(est_schr_adj)
})
beepr::beep(2)
saveRDS(adj_snr_schroeder_white, "./data/processed/200ms_schroeders_adjusted_snr_white_noise.RDS")
3.1.1.2 Single Schroders
Code
est_schr <- readRDS("./data/processed/extended_selection_table_single_schroeders.RDS")
est_schr$sound.id <- "a"
est_schr <- signal_to_noise_ratio(X = est_schr, mar = 0.01, cores = 20,
bp = NULL)
hist(est_schr$signal.to.noise.ratio)
adj_snr_schroeder_white <- lapply(30:1, function(i) {
print(i)
est_schr_adj <- add_noise(X = est_schr, target.snr = i, precision = 0.1,
mar = 0.01, cores = 1, bp = NULL, kind = "white", seed = NULL)
est_schr_adj$target.snr <- i
return(est_schr_adj)
})
beepr::beep(2)
saveRDS(adj_snr_schroeder_white, "./data/processed/single_schroeder_adjusted_snr_white_noise.RDS")
3.1.2 Check SNR adjusted waves
3.1.2.1 Examples
3.1.2.1.1 Repeated Schroeders
200 Hz, 9 components, positive phase
Code
adj_snr_schroeder <- readRDS("./data/processed/200ms_schroeders_adjusted_snr_white_noise.RDS")
# print(adj_snr_schroeder[[1]]$sound.id[10])
par(mar = c(0, 0, 0, 0), mfrow = c(5, 6))
for (i in 1:30) {
warbleR:::spectro_wrblr_int(wave = read_sound_file(adj_snr_schroeder[[i]],
10, from = 0, to = Inf), flim = c(0, 5), osc = FALSE, scale = FALSE,
axisY = FALSE, axisX = FALSE, grid = FALSE, palette = viridis::mako,
collevels = seq(-110, 0, 5))
text(0.2, 4, paste("SNR:", adj_snr_schroeder[[i]]$target.snr[1]),
col = "black", cex = 1.3)
}
500 Hz, 16 components, positive phase
Code
# print(adj_snr_schroeder[[1]]$sound.id[150])
par(mar = c(0, 0, 0, 0), mfrow = c(5, 6))
for (i in 1:30) {
warbleR:::spectro_wrblr_int(wave = read_sound_file(adj_snr_schroeder[[i]],
150, from = 0, to = Inf), flim = c(0, 12), osc = FALSE, scale = FALSE,
axisY = FALSE, axisX = FALSE, grid = FALSE, palette = viridis::mako,
collevels = seq(-110, 0, 5))
text(0.2, 11, paste("SNR:", adj_snr_schroeder[[i]]$target.snr[1]),
col = "black", cex = 1.3)
}
700 Hz, 24 components, positive phase
Code
# print(adj_snr_schroeder[[1]]$sound.id[250])
par(mar = c(0, 0, 0, 0), mfrow = c(5, 6))
for (i in 1:30) {
warbleR:::spectro_wrblr_int(wave = read_sound_file(adj_snr_schroeder[[i]],
250, from = 0, to = Inf), flim = c(0, 20), osc = FALSE, scale = FALSE,
axisY = FALSE, axisX = FALSE, grid = FALSE, palette = viridis::mako,
collevels = seq(-110, 0, 5))
text(0.2, 18, paste("SNR:", adj_snr_schroeder[[i]]$target.snr[1]),
col = "black", cex = 1.3)
}
3.1.2.1.2 Single Schroeders
200 Hz, 9 components, positive phase
Code
adj_snr_schroeder <- readRDS("./data/processed/single_schroeder_adjusted_snr_white_noise.RDS")
# print(adj_snr_schroeder[[1]]$sound.id[10])
par(mar = c(0, 0, 0, 0), mfrow = c(5, 6))
for (i in 1:30) {
wv <- read_sound_file(adj_snr_schroeder[[i]], 10)@left
plot(wv, type = "l", lwd = 2, col = mako(10)[6], xlab = "", ylab = "",
axes = FALSE, ylim = c(-2, 2))
box()
text(length(wv)/2, 1.7, paste("SNR:", adj_snr_schroeder[[i]]$target.snr[1]),
col = "black", cex = 1.3)
}
200 Hz, 9 components, negative phase
Code
# print(adj_snr_schroeder[[1]]$sound.id[9])
par(mar = c(0, 0, 0, 0), mfrow = c(5, 6))
for (i in 1:30) {
wv <- read_sound_file(adj_snr_schroeder[[i]], 9)@left
plot(wv, type = "l", lwd = 2, col = mako(10)[6], xlab = "", ylab = "",
axes = FALSE, ylim = c(-2, 2))
box()
text(length(wv)/2, 1.7, paste("SNR:", adj_snr_schroeder[[i]]$target.snr[1]),
col = "black", cex = 1.3)
}
500 Hz, 16 components, positive phase
Code
# print(adj_snr_schroeder[[1]]$sound.files[150])
par(mar = c(0, 0, 0, 0), mfrow = c(5, 6))
for (i in 1:30) {
wv <- read_sound_file(adj_snr_schroeder[[i]], 150)@left
plot(wv, type = "l", lwd = 2, col = mako(10)[6], xlab = "", ylab = "",
axes = FALSE, ylim = c(-2, 2))
box()
text(length(wv)/2, 1.7, paste("SNR:", adj_snr_schroeder[[i]]$target.snr[1]),
col = "black", cex = 1.3)
}
500 Hz, 16 components, negative phase
Code
# print(adj_snr_schroeder[[1]]$sound.files[149])
par(mar = c(0, 0, 0, 0), mfrow = c(5, 6))
for (i in 1:30) {
wv <- read_sound_file(adj_snr_schroeder[[i]], 149)@left
plot(wv, type = "l", lwd = 2, col = mako(10)[6], xlab = "", ylab = "",
axes = FALSE, ylim = c(-2, 2))
box()
text(length(wv)/2, 1.7, paste("SNR:", adj_snr_schroeder[[i]]$target.snr[1]),
col = "black", cex = 1.3)
}
700 Hz, 24 components, positive phase
Code
# print(adj_snr_schroeder[[1]]$sound.files[250])
par(mar = c(0, 0, 0, 0), mfrow = c(5, 6))
for (i in 1:30) {
wv <- read_sound_file(adj_snr_schroeder[[i]], 250)@left
plot(wv, type = "l", lwd = 2, col = mako(10)[6], xlab = "", ylab = "",
axes = FALSE, ylim = c(-2, 2))
box()
text(length(wv)/2, 1.7, paste("SNR:", adj_snr_schroeder[[i]]$target.snr[1]),
col = "black", cex = 1.3)
}
700 Hz, 24 components, negative phase
Code
# print(adj_snr_schroeder[[1]]$sound.files[249])
par(mar = c(0, 0, 0, 0), mfrow = c(5, 6))
for (i in 1:30) {
wv <- read_sound_file(adj_snr_schroeder[[i]], 249)@left
plot(wv, type = "l", lwd = 2, col = mako(10)[6], xlab = "", ylab = "",
axes = FALSE, ylim = c(-2, 2))
box()
text(length(wv)/2, 1.7, paste("SNR:", adj_snr_schroeder[[i]]$target.snr[1]),
col = "black", cex = 1.3)
}
3.1.3 Measure DTW distances
3.1.3.1 On repeated Schroeders
Code
adj_snr_schroeder <- readRDS("./data/processed/200ms_schroeders_adjusted_snr_white_noise.RDS")
dtw_dist_white_noise <- lapply(adj_snr_schroeder, function(schroeders) {
print(schroeders$target.snr[1])
cmbs <- t(combn(schroeders$sound.files, 2))
min_dist_l <- pbapply::pbsapply(cl = 22, 1:nrow(cmbs), function(x) {
s1 <- read_sound_file(schroeders, index = which(schroeders$sound.files ==
cmbs[x, 1]))@left
s2 <- read_sound_file(schroeders, index = which(schroeders$sound.files ==
cmbs[x, 2]))@left
# normalize
s1 <- s1/max(abs(s1))
s2 <- s2/max(abs(s2))
# make same length if (length(s1) != length(s2))
s1 <- approx(s1, n = 100)$y
s2 <- approx(s2, n = 100)$y
# duplicate 1
s1 <- rep(s1, 2)
# run dtw over longer vector
dists <- vapply(seq_len(length(s1) - length(s2)), function(x) {
segment <- s1[x:min(c(x + length(s2) - 1), length(s1))]
dtw_dist <- dtw::dtwDist(mx = rbind(s2, segment))
return(dtw_dist[1, 2])
}, FUN.VALUE = numeric(1))
return(data.frame(schr1 = cmbs[x, 1], schr2 = cmbs[x, 2],
min(dists)))
})
min_dists <- do.call(rbind, min_dist_l)
min_dists <- as.data.frame(matrix(min_dists[, 1], ncol = 3, byrow = TRUE))
names(min_dists) <- c("schr1", "schr2", "dtw.dist")
min_dists$dtw.dist <- as.numeric(min_dists$dtw.dist)
min_dists$target.snr <- schroeders$target.snr[1]
return(min_dists)
})
beepr::beep(2)
saveRDS(dtw_dist_white_noise, "./data/processed/dtw_distance_adjusted_snr_200ms_schroeders_white_noise.RDS")
3.1.3.2 On single Schroeders
Code
adj_snr_schroeder <- readRDS("./data/processed/single_schroeder_adjusted_snr_white_noise.RDS")
dtw_dist_white_noise <- lapply(adj_snr_schroeder, function(schroeders) {
print(schroeders$target.snr[1])
cmbs <- t(combn(schroeders$sound.files, 2))
min_dist_l <- pbapply::pbsapply(cl = 22, 1:nrow(cmbs), function(x) {
s1 <- read_sound_file(schroeders, index = which(schroeders$sound.files ==
cmbs[x, 1]))@left
s2 <- read_sound_file(schroeders, index = which(schroeders$sound.files ==
cmbs[x, 2]))@left
# normalize
s1 <- s1/max(abs(s1))
s2 <- s2/max(abs(s2))
# make same length if (length(s1) != length(s2))
s1 <- approx(s1, n = 100)$y
s2 <- approx(s2, n = 100)$y
# duplicate 1
s1 <- rep(s1, 2)
# run dtw over longer vector
dists <- vapply(seq_len(length(s1) - length(s2)), function(x) {
segment <- s1[x:min(c(x + length(s2) - 1), length(s1))]
dtw_dist <- dtw::dtwDist(mx = rbind(s2, segment))
return(dtw_dist[1, 2])
}, FUN.VALUE = numeric(1))
return(data.frame(schr1 = cmbs[x, 1], schr2 = cmbs[x, 2],
min(dists)))
})
min_dists <- do.call(rbind, min_dist_l)
min_dists <- as.data.frame(matrix(min_dists[, 1], ncol = 3, byrow = TRUE))
names(min_dists) <- c("schr1", "schr2", "dtw.dist")
min_dists$dtw.dist <- as.numeric(min_dists$dtw.dist)
min_dists$target.snr <- schroeders$target.snr[1]
return(min_dists)
})
beepr::beep(2)
saveRDS(dtw_dist_white_noise, "./data/processed/dtw_distance_adjusted_snr_single_schroeder_white_noise.RDS")
3.1.3.3 Statistical analysis
Modeling: - Multiple Regression on distance Matrices - Model:
\[\begin{align*}
Dissimilarity &\sim frequency + components + phase
\end{align*}\] - Response values scaled to make effect sizes comparable across models - Predictors were coded as pairwise binary matrices in which 0 means that calls in a dyad belong to the same level and 1 means calls belong to different levels - One model for each environment treatment as well as on the original model sounds
3.1.3.3.1 On repeated Schroeders
Code
dtw_dists_snr_list <- readRDS("./data/processed/dtw_distance_adjusted_snr_200ms_schroeders_white_noise.RDS")
adj_snr_schroeder1 <- readRDS("./data/processed/200ms_schroeders_adjusted_snr_white_noise.RDS")[[1]]
adj_snr_schroeder1$sound.id <- gsub("f0:f0 ", "f0:", adj_snr_schroeder1$sound.id)
dtw_wv_mod_list <- warbleR:::pblapply_wrblr_int(dtw_dists_snr_list,
cl = 20, function(x) {
# x$dist <- scale(x$dist)
target_snr <- x$target.snr
x$target.snr <- NULL
x$schr1 <- sapply(x$schr1, function(x) adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files ==
x])
x$schr2 <- sapply(x$schr2, function(x) adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files ==
x])
dist_tri <- PhenotypeSpace::rectangular_to_triangular(x)
freq_bi_tri <- as.dist(binary_triangular_matrix(group = sapply(strsplit(rownames(dist_tri),
"_"), "[[", 1)))
comp_bi_tri <- as.dist(binary_triangular_matrix(group = gsub("_n|_p",
"", sapply(strsplit(rownames(dist_tri), "_"), "[[", 2))))
sign_bi_tri <- as.dist(binary_triangular_matrix(group = sapply(strsplit(rownames(dist_tri),
"_"), "[[", 3)))
rect_var <- cbind(as.dist(dist_tri), freq_bi_tri, comp_bi_tri,
sign_bi_tri)
colnames(rect_var) <- c("dtw_dist", "frequency", "components",
"sign")
dtw_wv_mod <- MRM2(formula = dtw_dist ~ frequency + components +
sign, nperm = 10000, mat = rect_var)
return(dtw_wv_mod)
})
names(dtw_wv_mod_list) <- paste0("snr:", sapply(dtw_dists_snr_list,
function(x) x$target.snr[1]))
saveRDS(dtw_wv_mod_list, "./data/processed/matrix_correlation_dtw_distance_varying_snr_white_noise.RDS")
Code
mods <- readRDS("./data/processed/matrix_correlation_dtw_distance_varying_snr_white_noise.RDS")
estimates_dtw_wn <- do.call(rbind, lapply(seq_along(mods), function(x) {
Y <- data.frame(mods[[x]]$coef[-1, ])
# Y$rel_coef <- Y[, 1] / max(Y[, 1])
Y$rel_coef <- Y[, 1]
Y$predictor <- rownames(Y)
Y$model <- as.numeric(gsub("snr:", "", names(mods)[x]))
names(Y) <- c("coef", "p", "rel_coef", "predictor", "model")
return(Y)
}))
estimates_dtw_wn$rel_coef <- ifelse(estimates_dtw_wn$p < 0.05, estimates_dtw_wn$rel_coef,
0)
estimates_dtw_wn$signif <- ifelse(estimates_dtw_wn$p < 0.05, "p < 0.05",
"p >= 0.05")
estimates_dtw_wn$signif2 <- ifelse(estimates_dtw_wn$p < 0.05, "*",
"")
estimates_dtw_wn$model_f <- factor(estimates_dtw_wn$model, levels = 1:30)
ggplot(estimates_dtw_wn, aes(x = predictor, y = model_f, fill = rel_coef)) +
geom_tile() + coord_equal() + scale_fill_gradient2(low = viridis(10)[3],
high = viridis(10)[7], guide = "none") + geom_text(aes(label = signif2,
color = signif), size = 3) + scale_color_manual(values = c("black",
"gray")) + labs(y = "Signal-to-noise ratio", x = "Predictor",
color = "P value") + theme_classic() + theme(axis.text.x = element_text(color = "black",
size = 7, angle = 30, vjust = 0.8, hjust = 0.8)) + coord_flip()
Code
coef_by_signif <- aggregate(coef ~ signif, data = estimates_dtw_wn,
FUN = range)
ggplot(estimates_dtw_wn, aes(y = coef, x = model, color = predictor,
lty = predictor)) + geom_line(linewidth = 1.6) + labs(x = "Signal-to-noise ratio",
y = "Effect size") + scale_color_viridis_d(alpha = 0.7, begin = 0.2,
end = 0.8) + geom_hline(yintercept = mean(coef_by_signif[, 2][1,
1], coef_by_signif[, 2][2, 2]), lty = 2, color = "gray") + theme_classic()
3.1.3.3.1.1 Only phase
Code
ggplot(estimates_dtw_wn[estimates_dtw_wn$predictor == "sign", ], aes(y = coef,
x = model, color = predictor, lty = predictor)) + geom_line(linewidth = 1.6) +
geom_smooth() + labs(x = "Signal-to-noise ratio", y = "Effect size") +
scale_color_viridis_d(alpha = 0.7, begin = 0.2, end = 0.8) + geom_hline(yintercept = mean(coef_by_signif[,
2][1, 1], coef_by_signif[, 2][2, 2]), lty = 2, color = "gray") +
theme_classic() + geom_vline(xintercept = 16, lty = 2, color = "gray")
3.1.3.3.1.2 By frequency
Code
dtw_dists_snr_list <- readRDS("./data/processed/dtw_distance_adjusted_snr_200ms_schroeders_white_noise.RDS")
adj_snr_schroeder1 <- readRDS("./data/processed/200ms_schroeders_adjusted_snr_pink_noise.RDS")[[1]]
adj_snr_schroeder1$sound.id <- gsub("f0:f0 ", "f0:", adj_snr_schroeder1$sound.id)
dtw_wv_mod_list <- warbleR:::pblapply_wrblr_int(dtw_dists_snr_list,
cl = 1, function(y) {
# print(y$target.snr[1])
freqs <- unique(substr(sapply(y[, 1], function(x) adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files ==
x]), 0, 6))
mods <- lapply(1:length(freqs), function(i) {
y$schr1 <- sapply(y$schr1, function(x) adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files ==
x])
y$schr2 <- sapply(y$schr2, function(x) adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files ==
x])
# extract only those with the same freq
x <- y[grepl(paste(freqs[i], collapse = "|"), y$schr1) &
grepl(paste(freqs[i], collapse = "|"), y$schr2), ]
target_snr <- x$target.snr
x$target.snr <- NULL
dist_tri <- PhenotypeSpace::rectangular_to_triangular(x)
if (nrow(dist_tri) > 2) {
comp_bi_tri <- as.dist(binary_triangular_matrix(group = gsub("_n|_p",
"", sapply(strsplit(rownames(dist_tri), "_"), "[[",
2))))
sign_bi_tri <- as.dist(binary_triangular_matrix(group = sapply(strsplit(rownames(dist_tri),
"_"), "[[", 3)))
rect_var <- cbind(as.dist(dist_tri), comp_bi_tri,
sign_bi_tri)
colnames(rect_var) <- c("dtw_dist", "components",
"sign")
dtw_wv_mod <- MRM2(formula = dtw_dist ~ components +
sign, nperm = 10000, mat = rect_var)
} else dtw_wv_mod <- NULL
return(dtw_wv_mod)
})
names(mods) <- paste0("snr:", y$target.snr[1], "_", freqs)
mods <- mods[!sapply(mods, is.null)]
return(mods)
})
saveRDS(dtw_wv_mod_list, "./data/processed/matrix_correlation_dtw_distance_varying_snr_by_frequency_white_noise.RDS")
Discriminating Schroeder’s by phase grouped by frequency:
Code
mods <- readRDS("./data/processed/matrix_correlation_dtw_distance_varying_snr_by_frequency_white_noise.RDS")
estimates_list <- lapply(mods, function(y) {
estimates <- do.call(rbind, lapply(seq_along(y), function(x) {
Y <- data.frame(y[[x]]$coef[-1, ])
# Y$rel_coef <- Y[, 1] / max(Y[, 1])
Y$rel_coef <- Y[, 1]
Y$mod <- names(y)[x]
Y$predictor <- rownames(Y)
Y$freq <- strsplit(names(y)[x], "_")[[1]][2]
Y$freq <- strsplit(Y$freq, ":")[[1]][2]
names(Y) <- c("coef", "p", "rel_coef", "model", "predictor",
"freq")
Y$snr <- gsub("_", "", substr(names(y)[x], 0, 6))
return(Y)
}))
estimates$rel_coef <- ifelse(estimates$p < 0.05, estimates$rel_coef,
0)
estimates$signif <- ifelse(estimates$p < 0.05, "p < 0.05", "p >= 0.05")
return(estimates)
})
estimates <- do.call(rbind, estimates_list)
estimates$snr <- as.numeric(substr(estimates$snr, 5, nchar(estimates$snr)))
rownames(estimates) <- 1:nrow(estimates)
coef_by_signif <- aggregate(coef ~ signif, data = estimates[estimates$predictor ==
"sign", ], FUN = range)
ggplot(estimates[estimates$predictor == "sign", ], aes(y = coef, x = snr,
color = freq)) + geom_line(linewidth = 1.6) + ylim(c(-0.2, 0.5)) +
labs(x = "Signal-to-noise ratio", y = "Effect size when discriminating phase",
color = "F0\nfrequency") + scale_color_viridis_d(alpha = 0.7,
begin = 0.2, end = 0.8) + theme_classic()
Warning: Removed 24 rows containing missing values or values outside the scale range
(`geom_line()`).
Discriminating Schroeder’s by number of components grouped by frequency:
Code
coef_by_signif <- aggregate(coef ~ signif, data = estimates[estimates$predictor ==
"components", ], FUN = range)
ggplot(estimates[estimates$predictor == "components", ], aes(y = coef,
x = snr, color = freq)) + geom_line(linewidth = 1.6) + labs(x = "Signal-to-noise ratio",
y = "Effect size when discriminating number of components", color = "F0\nfrequency") +
scale_color_viridis_d(alpha = 0.7, begin = 0.1, end = 0.9) + geom_hline(yintercept = mean(coef_by_signif[,
2][1, 1], coef_by_signif[, 2][2, 2]), lty = 2, color = "gray") +
theme_classic()
3.1.3.3.2 On single Schroeders
Code
dtw_dists_snr_list <- readRDS("./data/processed/dtw_distance_adjusted_snr_single_schroeder_white_noise.RDS")
adj_snr_schroeder1 <- readRDS("./data/processed/200ms_schroeders_adjusted_snr_white_noise.RDS")[[1]]
adj_snr_schroeder1$sound.id <- gsub("f0:f0 ", "f0:", adj_snr_schroeder1$sound.id)
dtw_wv_mod_list <- warbleR:::pblapply_wrblr_int(dtw_dists_snr_list,
cl = 20, function(x) {
# x$dist <- scale(x$dist)
target_snr <- x$target.snr
x$target.snr <- NULL
x$schr1 <- sapply(strsplit(x$schr1, "_"), function(x) paste(x[2],
x[3], substr(x[4], 0, 1), sep = "_"))
x$schr2 <- sapply(strsplit(x$schr2, "_"), function(x) paste(x[2],
x[3], substr(x[4], 0, 1), sep = "_"))
# x$schr1 <- sapply(x$schr1, function(x)
# adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files
# == x]) x$schr2 <- sapply(x$schr2, function(x)
# adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files
# == x])
dist_tri <- PhenotypeSpace::rectangular_to_triangular(x)
freq_bi_tri <- as.dist(binary_triangular_matrix(group = sapply(strsplit(rownames(dist_tri),
"_"), "[[", 1)))
comp_bi_tri <- as.dist(binary_triangular_matrix(group = gsub("_n|_p",
"", sapply(strsplit(rownames(dist_tri), "_"), "[[", 2))))
sign_bi_tri <- as.dist(binary_triangular_matrix(group = sapply(strsplit(rownames(dist_tri),
"_"), "[[", 3)))
rect_var <- cbind(as.dist(dist_tri), freq_bi_tri, comp_bi_tri,
sign_bi_tri)
colnames(rect_var) <- c("dtw_dist", "frequency", "components",
"sign")
dtw_wv_mod <- MRM2(formula = dtw_dist ~ frequency + components +
sign, nperm = 10000, mat = rect_var)
return(dtw_wv_mod)
})
names(dtw_wv_mod_list) <- paste0("snr:", sapply(dtw_dists_snr_list,
function(x) x$target.snr[1]))
saveRDS(dtw_wv_mod_list, "./data/processed/matrix_correlation_dtw_distance_single_schroeder_varying_snr_white_noise.RDS")
Code
mods <- readRDS("./data/processed/matrix_correlation_dtw_distance_single_schroeder_varying_snr_white_noise.RDS")
estimates_dtw_wn <- do.call(rbind, lapply(seq_along(mods), function(x) {
Y <- data.frame(mods[[x]]$coef[-1, ])
# Y$rel_coef <- Y[, 1] / max(Y[, 1])
Y$rel_coef <- Y[, 1]
Y$predictor <- rownames(Y)
Y$model <- as.numeric(gsub("snr:", "", names(mods)[x]))
names(Y) <- c("coef", "p", "rel_coef", "predictor", "model")
return(Y)
}))
estimates_dtw_wn$rel_coef <- ifelse(estimates_dtw_wn$p < 0.05, estimates_dtw_wn$rel_coef,
0)
estimates_dtw_wn$signif <- ifelse(estimates_dtw_wn$p < 0.05, "p < 0.05",
"p >= 0.05")
estimates_dtw_wn$signif2 <- ifelse(estimates_dtw_wn$p < 0.05, "*",
"")
estimates_dtw_wn$model_f <- factor(estimates_dtw_wn$model, levels = 1:30)
ggplot(estimates_dtw_wn, aes(x = predictor, y = model_f, fill = rel_coef)) +
geom_tile() + coord_equal() + scale_fill_gradient2(low = viridis(10)[3],
high = viridis(10)[7], guide = "none") + geom_text(aes(label = signif2,
color = signif), size = 3) + scale_color_manual(values = c("black",
"gray")) + labs(y = "Signal-to-noise ratio", x = "Predictor",
color = "P value") + theme_classic() + theme(axis.text.x = element_text(color = "black",
size = 7, angle = 30, vjust = 0.8, hjust = 0.8)) + coord_flip()
Code
coef_by_signif <- aggregate(coef ~ signif, data = estimates_dtw_wn,
FUN = range)
ggplot(estimates_dtw_wn, aes(y = coef, x = model, color = predictor,
lty = predictor)) + geom_line(linewidth = 1.6) + labs(x = "Signal-to-noise ratio",
y = "Effect size") + scale_color_viridis_d(alpha = 0.7, begin = 0.2,
end = 0.8) + geom_hline(yintercept = mean(coef_by_signif[, 2][1,
1], coef_by_signif[, 2][2, 2]), lty = 2, color = "gray") + theme_classic()
3.1.3.3.2.1 Only phase
Code
ggplot(estimates_dtw_wn[estimates_dtw_wn$predictor == "sign", ], aes(y = coef,
x = model, color = predictor, lty = predictor)) + geom_line(linewidth = 1.6) +
geom_smooth() + labs(x = "Signal-to-noise ratio", y = "Effect size") +
scale_color_viridis_d(alpha = 0.7, begin = 0.2, end = 0.8) + geom_hline(yintercept = mean(coef_by_signif[,
2][1, 1], coef_by_signif[, 2][2, 2]), lty = 2, color = "gray") +
theme_classic() + geom_vline(xintercept = 16, lty = 2, color = "gray")
3.1.3.3.2.2 By frequency
Code
dtw_dists_snr_list <- readRDS("./data/processed/dtw_distance_adjusted_snr_200ms_schroeders_white_noise.RDS")
adj_snr_schroeder1 <- readRDS("./data/processed/200ms_schroeders_adjusted_snr_pink_noise.RDS")[[1]]
adj_snr_schroeder1$sound.id <- gsub("f0:f0 ", "f0:", adj_snr_schroeder1$sound.id)
dtw_wv_mod_list <- warbleR:::pblapply_wrblr_int(dtw_dists_snr_list,
cl = 1, function(y) {
# print(y$target.snr[1])
freqs <- unique(substr(sapply(y[, 1], function(x) adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files ==
x]), 0, 6))
mods <- lapply(1:length(freqs), function(i) {
y$schr1 <- sapply(y$schr1, function(x) adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files ==
x])
y$schr2 <- sapply(y$schr2, function(x) adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files ==
x])
# extract only those with the same freq
x <- y[grepl(paste(freqs[i], collapse = "|"), y$schr1) &
grepl(paste(freqs[i], collapse = "|"), y$schr2), ]
target_snr <- x$target.snr
x$target.snr <- NULL
dist_tri <- PhenotypeSpace::rectangular_to_triangular(x)
if (nrow(dist_tri) > 2) {
comp_bi_tri <- as.dist(binary_triangular_matrix(group = gsub("_n|_p",
"", sapply(strsplit(rownames(dist_tri), "_"), "[[",
2))))
sign_bi_tri <- as.dist(binary_triangular_matrix(group = sapply(strsplit(rownames(dist_tri),
"_"), "[[", 3)))
rect_var <- cbind(as.dist(dist_tri), comp_bi_tri,
sign_bi_tri)
colnames(rect_var) <- c("dtw_dist", "components",
"sign")
dtw_wv_mod <- MRM2(formula = dtw_dist ~ components +
sign, nperm = 10000, mat = rect_var)
} else dtw_wv_mod <- NULL
return(dtw_wv_mod)
})
names(mods) <- paste0("snr:", y$target.snr[1], "_", freqs)
mods <- mods[!sapply(mods, is.null)]
return(mods)
})
saveRDS(dtw_wv_mod_list, "./data/processed/matrix_correlation_dtw_distance_varying_snr_by_frequency_white_noise.RDS")
Discriminating Schroeder’s by phase grouped by frequency:
Code
mods <- readRDS("./data/processed/matrix_correlation_dtw_distance_varying_snr_by_frequency_white_noise.RDS")
estimates_list <- lapply(mods, function(y) {
estimates <- do.call(rbind, lapply(seq_along(y), function(x) {
Y <- data.frame(y[[x]]$coef[-1, ])
# Y$rel_coef <- Y[, 1] / max(Y[, 1])
Y$rel_coef <- Y[, 1]
Y$mod <- names(y)[x]
Y$predictor <- rownames(Y)
Y$freq <- strsplit(names(y)[x], "_")[[1]][2]
Y$freq <- strsplit(Y$freq, ":")[[1]][2]
names(Y) <- c("coef", "p", "rel_coef", "model", "predictor",
"freq")
Y$snr <- gsub("_", "", substr(names(y)[x], 0, 6))
return(Y)
}))
estimates$rel_coef <- ifelse(estimates$p < 0.05, estimates$rel_coef,
0)
estimates$signif <- ifelse(estimates$p < 0.05, "p < 0.05", "p >= 0.05")
return(estimates)
})
estimates <- do.call(rbind, estimates_list)
estimates$snr <- as.numeric(substr(estimates$snr, 5, nchar(estimates$snr)))
rownames(estimates) <- 1:nrow(estimates)
coef_by_signif <- aggregate(coef ~ signif, data = estimates[estimates$predictor ==
"sign", ], FUN = range)
ggplot(estimates[estimates$predictor == "sign", ], aes(y = coef, x = snr,
color = freq)) + geom_line(linewidth = 1.6) + ylim(c(-0.2, 0.5)) +
labs(x = "Signal-to-noise ratio", y = "Effect size when discriminating phase",
color = "F0\nfrequency") + scale_color_viridis_d(alpha = 0.7,
begin = 0.2, end = 0.8) + theme_classic()
Warning: Removed 24 rows containing missing values or values outside the scale range
(`geom_line()`).
Discriminating Schroeder’s by number of components grouped by frequency:
Code
coef_by_signif <- aggregate(coef ~ signif, data = estimates[estimates$predictor ==
"components", ], FUN = range)
ggplot(estimates[estimates$predictor == "components", ], aes(y = coef,
x = snr, color = freq)) + geom_line(linewidth = 1.6) + labs(x = "Signal-to-noise ratio",
y = "Effect size when discriminating number of components", color = "F0\nfrequency") +
scale_color_viridis_d(alpha = 0.7, begin = 0.1, end = 0.9) + geom_hline(yintercept = mean(coef_by_signif[,
2][1, 1], coef_by_signif[, 2][2, 2]), lty = 2, color = "gray") +
theme_classic()
3.1.4 Measure waveform correlation
3.1.4.1 On repeated Schroeders
Code
adj_snr_schroeder <- readRDS("./data/processed/200ms_schroeders_adjusted_snr_white_noise.RDS")
cor_noise <- lapply(adj_snr_schroeder, function(schroeders) {
print(schroeders$target.snr[1])
cmbs <- t(combn(schroeders$sound.files, 2))
min_cor_l <- pbapply::pbsapply(cl = 20, 1:nrow(cmbs), function(x) {
s1 <- read_sound_file(schroeders, index = which(schroeders$sound.files ==
cmbs[x, 1]))@left
s2 <- read_sound_file(schroeders, index = which(schroeders$sound.files ==
cmbs[x, 2]))@left
# normalize
s1 <- s1/max(abs(s1))
s2 <- s2/max(abs(s2))
# make same length if (length(s1) != length(s2))
s1 <- approx(s1, n = 100)$y
s2 <- approx(s2, n = 100)$y
# run correlation
cor <- cor(s1, s2)
return(data.frame(schr1 = cmbs[x, 1], schr2 = cmbs[x, 2],
cor = cor))
})
cors <- do.call(rbind, min_cor_l)
cors <- as.data.frame(matrix(cors[, 1], ncol = 3, byrow = TRUE))
names(cors) <- c("schr1", "schr2", "cor")
cors$cor <- as.numeric(cors$cor)
cors$target.snr <- cors$target.snr[1]
return(cors)
})
names(cor_noise) <- paste0("snr:", sapply(adj_snr_schroeder, function(x) x$target.snr[1]))
beepr::beep(2)
saveRDS(cor_noise, "./data/processed/waveform_correlation_adjusted_snr_200ms_schroeders_white_noise.RDS")
3.1.4.2 On single Schroeders
Code
adj_snr_schroeder <- readRDS("./data/processed/single_schroeder_adjusted_snr_white_noise.RDS")
cor_noise <- lapply(adj_snr_schroeder, function(schroeders) {
print(schroeders$target.snr[1])
cmbs <- t(combn(schroeders$sound.files, 2))
min_cor_l <- pbapply::pbsapply(cl = 20, 1:nrow(cmbs), function(x) {
s1 <- read_sound_file(schroeders, index = which(schroeders$sound.files ==
cmbs[x, 1]))@left
s2 <- read_sound_file(schroeders, index = which(schroeders$sound.files ==
cmbs[x, 2]))@left
# normalize
s1 <- s1/max(abs(s1))
s2 <- s2/max(abs(s2))
# make same length if (length(s1) != length(s2))
s1 <- approx(s1, n = 100)$y
s2 <- approx(s2, n = 100)$y
# run correlation
cor <- cor(s1, s2)
return(data.frame(schr1 = cmbs[x, 1], schr2 = cmbs[x, 2],
cor = cor))
})
cors <- do.call(rbind, min_cor_l)
cors <- as.data.frame(matrix(cors[, 1], ncol = 3, byrow = TRUE))
names(cors) <- c("schr1", "schr2", "cor")
cors$cor <- as.numeric(cors$cor)
cors$target.snr <- cors$target.snr[1]
return(cors)
})
names(cor_noise) <- paste0("snr:", sapply(adj_snr_schroeder, function(x) x$target.snr[1]))
beepr::beep(2)
saveRDS(cor_noise, "./data/processed/waveform_correlation_adjusted_snr_single_schroeders_white_noise.RDS")
3.1.4.3 Statistical analysis
3.1.4.3.1 On repeated Schroeders
Code
cor_snr_list <- readRDS("./data/processed/waveform_correlation_adjusted_snr_200ms_schroeders_white_noise.RDS")
adj_snr_schroeder1 <- readRDS("./data/processed/200ms_schroeders_adjusted_snr_white_noise.RDS")[[1]]
adj_snr_schroeder1$sound.id <- gsub("f0:f0 ", "f0:", adj_snr_schroeder1$sound.id)
cor_mod_list <- warbleR:::pblapply_wrblr_int(names(cor_snr_list),
cl = 20, function(x) {
x <- cor_snr_list[[x]]
# x$dist <- scale(x$dist)
target_snr <- "snr:30"
x$schr1 <- sapply(x$schr1, function(x) adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files ==
x])
x$schr2 <- sapply(x$schr2, function(x) adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files ==
x])
x$cor <- x$cor * -1
dist_tri <- PhenotypeSpace::rectangular_to_triangular(x)
freq_bi_tri <- as.dist(binary_triangular_matrix(group = sapply(strsplit(rownames(dist_tri),
"_"), "[[", 1)))
comp_bi_tri <- as.dist(binary_triangular_matrix(group = gsub("_n|_p",
"", sapply(strsplit(rownames(dist_tri), "_"), "[[", 2))))
sign_bi_tri <- as.dist(binary_triangular_matrix(group = sapply(strsplit(rownames(dist_tri),
"_"), "[[", 3)))
rect_var <- cbind(as.dist(dist_tri), freq_bi_tri, comp_bi_tri,
sign_bi_tri)
colnames(rect_var) <- c("cor", "frequency", "components",
"sign")
cor_wv_mod <- MRM2(formula = cor ~ frequency + components +
sign, nperm = 10000, mat = rect_var)
return(cor_wv_mod)
})
names(cor_mod_list) <- names(cor_snr_list)
saveRDS(cor_mod_list, "./data/processed/matrix_regression_waveform_correlation_varying_snr_white_noise.RDS")
Code
mods <- readRDS("./data/processed/matrix_regression_waveform_correlation_varying_snr_white_noise.RDS")
estimates_wf_wn <- do.call(rbind, lapply(seq_along(mods), function(x) {
Y <- data.frame(mods[[x]]$coef[-1, ])
# Y$rel_coef <- Y[, 1] / max(Y[, 1])
Y$rel_coef <- Y[, 1]
Y$predictor <- rownames(Y)
Y$model <- as.numeric(gsub("snr:", "", names(mods)[x]))
names(Y) <- c("coef", "p", "rel_coef", "predictor", "model")
return(Y)
}))
estimates_wf_wn$rel_coef <- ifelse(estimates_wf_wn$p < 0.05, estimates_wf_wn$rel_coef,
0)
estimates_wf_wn$signif <- ifelse(estimates_wf_wn$p < 0.05, "p < 0.05",
"p >= 0.05")
estimates_wf_wn$signif2 <- ifelse(estimates_wf_wn$p < 0.05, "*", "")
estimates_wf_wn$model_f <- factor(estimates_wf_wn$model, levels = 1:30)
ggplot(estimates_wf_wn, aes(x = predictor, y = model_f, fill = rel_coef)) +
geom_tile() + coord_equal() + scale_fill_gradient2(low = viridis(10)[3],
high = viridis(10)[7], guide = "none") + geom_text(aes(label = signif2,
color = signif), size = 3) + scale_color_manual(values = c("black",
"gray")) + labs(y = "Signal-to-noise ratio", x = "Predictor",
color = "P value") + theme_classic() + theme(axis.text.x = element_text(color = "black",
size = 7, angle = 30, vjust = 0.8, hjust = 0.8)) + coord_flip()
Code
coef_by_signif <- aggregate(coef ~ signif, data = estimates_wf_wn,
FUN = range)
ggplot(estimates_wf_wn, aes(y = coef, x = model, color = predictor,
lty = predictor)) + geom_line(linewidth = 1.6) + labs(x = "Signal-to-noise ratio",
y = "Effect size") + scale_color_viridis_d(alpha = 0.7, begin = 0.2,
end = 0.8) + geom_hline(yintercept = mean(coef_by_signif[, 2][1,
1], coef_by_signif[, 2][2, 2]), lty = 2, color = "gray") + theme_classic()
3.1.4.3.1.1 Only phase
Code
ggplot(estimates_wf_wn[estimates_wf_wn$predictor == "sign", ], aes(y = coef,
x = model, color = predictor, lty = predictor)) + geom_line(linewidth = 1.6) +
geom_smooth() + labs(x = "Signal-to-noise ratio", y = "Effect size") +
scale_color_viridis_d(alpha = 0.7, begin = 0.2, end = 0.8) + geom_hline(yintercept = mean(coef_by_signif[,
2][1, 1], coef_by_signif[, 2][2, 2]), lty = 2, color = "gray") +
theme_classic() + geom_vline(xintercept = 2, lty = 2, color = "gray")
3.1.4.3.1.2 By frequency
Code
cor_snr_list <- readRDS("./data/processed/waveform_correlation_adjusted_snr_200ms_schroeders_white_noise.RDS")
adj_snr_schroeder1 <- readRDS("./data/processed/200ms_schroeders_adjusted_snr_pink_noise.RDS")[[1]]
cor_snr_list <- lapply(seq_along(cor_snr_list), function(x) {
Y <- cor_snr_list[[x]]
Y$target.snr <- gsub("snr:", "", names(cor_snr_list)[x])
return(Y)
})
adj_snr_schroeder1$sound.id <- gsub("f0:f0 ", "f0:", adj_snr_schroeder1$sound.id)
cor_mod_list <- warbleR:::pblapply_wrblr_int(cor_snr_list, cl = 1,
function(y) {
freqs <- unique(substr(sapply(y[, 1], function(x) adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files ==
x]), 0, 6))
mods <- lapply(1:length(freqs), function(i) {
y$schr1 <- sapply(y$schr1, function(x) adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files ==
x])
y$schr2 <- sapply(y$schr2, function(x) adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files ==
x])
# extract only those with the same freq
x <- y[grepl(paste(freqs[i], collapse = "|"), y$schr1) &
grepl(paste(freqs[i], collapse = "|"), y$schr2), ]
target_snr <- x$target.snr
x$target.snr <- NULL
x$cor <- 1 - x$cor
dist_tri <- PhenotypeSpace::rectangular_to_triangular(x)
if (nrow(dist_tri) > 2) {
comp_bi_tri <- as.dist(binary_triangular_matrix(group = gsub("_n|_p",
"", sapply(strsplit(rownames(dist_tri), "_"), "[[",
2))))
sign_bi_tri <- as.dist(binary_triangular_matrix(group = sapply(strsplit(rownames(dist_tri),
"_"), "[[", 3)))
rect_var <- cbind(as.dist(dist_tri), comp_bi_tri,
sign_bi_tri)
colnames(rect_var) <- c("dtw_dist", "components",
"sign")
cor_mod <- MRM2(formula = dtw_dist ~ components +
sign, nperm = 10000, mat = rect_var)
} else cor_mod <- NULL
return(cor_mod)
})
names(mods) <- paste0("snr:", y$target.snr[1], "_", freqs)
mods <- mods[!sapply(mods, is.null)]
return(mods)
})
saveRDS(cor_mod_list, "./data/processed/matrix_correlation_waveforme_correlatione_varying_snr_by_frequency_white_noise.RDS")
Discriminating Schroeder’s by phase grouped by frequency:
Code
mods <- readRDS("./data/processed/matrix_correlation_waveforme_correlatione_varying_snr_by_frequency_white_noise.RDS")
estimates_list <- lapply(mods, function(y) {
estimates <- do.call(rbind, lapply(seq_along(y), function(x) {
Y <- data.frame(y[[x]]$coef[-1, ])
# Y$rel_coef <- Y[, 1] / max(Y[, 1])
Y$rel_coef <- Y[, 1]
Y$mod <- names(y)[x]
Y$predictor <- rownames(Y)
Y$freq <- strsplit(names(y)[x], "_")[[1]][2]
Y$freq <- strsplit(Y$freq, ":")[[1]][2]
names(Y) <- c("coef", "p", "rel_coef", "model", "predictor",
"freq")
Y$snr <- gsub("_", "", substr(names(y)[x], 0, 6))
return(Y)
}))
estimates$rel_coef <- ifelse(estimates$p < 0.05, estimates$rel_coef,
0)
estimates$signif <- ifelse(estimates$p < 0.05, "p < 0.05", "p >= 0.05")
return(estimates)
})
estimates <- do.call(rbind, estimates_list)
estimates$snr <- as.numeric(substr(estimates$snr, 5, nchar(estimates$snr)))
rownames(estimates) <- 1:nrow(estimates)
coef_by_signif <- aggregate(coef ~ signif, data = estimates[estimates$predictor ==
"sign", ], FUN = range)
ggplot(estimates[estimates$predictor == "sign", ], aes(y = coef, x = snr,
color = freq)) + geom_line(linewidth = 1.6) + labs(x = "Signal-to-noise ratio",
y = "Effect size when discriminating phase", color = "F0\nfrequency") +
scale_color_viridis_d(alpha = 0.7, begin = 0.2, end = 0.8) + theme_classic()
Discriminating Schroeder’s by number of components grouped by frequency:
Code
coef_by_signif <- aggregate(coef ~ signif, data = estimates[estimates$predictor ==
"components", ], FUN = range)
ggplot(estimates[estimates$predictor == "components", ], aes(y = coef,
x = snr, color = freq)) + geom_line(linewidth = 1.6) + labs(x = "Signal-to-noise ratio",
y = "Effect size when discriminating number of components", color = "F0\nfrequency") +
scale_color_viridis_d(alpha = 0.7, begin = 0.2, end = 0.8) + geom_hline(yintercept = mean(coef_by_signif[,
2][1, 1], coef_by_signif[, 2][2, 2]), lty = 2, color = "gray") +
theme_classic()
3.1.4.3.1.3 By component
Code
dtw_dists_snr_list <- readRDS("./data/processed/dtw_distance_schroeders_degradation_experiment_varying_snr.RDS")
dtw_wv_mod_list <- warbleR:::pblapply_wrblr_int(dtw_dists_snr_list,
cl = 1, function(y) {
# print(y$target.snr[1])
comps <- unique(sapply(strsplit(y[, 1], "_"), "[[", 2))
mods <- lapply(1:length(comps), function(i) {
# extract only those with the same freq
x <- y[grepl(paste(comps[i], collapse = "|"), y$schr1) &
grepl(paste(comps[i], collapse = "|"), y$schr2), ]
target_snr <- x$target.snr
x$target.snr <- NULL
dist_tri <- PhenotypeSpace::rectangular_to_triangular(x)
if (nrow(dist_tri) > 2) {
freq_bi_tri <- as.dist(binary_triangular_matrix(group = sapply(strsplit(rownames(dist_tri),
"_"), "[[", 1)))
sign_bi_tri <- as.dist(binary_triangular_matrix(group = sapply(strsplit(rownames(dist_tri),
"_"), "[[", 3)))
rect_var <- cbind(as.dist(dist_tri), freq_bi_tri,
sign_bi_tri)
colnames(rect_var) <- c("dtw_dist", "frequency", "sign")
dtw_wv_mod <- MRM2(formula = dtw_dist ~ components +
sign, nperm = 10000, mat = rect_var)
} else dtw_wv_mod <- NULL
return(dtw_wv_mod)
})
names(mods) <- paste0("snr:", y$target.snr[1], "_", comps)
mods <- mods[!sapply(mods, is.null)]
return(mods)
})
saveRDS(dtw_wv_mod_list, "./data/processed/matrix_correlation_dtw_distance_varying_snr_by_components.RDS")
Discriminating Schroeder’s by phase grouped by number of components:
Code
mods <- readRDS("./data/processed/matrix_correlation_dtw_distance_varying_snr_by_components.RDS")
estimates_list <- lapply(mods, function(y) {
estimates <- do.call(rbind, lapply(seq_along(y), function(x) {
Y <- data.frame(y[[x]]$coef[-1, ])
# Y$rel_coef <- Y[, 1] / max(Y[, 1])
Y$rel_coef <- Y[, 1]
Y$mod <- names(y)[x]
Y$predictor <- rownames(Y)
Y$comps <- strsplit(names(y)[x], "_")[[1]][2]
Y$comps <- strsplit(Y$comps, ":")[[1]][2]
names(Y) <- c("coef", "p", "rel_coef", "model", "predictor",
"comps")
Y$snr <- gsub("_", "", substr(names(y)[x], 0, 6))
return(Y)
}))
estimates$rel_coef <- ifelse(estimates$p < 0.05, estimates$rel_coef,
0)
estimates$signif <- ifelse(estimates$p < 0.05, "p < 0.05", "p >= 0.05")
return(estimates)
})
estimates <- do.call(rbind, estimates_list)
estimates$snr <- as.numeric(substr(estimates$snr, 5, nchar(estimates$snr)))
estimates$comps <- factor(estimates$comps, levels = unique(as.numeric(estimates$comps)))
rownames(estimates) <- 1:nrow(estimates)
coef_by_signif <- aggregate(coef ~ signif, data = estimates[estimates$predictor ==
"sign", ], FUN = range)
ggplot(estimates[estimates$predictor == "sign", ], aes(y = coef, x = snr,
color = comps)) + geom_line(linewidth = 1.6) + labs(x = "Signal-to-noise ratio",
y = "Effect size when discriminating sign", color = "Components") +
scale_color_viridis_d(alpha = 0.7, begin = 0.2, end = 0.8) + geom_hline(yintercept = mean(coef_by_signif[,
2][1, 1], coef_by_signif[, 2][2, 2]), lty = 2, color = "gray") +
theme_classic()
Discriminating Schroeder’s by frequency grouped by number of components:
Code
ggplot(estimates[estimates$predictor == "frequency", ], aes(y = coef,
x = snr, color = comps)) + geom_line(linewidth = 1.6) + labs(x = "Signal-to-noise ratio",
y = "Effect size when discriminating frequency", color = "Components") +
scale_color_viridis_d(alpha = 0.7, begin = 0.2, end = 0.8) + theme_classic()
3.1.4.3.2 On single Schroeders
Code
cor_snr_list <- readRDS("./data/processed/waveform_correlation_adjusted_snr_single_schroeders_white_noise.RDS")
adj_snr_schroeder1 <- readRDS("./data/processed/200ms_schroeders_adjusted_snr_white_noise.RDS")[[1]]
adj_snr_schroeder1$sound.id <- gsub("f0:f0 ", "f0:", adj_snr_schroeder1$sound.id)
cor_mod_list <- warbleR:::pblapply_wrblr_int(names(cor_snr_list),
cl = 20, function(y) {
x <- cor_snr_list[[y]]
target_snr <- "snr:30"
x$schr1 <- sapply(strsplit(x$schr1, "_"), function(x) paste(x[2],
x[3], substr(x[4], 0, 1), sep = "_"))
x$schr2 <- sapply(strsplit(x$schr2, "_"), function(x) paste(x[2],
x[3], substr(x[4], 0, 1), sep = "_"))
x$cor <- x$cor * -1
dist_tri <- PhenotypeSpace::rectangular_to_triangular(x)
freq_bi_tri <- as.dist(binary_triangular_matrix(group = sapply(strsplit(rownames(dist_tri),
"_"), "[[", 1)))
comp_bi_tri <- as.dist(binary_triangular_matrix(group = gsub("_n|_p",
"", sapply(strsplit(rownames(dist_tri), "_"), "[[", 2))))
sign_bi_tri <- as.dist(binary_triangular_matrix(group = sapply(strsplit(rownames(dist_tri),
"_"), "[[", 3)))
rect_var <- cbind(as.dist(dist_tri), freq_bi_tri, comp_bi_tri,
sign_bi_tri)
colnames(rect_var) <- c("cor", "frequency", "components",
"sign")
cor_wv_mod <- MRM2(formula = cor ~ frequency + components +
sign, nperm = 10000, mat = rect_var)
return(cor_wv_mod)
})
names(cor_mod_list) <- names(cor_snr_list)
saveRDS(cor_mod_list, "./data/processed/matrix_regression_waveform_correlation_varying_snr_single_schroeder_white_noise.RDS")
Code
mods <- readRDS("./data/processed/matrix_regression_waveform_correlation_varying_snr_single_schroeder_white_noise.RDS")
estimates_wf_wn <- do.call(rbind, lapply(seq_along(mods), function(x) {
Y <- data.frame(mods[[x]]$coef[-1, ])
# Y$rel_coef <- Y[, 1] / max(Y[, 1])
Y$rel_coef <- Y[, 1]
Y$predictor <- rownames(Y)
Y$model <- as.numeric(gsub("snr:", "", names(mods)[x]))
names(Y) <- c("coef", "p", "rel_coef", "predictor", "model")
return(Y)
}))
estimates_wf_wn$rel_coef <- ifelse(estimates_wf_wn$p < 0.05, estimates_wf_wn$rel_coef,
0)
estimates_wf_wn$signif <- ifelse(estimates_wf_wn$p < 0.05, "p < 0.05",
"p >= 0.05")
estimates_wf_wn$signif2 <- ifelse(estimates_wf_wn$p < 0.05, "*", "")
estimates_wf_wn$model_f <- factor(estimates_wf_wn$model, levels = 1:30)
ggplot(estimates_wf_wn, aes(x = predictor, y = model_f, fill = rel_coef)) +
geom_tile() + coord_equal() + scale_fill_gradient2(low = viridis(10)[3],
high = viridis(10)[7], guide = "none") + geom_text(aes(label = signif2,
color = signif), size = 3) + scale_color_manual(values = c("black",
"gray")) + labs(y = "Signal-to-noise ratio", x = "Predictor",
color = "P value") + theme_classic() + theme(axis.text.x = element_text(color = "black",
size = 7, angle = 30, vjust = 0.8, hjust = 0.8)) + coord_flip()
Code
coef_by_signif <- aggregate(coef ~ signif, data = estimates_wf_wn,
FUN = range)
ggplot(estimates_wf_wn, aes(y = coef, x = model, color = predictor,
lty = predictor)) + geom_line(linewidth = 1.6) + labs(x = "Signal-to-noise ratio",
y = "Effect size") + scale_color_viridis_d(alpha = 0.7, begin = 0.2,
end = 0.8) + geom_hline(yintercept = mean(coef_by_signif[, 2][1,
1], coef_by_signif[, 2][2, 2]), lty = 2, color = "gray") + theme_classic()
3.1.5 Measure linear-frequency spectrogram cross-correlation
Code
adj_snr_schroeder <- readRDS("./data/processed/200ms_schroeders_adjusted_snr_white_noise.RDS")
xc_list <- lapply(adj_snr_schroeder, function(schroeders) {
print(schroeders$target.snr[1])
xc <- cross_correlation(schroeders, ovlp = 90, parallel = 20,
wn = "hamming")
})
names(xc_list) <- paste0("snr:", sapply(adj_snr_schroeder, function(x) x$target.snr[1]))
saveRDS(xc_list, "./data/processed/fourier_cross_correlation_varying_snr_200ms_schroeders_white_noise.RDS")
beepr::beep(2)
Code
xc_list <- readRDS("./data/processed/fourier_cross_correlation_varying_snr_200ms_schroeders_white_noise.RDS")
adj_snr_schroeder1 <- readRDS("./data/processed/200ms_schroeders_adjusted_snr_pink_noise.RDS")[[1]]
adj_snr_schroeder1$sound.id <- gsub("f0:f0 ", "f0:", adj_snr_schroeder1$sound.id)
xc_mod_list <- warbleR:::pblapply_wrblr_int(seq_along(xc_list), cl = 20,
function(x) {
X <- xc_list[[x]]
# x$dist <- scale(x$dist)
target_snr <- gsub("snr:", "", names(xc_list)[x])
colnames(X) <- sapply(gsub("-1$", "", colnames(X)), function(x) adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files ==
x])
rownames(X) <- sapply(gsub("-1$", "", rownames(X)), function(x) adj_snr_schroeder1$sound.id[adj_snr_schroeder1$sound.files ==
x])
# convert to distance
X <- 1 - X
# cor_tri <-
# PhenotypeSpace::rectangular_to_triangular(x)
freq_bi_tri <- as.dist(binary_triangular_matrix(group = sapply(strsplit(rownames(X),
"_"), "[[", 1)))
comp_bi_tri <- as.dist(binary_triangular_matrix(group = gsub("_n|_p",
"", sapply(strsplit(rownames(X), "_"), "[[", 2))))
sign_bi_tri <- as.dist(binary_triangular_matrix(group = sapply(strsplit(rownames(X),
"_"), "[[", 3)))
rect_var <- cbind(as.dist(X), freq_bi_tri, comp_bi_tri, sign_bi_tri)
colnames(rect_var) <- c("xcor", "frequency", "components",
"sign")
dtw_wv_mod <- MRM2(formula = xcor ~ frequency + components +
sign, nperm = 10000, mat = rect_var)
return(dtw_wv_mod)
})
names(xc_mod_list) <- names(xc_list)
saveRDS(xc_mod_list, "./data/processed/matrix_regression_cross_correlation_varying_snr_white_noise.RDS")
Discriminating Schroeder’s by phase grouped by number of components:
Code
mods <- readRDS("./data/processed/matrix_regression_cross_correlation_varying_snr_white_noise.RDS")
estimates_xc_wn <- do.call(rbind, lapply(seq_along(mods), function(x) {
Y <- data.frame(mods[[x]]$coef[-1, ])
# Y$rel_coef <- Y[, 1] / max(Y[, 1])
Y$rel_coef <- Y[, 1]
Y$predictor <- rownames(Y)
Y$model <- as.numeric(gsub("snr:", "", names(mods)[x]))
names(Y) <- c("coef", "p", "rel_coef", "predictor", "model")
return(Y)
}))
estimates_xc_wn$rel_coef <- ifelse(estimates_xc_wn$p < 0.05, estimates_xc_wn$rel_coef,
0)
estimates_xc_wn$signif <- ifelse(estimates_xc_wn$p < 0.05, "p < 0.05",
"p >= 0.05")
estimates_xc_wn$signif2 <- ifelse(estimates_xc_wn$p < 0.05, "*", "")
estimates_xc_wn$model_f <- factor(estimates_xc_wn$model, levels = 1:30)
ggplot(estimates_xc_wn, aes(x = predictor, y = model_f, fill = rel_coef)) +
geom_tile() + coord_equal() + scale_fill_gradient2(low = viridis(10)[3],
high = viridis(10)[7], guide = "none") + geom_text(aes(label = signif2,
color = signif), size = 3) + scale_color_manual(values = c("black",
"gray")) + labs(y = "Signal-to-noise ratio", x = "Predictor",
color = "P value") + theme_classic() + theme(axis.text.x = element_text(color = "black",
size = 7, angle = 30, vjust = 0.8, hjust = 0.8)) + coord_flip()
Code
coef_by_signif3 <- aggregate(coef ~ signif, data = estimates_xc_wn,
FUN = range)
ggplot(estimates_xc_wn, aes(y = coef, x = model, color = predictor,
lty = predictor)) + geom_line(linewidth = 1.6) + labs(x = "Signal-to-noise ratio",
y = "Effect size") + scale_color_viridis_d(alpha = 0.7, begin = 0.2,
end = 0.8) + theme_classic()
3.1.5.1 Only phase
Code
ggplot(estimates_xc_wn[estimates_xc_wn$predictor == "sign", ], aes(y = abs(coef),
x = model, color = predictor, lty = predictor)) + geom_line(linewidth = 1.6) +
geom_smooth() + labs(x = "Signal-to-noise ratio", y = "Effect size") +
scale_color_viridis_d(alpha = 0.7, begin = 0.2, end = 0.8) + geom_hline(yintercept = 0,
lty = 2, color = "gray") + theme_classic()
4 Combined results plot
Code
estimates_wf_wn$method <- "waveform correlation"
estimates_dtw_wn$method <- "waveform DTW"
estimates_xc_wn$method <- "cross-correlation"
estims <- rbind(estimates_wf_wn, estimates_dtw_wn, estimates_xc_wn)
coef_by_signif2 <- aggregate(coef ~ signif + method, data = estims,
FUN = range)
ggplot(estims[estims$predictor == "sign", ], aes(y = abs(coef), x = model,
color = method)) + geom_line(linewidth = 1.6) + geom_smooth() +
labs(x = "Signal-to-noise ratio", y = "Phase\neffect size") +
scale_color_viridis_d(alpha = 0.7, begin = 0.2, end = 0.8) + xlim(c(1,
30)) + geom_hline(yintercept = 0, lty = 2, color = "gray") + theme_classic() +
scale_x_continuous(expand = c(0, 0))
5 Takeaways
Session information
R version 4.4.2 (2024-10-31)
Platform: x86_64-pc-linux-gnu
Running under: Ubuntu 22.04.5 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.10.0
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.10.0
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
[3] LC_TIME=es_CR.UTF-8 LC_COLLATE=en_US.UTF-8
[5] LC_MONETARY=es_CR.UTF-8 LC_MESSAGES=en_US.UTF-8
[7] LC_PAPER=es_CR.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=es_CR.UTF-8 LC_IDENTIFICATION=C
time zone: America/Costa_Rica
tzcode source: system (glibc)
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] numform_0.7.0 ecodist_2.1.3 PhenotypeSpace_0.1.0
[4] ggplot2_3.5.1 baRulho_2.1.4 ohun_1.0.2
[7] Rraven_1.0.14 viridis_0.6.5 viridisLite_0.4.2
[10] warbleR_1.1.34 NatureSounds_1.0.5 tuneR_1.4.7
[13] seewave_2.2.3 formatR_1.14 knitr_1.50
[16] kableExtra_1.4.0
loaded via a namespace (and not attached):
[1] DBI_1.2.3 bitops_1.0-9 deldir_2.0-4
[4] pbapply_1.7-2 gridExtra_2.3 remotes_2.5.0
[7] permute_0.9-7 testthat_3.2.3 rlang_1.1.5
[10] magrittr_2.0.3 e1071_1.7-16 compiler_4.4.2
[13] spatstat.geom_3.3-2 mgcv_1.9-1 png_0.1-8
[16] systemfonts_1.1.0 vctrs_0.6.5 Sim.DiffProc_4.9
[19] stringr_1.5.1 pkgconfig_2.0.3 crayon_1.5.3
[22] fastmap_1.2.0 backports_1.5.0 labeling_0.4.3
[25] rmarkdown_2.29 xfun_0.52 jsonlite_2.0.0
[28] goftest_1.2-3 spatstat.utils_3.1-0 terra_1.7-78
[31] Deriv_4.1.6 parallel_4.4.2 cluster_2.1.6
[34] R6_2.6.1 stringi_1.8.7 spatstat.data_3.1-2
[37] spatstat.univar_3.0-1 brio_1.1.5 Rcpp_1.0.14
[40] tensor_1.5 splines_4.4.2 Matrix_1.7-0
[43] igraph_2.1.4 tidyselect_1.2.1 rstudioapi_0.16.0
[46] abind_1.4-8 yaml_2.3.10 vegan_2.6-8
[49] codetools_0.2-20 dtw_1.23-1 spatstat.random_3.3-1
[52] spatstat.explore_3.3-2 curl_6.2.2 lattice_0.22-6
[55] tibble_3.2.1 withr_3.0.2 evaluate_1.0.3
[58] signal_1.8-1 sf_1.0-20 sketchy_1.0.5
[61] units_0.8-7 proxy_0.4-27 polyclip_1.10-7
[64] xml2_1.3.6 pillar_1.10.1 packrat_0.9.2
[67] KernSmooth_2.23-24 checkmate_2.3.2 generics_0.1.3
[70] sp_2.1-4 RCurl_1.98-1.17 munsell_0.5.1
[73] scales_1.3.0 class_7.3-22 glue_1.8.0
[76] tools_4.4.2 xaringanExtra_0.8.0 grid_4.4.2
[79] colorspace_2.1-1 nlme_3.1-165 raster_3.6-26
[82] cli_3.6.4 spatstat.sparse_3.1-0 svglite_2.1.3
[85] dplyr_1.1.4 gtable_0.3.6 fftw_1.0-9
[88] digest_0.6.37 classInt_0.4-11 farver_2.1.2
[91] rjson_0.2.23 htmlwidgets_1.6.4 htmltools_0.5.8.1
[94] lifecycle_1.0.4 httr_1.4.7 MASS_7.3-61