library(correlation)
library(tidyverse)
library(broom)
library(GGally)
library(readxl)
library(ggplot2)
library(kableExtra)
theme_set(theme_classic())
** To be useful, the ratio must outperform MUN **
Ferreira, M., Delagarde, R., & Edouard, N. (2021). CowNflow: A dataset on nitrogen flows and balances in dairy cows fed maize forage or herbage-based diets. Data in Brief, 38, 107393. https://www.sciencedirect.com/science/article/pii/S2352340921006752
cdat <- read_excel("~/Library/CloudStorage/OneDrive-UW-Madison/Documents/2022-Fall/F22 MPY_MUNY/CowNflow_6_Cow_measurements1.xlsx")
cdat %>%
group_by(exp) %>%
summarise(across(where(is.numeric), mean))
## # A tibble: 28 × 88
## exp 1.-Co…¹ 2.-Co…² 2.-Bo…³ 2.-La…⁴ 2.-Ge…⁵ 3.-Fe…⁶ 3.-Fe…⁷ 3.-Fe…⁸ 3.-Fe…⁹
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 E01 77246. 69.1 504. 34.8 14.1 11.2 NA NA NA
## 2 E02 79688. 50.4 522. 46.5 10.2 11.4 NA NA NA
## 3 E03 81748. 42.5 551. 50 20.5 11.8 NA NA NA
## 4 E04 79411 67.2 551 41.3 6.33 12.4 NA NA NA
## 5 E05 81936. 49.2 563. 30.8 12.2 4.92 5.12 2.44 2.28
## 6 E06 82553 62.4 642. 36.5 18.4 6.24 6.10 1.7 0.27
## 7 E07 84081 67.3 634. 18.8 6.17 13.8 6.01 1.83 0.242
## 8 E08 84310. 75.2 628. 24.5 3.38 7.78 5.24 0.431 0.63
## 9 E09 85297. 66.9 634. 36.8 10.2 15.1 NA NA NA
## 10 E10 83836. 112. 635. 27 0 5.02 5.22 4.99 1.16
## # … with 18 more rows, 78 more variables: `3.-Feed-5-intake-(kg-DM/day)` <dbl>,
## # `3.-Feed-6-intake-(kg-DM/day)` <dbl>, `3.-Feed-7-intake-(kg-DM/day)` <dbl>,
## # `3.-Feed-8-intake-(kg-DM/day)` <dbl>, `3.-Feed-9-intake-(kg-DM/day)` <dbl>,
## # `3.-Feed-10-intake-(kg-DM/day)` <dbl>,
## # `3.-Feed-11-intake-(kg-DM/day)` <dbl>,
## # `3.-Forage-proportion-in-the-diet-(kg/kg,-DM-basis)` <dbl>,
## # `3.-Maize-forage-proportion-in-the-diet-(kg/kg,-DM-basis)` <dbl>, …
cdat = cdat %>%
mutate(
prot_prod_kgperd = Tru.Prot*milk_kgperd/1000,
nue_true = prot_prod_kgperd/6.34*1000 / n_intake_gperd,
MUN = milk_urea * 0.46,
MUNY_gperd = MUN*milk_kgperd/100,
MUNY_MPY = MUNY_gperd / prot_prod_kgperd*100 ,
MPY_MUNY = prot_prod_kgperd*100 / MUNY_gperd,
MUN_MPY = MUN / prot_prod_kgperd,
manure_n_gperd = urine_n_gperd + `5.-Faecal-N-excretion-(g/day)`,
diet_cp = `4.-Diet-CP-concentration-(g/kg-DM)`,
diet_cp_c = scale(diet_cp, scale = F),
gest_wk = `2.-Gestation-week`,
lact_day = `2.-Lactation-week` * 7,
lact_day_c = scale(lact_day, scale = F),
bw = `2.-Body-weight-(kg)`,
lact_stage = ifelse(lact_day > 175, "late", "early"),
trt = `1.-Treatment-ID`)
only_cross_3trt = cdat %>%
group_by(exp, cow) %>%
summarise(n = n()) %>%
filter(n >2)
## `summarise()` has grouped output by 'exp'. You can override using the `.groups`
## argument.
# filter out fresh herbage diets
cdat1 = cdat %>%
right_join(only_cross_3trt) %>%
filter(`3.-Diet-type` != "Fresh_herbage") %>%
filter(`3.-Diet-type` != "Maize_Fresh_herbage")
## Joining, by = c("exp", "cow")
Show structure of this dataframe and SIGNIFICANT missingness for certain variables.
cr = cdat1 %>%
dplyr::select(cow, exp, nue_true, milk_kgperd, MUN, MUNY_gperd, MPY_MUNY, MUN_MPY, manure_n_gperd, diet_cp, lact_stage)
str(cr)
## tibble [220 × 11] (S3: tbl_df/tbl/data.frame)
## $ cow : chr [1:220] "E07_C1" "E07_C2" "E07_C3" "E07_C4" ...
## $ exp : chr [1:220] "E07" "E07" "E07" "E07" ...
## $ nue_true : num [1:220] 0.317 0.289 0.268 0.258 0.27 ...
## $ milk_kgperd : num [1:220] 39.2 37.3 36.4 30.5 38.4 39.1 33.3 30.9 33.6 29.8 ...
## $ MUN : num [1:220] NA NA NA NA NA NA NA NA NA NA ...
## $ MUNY_gperd : num [1:220] NA NA NA NA NA NA NA NA NA NA ...
## $ MPY_MUNY : num [1:220] NA NA NA NA NA NA NA NA NA NA ...
## $ MUN_MPY : num [1:220] NA NA NA NA NA NA NA NA NA NA ...
## $ manure_n_gperd: num [1:220] 360 379 395 351 414 345 361 387 348 377 ...
## $ diet_cp : num [1:220] 155 165 173 167 158 159 164 166 169 161 ...
## $ lact_stage : chr [1:220] "early" "early" "early" "early" ...
summary(cr)
## cow exp nue_true milk_kgperd
## Length:220 Length:220 Min. :0.08225 Min. : 5.50
## Class :character Class :character 1st Qu.:0.22965 1st Qu.:21.93
## Mode :character Mode :character Median :0.26707 Median :27.45
## Mean :0.26721 Mean :26.68
## 3rd Qu.:0.30255 3rd Qu.:32.30
## Max. :0.42649 Max. :47.00
##
## MUN MUNY_gperd MPY_MUNY MUN_MPY
## Min. : 2.760 Min. :0.7121 Min. : 15.70 Min. : 3.065
## 1st Qu.: 7.130 1st Qu.:1.6916 1st Qu.: 23.65 1st Qu.: 7.883
## Median : 8.901 Median :2.6037 Median : 34.85 Median :10.419
## Mean : 9.841 Mean :2.8461 Mean : 37.90 Mean :11.382
## 3rd Qu.:12.420 3rd Qu.:3.9500 3rd Qu.: 45.63 3rd Qu.:14.179
## Max. :21.528 Max. :5.9848 Max. :126.45 Max. :28.919
## NA's :128 NA's :128 NA's :128 NA's :128
## manure_n_gperd diet_cp lact_stage
## Min. :168.0 Min. :107.0 Length:220
## 1st Qu.:265.8 1st Qu.:140.0 Class :character
## Median :317.5 Median :151.0 Mode :character
## Mean :323.1 Mean :153.4
## 3rd Qu.:376.2 3rd Qu.:167.2
## Max. :661.0 Max. :241.0
##
220 treatment means from 56 cows in crossover experiments. Methods do not account for pseudoreplication caused by within-cow repeated measurements.
98 treatment means for most varaibles due to missingness.
crs = cdat1 %>%
dplyr::select(nue_true, milk_kgperd, MUN, MUNY_gperd, MPY_MUNY, MUN_MPY, manure_n_gperd, diet_cp, lact_stage, cow)
crs$cow %>% unique %>% length
## [1] 56
crs %>%
dplyr::select(-cow, -lact_stage) %>%
ggpairs(lower = list(continuous = wrap(ggally_points, size = .2, color = "black"))) + theme_bw() + ggtitle("Fig. 1. Pairwise relations between variables in trt means (n = 98) \n in crossover experiments in CowNFlow. ")
Distribution gets skewed for MPY_MUNY. This is because the ratio involves the product of MPY * (MUNY^-1).
Still using CowNFlow treatment means. In regressing NUE on MUN, MPY, and the MUN:MPY and MPY:MUN ratios, MUN was the best predictor. Conceptually, using a ratio as a predictor is the same as including main effects and an interaction between MPY and the inverse of MUN (1/MUN) and fixing the coefficients to equality. Therefore, I tested models including different combinations of MUN, MP%, MUNY, MPY, milk yield, to predict urinary N and NUE.
not shown, for conciseness
MUN is more predictive of NUE and urine N excretion than any of the MPY:MUNY ratios. Additionally, some of the ratios impose non-linear relationships and non-normal distributions, reducing their convenience compared to MUN.
Find data for a group of cows fed different dietary CP for at least 3-4 levels, where it would be possible to detect a quadratic trend in milk protein yield vs. dietary CP %.
I tried subsetting the crossover trials in the CowNFlow database, but in most cases the observations did not span broad enough CP to show a clear linear and quadratic response for the peak dietary CP. I have not tested this with covariates. Lactation stage or intial production may be important.
Inconclusive - unsure where to get enough data preferably within cow across several dietary CP levels to test this. Neither GIZ13 nor MAW636 works (?).
For GIZ13, test if rates of change in MUN or other related variables correlate with rates of change in NUE across experimental days within lactation stage. The implication would be that dynamic changes in certain variables could indicate declining NUE even without measuring DMI.
For GIZ13, using the entire dataset (day by day).
dat <- read_excel("SAS.xlsx", sheet = "SAS")
trt = dat %>%
select(AnID, Lact, Trt) %>%
mutate(AnID = as.character(AnID)) %>%
distinct(AnID, Lact, Trt)
# covariate
cvt = dat %>%
filter(Expwk == 1 | Expwk == 2) %>%
group_by(AnID) %>%
summarise(across(where(is.numeric), mean, .names = "cvt_{col}"))
dat = dat %>%
filter(!(Expwk == 1) ) %>%
filter(!(Expwk == 2)) %>%
mutate(MPY_MUNY_ratio = PrtYield*1000/MUNY,
DIM_c = scale(DIM, center = T, scale = F)) %>%
group_by(AnID) %>%
mutate( DIM_1 = min(DIM),
expday_c = scale(expday, scale = F),
BW_c = scale(BW, scale = F)) %>%
filter(NUE < 50) %>%
left_join(cvt) %>%
mutate(cvt_BW_c = scale(cvt_BW, scale = F))
## Joining, by = "AnID"
split = dat %>%
split(~.$AnID)
Show one element of “split” (measurements for cow 5062)
str(split$`5062`)
## gropd_df [20 × 63] (S3: grouped_df/tbl_df/tbl/data.frame)
## $ AnID : num [1:20] 5062 5062 5062 5062 5062 ...
## $ DIM : num [1:20] 244 245 251 252 258 259 265 266 267 268 ...
## $ Preg : num [1:20] 19 20 26 27 33 34 40 41 42 43 ...
## $ Lact : chr [1:20] "4_Late" "4_Late" "4_Late" "4_Late" ...
## $ Trt : chr [1:20] "C" "C" "C" "C" ...
## $ Expwk : num [1:20] 3 3 4 4 5 5 6 6 6 6 ...
## $ expday : num [1:20] 16 17 23 24 30 31 37 38 39 40 ...
## $ DailyMY : num [1:20] 41.7 42 43.2 43 39.9 ...
## $ FatYield : num [1:20] 1.82 1.63 1.65 1.79 1.61 ...
## $ PrtYield : num [1:20] 1.31 1.35 1.4 1.4 1.33 ...
## $ LactY : num [1:20] 1.77 1.79 1.8 1.78 1.71 ...
## $ SNFY : num [1:20] 3.53 3.6 3.68 3.66 3.49 ...
## $ SCC : num [1:20] 17.1 27.4 58 36.4 27.2 ...
## $ MUN : num [1:20] 12.4 12.6 11.9 12.1 12.2 ...
## $ FatPct : num [1:20] 4.36 3.87 3.81 4.16 4.03 ...
## $ PrtPct : num [1:20] 3.13 3.2 3.24 3.25 3.34 ...
## $ LactPct : num [1:20] 4.25 4.25 4.16 4.13 4.28 ...
## $ SNFPct : num [1:20] 8.46 8.56 8.52 8.5 8.74 ...
## $ MUNY : num [1:20] 5.17 5.29 5.13 5.19 4.88 ...
## $ DMI : num [1:20] 30.7 28.6 28.4 32.1 33.1 ...
## $ FPCM : num [1:20] 42.9 40.9 41.9 43.5 40 ...
## $ ECM : num [1:20] 47.2 45.1 46.2 47.9 44.1 ...
## $ NEL : num [1:20] 31 29.5 30.1 31.3 29 ...
## $ NI : num [1:20] 0.823 0.765 0.761 0.86 0.886 ...
## $ NUE : num [1:20] 24.9 27.6 28.8 25.5 23.6 ...
## $ FE : num [1:20] 1.36 1.47 1.52 1.34 1.21 ...
## $ FPCME : num [1:20] 1.4 1.43 1.47 1.36 1.21 ...
## $ ECME : num [1:20] 1.54 1.58 1.63 1.49 1.33 ...
## $ NELE : num [1:20] 1.01 1.034 1.058 0.974 0.876 ...
## $ BW : num [1:20] 753 745 775 763 785 ...
## $ MPY_MUNY_ratio: num [1:20] 252 255 273 270 273 ...
## $ DIM_c : num [1:20, 1] 47.7 48.7 54.7 55.7 61.7 ...
## ..- attr(*, "scaled:center")= num 196
## $ DIM_1 : num [1:20] 244 244 244 244 244 244 244 244 244 244 ...
## $ expday_c : num [1:20, 1] -27.5 -26.5 -20.5 -19.5 -13.5 -12.5 -6.5 -5.5 -4.5 -3.5 ...
## $ BW_c : num [1:20, 1] -30.19 -37.44 -7.51 -19.3 2.47 ...
## $ cvt_DIM : num [1:20] 236 236 236 236 236 ...
## $ cvt_Preg : num [1:20] 10.8 10.8 10.8 10.8 10.8 ...
## $ cvt_Expwk : num [1:20] 1.67 1.67 1.67 1.67 1.67 ...
## $ cvt_expday : num [1:20] 7.83 7.83 7.83 7.83 7.83 ...
## $ cvt_DailyMY : num [1:20] 40 40 40 40 40 ...
## $ cvt_FatYield : num [1:20] 1.72 1.72 1.72 1.72 1.72 ...
## $ cvt_PrtYield : num [1:20] 1.21 1.21 1.21 1.21 1.21 ...
## $ cvt_LactY : num [1:20] 1.74 1.74 1.74 1.74 1.74 ...
## $ cvt_SNFY : num [1:20] 3.39 3.39 3.39 3.39 3.39 ...
## $ cvt_SCC : num [1:20] 31.6 31.6 31.6 31.6 31.6 ...
## $ cvt_MUN : num [1:20] 11 11 11 11 11 ...
## $ cvt_FatPct : num [1:20] 4.3 4.3 4.3 4.3 4.3 ...
## $ cvt_PrtPct : num [1:20] 3.02 3.02 3.02 3.02 3.02 ...
## $ cvt_LactPct : num [1:20] 4.34 4.34 4.34 4.34 4.34 ...
## $ cvt_SNFPct : num [1:20] 8.49 8.49 8.49 8.49 8.49 ...
## $ cvt_MUNY : num [1:20] 4.41 4.41 4.41 4.41 4.41 ...
## $ cvt_DMI : num [1:20] 32.6 32.6 32.6 32.6 32.6 ...
## $ cvt_FPCM : num [1:20] 40.5 40.5 40.5 40.5 40.5 ...
## $ cvt_ECM : num [1:20] 44.6 44.6 44.6 44.6 44.6 ...
## $ cvt_NEL : num [1:20] 29.4 29.4 29.4 29.4 29.4 ...
## $ cvt_NI : num [1:20] 0.845 0.845 0.845 0.845 0.845 ...
## $ cvt_NUE : num [1:20] 22.5 22.5 22.5 22.5 22.5 ...
## $ cvt_FE : num [1:20] 1.23 1.23 1.23 1.23 1.23 ...
## $ cvt_FPCME : num [1:20] 1.24 1.24 1.24 1.24 1.24 ...
## $ cvt_ECME : num [1:20] 1.37 1.37 1.37 1.37 1.37 ...
## $ cvt_NELE : num [1:20] 0.903 0.903 0.903 0.903 0.903 ...
## $ cvt_BW : num [1:20] 732 732 732 732 732 ...
## $ cvt_BW_c : num [1:20, 1] 0 0 0 0 0 0 0 0 0 0 ...
## - attr(*, "groups")= tibble [1 × 2] (S3: tbl_df/tbl/data.frame)
## ..$ AnID : num 5062
## ..$ .rows: list<int> [1:1]
## .. ..$ : int [1:20] 1 2 3 4 5 6 7 8 9 10 ...
## .. ..@ ptype: int(0)
## ..- attr(*, ".drop")= logi TRUE
names = names(split)
mod_res = split %>%
purrr::map(., ~lm(cbind(NUE, MUN, MUNY, MPY_MUNY_ratio, DailyMY, FPCM, PrtPct)~expday_c, .)) %>%
purrr::map(., ~tidy(.)) %>%
bind_rows() %>%
mutate(AnID = rep(names, each = length(.$estimate)/length(names))) %>%
# filter(term!="(Intercept)") %>%
left_join(trt)
## Joining, by = "AnID"
# dat$expday_c %>% summary
day = -30:24
AnID = dat$AnID %>% unique
days = expand.grid(day = day, AnID = AnID) %>% mutate(AnID = as.character(AnID))
mod_res_y = mod_res %>%
dplyr::select(term, response, estimate, AnID, Lact, Trt) %>%
pivot_wider(id_cols = c(AnID, response, Trt, Lact), names_from = term, values_from = estimate) %>%
rename(int = `(Intercept)`,
sl = expday_c) %>%
left_join(days) %>%
mutate(y = sl*day + int)
## Joining, by = "AnID"
mod_res_y %>%
ggplot(aes(x = day, y = y, color = Lact, group = Lact)) +
geom_point(size = .1, alpha = .2) +
facet_wrap(~response, scales = "free") +
#theme(legend.position = "none") +
geom_smooth(method = "lm") +
ggtitle("Fig. 2. By lactation stage, individual cow and mean linear rates of change across \n experimental days for selected variables in GIZ13")
## `geom_smooth()` using formula 'y ~ x'
mod_res_y %>%
ggplot(aes(x = day, y = y, color = Trt, group = Trt)) +
geom_point(size = .1, alpha = .2) +
facet_wrap(~response, scales = "free") +
#theme(legend.position = "none") +
geom_smooth(method = "lm")+
ggtitle("Fig. 3. By CP level, individual cow and mean linear rates of change across \n experimental days for selected variables in GIZ13")
## `geom_smooth()` using formula 'y ~ x'
mod_res_y %>%
ggplot(aes(x = day, y = y, color = Trt, group = Trt)) +
geom_point(size = .1, alpha = .2) +
facet_grid(response~Lact, scales = "free") +
#theme(legend.position = "none") +
geom_smooth(method = "lm")+theme_classic() +
ggtitle("Fig. 4. By CP level (color) and lactation stage (facet), \n individual cow and mean linear rate of change across experimental days for \n selected variables in GIZ13")
## `geom_smooth()` using formula 'y ~ x'
Delta NUE appears related to Delta MUNY in late lactation. At all stages of lactation Delta NUE is related to Delta milk yield. Therefore, the appropriate time to change diets (to optimize NUE) may be when milk yield starts to drop. Delta MUNY and Delta MUN may be useful indicators of dropping NUE in late lactation…more data would be useful to confirm this.
Using GIZ13 data (and possibly combining it with other similar RCBD studies such as Barros et al. 2017), we can demonstrate that grouping and separately feeding late lactation cows lower protein results in significant environmental benefits, i.e., reduction in urine urea N, manure volatile solids, predicted ammonia emissions, GHG emissions.
Extension of RCBD designs in GIZ13 and other recent trials.
We could report some measured values (e.g., urine N), and some predicted (e.g., methane). This would describe the rate of increase in environmental impact across stages of lactation. For GIZ13 where we have BW change, we can also consider Productive N After accounting for change in BW and gestation, although these are only a small fraction of predicted N use.
The conclusions would recommend optimal late lactation feeding strategies for certain groups of cows to minimize environmental impact. For example, when to switch diets and how to do it (literature review or simulated diets in NASEM).
Can now run NASEM in R on “batches” of simulated conditions with Excel input. For example, can simulate increasing stage of lactation or gestation day by day, or changing diets day-by-day.
inputs = read_excel("FuncInputsBWchange.xlsx")
inputs[4:15, 1:5] %>%
kable() %>%
row_spec(11:12, background = "yellow")
DietID | “test1” | “test2” | “test3” | “test4” |
---|---|---|---|---|
An_BW_mature | 700 | 700 | 700 | 700 |
Trg_FrmGain | 0 | 0 | 0 | 0 |
Trg_RsrvGain | 0 | 0 | 0 | 0 |
An_Parity_rl | 2 | 2 | 2 | 2 |
An_BCS | 3.5 | 3.5 | 3.5 | 3.5 |
An_GestLength | 283 | 283 | 283 | 283 |
An_AgeConcept1st | NA | NA | NA | NA |
An_DIMConcept | 100 | 101 | 102 | 103 |
Fet_BWbrth | 40.909090909090907 | 40.909090909090907 | 40.909090909090907 | 40.909090909090907 |
An_StatePhys | “Lactating Cow” | “Lactating Cow” | “Lactating Cow” | “Lactating Cow” |
An_LactDay | 150 | 151 | 152 | 153 |
An_GestDay | 50 | 51 | 52 | 53 |