Skip to content

Commit ee99b94

Browse files
author
Beau Dekker
committed
2 parents 1eedb7e + ef492c0 commit ee99b94

15 files changed

Lines changed: 366 additions & 4 deletions

huw.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,8 @@ def renderpackettemplate(self, template="homepage.html", packet={}):
220220
packet['shopping_cart_count'] = self.shoppingcartcount()
221221
if 'r_products' not in packet:
222222
packet['r_products'] = self.recommendations(4, list(self.recommendationtypes.keys())[4], [], [])
223-
packet['r_type'] = list(self.recommendationtypes.values())[0]
224-
packet['r_string'] = list(self.recommendationtypes.values())[0]
223+
packet['r_type'] = list(self.recommendationtypes.values())[4]
224+
packet['r_string'] = list(self.recommendationtypes.values())[4]
225225
return render_template(template, packet=packet)
226226

227227
""" ..:: Recommendation Functions ::.. """
@@ -338,4 +338,4 @@ def changepaginationcount(self):
338338

339339
# TODO: add @app.errorhandler(404) and @app.errorhandler(405)
340340

341-
huw = HUWebshop(app)
341+
huw = HUWebshop(app)

huw_recommend.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import personalrecommendation as personalrec
1010
import pactum as pactum
1111

12+
1213
app = Flask(__name__)
1314
api = Api(app)
1415

@@ -105,6 +106,7 @@ def get(self, profileid, count, type_rec, shopping_list, pagecat, productid):
105106
prodids = [p[0] for p in products]
106107
else:
107108
prodids = [] # todo alternative/fallback
109+
108110

109111
elif type_rec == "combination":
110112
mogelijke_genders = ['Man', 'Vrouw']
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
from rdbconnection2 import conrdb
2+
3+
rdbcon, rdbcur = conrdb()
4+
5+
query_popular_table = """
6+
DO $$
7+
DECLARE
8+
_segment VARCHAR;
9+
i INT;
10+
index INT;
11+
r RECORD;
12+
clean_list VARCHAR[];
13+
_combi VARCHAR[];
14+
prod_freq_list VARCHAR[];
15+
prod_freq VARCHAR[];
16+
temp VARCHAR[];
17+
temp2 INT[];
18+
temp3 INT[];
19+
BEGIN
20+
-- [ MAAK DE TABEL AAN OF UPDATE DE TABEL ]
21+
DROP TABLE IF EXISTS popular CASCADE;
22+
CREATE TABLE popular (
23+
segment VARCHAR(255),
24+
gender VARCHAR(255),
25+
category VARCHAR(255),
26+
product_id1 VARCHAR(255),
27+
product_id2 VARCHAR(255),
28+
product_id3 VARCHAR(255),
29+
product_id4 VARCHAR(255),
30+
FOREIGN KEY (product_id1)
31+
REFERENCES product (product_id),
32+
FOREIGN KEY (product_id2)
33+
REFERENCES product (product_id),
34+
FOREIGN KEY (product_id3)
35+
REFERENCES product (product_id),
36+
FOREIGN KEY (product_id4)
37+
REFERENCES product (product_id)
38+
);
39+
-- [ VUL DE TABEL ]
40+
------------------------- || Voor elk segment bestaande binnen profielen
41+
foreach _segment in ARRAY(select array(select lower(segment) as segment
42+
from profile
43+
group by lower(segment)
44+
order by lower(segment))) loop
45+
------------------------ || Groepeer elke mogelijk combinatie gender-categorie van producten
46+
------------------------ || gekocht door profielen met het segment _segment
47+
foreach _combi slice 1 in ARRAY(select array(select array[lower(gender), lower(category)] from product
48+
natural join(select product_id from orders
49+
natural join(select * from sessions
50+
natural join(select browser_id from buids
51+
natural join profile where lower(segment)=_segment)
52+
as _id) as __id) as ___id
53+
group by lower(gender), lower(category)
54+
order by lower(gender), lower(category))) loop
55+
if _combi[1] is not Null and _combi[2] is not Null then -- || Als zowel het gender als de categorie niet Null zijn
56+
----------------------- || Neem dan de producten
57+
prod_freq_list := array(select ARRAY[product_id, count(*)::varchar] from product
58+
natural join(select product_id from orders
59+
natural join(select * from sessions
60+
natural join(select browser_id from buids
61+
natural join profile where lower(segment)=_segment)
62+
as _id) as __id) as ___id
63+
where lower(gender)=_combi[1] and lower(category)=_combi[2]
64+
group by product_id
65+
order by product_id);
66+
else -- || Als het gender Null is en de categorie niet
67+
if _combi[1] is Null and _combi[2] is not Null then
68+
prod_freq_list := array(select ARRAY[product_id, count(*)::varchar] from product
69+
natural join(select product_id from orders
70+
natural join(select * from sessions
71+
natural join(select browser_id from buids
72+
natural join profile where lower(segment)=_segment)
73+
as _id) as __id) as ___id
74+
where lower(gender) is Null and lower(category)=_combi[2]
75+
group by product_id
76+
order by product_id);
77+
else -- || Categorie Null bestaat niet op de front-end en is dus overbodig voor de tabel
78+
continue;
79+
end if;
80+
end if;
81+
temp := ARRAY[Null];
82+
temp2 := ARRAY[Null];
83+
foreach prod_freq slice 1 in array(prod_freq_list) loop
84+
temp = array_append(temp, prod_freq[1]);
85+
temp2 = array_append(temp2, prod_freq[2]::int);
86+
end loop;
87+
temp3 = ARRAY(select distinct unnest(temp2) order by 1);
88+
if array_length(temp3, 1) > 1 then
89+
for i in 1..4 loop
90+
for r in select max(x) as f from unnest(temp2) as x loop
91+
index = array_position(temp2, r.f);
92+
clean_list[i] = temp[index];
93+
temp = array_remove(temp, temp[index]);
94+
end loop;
95+
end loop;
96+
if clean_list[1] is not Null then
97+
INSERT INTO popular VALUES (_segment, _combi[1], _combi[2], clean_list[1], clean_list[2], clean_list[3], clean_list[4]);
98+
else
99+
continue;
100+
end if;
101+
end if;
102+
end loop;
103+
end loop;
104+
END $$;
105+
"""
106+
107+
rdbcur.execute(query_popular_table)
108+
rdbcon.commit()
109+
rdbcur.close()
110+
rdbcon.close()

user_story_4/popular/readme.md

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
# User story 4: Popular recommendation
2+
3+
Anderen kochten ook
4+
5+
Op de productoage van het front-end staat een kopje: 'Anderen kochten ook'. Hier worden de producten geplaatst van profielen die hetzelfde koopgedrag als de user vertonen,
6+
in dezelfde geslachtscategorie zitten als de gebruiker en passen bij de categorie van de pagina.
7+
8+
| _GP-V1A-Groep6_
9+
| --- |
10+
| TAAI-V1GP-19_2020 |
11+
| TICT-AI-V1A |
12+
| 1778287 |
13+
14+
# Onderbouwing algoritme
15+
16+
Omdat de aanbevelingen zijn gebaseerd op eerdere aankopen van andere mensen, wordt gekeken naar mensen die eerder orders hebben gedaan.
17+
18+
![](src/VennDiagram.png)
19+
20+
Het **U**niversum van het Venn-diagram hierboven bestaat uit klanten. Deze verzameling klanten kan **B**ekend zijn of (B̅) niet bekend zijn.
21+
Van alle profielen van bekende klanten, heeft een groep **E**vents. Daarnaast heeft een groep mensen met Events ook **O**rders.
22+
Voor elk **S**egment binnen deze verzameling wordt vervolgens gekeken naar de producten die door deze groep profielen zijn gekocht.
23+
Vervolgens wordt gekeken naar de verschillende **G**enders binnen ’n verzameling segment x waardoor de combinatie segment-gender ontstaat voor elke mogelijke gender binnen de verzameling van segment x.
24+
En om met elke **C**ategorie product pagina verschillende producten te tonen, verdelen we de verzameling van producten in segment x, gender y op categorieën.
25+
26+
## Huidige user behoort tot B̅
27+
/
28+
29+
## Huidige user behoort tot B
30+
31+
Deze groep kan vervolgens verder worden onderverdeeld. Welke mensen vertonen hetzelfde koopgedrag als de user? Hiervoor wordt gekeken naar het segment dat bij een profiel hoort.
32+
Voor elke verzameling profielen bij ‘n segment geldt: _segment_ is een subset van _O_. Wat voor segmenten zijn er, en hoe vaak komen profielen met een bepaald segment voor?
33+
34+
```sql
35+
select lower(segment), count(segment) as frequency
36+
from profile
37+
group by lower(segment)
38+
order by lower(segment);
39+
```
40+
41+
![](src/segmentfreq.png)
42+
43+
Als we hier zouden stoppen, dan zouden mensen die alleen vrouwelijke producten kopen ook mannelijke producten (of andersom, etc.) aangeboden krijgen.
44+
Daarom wordt voor alle aankopen van de profielen bij 'n segment x gekeken naar 'n gender y.
45+
Dus als we nu gaan kijken voor 'n segment: browser wat de distributie is van genders binnen de verzameling orders van dit segment dan krijgen we het volgende:
46+
47+
48+
```sql
49+
select lower(gender) as gender, count(*) as frequency from product
50+
natural join(select product_id from orders
51+
natural join(select * from sessions
52+
natural join(select browser_id from buids
53+
natural join profile where lower(segment)='browser')
54+
as _id) as __id) as ___id
55+
group by lower(gender)
56+
order by lower(gender);
57+
```
58+
59+
![](src/genderfreq.png)
60+
61+
Als we nu gaan kijken naar de frequencies van producten voor elke mogelijke combinatie van gender-category binnen de verzameling orders van profielen met het segment browser,
62+
krijgen we de volgende uitkomst:
63+
64+
```sql
65+
select lower(gender) as gender, lower(category) as category, count(*) as frequency from product
66+
natural join(select product_id from orders
67+
natural join(select * from sessions
68+
natural join(select browser_id from buids
69+
natural join profile where lower(segment)='browser')
70+
as _id) as __id) as ___id
71+
group by lower(gender), lower(category)
72+
order by lower(gender), lower(category);
73+
```
74+
75+
![](src/gendercatfreq.png)
76+
77+
Hierboven is de tabel getoond met de eerste 29 rijen van de in totaal 70 rijen.
78+
Hier kun je zien dat elke verzameling van producten voor 'n segment browser met gender x alle producten zijn onderverdeeld in categorieën die voorkomen binnen de verzameling producten.
79+
Dan zie je ook dat verzamelingen als grootverpakking minder combinaties hebben. Blijkbaar komen binnen de verzameling van grootverpakking slechts twee categorieën voor.
80+
81+
Ook zien we dat sommige combinaties, niet voorkomen of maar 1 product bevatten zoals; gender: gezin, category: kleding & sieraden. Dit betekent dat bij een user met
82+
het gedrag van een browser, gender kenmerk grootverpakking op de pagina van kleding & sieraden, maar 1 product krijgt aangeraden. Of soms geen enkel product als de category niet voorkomt
83+
in de gekochte producten.
84+
85+
# Nuttigheid
86+
87+
Door het sorteren op segment kenmerk, gender kenmerk en vervolgens per categoriepagina
88+
zou je kunnen zeggen dat mensen die dezelfde kenmerken als een user hadden statistisch gezien grotendeels hetzelfde gedrag zullen vertonen als de gebruiker.
89+
Neem bijvoorbeeld segment: browser en het gender kenmerk baby. Dan is de kans heel groot dat ze naar de categorie pagina van baby & kind kijken
90+
waar ook de meeste producten van zijn gekocht. En dus volgt dan indirect dat ze minder of vrijwel niet naar de pagina gezond & verzorging zullen kijken
91+
en dat het tonen van minder recommendations voor die pagina daarom gerechtvaardigd is.
92+
93+
# Pseudocode
94+
95+
```python
96+
Creëer tabel popular als deze nog niet bestond met de kolommen segment, gender, category, FK product_id1, FK product_id2, FK product_id3, FK product_id4, FK product_id5.
97+
Voor elk _segment in lijst met segments loop:
98+
Stop alle mogelijke gender-category combinaties binnen de verzameling met producten, de orders van profielen met segment _segment in een lijst seg.
99+
Voor elke _gender_category combinatie in seg loop:
100+
Stop de eerste vijf producten binnen de verzameling producten uit de orders van profielen met segment _segment, die voldoen aan de _gender_category combinatie in een lijst prodids.
101+
102+
Voeg achtereenvolgens de volgende delen in de tabel in: segment, gender, category, prodids[0], prodids[1], prodids[2], prodids[3], prodids[4]
103+
104+
```
105+
106+
# Relations
107+
108+
_Product_ -- _Popular_
109+
110+
Een product kan bij **0 of 1** rij horen van popular.
111+
112+
Een rij van popular hoort bij **meerdere** producten.
113+
114+
# Logistiek Datamodel
115+
116+
![](src/ERD_product_popular.png)
117+
118+
# DDL
119+
120+
Hieronder volgt de query die wordt uitgevoerd in createRelationTables.py om de relatie tussen de tabel popular en product te maken.
121+
122+
```sql
123+
DO $$
124+
DECLARE
125+
_segment VARCHAR;
126+
i INT;
127+
index INT;
128+
r RECORD;
129+
clean_list VARCHAR[];
130+
_combi VARCHAR[];
131+
prod_freq_list VARCHAR[];
132+
prod_freq VARCHAR[];
133+
temp VARCHAR[];
134+
temp2 INT[];
135+
temp3 INT[];
136+
BEGIN
137+
-- [ MAAK DE TABEL AAN OF UPDATE DE TABEL ]
138+
DROP TABLE IF EXISTS popular CASCADE;
139+
CREATE TABLE popular (
140+
segment VARCHAR(255),
141+
gender VARCHAR(255),
142+
category VARCHAR(255),
143+
product_id1 VARCHAR(255),
144+
product_id2 VARCHAR(255),
145+
product_id3 VARCHAR(255),
146+
product_id4 VARCHAR(255),
147+
FOREIGN KEY (product_id1)
148+
REFERENCES product (product_id),
149+
FOREIGN KEY (product_id2)
150+
REFERENCES product (product_id),
151+
FOREIGN KEY (product_id3)
152+
REFERENCES product (product_id),
153+
FOREIGN KEY (product_id4)
154+
REFERENCES product (product_id)
155+
);
156+
-- [ VUL DE TABEL ]
157+
------------------------- || Voor elk segment bestaande binnen profielen
158+
foreach _segment in ARRAY(select array(select lower(segment) as segment
159+
from profile
160+
group by lower(segment)
161+
order by lower(segment))) loop
162+
------------------------ || Groepeer elke mogelijk combinatie gender-categorie van producten
163+
------------------------ || gekocht door profielen met het segment _segment
164+
foreach _combi slice 1 in ARRAY(select array(select array[lower(gender), lower(category)] from product
165+
natural join(select product_id from orders
166+
natural join(select * from sessions
167+
natural join(select browser_id from buids
168+
natural join profile where lower(segment)=_segment)
169+
as _id) as __id) as ___id
170+
group by lower(gender), lower(category)
171+
order by lower(gender), lower(category))) loop
172+
if _combi[1] is not Null and _combi[2] is not Null then -- || Als zowel het gender als de categorie niet Null zijn
173+
----------------------- || Neem dan de producten
174+
prod_freq_list := array(select ARRAY[product_id, count(*)::varchar] from product
175+
natural join(select product_id from orders
176+
natural join(select * from sessions
177+
natural join(select browser_id from buids
178+
natural join profile where lower(segment)=_segment)
179+
as _id) as __id) as ___id
180+
where lower(gender)=_combi[1] and lower(category)=_combi[2]
181+
group by product_id
182+
order by product_id);
183+
else -- || Als het gender Null is en de categorie niet
184+
if _combi[1] is Null and _combi[2] is not Null then
185+
prod_freq_list := array(select ARRAY[product_id, count(*)::varchar] from product
186+
natural join(select product_id from orders
187+
natural join(select * from sessions
188+
natural join(select browser_id from buids
189+
natural join profile where lower(segment)=_segment)
190+
as _id) as __id) as ___id
191+
where lower(gender) is Null and lower(category)=_combi[2]
192+
group by product_id
193+
order by product_id);
194+
else -- || Categorie Null bestaat niet op de front-end en is dus overbodig voor de tabel
195+
continue;
196+
end if;
197+
end if;
198+
temp := ARRAY[Null];
199+
temp2 := ARRAY[Null];
200+
foreach prod_freq slice 1 in array(prod_freq_list) loop
201+
temp = array_append(temp, prod_freq[1]);
202+
temp2 = array_append(temp2, prod_freq[2]::int);
203+
end loop;
204+
temp3 = ARRAY(select distinct unnest(temp2) order by 1);
205+
if array_length(temp3, 1) > 1 then
206+
for i in 1..4 loop
207+
for r in select max(x) as f from unnest(temp2) as x loop
208+
index = array_position(temp2, r.f);
209+
clean_list[i] = temp[index];
210+
temp = array_remove(temp, temp[index]);
211+
end loop;
212+
end loop;
213+
if clean_list[1] is not Null then
214+
INSERT INTO popular VALUES (_segment, _combi[1], _combi[2], clean_list[1], clean_list[2], clean_list[3], clean_list[4]);
215+
else
216+
continue;
217+
end if;
218+
end if;
219+
end loop;
220+
end loop;
221+
END $$;
222+
```
223+
224+
# Tabel Popular
225+
226+
![](src/popular_table.PNG)
227+
228+
# Hoe werkt de recommendation?
229+
230+
![](src/FLOWCHART_userPop.png)
231+
232+
# Recommendations in de front-end
233+
234+
_Gezond & verzorging_
235+
236+
![](src/gezond_en_verzorging.PNG)
237+
238+
_Wonen & vrije tijd_
239+
240+
![](src/wonen_en_vrije_tijd.PNG)
9.12 KB
Loading
35.3 KB
Loading
21.2 KB
Loading
84.6 KB
Loading
25.6 KB
Loading
103 KB
Loading

0 commit comments

Comments
 (0)