{"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":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\nimport matplotlib.pyplot as plt\nimport matplotlib as mpl\nimport seaborn as sns\nsns.set_style('darkgrid')\n\nimport warnings\nwarnings.filterwarnings('ignore')\n\nimport tensorflow as tf\nfrom tqdm.notebook import tqdm\nfrom sklearn.model_selection import train_test_split, GroupShuffleSplit\nfrom pathlib import Path\n\nimport glob\nimport sys\nimport os\nimport math\nimport gc\nimport sys\nimport sklearn\nimport time\nimport json\nimport re\n\n# TQDM Progress Bar With Pandas Apply Function\ntqdm.pandas()\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-07-24T15:15:57.715539Z","iopub.execute_input":"2023-07-24T15:15:57.716139Z","iopub.status.idle":"2023-07-24T15:16:14.627145Z","shell.execute_reply.started":"2023-07-24T15:15:57.716106Z","shell.execute_reply":"2023-07-24T15:16:14.626177Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🔎 Dataset Description\nEl objetivo de esta competición es detectar y traducir el lenguaje de señas americano (ASL) a texto.\n\nEsta competencia requiere que las presentaciones se realicen en forma de modelos de TensorFlow Lite. Puedes entrenar tu modelo utilizando el marco de trabajo de tu elección siempre que conviertas el punto de control del modelo al formato tflite antes de la presentación. Consulta la página de evaluación para obtener más detalles.\n\n# 📄 Files\n\n## [train/supplemental_metadata].csv\n\n* `path` - La ruta al archivo de referencia.\n* `file_id` - Un identificador único para el archivo de datos.\n* `participant_id` - Un identificador único para el contribuyente de datos.\n* `sequence_id` - Un identificador único para la secuencia de referencia. Cada archivo de datos puede contener muchas secuencias.\n* `phrase` - Las etiquetas para la secuencia de referencia. Los conjuntos de datos de entrenamiento y prueba contienen **direcciones, números de teléfono y URL generados al azar, derivados de componentes de direcciones reales/números de teléfono/URL**. Cualquier coincidencia con direcciones reales, números de teléfono o URL es puramente accidental. **El conjunto de datos complementario consiste en oraciones deletreadas con los dedos**. Ten en cuenta que algunas de las URL incluyen contenido para adultos. El objetivo de esta competencia es apoyar a la comunidad de personas sordas y con discapacidad auditiva para que se involucren con la tecnología en igualdad de condiciones con otros adultos.\n\n## character_to_prediction_index.json\n\nUn diccionario en el que se asigna a distintos simbolos un número entero.\n\n## [train/supplemental]_landmarks/\n\nLos datos de referencia han sido extraídos con MediaPipe Holistic Solution, una herramienta de software que puede detectar y rastrear múltiples partes del cuerpo humano y gestos en secuencias de vídeo en tiempo real.\n\nLos datos de referencia. Los puntos de referencia se extrajeron de videos en bruto con el modelo de MediaPipe. **No todos los fotogramas necesariamente tenían manos visibles o manos que pudieran ser detectadas por el modelo**.\nLos archivos de referencia contienen los mismos datos que en la competición de ASL Signs (excepto la columna de ID de fila) pero con una estructura amplia. **Esto te permite aprovechar el formato Parquet para omitir por completo la carga de puntos de referencia que no estás utilizando**.\n\n* `sequence_id` - Un identificador único para la secuencia de referencia. Los archivos de referencia contienen aproximadamente 1,000 secuencias. El ID de secuencia se utiliza como índice del dataframe.\n* `frame` - El número de fotograma dentro de una secuencia de referencia.\n* `[x/y/z]_[type]_[landmark_index]` - Ahora hay 1,629 columnas de coordenadas espaciales para las coordenadas x, y y z de cada uno de los 543 puntos de referencia. El tipo de punto de referencia puede ser uno de `['face', 'left_hand', 'pose', 'right_hand']`. Aquí se pueden encontrar detalles sobre las ubicaciones de los puntos de referencia de las manos. Las coordenadas espaciales ya han sido normalizadas por MediaPipe. Ten en cuenta que el modelo de MediaPipe no está completamente entrenado para predecir la profundidad, por lo que es posible que desees ignorar los valores de z. Los puntos de referencia se han convertido a float32.\n","metadata":{}},{"cell_type":"markdown","source":"## 1) Importamos los paquetes necesarios para llevar a cabo el anális exploratorio inicial de los datos:","metadata":{}},{"cell_type":"code","source":"# import the desired packages\nimport numpy as np\nimport pandas as pd\nimport json\nimport plotly.graph_objects as go\nimport plotly.io as pio\npio.templates.default = \"simple_white\"","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:10:44.133295Z","iopub.execute_input":"2023-07-24T09:10:44.134303Z","iopub.status.idle":"2023-07-24T09:10:46.184355Z","shell.execute_reply.started":"2023-07-24T09:10:44.134268Z","shell.execute_reply":"2023-07-24T09:10:46.183071Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Definimos las funciones que nos serán útiles para previsualizar los datos:","metadata":{}},{"cell_type":"code","source":"def map_new_to_old_style(sequence):\n    \"\"\"\n    Esta funcíon recorre todas las columnas del DF (menos la de indice) y separa los distintos tipos de landmark.\n    \n    :sequence: DF donde cada fila representa un cierto instante de tiempo con MÚLTIPLES tipos de landmarks y sus coordenadas (x, y, z) correspondientes.\n    :returns: Nuevo DF donde cada fila representa un cierto instante de tiempo con UN tipo de landmark específico y sus coordenadas (x, y, z) correspondientes.\n    \n    \"\"\"\n    types = []\n    landmark_indexes = []\n    for column in list(sequence.columns)[1:544]:\n        parts = column.split(\"_\")\n        if len(parts) == 4:\n            types.append(parts[1] + \"_\" + parts[2])\n        else:\n            types.append(parts[1])\n\n        landmark_indexes.append(int(parts[-1]))\n\n    data = {\n        \"frame\": [],\n        \"type\": [],\n        \"landmark_index\": [],\n        \"x\": [],\n        \"y\": [],\n        \"z\": []\n    }\n\n    for index, row in sequence.iterrows():\n        data[\"frame\"] += [int(row.frame)]*543\n        data[\"type\"] += types\n        data[\"landmark_index\"] += landmark_indexes\n\n        for _type, landmark_index in zip(types, landmark_indexes):\n            data[\"x\"].append(row[f\"x_{_type}_{landmark_index}\"])\n            data[\"y\"].append(row[f\"y_{_type}_{landmark_index}\"])\n            data[\"z\"].append(row[f\"z_{_type}_{landmark_index}\"])\n\n    return pd.DataFrame.from_dict(data)\n\n\n# assign desired colors to landmarks\ndef assign_color(row):\n    \"\"\"\n    No necesita explicación.\n    \"\"\"\n    if row == 'face':\n        return 'red'\n    elif 'hand' in row:\n        return 'dodgerblue'\n    else:\n        return 'green'\n\n\n# specifies the plotting order\ndef assign_order(row):\n    \"\"\"\n    No necesita explicación.\n    \"\"\"\n    if row.type == 'face':\n        return row.landmark_index + 101\n    elif row.type == 'pose':\n        return row.landmark_index + 30\n    elif row.type == 'left_hand':\n        return row.landmark_index + 80\n    else:\n        return row.landmark_index\n\n\n\n\ndef visualise2d_landmarks(parquet_df, title=\"\"):\n    \"\"\"\n    Función para visualizar los datos correspondientes a los landmarks creando un gráfico interactivo en 2D \n    con su variacion en el tiempo mediante Plotly.\n    \n    :parquet_df: Es el DataFrame que contiene los datos de cada landmarks por separado. Se asume que el DF ya ha pasado por la función 'map_new_to_old_style' para tener el formato correcto.\n    :returns: Se muestran los datos utilizando fig.show(), lo que produce la visualización interactiva con la animación.\n    \"\"\"\n    connections = [  \n        [0, 1, 2, 3, 4,],\n        [0, 5, 6, 7, 8],\n        [0, 9, 10, 11, 12],\n        [0, 13, 14, 15, 16],\n        [0, 17, 18, 19, 20],\n\n        \n        [38, 36, 35, 34, 30, 31, 32, 33, 37],\n        [40, 39],\n        [52, 46, 50, 48, 46, 44, 42, 41, 43, 45, 47, 49, 45, 51],\n        [42, 54, 56, 58, 60, 62, 58],\n        [41, 53, 55, 57, 59, 61, 57],\n        [54, 53],\n\n        \n        [80, 81, 82, 83, 84, ],\n        [80, 85, 86, 87, 88],\n        [80, 89, 90, 91, 92],\n        [80, 93, 94, 95, 96],\n        [80, 97, 98, 99, 100], ]\n\n    parquet_df = map_new_to_old_style(parquet_df)\n    frames = sorted(set(parquet_df.frame))\n    first_frame = min(frames)\n    parquet_df['color'] = parquet_df.type.apply(lambda row: assign_color(row))\n    parquet_df['plot_order'] = parquet_df.apply(lambda row: assign_order(row), axis=1)\n    first_frame_df = parquet_df[parquet_df.frame == first_frame].copy()\n    first_frame_df = first_frame_df.sort_values([\"plot_order\"]).set_index('plot_order')\n\n\n    frames_l = []\n    for frame in frames:\n        filtered_df = parquet_df[parquet_df.frame == frame].copy()\n        filtered_df = filtered_df.sort_values([\"plot_order\"]).set_index(\"plot_order\")\n        traces = [go.Scatter(\n            x=filtered_df['x'],\n            y=filtered_df['y'],\n            mode='markers',\n            marker=dict(\n                color=filtered_df.color,\n                size=9))]\n\n        for i, seg in enumerate(connections):\n            trace = go.Scatter(\n                    x=filtered_df.loc[seg]['x'],\n                    y=filtered_df.loc[seg]['y'],\n                    mode='lines',\n            )\n            traces.append(trace)\n        frame_data = go.Frame(data=traces, traces = [i for i in range(17)])\n        frames_l.append(frame_data)\n\n    traces = [go.Scatter(\n        x=first_frame_df['x'],\n        y=first_frame_df['y'],\n        mode='markers',\n        marker=dict(\n            color=first_frame_df.color,\n            size=9\n        )\n    )]\n    for i, seg in enumerate(connections):\n        trace = go.Scatter(\n            x=first_frame_df.loc[seg]['x'],\n            y=first_frame_df.loc[seg]['y'],\n            mode='lines',\n            line=dict(\n                color='black',\n                width=2\n            )\n        )\n        traces.append(trace)\n    fig = go.Figure(\n        data=traces,\n        frames=frames_l\n    )\n\n\n    fig.update_layout(\n        width=500,\n        height=800,\n        scene={\n            'aspectmode': 'data',\n        },\n        updatemenus=[\n            {\n                \"buttons\": [\n                    {\n                        \"args\": [None, {\"frame\": {\"duration\": 100,\n                                                  \"redraw\": True},\n                                        \"fromcurrent\": True,\n                                        \"transition\": {\"duration\": 0}}],\n                        \"label\": \"&#9654;\",\n                        \"method\": \"animate\",\n                    },\n\n                ],\n                \"direction\": \"left\",\n                \"pad\": {\"r\": 100, \"t\": 100},\n                \"font\": {\"size\":30},\n                \"type\": \"buttons\",\n                \"x\": 0.1,\n                \"y\": 0,\n            }\n        ],\n    )\n    camera = dict(\n        up=dict(x=0, y=-1, z=0),\n        eye=dict(x=0, y=0, z=2.5)\n    )\n    fig.update_layout(title_text=title, title_x=0.5)\n    fig.update_layout(scene_camera=camera, showlegend=False)\n    fig.update_layout(xaxis = dict(visible=False),\n            yaxis = dict(visible=False),\n    )\n    fig.update_yaxes(autorange=\"reversed\")\n\n    fig.show()\n\n\ndef get_phrase(df, file_id, sequence_id):\n    \"\"\"\n    Obtiene la frase asociada a un file_id y un sequence_id específicos.\n    \n    :df: EL DF donde están contenidos los datos.\n    :file_id: Aqrchivo especifico de donde se va a seleccionar la frase.\n    :sequence_id: Secuencia específica dentro del archivo seleccionado.\n    \"\"\"\n    return df[\n        np.logical_and(\n            df.file_id == file_id, \n            df.sequence_id == sequence_id\n        )\n    ].phrase.iloc[0]","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:10:46.187828Z","iopub.execute_input":"2023-07-24T09:10:46.18937Z","iopub.status.idle":"2023-07-24T09:10:46.23677Z","shell.execute_reply.started":"2023-07-24T09:10:46.189321Z","shell.execute_reply":"2023-07-24T09:10:46.234055Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2 ) EDA del conjunto de entrenamiento:\n\nCargamos y previsualizamos los datos:","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv(\"/kaggle/input/asl-fingerspelling/train.csv\")\n\ntrain_df.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-24T15:16:30.387298Z","iopub.execute_input":"2023-07-24T15:16:30.388033Z","iopub.status.idle":"2023-07-24T15:16:30.580509Z","shell.execute_reply.started":"2023-07-24T15:16:30.387996Z","shell.execute_reply":"2023-07-24T15:16:30.579467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.file_id","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:10:46.594799Z","iopub.execute_input":"2023-07-24T09:10:46.596111Z","iopub.status.idle":"2023-07-24T09:10:46.608217Z","shell.execute_reply.started":"2023-07-24T09:10:46.596072Z","shell.execute_reply":"2023-07-24T09:10:46.607225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Analizamos de manera preliminar un descriptivo básico del tipo de datos presente en el dataset: ","metadata":{}},{"cell_type":"code","source":"train_df.describe()","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:10:46.612755Z","iopub.execute_input":"2023-07-24T09:10:46.613435Z","iopub.status.idle":"2023-07-24T09:10:46.655155Z","shell.execute_reply.started":"2023-07-24T09:10:46.6134Z","shell.execute_reply":"2023-07-24T09:10:46.654194Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Vamos a tratar de visualizar una de las secuencias de referencia presentes en el dataset. Como un archivo 'file_id' contiene diferentes secuencias de referencia, seleccionaremos la misma por el 'sequence_id'. Del mismo modo, para cada secuencia vamos a tener un número variable de fotogramas. ","metadata":{}},{"cell_type":"code","source":"train_df[train_df.file_id==2118949241]. head(25)","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:10:46.659597Z","iopub.execute_input":"2023-07-24T09:10:46.662097Z","iopub.status.idle":"2023-07-24T09:10:46.686193Z","shell.execute_reply.started":"2023-07-24T09:10:46.66206Z","shell.execute_reply":"2023-07-24T09:10:46.685065Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Seleccionamos el archivo y lo cargamos usando su ruta de referencia (los archivos estan en formato parquet):\nfile_id = 2118949241\npath_to_sign = f\"/kaggle/input/asl-fingerspelling/train_landmarks/{file_id}.parquet\"\n\n# Leemos el archivo parquet:\nsign = pd.read_parquet(path_to_sign)","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:10:46.68781Z","iopub.execute_input":"2023-07-24T09:10:46.688901Z","iopub.status.idle":"2023-07-24T09:11:03.531022Z","shell.execute_reply.started":"2023-07-24T09:10:46.688867Z","shell.execute_reply":"2023-07-24T09:11:03.529962Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sign.head(15)","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:11:03.535286Z","iopub.execute_input":"2023-07-24T09:11:03.535594Z","iopub.status.idle":"2023-07-24T09:11:03.575489Z","shell.execute_reply.started":"2023-07-24T09:11:03.535566Z","shell.execute_reply":"2023-07-24T09:11:03.574779Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('Número de secuencias de referencia en el archivo file_id=', file_id,':\\n', len(np.unique(sign.index)))","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:11:03.576943Z","iopub.execute_input":"2023-07-24T09:11:03.577622Z","iopub.status.idle":"2023-07-24T09:11:03.586281Z","shell.execute_reply.started":"2023-07-24T09:11:03.577589Z","shell.execute_reply":"2023-07-24T09:11:03.585414Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Comprobamos que cada archivo 'file_id' contiene aproximadamente unas 1000 secuencias de referencia. Vamos a seleccionar una de ellas por el 'sequence_id':","metadata":{}},{"cell_type":"code","source":"sequence_id= 355993778\nsequence = sign[sign.index == sequence_id]\nsequence.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:11:03.587745Z","iopub.execute_input":"2023-07-24T09:11:03.588497Z","iopub.status.idle":"2023-07-24T09:11:03.62268Z","shell.execute_reply.started":"2023-07-24T09:11:03.588462Z","shell.execute_reply":"2023-07-24T09:11:03.62173Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Visualizamos la frase correspondiente a la secuencia seleccionada:","metadata":{}},{"cell_type":"code","source":"sequence_phrase = get_phrase(train_df, file_id, sequence_id)\nvisualise2d_landmarks(sequence, f\"Phrase: {sequence_phrase}\")","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:11:03.624936Z","iopub.execute_input":"2023-07-24T09:11:03.625667Z","iopub.status.idle":"2023-07-24T09:11:47.613876Z","shell.execute_reply.started":"2023-07-24T09:11:03.625629Z","shell.execute_reply":"2023-07-24T09:11:47.612566Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#import matplotlib.pyplot as plt\n\n# ¿Y si quisiérmaos visualizar el número de Nans por secuencia? para saber más o menos la proporción de valores faltantes,\n#lo que nos daría un indicador de si las manos (u otros landmarks) están visibles o no en la secuencia:\n\n#nan_count_por_secuencia = sign.isnull().sum(axis=1)\n\n# Graficamos:\n#plt.figure(figsize=(10, 6))\n#plt.bar(nan_count_por_secuencia.index, nan_count_por_secuencia.values)\n#plt.xlabel('Secuencia')\n#plt.ylabel('Cantidad de NaNs')\n#plt.title('Número de NaNs por secuencia')\n#plt.show()\n\n#TARDA MUCHO EN PLOTEAR Y SERÍA PARA UN SOLO ARCHIVO, ESTUDIAR MÁS EN PROFUNDIDAD.","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:11:47.615374Z","iopub.execute_input":"2023-07-24T09:11:47.615844Z","iopub.status.idle":"2023-07-24T09:11:47.623931Z","shell.execute_reply.started":"2023-07-24T09:11:47.615797Z","shell.execute_reply":"2023-07-24T09:11:47.623018Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3 ) EDA del conjunto de datos complementario:\n\nCargamos y previsualizamos los datos:","metadata":{}},{"cell_type":"code","source":"supplemental_df = pd.read_csv(\"/kaggle/input/asl-fingerspelling/supplemental_metadata.csv\")\nsupplemental_df.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-24T15:16:45.050067Z","iopub.execute_input":"2023-07-24T15:16:45.050839Z","iopub.status.idle":"2023-07-24T15:16:45.242355Z","shell.execute_reply.started":"2023-07-24T15:16:45.050807Z","shell.execute_reply":"2023-07-24T15:16:45.24123Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Analizamos de manera preliminar un descriptivo básico del tipo de datos presente en el dataset: ","metadata":{}},{"cell_type":"code","source":"supplemental_df.describe()","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:11:47.79713Z","iopub.execute_input":"2023-07-24T09:11:47.798145Z","iopub.status.idle":"2023-07-24T09:11:47.828791Z","shell.execute_reply.started":"2023-07-24T09:11:47.79811Z","shell.execute_reply":"2023-07-24T09:11:47.827447Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Del mismo modo, repetiremos el proceso y trataremos de visualizar una de las secuencias de referencia presentes en el dataset para uno de los archivo 'file_id'.","metadata":{}},{"cell_type":"code","source":"# Seleccionamos el archivo y lo cargamos usando su ruta de referencia (los archivos estan en formato parquet):\nfile_id = 33432165\npath_to_sign = f\"/kaggle/input/asl-fingerspelling/supplemental_landmarks/{file_id}.parquet\"\n\n# Leemos el archivo parquet:\nsupplemental_sign = pd.read_parquet(path_to_sign)","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:11:47.83083Z","iopub.execute_input":"2023-07-24T09:11:47.831329Z","iopub.status.idle":"2023-07-24T09:12:12.707408Z","shell.execute_reply.started":"2023-07-24T09:11:47.831285Z","shell.execute_reply":"2023-07-24T09:12:12.70635Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"supplemental_sign.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:12:12.709124Z","iopub.execute_input":"2023-07-24T09:12:12.709516Z","iopub.status.idle":"2023-07-24T09:12:12.739609Z","shell.execute_reply.started":"2023-07-24T09:12:12.709476Z","shell.execute_reply":"2023-07-24T09:12:12.738402Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Comprobamos que cada archivo 'file_id' contiene aproximadamente unas 1000 secuencias de referencia. Vamos a seleccionar una de ellas por el 'sequence_id':","metadata":{}},{"cell_type":"code","source":"print('Número de secuencias de referencia en el archivo suplementario file_id=', file_id,':\\n', len(np.unique(supplemental_sign.index)))","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:12:12.74143Z","iopub.execute_input":"2023-07-24T09:12:12.742847Z","iopub.status.idle":"2023-07-24T09:12:12.765584Z","shell.execute_reply.started":"2023-07-24T09:12:12.742804Z","shell.execute_reply":"2023-07-24T09:12:12.764459Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Comprobamos que cada archivo 'file_id' contiene tmabién 1000 secuencias de referencia. Vamos a seleccionar una de ellas por el 'sequence_id':","metadata":{}},{"cell_type":"code","source":"sequence_id= 1540416468\nsequence = supplemental_sign[supplemental_sign.index == sequence_id]\nsequence.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:12:12.767232Z","iopub.execute_input":"2023-07-24T09:12:12.767613Z","iopub.status.idle":"2023-07-24T09:12:12.801829Z","shell.execute_reply.started":"2023-07-24T09:12:12.767578Z","shell.execute_reply":"2023-07-24T09:12:12.800827Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Comprobamos que cada archivo 'file_id' contiene aproximadamente unas 1000 secuencias de referencia. Vamos a seleccionar una de ellas por el 'sequence_id':","metadata":{}},{"cell_type":"code","source":"supplemental_df.iloc[80:130]","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:12:12.80334Z","iopub.execute_input":"2023-07-24T09:12:12.803668Z","iopub.status.idle":"2023-07-24T09:12:12.822797Z","shell.execute_reply.started":"2023-07-24T09:12:12.803636Z","shell.execute_reply":"2023-07-24T09:12:12.82172Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Visualizamos nuevamente la frase correspondiente a la secuencia seleccionada:","metadata":{}},{"cell_type":"code","source":"sequence_phrase = get_phrase(supplemental_df, file_id, sequence_id)\nvisualise2d_landmarks(sequence, f\"Phrase: {sequence_phrase}\")","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:12:12.824303Z","iopub.execute_input":"2023-07-24T09:12:12.825368Z","iopub.status.idle":"2023-07-24T09:12:40.909517Z","shell.execute_reply.started":"2023-07-24T09:12:12.825324Z","shell.execute_reply":"2023-07-24T09:12:40.907771Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n_________\n__________\n## Ideas de EDA sacadas del Notebook de Preprocesamiento:\n\n______\n______\n\n### Data Preparation:","metadata":{}},{"cell_type":"code","source":"#DEBUG: Esta variable indica si se está ejecutando en modo de depuración. Si es True, se ejecutará en modo de depuración, lo que puede implicar \n#la ejecución de un subconjunto de los datos para una ejecución más rápida y para facilitar la depuración.\n\nDEBUG = False\n\n# Read Train DataFrame\nif DEBUG:\n    train_df = pd.read_csv('/kaggle/input/asl-fingerspelling/train.csv').head(5000)\nelse:\n    train_df = pd.read_csv('/kaggle/input/asl-fingerspelling/train.csv')\n\n# Get complete file path to file\ndef get_file_path(path):\n    return f'/kaggle/input/asl-fingerspelling/{path}'\n\ntrain_df['file_path'] = train_df['path'].apply(get_file_path)\n\ntrain_df.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-24T15:16:52.329628Z","iopub.execute_input":"2023-07-24T15:16:52.330212Z","iopub.status.idle":"2023-07-24T15:16:52.49878Z","shell.execute_reply.started":"2023-07-24T15:16:52.330125Z","shell.execute_reply":"2023-07-24T15:16:52.497788Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Definimos la función `get_phrase_type`, que toma como entrada una frase (phrase):\n\n- Primero, verifica si la frase consiste únicamente en dígitos, signos de más (+) o guiones (-) utilizando la expresión regex `re.match(r'^[\\d+-]+$', phrase)`. Si la frase cumple con este patrón, se considera un \"Phone Number\" (número de teléfono).\n- Si no se cumple la primera condición, la función verifica si la frase contiene alguna de las subcadenas `['www', '.', '/']` y no contiene espacios en blanco mediante la expresión `any([substr in phrase for substr in ['www', '.', '/']])` and `' ' not in phrase`. Si se cumple esta condición, se considera una \"URL\".\n- Si ninguna de las dos condiciones anteriores se cumple, se asume que la frase es una \"Address\" (dirección).\n- Finalmente, la función devuelve el indetificativo","metadata":{}},{"cell_type":"code","source":"def get_phrase_type(phrase):\n    # Phone Number\n    if re.match(r'^[\\d+-]+$', phrase):\n        return 'phone_number'\n    # url\n    elif any([substr in phrase for substr in ['www', '.', '/']]) and ' ' not in phrase:\n        return 'url'\n    # Address\n    else:\n        return 'address'\n    \ntrain_df['phrase_type'] = train_df['phrase'].apply(get_phrase_type)\n\ntrain_df.head(10)","metadata":{"execution":{"iopub.status.busy":"2023-07-24T15:17:01.111103Z","iopub.execute_input":"2023-07-24T15:17:01.111505Z","iopub.status.idle":"2023-07-24T15:17:01.292265Z","shell.execute_reply.started":"2023-07-24T15:17:01.111475Z","shell.execute_reply":"2023-07-24T15:17:01.291132Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Phrase type plot:\nplt.figure(figsize=(10,2))\n\nsns.catplot(x=\"phrase_type\", y=None, kind=\"count\", data=train_df)\nplt.xlabel('Phrase Type')\nplt.ylabel('Frecuency')\nplt.title('Phrase type frecuency:')\n\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-24T15:17:04.166409Z","iopub.execute_input":"2023-07-24T15:17:04.166758Z","iopub.status.idle":"2023-07-24T15:17:04.843928Z","shell.execute_reply.started":"2023-07-24T15:17:04.166728Z","shell.execute_reply":"2023-07-24T15:17:04.842934Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### 1) Análisis de secuencias: \n\nHemos visto que cada archivo de datos contiene aproximadamente unas 1000 secuencias de referencia cada uno. Si analizamos dichas secuencias se ha comprobado que cada una representa frases de distintas características y naturaleza con un determinado número de caracteres. Del mismo modo se ha observado también que cada secuencia está compuesta por un número diferente de frames, siendo por tanto unas más largas que otras. \n\nPor esta razón, se llevará un análisis de las secuendcias atendiendo por un lado alnúmero de caracteres que contiene la frase que representan y por otro, al número de frames necesarios para representarlas.","metadata":{}},{"cell_type":"markdown","source":"**1.1) Análisis de los caracteres y longitud de la frase contenida en cada secuencia:**\n\nExtraemos de la frase los caracteres y la longitud de la frase.","metadata":{}},{"cell_type":"code","source":"# Split Phrase To Char Tuple\ntrain_df['phrase_char'] = train_df['phrase'].apply(tuple)\n# Character Length of Phrase\ntrain_df['phrase_char_len'] = train_df['phrase_char'].apply(len)\n\n# Maximum Input Length\nMAX_PHRASE_LENGTH = train_df['phrase_char_len'].max()\nprint(f'MAX_PHRASE_LENGTH: {MAX_PHRASE_LENGTH}')\n\n# Train DataFrame indexed by sequence_id to convenientlyy lookup recording data\ntrain_sequence_id = train_df.set_index('sequence_id')\n\ntrain_df.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-24T15:17:17.000378Z","iopub.execute_input":"2023-07-24T15:17:17.000744Z","iopub.status.idle":"2023-07-24T15:17:17.121922Z","shell.execute_reply.started":"2023-07-24T15:17:17.000714Z","shell.execute_reply":"2023-07-24T15:17:17.120866Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Character Count Occurance\nplt.figure(figsize=(14,6))\n\nsns.countplot(data=train_df, x='phrase_char_len', color='skyblue')\nplt.xlabel('Phrase Character Length')\nplt.ylabel('Sample Count')\nplt.title('Character Length Occurance of Phrases:')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-24T15:17:19.827929Z","iopub.execute_input":"2023-07-24T15:17:19.828658Z","iopub.status.idle":"2023-07-24T15:17:20.738776Z","shell.execute_reply.started":"2023-07-24T15:17:19.828623Z","shell.execute_reply":"2023-07-24T15:17:20.737828Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**1.2) Análisis del número de frames contenidos por secuencia:**\n\nDado que cada archivo puede contener muchas secuencias de landmark, vamos a visualizar la distribución de la cantidad de fotogramas en cada secuencia para entender su variabilidad y posiblemente detectar secuencias atípicas o muy cortas/largas.\n\nPara ello:\n\n- Define una variable `N` que indica el número de fragmentos de archivos Parquet que se analizarán. Si la variable IS_INTERACTIVE es True, se establece N en 5, de lo contrario, se establece en 25.\n- Define una lista vacía `N_UNIQUE_FRAMES` que se utilizará para almacenar el número de frames únicos en cada grabación. \n- Crea una serie `UNIQUE_FILE_PATHS` que contiene las rutas únicas de los archivos del DataFrame train en la columna \"file_path\".\n- Luego, se itera sobre una muestra aleatoria de N rutas de archivos obtenidas de UNIQUE_FILE_PATHS utilizando UNIQUE_FILE_PATHS.sample(N, random_state=SEED). Esto implica seleccionar aleatoriamente un subconjunto de rutas de archivo para analizar.\n- Para cada ruta de archivo seleccionada, se lee el archivo Parquet correspondiente utilizando pd.read_parquet(file_path) y se almacena en el DataFrame df. A continuación, el DataFrame df se agrupa por el valor de la columna \"sequence_id\" utilizando groupby('sequence_id').\n- Para cada grupo (grupo de secuencias con el mismo ID), se calcula el número de cuadros únicos en la columna \"frame\" utilizando group_df['frame'].nunique().El número de cuadros únicos obtenidos se agrega a la lista N_UNIQUE_FRAMES.","metadata":{}},{"cell_type":"code","source":"# If Notebook Is Run By Committing or In Interactive Mode For Development\nIS_INTERACTIVE = os.environ['KAGGLE_KERNEL_RUN_TYPE'] == 'Interactive'\n# Global Random Seed\nSEED = 42\n\n# Number of parquet chunks to analyse\nN = 5 if IS_INTERACTIVE else 25\n# Number of Unique Frames in Recording\nN_UNIQUE_FRAMES = []\n\nUNIQUE_FILE_PATHS = pd.Series(train_df['file_path'].unique()) # total file paths\n\nfor idx, file_path in enumerate(tqdm(UNIQUE_FILE_PATHS.sample(N, random_state=SEED))):\n    df = pd.read_parquet(file_path) # read the parquet \n    for group, group_df in df.groupby('sequence_id'):\n        N_UNIQUE_FRAMES.append(group_df['frame'].nunique())\n\n# Convert to Numpy Array\nN_UNIQUE_FRAMES = np.array(N_UNIQUE_FRAMES)","metadata":{"execution":{"iopub.status.busy":"2023-07-24T15:17:42.499672Z","iopub.execute_input":"2023-07-24T15:17:42.500046Z","iopub.status.idle":"2023-07-24T15:19:33.19853Z","shell.execute_reply.started":"2023-07-24T15:17:42.500007Z","shell.execute_reply":"2023-07-24T15:19:33.197339Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(15,8))\nplt.title('Number of Unique Frames:', size=24)\npd.Series(N_UNIQUE_FRAMES).plot(kind='hist', bins=128, color= 'salmon')\n\nxlim = math.ceil(plt.xlim()[1])\nplt.xlim(0, xlim)\nplt.xticks(np.arange(0, xlim, 50))\nplt.grid()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-24T15:25:55.066174Z","iopub.execute_input":"2023-07-24T15:25:55.066733Z","iopub.status.idle":"2023-07-24T15:25:55.764992Z","shell.execute_reply.started":"2023-07-24T15:25:55.066691Z","shell.execute_reply":"2023-07-24T15:25:55.764078Z"},"trusted":true},"execution_count":null,"outputs":[]}]}