{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nfrom tqdm import tqdm\nfrom pathlib import Path","metadata":{"execution":{"iopub.status.busy":"2023-02-27T09:55:52.766923Z","iopub.execute_input":"2023-02-27T09:55:52.768376Z","iopub.status.idle":"2023-02-27T09:55:52.798609Z","shell.execute_reply.started":"2023-02-27T09:55:52.768313Z","shell.execute_reply":"2023-02-27T09:55:52.797455Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* <font size=\"4\"> This notebook only focuses on preparing the data for training. A detailed description of the asl-sign dataset is already given [here](https://www.kaggle.com/code/robikscube/sign-language-recognition-eda-twitch-stream).</font>\n* <font size=\"4\"> If you want to try the prep dataset which only including the coordinates of both hands, add the dataset **prep-asl-sign-dataset**</font> \n\n<font size=\"3\">If you have any suggestion, I'm gladly appreciate it. </font>","metadata":{}},{"cell_type":"code","source":"# The asl-signs dataset come in the format where the coordinates (x, y, z) of body landmarks for each frame are splitted across multiple rows.\n# For example, this dataframe represents series of frame for one hand sign. \nexp_df = pd.read_parquet('/kaggle/input/asl-signs/train_landmark_files/16069/100015657.parquet')\nexp_df.head(n=10)","metadata":{"execution":{"iopub.status.busy":"2023-02-27T09:56:04.657272Z","iopub.execute_input":"2023-02-27T09:56:04.657696Z","iopub.status.idle":"2023-02-27T09:56:04.882029Z","shell.execute_reply.started":"2023-02-27T09:56:04.657658Z","shell.execute_reply":"2023-02-27T09:56:04.881108Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# The goal of this notebook is to prepare features where each row represent all coordinates of the body landmarks.\n# I already upload the prep dataset to kaggle (name: prep-asl-sign-dataset).\n# The end result should look like this\nexp_prep_df = pd.read_csv('/kaggle/input/d/surayuthpintawong/prep-asl-sign-dataset/train_data/16069_100015657.csv')\nexp_prep_df.head(n=10)\n# each row corresponds to all coordinates of the body landmarks of one frame.","metadata":{"execution":{"iopub.status.busy":"2023-02-27T10:07:05.455628Z","iopub.execute_input":"2023-02-27T10:07:05.456156Z","iopub.status.idle":"2023-02-27T10:07:05.503986Z","shell.execute_reply.started":"2023-02-27T10:07:05.456112Z","shell.execute_reply":"2023-02-27T10:07:05.501881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Only 126 columns (2 hands x 3 spatial coordinates x 21 landmarks) are included \n# in my dataset but you could add additional body types by changing the config, see the cell below.\nshape = exp_prep_df.shape\nnum_frames, num_features = shape[0], shape[1]\nprint('number of unique frames: ', num_frames) # 105\nprint('number of included features: ', num_features) # 126","metadata":{"execution":{"iopub.status.busy":"2023-02-27T10:04:53.338830Z","iopub.execute_input":"2023-02-27T10:04:53.339264Z","iopub.status.idle":"2023-02-27T10:04:53.346814Z","shell.execute_reply.started":"2023-02-27T10:04:53.339224Z","shell.execute_reply":"2023-02-27T10:04:53.345318Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<font size=\"4\"> The config specifies the </font>","metadata":{}},{"cell_type":"code","source":"# config\nselected_types = ['left_hand', 'right_hand'] # 'face', 'left_hand', 'pose', 'right_hand' (landmarks which you would like to use)\nroot_dataset = '/kaggle/input/asl-signs'  \nexport_to = 'prep_train/' \next = '.csv' # '.csv', '.npy'","metadata":{"execution":{"iopub.status.busy":"2023-02-26T14:54:24.573423Z","iopub.execute_input":"2023-02-26T14:54:24.573927Z","iopub.status.idle":"2023-02-26T14:54:24.580668Z","shell.execute_reply.started":"2023-02-26T14:54:24.573886Z","shell.execute_reply":"2023-02-26T14:54:24.579325Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# # Each body type has different number of landmarks\n# # To validate the numbers, execute \ndf = pd.read_parquet('/kaggle/input/asl-signs/train_landmark_files/16069/100015657.parquet')\nnum_frames = len(df['frame'].unique())\nfor _type in df['type'].unique():\n    print(_type, int(len(df[df['type'] == _type]) / num_frames))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_landmarks = {\n    'face': 468,\n    'left_hand': 21,\n    'pose': 33,\n    'right_hand': 21\n}\nroot_dataset = Path(root_dataset)\nexport_to = Path(export_to)\nprep_data_dir = export_to / 'train_data'\nprep_data_dir.mkdir(parents=True, exist_ok=True)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# define functions \ndef prep_landmark_df(df, selected_types):\n    prep_df = df \\\n        .pivot(index='frame', columns=['type', 'landmark_index'], values=['x', 'y', 'z']) \\\n        .reset_index()\n    \n    col_names = ['frame']\n    selected_cols = []\n    for coord in ['x' , 'y', 'z']:\n        for _type in num_landmarks.keys():\n            for landmark in range(num_landmarks[_type]):\n                col_names.append(f'{coord}_{_type}_{landmark}')\n                \n    prep_df.columns = col_names\n    prep_df = prep_df.filter(regex='|'.join(selected_types), axis='columns')\n    \n    return prep_df\n\ndef export_df(filename, df, dst=prep_data_dir):\n    dst_file = prep_data_dir / filename\n    if ext == '.csv':\n        df.to_csv(dst_file, index=False)\n    elif ext == '.npy':\n        np.save(dst_file, df.to_numpy())\n    else:\n        raise NotImplemented","metadata":{"execution":{"iopub.status.busy":"2023-02-26T12:57:48.507640Z","iopub.execute_input":"2023-02-26T12:57:48.508070Z","iopub.status.idle":"2023-02-26T12:57:48.517745Z","shell.execute_reply.started":"2023-02-26T12:57:48.508031Z","shell.execute_reply":"2023-02-26T12:57:48.516368Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# prep\ntrain_df = pd.read_csv(root_dataset / 'train.csv')\n\nfor i in tqdm(range(len(train_df))):\n    path = train_df['path'][i]\n    df = pd.read_parquet(root_dataset / path)\n    prep_df = prep_landmark_df(df, selected_types)\n    \n    filename = '_'.join(path.replace('.', '/').split('/')[-3:-1]) + ext\n    export_df(filename, prep_df)\n\n# make new train.csv --> prep_train.csv\nprep_train_df = train_df.copy(deep=True)\nprep_train_df['path'] = prep_train_df['path'] \\\n    .apply(lambda x: '_'.join(x.replace('.', '/').split('/')[-3:-1]) + ext)\nprep_train_df.to_csv(export_to / 'prep_train.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2023-02-26T13:01:13.140597Z","iopub.execute_input":"2023-02-26T13:01:13.141059Z","iopub.status.idle":"2023-02-26T14:12:40.694533Z","shell.execute_reply.started":"2023-02-26T13:01:13.141016Z","shell.execute_reply":"2023-02-26T14:12:40.692611Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#%%sh\n#zip -r prep_asl_sign_dataset_csv.zip  /kaggle/working/prep_train","metadata":{"execution":{"iopub.status.busy":"2023-02-26T15:14:00.526857Z","iopub.execute_input":"2023-02-26T15:14:00.528183Z","iopub.status.idle":"2023-02-26T15:14:00.535067Z","shell.execute_reply.started":"2023-02-26T15:14:00.528094Z","shell.execute_reply":"2023-02-26T15:14:00.533230Z"},"trusted":true},"execution_count":null,"outputs":[]}]}