generated from allenai/python-package-template
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
49f878d
commit b43c745
Showing
20 changed files
with
159,187 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
,sku,name,type,price,description | ||
0,JAF-001,nutellaphone who dis?,jaffle,1100,nutella and banana jaffle | ||
1,JAF-002,doctor stew,jaffle,1100,house-made beef stew jaffle | ||
2,JAF-003,the krautback,jaffle,1200,lamb and pork bratwurst with house-pickled cabbage sauerkraut and mustard | ||
3,JAF-004,flame impala,jaffle,1400,"pulled pork and pineapple al pastor marinated in ghost pepper sauce, kevin parker's favorite! " | ||
4,JAF-005,mel-bun,jaffle,1200,"melon and minced beef bao, in a jaffle, savory and sweet" | ||
5,BEV-001,tangaroo,beverage,600,mango and tangerine smoothie | ||
6,BEV-002,chai and mighty,beverage,500,oatmilk chai latte with protein boost | ||
7,BEV-003,vanilla ice,beverage,600,iced coffee with house-made french vanilla syrup | ||
8,BEV-004,for richer or pourover ,beverage,700,daily selection of single estate beans for a delicious hot pourover | ||
9,BEV-005,adele-ade,beverage,400,"a kiwi and lime agua fresca, hello from the other side of thirst" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
,id,name,opened_at,tax_rate | ||
0,4df82ef5-0cc0-4e67-a538-a0065c18d115,Philadelphia,2016-09-01T00:00:00,0.06 | ||
1,4bd23c5f-7a47-4242-99c2-3e34197c8942,Brooklyn,2017-03-12T00:00:00,0.04 | ||
2,4ef73a58-a12c-4058-b1ae-14e531f58798,Chicago,2018-04-29T00:00:00,0.0625 | ||
3,ca0d2635-72cc-4ac2-b65e-9993972ea055,San Francisco,2018-05-09T00:00:00,0.075 | ||
4,e8f4b489-d780-42df-9ed9-e9defe4bd524,New Orleans,2019-03-10T00:00:00,0.04 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
,id,name,cost,perishable,sku | ||
0,SUP-001,compostable cutlery - knife,7,False,JAF-001 | ||
1,SUP-002,cutlery - fork,7,False,JAF-001 | ||
2,SUP-003,serving boat,11,False,JAF-001 | ||
3,SUP-004,napkin,4,False,JAF-001 | ||
4,SUP-009,bread,33,True,JAF-001 | ||
5,SUP-011,nutella,46,True,JAF-001 | ||
6,SUP-012,banana,13,True,JAF-001 | ||
7,SUP-001,compostable cutlery - knife,7,False,JAF-002 | ||
8,SUP-002,cutlery - fork,7,False,JAF-002 | ||
9,SUP-003,serving boat,11,False,JAF-002 | ||
10,SUP-004,napkin,4,False,JAF-002 | ||
11,SUP-009,bread,33,True,JAF-002 | ||
12,SUP-010,cheese,20,True,JAF-002 | ||
13,SUP-013,beef stew,169,True,JAF-002 | ||
14,SUP-001,compostable cutlery - knife,7,False,JAF-003 | ||
15,SUP-002,cutlery - fork,7,False,JAF-003 | ||
16,SUP-003,serving boat,11,False,JAF-003 | ||
17,SUP-004,napkin,4,False,JAF-003 | ||
18,SUP-009,bread,33,True,JAF-003 | ||
19,SUP-010,cheese,20,True,JAF-003 | ||
20,SUP-014,lamb and pork bratwurst,234,True,JAF-003 | ||
21,SUP-015,house-pickled cabbage sauerkraut,43,True,JAF-003 | ||
22,SUP-016,mustard,7,True,JAF-003 | ||
23,SUP-001,compostable cutlery - knife,7,False,JAF-004 | ||
24,SUP-002,cutlery - fork,7,False,JAF-004 | ||
25,SUP-003,serving boat,11,False,JAF-004 | ||
26,SUP-004,napkin,4,False,JAF-004 | ||
27,SUP-009,bread,33,True,JAF-004 | ||
28,SUP-010,cheese,20,True,JAF-004 | ||
29,SUP-017,pulled pork,215,True,JAF-004 | ||
30,SUP-018,pineapple,26,True,JAF-004 | ||
31,SUP-021,ghost pepper sauce,20,True,JAF-004 | ||
32,SUP-001,compostable cutlery - knife,7,False,JAF-005 | ||
33,SUP-002,cutlery - fork,7,False,JAF-005 | ||
34,SUP-003,serving boat,11,False,JAF-005 | ||
35,SUP-004,napkin,4,False,JAF-005 | ||
36,SUP-009,bread,33,True,JAF-005 | ||
37,SUP-010,cheese,20,True,JAF-005 | ||
38,SUP-019,melon,33,True,JAF-005 | ||
39,SUP-020,minced beef,124,True,JAF-005 | ||
40,SUP-005,16oz compostable clear cup,13,False,BEV-001 | ||
41,SUP-006,16oz compostable clear lid,4,False,BEV-001 | ||
42,SUP-007,biodegradable straw,13,False,BEV-001 | ||
43,SUP-022,mango,32,True,BEV-001 | ||
44,SUP-023,tangerine,20,True,BEV-001 | ||
45,SUP-005,16oz compostable clear cup,13,False,BEV-002 | ||
46,SUP-006,16oz compostable clear lid,4,False,BEV-002 | ||
47,SUP-007,biodegradable straw,13,False,BEV-002 | ||
48,SUP-008,chai mix,98,True,BEV-002 | ||
49,SUP-024,oatmilk,11,True,BEV-002 | ||
50,SUP-025,whey protein,36,True,BEV-002 | ||
51,SUP-005,16oz compostable clear cup,13,False,BEV-003 | ||
52,SUP-006,16oz compostable clear lid,4,False,BEV-003 | ||
53,SUP-007,biodegradable straw,13,False,BEV-003 | ||
54,SUP-026,coffee,52,True,BEV-003 | ||
55,SUP-027,french vanilla syrup,72,True,BEV-003 | ||
56,SUP-005,16oz compostable clear cup,13,False,BEV-004 | ||
57,SUP-006,16oz compostable clear lid,4,False,BEV-004 | ||
58,SUP-007,biodegradable straw,13,False,BEV-004 | ||
59,SUP-026,coffee,52,True,BEV-004 | ||
60,SUP-005,16oz compostable clear cup,13,False,BEV-005 | ||
61,SUP-006,16oz compostable clear lid,4,False,BEV-005 | ||
62,SUP-007,biodegradable straw,13,False,BEV-005 | ||
63,SUP-028,kiwi,20,True,BEV-005 | ||
64,SUP-029,lime,13,True,BEV-005 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,5 @@ | ||
# Add your own dependencies to this file. | ||
numpy==1.24.0 | ||
pandas==1.5.2 | ||
Faker==15.3.4 | ||
tqdm==4.64.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import datetime | ||
|
||
import numpy as np | ||
|
||
|
||
class Curve: | ||
@classmethod | ||
def eval(cls, date): | ||
x = cls.TranslateDomain(date) | ||
x_mod = x % len(cls.Domain) | ||
x_translated = cls.Domain[x_mod] | ||
return cls.Expr(x_translated) | ||
|
||
|
||
class AnnualCurve(Curve): | ||
Domain = np.linspace(0, 2 * np.pi, 365) | ||
TranslateDomain = lambda date: date.timetuple().tm_yday | ||
Expr = lambda x: (np.cos(x) + 1) / 10 + 0.8 | ||
|
||
|
||
class WeekendCurve(Curve): | ||
Domain = tuple(range(6)) | ||
TranslateDomain = lambda date: date.weekday() - 1 | ||
Expr = lambda x: 0.6 if x >= 6 else 1 | ||
|
||
|
||
class GrowthCurve(Curve): | ||
Domain = tuple(range(500)) | ||
TranslateDomain = lambda date: (date.year - 2016) * 12 + date.month | ||
# ~ aim for ~20% growth/year | ||
Expr = lambda x: 1 + (x / 12) * 0.2 | ||
|
||
|
||
class Day(object): | ||
EPOCH = datetime.datetime(year=2016, month=9, day=1) | ||
SEASONAL_MONTHLY_CURVE = AnnualCurve() | ||
WEEKEND_CURVE = WeekendCurve() | ||
GROWTH_CURVE = GrowthCurve() | ||
|
||
def __init__(self, date_index, minutes=0): | ||
self.date_index = date_index | ||
self.date = self.EPOCH + datetime.timedelta(days=date_index, minutes=minutes) | ||
|
||
self.day_of_week = self._get_day_of_week(self.date) | ||
self.is_weekend = self._is_weekend(self.date) | ||
self.season = self._get_season(self.date) | ||
|
||
self.effects = [ | ||
self.SEASONAL_MONTHLY_CURVE.eval(self.date), | ||
self.WEEKEND_CURVE.eval(self.date), | ||
self.GROWTH_CURVE.eval(self.date), | ||
] | ||
|
||
def at_minute(self, minutes): | ||
return Day(self.date_index, minutes=minutes) | ||
|
||
def get_effect(self): | ||
total = 1 | ||
for effect in self.effects: | ||
total = total * effect | ||
return total | ||
|
||
# weekend_effect = 0.8 if date.is_weekend else 1 | ||
# summer_effect = 0.7 if date.season == 'summer' else 1 | ||
|
||
def _get_day_of_week(self, date): | ||
return date.weekday() | ||
|
||
def _is_weekend(self, date): | ||
# 5 + 6 are weekends | ||
return date.weekday() >= 5 | ||
|
||
def _get_season(self, date): | ||
month_no = date.month | ||
day_no = date.day | ||
|
||
if month_no in (1, 2) or (month_no == 3 and day_no < 21): | ||
return "winter" | ||
elif month_no in (3, 4, 5) or (month_no == 6 and day_no < 21): | ||
return "spring" | ||
elif month_no in (6, 7, 8) or (month_no == 9 and day_no < 21): | ||
return "summer" | ||
elif month_no in (9, 10, 11) or (month_no == 12 and day_no < 21): | ||
return "fall" | ||
else: | ||
return "winter" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
import random | ||
import uuid | ||
|
||
import numpy as np | ||
from faker import Faker | ||
|
||
from customers.order import Order | ||
from stores.inventory import Inventory | ||
|
||
fake = Faker() | ||
Faker.seed(123456789) | ||
|
||
|
||
class Customer(object): | ||
def __init__(self, store): | ||
self.customer_id = str(uuid.uuid4()) | ||
self.store = store | ||
self.name = fake.name() | ||
self.favorite_number = int(np.random.rand() * 100) | ||
|
||
def p_buy_season(self, day): | ||
return self.store.p_buy(day) | ||
|
||
def p_buy(self, day): | ||
p_buy_season = self.p_buy_season(day) | ||
p_buy_persona = self.p_buy_persona(day) | ||
p_buy_on_day = (p_buy_season * p_buy_persona) ** 0.5 | ||
return p_buy_on_day | ||
|
||
def get_order(self, day): | ||
items = self.get_order_items(day) | ||
order_time_delta = self.get_order_time(day) | ||
|
||
order_time = day.at_minute(order_time_delta + self.store.opens_at(day)) | ||
if not self.store.is_open_at(order_time): | ||
return None | ||
|
||
return Order(self, items, self.store, order_time) | ||
|
||
def get_order_items(self, day): | ||
raise NotImplemented() | ||
|
||
def get_order_time(self, store, day): | ||
raise NotImplemented() | ||
|
||
def p_buy_persona(self, day): | ||
raise NotImplemented() | ||
|
||
def sim_day(self, day): | ||
p_buy = self.p_buy(day) | ||
p_buy_threshold = np.random.random() | ||
|
||
if p_buy_threshold < p_buy: | ||
return self.get_order(day) | ||
else: | ||
return None | ||
|
||
def to_dict(self): | ||
return { | ||
"id": self.customer_id, | ||
"name": self.name, | ||
} | ||
|
||
|
||
class RemoteWorker(Customer): | ||
"This person works from a coffee shop" | ||
|
||
def p_buy_persona(self, day): | ||
buy_propensity = (self.favorite_number / 100) * 0.4 | ||
return 0.001 if day.is_weekend else buy_propensity | ||
|
||
def get_order_time(self, day): | ||
# most likely to order in the morning | ||
# exponentially less likely to order in the afternoon | ||
avg_time = 420 | ||
order_time = np.random.normal(loc=avg_time, scale=180) | ||
return max(0, int(order_time)) | ||
|
||
def get_order_items(self, day): | ||
num_drinks = 1 | ||
food = [] | ||
|
||
if random.random() > 0.7: | ||
num_drinks = 2 | ||
|
||
if random.random() > 0.7: | ||
food = Inventory.get_food(1) | ||
|
||
return Inventory.get_drink(num_drinks) + food | ||
|
||
|
||
class BrunchCrowd(Customer): | ||
"Do you sell mimosas?" | ||
|
||
def p_buy_persona(self, day): | ||
buy_propensity = 0.2 + (self.favorite_number / 100) * 0.2 | ||
return buy_propensity if day.is_weekend else 0 | ||
|
||
def get_order_time(self, day): | ||
# most likely to order in the early afternoon | ||
avg_time = 300 + ((self.favorite_number - 50) / 50) * 120 | ||
order_time = np.random.normal(loc=avg_time, scale=120) | ||
return max(0, int(order_time)) | ||
|
||
def get_order_items(self, day): | ||
num_customers = 1 + int(self.favorite_number / 20) | ||
return Inventory.get_drink(num_customers) + Inventory.get_food(num_customers) | ||
|
||
|
||
class Commuter(Customer): | ||
"the regular, thanks" | ||
|
||
def p_buy_persona(self, day): | ||
buy_propensity = 0.5 + (self.favorite_number / 100) * 0.3 | ||
return 0.001 if day.is_weekend else buy_propensity | ||
|
||
def get_order_time(self, day): | ||
# most likely to order in the morning | ||
# exponentially less likely to order in the afternoon | ||
avg_time = 60 | ||
order_time = np.random.normal(loc=avg_time, scale=30) | ||
return max(0, int(order_time)) | ||
|
||
def get_order_items(self, day): | ||
return Inventory.get_drink(1) | ||
|
||
|
||
class Student(Customer): | ||
"coffee might help" | ||
|
||
def p_buy_persona(self, day): | ||
if day.season == "summer": | ||
return 0 | ||
else: | ||
buy_propensity = 0.1 + (self.favorite_number / 100) * 0.4 | ||
return buy_propensity | ||
|
||
def get_order_time(self, day): | ||
# later is better | ||
avg_time = 9 * 60 | ||
order_time = np.random.normal(loc=avg_time, scale=120) | ||
return max(0, int(order_time)) | ||
|
||
def get_order_items(self, day): | ||
food = [] | ||
if random.random() > 0.5: | ||
food = Inventory.get_food(1) | ||
|
||
return Inventory.get_drink(1) + food | ||
|
||
|
||
class Casuals(Customer): | ||
"just popping in" | ||
|
||
def p_buy_persona(self, day): | ||
return 0.1 | ||
|
||
def get_order_time(self, day): | ||
avg_time = 5 * 60 | ||
order_time = np.random.normal(loc=avg_time, scale=120) | ||
return max(0, int(order_time)) | ||
|
||
def get_order_items(self, day): | ||
num_drinks = int(random.random() * 10 / 3) | ||
num_food = int(random.random() * 10 / 3) | ||
return Inventory.get_drink(num_drinks) + Inventory.get_food(num_food) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import uuid | ||
|
||
from customers.order_item import OrderItem | ||
|
||
|
||
class Order(object): | ||
def __init__(self, customer, items, store, day): | ||
self.order_id = str(uuid.uuid4()) | ||
self.customer = customer | ||
self.items = [OrderItem(self.order_id, item) for item in items] | ||
self.store = store | ||
self.day = day | ||
self.subtotal = sum(i.item.price for i in self.items) | ||
self.tax_paid = store.tax_rate * self.subtotal | ||
self.order_total = self.subtotal + self.tax_paid | ||
|
||
def __str__(self): | ||
return f"{self.customer.name} bought {str(self.items)} at {self.day}" | ||
|
||
def to_dict(self): | ||
return { | ||
"id": self.order_id, | ||
"customer": self.customer.customer_id, | ||
"ordered_at": self.day.date.isoformat(), | ||
# "order_month": self.day.date.strftime("%Y-%m"), | ||
"store_id": self.store.store_id, | ||
"subtotal": int(self.subtotal * 100), | ||
"tax_paid": int(self.tax_paid * 100), | ||
"order_total": int(self.order_total * 100), | ||
} | ||
|
||
def items_to_dict(self): | ||
return [i.to_dict(self.order_id) for i in self.items] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import uuid | ||
|
||
|
||
class OrderItem(object): | ||
def __init__(self, order_id, item): | ||
self.item_id = str(uuid.uuid4()) | ||
self.order_id = order_id | ||
self.item = item | ||
|
||
def to_dict(self): | ||
return { | ||
"id": self.item_id, | ||
"order_id": self.order_id, | ||
"sku": self.item.sku, | ||
} |
Oops, something went wrong.