{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":101849,"databundleVersionId":13093295,"sourceType":"competition"}],"dockerImageVersionId":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# Ariel NeurIPS 2025 — 1000 Dâhi Beyni Tek Dosya Pipeline\n# Tek dosya: .py olarak çalıştırılabilir\n\nimport os\nimport gc\nimport math\nimport json\nimport time\nfrom pathlib import Path\nimport numpy as np\nimport pandas as pd\nfrom itertools import product\n\nfrom sklearn.model_selection import KFold\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.decomposition import PCA\nfrom sklearn.metrics import mean_squared_error\n\ntry:\n    import lightgbm as lgb\nexcept:\n    lgb = None\ntry:\n    import xgboost as xgb\nexcept:\n    xgb = None\ntry:\n    import torch\n    import torch.nn as nn\n    from torch.utils.data import Dataset, DataLoader\nexcept:\n    torch = None\n\nSEED = 2025\nnp.random.seed(SEED)\nDATA_DIR = Path('/kaggle/input/ariel-data-challenge-2025')\nOUT_DIR = Path('./working')\nOUT_DIR.mkdir(parents=True, exist_ok=True)\n\n# ---------------- Seed & reproducibility ----------------\ndef seed_everything(seed=SEED):\n    np.random.seed(seed)\n    import random\n    random.seed(seed)\n    if torch is not None:\n        torch.manual_seed(seed)\n        torch.cuda.manual_seed_all(seed)\n        torch.backends.cudnn.deterministic=True\n        torch.backends.cudnn.benchmark=False\n\nseed_everything(SEED)\n\n# ---------------- Gaussian Log-Likelihood ----------------\ndef gaussian_log_likelihood(y_true, mu, sigma, eps=1e-8, axis=-1):\n    sigma = np.maximum(sigma, eps)\n    term = -0.5*(np.log(2*np.pi)+2*np.log(sigma)+((y_true-mu)/sigma)**2)\n    return term.sum(axis=axis)\n\ndef compute_competition_L(y_true, mu_pred, sigma_pred, channel_weights=None):\n    if channel_weights is None:\n        channel_weights=np.ones(y_true.shape[1])\n    cw = np.array(channel_weights)/(np.sum(channel_weights)+1e-12)\n    per_pixel = -0.5*(np.log(2*np.pi)+2*np.log(np.maximum(sigma_pred,1e-8))+((y_true-mu_pred)/np.maximum(sigma_pred,1e-8))**2)\n    weighted = per_pixel*cw[np.newaxis,:]\n    return weighted.sum()\n\n# ---------------- Submission writer ----------------\ndef write_submission(planet_ids, mu_preds, sigma_preds, out_path:Path):\n    n = len(planet_ids)\n    arr = np.hstack([planet_ids.reshape(-1,1), mu_preds, sigma_preds])\n    cols = ['planet_id'] + [f'mu_{i}' for i in range(mu_preds.shape[1])] + [f'sigma_{i}' for i in range(sigma_preds.shape[1])]\n    df = pd.DataFrame(arr, columns=cols)\n    df['planet_id'] = df['planet_id'].astype(object)\n    df.to_csv(out_path/'submission.csv', index=False)\n    print('submission.csv written to', out_path/'submission.csv')\n\n# ---------------- Spectral preprocessing ----------------\nfrom scipy.signal import savgol_filter, medfilt\nfrom scipy.ndimage import median_filter\n\ndef basic_savgol_transform(arr, window=11, poly=3):\n    if arr.ndim==1:\n        return savgol_filter(arr, window_length=min(window, arr.shape[0]//2*2+1), polyorder=poly)\n    else:\n        out=np.zeros_like(arr)\n        for i in range(arr.shape[0]):\n            w=min(window, arr.shape[1]//2*2+1)\n            out[i]=savgol_filter(arr[i], window_length=w, polyorder=poly)\n        return out\n\ndef common_mode_subtraction(obs_matrix, method='median'):\n    if method=='median': common=np.median(obs_matrix, axis=0)\n    elif method=='mean': common=np.mean(obs_matrix, axis=0)\n    else: common=PCA(n_components=1).fit_transform(obs_matrix.T).flatten()\n    cleaned=obs_matrix-common[np.newaxis,:]\n    return cleaned, common\n\ndef poly_detrend_vector(vec, degree=3):\n    x=np.arange(len(vec))\n    coeffs=np.polyfit(x, vec, deg=degree)\n    baseline=np.polyval(coeffs, x)\n    return vec-baseline, baseline\n\ndef denoise_spectrum(vec, method='combined', savgol_window=11, savgol_poly=3, medfilt_kernel=3):\n    if method=='savgol':\n        return savgol_filter(vec, window_length=min(savgol_window,len(vec)//2*2+1), polyorder=savgol_poly)\n    elif method=='med':\n        k=min(medfilt_kernel,len(vec) if len(vec)%2==1 else len(vec)-1)\n        return medfilt(vec, kernel_size=k)\n    else:\n        filtered=medfilt(vec,kernel_size=medfilt_kernel)\n        return savgol_filter(filtered, window_length=min(savgol_window,len(vec)//2*2+1), polyorder=savgol_poly)\n\ndef spectral_derivatives(vec):\n    v=np.asarray(vec)\n    first=np.gradient(v)\n    second=np.gradient(first)\n    return first, second\n\ndef log_ratio_features(vec, eps=1e-9):\n    v=np.maximum(vec, eps)\n    cont=median_filter(v, size=max(3,len(v)//100))\n    lr=np.log(v/(cont+eps))\n    return lr, cont\n\ndef aggregate_visits(visits_matrix, method='weighted_mean', weights=None):\n    if method=='median': return np.median(visits_matrix, axis=0)\n    elif method=='mean': return np.mean(visits_matrix, axis=0)\n    elif method=='weighted_mean':\n        if weights is None: var=np.var(visits_matrix, axis=0); weights=1.0/(var+1e-12)\n        else: weights=np.array(weights)\n        return np.average(visits_matrix, axis=0, weights=weights)\n\n# ---------------- PyTorch MLP heteroscedastic ----------------\nif torch is not None:\n    class SpectraDataset(Dataset):\n        def __init__(self, X, y=None):\n            self.X=X.astype(np.float32)\n            self.y=None if y is None else y.astype(np.float32)\n        def __len__(self):\n            return len(self.X)\n        def __getitem__(self, idx):\n            if self.y is None:\n                return self.X[idx]\n            return self.X[idx], self.y[idx]\n\n    class HeteroNet(nn.Module):\n        def __init__(self, in_dim, hidden=[512,256], out_dim=283):\n            super().__init__()\n            layers=[]\n            d=in_dim\n            for h in hidden:\n                layers.append(nn.Linear(d,h))\n                layers.append(nn.ReLU())\n                layers.append(nn.BatchNorm1d(h))\n                d=h\n            self.body=nn.Sequential(*layers)\n            self.mu_head=nn.Linear(d,out_dim)\n            self.log_sigma_head=nn.Linear(d,out_dim)\n        def forward(self,x):\n            h=self.body(x)\n            mu=self.mu_head(h)\n            sigma=torch.exp(self.log_sigma_head(h))\n            return mu, sigma\n\n    def hetero_loss(mu, sigma, y, eps=1e-8):\n        sigma=torch.clamp(sigma, min=eps)\n        loss=0.5*(torch.log(2*math.pi)+2*torch.log(sigma)+((y-mu)/sigma)**2)\n        return loss.mean()\n\n# ---------------- Ensemble configs ----------------\ndef generate_model_configs():\n    configs=[]\n    model_types=['lgb','xgb','mlp']; seeds=[2025,42,7,123]\n    lgb_params=[{'num_leaves':31,'learning_rate':0.05,'n_estimators':500},{'num_leaves':63,'learning_rate':0.03,'n_estimators':800}]\n    xgb_params=[{'max_depth':6,'eta':0.05,'nrounds':500},{'max_depth':8,'eta':0.03,'nrounds':700}]\n    mlp_params=[{'hidden':[512,256],'lr':1e-3,'epochs':30},{'hidden':[256,128],'lr':5e-4,'epochs':40}]\n    for mtype in model_types:\n        for seed in seeds:\n            if mtype=='lgb':\n                for p in lgb_params: configs.append({'type':'lgb','seed':seed,'params':p})\n            elif mtype=='xgb':\n                for p in xgb_params: configs.append({'type':'xgb','seed':seed,'params':p})\n            else:\n                for p in mlp_params: configs.append({'type':'mlp','seed':seed,'params':p})\n    return configs\n\nMODEL_CONFIGS=generate_model_configs()\nprint('Generated', len(MODEL_CONFIGS), 'model configs')\n\n# ---------------- OOF LightGBM ----------------\ndef run_oof_lightgbm(X,Y,n_splits=5,params=None):\n    n_targets=Y.shape[1]\n    oof_mu=np.zeros_like(Y); oof_sigma=np.zeros_like(Y)\n    kf=KFold(n_splits=n_splits, shuffle=True, random_state=SEED)\n    \n    for fold,(tr_idx,val_idx) in enumerate(kf.split(X)):\n        X_tr,X_val=X[tr_idx],X[val_idx]\n        Y_tr,Y_val=Y[tr_idx],Y[val_idx]\n        \n        for t in range(n_targets):\n            y_tr=Y_tr[:,t]; y_val=Y_val[:,t]\n            \n            if lgb is not None:\n                dtrain=lgb.Dataset(X_tr, label=y_tr)\n                dval=lgb.Dataset(X_val, label=y_val, reference=dtrain)\n                param=params or {'objective':'regression','metric':'rmse','verbosity':-1}\n                \n                bst=lgb.train(param, dtrain, num_boost_round=500,\n                              valid_sets=[dval],\n                              callbacks=[lgb.early_stopping(30), lgb.log_evaluation(0)])\n                \n                oof_mu[val_idx,t]=bst.predict(X_val)\n                resid=y_tr-bst.predict(X_tr)\n                oof_sigma[val_idx,t]=np.std(resid)\n            else:\n                oof_mu[val_idx,t]=y_tr.mean()\n                oof_sigma[val_idx,t]=y_tr.std()\n                \n        print(f'Fold {fold} done')\n    return oof_mu,oof_sigma\n\n# ---------------- Ensemble combine ----------------\ndef combine_ensemble_predictions(mu_list, sigma_list):\n    mus=np.stack(mu_list, axis=0)\n    sigs=np.stack(sigma_list, axis=0)\n    mu_mean=mus.mean(axis=0)\n    var_models=mus.var(axis=0)\n    aleatoric=(sigs**2).mean(axis=0)\n    sigma_ensemble=np.sqrt(aleatoric+var_models)\n    return mu_mean, sigma_ensemble\n\n# ---------------- Main pipeline ----------------\ndef main():\n    # ---------------- Load train ----------------\n    train_path = next(DATA_DIR.glob('**/train.csv'))\n    train_df=pd.read_csv(train_path)\n    planet_ids=train_df['planet_id'].values\n    y_train=train_df.drop(columns=['planet_id']).values\n\n    # ---------------- Feature prep placeholder ----------------\n    # TODO: add spectral loading + preprocessing + feature extraction\n    X_train=np.random.randn(len(y_train), 100)  # dummy features, replace with real spectral processing\n\n    # ---------------- Ensemble OOF ----------------\n    mu_list=[]; sigma_list=[]\n    for cfg in MODEL_CONFIGS[:3]:  # test küçük subset\n        if cfg['type']=='lgb':\n            mu,sigma=run_oof_lightgbm(X_train, y_train, params=cfg['params'])\n        else:\n            mu=np.zeros_like(y_train); sigma=np.ones_like(y_train)  # placeholder\n        mu_list.append(mu); sigma_list.append(sigma)\n\n    mu_ens, sigma_ens=combine_ensemble_predictions(mu_list, sigma_list)\n\n    # ---------------- Submission ----------------\n    sample_submission_path = next(DATA_DIR.glob('**/sample_submission.csv'))\n    submission_df=pd.read_csv(sample_submission_path)\n    test_ids=submission_df['planet_id'].values\n    write_submission(test_ids, mu_ens[:len(test_ids)], sigma_ens[:len(test_ids)], OUT_DIR)\n\nif __name__=='__main__':\n    main()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-10T00:27:44.789757Z","iopub.execute_input":"2025-09-10T00:27:44.790078Z","execution_failed":"2025-09-10T01:40:43.837Z"}},"outputs":[],"execution_count":null}]}