# Age Precision and Bias — Changes to FSA

**fishR » R**, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)

Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Last week I taught part of a workshop for the Minnesota Chapter of the American Fisheries Society on “Analyzing Age Data in R” (materials are here). I like doing these workshops because they give me ideas for improving the **FSA** package and fishR. One of several things that came out of this workshop was a realization that the measures of precision for multiple age assignments on individual fish (think two or more “readers” assigning an age to each fish) that I had coded in `ageComp()`

was restricted to only two age assignments. The methods as described in the literature generalize to two or more age assignments. My code had to change!

The latest version of the **FSA** package now has two new functions, `ageBias()`

and `agePrecision()`

, which replace `ageComp()`

(`ageComp()`

currently remains in **FSA** but will be removed in future versions, so you should begin changing your usage now). I have not yet updated the “Age Comparisons Vignette” on fishR (I want to make major changes to all of the content in that vignette, not just the R part), so I will briefly demonstrate the new functions in this post.

Obviously, I need to load the **FSA** package.

library(FSA)

I will use the information in the `WhitefishLC`

data frame which has age assignments for three structures (otoliths, finrays, and scales) made by two readers (1 and 2). The readers also came to a concensus age (labeled with a “C”).

data(WhitefishLC) str(WhitefishLC) ## 'data.frame': 151 obs. of 11 variables: ## $ fishID : int 1 2 3 4 5 6 7 8 9 10 ... ## $ tl : int 345 334 348 300 330 316 508 475 340 173 ... ## $ scale1 : int 3 4 7 4 3 4 6 4 3 1 ... ## $ scale2 : int 3 3 5 3 3 4 7 5 3 1 ... ## $ scaleC : int 3 4 6 4 3 4 7 5 3 1 ... ## $ finray1 : int 3 3 3 3 4 2 6 9 2 2 ... ## $ finray2 : int 3 3 3 2 3 3 6 9 3 1 ... ## $ finrayC : int 3 3 3 3 4 3 6 9 3 1 ... ## $ otolith1: int 3 3 3 3 3 6 9 11 3 1 ... ## $ otolith2: int 3 3 3 3 3 5 10 12 4 1 ... ## $ otolithC: int 3 3 3 3 3 6 10 11 4 1 ...

## Measures of Precision

Measures of precision are now computed with `agePrecision()`

which uses formula notation with all variables on the right-hand-side of the formula and separated by “plus”es. Of course, with the formula notation the `data=`

argument is required. [Note that the measures of precision here are not that useful because of potential bias between the structures; however, these data can be used to illustrate the use of more than two age assignments.]

ap3 <- agePrecision(~otolithC+finrayC+scaleC,data=WhitefishLC)

The overall measures of precision (mean APE, mean CV, and percent total agreement for all structures) are then computed with

summary(ap3,what="precision") ## Precision summary statistics ## n R CV APE PercAgree ## 151 3 21.77 16.19 12.58

The percentages of fish by absolute difference in age assignment for each pair of measures are obtained with

summary(ap3,what="agreement") ## Percentage of fish by differences in ages between pairs of assignments ## 0 1 2 3 4 5 ## otolithC v. finrayC 24.5033 21.1921 17.8808 11.9205 7.2848 7.9470 ## otolithC v. scaleC 19.8675 30.4636 16.5563 13.9073 5.9603 3.3113 ## finrayC v. scaleC 40.3974 34.4371 15.2318 5.2980 3.9735 0.0000 ## 6 7 8 9 10 11 ## otolithC v. finrayC 3.3113 2.6490 0.6623 1.3245 0.0000 0.6623 ## otolithC v. scaleC 5.2980 1.9868 1.3245 0.0000 0.0000 0.6623 ## finrayC v. scaleC 0.6623 0.0000 0.0000 0.0000 0.0000 0.0000 ## 12 13 14 ## otolithC v. finrayC 0.0000 0.0000 0.6623 ## otolithC v. scaleC 0.0000 0.6623 0.0000 ## finrayC v. scaleC 0.0000 0.0000 0.0000

The example above demonstrated the new functionality for more than two age assignments. Of course, two age assignments can still be used

ap2 <- agePrecision(~otolith1+otolith2,data=WhitefishLC) summary(ap2,what="precision") ## Precision summary statistics ## n R CV APE PercAgree ## 151 2 4.719 3.337 62.25 summary(ap2,what="agreement") ## Percentage of fish by differences in ages between pairs of assignments ## 0 1 2 ## 62.25 31.79 5.96

## Age Bias

The new code for assessing age bias uses `ageBias()`

with the same arguments used in the original `ageComp()`

– i.e., a formula with the age assignments thought to be “more correct” on the left-hand-side, the other age assignment on the right-hand-side, the `data=`

argument, and column and row labels in `col.lab=`

and `row.lab=`

, respectively. The `ageBias()`

function still only works with two sets of age assignments.

ab1 <- ageBias(otolithC~scaleC,data=WhitefishLC, col.lab="Otolith Age",row.lab="Scale Age")

The overall age agreement table and Bowker’s test for symmetry are computed with

summary(ab1,what="symmetry") ## Raw agreement table (square) ## Otolith Age ## Scale Age 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ## 1 5 4 1 - - - - - - - - - - - - - - - - - - ## 2 4 1 - 1 - - - - - - - - - - - - - - - - - ## 3 - 1 10 6 - 1 - - - - - - - - - - - - - - - ## 4 - - 5 7 3 3 - - - - - - - - - - - - - - - ## 5 - 1 - 3 2 5 3 4 - - 1 - - - - - - - - - - ## 6 - - 1 1 2 1 3 4 1 2 1 1 2 1 - - - - - - - ## 7 - - - - - - 1 3 6 4 2 2 1 1 - - - 1 - - - ## 8 - - - - 1 - 1 1 3 3 3 1 - - - - - - - - - ## 9 - - - - - - - - - - 1 1 1 - 2 - 1 - - - - ## 10 - - - - - - 1 - - - - 1 1 - - 1 - - - - - ## 11 - - - - - - - - - - - - 1 - 1 - 2 - - - - ## 12 - - - - - - - - - - - 1 - - 1 1 - - - - - ## 13 - - - - - - - - - - - - 1 1 - 1 1 1 - - - ## 14 - - - - - - - - - - - - - - 1 - - - 1 - - ## 15 - - - - - - - - - - - - - - - 1 - - - - - ## 16 - - - - - - - - - - - - - - - - - - - - - ## 17 - - - - - - - - - - - - - - - - - - - - - ## 18 - - - - - - - - - - - - - - - - - - - - - ## 19 - - - - - - - - - - - - - - - - - - - - - ## 20 - - - - - - - - - - - - - - - - - - - - - ## 21 - - - - - - - - - - - - - - - - - - - - - ## 22 - - - - - - - - - - - - - - - - - - - - - ## 23 - - - - - - - - - - - - - - - - - - - - - ## Otolith Age ## Scale Age 22 23 ## 1 - - ## 2 - - ## 3 - - ## 4 - - ## 5 - - ## 6 - - ## 7 - - ## 8 - - ## 9 - - ## 10 - 1 ## 11 - - ## 12 - - ## 13 - - ## 14 - - ## 15 - - ## 16 - - ## 17 - - ## 18 - - ## 19 - - ## 20 - - ## 21 - - ## 22 - - ## 23 - - ## ## Bowker's (Hoenig's) Test of Symmetry ## df chi.sq p ## 54 75.98 0.02598

The summary statistics, t-test results, and confidence intervals for the “other” (row) age assignments at each age of the “more correct” (column) age assignments are obtained with

summary(ab1,what="bias") ## Summary of Scale Age by Otolith Age ## otolithC n min max mean SE t adj.p sig LCI UCI ## 1 9 1 2 1.44 0.176 2.530 0.21160 FALSE 1.039 1.85 ## 2 7 1 5 2.00 0.577 0.000 1.00000 FALSE 0.587 3.41 ## 3 17 1 6 3.35 0.242 1.460 0.81763 FALSE 2.841 3.87 ## 4 18 2 6 3.83 0.232 -0.718 1.00000 FALSE 3.343 4.32 ## 5 8 4 8 5.25 0.491 0.509 1.00000 FALSE 4.089 6.41 ## 6 10 3 6 4.60 0.267 -5.250 0.00528 TRUE 3.997 5.20 ## 7 9 5 10 6.44 0.556 -1.000 1.00000 FALSE 5.163 7.73 ## 8 12 5 8 6.08 0.288 -6.665 0.00042 TRUE 5.450 6.72 ## 9 10 6 8 7.20 0.200 -8.999 0.00011 TRUE 6.748 7.65 ## 10 9 6 8 7.11 0.261 -11.087 0.00005 TRUE 6.510 7.71 ## 11 8 5 9 7.25 0.453 -8.275 0.00081 TRUE 6.178 8.32 ## 12 7 6 12 8.43 0.782 -4.564 0.03450 TRUE 6.514 10.34 ## 13 7 6 13 8.86 1.010 -4.101 0.05079 FALSE 6.385 11.33 ## 14 3 6 13 8.67 NA NA NA FALSE NA NA ## 15 5 9 14 11.00 0.949 -4.216 0.09462 FALSE 8.366 13.63 ## 16 4 10 15 12.50 NA NA NA FALSE NA NA ## 17 4 9 13 11.00 NA NA NA FALSE NA NA ## 18 2 7 13 10.00 NA NA NA FALSE NA NA ## 19 1 14 14 14.00 NA NA NA FALSE NA NA ## 23 1 10 10 10.00 NA NA NA FALSE NA NA

The default age-bias plot is provided with

plot(ab1)

I changed the code for the age-bias plot so that confidence intervals are not computed for ages with “small” sample sizes. The definition of small can be controlled with `min.n.CI=`

(which defaults to 5) in the `ageBias()`

call. For example, the default age-bias plot from the original `ageComp()`

is constructed with

ab2 <- ageBias(otolithC~scaleC,data=WhitefishLC,min.n.CI=2, col.lab="Otolith Age",row.lab="Scale Age") plot(ab2)

This is, of course, quite ugly. I also modified the code to more sensibly handle controlling the axes in situations like this. For example,

plot(ab2,ylim=c(0,23))

More details are in the help files for `ageBias()`

and `agePrecision()`

. Let me know if you have any questions or comments.

Filed under: Fisheries Science, R Tagged: "Age Bias", "Precision, Age, Age Comparisons", R

**leave a comment**for the author, please follow the link and comment on their blog:

**fishR » R**.

R-bloggers.com offers

**daily e-mail updates**about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.

Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.