diff --git a/config.yaml b/config.yaml index 5f5224f..7e65151 100644 --- a/config.yaml +++ b/config.yaml @@ -41,14 +41,14 @@ media: Search: 2.60 noisy_cpm_cpc: Amazon: - loc: 1 + loc: 0 scale: 1 TV: - loc: 1 + loc: 0 scale: 1 Long-Form Video: - loc: 1 + loc: 0 scale: 1 Search: - loc: 1 + loc: 0 scale: 1 \ No newline at end of file diff --git a/src/pysimmmulator/helpers.py b/src/pysimmmulator/helpers.py index d18f81d..3bf6ffd 100644 --- a/src/pysimmmulator/helpers.py +++ b/src/pysimmmulator/helpers.py @@ -41,7 +41,7 @@ def __repr__(self): @dataclass -class baseline: +class baseline_parameters: basic_params: basic_parameters base_p: int trend_p: int @@ -52,35 +52,6 @@ class baseline: def __post_init__(self): assert self.error_std < self.base_p, "Error std can not exceed base sales value" - self.calculate_params() - - def calculate_params(self): - # Number of days to generate data for - days = np.arange(0,self.basic_params.years*365) - - # Base sales of base_p units - base = np.zeros(shape=self.basic_params.years*365) + self.base_p - - #Trend of trend_p extra units per day - trend_cal = (self.trend_p/(self.basic_params.years*365))*self.base_p - trend = trend_cal * days - - #Temperature generated by a sin function and we can manipulate how much the sin function goes up or down with temp_var - temp = self.temp_var * np.sin(days*3.14/182.5) - - # coefficient of temperature's effect on sales will be a random variable with normal distribution - seasonality = np.random.normal(loc = self.temp_coef_mean, scale = self.temp_coef_sd, size = 1) * temp - - # add some noise to the trend - error = np.random.normal(loc=0, scale=self.error_std, size=self.basic_params.years*365) - - # Generate series for baseline sales - baseline_sales = base + trend + seasonality + error - - # if error term makes baseline_sales negative, make it 0 - baseline_sales = np.where(baseline_sales < 0, 0, baseline_sales) - - self.output = np.array([days, baseline_sales, base, trend, temp, seasonality, error]) @dataclass diff --git a/src/pysimmmulator/load_parameters.py b/src/pysimmmulator/load_parameters.py index b7ff2a8..5d56a1d 100644 --- a/src/pysimmmulator/load_parameters.py +++ b/src/pysimmmulator/load_parameters.py @@ -1,7 +1,7 @@ import yaml from pysimmmulator.helpers import ( basic_parameters, - baseline, + baseline_parameters, media_parameters ) @@ -13,10 +13,10 @@ def load_config(config_path: str = 'config.yaml') -> dict: def build_params(config_dict: dict) -> None: my_basic_params = basic_parameters(**config_dict['basic_params']) - my_baseline_params = baseline(basic_params=my_basic_params, **config_dict['baseline_parms']) + my_baseline_params = baseline_parameters(basic_params=my_basic_params, **config_dict['baseline_parms']) cfg = load_config(config_path = 'config.yaml') my_basic_params = basic_parameters(**cfg['basic_params']) -my_baseline_params = baseline(basic_params=my_basic_params, **cfg['baseline_parms']) +my_baseline_params = baseline_parameters(basic_params=my_basic_params, **cfg['baseline_parms']) my_media_params = media_parameters(**cfg['media']) \ No newline at end of file diff --git a/src/pysimmmulator/simmmulate.py b/src/pysimmmulator/simmmulate.py index 7d1a1e5..38b1a55 100644 --- a/src/pysimmmulator/simmmulate.py +++ b/src/pysimmmulator/simmmulate.py @@ -1,5 +1,6 @@ from pysimmmulator.helpers import ( basic_parameters, + baseline_parameters, media_parameters ) @@ -19,6 +20,46 @@ def __init__(self, basic_params: basic_parameters): self.basic_params = basic_params self.channels = basic_params.channels_clicks + basic_params.channels_impressions self.channel_count = len(self.channels) + + def simulate_baseline(self, base_p, trend_p: int, temp_var: int, temp_coef_mean: int, temp_coef_sd: int, error_std: int) -> None: + baseline_params = baseline_parameters( + basic_params=self.basic_params, + base_p=base_p, + trend_p=trend_p, + temp_var=temp_var, + temp_coef_mean=temp_coef_mean, + temp_coef_sd=temp_coef_sd, + error_std=error_std) + + # Number of days to generate data for + days = np.arange(0, self.basic_params.years*365) + # Base sales of base_p units + base = np.zeros(shape=self.basic_params.years*365) + self.base_p + #Trend of trend_p extra units per day + trend_cal = (self.trend_p/(self.basic_params.years*365))*self.base_p + trend = trend_cal * days + #Temperature generated by a sin function and we can manipulate how much the sin function goes up or down with temp_var + temp = self.temp_var * np.sin(days*3.14/182.5) + # coefficient of temperature's effect on sales will be a random variable with normal distribution + seasonality = np.random.normal(loc = self.temp_coef_mean, scale = self.temp_coef_sd, size = 1) * temp + # add some noise to the trend + error = np.random.normal(loc=0, scale=self.error_std, size=self.basic_params.years*365) + # Generate series for baseline sales + baseline_sales = base + trend + seasonality + error + # if error term makes baseline_sales negative, make it 0 + baseline_sales = np.where(baseline_sales < 0, 0, baseline_sales) + + self.baseline_sales_df = pd.DataFrame({ + "days":days, + "baseline_sales":baseline_sales, + "base":base, + "trend":trend, + "temp":temp, + "seasonality":seasonality, + "error":error}) + + + def simulate_ad_spend(self, campaign_spend_mean: int, campaign_spend_std: int, max_min_proportion_on_each_channel: dict) -> None: @@ -57,6 +98,12 @@ def generate_media(self, true_cpm: dict, true_cpc: dict, noisy_cpm_cpc: dict) -> media_params = media_parameters(true_cpm, true_cpc, noisy_cpm_cpc) media_params.check(basic_params=self.basic_params) + for channel in media_params.noise_channels: + channel_campaigns = self.spend_df[self.spend_df['channel'] == channel].shape[1] + self.spend_df[self.spend_df['channel'] == channel]['true_cpm'] + + noisy_cpm = true_cpm.values() + def run_with_config(self):