{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":31254,"databundleVersionId":3103714,"sourceType":"competition"}],"dockerImageVersionId":30158,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# **추천시스템을 만들어 봅시다!**","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport os\nfrom scipy.sparse import csr_matrix\nfrom implicit.als import AlternatingLeastSquares\n\n# Load Data\nfname_tran = '../input/h-and-m-personalized-fashion-recommendations/transactions_train.csv'\nfname_article = '../input/h-and-m-personalized-fashion-recommendations/articles.csv'\n\n# CSV 파일 로드\ndata = pd.read_csv(fname_tran, usecols=['customer_id', 'article_id', 'price'])\narticles = pd.read_csv(fname_article)\n\n# 🔹 article_id를 문자열로 변환 (데이터 일관성 유지)\ndata['article_id'] = data['article_id'].astype(str)\narticles['article_id'] = articles['article_id'].astype(str)\n\n# 🔹 이미지 경로 생성 (H&M 데이터셋 폴더 구조 적용)\narticles['image_path'] = articles['article_id'].apply(lambda x: f\"0{x[:2]}/0{x}.jpg\")\n\n# 🔹 데이터 가공 (고객-상품 매핑)\ndata['count'] = 1\ndata = data.groupby(['customer_id', 'article_id'], as_index=False).sum()\nuser_unique = data['customer_id'].unique()\narticle_unique = data['article_id'].unique()\n\n# 🔹 ID 변환 (Mapping)\nuser_to_idx = {v: k for k, v in enumerate(user_unique)}\narticle_to_idx = {v: k for k, v in enumerate(article_unique)}\nidx_to_article = {v: k for k, v in article_to_idx.items()}\n\n# 🔹 ID 매핑 (NaN 방지 및 필터링)\ndata['customer_id'] = data['customer_id'].map(user_to_idx).fillna(-1).astype(int)\ndata['article_id'] = data['article_id'].map(article_to_idx).fillna(-1).astype(int)\ndata = data[(data['customer_id'] >= 0) & (data['article_id'] >= 0)]\n\n# 🔹 CSR Matrix 생성\nnum_user = data['customer_id'].nunique()\nnum_article = data['article_id'].nunique()\ncsr_data = csr_matrix((data['count'], (data.customer_id, data.article_id)), shape=(num_user, num_article))\n\n# 🔹 ALS 모델 학습\nos.environ['OPENBLAS_NUM_THREADS'] = '1'\nos.environ['KMP_DUPLICATE_LIB_OK'] = 'True'\nos.environ['MKL_NUM_THREADS'] = '1'\n\nals_model = AlternatingLeastSquares(factors=360, regularization=0.01, use_gpu=True, iterations=5, dtype=np.float32, calculate_training_loss=True)\nals_model.fit(csr_data.T)\n\n# 🔹 추천 시스템 - 이미지 갤러리 표시\ndef show_recommendations(input_id, is_user=True, N=10):\n    \"\"\" 사용자가 구매할 만한 추천 아이템 또는 특정 제품과 유사한 제품을 갤러리로 표시 \"\"\"\n    if is_user:\n        if input_id not in user_to_idx:\n            print(\"사용자 ID를 찾을 수 없습니다.\")\n            return\n        user_idx = user_to_idx[input_id]\n        recommended = als_model.recommend(user_idx, csr_data, N=N)\n        recommended_articles = [idx_to_article[i[0]] for i in recommended]\n    else:\n        if input_id not in article_to_idx:\n            print(\"상품 ID를 찾을 수 없습니다.\")\n            return\n        article_idx = article_to_idx[input_id]\n        similar_items = als_model.similar_items(article_idx, N=N)\n        recommended_articles = [idx_to_article[i[0]] for i in similar_items]\n    \n    # 추천 아이템 정보 가져오기\n    recommended_df = articles[articles['article_id'].isin(recommended_articles)]\n    \n    # 🔹 이미지 갤러리 출력\n    fig, axes = plt.subplots(1, len(recommended_df), figsize=(15, 5))\n    if len(recommended_df) == 1:\n        axes = [axes]  # 리스트로 변환\n    for ax, (_, row) in zip(axes, recommended_df.iterrows()):\n        img_path = f\"../input/h-and-m-personalized-fashion-recommendations/images/{row['image_path']}\"\n        \n        try:\n            img = plt.imread(img_path)\n            ax.imshow(img)\n        except FileNotFoundError:\n            ax.text(0.5, 0.5, \"No Image\", fontsize=12, ha='center', va='center')\n\n        ax.set_title(row['prod_name'][:15])\n        ax.axis(\"off\")\n    plt.show()\n\n# 사용 예시\n# show_recommendations('000058a12d5b43e67d225668fa1f8d618c13dc232df0cad8ffe7ad4a1091e318', is_user=True)\n# show_recommendations('176209023', is_user=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-07T06:39:32.109379Z","iopub.execute_input":"2025-03-07T06:39:32.109779Z","iopub.status.idle":"2025-03-07T06:42:01.284859Z","shell.execute_reply.started":"2025-03-07T06:39:32.109745Z","shell.execute_reply":"2025-03-07T06:42:01.284031Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"show_recommendations('000058a12d5b43e67d225668fa1f8d618c13dc232df0cad8ffe7ad4a1091e318', is_user=True)\n# show_recommendations(176209023, is_user=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-07T06:42:01.286037Z","iopub.execute_input":"2025-03-07T06:42:01.286202Z","iopub.status.idle":"2025-03-07T06:42:03.470172Z","shell.execute_reply.started":"2025-03-07T06:42:01.286181Z","shell.execute_reply":"2025-03-07T06:42:03.469410Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"show_recommendations('176209023', is_user=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-07T06:44:29.756750Z","iopub.execute_input":"2025-03-07T06:44:29.757351Z","iopub.status.idle":"2025-03-07T06:44:31.964460Z","shell.execute_reply.started":"2025-03-07T06:44:29.757316Z","shell.execute_reply":"2025-03-07T06:44:31.963703Z"}},"outputs":[],"execution_count":null}]}