{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Dicom Data: Get Patient Demographics\n\n**Purpose:** This notebook is a starter for gathering patient demographics data from the dicom data on an image by image basis.\n\n**Description:** This notebook is helping me learn code documentation and coding best practices in Python. Also a starter for working with dicom data, which is new to me. Any criticism is appreciated.\n\n_Currently, I only see three demographic features that I would use alongside the pixel data for this project._\n\n[Link to the overview of the \"VinBigData Chest X-ray Abnormalities Detection\" Competition](http://www.kaggle.com/c/vinbigdata-chest-xray-abnormalities-detection)"},{"metadata":{},"cell_type":"markdown","source":"## Import Packages"},{"metadata":{"trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport pydicom\nimport typing\nimport warnings\nwarnings.filterwarnings(\"ignore\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Get Data\n\nUse the **path** parameter to read the training data CSV file into the notebook as a pandas dataframe."},{"metadata":{"trusted":true},"cell_type":"code","source":"# filepath to chest x-ray dicom data\npath = '/kaggle/input/vinbigdata-chest-xray-abnormalities-detection/'\n\ntrain_data = pd.read_csv(path+'train.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# list of demographic features\ndemo_features = ['PatientAge','PatientSex','PatientSize']\n\n# randomly picked test image from training data\ntest_image_id = train_data.image_id[6]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Custom Functions\n\n+ withdraw_element\n+ get_demographics"},{"metadata":{"trusted":true},"cell_type":"code","source":"def withdraw_element(x):\n    \"\"\"\n    Gets the data element from the raw element from the dicom data if raw, else returns the dicom data element.\n    \n    Parameters:\n    -----------\n        x (DataElement or RawDataElement): a dicom data element\n    \n    Returns:\n    --------\n        x (DataElement)\n    \"\"\"\n    if isinstance(x, pydicom.dataelem.RawDataElement):\n        return(pydicom.dataelem.DataElement_from_raw(x))\n    else:\n        return(x)\n\ndef get_demographics(image_id: str, demo_features: list)->pd.DataFrame:\n    \"\"\"\n    Gets the demographic feature values from the dicom data associated with an image_id and returns a dataframe with values labeled by columns.\n    \n    Parameters:\n    -----------\n        image_id (str): an alpha-numeric string corresponding to an images id\n        \n        demo_features (list): a list of strings corresponding to demographic features the user wants from the dicom data\n        \n    Returns:\n    --------\n        result_df (pandas dataframe): a dataframe of the demographic features and their values for the image_id\n    \"\"\"\n    file_path = path+'train/'+image_id+'.dicom'\n    meta_data = pydicom.dcmread(file_path)\n    \n    demo_values = [image_id]\n    for demo in demo_features:\n        try:\n            demo_values.append(withdraw_element(meta_data[demo]).value) # not all image_id meta data files have all demographic features\n        except:\n            demo_values.append('NaN')\n    result_df = pd.DataFrame(data = demo_values, index = [['image_id'] + demo_features]).T\n    \n    return(result_df)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Get Patient Demographics from Dicom Data\n\nUse the image_id to grab the only three demographic features seen in the data so far: Age, Sex, and Size.  If more are found, add them to the **demo_features** list parameter."},{"metadata":{"trusted":true},"cell_type":"code","source":"# get_demographics function result on single test image\n\ntest_results = get_demographics(test_image_id, demo_features)\nprint(test_results)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\n# get_demographics function result on dataframe\n\ntest_df = train_data[0:100]\n\npd.concat([get_demographics(x,demo_features) for x in test_df.image_id]) # concatenating a list of dataframes along the 0 axis returns a dataframe","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now, you can merge this demographic info with the pixel data using the unique image_id.\n\n### **Please upvote this notebook if you found it usefull!**"},{"metadata":{},"cell_type":"markdown","source":"## References\n\n* [Extracting raw elements from Dicom data with pydicom package](http://stackoverflow.com/questions/56601525/how-to-store-the-header-data-of-a-dicom-file-in-a-pandas-dataframe)\n* [drcapa's notebook for viewing the pixel data](http://www.kaggle.com/drcapa/chest-x-ray-starter)"},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}