import _ from 'lodash'; import { adjust_lenhei } from './z-score-helper'; import { standardize_sex_var, standardize_oedema_var, age_to_days, age_to_months, round } from './utils'; import anthro_zscore_length_for_age from './z-score-length-for-age'; import anthro_zscore_weight_for_age from './z-score-weight-for-age'; import anthro_zscore_weight_for_lenhei from './z-score-weight-for-lenhei'; import anthro_zscore_bmi_for_age from './z-score-bmi-for-age'; import anthro_zscore_head_circumference_for_age from './z-score-head-circumference-for-age'; import anthro_zscore_arm_circumference_for_age from './z-score-arm-circumference-for-age'; import anthro_zscore_triceps_skinfold_for_age from './z-score-triceps-skinfold-for-age'; import anthro_zscore_subscapular_skinfold_for_age from './z-score-subscapular-skinfold-for-age'; // ' Calculate z-scores for the eight anthropometric indicators // ' // ' @description // ' // ' This function calculates z-scores for the eight anthropometric indicators, // ' weight-for- age, length/height-for-age, weight-for-length/height, // ' body mass index (BMI)-for-age, head circumference-for-age, // ' arm circumference-for-age, triceps skinfold-for-age and subscapular // ' skinfold-for-age based on the WHO Child Growth Standards. // ' // ' @param sex A numeric or text variable containing gender information. // ' If it is numeric, its values must be: 1 for males and 2 for // ' females. If it is character, it must be "m" or "M" for males // ' and "f" or "F" for females. No z-scores will be calculated // ' if sex is missing. // ' @param age A numeric variable containing age information; age can be // ' in either days or months (if optional argument is_age_in_month // ' is set to TRUE). An exact age in days is expected and should // ' not be rounded if age is in months. Age-related z-scores will // ' NOT be calculated if age is missing (NA). // ' @param is_age_in_month A logical flag; if TRUE, variable age unit will be // ' treated as months. The function converts it to days by dividing // ' age by 30.4375 and rounding it to integer so that reference // ' tables can be used. When unspecified, the default value FALSE // ' is used and age unit is treated as days. // ' @param weight A numeric variable containing body weight information, which // ' must be in kilograms. Weight-related z-scores are not // ' calculated if body weight is missing. // ' @param lenhei A numeric variable containing length (recumbent length) or // ' height (standing height) information, which must be in // ' centimeters. Length/height-related z-scores will not be // ' calculated if lenhei is missing. For children with age // ' below 24 months (i.e. below 731 days) and standing height // ' measured, the function converts it to recumbent length by // ' adding 0.7 cm; and for children with age equal and above // ' 24 months and measured in recumbent length, the function // ' converts it to standing height by subtracting 0.7 cm. // ' This way all the z-scores calculated by this function are // ' length-based for children below 24 months, and // ' height-based otherwise. This converted length/height // ' according to age is assigned to the variable clenhei in // ' the resulting data.frame. // ' @param measure A character variable indicating whether recumbent length // ' or standing height was measured for each observation. // ' The values of this variable must be "L" or "l" for recumbent // ' length, and "H" or "h" for standing height. // ' Although it is highly recommended that this variable // ' is provided according to the measurements taken in // ' the survey, it is possible to run the analysis without // ' specifying this variable. If unspecified, the default // ' vector with all missing values is used. The function // ' imputes the missing values according to the // ' following algorithm: // ' \itemize{ // ' \item If age is not missing, then it is recumbent length // ' if age below 24 months (731 days), and standing height // ' if age equal and above 24 months. // ' \item If age is missing, then it is recumbent length if // ' measurement < 87 cm and standing height // ' if measurement >= 87 cm. // ' } // ' @param headc A numeric variable containing head circumference information, // ' which must be in centimeters. Head circumference-for-age // ' z-scores are not calculated if head circumference is missing. // ' @param armc A numeric variable containing arm circumference information, // ' which must be in centimeters. Arm circumference-for-age z-scores // ' are not calculated if arm circumference is missing. // ' @param triskin A numeric variable containing triceps skinfold information, // ' which must be in millimeters. Triceps skinfold-for-age z-scores // ' are not calculated if triceps skinfold is missing. // ' @param subskin A numeric variable containing subscapular skinfold information, // ' which must be in millimeters. Subscapular skinfold-for-age z-scores // ' are not calculated if subscapular skinfold is missing. // ' @param oedema The values of this character variable must be "n", "N" or "2" // ' for non-oedema, and "y", "Y", "1" for oedema. Although it is highly // ' recommended that this variable is provided by the survey, // ' it is possible to run // ' the analysis without specifying this variable. If unspecified, // ' the default vector of all "n" with values considered as // ' non-oedema is used. Missing values will be // ' treated as non-oedema. For oedema, weight related z-scores // ' (zwei, zwfl and zbmi) are NOT calculated (set to missing), // ' BUT they are treated as being < -3 SD in the weight-related // ' indicator prevalence (\code{\link{anthro_prevalence}}) // ' estimation. // ' // ' // ' @return A data.frame with three types of columns. Columns starting with a // ' "c" are cleaned versions of the input arguments. Columns beginning with // ' a "z" are the respective z-scores and columns prefixed by a "f" indicate // ' if these z-scores are flagged (integers). // ' The number of rows is given by the length // ' of the input arguments. // ' // ' The following columns are returned: // ' \itemize{ // ' \item{\code{clenhei}} converted length/height for deriving z-score // ' \item{\code{cbmi}} BMI value based on length/height given by clenhei // ' // ' \item{\code{zlen}} Length/Height-for-age z-score // ' \item{\code{flen}} 1, if \code{abs(zlen) > 6} // ' // ' \item{\code{zwei}} Weight-for-age z-score // ' \item{\code{fwei}} 1, if \code{zwei < -6} or \code{zwei > 5} // ' // ' \item{\code{zwfl}} Weight-for-length/height z-score // ' \item{\code{fwfl}} 1, if \code{abs(zwfl) > 5} // ' // ' \item{\code{zbmi}} BMI-for-age z-score // ' \item{\code{fbmi}} 1, if \code{abs(zbmi) > 5} // ' // ' \item{\code{zhc}} Head circumference-for-age z-score // ' \item{\code{fhc}} 1, if \code{abs(zhc) > 5} // ' // ' \item{\code{zac}} Arm circumference-for-age z-score // ' \item{\code{fac}} 1, if \code{abs(zac) > 5} // ' // ' \item{\code{zts}} Triceps skinfold-for-age z-score // ' \item{\code{fts}} 1, if \code{abs(zts) > 5} // ' // ' \item{\code{zss}} Subscapular skinfold-for-age z-score // ' \item{\code{fss}} 1, if \code{abs(zss) > 5} // ' // ' } // ' // ' If not all parameter values have equal length, parameter values will be // ' repeated to match the maximum length of all arguments except // ' \code{is_age_in_month} using \code{rep_len}. This happens without warnings. // ' // ' Z-scores are only computed for children younger than 60 months (age in months < 60) // ' // ' @references // ' WHO Multicentre Growth Reference Study Group (2006). WHO Child Growth Standards: Length/height-for-age, weight-for-age, weight-for-length, weight-for-height and body mass index-for-age: Methods and development. // ' Geneva: World Health Organization; pp 312. (web site: http://www.who.int/childgrowth/publications/en/ ) // ' // ' WHO Multicentre Growth Reference Study Group (2007). WHO Child Growth Standards: Head circumference-for-age, arm circumference-for-age, triceps skinfold-for-age and subscapular skinfold-for-age: Methods and development. // ' Geneva: World Health Organization; pp 217. (web site: http://www.who.int/childgrowth/publications/en/ ) // ' // ' @examples // ' # you can either use the function to compute zscores for specific values // ' anthro_zscores(sex = "f", age = 10, is_age_in_month = TRUE, weight = 10) // ' // ' # values will be recycled so not all input values need to be of the same length // ' anthro_zscores(sex = "f", age = c(10, 20, 30), weight = 10) // ' // ' # or use it with a compute dataset // ' \dontrun{ // ' your_data_set <- read.csv(".csv") // ' with( // ' your_data_set, // ' anthro_zscores( // ' sex = sex, age = age_in_days, // ' weight = weight, lenhei = lenhei // ' ) // ' ) // ' } // ' @include anthro.R // ' @include assertions.R // ' @export type anthro_zscores = { sex: string | 1 | 2, age?: number, is_age_in_month?: boolean, weight?: number, lenhei?: number, measure?: string, headc?: number, armc?: number, triskin?: number, subskin?: number, oedema?: string }; export default function anthro_zscores({ sex, age, is_age_in_month = false, weight, lenhei, measure, headc, armc, triskin, subskin, oedema = 'n', }: anthro_zscores) { // clean sex const csex = standardize_sex_var(sex); // clean oedema, we set all oedema not being "y" to "n" const oedema_clean = standardize_oedema_var(oedema); if(!csex) { console.error('Sex is required in order to calculate z-scores') } if(!age && csex) { // This will need to be adjusted if the "name" fields of the underlying anthro functions are changed console.info('Age not provided, returning only weight for length z-score without height adjustment') const output = { cbmi: undefined, clenhei: lenhei, cmeasure: undefined, csex, fac: undefined, fbmi: undefined, fhc: undefined, flen: undefined, fss: undefined, fts: undefined, fwei: undefined, zac: undefined, zbmi: undefined, zhc: undefined, zlen: undefined, zss: undefined, zts: undefined, zwei: undefined, ...anthro_zscore_weight_for_lenhei({ weight, lenhei: lenhei, lenhei_unit: undefined, sex: csex, oedema: oedema_clean, }), } return output } // clean measure let cmeasure: string | undefined = _.toLower(_.trim(measure)); cmeasure = ['l', 'h'].includes(cmeasure) ? cmeasure : undefined; const age_in_days = age ? age_to_days(age, is_age_in_month) : undefined; const age_in_months = age ? age_to_months(age, is_age_in_month) : undefined; // we consider a height measure for children younger than 9 months as // implausible cmeasure = (!_.isEmpty(cmeasure) && age_in_months && cmeasure === 'h' && age_in_months < 9) ? undefined : cmeasure; const clenhei = lenhei && age_in_days ? adjust_lenhei(age_in_days, cmeasure, lenhei) : undefined; const cbmi = weight && clenhei ? round(weight / ((clenhei / 100) ** 2)): undefined; if (age_in_days && age_in_months && csex) { const output = { clenhei, cbmi, cmeasure, csex, ...anthro_zscore_length_for_age({ lenhei: clenhei, age_in_days, age_in_months, sex: csex, }), ...anthro_zscore_weight_for_age({ weight, age_in_days, age_in_months, sex: csex, oedema: oedema_clean, }), ...anthro_zscore_weight_for_lenhei({ weight, lenhei: clenhei, lenhei_unit: cmeasure, age_in_days, age_in_months, sex: csex, oedema: oedema_clean, }), ...anthro_zscore_bmi_for_age({ bmi: cbmi, age_in_days, age_in_months, sex: csex, oedema: oedema_clean, }), ...anthro_zscore_head_circumference_for_age({ headc, age_in_days, age_in_months, sex: csex, }), ...anthro_zscore_arm_circumference_for_age({ armc, age_in_days, age_in_months, sex: csex, }), ...anthro_zscore_triceps_skinfold_for_age({ triskin, age_in_days, age_in_months, sex: csex, }), ...anthro_zscore_subscapular_skinfold_for_age({ subskin, age_in_days, age_in_months, sex: csex, }), }; return output } }