deppfellow commited on
Commit
00e640a
·
1 Parent(s): 0efcdce

Init commit of ease model

Browse files
Files changed (6) hide show
  1. app.py +120 -0
  2. data/2k_ids.pkl +3 -0
  3. data/2k_titles.pkl +3 -0
  4. func.py +54 -0
  5. model.py +115 -0
  6. requirements.txt +4 -0
app.py ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from streamlit_option_menu import option_menu
3
+ from func import *
4
+ from model import *
5
+
6
+
7
+ if "user_preferences" not in st.session_state:
8
+ st.session_state["user_preferences"] = {}
9
+
10
+ if "user_titles" not in st.session_state:
11
+ st.session_state["user_titles"] = []
12
+
13
+ data = pd.read_pickle("data/2k_titles.pkl")
14
+
15
+ def games_recomm(preferences_id):
16
+ if "rs" in st.session_state:
17
+ del st.session_state["rs"]
18
+
19
+ with st.spinner("Getting recommendation..."):
20
+ pref_value = []
21
+ for id in preferences_id:
22
+ if st.session_state[id] == "Positive":
23
+ pref_value.append(1)
24
+ elif st.session_state[id] == "Negative":
25
+ pref_value.append(0)
26
+
27
+ pred_df = pd.DataFrame({
28
+ 'user_id': [999999] * len(preferences_id),
29
+ 'app_id': preferences_id,
30
+ 'is_recommended': pref_value
31
+ })
32
+
33
+ res = ease_model(pred_df=pred_df, k=10)
34
+ st.session_state['rs'] = res
35
+
36
+ # st.write(len(st.session_state['rs']))
37
+ if len(st.session_state['rs']) >= 1:
38
+ st.success(f"Go to result page to view top {len(st.session_state['rs'])} recommendations.")
39
+ else:
40
+ st.error("Recommendation failed. Please reload the session.")
41
+
42
+ # st.write(res)
43
+
44
+ # Main Page Header
45
+ # Consist of Home page, Result page, About page, and Log page
46
+ def spr_sidebar():
47
+ menu = option_menu(
48
+ menu_title=None,
49
+ options=['Home', 'Result', 'About'],
50
+ icons=['house', 'joystick', 'info-square'],
51
+ menu_icon='cast',
52
+ default_index=0,
53
+ orientation='horizontal'
54
+ )
55
+
56
+ # Change 'app_mode' state based on current page
57
+ if menu == 'Home':
58
+ st.session_state['app_mode'] = 'Home'
59
+ elif menu == 'Result':
60
+ st.session_state['app_mode'] = 'Result'
61
+ elif menu == 'About':
62
+ st.session_state['app_mode'] = 'About'
63
+
64
+ # Home page. One of the page in Main Header
65
+ def home_page():
66
+ st.title("Steam Recommendation System")
67
+
68
+ # st.session_state['user_title'] = st.session_state['input_title']
69
+ preferences = st.multiselect(
70
+ label="Input games you like:",
71
+ options=list(data),
72
+ key="user_titles")
73
+
74
+ user_input = generate_app_gamebox(preferences)
75
+
76
+ state = st.button("Get state")
77
+
78
+ if state:
79
+ st.session_state["user_preferences"] = user_input
80
+
81
+ st.markdown("---")
82
+ games_recomm(st.session_state["user_preferences"])
83
+
84
+ st.session_state
85
+
86
+
87
+
88
+ # Result page
89
+ # Show the list of predictions for active user
90
+ def result_page():
91
+ if "rs" not in st.session_state:
92
+ st.error('Please input preferences titles and run "Get recommendation"')
93
+ else:
94
+ st.success(f'Top {len(st.session_state["rs"])}')
95
+ st.session_state
96
+
97
+ user_res = generate_res_gamebox(ids=st.session_state['rs'])
98
+
99
+ # About page
100
+ # Show the information of the project and the sites
101
+
102
+
103
+ def about_page():
104
+ pass
105
+
106
+
107
+ def main():
108
+ spr_sidebar()
109
+ # st.session_state
110
+
111
+ if st.session_state['app_mode'] == 'Home':
112
+ home_page()
113
+ elif st.session_state['app_mode'] == 'Result':
114
+ result_page()
115
+ elif st.session_state['app_mode'] == 'About':
116
+ about_page()
117
+
118
+
119
+ if __name__ == '__main__':
120
+ main()
data/2k_ids.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:dd9e84631b0dd97fe7d0fe982a28a03c9c65a4d1042437385137d05c92f829b3
3
+ size 60873
data/2k_titles.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2689a911254553451cdd573c751192f098d12b3b1cc9d872f7ac2e7b0d840018
3
+ size 60873
func.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import streamlit as st
3
+ import requests
4
+
5
+ from io import BytesIO
6
+ from PIL import Image
7
+
8
+ data_titles = pd.read_pickle("data/2k_titles.pkl")
9
+ data_ids = pd.read_pickle("data/2k_ids.pkl")
10
+
11
+ def generate_app_gamebox(titles):
12
+ titles_id = []
13
+ # selectboxes_id = {}
14
+
15
+ for title in titles:
16
+ titles_id.append(data_titles[title])
17
+
18
+ for id in titles_id:
19
+ url = f"https://cdn.cloudflare.steamstatic.com/steam/apps/{id}/header.jpg"
20
+ resp = requests.get(url)
21
+
22
+ if resp.status_code == 200:
23
+ container = st.container()
24
+ img_col, pref_col = container.columns([3, 2])
25
+
26
+ img_col.image(BytesIO(resp.content))
27
+ pref_col.selectbox(
28
+ "Your rating:",
29
+ options=["Positive", "Negative"],
30
+ key=id,
31
+ )
32
+
33
+ return titles_id
34
+
35
+ def generate_res_gamebox(ids):
36
+ # titles_list = []
37
+
38
+ for id in ids:
39
+ # titles_list.append(data_ids[id])
40
+ url_page = f"https://store.steampowered.com/app/{id}/"
41
+ url_img = f"https://cdn.cloudflare.steamstatic.com/steam/apps/{id}/header.jpg"
42
+ resp = requests.get(url_img)
43
+
44
+ if resp.status_code == 200:
45
+ with st.container():
46
+ st.image(BytesIO(resp.content))
47
+ st.caption(data_ids[id])
48
+
49
+ st.divider()
50
+
51
+ # for title in titles_list:
52
+ # # url = f"https://store.steampowered.com/app/"
53
+ # with st.container():
54
+
model.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import torch
3
+
4
+ from sklearn.neighbors import KNeighborsClassifier
5
+
6
+ # sparse_indices = torch.load("data/sparse_indices.pt")
7
+ # sparse_values = torch.load("data/sparse_values.pt")
8
+ class EASE:
9
+ def __init__(self, train,
10
+ user_col='user_id',
11
+ item_col='app_id',
12
+ score_col='is_recommended',
13
+ reg=250.):
14
+ """
15
+ train: (DataFrame) data of training set
16
+ user_col: (String) column name of users column
17
+ item_col: (String) column name of items column
18
+ score_col: (String) column name of interactions column
19
+ reg: (Float) EASE's regularization value
20
+ """
21
+
22
+ self.user_col = user_col
23
+ self.item_col = item_col
24
+ self.score_col = score_col
25
+ self.train = train
26
+ self.reg = reg
27
+
28
+ self.user_id_col = user_col + "_index"
29
+ self.item_id_col = item_col + "_index"
30
+
31
+ self.item_lookup = self.generate_label(train, self.item_col)
32
+
33
+ self.item_map = {}
34
+ for item, item_index in self.item_lookup.values:
35
+ self.item_map[item_index] = item
36
+
37
+ def generate_label(self, df, col):
38
+ dist_labels = df[[col]].drop_duplicates()
39
+ dist_labels[col +
40
+ "_index"] = dist_labels[col].astype("category").cat.codes
41
+
42
+ return dist_labels
43
+
44
+ def predict_active(self, pred_df, weight, k=10, remove_owned=True):
45
+ """
46
+ Args:
47
+ pred_df: (DataFrame) data of user interactions
48
+ weight: (Tensor) Weight matrix of pre-trained EASE model
49
+ k: (Integer) number of recommendation to be shown
50
+ remove_owned: (Boolean) Whether to remove already interacted items
51
+ """
52
+ train = pd.concat([self.train, pred_df], axis=0)
53
+ user_lookup = self.generate_label(train, self.user_col)
54
+
55
+ train = train.merge(user_lookup, on=[self.user_col], sort=False)
56
+ train = train.merge(self.item_lookup, on=[self.item_col], sort=False)
57
+
58
+ pred_df = pred_df[[self.user_col]].drop_duplicates()
59
+ pred_df = pred_df.merge(user_lookup, on=[self.user_col], sort=False)
60
+
61
+ indices = torch.LongTensor(train[[self.user_id_col, self.item_id_col]].values)
62
+ values = torch.FloatTensor(train[self.score_col])
63
+ sparse = torch.sparse.FloatTensor(indices.T, values)
64
+
65
+ # --------------------------------------------------
66
+ user_act_tensor = sparse.index_select(
67
+ dim=0, index=torch.LongTensor(pred_df[self.user_id_col])
68
+ )
69
+
70
+ _preds_act_tensor = user_act_tensor @ weight
71
+ if remove_owned:
72
+ _preds_act_tensor += -1. * user_act_tensor
73
+
74
+ output_preds = []
75
+ score_preds = []
76
+ for _preds in _preds_act_tensor:
77
+ top_items = _preds.topk(k)
78
+
79
+ output_preds.append([self.item_map[id] for id in top_items.indices.tolist()])
80
+ score_preds.append( top_items.values.tolist() )
81
+
82
+ pred_df['predicted_items'] = output_preds
83
+ pred_df['predicted_score'] = score_preds
84
+
85
+ escaped = [
86
+ ele for i_list in pred_df['predicted_items'].values for ele in i_list
87
+ ]
88
+
89
+ return escaped
90
+
91
+ def ease_model(pred_df, k=10):
92
+ ease_B = torch.load("data/ease_B.pt")
93
+ train = pd.read_csv("data/recs.csv")
94
+
95
+ ease = EASE(train)
96
+ res = ease.predict_active(pred_df=pred_df, weight=ease_B, k=k)
97
+
98
+ return res
99
+
100
+
101
+ # def main():
102
+ # pass
103
+ # # act_user = pd.DataFrame({
104
+ # # 'user_id': [999999, 999999, 999999, 999999, 999999, 999999],
105
+ # # 'app_id': [1689910, 1245620, 814380, 620980, 1551360, 774171],
106
+ # # 'is_recommended': [0, 1, 1, 0, 1, 1]
107
+ # # })
108
+ # # act_indices = torch.FloatTensor(ac)
109
+
110
+ # # print(
111
+ # # torch.sparse.FloatTensor(sparse_indices.T, sparse_values)
112
+ # # )
113
+
114
+ # if __name__ == '__main__':
115
+ # main()
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ pandas
2
+ requests
3
+ streamlit
4
+ streamlit_option_menu