{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.11.11"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":102335,"databundleVersionId":12518947,"sourceType":"competition"},{"sourceId":12059033,"sourceType":"datasetVersion","datasetId":7587404}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false},"papermill":{"default_parameters":{},"duration":27.724185,"end_time":"2025-06-04T12:32:53.776277","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2025-06-04T12:32:26.052092","version":"2.6.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os, joblib\nimport sys\nsys.path.append('/kaggle/input/weights')\nimport pandas as pd\nimport polars as pl\nimport kaggle_evaluation.cmi_inference_server\nimport warnings\nwarnings.filterwarnings('ignore')\nfrom collections import Counter","metadata":{"execution":{"iopub.status.busy":"2025-06-05T04:38:28.715352Z","iopub.execute_input":"2025-06-05T04:38:28.715740Z","iopub.status.idle":"2025-06-05T04:38:28.973483Z","shell.execute_reply.started":"2025-06-05T04:38:28.715706Z","shell.execute_reply":"2025-06-05T04:38:28.972611Z"},"papermill":{"duration":3.850064,"end_time":"2025-06-04T12:32:35.563968","exception":false,"start_time":"2025-06-04T12:32:31.713904","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 예측 모델 로드\nvoting_clf = joblib.load('/kaggle/input/weights/voting_250604.pkl')\n\n# 스케일러 로드\nscaler = joblib.load('/kaggle/input/weights/scaler.pkl')\n\n# 레이블 인코더 딕셔너리 로드\nle_map = joblib.load('/kaggle/input/weights/label_encoder.pkl')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def tof_summary(sequence):\n    tof_cols = [col for col in sequence.columns if 'tof' in col]\n\n    sequence['tof_mean'] = sequence[tof_cols].mean(axis=1)\n    sequence['tof_median'] = sequence[tof_cols].median(axis=1)\n    sequence['tof_min'] = sequence[tof_cols].min(axis=1)\n    sequence['tof_max'] = sequence[tof_cols].max(axis=1)\n    sequence['tof_std'] = sequence[tof_cols].std(axis=1)\n    sequence['tof_range'] = sequence['tof_max'] - sequence['tof_min']\n    sequence['tof_quantile10'] = sequence[tof_cols].quantile(0.1, axis=1)\n    sequence['tof_quantile25'] = sequence[tof_cols].quantile(0.25, axis=1)\n    sequence['tof_quantile75'] = sequence[tof_cols].quantile(0.75, axis=1)\n    sequence['tof_quantile90'] = sequence[tof_cols].quantile(0.9, axis=1)\n    sequence['tof_no_signal'] = sequence[tof_cols].eq(-1).sum(axis=1) # -1은 측정된 거리가 없어 no signal\n\n    # tof 픽셀 열 삭제\n    sequence = sequence.drop(tof_cols, axis=1)\n    return sequence","metadata":{"execution":{"iopub.status.busy":"2025-06-05T04:38:28.974705Z","iopub.execute_input":"2025-06-05T04:38:28.975490Z","iopub.status.idle":"2025-06-05T04:38:28.992310Z","shell.execute_reply.started":"2025-06-05T04:38:28.975464Z","shell.execute_reply":"2025-06-05T04:38:28.991421Z"},"papermill":{"duration":0.013617,"end_time":"2025-06-04T12:32:35.579786","exception":false,"start_time":"2025-06-04T12:32:35.566169","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:\n    '''\n    input : 한 시퀀스 데이터프레임\n    output : 시퀀스의 예측 제스쳐\n    '''\n\n    sequence = sequence.to_pandas()\n\n    # null 값 0으로 대체\n    sequence = sequence.fillna(0)\n\n    # 불필요 컬럼 제거\n    sequence = sequence.drop(['sequence_id','row_id','sequence_counter','subject'], axis=1)\n    if 'column_0' in sequence.columns:\n        sequence = sequence.drop('column_0', axis=1)\n    \n    # 특징 요약\n    sequence = tof_summary(sequence)\n    \n    # 스케일링\n    \n    sequence_scaled = scaler.transform(sequence.to_numpy())\n    \n    # 예측\n    y_pred = voting_clf.predict(sequence_scaled).astype(int)\n    \n    # 예측 배열 중 최빈값을 선택\n    y_pred = Counter(y_pred).most_common(1)[0][0]\n    \n    # 연속형 -> 범주형 레이블 변환\n    return le_map[y_pred]","metadata":{"execution":{"iopub.status.busy":"2025-06-05T04:38:28.993184Z","iopub.execute_input":"2025-06-05T04:38:28.993911Z","iopub.status.idle":"2025-06-05T04:38:29.043022Z","shell.execute_reply.started":"2025-06-05T04:38:28.993889Z","shell.execute_reply":"2025-06-05T04:38:29.042155Z"},"papermill":{"duration":0.01399,"end_time":"2025-06-04T12:32:35.595716","exception":false,"start_time":"2025-06-04T12:32:35.581726","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 채점 시뮬레이션 제출용\ninference_server = kaggle_evaluation.cmi_inference_server.CMIInferenceServer(predict)\n\nif os.getenv('KAGGLE_IS_COMPETITION_RERUN'):\n    inference_server.serve()\nelse:\n    inference_server.run_local_gateway(\n        data_paths=(\n            '/kaggle/input/weights/test.csv',\n            '/kaggle/input/weights/test_demographics.csv',\n        )\n    )","metadata":{"execution":{"iopub.status.busy":"2025-06-05T04:38:29.044459Z","iopub.execute_input":"2025-06-05T04:38:29.044690Z","iopub.status.idle":"2025-06-05T04:38:33.852101Z","shell.execute_reply.started":"2025-06-05T04:38:29.044667Z","shell.execute_reply":"2025-06-05T04:38:33.849326Z"},"papermill":{"duration":17.153261,"end_time":"2025-06-04T12:32:52.750967","exception":false,"start_time":"2025-06-04T12:32:35.597706","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null}]}