alkIndivAge {FSA}R Documentation

Use an age-length key to assign age to individuals in the unaged sample.


Use either the semi- or completely-random methods from Isermann and Knight (2005) to assign ages to individual fish in the unaged sample according to the information in an age-length key supplied by the user.


alkIndivAge(key, formula, data, type = c("SR", "CR"), breaks = NULL,
  seed = NULL)



A numeric matrix that contains the age-length key. The format of this matrix is important. See details.


A formula of the form age~length where age generically represents the variable that will contain the estimated ages once the key is applied (i.e., should currently contain no values) and length generically represents the variable that contains the known length measurements. If only ~length is used, then a new variable called “age” will be created in the resulting data frame.


A data.frame that minimally contains the length measurements and possibly contains a variable that will receive the age assignments as given in formula.


A string that indicates whether to use the semi-random (type="SR", default) or completely-random (type="CR") methods for assigning ages to individual fish. See the IFAR chapter for more details.


A numeric vector of lower values that define the length intervals. See details.


A single numeric that is given to set.seed to set the random seed. This allows repeatability of results.


The age-length key in key must have length intervals as rows and ages as columns. The row names of key (i.e., rownames(key)) must contain the minimum values of each length interval (e.g., if an interval is 100-109, then the corresponding row name must be 100). The column names of key (i.e., colnames(key)) must contain the age values (e.g., the columns can NOT be named with “age.1”, for example).

The length intervals in the rows of key must contain all of the length intervals present in the unaged sample to which the age-length key is to be applied (i.e., sent in the length portion of the formula). If this constraint is not met, then the function will stop with an error message.

If breaks=NULL, then the length intervals for the unaged sample will be determined with a starting interval at the minimum value of the row names in key and a width of the length intervals as determined by the minimum difference in adjacent row names of key. If length intervals of differing widths were used when constructing key, then those breaks should be supplied to breaks=. Use of breaks= may be useful when “uneven” length interval widths were used because the lengths in the unaged sample are not fully represented in the aged sample. See the examples.

Assigned ages will be stored in the column identified on the left-hand-side of formula (if the formula has both a left- and right-hand-side). If this variable is missing in formula, then the new column will be labeled with age.


The original data.frame in data with assigned ages added to the column supplied in formula or in an additional column labeled as age. See details.


The type="SR" method worked perfectly on a small example. The type="SR" method provides results that reasonably approximate the results from alkAgeDist and alkMeanVar, which suggests that the age assessments are reasonable.

IFAR Chapter

5-Age-Length Key.


Derek H. Ogle, This is largely an R version of the SAS code provided by Isermann and Knight (2005).


Ogle, D.H. 2016. Introductory Fisheries Analyses with R. Chapman & Hall/CRC, Boca Raton, FL.

Isermann, D.A. and C.T. Knight. 2005. A computer program for age-length keys incorporating age assignment to individual fish. North American Journal of Fisheries Management, 25:1153-1160. [Was (is?) from]

See Also

See alkAgeDist and alkMeanVar for alternative methods to derived age distributions and mean (and SD) values for each age. See alkPlot for methods to visualize age-length keys.


## First Example -- Even breaks for length categories
WR1 <- WR79
# add length categories (width=5)
WR1$LCat <- lencat(WR1$len,w=5)
# isolate aged and unaged samples
WR1.age <- subset(WR1, !
WR1.len <- subset(WR1,
# note no ages in unaged sample
# create age-length key
raw <- xtabs(~LCat+age,data=WR1.age)
( WR1.key <- prop.table(raw, margin=1) )
# apply the age-length key
WR1.len <- alkIndivAge(WR1.key,age~len,data=WR1.len)
# now there are ages
# combine orig age & new ages
WR1.comb <- rbind(WR1.age, WR1.len)
# mean length-at-age
# age frequency distribution
( af <- xtabs(~age,data=WR1.comb) )
# proportional age distribution
( ap <- prop.table(af) )

## Second Example -- length sample does not have an age variable
WR2 <- WR79
# isolate age and unaged samples
WR2.age <- subset(WR2, !
WR2.len <- subset(WR2,
# remove age variable (for demo only)
WR2.len <- WR2.len[,-3]
# add length categories to aged sample
WR2.age$LCat <- lencat(WR2.age$len,w=5)
# create age-length key
raw <- xtabs(~LCat+age,data=WR2.age)
( WR2.key <- prop.table(raw, margin=1) )
# apply the age-length key
WR2.len <- alkIndivAge(WR2.key,~len,data=WR2.len)
# add length cat to length sample
WR2.len$LCat <- lencat(WR2.len$len,w=5)
# combine orig age & new ages
WR2.comb <- rbind(WR2.age, WR2.len)

## Third Example -- Uneven breaks for length categories
WR3 <- WR79
# set up uneven breaks
brks <- c(seq(35,100,5),110,130)
WR3$LCat <- lencat(WR3$len,breaks=brks)
WR3.age <- subset(WR3, !
WR3.len <- subset(WR3,
raw <- xtabs(~LCat+age,data=WR3.age)
( WR3.key <- prop.table(raw, margin=1) )
WR3.len <- alkIndivAge(WR3.key,age~len,data=WR3.len,breaks=brks)
WR3.comb <- rbind(WR3.age, WR3.len)

[Package FSA version Index]