diff --git a/commons-math3-3.0-bin.tar.gz b/commons-math3-3.0-bin.tar.gz deleted file mode 100644 index 4c642b2..0000000 Binary files a/commons-math3-3.0-bin.tar.gz and /dev/null differ diff --git a/data/survey_recipes.xml b/data/long_recipebook.xml similarity index 90% rename from data/survey_recipes.xml rename to data/long_recipebook.xml index 74ace57..6727e03 100644 --- a/data/survey_recipes.xml +++ b/data/long_recipebook.xml @@ -452,7 +452,7 @@ on high speed until foamy. - Breaded Veal Cutlet ( Weinerschnitzel ) + Weinerschnitzel Veal @@ -673,7 +673,7 @@ baking powder and salt. - Chinese: Cashew Chicken 1 + Cashew Chicken Cashews @@ -2829,4 +2829,329 @@ Carbs 36 g. FROM: MADELINE HIMY (NFBH49A) + + + Hamburger Steak + + + Beef + Penndutch + + 1servings + + + + + + + + + 1 + pound + + Beef + ground + + + + 0.5 + teaspoon + + salt + + + + + 1 + + + onion + minced + + + + 1 + + + egg + well beaten + + + + 1 + dash + + pepper + + + + + 0.25 + cup + + bread crumbs + + + + + Mix in order given and shape into round cakes. Fry in butter until +nicely browned. Source: Pennsylvania Dutch Cook Book - Fine Old +Recipes, Culinary Arts Press, 1936. + + + + + Potatoes in a Thick Sauce + + + Main dish + Potatoes + Indian + Vegetarian + + 6servings + + + + + + + + + 5 + medium + + potatoes + cubed & cooked + + + + 1 + slice + + ginger + + + + + 1 + tablespoon + + Coriander + + + + + 1 + teaspoon + + cumin + + + + + 6 + tablespoons + + tomato sauce + + + + + 6 + tablespoons + + vegetable oil + + + + + 1 + teaspoon + + Fennel + + + + + 1 + teaspoon + + Fenugreek + + + + + 0.5 + teaspoon + + Black mustard seeds + + + + + 3 + + + Whole dried red chilies + + + + + 1 + teaspoon + + salt + + + + + 1.5 + teaspoons + + lemon juice + + + + + 1 + teaspoon + + Garam masala + + + + + Place ginger, coriander, cumin, tomato sauce & 3 tb water in a +blender & blend till smooth. + +Break potatoes into bite sized pieces. + +Heat oil (I use ghee) in a large pot. When hot, throw in fennel, +fenugreek & mustard seeds. After 20 seconds, add red chilies. As +they darken, put in paste from blender. Fry for 5 minutes, stirring +frequently. Put in the potato pieces & fry for 3 to 5 minutes. Add 1 +1/2 c warm water. Bring to a boil. Add salt & lemon juice. Simmer +for 20 minutes. + +Before serving, sprinkle with garam masala. + +Madhur Jaffrey, "An Invitation to Indian Cooking. + + + + + Tomato-Zucchini Casserole + + + Vegetarian + Casseroles + + 4servings + + + + + + + + + 1.5 + teaspoons + + chili powder + + + + + 1 + tablespoon + + parsley flakes + + + + + 0.5 + teaspoon + + garlic powder + + + + + 0.5 + teaspoon + + onion powder + + + + + 0.125 + teaspoon + + salt + + + + + 0.125 + teaspoon + + black pepper + ground + + + + 3 + cups + + zucchini + thinly sliced,fresh + + + + 1 + pound + + tomatoes + fresh,sliced + + + + 0.25 + cup + + bread crumbs + white,fresh + + + + 1 + tablespoon + + vegetable oil + + + + + 1. Combine chili powder, 1 1/2 teaspooons parsley flakes, garlic and +onion powders, salt and pepper in a small bowl.~ 2. Place half the +zucchini in a lightly greased 6-cup casserole, or layer with half the +tomatoes.~ 3. Sprinkle with half the seasoning mixture.~ 4. Repeat +the layers.~ 5. Combine bread crumbs, oil and remaining parsley +flakes; sprinkle over vegetables.~ 6. Bake, uncovered, in preheated +375'F. oven, until vegetables are tender, about 40 minutes.~ + + \ No newline at end of file diff --git a/data/long_survey.xml b/data/long_survey.xml new file mode 100644 index 0000000..2b6f832 --- /dev/null +++ b/data/long_survey.xml @@ -0,0 +1,275 @@ + + + + + 0 + Catalan Rice + + + 1 + Hamburger Steak + + + 2 + Potatoes in a Thick Sauce + + + 3 + Tomato-Zucchini Casserole + + + 4 + Honey Cake + + + 5 + Cashew Chicken + + + 6 + Kahlua Cake + + + 7 + Ice Cream, Lowfat + + + 8 + Blender Double Fudge Cake + + + 9 + Weinerschnitzel + + + + + 0 + vegetarian + + + 1 + allergic-nuts + + + + 0 + + + 0 + 10 + + + 1 + 2 + + + 2 + 5 + + + 3 + 5 + + + 4 + 5 + + + 5 + 5 + + + 6 + 5 + + + 7 + 5 + + + 8 + 5 + + + 9 + 5 + + + + + 0 + false + + + 1 + false + + + + + 1 + + + 0 + 0 + + + 1 + 0 + + + 2 + 5 + + + 3 + 6 + + + 4 + 5 + + + 5 + 5 + + + 6 + 5 + + + 7 + 5 + + + 8 + 5 + + + 9 + 5 + + + + + 0 + true + + + 1 + false + + + + + 2 + + + 0 + 9 + + + 1 + 2 + + + 2 + 2 + + + 3 + 2 + + + 4 + 5 + + + 5 + 0 + + + 6 + 5 + + + 7 + 5 + + + 8 + 5 + + + 9 + 5 + + + + + 0 + false + + + 1 + true + + + + + 3 + + + 0 + 9 + + + 1 + 2 + + + 2 + 2 + + + 3 + 2 + + + 4 + 5 + + + 5 + 7 + + + 6 + 5 + + + 7 + 5 + + + 8 + 5 + + + 9 + 5 + + + + + 0 + false + + + 1 + false + + + + \ No newline at end of file diff --git a/data/medium_recipebook.xml b/data/medium_recipebook.xml new file mode 100644 index 0000000..317b3d6 --- /dev/null +++ b/data/medium_recipebook.xml @@ -0,0 +1,521 @@ + + + + + Catalan Rice + + + Fish + Casserole + Main dish + Pork + Clams + + 6servings + + + + + + + + + 2.5 + cups + + Fish stock + + + + + 0.25 + teaspoon + + Saffron Threads + + + + + 0.25 + cup + + Dry white wine + + + + + 6 + tablespoons + + Lard + + + + + 0.5 + pound + + Chorizo + Sliced 1/4" + + + + 1.5 + pounds + + Pork Loin + 1" Cubes + + + + 1 + + + onion + thinly sliced + + + + 2 + + + Bell peppers + julienned + + + + 2 + + + tomatoes + peeled,seeded + + + + 3 + + + Large Squid + + + + + 2 + cups + + Long-Grained Rice + + + + + 0.75 + cup + + Blanched almonds + + + + + 0.333333 + cup + + Pine Nuts + + + + + 3 + + + garlic cloves + minced + + + + 1 + cup + + Artichoke hearts + drained + + + + 18 + + + Clams Or Mussels + scrubbed + + + + 0.5 + cup + + Peas + + + + + 0.25 + cup + + Pimientos + julienned + + + + 2 + tablespoons + + Fresh parsley + minced + + + + Clean squid and cut body sacs into rings. Cut tentacles in half. In +a small saucepan, bring stock to a bare simmer. Crush saffron and +combine it with wine in a small bowl. In a flameproof casserole or +paella pan, heat the lard over moderately high heat. Saute the +chorizo and pork, turning them until they are browned. Add the +onion, bell peppers, tomatoes, and squid and cook the mixture over +moderate heat, stirring, for 15 minutes. Stir in the rice and cook +for 1 minute, stirring. Stir in almonds, pine nuts, garlic, saffron +mixture, and artichoke hearts. Ladle in enough stock to just cover +the rice mixture. Bring to a boil and simmer it, covered, for 20 +minutes. Arrange the clams in the rice, add the peas, and simmer for +10-15 minutes, or until the rice is just tender and the clams open. +Discard any clams that do not open. Garnish with pimientos and +parsley. This is a recipe by Elizabeth David, appearing in an article +in 1972 by James Beard. It originated on Spain's Costa Brava. "not a +true paella, but it is quite good." A 1972 Gourmet Magazine Favorite. + + + + + Hamburger Steak + + + Beef + Penndutch + + 1servings + + + + + + + + + 1 + pound + + Beef + ground + + + + 0.5 + teaspoon + + salt + + + + + 1 + + + onion + minced + + + + 1 + + + egg + well beaten + + + + 1 + dash + + pepper + + + + + 0.25 + cup + + bread crumbs + + + + + Mix in order given and shape into round cakes. Fry in butter until +nicely browned. Source: Pennsylvania Dutch Cook Book - Fine Old +Recipes, Culinary Arts Press, 1936. + + + + + Potatoes in a Thick Sauce + + + Main dish + Potatoes + Indian + Vegetarian + + 6servings + + + + + + + + + 5 + medium + + potatoes + cubed & cooked + + + + 1 + slice + + ginger + + + + + 1 + tablespoon + + Coriander + + + + + 1 + teaspoon + + cumin + + + + + 6 + tablespoons + + tomato sauce + + + + + 6 + tablespoons + + vegetable oil + + + + + 1 + teaspoon + + Fennel + + + + + 1 + teaspoon + + Fenugreek + + + + + 0.5 + teaspoon + + Black mustard seeds + + + + + 3 + + + Whole dried red chilies + + + + + 1 + teaspoon + + salt + + + + + 1.5 + teaspoons + + lemon juice + + + + + 1 + teaspoon + + Garam masala + + + + + Place ginger, coriander, cumin, tomato sauce & 3 tb water in a +blender & blend till smooth. + +Break potatoes into bite sized pieces. + +Heat oil (I use ghee) in a large pot. When hot, throw in fennel, +fenugreek & mustard seeds. After 20 seconds, add red chilies. As +they darken, put in paste from blender. Fry for 5 minutes, stirring +frequently. Put in the potato pieces & fry for 3 to 5 minutes. Add 1 +1/2 c warm water. Bring to a boil. Add salt & lemon juice. Simmer +for 20 minutes. + +Before serving, sprinkle with garam masala. + +Madhur Jaffrey, "An Invitation to Indian Cooking. + + + + + Tomato-Zucchini Casserole + + + Vegetarian + Casseroles + + 4servings + + + + + + + + + 1.5 + teaspoons + + chili powder + + + + + 1 + tablespoon + + parsley flakes + + + + + 0.5 + teaspoon + + garlic powder + + + + + 0.5 + teaspoon + + onion powder + + + + + 0.125 + teaspoon + + salt + + + + + 0.125 + teaspoon + + black pepper + ground + + + + 3 + cups + + zucchini + thinly sliced,fresh + + + + 1 + pound + + tomatoes + fresh,sliced + + + + 0.25 + cup + + bread crumbs + white,fresh + + + + 1 + tablespoon + + vegetable oil + + + + + 1. Combine chili powder, 1 1/2 teaspooons parsley flakes, garlic and +onion powders, salt and pepper in a small bowl.~ 2. Place half the +zucchini in a lightly greased 6-cup casserole, or layer with half the +tomatoes.~ 3. Sprinkle with half the seasoning mixture.~ 4. Repeat +the layers.~ 5. Combine bread crumbs, oil and remaining parsley +flakes; sprinkle over vegetables.~ 6. Bake, uncovered, in preheated +375'F. oven, until vegetables are tender, about 40 minutes.~ + + + \ No newline at end of file diff --git a/data/medium_survey.xml b/data/medium_survey.xml new file mode 100644 index 0000000..2d02b4c --- /dev/null +++ b/data/medium_survey.xml @@ -0,0 +1,81 @@ + + + + + 0 + Catalan Rice + + + 1 + Hamburger Steak + + + 2 + Potatoes in a Thick Sauce + + + 3 + Tomato-Zucchini Casserole + + + + + 0 + vegan + + + + 0 + + + 0 + 10 + + + 1 + 2 + + + 2 + 5 + + + 3 + 5 + + + + + 0 + false + + + + + 1 + + + 0 + 0 + + + 1 + 0 + + + 2 + 5 + + + 3 + 6 + + + + + 0 + true + + + + \ No newline at end of file diff --git a/data/short_survey.xml b/data/short_survey.xml index 33805ec..dfebb14 100644 --- a/data/short_survey.xml +++ b/data/short_survey.xml @@ -21,19 +21,7 @@ 0 - - chocolate - - - - 1 - - nuts - - - - 2 - shellfish + vegan @@ -56,20 +44,12 @@ 5 - + 0 false - - 1 - false - - - 2 - false - - + 1 @@ -91,19 +71,11 @@ 5 - + 0 false - - 1 - false - - - 2 - false - - + \ No newline at end of file diff --git a/data/survey.xml b/data/survey.xml deleted file mode 100644 index f2f9937..0000000 --- a/data/survey.xml +++ /dev/null @@ -1,628 +0,0 @@ - - - - - 0 - Honey cake - - - 1 - Kahlua Cake - - - 2 - Ice Cream, Lowfat - - - 3 - Southwest Smoothie - - - 4 - Margarita Sunrise - - - 5 - Breaded Veal Cutlet ( Weinerschnitzel ) - - - 6 - Blender Double Fudge Cake - - - 7 - Chinese: Cashew Chicken 1 - - - 8 - Bayou Shrimp Creole - - - 9 - Crab Burgers - - - 10 - Broiled Flounder - - - 11 - Coconut Beer Batter Shrimp - - - 12 - Coconut Fish Curry - - - 13 - Catalan Rice - - - 14 - Baked Steak And Lima Beans - - - 15 - Tabasco Classic - Perfect Seared Steaks **** - - - 16 - Salisbury Steak with Mushroom Sauce - - - 17 - Meatless Loaf - - - 18 - Black Bean Soup - - - 29 - Fava Bean Burgers - - - 20 - Angel Hair Pesto Primavera - - - 21 - EGGPLANT LASAGNE - - - - - 0 - - chocolate - - - - 1 - - nuts - - - - 2 - - shellfish - - - - - 0 - - - 0 - 10 - - - 1 - 10 - - - 2 - 10 - - - 3 - 10 - - - 4 - 10 - - - 5 - 10 - - - 6 - 10 - - - 7 - 10 - - - 8 - 10 - - - 9 - 10 - - - 10 - 10 - - - 11 - 10 - - - 12 - 10 - - - 13 - 10 - - - 14 - 10 - - - 15 - 10 - - - 16 - 10 - - - 17 - 10 - - - 18 - 10 - - - 19 - 10 - - - 20 - 10 - - - - - 0 - false - - - 1 - false - - - 2 - false - - - - - 1 - - - 0 - 10 - - - 1 - 10 - - - 2 - 10 - - - 3 - 10 - - - 4 - 10 - - - 5 - 10 - - - 6 - 10 - - - 7 - 10 - - - 8 - 10 - - - 9 - 10 - - - 10 - 10 - - - 11 - 10 - - - 12 - 10 - - - 13 - 10 - - - 14 - 10 - - - 15 - 10 - - - 16 - 10 - - - 17 - 10 - - - 18 - 10 - - - 19 - 10 - - - 20 - 10 - - - - - 0 - false - - - 1 - false - - - 2 - false - - - - - 2 - - - 0 - 10 - - - 1 - 10 - - - 2 - 10 - - - 3 - 10 - - - 4 - 10 - - - 5 - 10 - - - 6 - 10 - - - 7 - 10 - - - 8 - 10 - - - 9 - 10 - - - 10 - 10 - - - 11 - 10 - - - 12 - 10 - - - 13 - 10 - - - 14 - 10 - - - 15 - 10 - - - 16 - 10 - - - 17 - 10 - - - 18 - 10 - - - 19 - 10 - - - 20 - 10 - - - - - 0 - false - - - 1 - false - - - 2 - false - - - - - 3 - - - 0 - 10 - - - 1 - 10 - - - 2 - 10 - - - 3 - 10 - - - 4 - 10 - - - 5 - 10 - - - 6 - 10 - - - 7 - 10 - - - 8 - 10 - - - 9 - 10 - - - 10 - 10 - - - 11 - 10 - - - 12 - 10 - - - 13 - 10 - - - 14 - 10 - - - 15 - 10 - - - 16 - 10 - - - 17 - 10 - - - 18 - 10 - - - 19 - 10 - - - 20 - 10 - - - - - 0 - false - - - 1 - false - - - 2 - false - - - - - 4 - - - 0 - 10 - - - 1 - 10 - - - 2 - 10 - - - 3 - 10 - - - 4 - 10 - - - 5 - 10 - - - 6 - 10 - - - 7 - 10 - - - 8 - 10 - - - 9 - 10 - - - 10 - 10 - - - 11 - 10 - - - 12 - 10 - - - 13 - 10 - - - 14 - 10 - - - 15 - 10 - - - 16 - 10 - - - 17 - 10 - - - 18 - 10 - - - 19 - 10 - - - 20 - 10 - - - - - 0 - false - - - 1 - false - - - 2 - false - - - - \ No newline at end of file diff --git a/src/dkohl/bayes/builders/FoodNetBuilder.java b/src/dkohl/bayes/builders/FoodNetBuilder.java index 677ea76..9dbb300 100644 --- a/src/dkohl/bayes/builders/FoodNetBuilder.java +++ b/src/dkohl/bayes/builders/FoodNetBuilder.java @@ -23,14 +23,19 @@ import dkohl.onthology.Ontology; public class FoodNetBuilder { public static final String TASTE = "Taste"; - public static final String SOMEONE_VEGETARIAN = "Vegetarian"; + + public static final String SOMEONE_VEGETARIAN = "vegetarian"; + public static final String SOMEONE_ALLERGIC_NUTS = "allergic-nuts"; + public static final String CONTAINS_MEAT = "Meat"; public static final String CONTAINS_VEGETABLE = "Vegetable"; public static final String CONTAINS_BEEF = TYPE.BEEF.toString(); public static final String CONTAINS_PORK = TYPE.PORK.toString(); public static final String CONTAINS_TOMATOS = TYPE.TOMATO.toString(); public static final String CONTAINS_POTATOS = TYPE.POTATO.toString(); - + public static final String CONTAINS_NUTS = "Nuts"; + public static final String CONTAINS_GENERIC_NUTS = TYPE.GENERIC_NUTS.toString(); + public static final String TRUE_VALUE = "true"; public static final String FALSE_VALUE = "false"; @@ -39,27 +44,30 @@ public class FoodNetBuilder { public static final String RATING_DOMAIN[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" }; - private static final String[] VARIABLES = { SOMEONE_VEGETARIAN, + private static final String[] VARIABLES = { SOMEONE_VEGETARIAN, SOMEONE_ALLERGIC_NUTS, CONTAINS_BEEF, CONTAINS_MEAT, CONTAINS_PORK, CONTAINS_POTATOS, - CONTAINS_TOMATOS, CONTAINS_VEGETABLE, TASTE }; + CONTAINS_TOMATOS, CONTAINS_VEGETABLE, CONTAINS_NUTS, CONTAINS_GENERIC_NUTS, TASTE }; private static final String[] OBSERVED = { CONTAINS_BEEF, CONTAINS_PORK, - CONTAINS_POTATOS, CONTAINS_TOMATOS, }; + CONTAINS_POTATOS, CONTAINS_TOMATOS, CONTAINS_GENERIC_NUTS}; public static Ontology createOntology() { HashSet classes = new HashSet(); classes.add(CONTAINS_MEAT); + classes.add(CONTAINS_NUTS); classes.add(CONTAINS_VEGETABLE); - Ontology onthology = new Ontology(classes); + Ontology ontology = new Ontology(classes); - onthology.define(CONTAINS_PORK, CONTAINS_MEAT); - onthology.define(CONTAINS_BEEF, CONTAINS_MEAT); + ontology.define(CONTAINS_PORK, CONTAINS_MEAT); + ontology.define(CONTAINS_BEEF, CONTAINS_MEAT); - onthology.define(CONTAINS_TOMATOS, CONTAINS_VEGETABLE); - onthology.define(CONTAINS_POTATOS, CONTAINS_VEGETABLE); - return onthology; + ontology.define(CONTAINS_GENERIC_NUTS, CONTAINS_NUTS); + + ontology.define(CONTAINS_TOMATOS, CONTAINS_VEGETABLE); + ontology.define(CONTAINS_POTATOS, CONTAINS_VEGETABLE); + return ontology; } private static Assignment build(String varible, String value) { @@ -86,14 +94,13 @@ public class FoodNetBuilder { return normPoint; } - public static DataSet getSurveyDataSet(Survey survey, RecipeBook recipeBook) { + public static DataSet getSurveyDataSet(Survey survey, RecipeBook recipeBook, int startIndex, int endIndex) { DataSet data = FoodExampleBuilder.examples(); Ontology onto = createOntology(); - int nDishes = survey.getDishCount(); for (int dinerIndex = 0; dinerIndex < survey.getDinerCount(); dinerIndex++) { Diner diner = survey.getDiner(dinerIndex); - for (int dishIndex = 0; dishIndex < nDishes; dishIndex++) { + for (int dishIndex = startIndex; dishIndex < endIndex; dishIndex++) { data.add(normalize(createDataPoint(recipeBook, survey.getDish(dishIndex), diner.getRating(dishIndex)),onto)); } } @@ -118,20 +125,41 @@ public class FoodNetBuilder { if (ingredients.contains(TYPE.TOMATO)) { point.add(build(CONTAINS_TOMATOS, TRUE_VALUE)); } + if (ingredients.contains(TYPE.GENERIC_NUTS)) { + point.add(build(CONTAINS_GENERIC_NUTS, TRUE_VALUE)); + } point.add(build(TASTE, "" + weight)); return point; } - public static ProbabilityDistribution vegi() { + public static ProbabilityDistribution vegi(Survey survey) { String names[] = { SOMEONE_VEGETARIAN }; ProbabilityTable table = new ProbabilityTable(names); - table.setProbabilityForAssignment("true;", new Probability(0)); - table.setProbabilityForAssignment("false;", new Probability(1)); + if (survey.isDiner("vegetarian")) { + table.setProbabilityForAssignment("true;", new Probability(1)); + table.setProbabilityForAssignment("false;", new Probability(0)); + } else { + table.setProbabilityForAssignment("true;", new Probability(0)); + table.setProbabilityForAssignment("false;", new Probability(1)); + } return table; } + public static ProbabilityDistribution allergicNuts(Survey survey) { + String names[] = { SOMEONE_ALLERGIC_NUTS }; + ProbabilityTable table = new ProbabilityTable(names); + if (survey.isDiner("allergic-nuts")) { + table.setProbabilityForAssignment("true;", new Probability(1)); + table.setProbabilityForAssignment("false;", new Probability(0)); + } else { + table.setProbabilityForAssignment("true;", new Probability(0)); + table.setProbabilityForAssignment("false;", new Probability(1)); + } + return table; + } + public static ProbabilityDistribution beef() { String names[] = { CONTAINS_MEAT, CONTAINS_BEEF }; ProbabilityTable table = new ProbabilityTable(names); @@ -143,13 +171,25 @@ public class FoodNetBuilder { ProbabilityTable table = new ProbabilityTable(names); return table; } - - public static ProbabilityDistribution meet() { + + public static ProbabilityDistribution meat() { String names[] = { SOMEONE_VEGETARIAN, CONTAINS_MEAT }; ProbabilityTable table = new ProbabilityTable(names); return table; } - + + public static ProbabilityDistribution genericNuts() { + String names[] = { CONTAINS_NUTS, CONTAINS_GENERIC_NUTS }; + ProbabilityTable table = new ProbabilityTable(names); + return table; + } + + public static ProbabilityDistribution nuts() { + String names[] = { SOMEONE_ALLERGIC_NUTS, CONTAINS_NUTS }; + ProbabilityTable table = new ProbabilityTable(names); + return table; + } + public static ProbabilityDistribution tomatos() { String names[] = { CONTAINS_VEGETABLE, CONTAINS_TOMATOS }; ProbabilityTable table = new ProbabilityTable(names); @@ -170,27 +210,34 @@ public class FoodNetBuilder { public static ProbabilityDistribution taste() { String names[] = { TASTE, CONTAINS_BEEF, CONTAINS_PORK, - CONTAINS_POTATOS, CONTAINS_TOMATOS }; + CONTAINS_POTATOS, CONTAINS_TOMATOS, CONTAINS_GENERIC_NUTS }; ContinousDistribution distribution = new ContinousDistribution(names, 0); return distribution; } - public static BayesNet createDishNet(Survey survey, RecipeBook recipeBook) { + public static BayesNet createDishNet(Survey survey, RecipeBook recipeBook, int startIndex, int endIndex) { BayesNet net = new BayesNet(VARIABLES); - net.setDistribution(new Variable(SOMEONE_VEGETARIAN, DOMAIN), vegi()); - net.setDistribution(new Variable(CONTAINS_MEAT, DOMAIN), meet()); + net.setDistribution(new Variable(SOMEONE_VEGETARIAN, DOMAIN), vegi(survey)); + net.setDistribution(new Variable(SOMEONE_ALLERGIC_NUTS, DOMAIN), allergicNuts(survey)); + + net.setDistribution(new Variable(CONTAINS_MEAT, DOMAIN), meat()); + net.setDistribution(new Variable(CONTAINS_NUTS, DOMAIN), nuts()); + net.setDistribution(new Variable(CONTAINS_VEGETABLE, DOMAIN), vegetables()); net.setDistribution(new Variable(CONTAINS_BEEF, DOMAIN), beef()); net.setDistribution(new Variable(CONTAINS_PORK, DOMAIN), pork()); net.setDistribution(new Variable(CONTAINS_POTATOS, DOMAIN), potatos()); net.setDistribution(new Variable(CONTAINS_TOMATOS, DOMAIN), tomatos()); + net.setDistribution(new Variable(CONTAINS_GENERIC_NUTS, DOMAIN), genericNuts()); + net.setDistribution(new Variable(TASTE, RATING_DOMAIN), taste()); Ontology ontology = createOntology(); for (String category : ontology.getClasses()) { net.connect(category, SOMEONE_VEGETARIAN); + net.connect(category, SOMEONE_ALLERGIC_NUTS); } for (String thing : OBSERVED) { @@ -198,7 +245,7 @@ public class FoodNetBuilder { net.connect(TASTE, thing); } - DataSet dataSet = getSurveyDataSet(survey, recipeBook); + DataSet dataSet = getSurveyDataSet(survey, recipeBook, startIndex, endIndex); for (String category : ontology.getClasses()) { MaximumLikelihoodEstimation.estimate(dataSet, net, category); diff --git a/src/dkohl/util/RootMeanSquareError.java b/src/dkohl/util/RootMeanSquareError.java index 3f10774..00eb797 100644 --- a/src/dkohl/util/RootMeanSquareError.java +++ b/src/dkohl/util/RootMeanSquareError.java @@ -4,32 +4,27 @@ import java.util.LinkedList; public class RootMeanSquareError { - private LinkedList expected; - private LinkedList groundTruth; - - public RootMeanSquareError() { - expected = new LinkedList(); - groundTruth = new LinkedList(); - } - - public void push(double predicted, double actual) { - expected.add(predicted); - groundTruth.add(actual); - } - - public double error() { - double mean = 0.0; - for(Double val : groundTruth) { - mean += val; + private LinkedList expected; + private LinkedList groundTruth; + + public RootMeanSquareError() { + expected = new LinkedList(); + groundTruth = new LinkedList(); } - mean /= groundTruth.size(); - - double err = 0.0; - for(Double val : expected) { - err += Math.pow(mean - val, 2); + + public void push(double predicted, double actual) { + expected.add(predicted); + groundTruth.add(actual); } - return Math.sqrt(err); - } - - + + public double error() { + double mean = 0.0; + for (int i = 0; i < expected.size(); i++){ + mean += Math.pow(expected.get(i) - groundTruth.get(i), 2); + } + mean /= groundTruth.size(); + + return Math.sqrt(mean); + } + } diff --git a/src/net/woodyfolsom/cs6601/p2/BayesChef.java b/src/net/woodyfolsom/cs6601/p2/BayesChef.java index f39cd59..e024008 100644 --- a/src/net/woodyfolsom/cs6601/p2/BayesChef.java +++ b/src/net/woodyfolsom/cs6601/p2/BayesChef.java @@ -6,24 +6,22 @@ import java.util.List; import java.util.Set; import net.woodyfolsom.cs6601.p2.Ingredient.TYPE; - -import org.apache.commons.math3.stat.regression.SimpleRegression; - import dkohl.bayes.bayesnet.BayesNet; import dkohl.bayes.builders.FoodNetBuilder; import dkohl.bayes.inference.EnumerateAll; import dkohl.bayes.probability.Assignment; import dkohl.bayes.probability.ProbabilityAssignment; import dkohl.bayes.probability.Variable; +import dkohl.util.RootMeanSquareError; public class BayesChef { public static void main(String... args) { System.out.println("Reading recipe book."); - RecipeBook recipeBook = RecipeBookReader.readRecipeBook(new File("data/short_recipebook.xml")); + RecipeBook recipeBook = RecipeBookReader.readRecipeBook(new File("data/long_recipebook.xml")); System.out.println("Reading survey data."); - Survey survey = SurveyReader.readSurvey(new File("data/short_survey.xml")); + Survey survey = SurveyReader.readSurvey(new File("data/long_survey.xml")); new BayesChef().reportBestMeal(recipeBook,survey); } @@ -36,29 +34,39 @@ public class BayesChef { System.out.println("Read data for " + numDiners + " diner(s)."); System.out.println("Creating Bayes net for survey dataset..."); - BayesNet net = FoodNetBuilder.createDishNet(survey, recipeBook); - System.out.println("Querying Bayes net for individual flavor preferences: "); - double[][] flavorPrefs = new double[4][]; + int numSurveyDishes = survey.getDishCount(); + int bayesNetIndexStart = 0; + int bayesNetIndexEnd = numSurveyDishes / 2; - flavorPrefs[0] = new double[] {0.0,printPreference(net, TYPE.PORK)}; - flavorPrefs[1] = new double[] {1.0,printPreference(net, TYPE.BEEF)}; - flavorPrefs[2] = new double[] {2.0,printPreference(net, TYPE.POTATO)}; - flavorPrefs[3] = new double[] {3.0,printPreference(net, TYPE.TOMATO)}; + int comparisonIndexStart = bayesNetIndexEnd; + int comparisonIndexEnd = numSurveyDishes; - SimpleRegression simpleRegression = new SimpleRegression(); - simpleRegression.addData(flavorPrefs); + //TODO change this to include min/max recipe indices for building the net + BayesNet net = FoodNetBuilder.createDishNet(survey, recipeBook, bayesNetIndexStart, bayesNetIndexEnd); - System.out.println("Individual flavor pref MSE: " + simpleRegression.getMeanSquareError()); - simpleRegression.clear(); + System.out.println("Querying Bayes net for predicted flavor preferences: "); + //TODO change this to query actual flavor combos from latter half of survey + double[] predictedRating = new double[numSurveyDishes - bayesNetIndexEnd]; - System.out.println("Querying Bayes net for recipe flavor preferences: "); - flavorPrefs = new double[recipeBook.getSize()][]; - - for (int i = 0; i < recipeBook.getSize(); i++) { - simpleRegression.addData(i,printPreference(net, recipeBook.getRecipe(i))); + for (int i = comparisonIndexStart; i < comparisonIndexEnd; i++) { + predictedRating[i - comparisonIndexStart] = printPreference(net, recipeBook.getRecipe(survey.getDish(i))); } - System.out.println("Recipe flavor pref MSE: " + simpleRegression.getMeanSquareError()); + + System.out.println("Querying survey dataset for actual recipe flavor preferences: "); + double[] actualRating = new double[predictedRating.length]; + + for (int i = comparisonIndexStart; i < comparisonIndexEnd; i++) { + actualRating[i - comparisonIndexStart] = survey.getAverageRating(i); + System.out.println("Actual average rating for " + survey.getDish(i) + ": " + actualRating[i - comparisonIndexStart]); + } + + RootMeanSquareError rmse = new RootMeanSquareError(); + for (int i = 0; i < actualRating.length; i++) { + rmse.push(predictedRating[i], actualRating[i]); + } + + System.out.println("Root Mean Squared Error (predicted vs. actual): " + rmse.error()); } int printPreference(BayesNet net, Recipe recipe) { @@ -69,7 +77,7 @@ public class BayesChef { net, createQuery(ingredientTypes.toArray(new TYPE[ingredientTypes.size()]))); double max_val = 0.0; - String max_arg = "N/A"; + String max_arg = "0"; for (ProbabilityAssignment p : probs) { if (p.getProbability() > max_val) { max_val = p.getProbability(); @@ -106,6 +114,7 @@ public class BayesChef { case BEEF: case POTATO: case TOMATO: + case GENERIC_NUTS: assignment.add(new Assignment(new Variable(type.toString(), FoodNetBuilder.DOMAIN), FoodNetBuilder.TRUE_VALUE)); break; diff --git a/src/net/woodyfolsom/cs6601/p2/Diner.java b/src/net/woodyfolsom/cs6601/p2/Diner.java index 2b70f7c..d9f6bd9 100644 --- a/src/net/woodyfolsom/cs6601/p2/Diner.java +++ b/src/net/woodyfolsom/cs6601/p2/Diner.java @@ -9,7 +9,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; public class Diner { private int id; private Map ratings = new HashMap(); - private Map allergies = new HashMap(); + private Map categories = new HashMap(); public int getId() { return id; @@ -19,7 +19,7 @@ public class Diner { return ratings.get(dishId); } - public boolean isAllergic(int categoryId) { - return allergies.get(categoryId); + public boolean isCategory(int categoryId) { + return categories.get(categoryId); } } diff --git a/src/net/woodyfolsom/cs6601/p2/Ingredient.java b/src/net/woodyfolsom/cs6601/p2/Ingredient.java index 6ba48a4..d8c5854 100644 --- a/src/net/woodyfolsom/cs6601/p2/Ingredient.java +++ b/src/net/woodyfolsom/cs6601/p2/Ingredient.java @@ -1,15 +1,13 @@ package net.woodyfolsom.cs6601.p2; -import java.util.ArrayList; import java.util.HashSet; -import java.util.List; import java.util.Set; import com.thoughtworks.xstream.annotations.XStreamAlias; @XStreamAlias("ing") public class Ingredient { - public enum TYPE { ALCOHOL, BEEF, DAIRY, EGGS, FISH, GLUTEN, GRAIN, NUTS, PORK, POULTRY, POTATO, SHELLFISH, SPICE, SUGAR, TOMATO} + public enum TYPE { ALCOHOL, BEEF, DAIRY, EGGS, FISH, GENERIC_NUTS, GLUTEN, GRAIN, PORK, POULTRY, POTATO, SHELLFISH, SPICE, SUGAR, TOMATO} private String item; @@ -30,11 +28,15 @@ public class Ingredient { public boolean isType(TYPE type) { switch (type) { case BEEF : - return item.contains("beef"); + //For our purposes, veal is just expensive beef + return item.contains("beef") || item.contains("veal"); case DAIRY : - return item.contains("margarine"); + return item.contains("margarine") || item.contains("milk"); case EGGS : return item.equals("egg") || item.equals("eggs"); + case GENERIC_NUTS : + //cashews, peanuts or generic nuts + return item.contains("cashew") || item.contains("peanut") || item.contains("nuts"); case GLUTEN : return item.contains("flour"); case PORK : diff --git a/src/net/woodyfolsom/cs6601/p2/Survey.java b/src/net/woodyfolsom/cs6601/p2/Survey.java index 877c872..3b1910a 100644 --- a/src/net/woodyfolsom/cs6601/p2/Survey.java +++ b/src/net/woodyfolsom/cs6601/p2/Survey.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamImplicit; @@ -16,6 +17,32 @@ public class Survey { @XStreamImplicit(itemFieldName="diner") private List diners = new ArrayList(); + public double getAverageRating(int recipeIndex) { + double total = 0.0; + for (Diner diner : diners) { + total += diner.getRating(recipeIndex); + } + return total/diners.size(); + } + + public boolean isDiner(String category) { + for (int i = 0; i < diners.size(); i++) { + if (isCategory(i,category)) { + return true; + } + } + return false; + } + + public boolean isCategory(int dinerIndex, String category) { + for (Entry entry : categories.entrySet()) { + if (entry.getValue().equals(category)) { + return diners.get(dinerIndex).isCategory(entry.getKey()); + } + } + return false; + } + public Diner getDiner(int dinerIndex) { return diners.get(dinerIndex); } diff --git a/test/net/woodyfolsom/cs6601/p2/RecipeBookReaderTest.java b/test/net/woodyfolsom/cs6601/p2/RecipeBookReaderTest.java index 3871b76..0661047 100644 --- a/test/net/woodyfolsom/cs6601/p2/RecipeBookReaderTest.java +++ b/test/net/woodyfolsom/cs6601/p2/RecipeBookReaderTest.java @@ -18,10 +18,10 @@ import org.junit.Test; public class RecipeBookReaderTest { @Test - public void testReadSurveyDataset() { - RecipeBook recipeBook = RecipeBookReader.readRecipeBook(new File("data/survey_recipes.xml")); + public void testReadLongRecipeBook() { + RecipeBook recipeBook = RecipeBookReader.readRecipeBook(new File("data/long_recipebook.xml")); assertNotNull(recipeBook); - assertThat(recipeBook.getSize(), is(equalTo(22))); + assertThat(recipeBook.getSize(), is(equalTo(25))); Recipe recipe = recipeBook.getRecipe(0); System.out.println(recipe.getHead().getTitle()); @@ -39,7 +39,28 @@ public class RecipeBookReaderTest { } @Test - public void testReadShortSurveyDataset() { + public void testReadMediumRecipeBook() { + RecipeBook recipeBook = RecipeBookReader.readRecipeBook(new File("data/medium_recipebook.xml")); + assertNotNull(recipeBook); + assertThat(recipeBook.getSize(), is(equalTo(4))); + + Recipe recipe = recipeBook.getRecipe(0); + System.out.println(recipe.getHead().getTitle()); + assertThat(recipe.getHead().getTitle(), is(equalTo("Catalan Rice"))); + assertFalse(recipe.getIngredients().contains(TYPE.EGGS)); + assertFalse(recipe.getIngredients().contains(TYPE.GLUTEN)); + assertTrue(recipe.getIngredients().contains(TYPE.SPICE)); + assertFalse(recipe.getIngredients().contains(TYPE.BEEF)); + assertFalse(recipe.getIngredients().contains(TYPE.POULTRY)); + assertFalse(recipe.getIngredients().contains(TYPE.SHELLFISH)); + + for (int rIndex = 0; rIndex < recipeBook.getSize(); rIndex++) { + System.out.println(recipeBook.getRecipe(rIndex).getHead().getTitle()); + } + } + + @Test + public void testReadShortRecipeBook() { RecipeBook recipeBook = RecipeBookReader.readRecipeBook(new File("data/short_recipebook.xml")); assertNotNull(recipeBook); assertThat(recipeBook.getSize(), is(equalTo(4))); diff --git a/test/net/woodyfolsom/cs6601/p2/SurveyReaderTest.java b/test/net/woodyfolsom/cs6601/p2/SurveyReaderTest.java index c000c97..0b86a18 100644 --- a/test/net/woodyfolsom/cs6601/p2/SurveyReaderTest.java +++ b/test/net/woodyfolsom/cs6601/p2/SurveyReaderTest.java @@ -12,13 +12,37 @@ import org.junit.Test; public class SurveyReaderTest { @Test - public void testReadSurveyDataset() { - Survey survey = SurveyReader.readSurvey(new File("data/survey.xml")); + public void testReadLongSurveyDataset() { + Survey survey = SurveyReader.readSurvey(new File("data/long_survey.xml")); assertNotNull(survey); - assertThat(survey.getDinerCount(), equalTo(5)); + assertThat(survey.getDishCount(), equalTo(10)); + assertThat(survey.getDinerCount(), equalTo(4)); + + assertThat(survey.isCategory(0,"vegetarian"), is(false)); + assertThat(survey.isCategory(0,"allergic-nuts"), is(false)); + + assertThat(survey.isCategory(1,"vegetarian"), is(true)); + assertThat(survey.isCategory(1,"allergic-nuts"), is(false)); + + assertThat(survey.isCategory(2,"vegan"), is(false)); + assertThat(survey.isCategory(2,"allergic-nuts"), is(true)); + + assertThat(survey.isDiner("vegetarian"), is(true)); + assertThat(survey.isDiner("allergic-nuts"), is(true)); + assertThat(survey.isDiner("rastafarian"), is(false)); + } + + @Test + public void testReadMediumSurveyDataset() { + Survey survey = SurveyReader.readSurvey(new File("data/medium_survey.xml")); + assertNotNull(survey); + + assertThat(survey.getDinerCount(), equalTo(2)); Diner diner = survey.getDiner(0); - assertThat(diner.isAllergic(0), is(false)); + assertThat(diner.isCategory(0), is(false)); + diner = survey.getDiner(1); + assertThat(diner.isCategory(0), is(true)); } }