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.
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.