Skip to contents

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