The gosset package [@deSousa2023gosset] provides methods to implement workflows to analyse experimental agriculture data, from data synthesis to model selection and visualisation. The package is named after W.S. Gosset aka ‘Student’, a pioneer of modern statistics in small sample experimental design and analysis.
In this example we show one of the possible workflows to assess trait prioritization and crop performance using decentralized on-farm data generated with the tricot approach [@deSousa2024]. We use the nicabean
data. This dataset was generated with decentralized on-farm trials of common bean (Phaseolus vulgaris L.) varieties in Nicaragua over five seasons (between 2015 and 2016). Following the tricot approach [@deSousa2024], farmers were asked to test in their farms three varieties of common bean. The varieties were randomly assigned as incomplete blocks of size three (out of 10 varieties). The farmers assessed which of the three varieties had the best and worst performance in eight traits (vigor, architecture, resistance to pests, resistance to diseases, tolerance to drought, yield, marketability, and taste). The farmers also provided their overall appreciation about the varieties, i.e., which variety had the best and the worst performance based on the overall performance considering all the traits.
Here we use the Plackett-Luce model, jointly proposed by Luce (1959) [@luce_individual_1959] and Plackett (1975) [@Plackett]. This model estimates the probability of one variety outperforming all the others (worth) in the trait based on the Luce's axiom[@luce_individual_1959]. The model is implemented in R
by Turner et al. (2020) with the package PlackettLuce [@Turner2020].
The nicabean
is a list with two data frames. The first, trial
, contains the trial data with farmers’ evaluations, ranked from 1 to 3, with 1 being the higher ranked variety and 3 the lowest ranked variety for the given trait and incomplete block. The rankings in this dataset were previously transformed from tricot rankings (where participants indicate best and worst) to ordinal rankings using the function rank_tricot()
. The second data frame, covar
, contains the covariates associated to the on-farm trial plots and farmers. This example will require the packages PlackettLuce [@Turner2020], climatrends [@climatrends], chirps [@chirps] and ggplot2 [@ggplot2].
``` {r starting, message = FALSE, eval = TRUE, echo = TRUE} library("gosset") library("PlackettLuce") library("climatrends") library("chirps") library("ggplot2")
data("nicabean", package = "gosset")
dat = nicabean$trial
covar = nicabean$covar
traits = unique(dat$trait)
dat
To start the analysis of the data, we transform the ordinal rankings into Plackett-Luce rankings (a sparse matrix) using the function `rank_numeric()`. We run iteratively over the traits adding the rankings to a list called `R`. Since the varieties are ranked in an ascending order, with 1 being the higher ranked and 3 the lower ranked, we use the argument `asceding = TRUE` to indicate which order should be used. ```r R = vector(mode = "list", length = length(traits)) for (i in seq_along(traits)) { dat_i = subset(dat, dat$trait == traits[i]) R[[i]] = rank_numeric(data = dat_i, items = "item", input = "rank", id = "id", ascending = TRUE) }
Using the function kendallTau()
we can compute the Kendall tau ($\tau$) coefficient [@kendall_1938] to identify the correlation between farmers' overall appreciation and the other traits in the trial. This approach can be used, for example, to assess the drivers of farmers choices or to prioritize traits to be tested in a next stage of tricot trials (e.g. a lite version of tricot with no more than 4 traits to assess). We use the overall appreciation as the reference trait, and compare the Kendall tau with the other 8 traits.
baseline = which(grepl("OverallAppreciation", traits)) kendall = lapply(R[-baseline], function(X){ kendallTau(x = X, y = R[[baseline]]) }) kendall = do.call("rbind", kendall) kendall$trait = traits[-baseline]
The kendall correlation shows that farmers prioritized the traits yield ($\tau$ = 0.749), taste ($\tau$ = 0.653) and marketability ($\tau$ = 0.639) when assessing overall appreciation.
kendall = kendall[,c(5, 1:4)] kendall[,2:4] = lapply(kendall[,2:4], function(x) round(x, 3)) kendall[,5] = formatC(kendall[,5], format = "e") kendall
For each trait, we fit a Plackett-Luce model using the function PlackettLuce()
from the package of the same name. This will allow us to continue the analysis of the trial data using the other functions in the package gosset.
mod = lapply(R, PlackettLuce)
The worth_map()
function can be used to visually assess and compare item performance based on different characteristics. The values represented in a worth_map are log-worth estimates. From the breeder or product developer perspective the function worth_map()
offers a visualization tool to help in identifying item performance based on different characteristics and select crossing materials.
worth_map(mod[-baseline], labels = traits[-baseline], ref = "Amadeus 77") + labs(x = "Variety", y = "Trait")
To consider the effect of climate factors on yield, we use agro-climatic covariates to fit a Plackett-Luce tree. For simplicity, we use the total rainfall (Rtotal) derived from CHIRPS data [@Funk2015], obtained in R using the R package chirps [@chirps]. Additional covariates can be used in a Plackett-Luce tree, for example using temperature data from R package ag5Tools [@ag5tools] or nasapower [@nasapower].
We request the CHIRPS data using the package chirps. Data should be returned as a matrix. This process can take some minutes to be implemented.
dates = c(min(covar[, "planting_date"]), max(covar[, "planting_date"]) + 70) chirps = get_chirps(covar[, c("longitude","latitude")], dates = as.character(dates), as.matrix = TRUE, server = "ClimateSERV")
load("nicabean_chirps.rda")
We compute the rainfall indices from planting date to the first 45 days of plant growth using the function rainfall()
from package climatrends [@climatrends].
newnames = dimnames(chirps)[[2]] newnames = gsub("chirps-v2.0.", "", newnames) newnames = gsub("[.]", "-", newnames) dimnames(chirps)[[2]] = newnames rain = rainfall(chirps, day.one = covar$planting_date, span = 45)
To be linked to covariates, the rankings should be coerced to a 'grouped_rankings' object. For this we use the function group()
from PlackettLuce. We retain the ranking corresponding to yield.
yield = which(grepl("Yield", traits)) G = group(R[[yield]], index = 1:length(R[[yield]])) head(G)
Now we can fit the Plackett-Luce tree with climate covariates.
pldG = cbind(G, rain) tree = pltree(G ~ Rtotal, data = pldG, alpha = 0.1) print(tree)
The following is an example of the plot made with the function plot()
in the gosset package. The functions node_labels()
, node_rules()
and top_items()
can be used to identify the splitting variables in the tree, the rules used to split the tree and the best items in each node, respectively.
node_labels(tree) node_rules(tree) top_items(tree, top = 3)
plot(tree, ref = "Amadeus 77")
We can use the function reliability()
to compute the reliability of the evaluated common bean varieties in each of the resulting nodes of the Plackett-Luce tree (Table 3). This helps in identifying the varieties with higher probability to outperform a variety check (Amadeus 77) [@eskridge_1992]. For simplicity, we present only the varieties with reliability $\geq$ 0.5.
reliability(tree, ref = "Amadeus 77")
rel = reliability(tree, ref = "Amadeus 77") rel = rel[rel$reliability >= 0.5, ] rel = rel[c(1:5)] rel
The result shows that three varieties can marginally outperform Amadeus 77 under drier growing conditions (Rtotal $\leq$ 193.82 mm) whereas two varieties have a superior yield performance when under higher rainfall conditions (Rtotal $>$ 193.82 mm) compared to the reference. This approach helps in identifying superior varieties for different target population environments. For example, the variety ALS 0532-6 shows weak performance in the whole yield ranking, however for the sub-group of higher rainfall, the variety outperforms all the others. Combining rankings with socio-economic covariates could also support the identification of superior materials for different market segments.
A better approach to assess the performance of varieties can be using the 'Overall Appreciation", since we expect this trait to capture the performance of the variety not only for yield, but for all the other traits prioritized by farmers (Table 2). To support this hypotheses, we use the function compare()
which applies the approach proposed by Bland and Altman (1986) [@MartinBland1986] to assess the agreement between two different measures. We compare overall vs yield. If both measures completely agree, all the varieties should be centered to 0 in the axis Y.
Overall = PlackettLuce(R[[baseline]]) Yield = PlackettLuce(R[[yield]]) compare(Overall, Yield) + labs(x = "Average log(worth)", y = "Difference (Overall Appreciation - Yield)")
The chart shows no complete agreement between overall appreciation and yield. For example, variety SX 14825-7-1 shows superior performance for overall appreciation when compared with yield. Looking at the log-worth in the heat map of Figure 1, we can argue that the superior performance of the given variety is also related to taste, marketability and diseases resistance. This performance, however, was not captured when assessing only yield.
Here we presented a simple workflow to assess crop variety performance and trait prioritization in decentralized on-farm trials with the tricot approach. A more complex workflow will also utilize other functions available in gosset, for example, a forward selection combined with crossvalidation()
to improve model robustness, or model selection with btpermute()
to consider all possible permutations in Bradley-Terry models, or a risk analysis using regret()
to support the selection of varieties, or using rank_numeric()
to combine legacy data and deal with heterogeneous data from different trials. All of these were previously implemented and validated elsewhere [@vanEtten2019; @Moyo_2021; @deSousa2021; @Steinkemindata2019; @brownlegacydata].
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.