R/StdEffort.R

utils::globalVariables(
  c(
    "gear", "Sp_Catch", "Tot_Catch", "Effort", "std_value", "Gear", "."
  )
)
#' Standardization of Fishing Effort (StdEffort)
#'
#'
#' A method for estimating species-specific fishing effort in multi-gear
#' fisheries where fishing gears differ in efficiency and catch composition.
#' The procedure allocates fishing effort to the target species using catch
#' proportions and gear-specific weighting factors, and expresses effort in
#' terms of a common standard gear unit. The standardized effort is then used
#' to compute a CPUE index suitable for stock assessment, abundance monitoring,
#' and fisheries management analyses.
#'

#' @importFrom stats predict
#' @importFrom stats aggregate
#' @importFrom stats as.formula
#' @importFrom stats var
#' @importFrom stats residuals

#' @importFrom stats model.matrix

#' @importFrom stats median
#' @importFrom dplyr group_by mutate ungroup
#'
#' @description
#' This package provides a function named \code{StdEffort} for standardisation
#' of fishing effort expended by various fishing gears in order to obtain the
#' Catch Per Unit Effort (CPUE) for a particular fish species using the time
#' series of total catch (landings) by each fishing gear, catch (landings) of a
#' particular species (for which the CPUE is required) by each gear, and total
#' effort expended by each gear.
#' See the example dataset \link[=StdEffort_dataset]{StdEffort_dataset}.
#' @param sp_catch Time series of catch/landings of a particular species
#'   (for which the CPUE is required) by each gear. First column should be year.
#' @param tot_catch Time series of total catch/landings by each fishing gear.
#'   First column should be year.
#' @param effort Time series of total effort expended by each gear.
#'   First column should be year.
#' @param meg Choose most efficient gear by providing the corresponding gear name (String value).
#'   (for most efficient gear as standard unit).
#'
#' @details
#' Marine fisheries governance and management practices are very essential to
#' ensure the sustainability of marine resources. A widely accepted resource
#' management strategy towards this is to derive sustainable fish harvest levels
#' based on the status of marine fish stock. Various fish stock assessment
#' models that describe the biomass dynamics using time series data on fish
#' catch and fishing effort are generally used for this purpose.
#'
#' In the scenario of a complex multi-species marine fishery in which different
#' species are caught by a number of fishing gears, and each gear harvests a
#' number of species, it is difficult to obtain the fishing effort corresponding
#' to each fish species. Since the capacity of the gears varies, the effort made
#' to catch a resource cannot be considered as the sum of efforts expended by
#' different fishing gears. This necessitates standardisation of fishing effort
#' on a unit basis.
#'
#' This function standardises fishing effort expended by various gears and
#' obtains Catch Per Unit Effort (CPUE) for a particular fish species using
#' time series data of total catch by each fishing gear, catch of a particular
#' species, and total effort expended by each gear.
#'
#' @return
#' The output includes a summary table containing Year, Total Catch,
#' Nominal CPUE, and Standardized CPUE. In addition, two plots are
#' produced: Nominal CPUE versus Total Catch and Standardized CPUE
#' versus Total Catch.
#'
#' @note
#' The standardised effort can be obtained by user chosen gear
#' (for example, OBGN in hours) for that species.
#'
#' @references
#' Eldho Varghese, T. V. Sathianandan, J. Jayasankar, Somy Kuriakose,
#' K. G. Mini and M. Muktha (2020). Bayesian State-space Implementation of
#' Schaefer Production Model for Assessment of Stock Status for Multi-gear
#' Fishery, \emph{Journal of the Indian Society of Agricultural Statistics},
#' \strong{74}(1), 35--42.
#'
#' \strong{Acknowledgements:}

#'The authors sincerely thank the Director,

#'ICAR–Central Marine Fisheries Research Institute (ICAR-CMFRI), Kochi,

#'for providing the necessary facilities and institutional support.

#'The authors also gratefully acknowledge the support provided by

#'the Indian Council of Agricultural Research (ICAR),

#'Department of Agricultural Research and Education (DARE),

#'Government of India, through the ICAR-National Fellow Project.
#'
#' @examples
#' \dontrun{
#' library(FESta)
#' data("StdEffort_dataset")
#' result<-StdEffort(
#'   sp_catch  = StdEffort_dataset$sp_catch,
#'   tot_catch = StdEffort_dataset$tot_catch,
#'   effort    = StdEffort_dataset$effort,
#'   meg       = 'OBGN'
#' )
#' print(result)
#' }
#'
#' @export
#' @keywords Fishing effort Standardisation Fish stock assessment
StdEffort<- function (sp_catch,tot_catch,effort,meg)
{
  effort[effort==0]<-NA
  sp_catch1<-sp_catch[ ,-1]
  tot_catch1<-tot_catch[ ,-1]
  effort1<-effort[ ,-1]
  year_col<-sp_catch[,1]
  k<-0
  for(i in 1:ncol(effort1))
  {
    k[i]<-min(effort1[ ,i][which (effort1[,i]>0)])
  }

  #replacing NA/Zero with lowest effort
  for(i in 1:ncol(effort1))
    for(j in 1:nrow(effort1))
    {
      if (is.na(effort1[j,i]))  ##Change 1 (14/08/26)
      {
        effort1[j,i]<-k[i]
      }
    }

  #catch Proportion
  catch_prop=sp_catch1/tot_catch1
  # Replace all NaN values with NA across the whole dataframe
  catch_prop[is.nan(as.matrix(catch_prop))] <- NA
  count<-0
  for(i in 1:ncol(catch_prop))
  {
    count[i]<-length(catch_prop[ ,i][!is.na(catch_prop[ ,i])])
  }


  avg<-0
  std<-0
  wt<-0

  for(i in 1:ncol(catch_prop))
  {
    avg[i]<-mean(catch_prop[ ,i], na.rm=TRUE) #removing missing values
    std[i]<-var(catch_prop[ ,i], na.rm=TRUE)*((count[i]-1)/count[i]) #removing missing values
  print(std[i])
    }
  cv<-avg/(std+1)
  sm=sum(sort(cv)) #To remove NA used sort()

  for(i in 1:ncol(catch_prop))
  {
    wt[i]<-cv[i]/sm
  }

  stde<-catch_prop
  for(i in 1:ncol(catch_prop))
  {
    for(j in 1:nrow(catch_prop))
    {
      stde[j,i]<- wt[i]*catch_prop[j,i]*effort1[j,i]
    }
  }

  catchPerHour<-tot_catch1/effort1

  avg_hour<-0

  for(i in 1:ncol(catchPerHour))
  {
    avg_hour[i]<-mean(catchPerHour[ ,i], na.rm=TRUE) #removing missing values
  }
  ###
  chosen_meg=which(colnames(catchPerHour) == meg)

  fact<-avg_hour[chosen_meg]



  factor<-avg_hour/fact

  gear_Names<-as.vector(colnames(stde))
  for(i in 1:ncol(stde))
  {
    if (factor[i]==1)
    {
      STD_Unit<-gear_Names[i]
    }
  }

  names(STD_Unit)<-paste("Total_Effort interms of the following Gear Units:")

  std_effort<-stde
  for(i in 1:ncol(catch_prop))
  {
    for(j in 1:nrow(catch_prop))
    {
      std_effort[j,i]<-stde[j,i]*factor[i]
    }
  }

  std_effort[is.na(std_effort)]<-0
  year<-c(sp_catch[ ,1])

  Total_Catch<-rowSums(sp_catch1, na.rm = TRUE)
  Total_Effort<-rowSums(std_effort, na.rm = TRUE)
  CPUE<-Total_Catch/Total_Effort

  ####my requirement
  # Use the actual name of the first column instead of assuming it's "Year"
  year_colname <- names(sp_catch)[1]

  new_df_catch <- tidyr::pivot_longer(sp_catch,
                                      cols      = -dplyr::all_of(year_colname),
                                      names_to  = "Gear",
                                      values_to = "Catch")
  new_df_effort <- tidyr::pivot_longer(effort,
                                       cols      = -dplyr::all_of(year_colname),
                                       names_to  = "Gear",
                                       values_to = "Effort")

  ########START HERE
  sp_catch_long <- stats::reshape(
    sp_catch,
    varying = names(sp_catch)[-1],   # all cols except year
    v.names = "sp_catch",
    timevar = "gear",
    times = names(sp_catch)[-1],
    direction = "long"
  )
  sp_catch_long <- sp_catch_long[, c(year_colname, "gear", "sp_catch")]
  row.names(sp_catch_long) <- NULL
  sp_catch_long <- sp_catch_long[order(sp_catch_long[[year_colname]], sp_catch_long$gear), ]

  effort_long <- stats::reshape(
    effort,
    varying = names(effort)[-1],   # all cols except year
    v.names = "effort",
    timevar = "gear",
    times = names(effort)[-1],
    direction = "long"
  )
  effort_long <- effort_long[, c(year_colname, "gear", "effort")]
  row.names(effort_long) <- NULL
  effort_long <- effort_long[order(effort_long[[year_colname]], effort_long$gear), ]
  names(tot_catch)[1] <- "year"   # standardize first column name to "year" for the pivot below
  tot_catch_long <- tot_catch |>
    tidyr::pivot_longer(
      cols = -year,
      names_to = "gear",
      values_to = "tot_catch"
    ) |>
    dplyr::arrange(year, gear)

  # Safety check: sp_catch_long, effort_long and tot_catch_long are built
  # independently, then combined by position with cbind() below. If the
  # Year/Gear ordering doesn't match exactly across all three, cbind() will
  # silently misalign the data. This check catches that before it happens.
  if (!all(sp_catch_long$gear == effort_long$gear) ||
      !all(sp_catch_long$gear == tot_catch_long$gear) ||
      !all(sp_catch_long[[year_colname]] == effort_long[[year_colname]]) ||
      !all(sp_catch_long[[year_colname]] == tot_catch_long$year)) {
    stop("Year/Gear values do not line up across sp_catch, tot_catch, and effort. ",
         "Check that all three inputs have identical, identically-ordered gear columns.")
  }

  req_data_format <- cbind(sp_catch_long, tot_catch_long[["tot_catch"]], effort_long[["effort"]])
  colnames(req_data_format) <- c("Year", "Gear", "Sp_Catch", "Tot_Catch", "Effort")

  # Compute standardized value, dropping rows where it can't be calculated
  req_data_format <- req_data_format |>
    dplyr::mutate(std_value = (Sp_Catch / Tot_Catch) * Effort) |>
    dplyr::filter(!is.na(std_value))

  # Step 2: pivot to wide format
  year_gear_table <- req_data_format |>
    dplyr::select(Year, Gear, std_value) |>
    tidyr::pivot_wider(
      names_from = Gear,
      values_from = std_value,
      values_fn = list(std_value = mean)  # In case of duplicates
    )

  # Step 3: row-wise sum with na.rm = TRUE
  year_gear_table <- year_gear_table |>
    dplyr::mutate(year_gear_tot = rowSums(dplyr::pick(-Year), na.rm = TRUE))

  year_gear_tot <- year_gear_table[["year_gear_tot"]]

  # Step 4: yearwise total catch
  year_sp_tot <- req_data_format |>
    dplyr::group_by(Year) |>
    dplyr::summarise(year_sp_tot = sum(Sp_Catch, na.rm = TRUE)) |>
    dplyr::pull(year_sp_tot)

  nominal_CPUE <- year_sp_tot / year_gear_tot
  ############################################END HERE

  calculate_and_plot_cpue(year = year_col,
                          std_cpue =CPUE,effort = unlist(new_df_effort[,3]), total_catch = Total_Catch,catch = unlist(new_df_catch[,3]),nom_cpue= nominal_CPUE)


}

Try the FESta package in your browser

Any scripts or data that you put into this service are public.

FESta documentation built on Aug. 20, 2026, 5:10 p.m.