-
Notifications
You must be signed in to change notification settings - Fork 0
/
simulate_behavior.py
143 lines (115 loc) · 4.18 KB
/
simulate_behavior.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# -*- coding: utf-8 -*-
"""
simulate_behavior.py
~~~~~~~~~~~~~~~~~~~~
Pretend to browse e-commerce and respond to ads
"""
import sys
import requests
import time
import uuid
import numpy as np
import logging
logger = logging.getLogger()
handler = logging.FileHandler('preferences.log')
logger.addHandler(handler)
logger.setLevel(10)
N_BRANDS = 6
def _get_user_brand_prefs():
"""
Provide a unit vector over the brands to represent
a user's preference among them
"""
prefs = np.random.uniform(0, 1, size=N_BRANDS)
normalized_prefs = prefs * (1. / sum(prefs))
return normalized_prefs
def _get_population_brand_prefs(n_users):
"""
Create user_ids and preferences
"""
return {
str(uuid.uuid4()): _get_user_brand_prefs()
for i in range(n_users)
}
def _get_brand_patterns():
"""
Define each brand's product mix (in terms of params to a normal dist)
"""
return [
(np.random.uniform(100, 800), np.random.exponential(10))
for i in range(N_BRANDS)
]
def _draw_user_brand_interest(user_prefs, brand_patterns):
"""
Draw a brand based on user preference and a product based on brand params
"""
brand_draw = np.random.multinomial(1, user_prefs)
brand_index = brand_draw.argmax()
product_price = np.random.normal(*brand_patterns[brand_index])
return dict(brand=brand_index, price=product_price)
def _receive_ad(population_prefs, user_id, brand_index):
"""
User receives an ad for brand
If user has reasonable preference for this brand, the preference increments
Otherwise, the preference drops.
"""
prefs = population_prefs[user_id]
if np.random.uniform(0, 1) > (N_BRANDS / 2.) * prefs[brand_index]:
prefs[brand_index] += .1
else:
prefs[brand_index] = prefs[brand_index] - .1 if prefs[brand_index] > .1 else 0.001
population_prefs[user_id] = prefs * (1. / sum(prefs))
logger.info(population_prefs[user_id])
return population_prefs
def _consider_purchase(product_viewed, population_prefs, user_id):
"""
User considers ending activity via purchase or bailing entirely
"""
sd = np.std(population_prefs[user_id])
logger.info(str(product_viewed.items()) + str(population_prefs[user_id]))
if sd < .05:
# low variance in prefs, nothing compelling here, bail
del population_prefs[user_id]
return population_prefs, False
if sd > .15:
# high variance in prefs, go for it
del population_prefs[user_id]
return population_prefs, True
return population_prefs, False
def _experience_product(product_viewed, user_id,
receiver_url, time_, population_prefs):
"""
Send logs to tracking service and check to see if an ad should render
"""
event = dict(user_id=user_id, timestamp=time_, **product_viewed)
r = requests.get(receiver_url + '/log', params=event)
if r.json().get('show'):
population_prefs = _receive_ad(population_prefs, user_id, event['brand'])
return population_prefs, event
def _register_purchase(event, receiver_url):
requests.post(receiver_url + '/conversion', params=event)
def main():
n_users = int(sys.argv[1])
receiver_url = sys.argv[2]
brand_patterns = _get_brand_patterns()
population_prefs = _get_population_brand_prefs(n_users)
user_ids = population_prefs.keys()
time_ = 0
while len(population_prefs) > n_users / 10.:
time_ += 1
user_idx = np.random.randint(len(population_prefs))
user_id = user_ids[user_idx]
user_prefs = population_prefs[user_id]
product_viewed = _draw_user_brand_interest(user_prefs, brand_patterns)
population_prefs, event = _experience_product(
product_viewed, user_id, receiver_url, time_, population_prefs)
if np.random.uniform(0, 1) > .9:
# import pdb; pdb.set_trace()
population_prefs, purchase = _consider_purchase(
product_viewed, population_prefs, user_id)
if purchase:
_register_purchase(event, receiver_url)
user_ids = population_prefs.keys()
logger.info(len(user_ids))
if __name__ == '__main__':
main()