{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceType":"competition","sourceId":8540,"databundleVersionId":862041}],"dockerImageVersionId":31234,"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\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.metrics import roc_auc_score\nimport lightgbm as lg\n# Для отображения всех столбцов (если их много)\npd.set_option('display.max_columns', None)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-24T15:01:32.902902Z","iopub.execute_input":"2026-02-24T15:01:32.904457Z","iopub.status.idle":"2026-02-24T15:01:32.910669Z","shell.execute_reply.started":"2026-02-24T15:01:32.904409Z","shell.execute_reply":"2026-02-24T15:01:32.909234Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Основной тестовый набор\ntest = pd.read_csv('/kaggle/input/talkingdata-adtracking-fraud-detection/test.csv')\nprint(\"test.csv\")\nprint(f\"Строк: {test.shape[0]}, столбцов: {test.shape[1]}\")\nprint(\"\\nПервые 5 строк:\")\nprint(test.head())\nprint(\"\\nПропуски:\")\nprint(test.isnull().sum())\nprint(\"\\nТипы данных:\")\nprint(test.dtypes)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-24T15:01:35.584426Z","iopub.execute_input":"2026-02-24T15:01:35.584788Z","iopub.status.idle":"2026-02-24T15:01:55.623024Z","shell.execute_reply.started":"2026-02-24T15:01:35.584761Z","shell.execute_reply":"2026-02-24T15:01:55.621467Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Полный обучающий набор\ntrain = pd.read_csv('/kaggle/input/talkingdata-adtracking-fraud-detection/train.csv')\nprint(\"train.csv\")\nprint(f\"Строк: {train.shape[0]}, столбцов: {train.shape[1]}\")\nprint(\"\\nПервые 5 строк:\")\nprint(train.head())\nprint(\"\\nЦелевая переменная (is_attributed):\")\nprint(train['is_attributed'].value_counts(normalize=True))\nprint(\"\\nПропуски:\")\nprint(train.isnull().sum())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-24T15:09:09.399624Z","iopub.execute_input":"2026-02-24T15:09:09.40002Z","iopub.status.idle":"2026-02-24T15:09:14.991793Z","shell.execute_reply.started":"2026-02-24T15:09:09.399992Z","shell.execute_reply":"2026-02-24T15:09:14.990468Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\n\n# --- ШАГ 1: ПОШАГОВОЕ ЧТЕНИЕ TRAIN.CSV ДО 1 МЛН СТРОК ---\nprint(\"Читаем train.csv по частям до набора 1 млн строк...\")\nchunk_size = 100_000  # Читаем частями по 100 тыс.\ntarget_size = 1_000_000\nchunks = []\n\nfor chunk in pd.read_csv(\n    '/kaggle/input/talkingdata-adtracking-fraud-detection/train.csv',\n    chunksize=chunk_size,\n    parse_dates=['click_time']\n):\n    chunks.append(chunk)\n    if sum(len(c) for c in chunks) >= target_size:\n        break\n\ntrain_full = pd.concat(chunks, ignore_index=True)\nprint(f\"Загружено {len(train_full)} строк\")\n\n\n# --- ШАГ 2: СТРАТИФИЦИРОВАННАЯ ВЫБОРКА 1 МЛН ВРУЧНУЮ ---\nprint(\"Делаем стратифицированную выборку 1 млн...\")\ntarget_fraud_ratio = train_full['is_attributed'].mean()\nn_fraud = int(target_size * target_fraud_ratio)\nn_non_fraud = target_size - n_fraud\n\n\nfraud_rows = train_full[train_full['is_attributed'] == 1]\nnon_fraud_rows = train_full[train_full['is_attributed'] == 0]\n\nsampled_fraud = fraud_rows.sample(n=n_fraud, random_state=42)\nsampled_non_fraud = non_fraud_rows.sample(n=n_non_fraud, random_state=42)\n\n\ntrain = pd.concat([sampled_fraud, sampled_non_fraud], axis=0).reset_index(drop=True)\nprint(f\"Выбрано {len(train)} строк. Доля fraud: {train['is_attributed'].mean():.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-24T15:09:18.732514Z","iopub.execute_input":"2026-02-24T15:09:18.733244Z","iopub.status.idle":"2026-02-24T15:09:20.869699Z","shell.execute_reply.started":"2026-02-24T15:09:18.733201Z","shell.execute_reply":"2026-02-24T15:09:20.868514Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Далее — ваш код (шаги 3–14 без изменений)\n\n\n# Удаляем attributed_time (почти все NaN)\ntrain = train.drop('attributed_time', axis=1)\n\n\n# --- ШАГ 3: ВРЕМЕННЫЕ ПРИЗНАКИ ---\ntrain['hour'] = train['click_time'].dt.hour\ntrain['day_of_week'] = train['click_time'].dt.dayofweek\ntrain['day_of_month'] = train['click_time'].dt.day\ntrain = train.drop('click_time', axis=1)\n\n# --- ШАГ 4: COUNT-ПРИЗНАКИ ДЛЯ КАТЕГОРИЙ ---\nfor col in ['ip', 'app', 'device', 'os', 'channel']:\n    count_map = train[col].value_counts()\n    train[f'{col}_count'] = train[col].map(count_map)\n\n\n# --- ШАГ 5: СГЛАЖЕННОЕ ЦЕЛЕВОЕ КОДИРОВАНИЕ ---\ndef smooth_target_encode(df, col, target='is_attributed', prior=0.001):\n    mean = df.groupby(col)[target].mean()\n    count = df[col].value_counts()\n    smooth = (mean * count + prior) / (count + 1)\n    return smooth\n\nencoding_maps = {}  # Для сохранения маппингов\nfor col in ['ip', 'app', 'channel']:\n    encoding_maps[col] = smooth_target_encode(train, col).to_dict()\n    train[f'{col}_target_enc'] = train[col].map(encoding_maps[col])\n\n\n# --- ШАГ 6: КОМБИНАЦИИ КАТЕГОРИЙ ---\ntrain['app_channel'] = train['app'].astype(str) + '_' + train['channel'].astype(str)\ntrain['ip_app'] = train['ip'].astype(str) + '_' + train['app'].astype(str)\n\nfor combo in ['app_channel', 'ip_app']:\n    combo_count = train[combo].value_counts()\n    train[f'{combo}_count'] = train[combo].map(combo_count)\n\n\n# --- ШАГ 7: ФОРМИРОВАНИЕ ПРИЗНАКОВ И ЦЕЛЕВОЙ ПЕРЕМЕННОЙ ---\nfeatures = [\n    'app', 'device', 'os', 'channel',\n    'hour', 'day_of_week', 'day_of_month',\n    'ip_count', 'app_count', 'channel_count',\n    'ip_target_enc', 'app_target_enc', 'channel_target_enc',\n    'app_channel_count', 'ip_app_count'\n]\n\nX = train[features]\ny = train['is_attributed']\nX = X.fillna(0)  # Заполняем пропуски","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-24T15:09:26.981898Z","iopub.execute_input":"2026-02-24T15:09:26.982822Z","iopub.status.idle":"2026-02-24T15:09:30.241Z","shell.execute_reply.started":"2026-02-24T15:09:26.982789Z","shell.execute_reply":"2026-02-24T15:09:30.240097Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- ШАГ 8: РАЗДЕЛЕНИЕ НА TRAIN/VAL ---\nfrom sklearn.model_selection import train_test_split\nX_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)\n\n\n# --- ШАГ 9: ОБУЧЕНИЕ МОДЕЛЕЙ ---\nfrom xgboost import XGBClassifier\nfrom catboost import CatBoostClassifier\nfrom sklearn.metrics import roc_auc_score\nfrom sklearn.model_selection import cross_val_score\n\n# XGBoost\nmodel_xgboost = XGBClassifier(\n    scale_pos_weight=439,\n    eval_metric='auc',\n    verbosity=0\n)\nmodel_xgboost.fit(X_train, y_train)\npred_xgboost = model_xgboost.predict_proba(X_val)[:, 1]\nprint(f\"AUC XGBoost (валидация): {roc_auc_score(y_val, pred_xgboost):.4f}\")\n\n\n# Кросс-валидация XGBoost\ncv_scores_xgboost = cross_val_score(model_xgboost, X, y, cv=5, scoring='roc_auc')\nprint(f\"AUC XGBoost (кросс-валидация, среднее): {cv_scores_xgboost.mean():.4f} (+/- {cv_scores_xgboost.std() * 2:.4f})\")\n\n# CatBoost\nmodel_catboost = CatBoostClassifier(\n    scale_pos_weight=439,\n    eval_metric='AUC',\n    verbose=0,\n    random_state=42\n)\nmodel_catboost.fit(X_train, y_train)\npred_catboost = model_catboost.predict_proba(X_val)[:, 1]\nprint(f\"AUC CatBoost (валидация): {roc_auc_score(y_val, pred_catboost):.4f}\")\n\n# Кросс-валидация CatBoost\ncv_scores_catboost = cross_val_score(model_catboost, X, y, cv=5, scoring='roc_auc')\nprint(f\"AUC CatBoost (кросс-валидация, среднее): {cv_scores_catboost.mean():.4f} (+/- {cv_scores_catboost.std() * 2:.4f})\")\n\n# --- ШАГ 10: ОБРАБОТКА ТЕСТА ---\ntest = pd.read_csv('/kaggle/input/talkingdata-adtracking-fraud-detection/test.csv', parse_dates=['click_time'])\n\n\n# Временные признаки\ntest['hour'] = test['click_time'].dt.hour\ntest['day_of_week'] = test['click_time'].dt.dayofweek\ntest['day_of_month'] = test['click_time'].dt.day\ntest = test.drop('click_time', axis=1)\n\n# COUNT-признаки (используем мап из train)\nfor col in ['ip', 'app', 'device', 'os', 'channel']:\n    count_map = train[col].value_counts()\n    test[f'{col}_count'] = test[col].map(count_map).fillna(0)\n\n# Целевое кодирование (используем сохранённые маппинги)\nfor col in ['ip', 'app', 'channel']:\n    test[f'{col}_target_enc'] = test[col].map(encoding_maps[col]).fillna(0)\n\n# Комбинации категорий\ntest['app_channel'] = test['app'].astype(str) + '_' + test['channel'].astype(str)\ntest['ip_app'] = test['ip'].astype(str) + '_' + test['app'].astype(str)\n\n\n# ... предыдущий код (до места остановки)\n\nfor combo in ['app_channel', 'ip_app']:\n    combo_count = train[combo].value_counts()  # Исправлено: добавлен вызов ()\n    test[f'{combo}_count'] = test[combo].map(combo_count).fillna(0)\n\n# --- ШАГ 11: ПОДГОТОВКА ПРИЗНАКОВ ДЛЯ ТЕСТА ---\nX_test = test[features]  # Используем тот же список признаков, что и для train\nX_test = X_test.fillna(0)  # Заполняем пропуски нулями\n\n# --- ШАГ 12: ПРЕДСКАЗАНИЯ НА ТЕСТЕ ---\nfrom sklearn.ensemble import VotingClassifier\n\n# Предсказания XGBoost\npred_test_xgboost = model_xgboost.predict_proba(X_test)[:, 1]\n\n# Предсказания CatBoost\npred_test_catboost = model_catboost.predict_proba(X_test)[:, 1]\n\n\n# Ансамбль: простое усреднение вероятностей\npred_test_ensemble = (pred_test_xgboost + pred_test_catboost) / 2\n\n# --- ШАГ 13: СОЗДАНИЕ САБМИШЕНА ---\nsubmission = pd.DataFrame({\n    'click_id': test['click_id'],\n    'is_attributed': pred_test_ensemble\n})\n\n# Проверяем корректность\nprint(f\"Размер сабмишена: {submission.shape}\")\nprint(f\"Мин. вероятность: {submission['is_attributed'].min():.6f}\")\nprint(f\"Макс. вероятность: {submission['is_attributed'].max():.6f}\")\nprint(f\"Среднее: {submission['is_attributed'].mean():.6f}\")\n\n# --- ШАГ 14: СОХРАНЕНИЕ РЕЗУЛЬТАТА ---\nsubmission.to_csv('submission.csv', index=False)\nprint(\"Сабмишен успешно сохранён в файл 'submission.csv'!\")\n\n# Дополнительно: сохраняем предсказания отдельно для анализа\nnp.save('pred_xgboost.npy', pred_test_xgboost)\nnp.save('pred_catboost.npy', pred_test_catboost)\nprint(\"Предсказания моделей сохранены в .npy файлы.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-24T15:09:38.431668Z","iopub.execute_input":"2026-02-24T15:09:38.432473Z","iopub.status.idle":"2026-02-24T15:20:02.803254Z","shell.execute_reply.started":"2026-02-24T15:09:38.432436Z","shell.execute_reply":"2026-02-24T15:20:02.802044Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- ДОПОЛНИТЕЛЬНЫЙ ШАГ: СОЗДАНИЕ ОТДЕЛЬНЫХ САБМИШЕНОВ ДЛЯ КАЖДОЙ МОДЕЛИ ---\n\nprint(\"Создаём отдельные сабмишены для каждой модели...\")\n\n\n# 1. Сабмишен для XGBoost\nsubmission_xgboost = pd.DataFrame({\n    'click_id': test['click_id'],\n    'is_attributed': pred_test_xgboost\n})\nsubmission_xgboost.to_csv('submission_xgboost.csv', index=False)\nprint(f\"Сабмишен XGBoost сохранён (размер: {submission_xgboost.shape})\")\n\n# 2. Сабмишен для CatBoost\nsubmission_catboost = pd.DataFrame({\n    'click_id': test['click_id'],\n    'is_attributed': pred_test_catboost\n})\nsubmission_catboost.to_csv('submission_catboost.csv', index=False)\nprint(f\"Сабмишен CatBoost сохранён (размер: {submission_catboost.shape})\")\n\n\n# 3. Сабмишен для ансамбля (уже есть, но дублируем вывод)\nprint(f\"Сабмишен ансамбля сохранён (размер: {submission.shape})\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f\"AUC XGBoost (валидация): {roc_auc_score(y_val, pred_xgboost):.4f}\")\nprint(f\"AUC CatBoost (валидация): {roc_auc_score(y_val, pred_catboost):.4f}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\n\n# Загружаем train (1 млн строк)\ntrain = pd.read_csv(\n    '/kaggle/input/talkingdata-adtracking-fraud-detection/train.csv',\n    nrows=1_000_000,\n    parse_dates=['click_time']\n)\n\nprint(f\"Размер: {train.shape}\")\nprint(f\"\\nТипы данных:\\n{train.dtypes}\")\nprint(f\"\\nПропуски:\\n{train.isnull().sum()}\")\nprint(f\"\\nДоля fraud: {train['is_attributed'].mean():.4%}\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\n\nprint(\"Читаем train.csv и собираем статистику по дням...\")\nchunk_size = 100_000\ntarget_total = 1_000_000\n\n# Словарь для накопления статистики по дням\ndaily_stats = {}\n\nfor chunk in pd.read_csv(\n    '/kaggle/input/talkingdata-adtracking-fraud-detection/train.csv',\n    chunksize=chunk_size,\n    parse_dates=['click_time'],\n    date_parser=lambda x: pd.to_datetime(x, format='%Y-%m-%d %H:%M:%S')\n):\n    # Добавляем столбец 'day'\n    chunk['day'] = chunk['click_time'].dt.date\n    \n    # Группируем по дням внутри чанка\n    chunk_stats = chunk.groupby('day').agg(\n        total_count=('is_attributed', 'count'),\n        fraud_count=('is_attributed', 'sum')\n    ).to_dict('index')\n    \n    # Обновляем общую статистику\n    for day, stats in chunk_stats.items():\n        if day not in daily_stats:\n            daily_stats[day] = {'total_count': 0, 'fraud_count': 0}\n        daily_stats[day]['total_count'] += stats['total_count']\n        daily_stats[day]['fraud_count'] += stats['fraud_count']\n\n# Преобразуем в DataFrame\ndaily_stats = pd.DataFrame.from_dict(daily_stats, orient='index').reset_index()\ndaily_stats.rename(columns={'index': 'day'}, inplace=True)\ndaily_stats['fraud_ratio'] = daily_stats['fraud_count'] / daily_stats['total_count']\n\nprint(f\"Собранная статистика по {len(daily_stats)} дням\")\n\n\n# --- ШАГ 2: СТРАТИФИЦИРОВАННАЯ ВЫБОРКА ПО ДНЯМ И ДОЛЕ FRAUD ---\nprint(\"Делаем стратифицированную выборку по дням и доле fraud...\")\n\n\nsampled_chunks = []\ndays = daily_stats['day'].tolist()\nn_days = len(days)\nbase_per_day = target_total // n_days\n\n\n# Повторно читаем файл чанками\nfor chunk in pd.read_csv(\n    '/kaggle/input/talkingdata-adtracking-fraud-detection/train.csv',\n    chunksize=chunk_size,\n    parse_dates=['click_time'],\n    date_parser=lambda x: pd.to_datetime(x, format='%Y-%m-%d %H:%M:%S')\n):\n    chunk['day'] = chunk['click_time'].dt.date\n    \n    # Для каждого дня в чанке\n    chunk_days = chunk['day'].unique()\n    for day in chunk_days:\n        if day not in days:\n            continue  # Пропускаем дни не из статистики\n        \n        day_data = chunk[chunk['day'] == day]\n        \n        # Получаем целевые числа fraud/non-fraud\n        day_info = daily_stats[daily_stats['day'] == day].iloc[0]\n        n_target = base_per_day\n        n_fraud = int(n_target * day_info['fraud_ratio'])\n        n_non_fraud = n_target - n_fraud\n        \n        if n_fraud == 0 and day_data[day_data['is_attributed'] == 1].shape[0] > 0:\n            n_fraud = 1\n            n_non_fraud -= 1\n        \n        \n        # Выборка\n        fraud_sample = day_data[day_data['is_attributed'] == 1].sample(\n            n=min(n_fraud, len(day_data[day_data['is_attributed'] == 1])),\n            random_state=42\n        )\n        non_fraud_sample = day_data[day_data['is_attributed'] == 0].sample(\n            n=min(n_non_fraud, len(day_data[day_data['is_attributed'] == 0])),\n            random_state=42\n        )\n        \n        sampled_day = pd.concat([fraud_sample, non_fraud_sample], axis=0)\n        sampled_chunks.append(sampled_day)\n\n# Объединяем только выбранные строки\ntrain = pd.concat(sampled_chunks, ignore_index=True)\nprint(f\"Выбрано {len(train)} строк. Доля fraud: {train['is_attributed'].mean():.4f}\")\n\ntrain = train.drop('day', axis=1)  # Удаляем временный столбец\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if len(train) > target_total:\n    train = train.sample(n=target_total, random_state=42)\ntrain['day'] = pd.to_datetime(train['click_time']).dt.date\nprint(train.groupby('day')['is_attributed'].mean())\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Далее — ваш код (шаги 3–14 без изменений)\n\n\n# Удаляем attributed_time (почти все NaN)\ntrain = train.drop('attributed_time', axis=1)\n\n\n# --- ШАГ 3: ВРЕМЕННЫЕ ПРИЗНАКИ ---\ntrain['hour'] = train['click_time'].dt.hour\ntrain['day_of_week'] = train['click_time'].dt.dayofweek\ntrain['day_of_month'] = train['click_time'].dt.day\ntrain = train.drop('click_time', axis=1)\n\n# --- ШАГ 4: COUNT-ПРИЗНАКИ ДЛЯ КАТЕГОРИЙ ---\nfor col in ['ip', 'app', 'device', 'os', 'channel']:\n    count_map = train[col].value_counts()\n    train[f'{col}_count'] = train[col].map(count_map)\n\n\n# --- ШАГ 5: СГЛАЖЕННОЕ ЦЕЛЕВОЕ КОДИРОВАНИЕ ---\ndef smooth_target_encode(df, col, target='is_attributed', prior=0.001):\n    mean = df.groupby(col)[target].mean()\n    count = df[col].value_counts()\n    smooth = (mean * count + prior) / (count + 1)\n    return smooth\n\nencoding_maps = {}  # Для сохранения маппингов\nfor col in ['ip', 'app', 'channel']:\n    encoding_maps[col] = smooth_target_encode(train, col).to_dict()\n    train[f'{col}_target_enc'] = train[col].map(encoding_maps[col])\n\n\n# --- ШАГ 6: КОМБИНАЦИИ КАТЕГОРИЙ ---\ntrain['app_channel'] = train['app'].astype(str) + '_' + train['channel'].astype(str)\ntrain['ip_app'] = train['ip'].astype(str) + '_' + train['app'].astype(str)\n\nfor combo in ['app_channel', 'ip_app']:\n    combo_count = train[combo].value_counts()\n    train[f'{combo}_count'] = train[combo].map(combo_count)\n\n\n# --- ШАГ 7: ФОРМИРОВАНИЕ ПРИЗНАКОВ И ЦЕЛЕВОЙ ПЕРЕМЕННОЙ ---\nfeatures = [\n    'app', 'device', 'os', 'channel',\n    'hour', 'day_of_week', 'day_of_month',\n    'ip_count', 'app_count', 'channel_count',\n    'ip_target_enc', 'app_target_enc', 'channel_target_enc',\n    'app_channel_count', 'ip_app_count'\n]\n\nX = train[features]\ny = train['is_attributed']\nX = X.fillna(0)  # Заполняем пропуски","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- ШАГ 8: РАЗДЕЛЕНИЕ НА TRAIN/VAL ---\nfrom sklearn.model_selection import train_test_split\nX_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)\n\n\n# --- ШАГ 9: ОБУЧЕНИЕ МОДЕЛЕЙ ---\nfrom xgboost import XGBClassifier\nfrom catboost import CatBoostClassifier\nfrom sklearn.metrics import roc_auc_score\nfrom sklearn.model_selection import cross_val_score\n\n# XGBoost\nmodel_xgboost = XGBClassifier(\n    scale_pos_weight=439,\n    eval_metric='auc',\n    verbosity=0\n)\nmodel_xgboost.fit(X_train, y_train)\npred_xgboost = model_xgboost.predict_proba(X_val)[:, 1]\nprint(f\"AUC XGBoost (валидация): {roc_auc_score(y_val, pred_xgboost):.4f}\")\n\n\n# Кросс-валидация XGBoost\ncv_scores_xgboost = cross_val_score(model_xgboost, X, y, cv=5, scoring='roc_auc')\nprint(f\"AUC XGBoost (кросс-валидация, среднее): {cv_scores_xgboost.mean():.4f} (+/- {cv_scores_xgboost.std() * 2:.4f})\")\n\n# CatBoost\nmodel_catboost = CatBoostClassifier(\n    scale_pos_weight=439,\n    eval_metric='AUC',\n    verbose=0,\n    random_state=42\n)\nmodel_catboost.fit(X_train, y_train)\npred_catboost = model_catboost.predict_proba(X_val)[:, 1]\nprint(f\"AUC CatBoost (валидация): {roc_auc_score(y_val, pred_catboost):.4f}\")\n\n# Кросс-валидация CatBoost\ncv_scores_catboost = cross_val_score(model_catboost, X, y, cv=5, scoring='roc_auc')\nprint(f\"AUC CatBoost (кросс-валидация, среднее): {cv_scores_catboost.mean():.4f} (+/- {cv_scores_catboost.std() * 2:.4f})\")\n\n# --- ШАГ 10: ОБРАБОТКА ТЕСТА ---\ntest = pd.read_csv('/kaggle/input/talkingdata-adtracking-fraud-detection/test.csv', parse_dates=['click_time'])\n\n\n# Временные признаки\ntest['hour'] = test['click_time'].dt.hour\ntest['day_of_week'] = test['click_time'].dt.dayofweek\ntest['day_of_month'] = test['click_time'].dt.day\ntest = test.drop('click_time', axis=1)\n\n# COUNT-признаки (используем мап из train)\nfor col in ['ip', 'app', 'device', 'os', 'channel']:\n    count_map = train[col].value_counts()\n    test[f'{col}_count'] = test[col].map(count_map).fillna(0)\n\n# Целевое кодирование (используем сохранённые маппинги)\nfor col in ['ip', 'app', 'channel']:\n    test[f'{col}_target_enc'] = test[col].map(encoding_maps[col]).fillna(0)\n\n# Комбинации категорий\ntest['app_channel'] = test['app'].astype(str) + '_' + test['channel'].astype(str)\ntest['ip_app'] = test['ip'].astype(str) + '_' + test['app'].astype(str)\n\n\n# ... предыдущий код (до места остановки)\n\nfor combo in ['app_channel', 'ip_app']:\n    combo_count = train[combo].value_counts()  # Исправлено: добавлен вызов ()\n    test[f'{combo}_count'] = test[combo].map(combo_count).fillna(0)\n\n# --- ШАГ 11: ПОДГОТОВКА ПРИЗНАКОВ ДЛЯ ТЕСТА ---\nX_test = test[features]  # Используем тот же список признаков, что и для train\nX_test = X_test.fillna(0)  # Заполняем пропуски нулями\n\n# --- ШАГ 12: ПРЕДСКАЗАНИЯ НА ТЕСТЕ ---\nfrom sklearn.ensemble import VotingClassifier\n\n# Предсказания XGBoost\npred_test_xgboost = model_xgboost.predict_proba(X_test)[:, 1]\n\n# Предсказания CatBoost\npred_test_catboost = model_catboost.predict_proba(X_test)[:, 1]\n\n\n# Ансамбль: простое усреднение вероятностей\npred_test_ensemble = (pred_test_xgboost + pred_test_catboost) / 2\n\n# --- ШАГ 13: СОЗДАНИЕ САБМИШЕНА ---\nsubmission = pd.DataFrame({\n    'click_id': test['click_id'],\n    'is_attributed': pred_test_ensemble\n})\n\n# Проверяем корректность\nprint(f\"Размер сабмишена: {submission.shape}\")\nprint(f\"Мин. вероятность: {submission['is_attributed'].min():.6f}\")\nprint(f\"Макс. вероятность: {submission['is_attributed'].max():.6f}\")\nprint(f\"Среднее: {submission['is_attributed'].mean():.6f}\")\n\n# --- ШАГ 14: СОХРАНЕНИЕ РЕЗУЛЬТАТА ---\nsubmission.to_csv('submission.csv', index=False)\nprint(\"Сабмишен успешно сохранён в файл 'submission.csv'!\")\n\n# Дополнительно: сохраняем предсказания отдельно для анализа\nnp.save('pred_xgboost.npy', pred_test_xgboost)\nnp.save('pred_catboost.npy', pred_test_catboost)\nprint(\"Предсказания моделей сохранены в .npy файлы.\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- ДОПОЛНИТЕЛЬНЫЙ ШАГ: СОЗДАНИЕ ОТДЕЛЬНЫХ САБМИШЕНОВ ДЛЯ КАЖДОЙ МОДЕЛИ ---\n\nprint(\"Создаём отдельные сабмишены для каждой модели...\")\n\n\n# 1. Сабмишен для XGBoost\nsubmission_xgboost = pd.DataFrame({\n    'click_id': test['click_id'],\n    'is_attributed': pred_test_xgboost\n})\nsubmission_xgboost.to_csv('submission_xgboost.csv', index=False)\nprint(f\"Сабмишен XGBoost сохранён (размер: {submission_xgboost.shape})\")\n\n# 2. Сабмишен для CatBoost\nsubmission_catboost = pd.DataFrame({\n    'click_id': test['click_id'],\n    'is_attributed': pred_test_catboost\n})\nsubmission_catboost.to_csv('submission_catboost.csv', index=False)\nprint(f\"Сабмишен CatBoost сохранён (размер: {submission_catboost.shape})\")\n\n\n# 3. Сабмишен для ансамбля (уже есть, но дублируем вывод)\nprint(f\"Сабмишен ансамбля сохранён (размер: {submission.shape})\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}