Skip to contents

Overview

greenfeedr provides a set of functions that help you work with GreenFeed data:

  • get_gfdata() downloads GreenFeed data via API.
  • report_gfdata() downloads and generates markdown reports of daily and final GreenFeed data.
  • process_gfdata() processes and averages daily or final GreenFeed data.
  • pellin() processes pellet intakes from GreenFeed units.
  • viseat() processes GreenFeed visits.

Most of these use the same daily and final data from GreenFeed system.

Citation

More complete information about how to use greenfeedr can be found in:

Cheat Sheet

Installation

You can install the released version of greenfeedr from CRAN with:

install.packages("greenfeedr")

Usage

Here we present an example of how to use process_gfdata():

library(greenfeedr)
#> Warning: package 'greenfeedr' was built under R version 4.4.1

Note that we received the finalized data (or Summarized Data) for our study using GreenFeed from C-Lock Inc. So, now we need to process all the daily records obtained.

The data looks like (first 5 cols):

RFID FID Start Time End Time Good Data Duration Hour Of Day CO2 Massflow (g/d) CH4 Massflow (g/d) O2 Massflow (g/d)
840003250681664 1 2024-05-13 09:33:24 2024-05-13 09:36:31 1899-12-31 00:02:31 9.556666 10541.00 466.9185 6821.710
840003250681664 1 2024-05-13 10:25:44 2024-05-13 10:32:40 1899-12-31 00:06:09 10.428889 14079.59 579.3398 8829.182
840003250681799 1 2024-05-13 12:29:02 2024-05-13 12:45:19 1899-12-31 00:10:21 12.483889 9273.30 302.3902 6193.614
840003250681664 1 2024-05-13 13:06:20 2024-05-13 13:12:14 1899-12-31 00:04:00 13.105555 14831.44 501.0839 10705.166
840003250681664 1 2024-05-13 14:34:58 2024-05-13 14:41:52 1899-12-31 00:04:55 14.582778 20187.44 759.9457 11080.463
840003234513955 1 2024-05-13 14:59:14 2024-05-13 15:11:50 1899-12-31 00:03:42 14.987223 13994.72 472.2763 8997.816

The first step is to investigate the total number of records, records per day, and days with records per week we have in our GreenFeed data.

To do this we will use the process_gfdata() function and test threshold values that will define the records we will retain for further analysis. Note that the function includes :

  • param1 is the number of records per day.
    • This parameter controls the minimum number of records that must be present for each day in the dataset to be considered valid.
  • param2 is the number of days with records per week.
    • This parameter ensures that a minimum number of days within a week have valid records to be included in the analysis.
  • min_time is the minimum duration of a record.
    • This parameter specifies the minimum time threshold for each record to be considered valid.

We can make an iterative process evaluating all possible combinations of parameters. Then, we define the parameters as follows:

# Define the parameter space for param1 (i), param2 (j), and min_time (k):
i <- seq(1, 3)
j <- seq(3, 7)
k <- seq(2, 5)

# Generate all combinations of i, j, and k
param_combinations <- expand.grid(param1 = i, param2 = j, min_time = k)

Interestingly, we have 60 combinations of our 3 parameters (param1, param2, and min_time).

The next step, is to evaluate the function process_gfdata() with the defined set of parameters. Note that the function can handle as argument a file path to the data files or the data as data frame.

# Helper function to call process_gfdata and extract relevant information
process_and_summarize <- function(param1, param2, min_time) {
  data <- process_gfdata(
    data = finaldata,
    start_date = "2024-05-13",
    end_date = "2024-05-25",
    param1 = param1,
    param2 = param2,
    min_time = min_time
  )

  # Extract daily_data and weekly_data
  daily_data <- data$daily_data
  weekly_data <- data$weekly_data

  # Calculate the required metrics
  records_d <- nrow(daily_data)
  cows_d <- length(unique(daily_data$RFID))

  mean_dCH4 <- mean(daily_data$CH4GramsPerDay, na.rm = TRUE)
  sd_dCH4 <- sd(daily_data$CH4GramsPerDay, na.rm = TRUE)
  CV_dCH4 <- sd(daily_data$CH4GramsPerDay, na.rm = TRUE) / mean(daily_data$CH4GramsPerDay, na.rm = TRUE)
  mean_dCO2 <- mean(daily_data$CO2GramsPerDay, na.rm = TRUE)
  sd_dCO2 <- sd(daily_data$CO2GramsPerDay, na.rm = TRUE)
  CV_dCO2 <- sd(daily_data$CO2GramsPerDay, na.rm = TRUE) / mean(daily_data$CO2GramsPerDay, na.rm = TRUE)

  records_w <- nrow(weekly_data)
  cows_w <- length(unique(weekly_data$RFID))

  mean_wCH4 <- mean(weekly_data$CH4GramsPerDay, na.rm = TRUE)
  sd_wCH4 <- sd(weekly_data$CH4GramsPerDay, na.rm = TRUE)
  CV_wCH4 <- sd(weekly_data$CH4GramsPerDay, na.rm = TRUE) / mean(weekly_data$CH4GramsPerDay, na.rm = TRUE)
  mean_wCO2 <- mean(weekly_data$CO2GramsPerDay, na.rm = TRUE)
  sd_wCO2 <- sd(weekly_data$CO2GramsPerDay, na.rm = TRUE)
  CV_wCO2 <- sd(weekly_data$CO2GramsPerDay, na.rm = TRUE) / mean(weekly_data$CO2GramsPerDay, na.rm = TRUE)

  # Return a summary row
  return(data.frame(
    param1 = param1,
    param2 = param2,
    min_time = min_time,
    records_d = records_d,
    cows_d = cows_d,
    mean_dCH4 = round(mean_dCH4, 1),
    sd_dCH4 = round(sd_dCH4, 1),
    CV_dCH4 = round(CV_dCH4, 2),
    mean_dCO2 = round(mean_dCO2, 1),
    sd_dCO2 = round(sd_dCO2, 1),
    CV_dCO2 = round(CV_dCO2, 2),
    records_w = records_w,
    cows_w = cows_w,
    mean_wCH4 = round(mean_wCH4, 1),
    sd_wCH4 = round(sd_wCH4, 1),
    CV_wCH4 = round(CV_wCH4, 2),
    mean_wCO2 = round(mean_wCO2, 1),
    sd_wCO2 = round(sd_wCO2, 1),
    CV_wCO2 = round(CV_wCO2, 2)
  ))
}

# Apply helper function to all combinations and combine results into a data frame
data <- param_combinations %>%
  purrr::pmap_dfr(process_and_summarize)

Finally, the results from our function will be placed in a data frame with the following structure:

param1 param2 min_time records_d cows_d mean_dCH4 sd_dCH4 CV_dCH4 mean_dCO2 sd_dCO2 CV_dCO2 records_w cows_w mean_wCH4 sd_wCH4 CV_wCH4 mean_wCO2 sd_wCO2 CV_wCO2
1 3 2 184 25 380.2 110.5 0.29 11429.1 2531.7 0.22 33 19 382.4 54.8 0.14 11488.1 1428.0 0.12
2 3 2 116 20 380.8 84.9 0.22 11450.6 2076.6 0.18 22 15 392.7 58.7 0.15 11630.5 1421.7 0.12
3 3 2 75 19 373.1 86.7 0.23 11394.2 2185.9 0.19 12 10 377.1 62.1 0.16 11458.8 1429.4 0.12
1 4 2 184 25 380.2 110.5 0.29 11429.1 2531.7 0.22 25 15 389.9 50.4 0.13 11685.1 1266.2 0.11
2 4 2 116 20 380.8 84.9 0.22 11450.6 2076.6 0.18 17 14 380.5 51.6 0.14 11367.5 1264.2 0.11
3 4 2 75 19 373.1 86.7 0.23 11394.2 2185.9 0.19 6 5 359.4 41.9 0.12 11310.2 1595.7 0.14
1 5 2 184 25 380.2 110.5 0.29 11429.1 2531.7 0.22 21 15 380.2 48.1 0.13 11444.3 1182.3 0.10
2 5 2 116 20 380.8 84.9 0.22 11450.6 2076.6 0.18 8 7 361.5 38.8 0.11 11247.0 1250.1 0.11
3 5 2 75 19 373.1 86.7 0.23 11394.2 2185.9 0.19 4 3 360.3 50.0 0.14 11555.9 2000.6 0.17
1 6 2 184 25 380.2 110.5 0.29 11429.1 2531.7 0.22 14 11 378.1 50.6 0.13 11208.1 1316.1 0.12

That gives the user an idea of what are the pros and cons of being more or less conservative when processing GreenFeed data for analysis. In general, the more conservative the parameters are, the fewer records are retained in the data.

Getting help

If you encounter a clear bug, please file an issue with a minimal reproducible example on GitHub.