{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":53666,"databundleVersionId":6589269,"sourceType":"competition"}],"dockerImageVersionId":30698,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport pyarrow.parquet as pq\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\n\nimport torch.nn as nn\nimport torch.optim as optim\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-06-07T10:09:41.935448Z","iopub.execute_input":"2024-06-07T10:09:41.935948Z","iopub.status.idle":"2024-06-07T10:09:47.379422Z","shell.execute_reply.started":"2024-06-07T10:09:41.935914Z","shell.execute_reply":"2024-06-07T10:09:47.378126Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CFG:\n    input_len = 20","metadata":{"execution":{"iopub.status.busy":"2024-06-07T10:09:47.381826Z","iopub.execute_input":"2024-06-07T10:09:47.382367Z","iopub.status.idle":"2024-06-07T10:09:47.389144Z","shell.execute_reply.started":"2024-06-07T10:09:47.382308Z","shell.execute_reply":"2024-06-07T10:09:47.387575Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = pq.read_table('/kaggle/input/child-mind-institute-detect-sleep-states/train_series.parquet').to_pandas() # .sample(n=500, random_state=42)\ntrain_events = pd.read_csv('/kaggle/input/child-mind-institute-detect-sleep-states/train_events.csv') # .sample(n=500, random_state=42)\n\ntrain_df['timestamp'] = pd.to_datetime(train_df['timestamp'], format='%Y-%m-%dT%H:%M:%S-%f')\ntrain_events['timestamp'] = pd.to_datetime(train_events['timestamp'], format='%Y-%m-%dT%H:%M:%S-%f')\n\nprint(train_df.shape)\nprint(train_events.shape)\nprint(train_df.head())\nprint(train_events.head())\n\n","metadata":{"execution":{"iopub.status.busy":"2024-06-07T10:09:47.391023Z","iopub.execute_input":"2024-06-07T10:09:47.391449Z","iopub.status.idle":"2024-06-07T10:25:39.610275Z","shell.execute_reply.started":"2024-06-07T10:09:47.391417Z","shell.execute_reply":"2024-06-07T10:25:39.608669Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DDS_Train_Dataset(Dataset):\n    def __init__(self, df, df_events):\n        \n        # 保留10%的数据\n        df = df.sample(frac=0.1, random_state=42) # sample\n        \n        self.mean = {k: np.mean(df[k]) for k in ['anglez', 'enmo']}\n        self.std = {k: np.std(df[k]) for k in ['anglez', 'enmo']}\n#         print('mean: ', self.mean)\n#         print('std: ', self.std)\n        df['anglez'] = (df['anglez'] - self.mean['anglez']) / self.std['anglez']\n        df['enmo'] = (df['enmo'] - self.mean['enmo']) / self.std['enmo']\n        \n        self.input_len = CFG.input_len\n        self.grouped_df = [(data[0], data[1].reset_index()) for data in df.groupby('series_id')]\n        \n        # df_events保留与df series_id一致的数据\n        sampled_series_ids = df['series_id'].unique() # sample\n        df_events = df_events[df_events['series_id'].isin(sampled_series_ids)]\n        \n        self.grouped_df_events = {k: v.reset_index(drop=True) for k,v in df_events.groupby('series_id')}\n        self.series_id = df['series_id'].unique()\n#         self.series_start_day = {k: df_events[df_events['series_id'] == k]['timestamp'].min() for k in self.series_id}\n        self.series_size = np.array([series_i[-1].shape[0] - self.input_len + 1 for series_i in self.grouped_df])\n        self.series_line = np.cumsum(self.series_size)\n    \n    def __len__(self):\n        return self.series_line[-1]\n    \n    def __getitem__(self, idx):\n        line_cnt = 0\n        while idx >= self.series_line[line_cnt]:\n            line_cnt += 1\n        \n        series_idx = idx\n        if line_cnt != 0:\n            series_idx -= self.series_line[line_cnt - 1]\n        \n#         print(line_cnt, series_idx)\n        \n        row = self.grouped_df[line_cnt][-1].iloc[series_idx : series_idx + self.input_len]\n        series_id, label_step = row.iloc[-1][['series_id', 'step']]\n        \n #       label = 0 if self.grouped_df_events[series_id].iloc[0]['event'] == 'onset' else 1  # 0 awake  | 1 sleep\n #       event_idx = 0\n #       while label_step >= self.grouped_df_events[series_id].iloc[event_idx]['step']:\n #           label = 0 if self.grouped_df_events[series_id].iloc[0]['event'] == 'onset' else 1\n #           event_idx += 1\n        event_idx = 0\n        if label_step < self.grouped_df_events[series_id].iloc[event_idx]['step']:\n            label = 0 if self.grouped_df_events[series_id].iloc[0]['event'] == 'onset' else 1  # 0 awake  | 1 sleep\n        else:\n#             print(self.grouped_df_events[series_id])\n            flag = True\n            while label_step >= self.grouped_df_events[series_id].iloc[event_idx]['step']:\n                event_idx += 1\n                if event_idx >= len(self.grouped_df_events[series_id]):\n                    flag = False\n                    break\n            if flag:\n                label = 1 if self.grouped_df_events[series_id].iloc[event_idx]['event'] == 'onset' else 0\n            else:\n                label = 1 if self.grouped_df_events[series_id].iloc[len(self.grouped_df_events[series_id]) - 1]['event'] == 'onset' else 0\n#         print('label: ', label)\n#         print('event_idx: ', event_idx)\n#         print(series_id, label_step)\n#         print(row)\n        feature = row[['anglez', 'enmo']]\n        feature = torch.as_tensor(feature.values, dtype=torch.float32)\n        label = torch.as_tensor(label, dtype=torch.int64)\n        \n        return feature, label\n#         return feature, label.unsqueeze(dim=-1)\n\n\n# delta = (self.df['timestamp'].iloc[0].date() - self.series_start_day['038441c925bb'].date()).days\n\n# train_ds = DDS_Train_Dataset(train_df, train_events)\n# print(len(train_ds))\n# feature, label = train_ds[5000]\n# print('feature: ', feature)\n# print('feature.shape: ', feature.shape)\n# print('label: ', label)\n# print('label.shape: ', label.shape)","metadata":{"execution":{"iopub.status.busy":"2024-06-07T10:25:39.614064Z","iopub.execute_input":"2024-06-07T10:25:39.614518Z","iopub.status.idle":"2024-06-07T10:25:39.637598Z","shell.execute_reply.started":"2024-06-07T10:25:39.614485Z","shell.execute_reply":"2024-06-07T10:25:39.636071Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DDS_Test_Dataset(Dataset):\n    def __init__(self, df):\n        \n        # 保留10%的数据\n        df = df.sample(frac=0.1, random_state=42) # sample\n        \n        self.mean = {k: np.mean(df[k]) for k in ['anglez', 'enmo']}\n        self.std = {k: np.std(df[k]) for k in ['anglez', 'enmo']}\n        print('mean: ', self.mean)\n        print('std: ', self.std)\n        df['anglez'] = (df['anglez'] - self.mean['anglez']) / self.std['anglez']\n        df['enmo'] = (df['enmo'] - self.mean['enmo']) / self.std['enmo']\n        \n        self.input_len = CFG.input_len\n        self.grouped_df = [(data[0], data[1].reset_index()) for data in df.groupby('series_id')]\n        \n        self.series_id = df['series_id'].unique()\n#         self.series_start_day = {k: df_events[df_events['series_id'] == k]['timestamp'].min() for k in self.series_id}\n        self.series_size = np.array([series_i[-1].shape[0] - self.input_len + 1 for series_i in self.grouped_df])\n        self.series_line = np.cumsum(self.series_size)\n    \n    def __len__(self):\n#         print(\"Series line:\", self.series_line)\n#         print(\"Last element of series line:\", self.series_line[-1])\n        return self.series_line[-1]\n    \n    def __getitem__(self, idx):\n        line_cnt = 0\n        while idx >= self.series_line[line_cnt]:\n            line_cnt += 1\n        \n        series_idx = idx\n        if line_cnt != 0:\n            series_idx -= self.series_line[line_cnt - 1]\n        \n#         print(line_cnt, series_idx)\n        \n        row = self.grouped_df[line_cnt][-1].iloc[series_idx : series_idx + self.input_len]\n        series_id, label_step = row.iloc[-1][['series_id', 'step']]\n        \n #       label = 0 if self.grouped_df_events[series_id].iloc[0]['event'] == 'onset' else 1  # 0 awake  | 1 sleep\n #       event_idx = 0\n #       while label_step >= self.grouped_df_events[series_id].iloc[event_idx]['step']:\n #           label = 0 if self.grouped_df_events[series_id].iloc[0]['event'] == 'onset' else 1\n #           event_idx += 1\n\n\n #      event_idx = 0\n #      if label_step < self.grouped_df_events[series_id].iloc[event_idx]['step']:\n #          label = 0 if self.grouped_df_events[series_id].iloc[0]['event'] == 'onset' else 1  # 0 awake  | 1 sleep\n #      else:\n #          while label_step >= self.grouped_df_events[series_id].iloc[event_idx]['step']:\n #              event_idx += 1\n #          label = 1 if self.grouped_df_events[series_id].iloc[event_idx]['event'] == 'onset' else 0\n\n#         print('label: ', label)\n#         print('event_idx: ', event_idx)\n#         print(series_id, label_step)\n#         print(row)\n\n        feature = row[['anglez', 'enmo']]\n        feature = torch.as_tensor(feature.values, dtype=torch.float32)\n        \n        return feature","metadata":{"execution":{"iopub.status.busy":"2024-06-07T10:25:39.639829Z","iopub.execute_input":"2024-06-07T10:25:39.640295Z","iopub.status.idle":"2024-06-07T10:25:39.65904Z","shell.execute_reply.started":"2024-06-07T10:25:39.640255Z","shell.execute_reply":"2024-06-07T10:25:39.65752Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class SleepStateGRU(nn.Module):\n    def __init__(self, input_size, hidden_size, num_layers, output_size):\n        super(SleepStateGRU, self).__init__()\n        self.hidden_size = hidden_size\n        self.num_layers = num_layers\n        self.gru = nn.GRU(input_size, hidden_size, num_layers, batch_first=True)\n        self.fc = nn.Linear(hidden_size, output_size)\n        \n    def forward(self, x, hidden=None):\n        batch_size = x.shape[0] # 获取批次大小\n        device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n        if hidden is None:\n            h_0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device) # 初始化隐藏状态\n        else:\n            h_0 = hidden\n        out, _ = self.gru(x, h_0)\n        batch_size, timestep, hidden_size = out.shape   # GRU输出的维度信息\n        out = out[:, -1]\n        out = out.reshape(-1, hidden_size)\n        out = self.fc(out)\n        out = out.reshape(batch_size, -1) # 转换维度\n#        out = self.fc(out[:, -1, :]) # 取最后一个时间步的输出用于分类\n        return out\n","metadata":{"execution":{"iopub.status.busy":"2024-06-07T10:25:39.661398Z","iopub.execute_input":"2024-06-07T10:25:39.662222Z","iopub.status.idle":"2024-06-07T10:25:39.678083Z","shell.execute_reply.started":"2024-06-07T10:25:39.662167Z","shell.execute_reply":"2024-06-07T10:25:39.67653Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_model(model, train_loader, criterion, optimizer, device, batch_size=32, num_epochs=10):\n    model.to(device)\n    print('Train model')\n    loss_show = []\n    acc_show = []\n    for epoch in range(num_epochs):\n        model.train()\n        running_loss = 0.0\n        running_corrects = 0\n        for i, (features, labels) in enumerate(train_loader):\n            features, labels = features.to(device), labels.to(device)\n            outputs = model(features)\n            optimizer.zero_grad()\n            pred = torch.argmax(outputs, dim=1).to('cpu')\n            # 前向传播\n            loss = criterion(outputs, labels)\n            # 反向传播和优化\n            loss.backward()\n            optimizer.step()\n            running_loss += loss.item()\n            running_corrects+= torch.sum(pred == labels.cpu().detach()).item()\n        \n        print(f\"Epoch {epoch+1}/{num_epochs}, Loss: {running_loss/len(train_loader)}, Acc:{running_corrects/len(train_loader)}%\")\n        \n    print('Training complete.')\n    plt.subplot(211)\n    plt.plot(range(num_epochs), loss_show)\n    plt.subplot(212)\n    plt.plot(range(num_epochs), acc_show)\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-06-07T10:25:39.679916Z","iopub.execute_input":"2024-06-07T10:25:39.680304Z","iopub.status.idle":"2024-06-07T10:25:39.693286Z","shell.execute_reply.started":"2024-06-07T10:25:39.680273Z","shell.execute_reply":"2024-06-07T10:25:39.692002Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def test_model(model, test_loader, device, batch_size=32):\n    model.eval() # 设置模型为评估模式\n    model.to(device)\n    print('Evaluate model on test dataset')\n    \n    predictions = []\n    with torch.no_grad(): # 不进行梯度计算以节省内存和加快速度\n        for i, features in enumerate(test_loader):\n            features = features.to(device)\n            outputs = model(features)\n            _, preds = torch.max(outputs, 1)\n            predictions.extend(preds.cpu().numpy())\n    \n    return predictions","metadata":{"execution":{"iopub.status.busy":"2024-06-07T10:25:39.694855Z","iopub.execute_input":"2024-06-07T10:25:39.695226Z","iopub.status.idle":"2024-06-07T10:25:39.709859Z","shell.execute_reply.started":"2024-06-07T10:25:39.695196Z","shell.execute_reply":"2024-06-07T10:25:39.708392Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_ds = DDS_Train_Dataset(train_df, train_events)\nprint(len(train_ds))\n\nfeature, label = train_ds[5000]\n# print('feature: ', feature)\n# print('feature.shape: ', feature.shape)\n# print('label: ', label)\n# print('label.shape: ', label.shape)\n\n# feature, label = test_ds[5000]\n# print('feature: ', feature)\n# print('feature.shape: ', feature.shape)\n# print('label: ', label)\n# print('label.shape: ', label.shape)\n\n\nbatch_size_tr = 32\ntrain_dl = DataLoader(train_ds, batch_size=batch_size_tr, shuffle=True)\n# del train_ds, test_ds\n\n# 设定超参数\ninput_size = 2 # 假设特征维度为2 ('anglez', 'enmo')\nhidden_size = 128\nnum_layers = 2\noutput_size = 2 # 输出类别数，这里假设是两类：清醒和睡眠\nlearning_rate = 0.001\n\n# 初始化模型、损失函数和优化器\nmodel = SleepStateGRU(input_size, hidden_size, num_layers, output_size)\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=learning_rate)\nnum_epochs = 30\n# scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, patience=3, verbose=True, factor=0.5, min_lr=0.000001)\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n# 开始训练\ntrain_model(model, train_dl, criterion, optimizer, device, num_epochs=num_epochs)\n","metadata":{"execution":{"iopub.status.busy":"2024-06-07T10:25:39.711555Z","iopub.execute_input":"2024-06-07T10:25:39.711943Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df = pq.read_table('/kaggle/input/child-mind-institute-detect-sleep-states/test_series.parquet').to_pandas()\ntest_df['timestamp'] = pd.to_datetime(test_df['timestamp'], format='%Y-%m-%dT%H:%M:%S-%f')\n\nprint(test_df.shape)\nprint(test_df.head())\n\ntest_ds = DDS_Test_Dataset(test_df)\nprint(len(test_ds))\n\nbatch_size_te = 1\ntest_dl = DataLoader(test_ds, batch_size=batch_size_te, shuffle=False)\n\npredictions = test_model(model, test_dl, criterion, device)\nprint(len(predictions))","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}