Nutrient Profile Model Scoring
Source:vignettes/nutrientprofile_scoring.Rmd
nutrientprofile_scoring.Rmd
To determine the individual nutritional element scores that can be used in a Nutrient Profile Model there are two crucial steps:
- Adjust the nutritional value based on the specific gravity adjusted weight and any unit transformations required
- Score the adjusted nutritional value based on a set of thresholds
Below we outline the underlying logic for implementing both these
steps in the nutrientprofiler
package.
Adjuster functions
Nutritional values need to be adjusted before scoring to ensure:
- The nutritional information is adjusted based on their nutrient denisty which is standardised to 100g of the product rather than the total amount to enable better comparisons between products
- They are converted into the appropriate unit for scoring thresholds
All adjuster functions are built ontop of the
generic_adjuster
function.
generic_adjuster(10, 15)
#> [1] 66.66667
This takes a value
argument for the amount of a
nutritional category and divides it by the second argument
adjusted_weight
which corresponds to the specific gravity
adjusted weight/volume for the product as determined using the specific
gravity functions above. The output of this is multiplied by 100 to give
the final adjusted value.
Energy and salt adjustments
This is enough for adjusting most nutritional values but for both energy and salt we need additional steps to properly adjust the value for the appropriate units. This is because for energy nutritional information can be in either kcal or kJ and for salt can either be listed as a sodium measurement in mg or a salt measurement in g. The scoring thresholds for the Nutrient Profile Model are specified for kJ for energy and mg of sodium for salt so additional steps are needed to properly adjust these values if present in the alternate unit.
This is handled by specific adjuster functions for energy and salt
that also take an adjuster_type
argument to specify the
units of the passed value.
# for energy in kj
energy_value_adjuster(10, 80, adjuster_type="kj")
#> [1] 12.5
# for energy in kcal
energy_value_adjuster(60, 300, adjuster_type="kj")
#> [1] 20
# for salt in grams
salt_adjuster(3, 100, adjuster_type="salt")
#> [1] 1200
# for salt in mg of sodium
salt_adjuster(60, 100, adjuster_type="sodium")
#> [1] 60
Scoring function
The adjuster functions return an adjusted value for nutritional
information to ensure we can calculate the NPM Score based on 100g of
the product. We use this adjusted value in the subsequent step for
actually calculating a score for each of our nutrient groups. This is
performed using the NPM_score_function
which acts as a
dispatcher function that takes value
and type
arguments to determine which adjustment function to call and which
scoring thresholds to use. This function also takes optional additional
arguments such as specifying the adjusted_weight
that can
be passed into the adjuster functions and the adjuster_type
argument for some types such as energy
and
salt
.
# calculate a score for a protein value
NPM_score_function(80, adjusted_weight=100, "protein")
#> [1] 5
Under the hood this function is calling the
generic_adjuster
from above to adjust the nutritional value
using the adjusted_weight
, next it passes this adjusted
value to the scoring_function
. The
scoring_function
determines the score of a value based on
provided score thresholds.
# create thesholds vector from largest to smallest
THRESHOLDS <- c(3, 2, 1)
# score the value 1 against the provided thresholds
# returns 0
scoring_function(1, THRESHOLDS)
#> [1] 0
# returns 2
scoring_function(2.1, THRESHOLDS)
#> [1] 2
The scoring_function
behaves by taking a vector of
thresholds in descending order. First it sets the score to be the total
number of thresholds available (i.e. 3 in the above example). It takes
the value we have provided and checks if this value is greater than each
item in the thresholds vector, if it is greater than the item from
thresholds it returns the score corresponding to that item. If the value
isn’t greater than the item then the score, set earlier, is deducted 1.
The continues for each item in the thresholds until the only option left
is our value not being greater than the final item in our thresholds
leading to a score of 0.
Fruit, vegetables and nuts scoring
The one exception to this scoring function is for fruit, vegetables
and nuts. This nutritional information is presented as a percentage and
the scoring for this specified in the Nutrient Profile Model doesn’t
score this in a continuous manner so this package includes a specific
fruit_veg_nut_scorer
. This function takes value and returns
a score (either 0, 1, 2 or 5) depending on if the value meets a specific
percentage threshold.
# scores a 5
fruit_veg_nut_scorer(81)
#> [1] 5
# scores a 2
fruit_veg_nut_scorer(70)
#> [1] 2
# scores a 1
fruit_veg_nut_scorer(45)
#> [1] 1
# scores a 0
fruit_veg_nut_scorer(20)
#> [1] 0