{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":81933,"databundleVersionId":9643020,"sourceType":"competition"}],"dockerImageVersionId":30775,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd # for data manipulation/analysis tabularly \nimport numpy as np # for calculations and working with arrays\nimport matplotlib.pyplot as plt # for visuals\nimport seaborn as sns # for graphics (easier)\nfrom sklearn.model_selection import train_test_split # splits dataset into training and testing sets\nfrom sklearn.ensemble import RandomForestClassifier # builds models\nfrom sklearn.metrics import classification_report, confusion_matrix # evaluates performance of model\nfrom sklearn.preprocessing import StandardScaler # standardize data\nfrom sklearn.decomposition import PCA # dimensionality reduction = visualizing and improving model performance","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:13:52.560144Z","iopub.execute_input":"2025-02-16T22:13:52.560401Z","iopub.status.idle":"2025-02-16T22:13:52.565963Z","shell.execute_reply.started":"2025-02-16T22:13:52.560378Z","shell.execute_reply":"2025-02-16T22:13:52.565028Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# to load csv data\ntrainSet = pd.read_csv('/kaggle/input/child-mind-institute-problematic-internet-use/train.csv')\ntestSet = pd.read_csv('/kaggle/input/child-mind-institute-problematic-internet-use/test.csv')\ntrainSet[:15] # to check the training data","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:13:52.567260Z","iopub.execute_input":"2025-02-16T22:13:52.567569Z","iopub.status.idle":"2025-02-16T22:13:52.633874Z","shell.execute_reply.started":"2025-02-16T22:13:52.567539Z","shell.execute_reply":"2025-02-16T22:13:52.632955Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# to get stat details on the training se (variable features - distribution, scale, etc.)\ntrainSet.describe().transpose()","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:13:52.634847Z","iopub.execute_input":"2025-02-16T22:13:52.635096Z","iopub.status.idle":"2025-02-16T22:13:52.739233Z","shell.execute_reply.started":"2025-02-16T22:13:52.635074Z","shell.execute_reply":"2025-02-16T22:13:52.738227Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"trainSet.info() # tells us about the dataset structure (3960 entries, 82 columns)\n# quite a few columns like Physical-Weight, Physical-HeartRate, etc., have NaN values - cleaning needed","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:13:52.741634Z","iopub.execute_input":"2025-02-16T22:13:52.741949Z","iopub.status.idle":"2025-02-16T22:13:52.755460Z","shell.execute_reply.started":"2025-02-16T22:13:52.741923Z","shell.execute_reply":"2025-02-16T22:13:52.754677Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"trainSet['sii'].value_counts() # breakdown of sii rankings across the values (ranking ranges from 0 to 3)\n# background: sii = severity impairment index (standard measure of problematic internet use): 0 for None, 1 for Mild, 2 for Moderate, and 3 for Severe","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:13:52.756480Z","iopub.execute_input":"2025-02-16T22:13:52.756799Z","iopub.status.idle":"2025-02-16T22:13:52.770584Z","shell.execute_reply.started":"2025-02-16T22:13:52.756768Z","shell.execute_reply":"2025-02-16T22:13:52.769557Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# many columns have NaN values, so we set a threshold for cleaning to be 50%\n# if column has more than 50% non-NaN values, we keep them selected (bc they are more reliable data)\n# otherwise, we replace NaN values with zero in columns with less than 50% non-NaN values (helps mainutain consistency and avoid issues during modeling)\n\nthreshold = 0.5 * len(trainSet) # take half the length of the training set\nreliableCols = trainSet.columns[trainSet.isnull().sum() < threshold] # pick cols from training set where missing values < 50%\ntrainSet = trainSet[reliableCols] # the data we train model with will be just reliableCols\n\ntrainSet = trainSet.fillna(0) # replace any NaN values in the training set with zeroes","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:13:52.771775Z","iopub.execute_input":"2025-02-16T22:13:52.772068Z","iopub.status.idle":"2025-02-16T22:13:52.789732Z","shell.execute_reply.started":"2025-02-16T22:13:52.772043Z","shell.execute_reply":"2025-02-16T22:13:52.788788Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"targetCol = 'sii' # target = what we want to predict or analyze\ntrainSetCleaned = trainSet.dropna(subset=[targetCol]) # so, get rid of rows that have missing sii values (this way, we only deal with complete data for target variable)\n\ntrainSetCleaned[:10] # check that this works and there is a cleaned set\ntrainSetCleaned.info() # details about the cleaned training set","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:13:52.790829Z","iopub.execute_input":"2025-02-16T22:13:52.791169Z","iopub.status.idle":"2025-02-16T22:13:52.810745Z","shell.execute_reply.started":"2025-02-16T22:13:52.791137Z","shell.execute_reply":"2025-02-16T22:13:52.809609Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# categorical (object) columns besides 'id'\ncategoryCols = ['Basic_Demos-Enroll_Season', 'CGAS-Season', 'Physical-Season','FGC-Season', 'BIA-Season', 'PCIAT-Season', 'SDS-Season', 'PreInt_EduHx-Season'] \n\n# need boxplots btwn target (sii) and the categorical columns (excluding 'id')\nplt.figure(figsize = (16, 24))\n\nfor i, col in enumerate(categoryCols, 1): # i for index, enumerate iterates over categorical columns\n    plt.subplot(4, 2, i)  # 4 rows, 2 columns, plot i\n    sns.boxplot(x = col, y = 'sii', data = trainSetCleaned)\n    plt.xticks(rotation = 45)\n    plt.title(f\"'sii' vs {col}\")\n\nplt.tight_layout()\nplt.show()\n\n# how do these categories (season of enrollment/participation for bio-electric impedance analysis, parent-child internet addiction test, sleep disturbance scale, \n# children's global assessment scale, physical measures, fitnessgram, internet use) affect the sii rankings?","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:13:52.812155Z","iopub.execute_input":"2025-02-16T22:13:52.812469Z","iopub.status.idle":"2025-02-16T22:13:54.104886Z","shell.execute_reply.started":"2025-02-16T22:13:52.812439Z","shell.execute_reply":"2025-02-16T22:13:54.103819Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"numericCols = trainSetCleaned.select_dtypes(include=['float64', 'int64']).columns # now consider the numerical columns that have floats and integers as values\n\n# to define plots per row \nplotsPerRow = 5\nnumRows = (len(numericCols) + plotsPerRow - 1) // plotsPerRow\n\n# compare sii rankings against numerical columns\nplt.figure(figsize = (20, 4 * numRows))\n\nfor i, col in enumerate(numericCols): # i is index, enumerate iterates over (in this case) the numerical columns\n    plt.subplot(numRows, plotsPerRow, i + 1)\n    sns.boxplot(x = 'sii', y = col, data = trainSetCleaned)\n    plt.title(col)\n    plt.tight_layout()\n\nplt.show()\n\n# similar thought: how do the numerical columns affect the sii rankings?","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:13:54.106030Z","iopub.execute_input":"2025-02-16T22:13:54.106311Z","iopub.status.idle":"2025-02-16T22:14:29.718320Z","shell.execute_reply.started":"2025-02-16T22:13:54.106286Z","shell.execute_reply":"2025-02-16T22:14:29.717309Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# categorical columns for seasons\nseasonCols = ['Basic_Demos-Enroll_Season', 'CGAS-Season', 'Physical-Season', 'FGC-Season', 'BIA-Season', 'PCIAT-Season', 'SDS-Season', 'PreInt_EduHx-Season']\nseasonMap = {'Spring': 0,'Summer': 1,'Fall': 2,'Winter': 3} # to encode these, we create a mapping that assigns numbers to each season (easier for algorithms to work with)\n\n# loop through each season column to replace them with integer numbers (bc most ml models need numerical input)\nfor col in seasonCols:\n    if col in trainSetCleaned.columns: # if we get a column that is part of the training set's included columns...\n        trainSetCleaned[col] = trainSetCleaned[col].replace(seasonMap).infer_objects(copy=False).astype(int) # replace the values in the column with the number mapping\n        # also make sure that values will be stored as integers + helps in cases where values were previously objects (strings) to make them integers","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:14:29.719637Z","iopub.execute_input":"2025-02-16T22:14:29.719978Z","iopub.status.idle":"2025-02-16T22:14:29.746553Z","shell.execute_reply.started":"2025-02-16T22:14:29.719943Z","shell.execute_reply":"2025-02-16T22:14:29.745604Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"trainSetNoID = trainSetCleaned.drop(columns = ['id'], errors = 'ignore') # ignore the ID column bc it is unneeded for analysis\ncorrelMatrix = trainSetNoID.corr() # to get correlation matrix, which quantifies how strongly pairs of features are related to each other (on scale of -1 to +1)\n# positive value = direct relationship, negative value = inverse one\n\n# now a heatmap to tie it all together\n# colors = correlation strength (visually helps us pinpoint which features are most closely correlated)\nplt.figure(figsize = (30, 30))\nsns.heatmap(correlMatrix, annot = True, fmt = '.1f', cmap = 'coolwarm', square = True) # bluer\nplt.title('Correlation Heatmap')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:14:29.748276Z","iopub.execute_input":"2025-02-16T22:14:29.748610Z","iopub.status.idle":"2025-02-16T22:14:36.622322Z","shell.execute_reply.started":"2025-02-16T22:14:29.748575Z","shell.execute_reply":"2025-02-16T22:14:36.620900Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"colsInCommon = trainSetCleaned.columns.intersection(testSet.columns) # check cleaned training set and test set to see what columns are shared in common\n\n# Prepare the feature matrix X and target vector y\nX = trainSetCleaned[colsInCommon].drop(columns=['id']) # select the shared columns from the cleaned training set, but ignore the ID column (which is useless for modeling)\ny = trainSetCleaned['sii'] # the sii column in the cleaned training set bc it is our target variable that we want to predict (helps prep for ml model)","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:14:36.623539Z","iopub.execute_input":"2025-02-16T22:14:36.623881Z","iopub.status.idle":"2025-02-16T22:14:36.632077Z","shell.execute_reply.started":"2025-02-16T22:14:36.623846Z","shell.execute_reply":"2025-02-16T22:14:36.631324Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 2) # to split matrix X and target vector y into training and testing sets\n# train_test_split is a scikit-learn function; test_size = 0.2 means it will set aside 20% of the data for testing (to help evaluate model performance later on)","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:14:36.635274Z","iopub.execute_input":"2025-02-16T22:14:36.635622Z","iopub.status.idle":"2025-02-16T22:14:36.645715Z","shell.execute_reply.started":"2025-02-16T22:14:36.635591Z","shell.execute_reply":"2025-02-16T22:14:36.644629Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# to standardize the features in X to have mean of 0 and stdev of 1 (helps improve ml algorithm performances)\nscaler = StandardScaler()\nX_train_scaled = scaler.fit_transform(X_train) # fits scaler (gets mean and stdev) on X_train \nX_test_scaled = scaler.transform(X_test) # uses the same mean and stdev to transform X_test\n\n# remember: \n# X = the columns shared in common between the cleaned training set and test set\n# y = the sii rankings column from cleaned training set","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:14:36.646963Z","iopub.execute_input":"2025-02-16T22:14:36.647378Z","iopub.status.idle":"2025-02-16T22:14:36.667078Z","shell.execute_reply.started":"2025-02-16T22:14:36.647344Z","shell.execute_reply":"2025-02-16T22:14:36.666005Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# pca for dimensionality reduction of the testing and training sets\npca = PCA(n_components = 0.95)  # we keep 95% of the variance \nX_train_pca = pca.fit_transform(X_train_scaled) # fits pca on standardized X_train_scaled to make it lower-dimension\nX_test_pca = pca.transform(X_test_scaled) # uses same pca transformation on X_test_scaled to keep consistent with training data\n\n# X_train_pca has less features, but the most important patterns in the data are represented","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:14:36.668756Z","iopub.execute_input":"2025-02-16T22:14:36.669140Z","iopub.status.idle":"2025-02-16T22:14:36.691064Z","shell.execute_reply.started":"2025-02-16T22:14:36.669092Z","shell.execute_reply":"2025-02-16T22:14:36.688051Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# to create the random forest classifier (improves prediction accuracy and controls overfitting)\nrfModel = RandomForestClassifier(n_estimators = 100, random_state = 42, max_depth = 10,  min_samples_split = 10, min_samples_leaf=4)\n# we use 100 decision trees, limit each tree's depth to 10, and set the min and max samples for splitting/leaf nodes to make sure the model generalizes adequately","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:14:36.693188Z","iopub.execute_input":"2025-02-16T22:14:36.694455Z","iopub.status.idle":"2025-02-16T22:14:36.710022Z","shell.execute_reply.started":"2025-02-16T22:14:36.694428Z","shell.execute_reply":"2025-02-16T22:14:36.708187Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# to fit random forest model to pca-transformed data\nrfModel.fit(X_train_pca, y_train) \n# use random forest for the pca-transformed/reduced X features and target vector y from training set","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:14:36.711419Z","iopub.execute_input":"2025-02-16T22:14:36.712498Z","iopub.status.idle":"2025-02-16T22:14:37.614467Z","shell.execute_reply.started":"2025-02-16T22:14:36.712471Z","shell.execute_reply":"2025-02-16T22:14:37.613547Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# to make predictions on the test set, which has data the model hasn't seen yet\ny_pred = rfModel.predict(X_test_pca) \n# make predictions about the sii rankings (y) based on the pca-reduced X_test data\n\nprint('Classification Report: ') # for making classification report\nprint(classification_report(y_test, y_pred)) # print the actual sii rankings versus model's predicted ones\n\nprint('\\nExplanation of the Classification Report:')\nprint('precision = how many predicted positives were actual positives (minimizes false POSITIVES).')\nprint('recall = how many actual positives were correctly identified (minimizes false NEGATIVES).')\nprint('f1-score = harmonic mean of precision and recall.')\nprint('support = number of actual occurrences of the class in the dataset.\\n')\n\nprint('Confusion Matrix: ')\nprint(confusion_matrix(y_test, y_pred)) # get confusion matrix to evaluate the model's prediction accuracy\n\nprint('\\nExplanation of the Confusion Matrix:')\nprint('each row = actual class; each column = predicted class.')\nprint('for example, entry at (i, j) = number of times class i was predicted as class j.')\nprint('diagonal entries = number of correct predictions for each class.')\nprint('off-diagonal entries = misclassifications.\\n')\n\naccuracy = rfModel.score(X_test_pca, y_test) \n# how do the actual (test) sii rankings compare to what model predicted from pca-reduced training set X features?\n\nprint(f'Model accuracy is {accuracy}.')","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:14:37.615694Z","iopub.execute_input":"2025-02-16T22:14:37.616022Z","iopub.status.idle":"2025-02-16T22:14:37.658107Z","shell.execute_reply.started":"2025-02-16T22:14:37.615990Z","shell.execute_reply":"2025-02-16T22:14:37.656990Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# define all columns for SEASONS (not looking strictly at categorical or numerical this time!!)\nseasonColDef = ['Basic_Demos-Enroll_Season', 'CGAS-Season', 'Physical-Season', 'FGC-Season', 'BIA-Season', 'PCIAT-Season', 'SDS-Season', 'PreInt_EduHx-Season']\nseasonMapper = {'Spring': 0, 'Summer': 1, 'Fall': 2, 'Winter': 3} # create a season mapper again\n\nfor col in seasonColDef: # replace season values in test data using the mapping\n    if col in testSet.columns:  # Check if the column exists in testSet\n        testSet[col] = testSet[col].map(seasonMapper) \n        # if column does exist, replace season name values with number mapping","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:14:37.659359Z","iopub.execute_input":"2025-02-16T22:14:37.659602Z","iopub.status.idle":"2025-02-16T22:14:37.670377Z","shell.execute_reply.started":"2025-02-16T22:14:37.659579Z","shell.execute_reply":"2025-02-16T22:14:37.669517Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"testSet.fillna(0, inplace=True) # replace any NaN values with zeroes in the testing set\ncolsInCommon = trainSetCleaned.columns.intersection(testSet.columns) # check cleaned training set and test set to see what columns are shared in common\n\n# to prep test data using columns shared in common\nX_test_data = testSet[colsInCommon].drop(columns = ['id']) # consider all test data columns except ID one\nX_test_scaled = scaler.transform(X_test_data) # same scaler used on training data gets used on test data\n\n# for applying pca to test data\nX_test_pca = pca.transform(X_test_scaled) #pca-reduced test X features are just the scaled test X features with pca transformations made\npredictor = rfModel.predict(X_test_pca) # now make predictions based on the pca-reduced test data X features\n\nfinish = pd.DataFrame({'id': testSet['id'], 'sii': predictor}) # use the ID from testing set + the model's predicted sii rankings\nfinish.to_csv('submission.csv', index = False) # to save final dataframe as csv file\nprint(finish[:30]) # check that final dataframe is good to go","metadata":{"execution":{"iopub.status.busy":"2025-02-16T22:14:37.671290Z","iopub.execute_input":"2025-02-16T22:14:37.671516Z","iopub.status.idle":"2025-02-16T22:14:37.708301Z","shell.execute_reply.started":"2025-02-16T22:14:37.671494Z","shell.execute_reply":"2025-02-16T22:14:37.706992Z"},"trusted":true},"outputs":[],"execution_count":null}]}