Compiled date: 2024-11-28
Last edited: 2022-01-12
License: GPL-3
Run the following code to install the Bioconductor version of the package.
We will also need some additional CRAN packages that will be very useful in this vignette.
In nutritional studies, dietary data are usually collected by using different questionnaires such as FFQs (food frequency questionnaires) or 24h-DRs (24 hours dietary recall). Commonly, the text collected in these questionnaires require a manual preprocessing step before being analyzed.
This is an example of how an FFQ could look like in a common nutritional study.
load("data/sample_ffq.rda")
sample_ffq %>%
dplyr::slice(1L:10L) %>%
kbl(row.names = FALSE, booktabs = TRUE) %>%
kable_styling(latex_options = c("striped"))
ID | Name |
---|---|
ID_001 | Beef: roast, steak, mince, stew casserole, curry or bolognese |
ID_002 | Beefburgers |
ID_003 | Pork: roast, chops, stew, slice or curry |
ID_004 | Lamb: roast, chops, stew or curry |
ID_005 | Chicken, turkey or other poultry: including fried, casseroles or curry |
ID_006 | Bacon |
ID_007 | Ham |
ID_008 | Corned beef, Spam, luncheon meats |
ID_009 | Sausages |
ID_0010 | Savoury pies, e.g. meat pie, pork pie, pasties, steak & kidney pie, sausage rolls, scotch egg |
The fobitools::annotate_foods()
function allows the
automatic annotation of free nutritional text using the FOBI ontology
(Castellano-Escuder et al.
2020). This function provides users with a table of food IDs,
food names, FOBI IDs and FOBI names of the FOBI terms that match the
input text. The input should be structured as a two column data frame,
indicating the food IDs (first column) and food names (second column).
Note that food names can be provided both as words and complex
strings.
This function includes a text mining algorithm composed of 5 sequential layers. In this process, singulars and plurals are analyzed, irrelevant words are removed, each string of the text input is tokenized and each word is analyzed independently, and the semantic similarity between input text and FOBI items is computed. Finally, this function also shows the percentage of the annotated input text.
annotated_text <- fobitools::annotate_foods(sample_ffq)
#> 89.57% annotated
#> 2.165 sec elapsed
annotated_text$annotated %>%
dplyr::slice(1L:10L) %>%
kbl(row.names = FALSE, booktabs = TRUE) %>%
kable_styling(latex_options = c("striped"))
FOOD_ID | FOOD_NAME | FOBI_ID | FOBI_NAME |
---|---|---|---|
ID_00100 | Oranges, satsumas, mandarins, tangerines, clementines | FOODON:03309832 | orange (whole, raw) |
ID_00101 | Grapefruit | FOODON:03301702 | grapefruit (whole, raw) |
ID_00102 | Bananas | FOODON:03311513 | banana (whole, ripe) |
ID_00103 | Grapes | FOODON:03301123 | grape (whole, raw) |
ID_00104 | Melon | FOODON:03301593 | melon (raw) |
ID_00105 | *Peaches, plums, apricots, nectarines | FOODON:03301107 | nectarine (whole, raw) |
ID_00106 | *Strawberries, raspberries, kiwi fruit | FOODON:03305656 | fruit (dried) |
ID_00106 | *Strawberries, raspberries, kiwi fruit | FOODON:03414363 | kiwi |
ID_00106 | *Strawberries, raspberries, kiwi fruit | FOODON:00001057 | plant fruit food product |
ID_00107 | Tinned fruit | FOODON:03305656 | fruit (dried) |
Additionally, the similarity argument indicates the semantic similarity cutoff used at the last layer of the text mining pipeline. It is a numeric value between 1 (exact match) and 0 (very poor match). Users can modify this value to obtain more or less accurated annotations. Authors do not recommend values below 0.85 (default).
annotated_text_95 <- fobitools::annotate_foods(sample_ffq, similarity = 0.95)
#> 86.5% annotated
#> 2.155 sec elapsed
annotated_text_95$annotated %>%
dplyr::slice(1L:10L) %>%
kbl(row.names = FALSE, booktabs = TRUE) %>%
kable_styling(latex_options = c("striped"))
FOOD_ID | FOOD_NAME | FOBI_ID | FOBI_NAME |
---|---|---|---|
ID_00100 | Oranges, satsumas, mandarins, tangerines, clementines | FOODON:03309832 | orange (whole, raw) |
ID_00101 | Grapefruit | FOODON:03301702 | grapefruit (whole, raw) |
ID_00102 | Bananas | FOODON:03311513 | banana (whole, ripe) |
ID_00103 | Grapes | FOODON:03301123 | grape (whole, raw) |
ID_00104 | Melon | FOODON:03301593 | melon (raw) |
ID_00105 | *Peaches, plums, apricots, nectarines | FOODON:03301107 | nectarine (whole, raw) |
ID_00106 | *Strawberries, raspberries, kiwi fruit | FOODON:03305656 | fruit (dried) |
ID_00106 | *Strawberries, raspberries, kiwi fruit | FOODON:03414363 | kiwi |
ID_00106 | *Strawberries, raspberries, kiwi fruit | FOODON:00001057 | plant fruit food product |
ID_00107 | Tinned fruit | FOODON:03305656 | fruit (dried) |
See that by increasing the similarity value from 0.85 (default value)
to 0.95 (a more accurate annotation), the percentage of annotated terms
decreases from 89.57% to 86.5%. Let’s check those food items annotated
with similarity = 0.85
but not with
similarity = 0.95
.
annotated_text$annotated %>%
filter(!FOOD_ID %in% annotated_text_95$annotated$FOOD_ID) %>%
kbl(row.names = FALSE, booktabs = TRUE) %>%
kable_styling(latex_options = c("striped"))
FOOD_ID | FOOD_NAME | FOBI_ID | FOBI_NAME |
---|---|---|---|
ID_00124 | Beansprouts…130 | FOODON:00002753 | bean (whole) |
ID_00127 | Watercress | FOODON:00002340 | water food product |
ID_00140 | Beansprouts…171 | FOODON:00002753 | bean (whole) |
ID_00143 | Brocoli | FOODON:03301713 | broccoli floret (whole, raw) |
ID_002 | Beefburgers | FOODON:00002737 | beef hamburger (dish) |
Then, with the fobitools::fobi_graph()
function we can
visualize the annotated food terms with their corresponding FOBI
relationships.
Most likely we may be interested in knowing the food-related compounds in our study. Well, if so, once the foods are annotated we can obtain the metabolites associated with the annotated foods as follows:
inverse_rel <- fobitools::fobi %>%
filter(id_BiomarkerOf %in% annotated_text$annotated$FOBI_ID) %>%
dplyr::select(id_code, name, id_BiomarkerOf, FOBI) %>%
dplyr::rename(METABOLITE_ID = 1, METABOLITE_NAME = 2, FOBI_ID = 3, METABOLITE_FOBI_ID = 4)
annotated_foods_and_metabolites <- left_join(annotated_text$annotated, inverse_rel, by = "FOBI_ID")
annotated_foods_and_metabolites %>%
filter(!is.na(METABOLITE_ID)) %>%
dplyr::slice(1L:10L) %>%
kbl(row.names = FALSE, booktabs = TRUE) %>%
kable_styling(latex_options = c("striped"))
FOOD_ID | FOOD_NAME | FOBI_ID | FOBI_NAME | METABOLITE_ID | METABOLITE_NAME | METABOLITE_FOBI_ID |
---|---|---|---|---|---|---|
ID_00100 | Oranges, satsumas, mandarins, tangerines, clementines | FOODON:03309832 | orange (whole, raw) | CHEBI:15600 | (+)-catechin | FOBI:030460 |
ID_00100 | Oranges, satsumas, mandarins, tangerines, clementines | FOODON:03309832 | orange (whole, raw) | CHEBI:15864 | luteolin | FOBI:030555 |
ID_00100 | Oranges, satsumas, mandarins, tangerines, clementines | FOODON:03309832 | orange (whole, raw) | CHEBI:16243 | quercetin | FOBI:030558 |
ID_00100 | Oranges, satsumas, mandarins, tangerines, clementines | FOODON:03309832 | orange (whole, raw) | CHEBI:17620 | ferulic acid | FOBI:030406 |
ID_00100 | Oranges, satsumas, mandarins, tangerines, clementines | FOODON:03309832 | orange (whole, raw) | CHEBI:17620 | ferulic acid | FOBI:030406 |
ID_00100 | Oranges, satsumas, mandarins, tangerines, clementines | FOODON:03309832 | orange (whole, raw) | CHEBI:18388 | apigenin | FOBI:030553 |
ID_00100 | Oranges, satsumas, mandarins, tangerines, clementines | FOODON:03309832 | orange (whole, raw) | CHEBI:28499 | kaempferol | FOBI:030565 |
ID_00100 | Oranges, satsumas, mandarins, tangerines, clementines | FOODON:03309832 | orange (whole, raw) | CHEBI:6052 | isorhamnetin | FOBI:030562 |
ID_00100 | Oranges, satsumas, mandarins, tangerines, clementines | FOODON:03309832 | orange (whole, raw) | CHEBI:77131 | sinapic acid | FOBI:030412 |
ID_00100 | Oranges, satsumas, mandarins, tangerines, clementines | FOODON:03309832 | orange (whole, raw) | CHEBI:77131 | sinapic acid | FOBI:030412 |
The FOBI ontology is currently in its first release version, so it
does not yet include information on many metabolites, foods and food
relationships. All future efforts will be directed at expanding this
ontology, leading to a significant increase in the number of
metabolites, foods (from FoodOn ontology (Dooley et al. 2018)) and
metabolite-food relationships. The fobitools
package
provides the methodology for easy use of the FOBI ontology regardless of
the amount of information it contains. Therefore, future FOBI
improvements will also have a direct impact on the
fobitools
package, increasing its utility and allowing to
perform, among others, more accurate, complete and robust dietary text
annotations.
sessionInfo()
#> R version 4.4.2 (2024-10-31)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.1 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_US.UTF-8 LC_COLLATE=C
#> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
#> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
#> [9] LC_ADDRESS=C LC_TELEPHONE=C
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] kableExtra_1.4.0 lubridate_1.9.3 forcats_1.0.0 stringr_1.5.1
#> [5] dplyr_1.1.4 purrr_1.0.2 readr_2.1.5 tidyr_1.3.1
#> [9] tibble_3.2.1 ggplot2_3.5.1 tidyverse_2.0.0 fobitools_1.15.1
#> [13] BiocStyle_2.35.0
#>
#> loaded via a namespace (and not attached):
#> [1] DBI_1.2.3 ada_2.0-5 qdapRegex_0.7.8
#> [4] gridExtra_2.3 rlang_1.1.4 magrittr_2.0.3
#> [7] e1071_1.7-16 compiler_4.4.2 RSQLite_2.3.8
#> [10] systemfonts_1.1.0 vctrs_0.6.5 pkgconfig_2.0.3
#> [13] crayon_1.5.3 fastmap_1.2.0 labeling_0.4.3
#> [16] ggraph_2.2.1 utf8_1.2.4 rmarkdown_2.29
#> [19] prodlim_2024.06.25 tzdb_0.4.0 bit_4.5.0
#> [22] xfun_0.49 cachem_1.1.0 jsonlite_1.8.9
#> [25] blob_1.2.4 tictoc_1.2.1 BiocParallel_1.41.0
#> [28] tweenr_2.0.3 syuzhet_1.0.7 parallel_4.4.2
#> [31] R6_2.5.1 bslib_0.8.0 stringi_1.8.4
#> [34] textclean_0.9.3 parallelly_1.39.0 rpart_4.1.23
#> [37] jquerylib_0.1.4 Rcpp_1.0.13-1 knitr_1.49
#> [40] future.apply_1.11.3 clisymbols_1.2.0 timechange_0.3.0
#> [43] Matrix_1.7-1 splines_4.4.2 nnet_7.3-19
#> [46] igraph_2.1.1 tidyselect_1.2.1 rstudioapi_0.17.1
#> [49] yaml_2.3.10 viridis_0.6.5 codetools_0.2-20
#> [52] listenv_0.9.1 lattice_0.22-6 withr_3.0.2
#> [55] evaluate_1.0.1 ontologyIndex_2.12 future_1.34.0
#> [58] survival_3.7-0 proxy_0.4-27 polyclip_1.10-7
#> [61] xml2_1.3.6 pillar_1.9.0 BiocManager_1.30.25
#> [64] lexicon_1.2.1 generics_0.1.3 vroom_1.6.5
#> [67] hms_1.1.3 munsell_0.5.1 scales_1.3.0
#> [70] ff_4.5.0 globals_0.16.3 xtable_1.8-4
#> [73] class_7.3-22 glue_1.8.0 RecordLinkage_0.4-12.4
#> [76] maketools_1.3.1 tools_4.4.2 sys_3.4.3
#> [79] data.table_1.16.2 fgsea_1.33.0 buildtools_1.0.0
#> [82] graphlayouts_1.2.1 fastmatch_1.1-4 tidygraph_1.3.1
#> [85] cowplot_1.1.3 grid_4.4.2 ipred_0.9-15
#> [88] colorspace_2.1-1 ggforce_0.4.2 cli_3.6.3
#> [91] evd_2.3-7.1 fansi_1.0.6 viridisLite_0.4.2
#> [94] svglite_2.1.3 lava_1.8.0 gtable_0.3.6
#> [97] sass_0.4.9 digest_0.6.37 ggrepel_0.9.6
#> [100] farver_2.1.2 memoise_2.0.1 htmltools_0.5.8.1
#> [103] lifecycle_1.0.4 bit64_4.5.2 MASS_7.3-61