{"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":"# Install two dedicated libraries for handling jpeg2000 files\n!pip install -qU python-gdcm pylibjpeg\n\n#Install dicomsdl for handling dicom files a little faster\n!pip install -qU dicomsdl","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-02-24T23:06:10.679028Z","iopub.execute_input":"2023-02-24T23:06:10.679402Z","iopub.status.idle":"2023-02-24T23:06:30.73166Z","shell.execute_reply.started":"2023-02-24T23:06:10.679369Z","shell.execute_reply":"2023-02-24T23:06:30.730383Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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 numpy.random\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport matplotlib.pyplot as plt # for making plots\nfrom tqdm.notebook import tqdm\nimport sys\nfrom multiprocessing import cpu_count\nimport cv2\nimport ray #Used for parallel processing quickly\nimport time\nfrom sklearn.model_selection import train_test_split\nimport glob\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\nimport os\n#for dirname, _, filenames in os.walk('/kaggle/input'):\n#    for filename in filenames:\n#        (os.path.join(dirname, filename))\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-02-24T23:06:30.734832Z","iopub.execute_input":"2023-02-24T23:06:30.735262Z","iopub.status.idle":"2023-02-24T23:06:30.744639Z","shell.execute_reply.started":"2023-02-24T23:06:30.735223Z","shell.execute_reply":"2023-02-24T23:06:30.743587Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Import csv data as a data frame.\ncsv_train = pd.read_csv(\"/kaggle/input/rsna-breast-cancer-detection/train.csv\")\ncsv_test = pd.read_csv(\"/kaggle/input/rsna-breast-cancer-detection/test.csv\")\n\ncsv_train.info()\n# age, BIRADS, and density are missing some entries; the latter two are missing many.","metadata":{"execution":{"iopub.status.busy":"2023-02-24T23:06:30.746417Z","iopub.execute_input":"2023-02-24T23:06:30.747265Z","iopub.status.idle":"2023-02-24T23:06:30.842289Z","shell.execute_reply.started":"2023-02-24T23:06:30.747228Z","shell.execute_reply":"2023-02-24T23:06:30.841101Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# For a preliminary attempt, let's drop rows that are not even in the test set.\ncolumns_in_test = []\nfor col in csv_test.columns:\n    if col != 'prediction_id': # This column is not in the training set.\n        columns_in_test.append(col)\ncolumns_in_test.append('cancer') # Make sure we don't drop the target column yet!\nprint(columns_in_test)\n\ndata_train = csv_train[columns_in_test]\n# data_train.head()\n\n#One single stupid file is completely blank for no reason: patient 822 image 1942326353. I manually remove it\nbad_ids = [1942326353, 1078943060, 398038886, 439796429, 63473691]\n\ndata_train = data_train.drop(data_train[data_train['image_id'].isin(bad_ids)].index)\ndata_train.shape\n\n# Get rid of entries with missing age, since there's only a small number of these.\ndata_train = data_train.dropna(subset=['age'])\n# Let's rescale so that ages listed are between (0, 1) for CNN convenience.\ndata_train['age'] = data_train['age'] / data_train['age'].max()","metadata":{"execution":{"iopub.status.busy":"2023-02-24T23:06:30.845449Z","iopub.execute_input":"2023-02-24T23:06:30.845902Z","iopub.status.idle":"2023-02-24T23:06:30.878268Z","shell.execute_reply.started":"2023-02-24T23:06:30.845853Z","shell.execute_reply":"2023-02-24T23:06:30.877204Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create a list of all cancer patients and non cancer patients.\ncancer_train = data_train.loc[csv_train.cancer == 1]\nnocancer_train = data_train.loc[csv_train.cancer == 0]\n\ncancer_train.head()","metadata":{"execution":{"iopub.status.busy":"2023-02-24T23:06:30.880174Z","iopub.execute_input":"2023-02-24T23:06:30.881098Z","iopub.status.idle":"2023-02-24T23:06:30.908619Z","shell.execute_reply.started":"2023-02-24T23:06:30.88106Z","shell.execute_reply":"2023-02-24T23:06:30.907519Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# The PNGs were finally output successfully! They are now saved & imported to Input.\n# Time to start training on the data.\n\n# Converting all the PNGs back to np.array's & adding relevant data from\n# the CSV file entries for each image.\n# According to https://www.kaggle.com/code/devashishprasad/fastest-way-to-read-and-process-images\n# PIL has a pretty fast image importing process.\nimport PIL\nfrom PIL import Image\n\n# Parallel processing iterator. Runs \"ray.get()\" on each ray future.\ndef to_iterator(obj_ids):\n    while obj_ids:\n        done,  obj_ids = ray.wait(obj_ids)\n        yield ray.get(done[0])\n\n#Getting one png\ndef import_PNG(imagepath):\n    im = (np.array( Image.open(imagepath)) / 255.  )\n    return im\n\n@ray.remote\ndef create_info_array(imagepath, csv_info):\n    \n    image_id = imagepath.split('/')[-1].split('.')[0] #get image id from filename\n    image_id = int(image_id)\n    csv_image_data = csv_info.loc[csv_info['image_id'] == image_id] #get proper row\n    # we don't need the patient_id or image_id, it carries no clinical information\n    csv_image_data = csv_image_data.drop(['patient_id', 'image_id'], axis=1) \n    \n    image_data = list(csv_image_data.values.tolist()[0]) #convert to list\n    image = import_PNG(imagepath) #get the image as an np array\n    return image, image_data\n\ndef onehot(df, encode):\n    temp = pd.get_dummies(df[encode])\n    df = df.drop([encode], axis=1)\n    df = pd.concat([df, temp], axis=1)\n    return df\n\n# For now let's assume these are not relevant; I find it unlikely that location has that much relevance here.\n# Some areas may be e.g. more affluent than others which could in principle affect results, but we have\n# little information about the sites or machines to deduce anything meaningful.\nirrelevant_col = ['machine_id', 'site_id'] \ndata_train_relevant = data_train.drop(irrelevant_col, axis=1)\n\n# One-Hot: the Laterality and View columns are strings; there's only a few types of entries for each so let's just one-hot encode them.\nonehotcols = ['laterality', 'view']\nfor col in onehotcols:\n    data_train_relevant = onehot(data_train_relevant, col)\n\n# Implant column is a int64 for some reason; let's convert it to uint8 so it's lighter.\ndata_train_relevant['implant'] = data_train_relevant['implant'].astype('uint8')\n\n#Now we have all of the csv data in numerical values. We can input it to a network easily.\n\npngfolder = '/kaggle/input/rnsa-s-m-pngs-v2/train/processed_512'","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-02-24T23:06:30.910597Z","iopub.execute_input":"2023-02-24T23:06:30.911402Z","iopub.status.idle":"2023-02-24T23:06:30.953579Z","shell.execute_reply.started":"2023-02-24T23:06:30.911366Z","shell.execute_reply":"2023-02-24T23:06:30.952591Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#g = glob.iglob(pngfolder + '/**/*.png', recursive=True) #this was to test some weird error, commenting it out\n#for i in range(10):\n#    print(next(g))","metadata":{"execution":{"iopub.status.busy":"2023-02-24T23:06:30.955422Z","iopub.execute_input":"2023-02-24T23:06:30.956227Z","iopub.status.idle":"2023-02-24T23:06:30.960953Z","shell.execute_reply.started":"2023-02-24T23:06:30.956192Z","shell.execute_reply":"2023-02-24T23:06:30.959869Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.layers import *\nfrom tensorflow.keras.models import Sequential, Model\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\ngpu_devices = tf.config.experimental.list_physical_devices('GPU')\nfor device in gpu_devices:\n    tf.config.experimental.set_memory_growth(device, True)\n\nwith tf.device('/gpu:0'):\n    # convoluting and pooling image - convolution less consequential than pooling for image dimension\n    \n    input_Image = tf.keras.layers.Input(shape=(512,512, 1))\n    print(type(input_Image))\n    \n    # randomly rotate image\n    iput_Image = tf.keras.layers.RandomRotation((-0.4, 0.4))(input_Image)\n    \n    print(type(iput_Image))\n    \n    \n    print(iput_Image.get_shape())\n    \n    # relu is a transformation applied to the output of a node\n    conv_Image = Conv2D(3, 13, activation='relu', \n                        input_shape = (512, 512, 1))(iput_Image) # convolution neural network\n\n    \n    \n    print(conv_Image.get_shape())\n    \n    # we take the max of different sections of the image, similar to the concept of a kernal\n    # my gut is that pool size can be much smaller. We can test out a few different iterations\n    pool_Image = MaxPooling2D(pool_size=10)(conv_Image) # to reduce the size of the image for input to the rest of the ML\n                        \n   \n    \n    print(pool_Image.get_shape())\n    \n#     seems to be 25, 25, 10 shape\n\n#   second round of convolutions / pooling \n\n    conv_Image = Conv2D(3, 5, activation='relu', \n                        input_shape = (50, 50, 3))(pool_Image)\n    \n    print(conv_Image.get_shape())\n\n    \n    pool_Image = MaxPooling2D(pool_size=4)(conv_Image)\n    \n    print(pool_Image.get_shape())\n    \n    \n    \n    flatten_Image = Flatten()(pool_Image)\n    \n    # concating the input tags to the image\n    input_Tags = Input(shape=(10,))\n    input_all = Concatenate()([flatten_Image, input_Tags])\n    \n    \n    # added more nodes per layer and more layers\n    CNN = GaussianNoise(0.1)(input_all)\n    CNN = Dense(10, activation='relu')(CNN)\n#     CNN = Dense(10, activation='relu')(CNN)\n#     CNN = Dense(10, activation='relu')(CNN)\n    CNN = Dense(10, activation='relu')(CNN)\n    CNN = Dense(1, activation='sigmoid')(CNN)\n\n\n    ML = Model(inputs=[input_Image, input_Tags], outputs=CNN)\n    ML.summary()\n    \n    # seems to be the right loss function - used for binary outcomes\n    # I set from_logits to True because I'm not assuming that things are standardized. It generally seems like a safer option\n    \n    # decreased learning rate significantly to avoid immediately finding local minimum\n    optimizer = tf.keras.optimizers.Adam(\n    learning_rate=0.01)\n    \n    ML.compile(optimizer=optimizer,\n               loss=tf.keras.losses.BinaryCrossentropy(from_logits=False),\n               metrics=['accuracy']\n              )\n# This ML model appears to be really, really inefficient/slow (?)","metadata":{"execution":{"iopub.status.busy":"2023-02-24T23:06:30.962932Z","iopub.execute_input":"2023-02-24T23:06:30.963747Z","iopub.status.idle":"2023-02-24T23:06:31.113555Z","shell.execute_reply.started":"2023-02-24T23:06:30.963708Z","shell.execute_reply":"2023-02-24T23:06:31.112487Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# defining class weights to mitigate bias \n\ndf_cancer = data_train_relevant.loc[data_train_relevant['cancer']==1]\npos = len(df_cancer.index)\ndf_clear = data_train_relevant.loc[data_train_relevant['cancer']==0]\nneg = len(df_clear.index)\ntotal = (pos + neg)\nprint(pos, neg, total)\n\nweight_for_0 = .6\nweight_for_1 = .5\n\n# weight_for_0 = (50 / neg) * (total / 2.0)\n# weight_for_1 = (1 / pos) * (total / 2.0)\n\nclass_weight = {0: weight_for_0, 1: weight_for_1}\n\nprint('Weight for class 0: {:.2f}'.format(weight_for_0))\nprint('Weight for class 1: {:.2f}'.format(weight_for_1))","metadata":{"execution":{"iopub.status.busy":"2023-02-24T23:06:31.115545Z","iopub.execute_input":"2023-02-24T23:06:31.115926Z","iopub.status.idle":"2023-02-24T23:06:31.134291Z","shell.execute_reply.started":"2023-02-24T23:06:31.115889Z","shell.execute_reply":"2023-02-24T23:06:31.133308Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# def fracture_dataframe(df, samplefrac = 1, samplefrac_clear = 1, seed = None, shuffle = False, signal_frac = None):\n#     out = []\n    \n#     if seed != None:\n#         np.random.seed(seed)\n#     df_cancer = df.loc[df['cancer']==1]\n#     df_clear = df.loc[df['cancer']==0]\n#     if signal_frac == None:\n#         signal_frac = 1\n#     N_cancer = len(df_cancer)\n#     N_clear = len(df_clear)\n#     num_arrays = int(np.ceil(N_cancer / (N_clear/signal_frac)))\n    \n#     df_cancer.sample(frac=samplefrac).reset_index(drop=True, inplace=True)\n#     df_cancer.sample(frac=samplefrac_clear).reset_index(drop=True, inplace=True)\n#     cancer_subarrays = np.array_split(df_cancer, num_arrays)\n    \n#     out = []\n#     for df_frac in cancer_subarrays:\n#         pd_merge = pd.concat([df_frac, df_clear])\n#         pd_merge.sample(frac=samplefrac).reset_index(drop=True, inplace=True)\n#         out.append(pd_merge)\n#     return out","metadata":{"execution":{"iopub.status.busy":"2023-02-24T23:06:31.138384Z","iopub.execute_input":"2023-02-24T23:06:31.139726Z","iopub.status.idle":"2023-02-24T23:06:31.14536Z","shell.execute_reply.started":"2023-02-24T23:06:31.139683Z","shell.execute_reply":"2023-02-24T23:06:31.144184Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# split test and train\ndef split_test_train(df, samplefrac = 1, test_size = 1000):\n    df.sample(frac=samplefrac).reset_index(drop=True, inplace=True)\n    df_bottom = df.iloc[-test_size: ]\n    df = df.iloc[:-test_size]\n    test = df_bottom\n    return test, df\n    \n\n# split train into batches\ndef split_dataframe(df, train_sample = 50, samplefrac = 1):        \n    df_cancer = df.loc[df['cancer']==1].iloc[:train_sample]\n    df_clear = df.loc[df['cancer']==0].iloc[:train_sample]\n    train = pd.concat([df_cancer, df_clear])    \n    train.sample(frac=samplefrac).reset_index(drop=True, inplace=True)\n    return train","metadata":{"execution":{"iopub.status.busy":"2023-02-24T23:06:31.14724Z","iopub.execute_input":"2023-02-24T23:06:31.147608Z","iopub.status.idle":"2023-02-24T23:06:31.160277Z","shell.execute_reply.started":"2023-02-24T23:06:31.147574Z","shell.execute_reply":"2023-02-24T23:06:31.158898Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import sklearn.utils\n\n# We need to manually shuffle the data_frame because \n# the keras validation split functionality doesn't do this!\ndata_train_relevant =  data_train_relevant.sample(frac=1).reset_index(drop=True)\n\n# We'll add a column to the dataframe with all of the filenames to use with flow_from_dataframe.\ndata_train_relevant['file'] = data_train_relevant.apply(\n    lambda x: pngfolder + '/' + str(int(x['patient_id'])) + '/' + str(int(x['image_id'])) \n    + '.png', axis=1)\n\n#print(data_train_relevant.head)\n\n# To create the correct shape of inputs for the network, we need to get both the\n# image data and the csv data -- have all the columns be the \"target y\" for flow_from_dataframe.\n# this function grabs the pngs (from file path 'file' column and the related data in the DF. The image imports happen here)\n#split the sample into training and validation sets\n\n\ndata_test, training_data = split_test_train(data_train_relevant, samplefrac = 1, test_size = 5000)\n\n\n# To create the correct shape of inputs for the network, we need to get both the\n# image data and the csv data -- have all the columns be the \"target y\" for flow_from_dataframe.\ndef data_from_dataframe(directory, generator, subset='training', batch_size = 32, shuffle=True,\n                        data = data_train_relevant, columns = ['cancer'], seed = None):\n    \n    if subset == 'test':\n        subset2 = 'training'\n    else:\n        subset2 = subset\n    \n    gendat = generator.flow_from_dataframe(data, directory=directory, shuffle = shuffle, \n                                           target_size = (ImageSize, ImageSize),\n                                           subset = subset2, batch_size = batch_size,\n                                           x_col = 'file', y_col = columns, \n                                           class_mode = 'multi_output', \n                                           color_mode = 'grayscale', \n                                           validate_filenames=False)\n    \n    i = 0\n    N = gendat.n\n    while i < N:\n        data = gendat.next()\n        x_im = np.array(data[0]).astype(np.float16) # reference to image\n        x_info = np.array(data[1][:-1]).T.astype(np.float16) # data columns\n        y = data[1][-1]  # target column (i.e. cancer)\n        i += batch_size\n        if subset == 'test':\n            yield [x_im, x_info]\n        else:\n            yield [x_im, x_info], y\n\n\nImageSize = 512 # i don't know if we should be resizing this\nval_split = 0.2 \nbatch_size = 32 # in order to conserve memory, maybe we should reduce this\n\ncols = ['age', 'implant', 'L', 'R', 'AT', 'CC', 'LM', 'LMO', 'ML', 'MLO', 'cancer']\n# Make a Keras ImageDataGenerator\nimagegen = ImageDataGenerator(rescale = 1/255, validation_split = val_split)\nimagegen2 = ImageDataGenerator(rescale = 1/255, validation_split = 0)\n\n# batch size just has to do with iterating through the dataframe - every epoch in our ml model iterates through all the batches\n","metadata":{"execution":{"iopub.status.busy":"2023-02-24T23:06:31.162328Z","iopub.execute_input":"2023-02-24T23:06:31.162831Z","iopub.status.idle":"2023-02-24T23:06:31.981343Z","shell.execute_reply.started":"2023-02-24T23:06:31.162661Z","shell.execute_reply":"2023-02-24T23:06:31.980372Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#xtest = next(train_gen)\n# this was for testing to debug a weird error that was coming up","metadata":{"execution":{"iopub.status.busy":"2023-02-24T23:06:31.982612Z","iopub.execute_input":"2023-02-24T23:06:31.982982Z","iopub.status.idle":"2023-02-24T23:06:31.987522Z","shell.execute_reply.started":"2023-02-24T23:06:31.982947Z","shell.execute_reply":"2023-02-24T23:06:31.9865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import gc","metadata":{"execution":{"iopub.status.busy":"2023-02-24T23:06:31.989048Z","iopub.execute_input":"2023-02-24T23:06:31.990075Z","iopub.status.idle":"2023-02-24T23:06:31.996557Z","shell.execute_reply.started":"2023-02-24T23:06:31.990039Z","shell.execute_reply":"2023-02-24T23:06:31.995509Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.callbacks import EarlyStopping, ModelCheckpoint\n\n# don't know if we need checkpointer\n# checkpointer = ModelCheckpoint(filepath='weights.hdf5', \n#                                verbose=1, save_best_only=True)\n\n#  why is validation data a tuple and train gen isn't?\n# CHANGE EPOCHS TO SOMETHING REASONABLE\n\nearly_stopping = EarlyStopping(monitor = 'val_loss', patience = 5)\n\n\nfor counter in range(4000):\n    current_batch = split_dataframe(training_data, train_sample = 50)\n    train_gen = data_from_dataframe(None, imagegen, subset='training', batch_size = batch_size,\n                                data = current_batch, columns = cols)\n    val_gen = data_from_dataframe(None, imagegen, subset='validation', batch_size = batch_size,\n                                data = current_batch, columns = cols)\n    ML.fit(train_gen, epochs=1, validation_data = val_gen, shuffle = True, class_weight = class_weight,\n           validation_steps = 1, batch_size = batch_size, \n           workers = 1, use_multiprocessing = False, \n           steps_per_epoch = (len(data_train_relevant) * (1-val_split)) // batch_size,\n           callbacks = [early_stopping])\n    del train_gen\n    del val_gen\n    del current_batch\n#     gc.collect(0)\n#     gc.collect(1)\n#     gc.collect(2)","metadata":{"execution":{"iopub.status.busy":"2023-02-24T23:06:31.997929Z","iopub.execute_input":"2023-02-24T23:06:31.998553Z","iopub.status.idle":"2023-02-25T00:22:48.676195Z","shell.execute_reply.started":"2023-02-24T23:06:31.998513Z","shell.execute_reply":"2023-02-25T00:22:48.675168Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ML.save_weights('breastcancerpredictor.h5')","metadata":{"execution":{"iopub.status.busy":"2023-02-25T00:22:48.678026Z","iopub.execute_input":"2023-02-25T00:22:48.678686Z","iopub.status.idle":"2023-02-25T00:22:48.699856Z","shell.execute_reply.started":"2023-02-25T00:22:48.678648Z","shell.execute_reply":"2023-02-25T00:22:48.698896Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_gen = data_from_dataframe(None, imagegen2, batch_size = batch_size, subset='test',\n                                data = data_test, columns = cols, shuffle = False)\n#ML.evaluate(test_gen, batch_size = batch_size, workers = cpu_count(), \n#            use_multiprocessing = True, steps = (len(data_test) // batch_size))\ny = ML.predict(test_gen, steps = np.ceil(len(data_test) / batch_size), verbose=1)\nprint(y)\ny = y.T[0]\nprint(y)","metadata":{"execution":{"iopub.status.busy":"2023-02-25T00:22:48.701299Z","iopub.execute_input":"2023-02-25T00:22:48.701925Z","iopub.status.idle":"2023-02-25T00:24:51.305603Z","shell.execute_reply.started":"2023-02-25T00:22:48.701889Z","shell.execute_reply":"2023-02-25T00:24:51.304354Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def pfbeta(labels, predictions, beta=1):\n    y_true_count = 0\n    ctp = 0\n    cfp = 0\n\n    for idx in range(len(labels)):\n        prediction = min(max(predictions[idx], 0), 1)\n        if (labels[idx]):\n            y_true_count += 1\n            ctp += prediction\n        else:\n            cfp += prediction\n\n    beta_squared = beta * beta\n    c_precision = ctp / (ctp + cfp)\n    c_recall = ctp / y_true_count\n    if (c_precision > 0 and c_recall > 0):\n        result = (1 + beta_squared) * (c_precision * c_recall) / (beta_squared * c_precision + c_recall)\n        return result\n    else:\n        return 0","metadata":{"execution":{"iopub.status.busy":"2023-02-25T00:24:51.30752Z","iopub.execute_input":"2023-02-25T00:24:51.308371Z","iopub.status.idle":"2023-02-25T00:24:51.318081Z","shell.execute_reply.started":"2023-02-25T00:24:51.30833Z","shell.execute_reply":"2023-02-25T00:24:51.317029Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels_true = np.array(data_test['cancer'])\nscore_1 = pfbeta(labels_true, y)\nprint(score_1)","metadata":{"execution":{"iopub.status.busy":"2023-02-25T00:24:51.320152Z","iopub.execute_input":"2023-02-25T00:24:51.32133Z","iopub.status.idle":"2023-02-25T00:24:51.374054Z","shell.execute_reply.started":"2023-02-25T00:24:51.321289Z","shell.execute_reply":"2023-02-25T00:24:51.372906Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# plt.hist(y)\nplt.hist(np.array(y))","metadata":{"execution":{"iopub.status.busy":"2023-02-25T00:24:51.376143Z","iopub.execute_input":"2023-02-25T00:24:51.377146Z","iopub.status.idle":"2023-02-25T00:24:51.599373Z","shell.execute_reply.started":"2023-02-25T00:24:51.377088Z","shell.execute_reply":"2023-02-25T00:24:51.598345Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.hist(y-labels_true[:len(y)])","metadata":{"execution":{"iopub.status.busy":"2023-02-25T00:24:51.601306Z","iopub.execute_input":"2023-02-25T00:24:51.602124Z","iopub.status.idle":"2023-02-25T00:24:51.809375Z","shell.execute_reply.started":"2023-02-25T00:24:51.602084Z","shell.execute_reply":"2023-02-25T00:24:51.808395Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# want to train our model in separate iterations without each round influencing the next\ndel ML","metadata":{"execution":{"iopub.status.busy":"2023-02-25T00:24:51.811302Z","iopub.execute_input":"2023-02-25T00:24:51.812125Z","iopub.status.idle":"2023-02-25T00:24:51.817122Z","shell.execute_reply.started":"2023-02-25T00:24:51.812085Z","shell.execute_reply":"2023-02-25T00:24:51.815924Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}