{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport seaborn as sns\nfrom matplotlib import pyplot as plt\nimport networkx as nx\nfrom gensim.models import Word2Vec\nfrom sklearn.metrics.pairwise import cosine_similarity\nimport matplotlib.image as mpimg\nimport random","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:52:53.010639Z","iopub.execute_input":"2023-07-03T04:52:53.011074Z","iopub.status.idle":"2023-07-03T04:52:53.017501Z","shell.execute_reply.started":"2023-07-03T04:52:53.011040Z","shell.execute_reply":"2023-07-03T04:52:53.016514Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"articles = pd.read_csv(\"../input/h-and-m-personalized-fashion-recommendations/articles.csv\")\n# customers = pd.read_csv(\"../input/h-and-m-personalized-fashion-recommendations/customers.csv\")\ntransactions = pd.read_csv(\"../input/h-and-m-personalized-fashion-recommendations/transactions_train.csv\")","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:52:53.019545Z","iopub.execute_input":"2023-07-03T04:52:53.020108Z","iopub.status.idle":"2023-07-03T04:53:39.073923Z","shell.execute_reply.started":"2023-07-03T04:52:53.020073Z","shell.execute_reply":"2023-07-03T04:53:39.072886Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"item_freq = transactions.groupby('article_id')['customer_id'].nunique()\nuser_freq = transactions.groupby('customer_id')['article_id'].nunique()\n\nitems = item_freq[item_freq >= 100].index\nusers = user_freq[user_freq >= 100].index\n\nfiltered_df = transactions[transactions['article_id'].isin(items) & transactions['customer_id'].isin(users)]","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:53:39.075486Z","iopub.execute_input":"2023-07-03T04:53:39.076337Z","iopub.status.idle":"2023-07-03T04:54:45.654357Z","shell.execute_reply.started":"2023-07-03T04:53:39.076299Z","shell.execute_reply":"2023-07-03T04:54:45.653001Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"freq = filtered_df.groupby(['customer_id', 'article_id']).size().reset_index(name='frequency')\n\nGraphTravel_HM = filtered_df.merge(freq, on=['customer_id', 'article_id'], how='left')\n\nGraphTravel_HM = GraphTravel_HM[GraphTravel_HM['frequency'] >= 10]","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:54:45.657200Z","iopub.execute_input":"2023-07-03T04:54:45.657585Z","iopub.status.idle":"2023-07-03T04:54:58.251960Z","shell.execute_reply.started":"2023-07-03T04:54:45.657554Z","shell.execute_reply":"2023-07-03T04:54:58.250616Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display(GraphTravel_HM)\n\nprint(\"unique customer_id\" , GraphTravel_HM.customer_id.nunique())\nprint(\"unique article_id\" , GraphTravel_HM.article_id.nunique())","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:54:58.253455Z","iopub.execute_input":"2023-07-03T04:54:58.254001Z","iopub.status.idle":"2023-07-03T04:54:58.282801Z","shell.execute_reply.started":"2023-07-03T04:54:58.253966Z","shell.execute_reply":"2023-07-03T04:54:58.281357Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sns.histplot(GraphTravel_HM['frequency'], kde=True, bins=30)\n\nplt.title('Distribution of frequency')\nplt.xlabel('Frequency')\nplt.ylabel('Density')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:54:58.284544Z","iopub.execute_input":"2023-07-03T04:54:58.285098Z","iopub.status.idle":"2023-07-03T04:54:58.818241Z","shell.execute_reply.started":"2023-07-03T04:54:58.285066Z","shell.execute_reply":"2023-07-03T04:54:58.816882Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"unique_customer_ids = GraphTravel_HM['customer_id'].unique()\ncustomer_id_mapping = {id: i for i, id in enumerate(unique_customer_ids)}\nGraphTravel_HM['customer_id'] = GraphTravel_HM['customer_id'].map(customer_id_mapping)\n\nitem_name_mapping = dict(zip(articles['article_id'], articles['prod_name'])) # prod_name","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:54:58.820406Z","iopub.execute_input":"2023-07-03T04:54:58.820800Z","iopub.status.idle":"2023-07-03T04:54:58.905747Z","shell.execute_reply.started":"2023-07-03T04:54:58.820766Z","shell.execute_reply":"2023-07-03T04:54:58.904533Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"G = nx.Graph()\n\nfor index, row in GraphTravel_HM.iterrows():\n    G.add_node(row['customer_id'], type='user')\n    G.add_node(row['article_id'], type='item')\n    G.add_edge(row['customer_id'], row['article_id'], weight=row['frequency'])","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:54:58.916310Z","iopub.execute_input":"2023-07-03T04:54:58.916684Z","iopub.status.idle":"2023-07-03T04:55:00.706557Z","shell.execute_reply.started":"2023-07-03T04:54:58.916642Z","shell.execute_reply":"2023-07-03T04:55:00.705206Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# biased random walk  \ndef biased_random_walk(G, start_node, walk_length, p=1, q=1):\n    walk = [start_node]\n\n    while len(walk) < walk_length:\n        cur_node = walk[-1]\n        cur_neighbors = list(G.neighbors(cur_node))\n\n        if len(cur_neighbors) > 0:\n            if len(walk) == 1:\n                walk.append(random.choice(cur_neighbors))\n            else:\n                prev_node = walk[-2]\n\n                probability = []\n                for neighbor in cur_neighbors:\n                    if neighbor == prev_node:\n                        # Return parameter \n                        probability.append(1/p)\n                    elif G.has_edge(neighbor, prev_node):\n                        # Stay parameter \n                        probability.append(1)\n                    else:\n                        # In-out parameter \n                        probability.append(1/q)\n\n                probability = np.array(probability)\n                probability = probability / probability.sum()  # normalize\n\n                next_node = np.random.choice(cur_neighbors, p=probability)\n                walk.append(next_node)\n        else:\n            break\n\n    return walk","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:55:00.708205Z","iopub.execute_input":"2023-07-03T04:55:00.709079Z","iopub.status.idle":"2023-07-03T04:55:00.719627Z","shell.execute_reply.started":"2023-07-03T04:55:00.709034Z","shell.execute_reply":"2023-07-03T04:55:00.718401Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def generate_walks(G, num_walks, walk_length, p=1, q=1):\n    walks = []\n    nodes = list(G.nodes())\n    for _ in range(num_walks):\n        random.shuffle(nodes)  # to ensure randomness\n        for node in nodes:\n            walk_from_node = biased_random_walk(G, node, walk_length, p, q)\n            walks.append(walk_from_node)\n    return walks","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:55:00.721042Z","iopub.execute_input":"2023-07-03T04:55:00.721524Z","iopub.status.idle":"2023-07-03T04:55:00.733980Z","shell.execute_reply.started":"2023-07-03T04:55:00.721495Z","shell.execute_reply":"2023-07-03T04:55:00.732649Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Random Walk \nwalks = generate_walks(G, num_walks=10, walk_length=20, p=9, q=1)\nfiltered_walks = [walk for walk in walks if len(walk) >= 5]\n\n# to String  (for Word2Vec input)\nwalks = [[str(node) for node in walk] for walk in walks]\n\n# Word2Vec train\nmodel = Word2Vec(walks, vector_size=128, window=5, min_count=0,  hs=1, sg=1, workers=4, epochs=10)\n\n# node embedding extract\nembeddings = {node_id: model.wv[node_id] for node_id in model.wv.index_to_key}","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:55:00.753384Z","iopub.execute_input":"2023-07-03T04:55:00.753838Z","iopub.status.idle":"2023-07-03T04:55:36.790695Z","shell.execute_reply.started":"2023-07-03T04:55:00.753797Z","shell.execute_reply":"2023-07-03T04:55:36.789636Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_user_embedding(user_id, embeddings):\n    return embeddings[str(user_id)]","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:55:36.799877Z","iopub.execute_input":"2023-07-03T04:55:36.800321Z","iopub.status.idle":"2023-07-03T04:55:36.813652Z","shell.execute_reply.started":"2023-07-03T04:55:36.800282Z","shell.execute_reply":"2023-07-03T04:55:36.812158Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_rated_items(user_id, df):\n    return set(df[df['customer_id'] == user_id]['article_id'])","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:55:36.815343Z","iopub.execute_input":"2023-07-03T04:55:36.816239Z","iopub.status.idle":"2023-07-03T04:55:36.827026Z","shell.execute_reply.started":"2023-07-03T04:55:36.816201Z","shell.execute_reply":"2023-07-03T04:55:36.825670Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def calculate_similarities(user_id, df, embeddings):\n    rated_items = get_rated_items(user_id, df)\n    user_embedding = get_user_embedding(user_id, embeddings)\n\n    item_similarities = []\n    for item_id in set(df['article_id']):\n        if item_id not in rated_items:  \n            item_embedding = embeddings[str(item_id)]\n            similarity = cosine_similarity([user_embedding], [item_embedding])[0][0]\n            item_similarities.append((item_id, similarity))\n\n    return item_similarities","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:55:36.828410Z","iopub.execute_input":"2023-07-03T04:55:36.828823Z","iopub.status.idle":"2023-07-03T04:55:36.840789Z","shell.execute_reply.started":"2023-07-03T04:55:36.828782Z","shell.execute_reply":"2023-07-03T04:55:36.839689Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_images(items, item_name_mapping, num_items, show_similarity=False):\n    f, ax = plt.subplots(1, num_items, figsize=(20,10))\n    if num_items == 1:\n        ax = [ax]\n    for i, item in enumerate(items):\n        item_id, similarity = item\n        print(f\"- Item {item_id}: {item_name_mapping[item_id]}\", end='')\n        if show_similarity:\n            print(f\" with similarity score: {similarity}\")\n        else:\n            print()\n        img_path = f\"../input/h-and-m-personalized-fashion-recommendations/images/0{str(item_id)[:2]}/0{int(item_id)}.jpg\"\n        try:\n            img = mpimg.imread(img_path)\n            ax[i].imshow(img)\n            ax[i].set_title(f'Item {item_id}')\n            ax[i].set_xticks([], [])\n            ax[i].set_yticks([], [])\n            ax[i].grid(False)\n        except FileNotFoundError:\n            print(f\"Image for item {item_id} not found.\")\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:55:36.842525Z","iopub.execute_input":"2023-07-03T04:55:36.843006Z","iopub.status.idle":"2023-07-03T04:55:36.854673Z","shell.execute_reply.started":"2023-07-03T04:55:36.842966Z","shell.execute_reply":"2023-07-03T04:55:36.853397Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\ndef recommend_items(user_id, df, embeddings, item_name_mapping, num_items=5):\n    rated_items = get_rated_items(user_id, df)\n    \n    print(f\"User {user_id} has purchased:\")\n    show_images([(item_id, 0) for item_id in list(rated_items)[:5]], item_name_mapping, min(len(rated_items), 5))\n    \n    item_similarities = calculate_similarities(user_id, df, embeddings)\n\n    recommended_items = sorted(item_similarities, key=lambda x: x[1], reverse=True)[:num_items]\n\n    print(f\"\\nRecommended items for user {user_id}:\")\n    show_images(recommended_items, item_name_mapping, num_items, show_similarity=True)\n","metadata":{"execution":{"iopub.status.busy":"2023-07-03T04:55:36.855969Z","iopub.execute_input":"2023-07-03T04:55:36.856391Z","iopub.status.idle":"2023-07-03T04:55:36.872116Z","shell.execute_reply.started":"2023-07-03T04:55:36.856363Z","shell.execute_reply":"2023-07-03T04:55:36.871108Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# costomer 45's top 5 \nrecommend_items(25, GraphTravel_HM, embeddings, item_name_mapping, num_items=5)","metadata":{"execution":{"iopub.status.busy":"2023-07-03T05:00:00.540125Z","iopub.execute_input":"2023-07-03T05:00:00.540606Z","iopub.status.idle":"2023-07-03T05:00:03.583445Z","shell.execute_reply.started":"2023-07-03T05:00:00.540568Z","shell.execute_reply":"2023-07-03T05:00:03.582415Z"},"trusted":true},"execution_count":null,"outputs":[]}]}