Compute age- and length-binned number proportions#

Import necessary modules#

With all of the data ingested, preprocessed, and stratified, we can begin to run the transect-based analysis for estimating spatial distributions of fish. The first steps of this part of the analysis leverage functions from the proportions module from the survey sub-package.

from echopop.survey import proportions as get_proportions

Animal counts over age and length bins#

The first step comprises computing the count distributions for length and age bins (if present) for each sex across strata (we will be using "stratum_ks" as our stratum definition). These binned counts are done separately for aged and unaged fish since they are processed somewhat differently throughout this workflow. However, the function compute_binned_counts from the survey.proportions module can be parameterized within any number of groupby_col columns.

# Dataset for number counts
ds_counts = xr.Dataset()

# Aged
ds_counts["aged"] = get_proportions.compute_binned_counts(
    data=dict_df_bio["specimen"].dropna(subset=["age", "length", "weight"]),
    groupby_cols=["stratum_ks", "length_bin", "age_bin", "sex"],
    count_col="length",
    agg_func="size",
)

# Unaged
ds_counts["unaged"] = get_proportions.compute_binned_counts(
    data=dict_df_bio["length"].copy().dropna(subset=["length"]),
    groupby_cols=["stratum_ks", "length_bin", "sex"],
    count_col="length_count",
    agg_func="sum",
)

The compute_binned_counts function produces an xarray.Dataset comprising the aged and unaged datasets. These are stored as data variables within ds_counts with shared coordinates and dimensions.

with the defined groupby_cols and their associated count totals. For instance, the first 10 rows of dict_df_counts["aged"] looks like:

<xarray.Dataset> Size: 200kB
Dimensions:     (stratum_ks: 9, length_bin: 40, age_bin: 22, sex: 3)
Coordinates:
  * stratum_ks  (stratum_ks) int64 72B 0 1 2 3 4 5 6 7 8
  * length_bin  (length_bin) category 680B (1.0, 3.0] ... (79.0, 81.0]
  * age_bin     (age_bin) category 374B (0.5, 1.5] (1.5, 2.5] ... (21.5, 22.5]
  * sex         (sex) object 24B 'female' 'male' 'unsexed'
Data variables:
    aged        (stratum_ks, length_bin, age_bin, sex) int64 190kB 0 0 0 ... 0 0
    unaged      (stratum_ks, length_bin, sex) float64 9kB nan nan ... 0.0 0.0

Convert counts into number proportions#

These binned counts are normalized into proportions using the number_proportions function. This takes in the entire dictionary copmrising the aged and unaged fish to compute the within group proportions (i.e. those specific to just aged and unaged) as well as the overall/global proportions (i.e. counts relative to the summed counts across all aged and unaged animals). This adds one data variable: proportion (overall/global). Within-group proportions can be derived by re-normalizing proportion within the target dataset/group context. Here, the exclude_filters argument is defined to explicitly remove sex = "unsexed" from only the aged dataset.

# Compute number proportions
dict_ds_number_proportion = get_proportions.number_proportions(
    data=ds_counts,
    stratum_dim="stratum_ks",
    exclude_filters={"aged": {"sex": "unsexed"}},
)

This results in a dictionary of xarray.Dataset objects containing two data variables: count (number of animals per bin) and proportion (overall/across-group proportion). As an example, the aged dataset contains this structure:

<xarray.Dataset> Size: 255kB
Dimensions:     (stratum_ks: 9, length_bin: 40, age_bin: 22, sex: 2)
Coordinates:
  * stratum_ks  (stratum_ks) int64 72B 0 1 2 3 4 5 6 7 8
  * length_bin  (length_bin) category 680B (1.0, 3.0] ... (79.0, 81.0]
  * age_bin     (age_bin) category 374B (0.5, 1.5] (1.5, 2.5] ... (21.5, 22.5]
  * sex         (sex) object 16B 'female' 'male'
Data variables:
    count       (stratum_ks, length_bin, age_bin, sex) int64 127kB 0 0 0 ... 0 0
    proportion  (stratum_ks, length_bin, age_bin, sex) float64 127kB 0.0 ... 0.0