{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":31254,"databundleVersionId":3103714,"sourceType":"competition"}],"dockerImageVersionId":31040,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transactions = pd.read_csv('/kaggle/input/h-and-m-personalized-fashion-recommendations/transactions_train.csv',dtype={\n        'article_id': 'category',\n        'customer_id': 'category',\n        'price': 'float32'\n    },\n    parse_dates=['t_dat'])\narticles = pd.read_csv('/kaggle/input/h-and-m-personalized-fashion-recommendations/articles.csv',dtype={'customer_id': 'category'})\ncustomers = pd.read_csv('/kaggle/input/h-and-m-personalized-fashion-recommendations/customers.csv',dtype={'article_id': 'category'})\n\n#Verify loading\nprint(\"Transactions shape:\", transactions.shape)\nprint(\"Customers shape:\", customers.shape)\nprint(\"Articles shape:\", articles.shape)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Handle missing values in customers\ncustomers['FN'] = customers['FN'].fillna(0).astype('int8')\ncustomers['Active'] = customers['Active'].fillna(0).astype('int8')\ncustomers['club_member_status'] = customers['club_member_status'].fillna('UNKNOWN')\ncustomers['fashion_news_frequency'] = customers['fashion_news_frequency'].replace('None', 'NONE').fillna('NONE')\n\n# Clean articles data\narticles['detail_desc'] = articles['detail_desc'].fillna('Not Available')\n\n# Merge datasets\nmerged_data = transactions.merge(customers, on='customer_id', how='left')\nmerged_data = merged_data.merge(articles, on='article_id', how='left')\n\n# Check merged data\nprint(\"\\nMerged data shape:\", merged_data.shape)\nprint(\"Missing values after merge:\")\nprint(merged_data.isnull().sum())","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Product popularity features\nproduct_popularity = transactions.groupby('article_id', observed=True).agg(\n    total_purchases=('customer_id', 'count'),\n    unique_customers=('customer_id', 'nunique')\n).reset_index()\nproduct_popularity['popularity_rank'] = product_popularity['total_purchases'].rank(ascending=False, method='dense')\n\n# Customer activity features\ncustomer_activity = transactions.groupby('customer_id', observed=True).agg(\n    purchase_count=('t_dat', 'count'),\n    first_purchase=('t_dat', 'min'),\n    last_purchase=('t_dat', 'max'),\n    avg_price=('price', 'mean')\n).reset_index()\ncustomer_activity['purchase_frequency'] = customer_activity['purchase_count'] / (customer_activity['last_purchase'] - customer_activity['first_purchase']).dt.days\n\n# Product age features\ncurrent_date = transactions['t_dat'].max()\nproduct_age = transactions.groupby('article_id', observed=True)['t_dat'].min().reset_index()\nproduct_age['product_age_days'] = (current_date - product_age['t_dat']).dt.days\n\nprint(\"\\nFeature engineering completed:\")\nprint(\"- Product features:\", product_popularity.shape)\nprint(\"- Customer features:\", customer_activity.shape)\nprint(\"- Product age features:\", product_age.shape)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Prepare Data for Modeling\nimport numpy as np\nfrom scipy.sparse import csr_matrix\nfrom sklearn.model_selection import train_test_split\n\n#Create user-item interaction matrix (binary)\nuser_ids = transactions['customer_id'].astype('category').cat.codes\nitem_ids = transactions['article_id'].astype('category').cat.codes\n\ninteraction_matrix = csr_matrix(\n    (np.ones(len(transactions), (user_ids, item_ids)),\n    shape=(len(user_ids.unique()), len(item_ids.unique()))\n)\n\n#Split data\ntrain_matrix, test_matrix = train_test_split(\n    interaction_matrix, \n    test_size=0.2,\n    random_state=42\n)\n\n#Baseline Models\nfrom collections import defaultdict\n\n#Popularity Model\ndef popularity_model(transactions, n_recommendations=12):\n    top_items = transactions['article_id'].value_counts().head(n_recommendations).index.tolist()\n    return {user: top_items for user in transactions['customer_id'].unique()}\n\npopularity_recs = popularity_model(transactions)\n\n#Recent Popularity Model\ndef recent_popularity_model(transactions, days=30, n_recommendations=12):\n    recent_date = transactions['t_dat'].max()\n    recent_trans = transactions[transactions['t_dat'] >= (recent_date - pd.Timedelta(days=days)]\n    top_items = recent_trans['article_id'].value_counts().head(n_recommendations).index.tolist()\n    return {user: top_items for user in transactions['customer_id'].unique()}\n\nrecent_recs = recent_popularity_model(transactions)\n\n#Collaborative Filtering Models\nfrom lightfm import LightFM\nfrom lightfm.evaluation import precision_at_k, recall_at_k\n\n#Initialize model\nmodel = LightFM(\n    loss='warp',  # Weighted Approximate-Rank Pairwise\n    no_components=30,\n    user_alpha=0.0001,\n    item_alpha=0.0001\n)\n\n#Train model\nmodel.fit(\n    train_matrix,\n    epochs=20,\n    num_threads=4,\n    verbose=True\n)\n\n#Model Evaluation\ntrain_precision = precision_at_k(model, train_matrix, k=12).mean()\ntest_precision = precision_at_k(model, test_matrix, k=12).mean()\n\nprint(f\"\\nModel Performance:\")\nprint(f\"Train Precision@12: {train_precision:.4f}\")\nprint(f\"Test Precision@12: {test_precision:.4f}\")\n\n#Generate Recommendations\ndef generate_recommendations(model, user_ids, item_ids, n=12):\n    all_items = np.arange(interaction_matrix.shape[1])\n    user_codes = {user: code for code, user in enumerate(user_ids.cat.categories)}\n    \n    recommendations = {}\n    for user, user_code in tqdm(user_codes.items()):\n        scores = model.predict(user_code, all_items)\n        top_items = np.argsort(-scores)[:n]\n        recommendations[user] = item_ids.cat.categories[top_items].tolist()\n    \n    return recommendations\n\ncf_recs = generate_recommendations(model, user_ids, item_ids)\n\n#Hybrid Recommendations\ndef hybrid_recommendation(user, cf_recs, pop_recs, weight=0.7):\n    \"\"\"Combine collaborative filtering and popularity\"\"\"\n    cf_items = cf_recs.get(user, [])\n    pop_items = pop_recs.get(user, [])\n    \n    #Take top from CF, fill remainder with popular items\n    n_cf = int(12 * weight)\n    recommendations = cf_items[:n_cf] + pop_items[:12-n_cf]\n    return recommendations[:12]  # Ensure exactly 12\n\n#Create final recommendations\nfinal_recs = {\n    user: hybrid_recommendation(user, cf_recs, popularity_recs)\n    for user in transactions['customer_id'].unique()[:10000]  # Sample for demo\n}\n\n#Save Results\nimport json\n\nwith open('recommendations.json', 'w') as f:\n    json.dump(final_recs, f)\n\n#Create Kaggle submission format\nsubmission = pd.DataFrame({\n    'customer_id': final_recs.keys(),\n    'prediction': [' '.join(map(str, items)) for items in final_recs.values()]\n})\nsubmission.to_csv('submission.csv', index=False)\n\nprint(\"\\nRecommendations generated and saved!\")\nprint(f\"Total users processed: {len(final_recs)}\")\nprint(f\"Sample recommendation: {next(iter(final_recs.items()))}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}