Food for Thought I -- Getting Data

About

This is an ongoing project on menu optimizing. It’s mainly an excuse for me to use several data science techniques in various proportions: along the way I query an API, generate menus, solve them algorithmically, simulate solving them, scrape the web for real menus, and touch on some natural language processing techniques. Don’t worry about getting too hungry: this project has been fairly nicknamed slandered “Eat, Pray, Barf.”

The meat of the project surrounds building menus and changing them until they are in compliance with daily nutritional guidelines. We’ll simulate the curve of the proportion of these that are solvable as we increase the minimum portion size that each food must meet. Finally, I start about trying to improve the quality of the menus (i.e., decrease barf factor) by taking a cue from actual recipes scraped from Allrecipes.com. Check out the GitHub repo for the full code and [writeup](https://github.com/aedobbyn/menu-builder/blob/master/compile/writeup.md.


Getting from A to Beef

The data we’ll be using here is conveniently located in an Excel file called ABBREV.xlsx on the USDA website. As the name suggests, this is an abbreviated version of all the foods in their database.

If you do want the full list, they provide a Microsoft Access SQL dump as well (which requires that you have Access). The USDA also does have an open API so you can create an API key and grab foods from them with requests along the lines of a quick example I’ll go through. The API documentation walks through the format for requesting data in more detail. I’ll walk through an exmaple of how to get some foods and a few of their associated nutrient values.

The base URL we’ll want is http://api.nal.usda.gov/ndb/.

The default number of results per request is 50 so we specify 1500 as our max. In this example I set subset to 1 in order to grab the most common foods. (Otherwise 1:1500 query only gets you from a to beef 😆.) If you do want to grab all foods, you can send requests of 1500 iteratively specifying offset, which refers to the number of the first row you want, and then glue them together. We’ve specified just 4 nutrient values we want here: calories, sugar, lipids, and carbohydrates.

After attaching those parameters to the end of our base URL, we’d have:

http://api.nal.usda.gov/ndb/nutrients/?format=json&api_key="<YOUR_KEY_HERE>&subset=1&max=1500&nutrients=205&nutrients=204&nutrients=208&nutrients=269

In the browser, you could paste that same thing in to see:


We’ll use the jsonlite package to turn that fromJSON into an R object.

foods_raw <- jsonlite::fromJSON(paste0("http://api.nal.usda.gov/ndb/nutrients/?format=json&api_key=", 
                       key, "&subset=1&max=1500&nutrients=205&nutrients=204&nutrients=208&nutrients=269"), flatten = FALSE)

foods <- as_tibble(foods_raw$report$foods)
head(foods) %>% kable(format = "html")
ndbno name weight measure nutrients
14007 Alcoholic beverage, beer, light, BUD LIGHT 29.5 1.0 fl oz 208, 269, 204, 205, Energy, Sugars, total, Total lipid (fat), Carbohydrate, by difference, kcal, g, g, g, 9, –, 0.00, 0.38, 29, –, 0, 1.3
14009 Alcoholic beverage, daiquiri, canned 30.5 1.0 fl oz 208, 269, 204, 205, Energy, Sugars, total, Total lipid (fat), Carbohydrate, by difference, kcal, g, g, g, 38, –, 0.00, 4.79, 125, –, 0, 15.7
14534 Alcoholic beverage, liqueur, coffee, 63 proof 34.8 1.0 fl oz 208, 269, 204, 205, Energy, Sugars, total, Total lipid (fat), Carbohydrate, by difference, kcal, g, g, g, 107, –, 0.10, 11.21, 308, –, 0.3, 32.2
14015 Alcoholic beverage, pina colada, canned 32.6 1.0 fl oz 208, 269, 204, 205, Energy, Sugars, total, Total lipid (fat), Carbohydrate, by difference, kcal, g, g, g, 77, –, 2.48, 9.00, 237, –, 7.6, 27.6
14019 Alcoholic beverage, tequila sunrise, canned 31.1 1.0 fl oz 208, 269, 204, 205, Energy, Sugars, total, Total lipid (fat), Carbohydrate, by difference, kcal, g, g, g, 34, –, 0.03, 3.51, 110, –, 0.1, 11.3
14027 Alcoholic beverage, whiskey sour, canned 30.8 1.0 fl oz 208, 269, 204, 205, Energy, Sugars, total, Total lipid (fat), Carbohydrate, by difference, kcal, g, g, g, 37, –, 0.00, 4.13, 119, –, 0, 13.4

We’ve got one row per food and a nested list-col of nutrients.

str(foods$nutrients[1:3])
## List of 3
##  $ :'data.frame':    4 obs. of  5 variables:
##   ..$ nutrient_id: chr [1:4] "208" "269" "204" "205"
##   ..$ nutrient   : chr [1:4] "Energy" "Sugars, total" "Total lipid (fat)" "Carbohydrate, by difference"
##   ..$ unit       : chr [1:4] "kcal" "g" "g" "g"
##   ..$ value      : chr [1:4] "9" "--" "0.00" "0.38"
##   ..$ gm         : chr [1:4] "29" "--" "0" "1.3"
##  $ :'data.frame':    4 obs. of  5 variables:
##   ..$ nutrient_id: chr [1:4] "208" "269" "204" "205"
##   ..$ nutrient   : chr [1:4] "Energy" "Sugars, total" "Total lipid (fat)" "Carbohydrate, by difference"
##   ..$ unit       : chr [1:4] "kcal" "g" "g" "g"
##   ..$ value      : chr [1:4] "38" "--" "0.00" "4.79"
##   ..$ gm         : chr [1:4] "125" "--" "0" "15.7"
##  $ :'data.frame':    4 obs. of  5 variables:
##   ..$ nutrient_id: chr [1:4] "208" "269" "204" "205"
##   ..$ nutrient   : chr [1:4] "Energy" "Sugars, total" "Total lipid (fat)" "Carbohydrate, by difference"
##   ..$ unit       : chr [1:4] "kcal" "g" "g" "g"
##   ..$ value      : chr [1:4] "107" "--" "0.10" "11.21"
##   ..$ gm         : chr [1:4] "308" "--" "0.3" "32.2"

If we tried to unnest this right now we’d get an error.

foods %>% unnest()   # error :(

That’s because missing values are coded as --.

foods$nutrients[[100]] %>% as_tibble() 
## # A tibble: 4 x 5
##   nutrient_id nutrient                    unit  value gm   
## * <chr>       <chr>                       <chr> <chr> <chr>
## 1 208         Energy                      kcal  --    --   
## 2 269         Sugars, total               g     --    --   
## 3 204         Total lipid (fat)           g     0.00  0    
## 4 205         Carbohydrate, by difference g     --    --

This becomes an issue for two of these columns, gm and value because gm gets coded as type numeric if there are no mising values and character otherwise. Consider the case where we have no missing values: here we see that gm is numeric.

foods$nutrients[[200]] %>% as_tibble()
## # A tibble: 4 x 5
##   nutrient_id nutrient                    unit  value    gm
## * <chr>       <chr>                       <chr> <chr> <dbl>
## 1 208         Energy                      kcal  216   540. 
## 2 269         Sugars, total               g     17.00  42.5
## 3 204         Total lipid (fat)           g     12.00  30.0
## 4 205         Carbohydrate, by difference g     23.98  60.0

We can’t unnest yet because a single column in a dataframe can only have values of one type; without changing the types of the various gm columns to a lowest common denominator, we won’t be able to combine them.

We can replace our --s with NAs no problem

foods$nutrients <- foods$nutrients %>% 
  map(na_if, "--") 

but unnesting is the challenge.

foods %>% unnest()
## Error in bind_rows_(x, .id): Column `gm` can't be converted from character to numeric

The naive approach of mapping character over all the nutrients columns doesn’t give us the output we expect

foods$nutrients[1] %>% map(as.character)
## [[1]]
## [1] "c(\"208\", \"269\", \"204\", \"205\")"                                                   
## [2] "c(\"Energy\", \"Sugars, total\", \"Total lipid (fat)\", \"Carbohydrate, by difference\")"
## [3] "c(\"kcal\", \"g\", \"g\", \"g\")"                                                        
## [4] "c(\"9\", NA, \"0.00\", \"0.38\")"                                                        
## [5] "c(\"29\", NA, \"0\", \"1.3\")"

and we’re stuck with the usual sense of not quite being able to reach the part of the data we want. (All credit here to Jenny Bryan.)

So instead we’ll dive into the second level of our nested list, take everything in there to character, and then unnest.

foods$nutrients <- foods$nutrients %>% modify_depth(2, as.character)

Which is a nicer way of saying

for (i in 1:length(foods$nutrients)) {
  for (j in 1:nrow(foods$nutrients[[1]])) {
    foods$nutrients[[i]]$nutrient_id[j] <- as.character(foods$nutrients[[i]]$nutrient_id[j])
    foods$nutrients[[i]]$nutrient[j] <- as.character(foods$nutrients[[i]]$nutrient[j])
    foods$nutrients[[i]]$unit[j] <- as.character(foods$nutrients[[i]]$unit[j])
    foods$nutrients[[i]]$gm[j] <- as.character(foods$nutrients[[i]]$gm[j])
    foods$nutrients[[i]]$value[j] <- as.character(foods$nutrients[[i]]$value[j])
  }
}

Now we can unnest the whole thing.

foods <- foods %>% unnest()

Finally, let’s set value and gm to numeric.

foods$value <- as.numeric(foods$value)
foods$gm <- as.numeric(foods$gm)
foods[1:20, ] %>% kable(format = "html")
ndbno name weight measure nutrient_id nutrient unit value gm
14007 Alcoholic beverage, beer, light, BUD LIGHT 29.5 1.0 fl oz 208 Energy kcal 9.00 29.0
14007 Alcoholic beverage, beer, light, BUD LIGHT 29.5 1.0 fl oz 269 Sugars, total g NA NA
14007 Alcoholic beverage, beer, light, BUD LIGHT 29.5 1.0 fl oz 204 Total lipid (fat) g 0.00 0.0
14007 Alcoholic beverage, beer, light, BUD LIGHT 29.5 1.0 fl oz 205 Carbohydrate, by difference g 0.38 1.3
14009 Alcoholic beverage, daiquiri, canned 30.5 1.0 fl oz 208 Energy kcal 38.00 125.0
14009 Alcoholic beverage, daiquiri, canned 30.5 1.0 fl oz 269 Sugars, total g NA NA
14009 Alcoholic beverage, daiquiri, canned 30.5 1.0 fl oz 204 Total lipid (fat) g 0.00 0.0
14009 Alcoholic beverage, daiquiri, canned 30.5 1.0 fl oz 205 Carbohydrate, by difference g 4.79 15.7
14534 Alcoholic beverage, liqueur, coffee, 63 proof 34.8 1.0 fl oz 208 Energy kcal 107.00 308.0
14534 Alcoholic beverage, liqueur, coffee, 63 proof 34.8 1.0 fl oz 269 Sugars, total g NA NA
14534 Alcoholic beverage, liqueur, coffee, 63 proof 34.8 1.0 fl oz 204 Total lipid (fat) g 0.10 0.3
14534 Alcoholic beverage, liqueur, coffee, 63 proof 34.8 1.0 fl oz 205 Carbohydrate, by difference g 11.21 32.2
14015 Alcoholic beverage, pina colada, canned 32.6 1.0 fl oz 208 Energy kcal 77.00 237.0
14015 Alcoholic beverage, pina colada, canned 32.6 1.0 fl oz 269 Sugars, total g NA NA
14015 Alcoholic beverage, pina colada, canned 32.6 1.0 fl oz 204 Total lipid (fat) g 2.48 7.6
14015 Alcoholic beverage, pina colada, canned 32.6 1.0 fl oz 205 Carbohydrate, by difference g 9.00 27.6
14019 Alcoholic beverage, tequila sunrise, canned 31.1 1.0 fl oz 208 Energy kcal 34.00 110.0
14019 Alcoholic beverage, tequila sunrise, canned 31.1 1.0 fl oz 269 Sugars, total g NA NA
14019 Alcoholic beverage, tequila sunrise, canned 31.1 1.0 fl oz 204 Total lipid (fat) g 0.03 0.1
14019 Alcoholic beverage, tequila sunrise, canned 31.1 1.0 fl oz 205 Carbohydrate, by difference g 3.51 11.3


Prep Time: 20mins

Great, we’ve successfully unnested. As I mentioned before, we’ll use our nice ABBREV.xlsx rather than using data pulled from the API. So:

abbrev_raw <- readxl::read_excel(here("source", "food-progress", "data", "raw", "ABBREV.xlsx")) %>% as_tibble()
## Warning in read_fun(path = path, sheet = sheet, limits = limits, shim =
## shim, : partial argument match of 'sheet' to 'sheet_i'
abbrev_raw %>% sample_n(20) %>% kable(format = "html")
NDB_No Shrt_Desc Water_(g) Energ_Kcal Protein_(g) Lipid_Tot_(g) Ash_(g) Carbohydrt_(g) Fiber_TD_(g) Sugar_Tot_(g) Calcium_(mg) Iron_(mg) Magnesium_(mg) Phosphorus_(mg) Potassium_(mg) Sodium_(mg) Zinc_(mg) Copper_mg) Manganese_(mg) Selenium_(µg) Vit_C_(mg) Thiamin_(mg) Riboflavin_(mg) Niacin_(mg) Panto_Acid_mg) Vit_B6_(mg) Folate_Tot_(µg) Folic_Acid_(µg) Food_Folate_(µg) Folate_DFE_(µg) Choline_Tot_ (mg) Vit_B12_(µg) Vit_A_IU Vit_A_RAE Retinol_(µg) Alpha_Carot_(µg) Beta_Carot_(µg) Beta_Crypt_(µg) Lycopene_(µg) Lut+Zea_ (µg) Vit_E_(mg) Vit_D_µg Vit_D_IU Vit_K_(µg) FA_Sat_(g) FA_Mono_(g) FA_Poly_(g) Cholestrl_(mg) GmWt_1 GmWt_Desc1 GmWt_2 GmWt_Desc2 Refuse_Pct
05628 EMU,INSIDE DRUM,RAW 74.73 108 22.22 1.49 1.15 0.00 0.0 0.00 4 5.23 26 229 318 102 4.33 0.205 0.028 31.4 0.0 0.420 0.446 7.304 2.674 0.626 12 0 12 12 NA 2.26 17 5 5 0 0 0 0 0 0.22 NA NA NA 0.386 0.532 0.256 67 85.00 3 oz 572.0 1 inside drum 0
11396 POTATOES,O’BRIEN,FRZ,UNPREP 79.97 76 1.83 0.14 0.60 17.47 1.9 NA 13 1.03 18 49 249 33 0.29 0.127 0.119 1.2 11.3 0.054 0.045 1.129 0.428 0.209 8 0 8 8 NA 0.00 148 7 0 NA NA NA NA NA NA 0.0 0 NA 0.032 0.006 0.061 NA NA NA NA NA 0
08067 CEREALS RTE,KELLOGG,KELLOGG’S SPL K 3.00 377 17.79 1.79 4.00 73.40 1.4 12.69 23 28.00 12 48 53 667 0.69 0.179 NA 54.9 68.0 1.690 1.910 22.600 NA 6.440 1290 1271 19 2180 11.0 19.40 1667 500 500 0 0 0 0 0 15.30 3.3 134 0.1 0.400 0.300 0.400 0 31.00 1 cup, (1 NLEA serving) NA NA 0
01013 CHEESE,COTTAGE,CRMD,W/FRUIT 79.64 97 10.69 3.85 1.20 4.61 0.2 2.38 53 0.16 7 113 90 344 0.33 0.040 0.003 7.7 1.4 0.033 0.142 0.150 0.181 0.068 11 0 11 11 17.5 0.53 146 38 37 0 14 0 0 0 0.04 0.0 0 0.4 2.311 1.036 0.124 13 113.00 4 oz 226.0 1 cup, (not packed) 0
03167 BABYFOOD,APPLE-BANANA JUC 87.10 51 0.20 0.10 0.26 12.30 0.2 11.00 7 0.20 6 8 123 4 0.04 0.020 0.080 0.3 27.9 0.010 0.010 0.140 0.125 0.060 1 0 1 1 2.3 0.00 9 0 0 3 4 0 0 16 0.02 0.0 0 0.0 0.018 0.004 0.034 0 31.20 1 fl oz 131.0 1 bottle, Earth’s Best (4.2 fl oz) 0
28378 PEPPERIDGE FARM,CINN SWIRL BREAD 31.00 300 0.01 5.00 1.40 52.90 3.2 14.60 75 3.20 NA NA NA 386 NA NA NA NA 1.1 0.400 NA 2.900 NA NA NA NA NA NA NA NA 100 NA NA NA NA NA NA NA NA NA NA NA 1.100 1.100 3.200 1 28.00 1 serving NA NA 0
11783 EGGPLANT,CKD,BLD,DRND,W/SALT 89.67 33 0.83 0.23 1.13 8.14 2.5 3.20 6 0.25 11 15 123 239 0.12 0.059 0.113 0.1 1.3 0.076 0.020 0.600 0.075 0.086 14 0 14 14 9.4 0.00 37 2 0 0 22 0 0 0 0.41 0.0 0 2.9 0.044 0.020 0.093 0 99.00 1 cup, (1" cubes) NA NA 0
13955 BEEF,BTTM SIRLOIN,TRI-TIP RST,LN & FAT,0" FAT,CHOIC,CKD,RSTD 61.82 221 25.66 12.36 1.03 0.00 0.0 0.00 17 1.70 20 189 308 50 4.52 0.083 0.009 27.3 0.0 0.064 0.113 6.959 0.505 0.511 8 0 8 8 97.7 1.69 0 0 0 0 0 0 0 0 0.41 NA NA 1.4 4.546 6.121 0.406 85 85.00 3 oz 591.0 1 roast, (yield from 714 g raw meat) 2
05146 GOOSE,DOMESTICATED,MEAT&SKN,RAW 49.66 371 15.86 33.62 0.87 0.00 0.0 NA 12 2.50 18 234 308 73 1.72 0.270 0.020 14.4 4.2 0.085 0.245 3.608 1.294 0.390 4 0 4 4 NA 0.34 55 17 17 NA NA NA NA NA NA NA NA NA 9.780 17.770 3.760 80 85.00 3 oz 320.0 1 unit, (yield from 1 lb ready-to-cook goose) 19
06082 CAMPBELL’S RED & WHITE,CHICK NOODLEO’S SOUP,COND 83.00 71 2.38 1.98 0.73 11.90 0.8 1.59 NA 0.57 NA NA 429 381 NA NA NA NA 0.0 NA NA NA NA NA NA NA NA NA NA NA 397 NA NA NA NA NA NA NA NA NA NA NA 0.794 0.794 0.397 16 126.00 1 serving, 1/2 cup NA NA 0
06736 SOUP,CRM OF CHICK,CND,COND,SINGLE BRAND 81.40 99 2.40 6.50 2.00 7.70 NA NA NA NA NA NA NA 788 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 0 NA NA NA NA NA NA NA NA NA NA NA 1.610 1.640 2.050 7 126.00 1 serving 305.0 1 package, yields 0
18995 KELLOGG’S,EGGO,BISCUIT SCRAMBLERS,BACON,EGG & CHS 42.90 258 8.80 7.90 NA 38.30 2.1 4.70 124 2.70 14 215 225 610 0.50 NA NA NA NA 0.300 0.260 2.400 NA 0.020 75 NA NA NA NA 0.10 NA NA NA NA NA NA NA NA 0.00 0.0 0 NA 4.100 1.500 1.100 27 105.00 1 bscuit NA NA 0
09247 PEACHES,DRIED,SULFURED,STWD,WO/ SUGAR 78.10 77 1.16 0.25 0.80 19.69 2.7 16.99 9 1.31 13 38 320 2 0.18 0.117 0.098 0.2 3.7 0.005 0.021 1.519 0.181 0.038 0 0 0 0 4.1 0.00 197 10 0 0 98 40 0 180 0.06 0.0 0 5.0 0.026 0.089 0.118 0 258.00 1 cup NA NA 0
14066 BEVERAGES,PROT PDR WHEY BSD 3.44 352 78.13 1.56 10.55 6.25 3.1 0.00 469 1.13 195 1321 500 156 6.18 0.049 NA 26.7 0.0 0.609 2.017 1.136 5.516 0.607 33 0 33 33 224.0 2.45 0 0 0 0 0 0 0 0 0.00 0.0 0 0.0 0.781 0.158 0.299 16 32.00 .33 cup NA NA 0
23364 BEEF,RND,EYE OF RND STEAK,BNLESS,LN,0" FAT,CHOIC,RAW 73.18 124 23.35 3.38 1.10 0.00 0.0 0.00 13 1.47 12 221 324 52 3.43 0.049 0.001 22.8 0.0 0.063 0.183 6.810 0.346 0.648 4 0 4 4 64.7 1.68 6 2 2 0 0 0 0 0 0.25 0.0 1 1.5 1.137 1.353 0.248 58 85.00 3 oz 133.0 1 steak 2
10120 PORK,FRSH,LOIN,BLADE (CHOPS),BONE-IN,LN,CKD,PAN-FRIED 61.13 222 26.38 12.14 1.28 0.00 0.0 0.00 46 0.88 21 237 335 88 3.03 0.105 0.012 38.7 0.0 0.506 0.353 8.628 1.212 0.501 0 0 0 0 85.0 0.72 10 3 3 0 0 0 0 0 0.22 0.6 23 0.0 2.557 5.744 1.079 82 85.00 3 oz 215.0 1 chop 33
25018 FORM BAR,MARS SNACKFOOD US,COCOAVIA,CHOC BLUEBERRY 20.10 325 6.21 9.27 5.00 57.87 4.6 33.40 1207 1.88 NA NA NA 260 NA NA NA NA 42.4 NA NA NA NA 1.364 273 273 0 464 NA 4.09 32 NA NA NA NA NA NA NA NA NA NA NA 3.870 NA NA 2 22.00 1 bar NA NA 0
19922 CANDIES,COCNT BAR,NOT CHOC COVERED 13.26 481 2.13 27.65 1.10 55.87 6.4 36.16 43 0.77 27 93 294 128 1.02 0.360 1.238 8.6 2.7 0.069 0.021 0.445 0.247 0.045 22 0 22 22 10.0 0.00 0 0 0 0 0 0 0 0 0.20 0.0 0 0.1 25.540 0.328 0.084 0 NA NA NA NA 0
14087 BEVERAGES,V8 SPLASH SMOOTHIES,STRAWBERRY BANANA 90.28 37 1.22 0.00 0.33 8.16 0.0 7.35 41 0.15 NA NA 24 29 NA NA NA NA 24.5 NA NA 0.816 NA 0.082 NA NA NA NA NA 0.24 408 NA NA NA NA NA NA NA NA NA NA NA 0.000 NA NA 0 245.00 1 serving, 8 oz NA NA 0
17271 VEAL,BREAST,WHL,BNLESS,LN&FAT,RAW 67.67 208 17.47 14.75 0.90 0.00 NA NA 7 0.53 18 172 286 71 2.33 0.094 0.010 6.6 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 5.896 7.164 0.952 71 28.35 1 oz 453.6 1 lb 0

How much data are we working with here?

dim(abbrev_raw)
## [1] 8790   53

You can read in depth the prep I did on this file in /scripts/prep. Mainly this involved a bit of cleaning like stripping out parentheses from column names, e.g., Vit_C_(mg) becomes Vit_C_mg.

In there you’ll also find a dataframe called all_nut_and_mr_df where I define the nutritional constraints on menus. If a nutrient is among the “must restricts,” that is, it’s one of Lipid_Tot_g, Sodium_mg, Cholestrl_mg, FA_Sat_g, then its corresponding value is a daily upper bound. Otherwise, the nutrient is a “positive nutrient” and its vlaue is a lower bound. For example, you’re supposed to have at least 18mg of Iron and no more than 2400mg of Sodium per day. (As someone who puts salt on everything indiscriminately I’d be shocked if I’ve ever been under that threshold.)

all_nut_and_mr_df %>% kable(format = "html")
nutrient value
Lipid_Tot_g 65
Sodium_mg 2400
Cholestrl_mg 300
FA_Sat_g 20
Protein_g 56
Calcium_mg 1000
Iron_mg 18
Magnesium_mg 400
Phosphorus_mg 1000
Potassium_mg 3500
Zinc_mg 15
Copper_mg 2
Manganese_mg 2
Selenium_µg 70
Vit_C_mg 60
Thiamin_mg 2
Riboflavin_mg 2
Niacin_mg 20
Panto_Acid_mg 10
Vit_B6_mg 2

In /scripts/prep we also create a z-scored version of abbrev with:

scaled <- abbrev %>% 
  drop_na_(all_nut_and_mr_df$nutrient) %>% filter(!(is.na(Energ_Kcal)) & !(is.na(GmWt_1))) %>% 
  mutate_at(
    vars(nutrient_names, "Energ_Kcal"), dobtools::z_score   # <-- equivalent to scale(), but simpler
  )

I usually shunt Shrt_Desc all the way off screen to the right but here I’ll put it next to its shorter sibling, shorter_desc so you can see how the truncation of name looks. Here’s a random sample of 20 foods.

scaled %>% sample_n(20) %>% 
  select(shorter_desc, Shrt_Desc, everything()) %>% kable(format = "html")
shorter_desc Shrt_Desc solution_amounts GmWt_1 serving_gmwt cost Lipid_Tot_g Sodium_mg Cholestrl_mg FA_Sat_g Protein_g Calcium_mg Iron_mg Magnesium_mg Phosphorus_mg Potassium_mg Zinc_mg Copper_mg Manganese_mg Selenium_µg Vit_C_mg Thiamin_mg Riboflavin_mg Niacin_mg Panto_Acid_mg Vit_B6_mg Energ_Kcal NDB_No score scaled_score
CHICKPEAS CHICKPEAS,MATURE SEEDS,CKD,BLD,W/SALT 1 164.00 164.00 2.18 -0.5341459 -0.0530327 -0.3613150 -0.5113433 -0.4041843 -0.0884245 0.1539957 0.2707765 -0.0245231 -0.0121333 -0.2023897 0.2270948 0.0464732 -0.3987753 -0.1079554 -0.1514571 -0.3818365 -0.6659618 -0.2688071 -0.3197053 -0.3182903 16357 -2831.270 0.6716992
BEEF BEEF,TENDERLOIN,STEAK,LN,1/8" FAT,SEL,RAW 1 28.35 28.35 4.77 -0.2957044 -0.2199216 0.0808004 -0.2032300 0.7989858 -0.2166902 -0.1467632 -0.2071661 0.1586982 0.1435610 0.4619705 -0.1910241 -0.0808814 0.4292502 -0.1318713 -0.2384740 -0.2623026 0.5859306 -0.0067417 0.8196850 -0.4231005 23583 -3218.935 -0.0694125
FISH OIL FISH OIL,HERRING 1 13.60 13.60 8.35 6.4199240 -0.2687455 4.9302538 2.8585061 -1.2117667 -0.3212029 -0.5197976 -0.6468732 -0.7752833 -0.7312928 -0.6189762 -0.3061583 -0.0822562 -0.5130922 -0.1318713 -0.3917893 -0.5187572 -0.7779127 -0.4758531 -0.6476044 4.5160821 04590 -3494.671 -0.5965461
PORK PORK,FRSH,LOIN,CNTR RIB (CHOPS OR ROASTS),BONE-IN,LN,RAW 1 85.00 85.00 3.56 -0.3763747 -0.2154831 0.0255360 -0.2952472 0.7743755 -0.2071890 -0.3775782 -0.1689306 0.1899799 0.1559177 -0.0825870 -0.2031435 -0.0811313 0.6702427 -0.1318713 0.6109762 -0.1145152 0.6448858 0.0490015 1.0862505 -0.5017082 10048 -2886.827 0.5654894
CASHEW NUTS CASHEW NUTS,OIL RSTD,W/SALT 1 129.00 129.00 8.03 2.6912404 0.0046682 -0.3613150 0.8046309 0.3231867 -0.1169280 0.8907386 4.5722596 1.5976553 0.8305931 0.8377152 2.7888307 0.1262104 0.1141062 -0.1263523 0.3602848 -0.0449682 -0.4084321 0.1612117 0.1143482 2.4133266 12586 -1864.426 2.5200456
BEEF BEEF,BRISKET,FLAT HALF,BNLESS,LN,0" FAT,SEL,RAW 1 85.00 85.00 8.70 -0.4234919 -0.1932904 0.1153407 -0.3011786 0.7698180 -0.2594454 -0.0348529 -0.1880484 0.1989175 0.1410897 0.8241013 -0.2061733 -0.0820062 0.3242022 -0.1318713 -0.2260430 -0.1601554 0.5427252 0.0815786 0.8385569 -0.5803159 13597 -2938.445 0.4668098
LAMB LAMB,NZ,IMP,FRZ,FORESHANK,LN & FAT,1/8" FAT,CKD,BRSD 1 85.00 85.00 1.69 0.4110536 -0.2270232 0.3433064 0.6991478 1.2465286 -0.2546948 -0.0371844 -0.3601077 0.0067586 -0.4396748 0.6879619 -0.1516361 -0.0792566 -0.3493409 -0.1318713 -0.2467613 0.1984464 0.5139926 -0.1790388 -0.4588855 0.2974699 17257 -3207.760 -0.0480494
PEPPER PEPPER,BLACK 1 2.30 2.30 7.93 -0.4863148 -0.2509913 -0.3613150 -0.3313166 -0.2647260 1.7833039 1.7440547 2.6222540 -0.0692112 2.5531160 -0.2949644 1.7086902 1.5116129 -0.3616995 -0.1318713 -0.1680318 -0.1275553 -0.5346429 0.5369352 0.0388606 0.2516154 02030 -3325.246 -0.2726501
PORK PORK,FRSH,LOIN,WHL,LN,CKD,BRLD 1 85.00 85.00 4.95 -0.0194262 -0.2119322 0.1844212 0.0290574 1.3923674 -0.2404431 -0.3076343 -0.0924598 0.3553259 0.3511535 0.0562752 -0.1925390 -0.0811313 0.9761178 -0.1189935 1.5205094 0.2158331 0.3379785 0.0518972 0.5130168 -0.0169608 10026 -2805.155 0.7216232
SCALLOP SCALLOP,MXD SP,CKD,BREADED&FRIED 1 31.00 31.00 1.55 0.0619580 0.1431504 0.0117199 -0.1266024 0.4353003 -0.1216786 -0.3286175 0.4810712 0.2793561 0.0916629 -0.3303607 -0.1879943 -0.0647590 0.3180229 -0.0895586 -0.3047725 -0.2796894 -0.4575968 -0.3310657 -0.3173463 0.0223430 15173 -3315.176 -0.2533984
MILK MILK,RED FAT,FLUID,2% MILKFAT,W/ ADDED NFMS, VIT A & VIT D 1 245.00 245.00 4.31 -0.5819770 -0.2225847 -0.3060506 -0.3628974 -0.8945673 0.2868713 -0.5081402 -0.3792254 -0.3284022 -0.3309359 -0.5100647 -0.2940389 -0.0820062 -0.4420303 -0.1134745 -0.3089162 -0.1427687 -0.7587576 -0.2326102 -0.5414500 -1.0585126 01080 -2519.418 1.2678762
BEEF BEEF,NZ,IMP,OYSTER BLADE,LN & FAT,RAW 1 113.00 113.00 6.52 0.0169825 -0.2181462 0.0255360 0.0571114 0.7269779 -0.3022006 -0.0791507 -0.3027546 -0.0915552 -0.0195473 0.5953871 -0.2182927 -0.0812563 -0.4512993 -0.1318713 -0.2736951 -0.2644760 -0.2898833 0.1257388 -0.2890385 -0.2265813 23440 -2957.018 0.4313035
BEVERAGE BEVERAGE,CHOCOLATE-FLAVOR BEV MIX FOR MILK,PDR,W/ ADDED NUTR 1 22.00 22.00 5.06 -0.5569906 -0.1480173 -0.3613150 -0.1900847 -0.7970376 1.8403109 -0.5197976 0.3663650 -0.3909656 -0.0393180 1.2379650 1.0709073 0.0061047 -0.4543889 0.3703628 -0.3731429 -0.3970500 -0.7355587 -0.4758531 1.4967141 1.2276608 14557 -3203.100 -0.0391409
SALAD DRSNG SALAD DRSNG,SWT&SOUR 1 16.00 16.00 5.29 -0.7190452 -0.0841025 -0.3613150 -0.5544664 -1.2026517 -0.3022006 -0.5104717 -0.5895201 -0.7618769 -0.6497386 -0.6135306 -0.2910091 -0.0747574 -0.4636579 0.0171432 -0.3710710 -0.5187572 -0.7651427 -0.4563068 -0.6240145 -1.2943357 43019 -3398.794 -0.4132544
PINEAPPLE PINEAPPLE,CND,JUC PK,SOL&LIQUIDS 1 249.00 249.00 8.48 -0.7133341 -0.2678577 -0.3613150 -0.5535045 -1.1734840 -0.2546948 -0.4545165 -0.3792254 -0.7484704 -0.4297895 -0.5917483 -0.1758749 0.0578463 -0.5007336 0.0428988 -0.1949655 -0.4774637 -0.7174678 -0.4034594 -0.4730394 -0.9995569 09268 -2957.983 0.4294584
BEEF BEEF,CHUCK FOR STEW,LN & FAT,SEL,CKD,BRSD 1 85.00 85.00 8.85 -0.2664346 -0.2083814 0.3433064 -0.1514503 1.7314426 -0.2499443 0.1423384 -0.2071661 0.2793561 0.0595355 1.6872250 -0.1304272 -0.0802565 0.4817742 -0.1318713 -0.2260430 0.1332461 0.2543345 0.0309030 0.5837864 -0.1741762 23091 -2951.099 0.4426172
MACARONI & CHS MACARONI & CHS,CND,MICROWAVABLE 1 213.00 213.00 6.12 -0.2914210 0.0286363 -0.2231539 0.0330651 -0.6666942 -0.0504199 -0.3076343 -0.3983431 -0.3418086 -0.5533564 -0.4692228 0.0877218 -0.0547606 -0.1577828 -0.1318713 -0.2343303 -0.1145152 -0.5552879 -0.3817413 -0.5603219 -0.5148095 22919 -3597.139 -0.7924361
OIL OIL,INDUSTRIAL,PALM KERNEL (HYDROGENATED),CONFECTION FAT 1 13.60 13.60 4.93 6.4199240 -0.2634192 -0.3613150 14.4666200 -1.2117667 -0.3164524 -0.4848256 -0.6468732 -0.7752833 -0.7288214 -0.5971939 -0.3061583 -0.0822562 -0.5130922 -0.1318713 -0.3917893 -0.5187572 -0.7779127 -0.4758531 -0.6476044 4.3981706 04657 -3400.856 -0.4171963
LAMB LAMB,DOM,COMP OF RTL CUTS,LN,1/4"FAT,CHOIC,RAW 1 28.35 28.35 3.55 -0.3442493 -0.2101568 0.0877085 -0.2530860 0.6376516 -0.2736972 -0.1071283 -0.1498129 0.0693220 -0.0393180 0.4864756 -0.1243675 -0.0792566 0.2098852 -0.1318713 -0.1224515 -0.0188880 0.4990942 0.0309030 -0.2701666 -0.5148095 17003 -3253.866 -0.1361904
YOGURT YOGURT,FRUIT,LOFAT,9 GRAMS PROT PER 8 OZ,FORT W/ VITAMIN D 1 170.00 170.00 5.52 -0.6369471 -0.2216970 -0.3267747 -0.4355173 -0.8489927 0.3343771 -0.5058088 -0.3983431 -0.2881829 -0.2938659 -0.4365494 -0.1864793 -0.0742574 -0.4265821 -0.1208332 -0.3213471 -0.1666755 -0.7596090 -0.1529771 -0.5603219 -0.7440819 01216 -2717.586 0.8890326

Then we do a few mutates to abbrev using the function below. This is a function we can use on any menu dataframe, not just abbrev, which is why it’s called do_menu_mutates(). Turns out that the short descriptions of foods in the Shrt_Desc column actually aren’t so short so we’ll create a shorter_desc column by taking only the values in Shrt_Desc up to the first comma. That turns “BUTTER,WHIPPED,W/ SALT” into just “BUTTER”.

Since we’ll need a cost associated with each row in order to optimize something, for now each item gets a random cost between $1 and $10.

What we’ll do when we eventually “solve” these menus is change the amount we have of each item, i.e. its GmWt_1. We’ll vary that by multiplying it by some solution_amount. In order to keep a record of what the gram weight of a single serving of a food is, we’ll save that in serving_gmwt. Since we know that all foods in abbrev are exactly one serving, for now GmWt_1 and serving_gmwt are the same thing, and solution_amounts is 1.

Finally, we rearrange columns a bit.

cols_to_keep <- c(nutrient_names, "Shrt_Desc", "GmWt_1", "NDB_No")

do_menu_mutates <- function(menu, to_keep = cols_to_keep) {

  quo_to_keep <- quo(to_keep)
  
  menu <- menu %>% 
    mutate(
      shorter_desc = map_chr(Shrt_Desc, grab_first_word, splitter = ","), # Take only the fist word
      cost = runif(nrow(.), min = 1, max = 10) %>% round(digits = 2) # Add a cost column
    ) 
  
  if (!("serving_gmwt" %in% names(menu))) {
    menu <- menu %>% mutate(
      serving_gmwt = GmWt_1   # Single serving gram weight
    )
  }
  
  if (!("solution_amounts" %in% names(menu))) {
    menu <- menu %>% mutate(
      solution_amounts = 1   # Single serving gram weight
    )
  }
  
  menu <- menu %>%
    select(shorter_desc, solution_amounts, GmWt_1, serving_gmwt, cost, !!quo_to_keep,  Shrt_Desc, NDB_No)
  
  return(menu)
}

We’ll do these mutates and score each item (see /scripts/score/rank_foods.R for add_ranked_foods(); also more on scoring in the Scoring section below).

abbrev <- abbrev %>% do_menu_mutates() %>% add_ranked_foods() 
## score column doesn't exist; creating it
## scaled_score doesn't exist; creating it

And now we’ve got our main bucket of foods to pull from, each with a single portion size for now.

abbrev[1:20, ] %>% kable(format = "html")
shorter_desc solution_amounts GmWt_1 serving_gmwt cost Lipid_Tot_g Sodium_mg Cholestrl_mg FA_Sat_g Protein_g Calcium_mg Iron_mg Magnesium_mg Phosphorus_mg Potassium_mg Zinc_mg Copper_mg Manganese_mg Selenium_µg Vit_C_mg Thiamin_mg Riboflavin_mg Niacin_mg Panto_Acid_mg Vit_B6_mg Energ_Kcal Shrt_Desc NDB_No score scaled_score
BUTTER 1 5.00 5.00 5.42 81.11 643 215 51.368 0.85 24 0.02 2 24 24 0.09 0.000 0.000 1.0 0.0 0.005 0.034 0.042 0.110 0.003 717 BUTTER,WITH SALT 01001 -3419.716 -0.4532518
BUTTER 1 3.80 3.80 5.13 78.30 583 225 45.390 0.49 23 0.05 1 24 41 0.05 0.010 0.001 0.0 0.0 0.007 0.064 0.022 0.097 0.008 718 BUTTER,WHIPPED,W/ SALT 01002 -3405.992 -0.4270146
BUTTER OIL 1 12.80 12.80 8.28 99.48 2 256 61.924 0.28 4 0.00 0 3 5 0.01 0.001 0.000 0.0 0.0 0.001 0.005 0.003 0.010 0.001 876 BUTTER OIL,ANHYDROUS 01003 -3426.108 -0.4654711
CHEESE 1 28.35 28.35 7.78 28.74 1146 75 18.669 21.40 528 0.31 23 387 256 2.66 0.040 0.009 14.5 0.0 0.029 0.382 1.016 1.729 0.166 353 CHEESE,BLUE 01004 -3383.120 -0.3832890
CHEESE 1 132.00 132.00 6.67 29.68 560 94 18.764 23.24 674 0.43 24 451 136 2.60 0.024 0.012 14.5 0.0 0.014 0.351 0.118 0.288 0.065 371 CHEESE,BRICK 01005 -2550.059 1.2092995
CHEESE 1 28.35 28.35 9.29 27.68 629 100 17.410 20.75 184 0.50 20 188 152 2.38 0.019 0.034 14.5 0.0 0.070 0.520 0.380 0.690 0.235 334 CHEESE,BRIE 01006 -3427.868 -0.4688367
CHEESE 1 28.35 28.35 3.63 24.26 842 72 15.259 19.80 388 0.33 20 347 187 2.38 0.021 0.038 14.5 0.0 0.028 0.488 0.630 1.364 0.227 300 CHEESE,CAMEMBERT 01007 -3365.981 -0.3505239
CHEESE 1 28.35 28.35 5.27 29.20 690 93 18.584 25.18 673 0.64 22 490 93 2.94 0.024 0.021 14.5 0.0 0.031 0.450 0.180 0.190 0.074 376 CHEESE,CARAWAY 01008 -3234.675 -0.0995030
CHEESE 1 132.00 132.00 3.19 33.31 653 99 18.867 22.87 710 0.14 27 455 76 3.64 0.030 0.027 28.5 0.0 0.029 0.428 0.059 0.410 0.066 404 CHEESE,CHEDDAR 01009 -2687.571 0.9464129
CHEESE 1 28.35 28.35 7.47 30.60 700 103 19.475 23.37 643 0.21 21 464 95 2.79 0.042 0.012 14.5 0.0 0.046 0.293 0.080 0.413 0.074 387 CHEESE,CHESHIRE 01010 -3257.267 -0.1426935
CHEESE 1 132.00 132.00 7.37 32.11 604 95 20.218 23.76 685 0.76 26 457 127 3.07 0.042 0.012 14.5 0.0 0.015 0.375 0.093 0.210 0.079 394 CHEESE,COLBY 01011 -2599.704 1.1143912
CHEESE 1 113.00 113.00 7.83 4.30 364 17 1.718 11.12 83 0.07 8 159 104 0.40 0.029 0.002 9.7 0.0 0.027 0.163 0.099 0.557 0.046 98 CHEESE,COTTAGE,CRMD,LRG OR SML CURD 01012 -3386.210 -0.3891963
CHEESE 1 113.00 113.00 7.29 3.85 344 13 2.311 10.69 53 0.16 7 113 90 0.33 0.040 0.003 7.7 1.4 0.033 0.142 0.150 0.181 0.068 97 CHEESE,COTTAGE,CRMD,W/FRUIT 01013 -3463.568 -0.5370853
CHEESE 1 145.00 145.00 9.32 0.29 372 7 0.169 10.34 86 0.15 11 190 137 0.47 0.030 0.022 9.4 0.0 0.023 0.226 0.144 0.446 0.016 72 CHEESE,COTTAGE,NONFAT,UNCRMD,DRY,LRG OR SML CURD 01014 -3278.578 -0.1834343
CHEESE 1 113.00 113.00 1.14 2.27 308 12 1.235 10.45 111 0.13 9 150 125 0.51 0.033 0.015 11.9 0.0 0.020 0.251 0.103 0.524 0.057 81 CHEESE,COTTAGE,LOWFAT,2% MILKFAT 01015 -3266.099 -0.1595762
CHEESE 1 113.00 113.00 6.99 1.02 406 4 0.645 12.39 61 0.14 5 134 86 0.38 0.028 0.003 9.0 0.0 0.021 0.165 0.128 0.215 0.068 72 CHEESE,COTTAGE,LOWFAT,1% MILKFAT 01016 -3490.534 -0.5886355
CHEESE 1 14.50 14.50 7.67 34.44 314 101 20.213 6.15 97 0.11 9 107 132 0.50 0.018 0.011 8.6 0.0 0.023 0.230 0.091 0.517 0.056 350 CHEESE,CREAM 01017 -3389.710 -0.3958887
CHEESE 1 28.35 28.35 2.59 27.80 812 89 17.572 24.99 731 0.44 30 536 188 3.75 0.036 0.011 14.5 0.0 0.037 0.389 0.082 0.281 0.076 357 CHEESE,EDAM 01018 -3208.657 -0.0497637
CHEESE 1 150.00 150.00 1.91 21.28 917 89 14.946 14.21 493 0.65 19 337 62 2.88 0.032 0.028 15.0 0.0 0.154 0.844 0.991 0.967 0.424 264 CHEESE,FETA 01019 -3516.569 -0.6384083
CHEESE 1 132.00 132.00 1.22 31.14 800 116 19.196 25.60 550 0.23 14 346 64 3.50 0.025 0.014 14.5 0.0 0.021 0.204 0.150 0.429 0.083 389 CHEESE,FONTINA 01020 -3304.806 -0.2335737

Per 100g vs. Raw

Note how our column titles have aways end with _g or _mg. That’s because this column is giving us the value of each nutrient, per 100g of this food. The value we’ve got in that column isn’t the raw value. Our contraints, though, are in raw terms. We’ll need a way to know whether we’ve gotten our 1000mg of Calcium from the foods in our menu, each of which list how much Calcium they provide per 100g of that food.

In order to get to the raw value of a nutrient, for each food in our menu we’ll multiply the 100g value of that nutrient by the weight of the food in grams, or its GmWt_1:

\(TotalNutrientVal = \sum_{i=1}^{k} Per100gVal_{i} * GmWt_{i}\)

where k the total number of foods in our menu.

Two helper functions get_per_g_vals() and get_raw_vals() in /scripts/solve allow us to go back and forth between raw and per 100g values. We’ll try to keep everything in per 100g whenever possible, as that’s the format our raw data is in. Our main solving function does accept both formats, however.

abbrev %>% sample_n(10) %>% get_raw_vals() %>% kable(format = "html")
shorter_desc GmWt_1 serving_gmwt cost Lipid_Tot_g Sodium_mg Cholestrl_mg FA_Sat_g Protein_g Calcium_mg Iron_mg Magnesium_mg Phosphorus_mg Potassium_mg Zinc_mg Copper_mg Manganese_mg Selenium_µg Vit_C_mg Thiamin_mg Riboflavin_mg Niacin_mg Panto_Acid_mg Vit_B6_mg Energ_Kcal solution_amounts Shrt_Desc NDB_No score scaled_score
COLLARDS 36.0 36.0 3.00 0.2196 6.12 0.00 0.01980 1.0872 83.520 0.1692 9.72 9.00 76.680 0.0756 0.016560 0.23688 0.468 12.708 0.019440 0.046800 0.26712 0.09612 0.059400 11.520 1 COLLARDS,RAW 11161 -3186.189 -0.0068108
WHEAT GERM 115.0 115.0 6.07 11.1780 13.80 0.00 1.91475 26.6225 44.850 7.1990 274.85 968.30 1025.800 14.1335 0.915400 15.29615 91.080 0.000 2.164300 0.573850 7.83495 2.59555 1.495000 414.000 1 WHEAT GERM,CRUDE 20078 -951.723 4.2648873
SWEETENERS 0.5 0.5 4.83 0.0000 2.86 NA NA 0.0103 4.395 0.0008 0.03 0.04 0.195 0.0002 0.000035 0.00011 NA NA 0.000075 0.000075 NA 0.00040 0.000075 1.735 1 SWEETENERS,SUGAR SUB,GRANULATED,BROWN 19909 -3372.188 -0.3623906
RESTAURANT 604.0 604.0 2.86 42.1592 2428.08 157.04 8.16608 58.9504 120.800 4.5904 144.96 567.76 1316.720 4.4696 0.440920 1.54624 48.924 42.884 0.193280 0.332200 16.65228 3.02000 1.467720 779.160 1 RESTAURANT,CHINESE,KUNG PAO CHICK 36619 -3678.685 -0.9483298
SOUP 126.0 126.0 4.39 1.9656 812.70 5.04 0.46620 2.3184 51.660 0.3150 12.60 52.92 42.840 0.2268 0.120960 0.37800 5.166 0.000 0.017640 0.025200 1.15668 0.17640 0.025200 85.680 1 SOUP,CHICK W/ RICE,CND,COND 06023 -4024.226 -1.6089111
PUDDINGS 99.0 99.0 9.71 1.8810 1753.29 0.00 0.81675 2.2770 11.880 1.2771 44.55 71.28 233.640 0.6138 0.350460 0.36333 2.475 0.000 0.009900 0.054450 0.23166 0.02475 0.011880 374.220 1 PUDDINGS,CHOC,DRY MIX,INST 19184 -4760.948 -3.0173271
LAMB 85.0 85.0 1.12 18.7340 44.20 107.10 6.23985 14.8835 5.100 1.4790 12.75 121.55 112.200 1.7595 0.169150 0.01700 7.735 0.000 0.030600 0.289850 1.93120 0.49130 0.065450 231.200 1 LAMB,NZ,IMP,TONGUE - SWISS CUT,CKD,SOAKED & SIMMRD 17378 -3269.822 -0.1666950
VEAL 85.0 85.0 5.85 5.3805 56.95 113.90 2.15050 30.7360 6.800 1.1220 24.65 211.65 325.550 3.3660 0.119000 0.03315 13.090 0.000 0.051000 0.297500 8.97600 0.86700 0.306000 179.350 1 VEAL,LEG (TOP RND),LN&FAT,CKD,BRSD 17095 -2924.767 0.4929572
BEANS 111.0 111.0 6.45 0.4551 3.33 NA 0.05217 2.1978 67.710 0.8880 32.19 46.62 263.070 0.3441 0.073260 0.36630 1.110 12.210 0.081030 0.114330 0.53835 0.18648 0.069930 44.400 1 BEANS,SNAP,GRN,FRZ,ALL STYLES,MICROWAVED 11062 -2950.068 0.4445898
BEEF 85.0 85.0 8.14 9.4775 50.15 68.85 3.85390 24.2845 11.900 2.8985 16.15 225.25 311.100 3.9610 0.076500 0.00850 22.015 0.000 0.054400 0.348500 4.94105 0.31365 0.605200 189.550 1 BEEF,LOIN,TOPLOINSTK,BNLS,LIPOFF,LN FT,0" FT,ALLGRD,CKD,GRLD 13445 -2882.425 0.5739052

On to part two for building