This content was originally posted on Reddit, before I had a working website. I am recreating the post here, but I think it’s worth checking out the reddit post anyway - the comments were educational and pretty funny actually.

Recently I took a deep dive into the SVD/PCA. My goal was to understand the math with confidence, and then use it for something interesting. In my project, NumPy’s svd function does the hard work, but even still, just using it challenged my understanding in instructive ways. Between my study and the project, I feel I truly understand, mathematically, what the SVD does and why it works. Finally. Feels good.
Anyway, my project was to calculate the Eigen Grandito, which is named after the Onion article, “Taco Bell’s Five Ingredients Combined In Totally New Way”, which, in more mathematical terms, asserts that Taco Bell’s dishes are all linear combinations of the same ingredients.
And so the Eigen Grandito “recipe” is just the first principle component of the matrix of Taco Bell dishes and their ingredients. In theory, the Eign Grandito is the “most Taco Bell” of Taco Bell dishes.
Here is a link to my code and the results: link (also reproduced at the bottom of this article)
Any feedback and corrections are welcome. I would love to know if I’ve made any mistakes.
Finally, here are the results:
6.5 in flour tortilla - 1.0
10 in flour tortilla - 0.6
12 in flour tortilla - 0.3
taco shell - 0.6
taco shell bowl - 0.1
tostado shell - 0.2
mexican pizza shell - 0.1
flatbread shell - 0.2
seasoned beef scoops 2.0
chicken scoops 0.4
steak scoops 0.4
chunky beans (rs) red scoops 1.0
chunky beans (gs) green scoops 0.3
seasoned rice yellow scoops 0.4
lettuce (fngr) fingers 3.7
lettuce (oz) ounces 0.4
diced tomatoes fingers 3.1
diced onions fingers 0.2
cheddar cheese (fngr) fingers 2.2
three cheese blend (fngr) fingers 0.3
three cheese blend (oz) ounces 0.2
nacho cheese sauce pumps 0.6
pepper jack sauce z 0.2
avocado ranch z 0.2
lava sauce z 0.3
red sauce pumps 0.4
sour cream (clk) clicks 1.4
sour cream (dlp) dollops 0.3
guacamole (dlp) dollops 0.2
red strips fingers 0.2
fiesta salsa purple scoops 0.1
nacho chips - 0.2
eggs scoops 0.1
I have no idea how to actually prepare this. I guess you just grill it.
Here is the data I used: MenuIngredients.csv
And, for the sake of completeness, here are some notes I referred to when putting together the above: TacoBellPortionNotes.txt
Here is the python source code:
# References
# The Onion article on the Grandito
# https://www.theonion.com/taco-bells-five-ingredients-combined-in-totally-new-way-1819564909
# Ingredients of the Taco Bell menu
# https://www.flashcardmachine.com/taco-bellingredients.html
# Info on Taco Bell scoop and proportion sizes
# https://quizlet.com/119643026/taco-bell-portioning-tool-test-flash-cards/
# Imports
from inspect import getsourcefile # For getting this source file's directory
from os.path import abspath # For getting this source file's directory
import os
import pandas as pd
import numpy as np
# Construct path and filenames for input and output data
ThisFile = abspath(getsourcefile(lambda:0))
ThisDirectory = ThisFile.replace('EigenGrandito.py', '')
SourceCsv = ThisDirectory + 'MenuIngredients.csv'
def Main():
#-----------------------------
# Load menu data
Source_df = pd.read_csv(SourceCsv, header=0, index_col=0)
Source_df = Source_df.fillna(0) # replace NaN values with 0
UnitsList = Source_df.loc[:,'Units'].to_numpy() # save the units list, for later output
Source_df.drop('Units', axis=1, inplace=True) # remove unneeded columns
#-----------------------------
# Show A and compute the SVD
A = Source_df
print("\nA= ")
print(A.shape)
print(A)
U, E, Vt = np.linalg.svd(A,full_matrices=True)
#-----------------------------
# negate U and V, because otherwise PC1 is all negative
# and it doesn't make sense for the most dominant component to
# be made up of negative amounts of ingredients.
U = U*-1
Vt = Vt*-1
#-----------------------------
# Optional: Analyze the singular values to determine how many principle
# components would be needed to reconstruct A to a desired accuracy.
if False:
print("\nSingular Values = ")
print(np.round(E, decimals=2))
print("\nSingular Values as percentages= ")
E_percents = (E/np.sum(E))*100.0
print(np.round(E_percents, decimals=2))
iNumSingularValues = 0;
TotalPercent = 0.0
TargetPercent = 80;
while TotalPercent < TargetPercent and iNumSingularValues < len(E_percents):
TotalPercent += E_percents[iNumSingularValues]
iNumSingularValues += 1;
print("\nNum Principle Components needed to recreate {:.2f} percent of A: {:d}".format(TargetPercent, iNumSingularValues))
#-----------------------------
# Print U, E, Vt, and UEVt
print("\nU = ")
print(U.shape)
print(np.round(U, decimals=2))
print("\nE = ")
E = np.diag(E)
print(E.shape)
print(np.round(E, decimals=2))
print("\nVt = ")
print(Vt.shape)
print(np.round(Vt, decimals=2))
print("\nUEVt =")
U = U[:,0:44] # remove the last columns of U
UEVt = U @ (E @ Vt)
print(np.round(UEVt, decimals=2))
#-----------------------------
# prepare the grandito recipe
# first principle component * first singular value
Grandito = U[:,0] * E[0,0]
# Assume we want at least a 1.0 amount of the 6.5 in flour tortilla
# and scale everything accordingly.
ScalingFactor = 1.0/Grandito[0]
Grandito = Grandito * ScalingFactor
# if the ingredient amount is too low, assume it's 0
for i, val in enumerate(Grandito):
if val < 0.1:
Grandito[i] = 0
# round to the nearest 10th
Grandito = np.round(Grandito, decimals=1)
# Convert the numerical values into a string, so we
# can replace 0 values with a character, for better readibility
strGrandito = []
for i, val in enumerate(Grandito):
if Grandito[i] == 0:
strGrandito.append("-")
else:
strGrandito.append(str(Grandito[i]))
#-----------------------------
# print the Eigen Grandito recipe
print("\n\nBEEP BOOP BEEP BOOP...Your Eigen Grandito Recipe is:")
Answer_df = pd.DataFrame(index=Source_df.index.copy())
Answer_df.insert(0, "", UnitsList, allow_duplicates=True)
Answer_df.insert(1, "", strGrandito, allow_duplicates=True)
print(Answer_df)
#-----------------------------
# Optional: Export the tables to CSVs
if False:
Vt = np.round(Vt, decimals=5)
U = np.round(U, decimals=5)
Out_df = pd.DataFrame(U)
Out_df.to_csv(ThisDirectory + 'MenuIngredients_U.csv', index=False)
Out_df = pd.DataFrame(Vt)
Out_df.to_csv(ThisDirectory + 'MenuIngredients_Vt.csv', index=False)
Main()This is the output:
A=
(51, 44)
A.M. Crunchwrap ... Chicken Soft Taco
6.5 in flour tortilla 0.0 ... 1.0
8 in tortilla 0.0 ... 0.0
10 in flour tortilla 1.0 ... 0.0
12 in flour tortilla 0.0 ... 0.0
taco shell 0.0 ... 0.0
taco shell bowl 0.0 ... 0.0
red taco shell 0.0 ... 0.0
tostado shell 0.0 ... 0.0
mexican pizza shell 0.0 ... 0.0
flatbread shell 0.0 ... 0.0
seasoned beef 0.0 ... 0.0
chicken 0.0 ... 1.0
steak 0.0 ... 0.0
potato bites 0.0 ... 0.0
chunky beans (rs) 0.0 ... 0.0
chunky beans (gs) 0.0 ... 0.0
black beans 0.0 ... 0.0
seasoned rice 0.0 ... 0.0
cilantro rice 0.0 ... 0.0
lettuce (fngr) 0.0 ... 2.0
lettuce (oz) 0.0 ... 0.0
romaine lettuce 0.0 ... 0.0
diced tomatoes 0.0 ... 0.0
diced onions 0.0 ... 0.0
cheddar cheese (fngr) 0.0 ... 1.0
cheddar cheese (ps) 1.0 ... 0.0
three cheese blend (fngr) 0.0 ... 0.0
three cheese blend (oz) 0.0 ... 0.0
three cheese blend (ps) 0.0 ... 0.0
nacho cheese sauce 0.0 ... 0.0
pepper jack sauce 0.0 ... 0.0
avocado ranch 0.0 ... 0.0
lava sauce 0.0 ... 0.0
creamy jalepeno sauce 1.0 ... 0.0
creamy cilantro dressing 0.0 ... 0.0
red sauce 0.0 ... 0.0
sour cream (clk) 0.0 ... 0.0
sour cream (dlp) 0.0 ... 0.0
guacamole (dlp) 0.0 ... 0.0
guacamole (s) 0.0 ... 0.0
red strips 0.0 ... 0.0
fiesta salsa 0.0 ... 0.0
pizza sauce 0.0 ... 0.0
nacho chips 0.0 ... 0.0
jalapeno 0.0 ... 0.0
roasted corn salsa 0.0 ... 0.0
pico de gallo 0.0 ... 0.0
eggs 1.0 ... 0.0
bacon 0.5 ... 0.0
sausage crumbles 0.5 ... 0.0
hash brown 1.0 ... 0.0
[51 rows x 44 columns]
U =
(51, 51)
[[ 0.16 -0.1 -0.03 ... 0.01 0. 0.01]
[ 0. -0. -0. ... 0.11 -0.05 -0.19]
[ 0.1 0.13 -0.07 ... -0. -0. -0. ]
...
[ 0. 0. -0. ... -0.5 0.37 0.27]
[ 0.01 0.01 -0.02 ... 0.26 -0.28 0.08]
[ 0. 0. -0. ... 0. -0.02 -0.58]]
E =
(44, 44)
[[11.57 0. 0. ... 0. 0. 0. ]
[ 0. 6.18 0. ... 0. 0. 0. ]
[ 0. 0. 6.1 ... 0. 0. 0. ]
...
[ 0. 0. 0. ... 0.06 0. 0. ]
[ 0. 0. 0. ... 0. 0. 0. ]
[ 0. 0. 0. ... 0. 0. 0. ]]
Vt =
(44, 44)
[[ 0.01 0.05 0.04 ... 0.17 0.15 0.15]
[ 0.03 0.02 0.04 ... -0.17 -0.22 -0.2 ]
[-0.02 -0.04 -0.07 ... -0.07 -0.1 -0.12]
...
[ 0.01 0.06 -0. ... 0.27 0.28 -0.25]
[-0. 0. -0. ... -0.27 0. 0. ]
[-0. 0. -0. ... -0.51 0. -0. ]]
UEVt =
[[ 0. 0. 0. ... -0. 1. 1. ]
[-0. 0. -0. ... -0. -0. 0. ]
[ 1. 1. 1. ... -0. -0. -0. ]
...
[ 0.5 -0. 0. ... 0. -0. -0. ]
[ 0.5 -0. 1. ... 0. 0. 0. ]
[ 1. 0. -0. ... 0. -0. -0. ]]
BEEP BOOP BEEP BOOP...Your Eigen Grandito Recipe is:
6.5 in flour tortilla - 1.0
8 in tortilla - -
10 in flour tortilla - 0.6
12 in flour tortilla - 0.3
taco shell - 0.6
taco shell bowl - 0.1
red taco shell - -
tostado shell - 0.2
mexican pizza shell - 0.1
flatbread shell - 0.2
seasoned beef scoops 2.0
chicken scoops 0.4
steak scoops 0.4
potato bites - 0.2
chunky beans (rs) red scoops 1.0
chunky beans (gs) green scoops 0.3
black beans scoops -
seasoned rice yellow scoops 0.4
cilantro rice scoops -
lettuce (fngr) fingers 3.7
lettuce (oz) ounces 0.4
romaine lettuce ounces -
diced tomatoes fingers 3.1
diced onions fingers 0.2
cheddar cheese (fngr) fingers 2.2
cheddar cheese (ps) purple scoops -
three cheese blend (fngr) fingers 0.3
three cheese blend (oz) ounces 0.2
three cheese blend (ps) purple scoops -
nacho cheese sauce pumps 0.6
pepper jack sauce z 0.2
avocado ranch z 0.2
lava sauce z 0.3
creamy jalepeno sauce z -
creamy cilantro dressing ladles -
red sauce pumps 0.4
sour cream (clk) clicks 1.4
sour cream (dlp) dollops 0.3
guacamole (dlp) dollops 0.2
guacamole (s) scoops -
red strips fingers 0.2
fiesta salsa purple scoops 0.1
pizza sauce ladles -
nacho chips - 0.2
jalapeno portions -
roasted corn salsa scoops -
pico de gallo scoops -
eggs scoops 0.1
bacon scoops -
sausage crumbles scoops -
hash brown - -