{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.17","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"tpu1vmV38","dataSources":[{"sourceId":105399,"databundleVersionId":12733338,"sourceType":"competition"}],"dockerImageVersionId":31042,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"## import libraries\n!pip install xgboost\nimport pandas as pd\nimport numpy as np\nfrom sklearn.model_selection import GroupShuffleSplit\nfrom sklearn.metrics import log_loss\nimport matplotlib.pyplot as plt\nimport xgboost as xgb","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:29:06.439123Z","iopub.execute_input":"2025-06-24T07:29:06.439514Z","iopub.status.idle":"2025-06-24T07:29:09.913369Z","shell.execute_reply.started":"2025-06-24T07:29:06.439483Z","shell.execute_reply":"2025-06-24T07:29:09.908999Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Global parameters\nTRAIN_SAMPLE_FRAC = 0.2  \nRANDOM_STATE = 42\nnp.random.seed(RANDOM_STATE)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:29:09.915405Z","iopub.execute_input":"2025-06-24T07:29:09.915681Z","iopub.status.idle":"2025-06-24T07:29:09.925232Z","shell.execute_reply.started":"2025-06-24T07:29:09.915651Z","shell.execute_reply":"2025-06-24T07:29:09.920767Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load parquet files\ntrain = pd.read_parquet('/kaggle/input/aeroclub-recsys-2025/train.parquet')\ntest = pd.read_parquet('/kaggle/input/aeroclub-recsys-2025/test.parquet')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:29:09.927150Z","iopub.execute_input":"2025-06-24T07:29:09.927393Z","iopub.status.idle":"2025-06-24T07:29:43.003264Z","shell.execute_reply.started":"2025-06-24T07:29:09.927368Z","shell.execute_reply":"2025-06-24T07:29:42.998612Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f\"Train shape: {train.shape}, Test shape: {test.shape}\")\nprint(f\"Unique ranker_ids in train: {train['ranker_id'].nunique():,}\")\nprint(f\"Selected rate: {train['selected'].mean():.3f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:29:43.006670Z","iopub.execute_input":"2025-06-24T07:29:43.006919Z","iopub.status.idle":"2025-06-24T07:29:44.373549Z","shell.execute_reply.started":"2025-06-24T07:29:43.006894Z","shell.execute_reply":"2025-06-24T07:29:44.367958Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"## sample by ranker_id\nif TRAIN_SAMPLE_FRAC < 1.0:\n    unique_rankers = train['ranker_id'].unique()\n    n_sample = int(len(unique_rankers) * TRAIN_SAMPLE_FRAC)\n    sampled_rankers = np.random.RandomState(RANDOM_STATE).choice(\n        unique_rankers, size=n_sample, replace=False\n    )\n    train = train[train['ranker_id'].isin(sampled_rankers)]\n    print(f\"Sampled train to {len(train):,} rows ({train['ranker_id'].nunique():,} groups)\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:29:44.374587Z","iopub.execute_input":"2025-06-24T07:29:44.374812Z","iopub.status.idle":"2025-06-24T07:29:54.841124Z","shell.execute_reply.started":"2025-06-24T07:29:44.374789Z","shell.execute_reply":"2025-06-24T07:29:54.836984Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Convert ranker_id to string for CatBoost for the process\ntrain['ranker_id'] = train['ranker_id'].astype(str)\ntest['ranker_id'] = test['ranker_id'].astype(str)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:29:54.843120Z","iopub.execute_input":"2025-06-24T07:29:54.843606Z","iopub.status.idle":"2025-06-24T07:29:55.062932Z","shell.execute_reply.started":"2025-06-24T07:29:54.843580Z","shell.execute_reply":"2025-06-24T07:29:55.057976Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define categorical features there \ncat_features = [\n    'nationality', 'searchRoute', 'corporateTariffCode',\n    # Leg 0 segments 0-1\n    'legs0_segments0_aircraft_code', 'legs0_segments0_arrivalTo_airport_city_iata',\n    'legs0_segments0_arrivalTo_airport_iata', 'legs0_segments0_departureFrom_airport_iata',\n    'legs0_segments0_marketingCarrier_code', 'legs0_segments0_operatingCarrier_code',\n    'legs0_segments1_aircraft_code', 'legs0_segments1_arrivalTo_airport_city_iata',\n    'legs0_segments1_arrivalTo_airport_iata', 'legs0_segments1_departureFrom_airport_iata',\n    'legs0_segments1_marketingCarrier_code', 'legs0_segments1_operatingCarrier_code',\n    # Leg 1 segments 0-1\n    'legs1_segments0_aircraft_code', 'legs1_segments0_arrivalTo_airport_city_iata',\n    'legs1_segments0_arrivalTo_airport_iata', 'legs1_segments0_departureFrom_airport_iata',\n    'legs1_segments0_marketingCarrier_code', 'legs1_segments0_operatingCarrier_code',\n    'legs1_segments1_aircraft_code', 'legs1_segments1_arrivalTo_airport_city_iata',\n    'legs1_segments1_arrivalTo_airport_iata', 'legs1_segments1_departureFrom_airport_iata',\n    'legs1_segments1_marketingCarrier_code', 'legs1_segments1_operatingCarrier_code'\n]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:29:55.063765Z","iopub.execute_input":"2025-06-24T07:29:55.063994Z","iopub.status.idle":"2025-06-24T07:29:55.075183Z","shell.execute_reply.started":"2025-06-24T07:29:55.063969Z","shell.execute_reply":"2025-06-24T07:29:55.070675Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def duration_to_minutes(duration_str):\n    \"\"\"Convert time format (HH:MM:SS) to minutes\"\"\"\n    if pd.isna(duration_str) or duration_str is None:\n        return np.nan\n    try:\n        parts = str(duration_str).split(':')\n        if len(parts) == 3:\n            hours, minutes, seconds = map(int, parts)\n            return hours * 60 + minutes + seconds / 60\n        return np.nan\n    except:\n        return np.nan\n\ndef create_features(df):\n    \"\"\"Create features for flight ranking\"\"\"\n    # Convert duration columns to minutes\n    duration_cols = ['legs0_duration', 'legs1_duration']\n    for leg in [0, 1]:\n        for seg in range(4):\n            duration_cols.append(f'legs{leg}_segments{seg}_duration')\n    \n    for col in duration_cols:\n        if col in df.columns:\n            df[col] = df[col].apply(duration_to_minutes)\n    \n    # Price features\n    df['price_per_tax'] = df['totalPrice'] / (df['taxes'] + 1)\n    df['tax_rate'] = df['taxes'] / (df['totalPrice'] + 1)\n    \n    # Duration features\n    df['total_duration'] = df['legs0_duration'].fillna(0) + df['legs1_duration'].fillna(0)\n    df['duration_ratio'] = df['legs0_duration'] / (df['legs1_duration'].fillna(df['legs0_duration']) + 1)\n    \n    # Count segments\n    for leg in [0, 1]:\n        segments = [f'legs{leg}_segments{i}_duration' for i in range(2)]\n        df[f'n_segments_leg{leg}'] = df[segments].notna().sum(axis=1)\n    df['total_segments'] = df['n_segments_leg0'] + df['n_segments_leg1']\n    \n    # Trip type\n    df['is_one_way'] = df['legs1_duration'].isna().astype(int)\n    \n    # Ranking features within group\n    df['price_rank'] = df.groupby('ranker_id')['totalPrice'].rank()\n    df['price_pct_rank'] = df.groupby('ranker_id')['totalPrice'].rank(pct=True)\n    df['duration_rank'] = df.groupby('ranker_id')['total_duration'].rank()\n    \n    # Binary features\n    df['frequentFlyer'] = pd.to_numeric(df['frequentFlyer'], errors='coerce').fillna(0)\n    df['is_vip_freq'] = ((df['isVip'] == 1) | (df['frequentFlyer'] == 1)).astype(int)\n    df['has_return'] = (~df['legs1_duration'].isna()).astype(int)\n    df['has_corporate_tariff'] = (~df['corporateTariffCode'].isna()).astype(int)\n    \n    # Baggage allowance\n    df['baggage_total'] = (df['legs0_segments0_baggageAllowance_quantity'].fillna(0) + \n                          df['legs1_segments0_baggageAllowance_quantity'].fillna(0))\n    \n    # Fees\n    df['total_fees'] = (df['miniRules0_monetaryAmount'].fillna(0) + \n                       df['miniRules1_monetaryAmount'].fillna(0))\n    df['has_fees'] = (df['total_fees'] > 0).astype(int)\n    df['fee_rate'] = df['total_fees'] / (df['totalPrice'] + 1)\n    \n    # Time features\n    for col in ['legs0_departureAt', 'legs0_arrivalAt', 'legs1_departureAt', 'legs1_arrivalAt']:\n        if col in df.columns:\n            df[col] = pd.to_datetime(df[col], errors='coerce')\n            df[f'{col}_hour'] = df[col].dt.hour\n            df[f'{col}_weekday'] = df[col].dt.weekday\n    \n    # Direct flight features\n    df['is_direct_leg0'] = (df['n_segments_leg0'] == 1).astype(int)\n    df['is_direct_leg1'] = (df['n_segments_leg1'] == 1).astype(int)\n    df['both_direct'] = (df['is_direct_leg0'] & df['is_direct_leg1']).astype(int)\n    \n    # Access features\n    df['has_access_tp'] = (df['pricingInfo_isAccessTP'] == 1).astype(int)\n    \n    # Handle categorical NaNs\n    for col in cat_features:\n        if col in df.columns:\n            if df[col].dtype.name == 'Int64':\n                df[col] = df[col].astype('Int64').astype(str).replace('<NA>', 'missing')\n            else:\n                df[col] = df[col].fillna('missing').astype(str)\n    \n    # Cabin class features\n    df['avg_cabin_class'] = df[['legs0_segments0_cabinClass', 'legs1_segments0_cabinClass']].mean(axis=1)\n    df['cabin_class_diff'] = df['legs0_segments0_cabinClass'] - df['legs1_segments0_cabinClass']\n    \n    return df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:29:55.077319Z","iopub.execute_input":"2025-06-24T07:29:55.077541Z","iopub.status.idle":"2025-06-24T07:29:55.098461Z","shell.execute_reply.started":"2025-06-24T07:29:55.077518Z","shell.execute_reply":"2025-06-24T07:29:55.093881Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# feature engineering applied\ntrain = create_features(train)\ntest = create_features(test)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:29:55.100094Z","iopub.execute_input":"2025-06-24T07:29:55.100533Z","iopub.status.idle":"2025-06-24T07:32:33.606279Z","shell.execute_reply.started":"2025-06-24T07:29:55.100508Z","shell.execute_reply":"2025-06-24T07:32:33.601349Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Columns excluded\nexclude_cols = ['Id', 'ranker_id', 'selected', 'profileId', 'requestDate',\n                'legs0_departureAt', 'legs0_arrivalAt', 'legs1_departureAt', 'legs1_arrivalAt',\n                'miniRules0_percentage', 'miniRules1_percentage',  # >90% missing\n                'frequentFlyer']  # Already processed\n\n# Exclude segment 2-3 columns (>98% missing)\nfor leg in [0, 1]:\n    for seg in [2, 3]:\n        for suffix in ['aircraft_code', 'arrivalTo_airport_city_iata', 'arrivalTo_airport_iata',\n                      'baggageAllowance_quantity', 'baggageAllowance_weightMeasurementType',\n                      'cabinClass', 'departureFrom_airport_iata', 'duration', 'flightNumber',\n                      'marketingCarrier_code', 'operatingCarrier_code', 'seatsAvailable']:\n            exclude_cols.append(f'legs{leg}_segments{seg}_{suffix}')\n\nfeature_cols = [col for col in train.columns if col not in exclude_cols]\ncat_features_final = [col for col in cat_features if col in feature_cols]\n\nprint(f\"Using {len(feature_cols)} features ({len(cat_features_final)} categorical)\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:32:33.608535Z","iopub.execute_input":"2025-06-24T07:32:33.608796Z","iopub.status.idle":"2025-06-24T07:32:33.619693Z","shell.execute_reply.started":"2025-06-24T07:32:33.608771Z","shell.execute_reply":"2025-06-24T07:32:33.615486Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Preparing data\nX_train = train[feature_cols]\ny_train = train['selected']\ngroups_train = train['ranker_id']\n\nX_test = test[feature_cols]\ngroups_test = test['ranker_id']\n\n# Group-based splited\ngss = GroupShuffleSplit(n_splits=1, test_size=0.2, random_state=RANDOM_STATE)\ntrain_idx, val_idx = next(gss.split(X_train, y_train, groups_train))\n\nX_tr, X_val = X_train.iloc[train_idx], X_train.iloc[val_idx]\ny_tr, y_val = y_train.iloc[train_idx], y_train.iloc[val_idx]\ngroups_tr, groups_val = groups_train.iloc[train_idx], groups_train.iloc[val_idx]\n\nprint(f\"Train: {len(X_tr):,} rows, Val: {len(X_val):,} rows, Test: {len(X_test):,} rows\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:32:33.622033Z","iopub.execute_input":"2025-06-24T07:32:33.622282Z","iopub.status.idle":"2025-06-24T07:32:45.780938Z","shell.execute_reply.started":"2025-06-24T07:32:33.622260Z","shell.execute_reply":"2025-06-24T07:32:45.775786Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Quick data exploration\nfig, axes = plt.subplots(1, 2, figsize=(12, 4))\n\n# Selection rate by price rank\ntrain_sample = train.sample(min(10000, len(train)))\nprice_rank_selection = train_sample.groupby('price_rank')['selected'].mean()\naxes[0].plot(price_rank_selection.index[:20], price_rank_selection.values[:20], marker='o')\naxes[0].set_xlabel('Price Rank within Group')\naxes[0].set_ylabel('Selection Rate')\naxes[0].set_title('Selection Rate by Price Rank')\n\n# Direct vs connecting flights\ndirect_selection = train.groupby('total_segments')['selected'].mean()\naxes[1].bar(direct_selection.index, direct_selection.values)\naxes[1].set_xlabel('Total Segments')\naxes[1].set_ylabel('Selection Rate')\naxes[1].set_title('Selection Rate by Number of Segments')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:32:45.783101Z","iopub.execute_input":"2025-06-24T07:32:45.783346Z","iopub.status.idle":"2025-06-24T07:32:46.420649Z","shell.execute_reply.started":"2025-06-24T07:32:45.783321Z","shell.execute_reply":"2025-06-24T07:32:46.416068Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# MOdel Training\nfor df in [X_tr, X_val, X_test]:\n    for col in df.columns:\n        if df[col].dtype == 'object' or str(df[col].dtype) == 'category':\n            df[col], _ = pd.factorize(df[col])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:32:46.422304Z","iopub.execute_input":"2025-06-24T07:32:46.422518Z","iopub.status.idle":"2025-06-24T07:33:07.804894Z","shell.execute_reply.started":"2025-06-24T07:32:46.422494Z","shell.execute_reply":"2025-06-24T07:33:07.799381Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"group_sizes_tr = groups_tr.value_counts().sort_index().tolist()\ngroup_sizes_val = groups_val.value_counts().sort_index().tolist()\n\ndtrain = xgb.DMatrix(X_tr, label=y_tr)\ndtrain.set_group(group_sizes_tr)\n\ndval = xgb.DMatrix(X_val, label=y_val)\ndval.set_group(group_sizes_val)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:33:07.806968Z","iopub.execute_input":"2025-06-24T07:33:07.807434Z","iopub.status.idle":"2025-06-24T07:33:10.933123Z","shell.execute_reply.started":"2025-06-24T07:33:07.807405Z","shell.execute_reply":"2025-06-24T07:33:10.923010Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"params = {\n    \"objective\": \"rank:pairwise\",\n    \"learning_rate\": 0.1,\n    \"max_depth\": 6,\n    \"eval_metric\": \"ndcg@3\",  # or \"map@3\"\n    \"random_state\": RANDOM_STATE,\n    \"tree_method\": \"hist\"  # Use 'gpu_hist' if GPU available\n}\n\nmodel = xgb.train(\n    params=params,\n    dtrain=dtrain,\n    num_boost_round=200,\n    evals=[(dtrain, \"train\"), (dval, \"val\")],\n    early_stopping_rounds=20,\n    verbose_eval=10\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:33:10.933971Z","iopub.execute_input":"2025-06-24T07:33:10.934305Z","iopub.status.idle":"2025-06-24T07:33:54.104789Z","shell.execute_reply.started":"2025-06-24T07:33:10.934273Z","shell.execute_reply":"2025-06-24T07:33:54.094153Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Model Evaluation\n# Test prediction\ndtest = xgb.DMatrix(X_test)\ntest_preds = model.predict(dtest)\n\n# Validation prediction for metric\ndval_full = xgb.DMatrix(X_val)\nval_preds = model.predict(dval_full)\n\n# Evaluation\ndef sigmoid(x):\n    return 1 / (1 + np.exp(-x / 10))\n\nval_df = pd.DataFrame({\n    'ranker_id': groups_val,\n    'pred': val_preds,\n    'selected': y_val\n})\n\ntop_preds = val_df.loc[val_df.groupby('ranker_id')['pred'].idxmax()]\ntop_preds['prob'] = sigmoid(top_preds['pred'])\n\nval_logloss = log_loss(top_preds['selected'], top_preds['prob'])\nval_accuracy = (top_preds['selected'] == 1).mean()\n\nprint(f\"Validation metrics:\")\nprint(f\"LogLoss: {val_logloss:.4f}\")\nprint(f\"Top-1 Accuracy: {val_accuracy:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:33:54.106998Z","iopub.execute_input":"2025-06-24T07:33:54.107348Z","iopub.status.idle":"2025-06-24T07:34:01.726108Z","shell.execute_reply.started":"2025-06-24T07:33:54.107321Z","shell.execute_reply":"2025-06-24T07:34:01.720849Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Feature importance\nimportance_dict = model.get_score(importance_type='gain')\nfeature_importance = pd.DataFrame({\n    'feature': list(importance_dict.keys()),\n    'importance': list(importance_dict.values())\n}).sort_values(by='importance', ascending=False)\n\n# Plot top 20 features\nplt.figure(figsize=(10, 8))\ntop_features = feature_importance.head(20)\nplt.barh(range(len(top_features)), top_features['importance'])\nplt.yticks(range(len(top_features)), top_features['feature'])\nplt.xlabel('Feature Importance (gain)')\nplt.title('Top 20 Most Important Features')\nplt.gca().invert_yaxis()\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:34:01.726928Z","iopub.execute_input":"2025-06-24T07:34:01.727199Z","iopub.status.idle":"2025-06-24T07:34:02.039278Z","shell.execute_reply.started":"2025-06-24T07:34:01.727172Z","shell.execute_reply":"2025-06-24T07:34:02.033630Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Generatng Predictions\ngroup_sizes_test = groups_test.value_counts().sort_index().tolist()\ndtest = xgb.DMatrix(X_test)\ndtest.set_group(group_sizes_test)\n\ntest_preds = model.predict(dtest)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:34:02.041892Z","iopub.execute_input":"2025-06-24T07:34:02.042188Z","iopub.status.idle":"2025-06-24T07:34:08.755714Z","shell.execute_reply.started":"2025-06-24T07:34:02.042160Z","shell.execute_reply":"2025-06-24T07:34:08.750490Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Creating submission\nsubmission = test[['Id', 'ranker_id']].copy()\nsubmission['pred_score'] = test_preds\n\n# Assigning ranks (1 = best option)\nsubmission['selected'] = submission.groupby('ranker_id')['pred_score'].rank(\n    ascending=False, method='first'\n).astype(int)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:34:08.758174Z","iopub.execute_input":"2025-06-24T07:34:08.758630Z","iopub.status.idle":"2025-06-24T07:34:12.005483Z","shell.execute_reply.started":"2025-06-24T07:34:08.758604Z","shell.execute_reply":"2025-06-24T07:34:12.000574Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Verify ranking integrity\nassert submission.groupby('ranker_id')['selected'].apply(\n    lambda x: sorted(x.tolist()) == list(range(1, len(x)+1))\n).all(), \"Invalid ranking!\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:34:12.006404Z","iopub.execute_input":"2025-06-24T07:34:12.006620Z","iopub.status.idle":"2025-06-24T07:34:14.587931Z","shell.execute_reply.started":"2025-06-24T07:34:12.006599Z","shell.execute_reply":"2025-06-24T07:34:14.582887Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Saving submission\n# submission[['Id', 'ranker_id', 'selected']].to_parquet('submission.parquet', index=False)\nsubmission[['Id', 'ranker_id', 'selected']].to_csv('submission_xgboost.csv', index=False)\nprint(f\"Submission saved. Shape: {submission.shape}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T07:34:14.589930Z","iopub.execute_input":"2025-06-24T07:34:14.590175Z","iopub.status.idle":"2025-06-24T07:34:26.701545Z","shell.execute_reply.started":"2025-06-24T07:34:14.590153Z","shell.execute_reply":"2025-06-24T07:34:26.695581Z"}},"outputs":[],"execution_count":null}]}