Last updated: 2021-03-04
Checks: 6 1
Knit directory: fitnessGWAS/
This reproducible R Markdown analysis was created with workflowr (version 1.6.2). The Checks tab describes the reproducibility checks that were applied when the results were created. The Past versions tab lists the development history.
Great! Since the R Markdown file has been committed to the Git repository, you know the exact version of the code that produced these results.
Great job! The global environment was empty. Objects defined in the global environment can affect the analysis in your R Markdown file in unknown ways. For reproduciblity it’s best to always run the code in an empty environment.
The command set.seed(20180914)
was run prior to running the code in the R Markdown file. Setting a seed ensures that any results that rely on randomness, e.g. subsampling or permutations, are reproducible.
Great job! Recording the operating system, R version, and package versions is critical for reproducibility.
Nice! There were no cached chunks for this analysis, so you can be confident that you successfully produced the results during this run.
Using absolute paths to the files within your workflowr project makes it difficult for you and others to run your code on a different machine. Change the absolute path(s) below to the suggested relative path(s) to make your code more reproducible.
absolute | relative |
---|---|
~/Rprojects/fitnessGWAS/ | . |
Great! You are using Git for version control. Tracking code development and connecting the code version to the results is critical for reproducibility.
The results in this page were generated with repository version b1836d7. See the Past versions tab to see a history of the changes made to the R Markdown and HTML files.
Note that you need to be careful to ensure that all relevant files for the analysis have been committed to Git prior to generating the results (you can use wflow_publish
or wflow_git_commit
). workflowr only checks the R Markdown file, but you know if there are other scripts or data files that it depends on. Below is the status of the Git repository when the results were generated:
Ignored files:
Ignored: .DS_Store
Ignored: .Rapp.history
Ignored: .Rhistory
Ignored: .Rproj.user/
Ignored: .httr-oauth
Ignored: .pversion
Ignored: analysis/.DS_Store
Ignored: analysis/correlations_SNP_effects_cache/
Ignored: analysis/plot_models_variant_effects_cache/
Ignored: code/.DS_Store
Ignored: code/Drosophila_GWAS.Rmd
Ignored: data/.DS_Store
Ignored: data/derived/
Ignored: data/input/.DS_Store
Ignored: data/input/.pversion
Ignored: data/input/dgrp.fb557.annot.txt
Ignored: data/input/dgrp2.bed
Ignored: data/input/dgrp2.bim
Ignored: data/input/dgrp2.fam
Ignored: data/input/huang_transcriptome/
Ignored: figures/.DS_Store
Untracked files:
Untracked: Rplots.pdf
Untracked: analysis/GO_KEGG_enrichment.Rmd
Untracked: analysis/TWAS_tables.Rmd
Untracked: analysis/plot_models_variant_effects.Rmd
Untracked: code/GO_and_KEGG_gsea.R
Untracked: code/eQTL_analysis.Rmd
Untracked: code/make_sites_files_for_ARGweaver.R
Untracked: code/plotting_results.Rmd
Untracked: code/run_argweaver.R
Untracked: code/run_mashr.R
Untracked: data/argweaver/
Untracked: data/input/TF_binding_sites.csv
Untracked: figures/GWAS_mixture_proportions.rds
Untracked: figures/GWAS_stats_figure.pdf
Untracked: figures/TWAS_mixture_proportions.rds
Untracked: figures/TWAS_stats_figure.pdf
Untracked: figures/antagonism_ratios.pdf
Untracked: figures/composite_mixture_figure.pdf
Untracked: figures/eff_size_histos.pdf
Untracked: figures/stats_figure.pdf
Untracked: manuscript/
Unstaged changes:
Modified: .gitignore
Modified: README.md
Modified: analysis/GWAS_tables.Rmd
Modified: analysis/TWAS.Rmd
Modified: analysis/_site.yml
Deleted: analysis/about.Rmd
Modified: analysis/checking_mashr_results.Rmd
Deleted: analysis/eQTL_analysis.Rmd
Modified: analysis/gwas_adaptive_shrinkage.Rmd
Modified: analysis/license.Rmd
Modified: analysis/make_annotation_database.Rmd
Modified: analysis/plot_line_means.Rmd
Modified: analysis/plotting_results.Rmd
Deleted: code/gwas_adaptive_shrinkage.R
Modified: data/input/female_fitness.csv
Modified: data/input/female_fitness_CLEANED.csv
Modified: data/input/male_fitness.csv
Modified: data/input/male_fitness_CLEANED.csv
Modified: figures/figure1.eps
Deleted: figures/figure1.png
Modified: figures/figure2.eps
Note that any generated files, e.g. HTML, png, CSS, etc., are not included in this status report because it is ok for generated content to have uncommitted changes.
These are the previous versions of the repository in which changes were made to the R Markdown (analysis/get_predicted_line_means.Rmd
) and HTML (docs/get_predicted_line_means.html
) files. If you’ve configured a remote Git repository (see ?wflow_git_remote
), click on the hyperlinks in the table below to view the files as they were in that past version.
File | Version | Author | Date | Message |
---|---|---|---|---|
Rmd | b1836d7 | lukeholman | 2021-03-04 | big first commit 2021 |
Rmd | 8d54ea5 | Luke Holman | 2018-12-23 | Initial commit |
html | 8d54ea5 | Luke Holman | 2018-12-23 | Initial commit |
library(tidyverse)
library(brms)
library(mice)
library(ICC)
library(future)
library(future.apply)
library(kableExtra)
Most studies of the DGRP calculate “line means” simply by averaging the phenotypes of several individuals per line. Instead, we used Bayesian generalised linear mixed model (GLMMs) to estimate the true line means for each of the 4 fitness traits, implemented in the brms
package.
One notable advantage of using a model instead of a simple average is that a model allows one to statistically remove confounding factors such as block effects, which would otherwise bias the line means. Note that we intentionally measured line 352 in every block in our experiments, in order to improve our precision to estimate block effects.
Additionally, we must properly account for our experimental design in order to avoid pseudoreplication. Our design involved repeatedly measuring the same individuals to determine early- and late-life fitness.
For the progeny count data used to measure early and late female fitness, we used multivariate model with two components, one for early- and one for late-life fitness, which had the following formulae (in brms
-like pseudocode):
Progeny count (early) = Intercept + (1 | p | line) + (1 | q | block) + (1 | r | vial)
Progeny count (late) = Intercept + (1 | p | line) + (1 | q | block) + (1 | r | vial)
To explain, the terms with the form (1 | x | y)
represent random intercepts for line, block, and vial ID, where the letter between the pipe operator indicates which random intercepts should be assumed to be (potentially) correlated with which other random intercepts. We therefore assume that the effect of line, block, and vial ID on each observation are potentially correlated for both of the response variables, and estiamte that correlation while fitting the multivariate model.
The progeny count data were assumed to follow a Poisson distribution (with the standard log link function).
Similarly, for our measure of male fitness (proportion of offspring sired), we used a multivariate model consisting of a pair of binomial GLMMs, with the following formula:
Proportion of progeny sired (early) = Intercept + (1 | p | line) + (1 | q | block) + (1 | r | vial)
Proportion of progeny sired (late) = Intercept + num.GFP.males + (1 | p | line) + (1 | q | block) + (1 | r | vial)
Where the response variable was a Bernoulli outcome describing the paternity of each offspring observed. Note that in the late life fitness model, we included the number of surviving rival (GFP) males as an additional predictor. We reasoned that the rival males might die at random with respect to the genotype of the focal males, which lowers competition on the focal males, and so we can get an improved estimate of the focal males’ siring success by statistically correcting for their deaths via the model.
load_and_tidy_fitness_data <- function(){
female_fitness <- read_csv("data/input/female_fitness.csv") %>%
arrange(line) %>%
split(paste(.$block, .$line)) %>%
map(~ .x %>% mutate(replicate = 1:n())) %>%
bind_rows() %>%
mutate(vial = 1:n(),
vial = paste("F", line, block, replicate, sep = "_"),
line = paste("line_", line, sep = "")) %>%
dplyr::select(-num.F.late1, -num.F.late2, -num.laying.F.early, -replicate) %>%
mutate(female.fitness.early = replace(female.fitness.early, is.na(female.fitness.early), 0),
female.fitness.late = replace(female.fitness.late, is.na(female.fitness.late), 0))
male_fitness <- read_csv("data/input/male_fitness.csv") %>%
arrange(line) %>%
split(paste(.$block, .$line)) %>%
map(~ .x %>% mutate(replicate = 1:n())) %>%
bind_rows() %>%
mutate(vial = paste("M", line, block, replicate, sep = "_"),
line = paste("line_", line, sep = "")) %>%
dplyr::select(-num.DGRP.males, -replicate)
# Remove the small number of observations where the females had no offspring, so we cannot measure the
# rival vs focal male competitive abilities
# NOTE: Not needed any more, because now I impute this as missing data
# exclude_early <- male_fitness$early.male.rival + male_fitness$early.male.focal == 0
# exclude_late <- male_fitness$late.male.rival + male_fitness$late.male.focal == 0
# male_fitness$early.male.rival[exclude_early] <- NA
# male_fitness$early.male.focal[exclude_early] <- NA
# male_fitness$late.male.rival[exclude_late] <- NA
# male_fitness$late.male.focal[exclude_late] <- NA
# Save these tidy files, for data archiving
write.csv(female_fitness, file = "data/input/female_fitness_CLEANED.csv", row.names = FALSE)
write.csv(male_fitness, file = "data/input/male_fitness_CLEANED.csv", row.names = FALSE)
list(female_fitness = female_fitness, male_fitness = male_fitness)
}
# This function calculates the traditional line means (i.e. simple averages) for each line
get_line_means <- function(){
left_join(
load_and_tidy_fitness_data()[[1]] %>%
select(line, female.fitness.early, female.fitness.late) %>%
group_by(line) %>%
summarise(female.fitness.early = mean(female.fitness.early),
female.fitness.late = mean(female.fitness.late)),
load_and_tidy_fitness_data()[[2]] %>%
group_by(line) %>%
summarise(early.male.rival = sum(early.male.rival),
early.male.focal = sum(early.male.focal),
late.male.rival = sum(late.male.rival),
late.male.focal = sum(late.male.focal),
male.fitness.early = early.male.focal / (early.male.focal + early.male.rival),
male.fitness.late = late.male.focal / (late.male.focal + late.male.rival)) %>%
select(line, male.fitness.early, male.fitness.late),
by = "line") %>% as.data.frame()
}
# A function to calculate each line's expected fitness, using brms models to adjust for block + vial random effects
# For the male late life assay, we also adjust for the number of competitor males that died
# (this assumes that their deaths happened randomly with respect to which line we were measuring)
get_predicted_line_means <- function(overwrite = FALSE){
# If it's already calculated, just load up the file. Otherwise, make the file
out.file <- "data/derived/predicted_line_means.csv"
if(file.exists(out.file) & !overwrite) return(read_csv(out.file))
####### Load the individual-level data for females
female_fitness <- load_and_tidy_fitness_data()[[1]]
####### Load the individual-level data for males, and impute missing values
# For one vial, there is no early-life measurement because the females did not produce offspring.
# Therefore we impute that datapoint and make 5 imputed datasets using the package 'mice'
# See this link for explanation: https://cran.r-project.org/web/packages/brms/vignettes/brms_missings.html
male_fitness <- load_and_tidy_fitness_data()[[2]]
male_fitness <- male_fitness %>%
mutate(early.male.rival = replace(early.male.rival, early.male.rival + early.male.focal == 0, NA),
early.male.focal = replace(early.male.focal, is.na(early.male.rival), NA))
male_fitness_imputed <- mice(male_fitness, m = 5, print = FALSE, seed = 1)
male_fitness_imputed <- lapply(1:5, function(i) { # for each imputed dataset,
complete(male_fitness_imputed, i) %>%
mutate(total1 = early.male.rival + early.male.focal, # tally up the focal+rival offspring for binomial model
total2 = late.male.rival + late.male.focal,
num.GFP.males = as.numeric(scale(num.GFP.males))) %>% # scale this covariate
# For late-life assays where the 5 focal males all died before reaching age 14,
# we need to assign them zero fitness. We did this by assuming that the rivals sired 100/100 offspring.
# This scenario happened in 47 vials (out of 810)
mutate(late.male.focal = replace(late.male.focal, total2 == 0, 100),
total2 = replace(total2, total2 == 0, 100))
})
####### Run model on the female data
prior_females <-
c(set_prior("cauchy(0, 0.1)", class = "sd", resp = 'femalefitnessearly', group = "line"),
set_prior("cauchy(0, 0.1)", class = "sd", resp = 'femalefitnessearly', group = "block"),
set_prior("cauchy(0, 0.1)", class = "sd", resp = 'femalefitnessearly', group = "vial"),
set_prior("cauchy(0, 0.1)", class = "sd", resp = 'femalefitnesslate', group = "line"),
set_prior("cauchy(0, 0.1)", class = "sd", resp = 'femalefitnesslate', group = "block"),
set_prior("cauchy(0, 0.1)", class = "sd", resp = 'femalefitnesslate', group = "vial"))
prior_males <-
c(set_prior("cauchy(0, 0.1)", class = "sd", resp = 'earlymalefocal', group = "line"),
set_prior("cauchy(0, 0.1)", class = "sd", resp = 'earlymalefocal', group = "block"),
set_prior("cauchy(0, 0.1)", class = "sd", resp = 'earlymalefocal', group = "vial"),
set_prior("cauchy(0, 0.1)", class = "sd", resp = 'latemalefocal', group = "line"),
set_prior("cauchy(0, 0.1)", class = "sd", resp = 'latemalefocal', group = "block"),
set_prior("cauchy(0, 0.1)", class = "sd", resp = 'latemalefocal', group = "vial"))
female1 <- bf(female.fitness.early ~ (1 | p | line) + (1 | q | block) + (1 | r | vial))
female2 <- bf(female.fitness.late ~ (1 | p | line) + (1 | q | block) + (1 | r | vial))
female_model <- brm(female1 + female2,
family = "poisson", data = female_fitness,
prior = prior_females,
iter = 5000, chains = 4, cores = 4,
seed = 1, control = list(adapt_delta = 0.999, max_treedepth = 15))
writeLines(capture.output(summary(female_model)), con = "data/derived/model_summary_females.txt")
saveRDS(female_model, "data/derived/female_fitness_prediction_model.rds") # maybe delete later - probably not needed?
### Run model on male data
# Fit num.GFP.males, but only for the late life data
male1 <- bf(early.male.focal | trials(total1) ~ (1 | p | line) + (1 | q | block) + (1 | r | vial))
male2 <- bf(late.male.focal | trials(total2) ~ num.GFP.males + (1 | p | line) + (1 | q | block) + (1 | r | vial))
# Run 5 models, on each of the 5 imputed datasets, and combine the results
male_model <- brm_multiple(male1 + male2,
family = "binomial",
prior = prior_males,
data = male_fitness_imputed,
iter = 5000, chains = 4, cores = 4,
seed = 1, control = list(adapt_delta = 0.999, max_treedepth = 15))
writeLines(capture.output(summary(male_model)), con = "data/derived/model_summary_males.txt")
saveRDS(male_model, "data/derived/male_fitness_prediction_model.rds") # maybe delete later - probably not needed?
male_model <- readRDS("data/derived/male_fitness_prediction_model.rds")
####### Define new data for prediction
new.data.female <- female_fitness %>%
select(line) %>% distinct() %>% arrange(line)
new.data.male <- male_fitness %>%
select(line) %>% distinct() %>% arrange(line) %>%
mutate(total1 = 100, # I checked, and changing this number does not affect the line means, as expected
total2 = 100,
num.GFP.males = male_fitness %>% .$num.GFP.males %>% mean(na.rm=TRUE))
# Get predicted lines means for early and late life *female* fitness on linear predictor scale (i.e. fairly normal)
female_line_preds <- data.frame(new.data.female,
fitted(female_model,
newdata = new.data.female,
re_formula = "~ ( 1 | line)",
scale = "linear")) %>%
select(line, Estimate.femalefitnessearly, Estimate.femalefitnesslate) %>%
rename(female.fitness.early = Estimate.femalefitnessearly,
female.fitness.late = Estimate.femalefitnesslate) %>%
mutate(female.fitness.early = as.numeric(scale(female.fitness.early)), # scale the line means
female.fitness.late = as.numeric(scale(female.fitness.late)))
# Get predicted lines means for early and late life *male* fitness on linear predictor scale (i.e. fairly normal)
male_line_preds <- data.frame(new.data.male,
fitted(male_model,
newdata = new.data.male,
re_formula = "~ (1 | line)",
scale = "linear")) %>%
select(line, Estimate.earlymalefocal, Estimate.latemalefocal) %>%
rename(male.fitness.early = Estimate.earlymalefocal,
male.fitness.late = Estimate.latemalefocal) %>%
mutate(male.fitness.early = as.numeric(scale(male.fitness.early)), # scale the line means
male.fitness.late = as.numeric(scale(male.fitness.late)))
## Define a function to get the ICC for line, for each posterior sample of predicted line means
get_ICC_line <- function(predictions){
cols <- str_detect(names(predictions), "X")
first_posterior_column <- which(cols)[1]
n_draws <- sum(cols)
plan("multiprocess")
future_lapply(0:(n_draws - 1), function(i){
ICCbare(predictions$line, predictions[, i + first_posterior_column])
}) %>% unlist()
}
# Calculate ICC for each sample, separately for old and young females
# For females, this is done on the estimated line mean progeny produced (i.e. response scale)
predicted <- fitted(female_model, summary = FALSE)
Line_ICC_female_early <- get_ICC_line(data.frame(female_fitness, t(predicted[, , 1])))
Line_ICC_female_late <- get_ICC_line(data.frame(female_fitness, t(predicted[, , 2])))
# Do the same for males
# For males, this is done on the estimated proportion progeny sired (i.e. response scale)
new_data <- male_fitness %>%
select(block, line, vial.ID) %>%
mutate(total1 = 100,
total2 = 100,
num.GFP.males = male_fitness %>% .$num.GFP.males %>% mean(na.rm=TRUE))
predicted <- fitted(male_model, summary = FALSE, newdata = new_data)
Line_ICC_male_early <- get_ICC_line(data.frame(new_data, t(predicted[, , 1])))
Line_ICC_male_late <- get_ICC_line(data.frame(new_data, t(predicted[, , 2])))
ICC <- list(Line_ICC_female_early,
Line_ICC_female_late,
Line_ICC_male_early,
Line_ICC_male_late) %>% lapply(posterior_summary) %>%
do.call("rbind", .) %>% as_tibble() %>%
mutate(Fitness_trait = c("Female early-life fitness", "Female late-life fitness",
"Male early-life fitness", "Male late-life fitness"))
write.csv(ICC, file = "data/derived/ICC.csv", row.names = TRUE)
# Record which block(s) each line was measured in. Generally one block, except for ref line (all blocks)
line_blocks <- rbind(female_fitness %>% select(block, line),
male_fitness %>% select(block, line)) %>%
mutate(block = replace(block, line == "352", "reference_line")) %>%
distinct() %>%
group_by(line) %>% summarise(block = paste0(block, collapse = ", "))
predicted_line_means <- female_line_preds %>%
left_join(male_line_preds, by = "line") %>%
left_join(line_blocks, by = "line") %>%
arrange(line)
write.csv(predicted_line_means, out.file, row.names = FALSE)
}
The object line_means
is the raw line means: unscaled, arithmetic means and in the original units.
The object predicted_line_means
is the estimated line means from the Bayesian models. These means are on the scale of the linear predictor (i.e. Poisson for females, binomial for males) rather than on the scale of the original response. They have been scaled to have a mean of 0 and a variance of 1.
line_means <- get_line_means()
predicted_line_means <- get_predicted_line_means(overwrite = FALSE)
cat(readLines('data/derived/model_summary_females.txt'), sep = '\n')
Family: MV(poisson, poisson) Links: mu = log mu = log Formula: female.fitness.early ~ (1 | p | line) + (1 | q | block) + (1 | r | vial) female.fitness.late ~ (1 | p | line) + (1 | q | block) + (1 | r | vial) Data: female_fitness (Number of observations: 816) Samples: 4 chains, each with iter = 5000; warmup = 2500; thin = 1; total post-warmup samples = 10000 Group-Level Effects: ~block (Number of levels: 10) Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS sd(femalefitnessearly_Intercept) 0.29 0.09 0.16 0.50 1.00 6955 7704 sd(femalefitnesslate_Intercept) 1.21 0.35 0.70 2.05 1.00 7505 8048 cor(femalefitnessearly_Intercept,femalefitnesslate_Intercept) -0.42 0.29 -0.88 0.22 1.00 8010 7082 ~line (Number of levels: 125) Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS sd(femalefitnessearly_Intercept) 0.58 0.05 0.50 0.68 1.00 5014 7236 sd(femalefitnesslate_Intercept) 1.82 0.17 1.51 2.18 1.00 5993 7883 cor(femalefitnessearly_Intercept,femalefitnesslate_Intercept) 0.68 0.07 0.53 0.79 1.00 7663 7679 ~vial (Number of levels: 816) Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS sd(femalefitnessearly_Intercept) 0.52 0.02 0.49 0.55 1.00 4219 6935 sd(femalefitnesslate_Intercept) 1.54 0.07 1.42 1.68 1.00 4543 6625 cor(femalefitnessearly_Intercept,femalefitnesslate_Intercept) 0.21 0.05 0.12 0.30 1.00 7886 7637 Population-Level Effects: Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS femalefitnessearly_Intercept 4.40 0.11 4.19 4.62 1.00 11285 6886 femalefitnesslate_Intercept 0.70 0.44 -0.16 1.57 1.00 13404 7848 Samples were drawn using sampling(NUTS). For each parameter, Bulk_ESS and Tail_ESS are effective sample size measures, and Rhat is the potential scale reduction factor on split chains (at convergence, Rhat = 1).
cat(readLines('data/derived/model_summary_males.txt'), sep = '\n')
Family: MV(binomial, binomial) Links: mu = logit mu = logit Formula: early.male.focal | trials(total1) ~ (1 | p | line) + (1 | q | block) + (1 | r | vial) late.male.focal | trials(total2) ~ num.GFP.males + (1 | p | line) + (1 | q | block) + (1 | r | vial) Data: male_fitness_imputed (Number of observations: 810) Samples: 20 chains, each with iter = 5000; warmup = 2500; thin = 1; total post-warmup samples = 50000 Group-Level Effects: ~block (Number of levels: 10) Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS sd(earlymalefocal_Intercept) 0.74 0.20 0.46 1.21 1.00 25462 31760 sd(latemalefocal_Intercept) 0.34 0.22 0.01 0.83 1.00 6387 19201 cor(earlymalefocal_Intercept,latemalefocal_Intercept) 0.36 0.40 -0.62 0.94 1.00 30792 28410 ~line (Number of levels: 124) Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS sd(earlymalefocal_Intercept) 0.54 0.05 0.45 0.65 1.00 17106 27248 sd(latemalefocal_Intercept) 0.85 0.20 0.45 1.22 1.01 2221 2337 cor(earlymalefocal_Intercept,latemalefocal_Intercept) 0.68 0.15 0.36 0.95 1.01 2784 3159 ~vial (Number of levels: 810) Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS sd(earlymalefocal_Intercept) 0.81 0.03 0.76 0.86 1.01 1459 30181 sd(latemalefocal_Intercept) 2.79 0.11 2.58 3.01 1.00 9096 21491 cor(earlymalefocal_Intercept,latemalefocal_Intercept) 0.18 0.04 0.10 0.26 1.01 2437 14178 Population-Level Effects: Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS earlymalefocal_Intercept 0.15 0.25 -0.34 0.66 1.00 23930 27025 latemalefocal_Intercept -0.81 0.19 -1.17 -0.42 1.00 25469 27873 latemalefocal_num.GFP.males -0.13 0.12 -0.37 0.10 1.00 13718 23568 Samples were drawn using sampling(NUTS). For each parameter, Bulk_ESS and Tail_ESS are effective sample size measures, and Rhat is the potential scale reduction factor on split chains (at convergence, Rhat = 1).
The table shows the posterior estimate of the intra-class correlation coefficient (ICC, which measures the proportion of variance within and between lines), using the above models to adjust for block effects (and one covariate in the male late-life fitness analysis). ICC was calculated using ICC::ICCbare
.
read.csv('data/derived/ICC.csv') %>%
select(Fitness_trait, Estimate, Est.Error, Q2.5, Q97.5) %>%
rename(`Fitness trait` = Fitness_trait, `Est. Error` = Est.Error, `Lower 95% CI` = Q2.5, `Upper 95% CI` = Q97.5) %>%
mutate(across(where(is.numeric), ~ .x * 100)) %>%
kable(digits = 2) %>% kable_styling(full_width = FALSE)
Fitness trait | Estimate | Est. Error | Lower 95% CI | Upper 95% CI |
---|---|---|---|---|
Female early-life fitness | 62.53 | 0.67 | 61.23 | 63.85 |
Female late-life fitness | 55.99 | 0.99 | 54.09 | 57.96 |
Male early-life fitness | 44.38 | 0.97 | 42.47 | 46.26 |
Male late-life fitness | 9.26 | 6.74 | -1.53 | 19.89 |