<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://mateuszbuda.com/feed.xml" rel="self" type="application/atom+xml" /><link href="http://mateuszbuda.com/" rel="alternate" type="text/html" /><updated>2026-08-30T20:19:08+00:00</updated><id>http://mateuszbuda.com/feed.xml</id><title type="html">Mateusz Buda</title><subtitle>Machine Learning Engineer and AI Product Developer</subtitle><author><name>Mateusz Buda</name></author><entry><title type="html">Deep learning matches performance of radiologists in diagnosis of thyroid nodules</title><link href="http://mateuszbuda.com/2020/01/06/thyroid.html" rel="alternate" type="text/html" title="Deep learning matches performance of radiologists in diagnosis of thyroid nodules" /><published>2020-01-06T00:00:00+00:00</published><updated>2020-01-06T00:00:00+00:00</updated><id>http://mateuszbuda.com/2020/01/06/thyroid</id><content type="html" xml:base="http://mateuszbuda.com/2020/01/06/thyroid.html"><![CDATA[<h3 id="background">Background</h3>

<p>Thyroid is a gland in the neck consisting of two lobes.
Thyroid nodules are estimated to affect as much as 50% of the population.
Triaging them for biopsy is done based on assessment of ultrasound (US) imaging by radiologists.
However, interpretation of thyroid ultrasound suffers from high inter-reader variability and overdiagnosis.</p>

<p style="text-align: center">
    <img src="/images/thyroid/thyroid-nodule.jpg" alt="Thyroid nodule" width="50%" />
</p>

<h3 id="data">Data</h3>

<p>Our dataset included US images for 1377 thyroid nodules from 1230 patients (Figure 1).
All nodules were assigned ground truth labels (benign or cancer) proven by either biopsy or surgery.
For testing, we selected 99 cases that were additionally annotated by multiple radiologists.
The remaining 1278 cases were used for algorithm development.</p>

<p style="text-align: center">
    <img src="/images/thyroid/thyroid-us-1.png" alt="Thyroid Ultrasound" height="250px" />
    <img src="/images/thyroid/thyroid-us-2.png" alt="Thyroid Ultrasound" height="250px" />
    <br />
    Figure 1: Deidentified ultrasound images of a thyroid nodule.
</p>

<h3 id="deep-learning-algorithm">Deep learning algorithm</h3>

<p>We developed a deep learning algorithm to provide management recommendations for thyroid nodules observed on ultrasound images .
Code repository for methods applied in this project is available at the following link: <a href="https://github.com/mateuszbuda/thyroid-us" target="_blank">github.com/mateuszbuda/thyroid-us</a>.</p>

<p>The main steps of the algorithm are:</p>

<ol>
  <li>Extraction of region of interest (ROI) based on calliper marks using Faster R-CNN network.</li>
  <li>Prediction of malignancy using multi-task CNN.</li>
  <li>Stratification into risk level and biopsy recommendation.</li>
</ol>

<h4 id="roi-extraction">ROI extraction</h4>

<p>Extraction of ROI with a nodule from thyroid US was performed by detection of calliper marks with Faster R-CNN network.
ROI was defined as a rectangle enclosing all detected calipers, as shown in Figure 2.</p>

<p style="text-align: center">
    <img src="/images/thyroid/detection.png" alt="Thyroid ROI" width="50%" />
    <br />
    Figure 2. Thyroid US with detected calliper marks (red boxes) and ROI enclosing them (blue box).
</p>

<h4 id="multi-task-cnn">Multi-task CNN</h4>

<p>For prediction of malignancy, we developed a multi-task CNN (Figure 3).
The main task for the network was to predict malignancy of thyroid nodules based on US images.
Auxiliary tasks, trained jointly with the main task, were prediction of nodule’s visual features that were highly relevant to the malignancy status.
Shared weight were updated based on training signal from all tasks.
As a result, the network was able to extract generalizable features, even when trained on a small dataset.</p>

<p style="text-align: center">
    <img src="/images/thyroid/multitask.png" alt="Multi-task CNN" width="90%" />
    <br />
    Figure 3. Multi-task CNN network for malignancy prediction of thyroid nodules based on US images.
</p>

<h3 id="results">Results</h3>

<p>For the test nodules, the proposed deep learning algorithm achieved AUC of 0.87, which was similar to a committee of three expert radiologists (AUC=0.91).</p>

<p style="text-align: center">
    <img src="/images/thyroid/roc.png" alt="Test ROC" width="67%" />
    <br />
    Figure 4. ROC curves comparing deep learning and radiologists on a test set [1].
</p>

<p>The proposed deep learning algorithm achieved 87% sensitivity and 52% specificity.
Sensitivity and specificity of the deep learning algorithm for thyroid nodule biopsy recommendations was similar to that of expert radiologists.</p>

<h3 id="references">References</h3>

<p>[1] Mateusz Buda, Benjamin Wildman-Tobriner, Jenny K Hoang, David Thayer, Franklin N Tessler, William D Middleton, Maciej A Mazurowski “Management of thyroid nodules seen on US images: deep learning may match performance of radiologists.” Radiology, 2019.</p>

<h3 id="links">Links</h3>

<ul>
  <li>Radiology paper: <a href="https://doi.org/10.1148/radiol.2019181343" target="_blank">https://doi.org/10.1148/radiol.2019181343</a>.</li>
  <li>GitHub repository: <a href="https://github.com/mateuszbuda/thyroid-us" target="_blank">github.com/mateuszbuda/thyroid-us</a>.</li>
  <li>Contributed Talk at the <a href="https://conference2019.mlinpl.org" target="_blank">ML in PL Conference 2019</a>: <a href="https://youtu.be/VMZnv5vWhUM" target="_blank">https://youtu.be/VMZnv5vWhUM</a>.</li>
</ul>

<p style="text-align: center">
    <iframe width="560" height="315" src="https://www.youtube.com/embed/VMZnv5vWhUM" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
</p>]]></content><author><name>Mateusz Buda</name></author><summary type="html"><![CDATA[Interpretation of nodules at thyroid ultrasound is time consuming and suffers from inter-reader variability. In our study, we developed a deep learning algorithm to provide management recommendations for thyroid nodules observed on ultrasound images and compared its performance with radiologists. We showed that the performance of the algorithm was similar to that of consensus of three expert readers.]]></summary></entry><entry><title type="html">Deep radiogenomics - classification of brain tumor to molecular subtypes based on magnetic resonance images</title><link href="http://mateuszbuda.com/2019/09/02/genomic.html" rel="alternate" type="text/html" title="Deep radiogenomics - classification of brain tumor to molecular subtypes based on magnetic resonance images" /><published>2019-09-02T00:00:00+00:00</published><updated>2019-09-02T00:00:00+00:00</updated><id>http://mateuszbuda.com/2019/09/02/genomic</id><content type="html" xml:base="http://mateuszbuda.com/2019/09/02/genomic.html"><![CDATA[<style>
p, li {
	text-align: justify
}
</style>

<p>Radiogenomics is a challenging task of distinguishing molecular subtypes of a lesion based on radiological imaging data.
The genomic type of a tumor is a valuable information and can help in guiding patient’s treatment.</p>

<p>The dataset used for development was obtained from The Cancer Imaging Archive (<a href="https://wiki.cancerimagingarchive.net/display/Public/TCGA-LGG" target="_blank">TCIA</a>) and involved 110 cases of lower-grade glioma patients.
Registers brain MR images with manual FLAIR abnormality segmentation masks are published as a Kaggle Dataset <a href="https://www.kaggle.com/mateuszbuda/lgg-mri-segmentation" target="_blank">lgg-mri-segmentation</a>.</p>

<p style="text-align: center">
	<img src="/images/genomic/TCGA_CS_6666_20011109_15_0_0_0_1.tif" alt="TCGA_CS_6666_20011109_15_0_0_0_1" width="16%" />
	<img src="/images/genomic/TCGA_DU_6401_19831001_22_0_0_0_1.tif" alt="TCGA_DU_6401_19831001_22_0_0_0_1" width="16%" />
	<img src="/images/genomic/TCGA_DU_7299_19910417_27_0_0_0_1.tif" alt="TCGA_DU_7299_19910417_27_0_0_0_1" width="16%" />
	<img src="/images/genomic/TCGA_DU_7306_19930512_27_0_0_0_1.tif" alt="TCGA_DU_7306_19930512_27_0_0_0_1" width="16%" />
	<img src="/images/genomic/TCGA_HT_A61B_19991127_41_0_0_0_1.tif" alt="TCGA_HT_A61B_19991127_41_0_0_0_1" width="16%" />
</p>
<p style="text-align: center">
	<img src="/images/genomic/TCGA_CS_4941_19960909_11_0_0_0_2.tif" alt="TCGA_CS_4941_19960909_11_0_0_0_2" width="16%" />
	<img src="/images/genomic/TCGA_DU_7010_19860307_42_0_0_0_2.tif" alt="TCGA_DU_7010_19860307_42_0_0_0_2" width="16%" />
	<img src="/images/genomic/TCGA_FG_A4MU_20030903_14_0_0_0_2.tif" alt="TCGA_FG_A4MU_20030903_14_0_0_0_2" width="16%" />
	<img src="/images/genomic/TCGA_HT_7686_19950629_15_0_0_0_2.tif" alt="TCGA_HT_7686_19950629_15_0_0_0_2" width="16%" />
	<img src="/images/genomic/TCGA_HT_8106_19970727_20_0_0_0_2.tif" alt="TCGA_HT_8106_19970727_20_0_0_0_2" width="16%" />
</p>
<p style="text-align: center">
	<img src="/images/genomic/TCGA_DU_7018_19911220_22_0_0_0_3.tif" alt="TCGA_DU_7018_19911220_22_0_0_0_3" width="16%" />
	<img src="/images/genomic/TCGA_DU_7294_19890104_27_0_0_0_3.tif" alt="TCGA_DU_7294_19890104_27_0_0_0_3" width="16%" />
	<img src="/images/genomic/TCGA_DU_7302_19911203_20_0_0_0_3.tif" alt="TCGA_DU_7302_19911203_20_0_0_0_3" width="16%" />
	<img src="/images/genomic/TCGA_FG_7637_20000922_30_0_0_0_3.tif" alt="TCGA_FG_7637_20000922_30_0_0_0_3" width="16%" />
	<img src="/images/genomic/TCGA_HT_7616_19940813_22_0_0_0_3.tif" alt="TCGA_HT_7616_19940813_22_0_0_0_3" width="16%" />
</p>

<p>Figure 1. Randomly sampled patches of tumors extracted from FLAIR sequences of brain MRI masked with manual segmentations.
Each row corresponds to a separate genomic subtype cluster.</p>

<p>A method that we applied was transfer learning from a different brain MRI dataset containing scans from cases with tumors of a similar type.
Obtained results show a notable association between imaging and genomic data.
This provides strong evidence for genomic subtypes being exposed in MRI.</p>

<p style="text-align: center">
	<img src="/images/genomic/roc.tiff" alt="ROC" width="67%" />
</p>

<p>Figure 2. Receiver operating characteristic curve for the task of discriminating betwen tumor genomic subtypes of significantly different survivals times.</p>

<p>In Figure 3, we show network attention heatmaps, which indicate parts of the image responsible for prediction. Increased response by the network was for tumor margin regions of high irregularity.</p>

<p style="text-align: center">
	<img src="/images/genomic/heatmaps.tiff" alt="Heatmaps" width="67%" />
</p>

<p>While deep learning cannot yet replace genomic testing, it shows promise in aiding clinical decisions.</p>

<h3 id="links">Links</h3>

<ul>
  <li>Full paper: <a href="https://doi.org/10.1148/ryai.2019180050" target="_blank">Radiology: Artificial Intelligence</a></li>
  <li>Data: <a href="https://www.kaggle.com/mateuszbuda/lgg-mri-segmentation" target="_blank">lgg-mri-segmentation</a></li>
</ul>]]></content><author><name>Mateusz Buda</name></author><summary type="html"><![CDATA[Radiogenomics is a challenging task of distinguishing molecular subtypes of a lesion based on radiological imaging data. A method that we applied was transfer learning from a different brain MRI dataset containing scans from cases with tumors of a similar type. Obtained results show a notable association between imaging and genomic data. This provides strong evidence for genomic subtypes being exposed in MRI.]]></summary></entry><entry><title type="html">Genetic optimization of a risk stratification system for thyroid nodules</title><link href="http://mateuszbuda.com/2019/05/23/aitirads.html" rel="alternate" type="text/html" title="Genetic optimization of a risk stratification system for thyroid nodules" /><published>2019-05-23T00:00:00+00:00</published><updated>2019-05-23T00:00:00+00:00</updated><id>http://mateuszbuda.com/2019/05/23/aitirads</id><content type="html" xml:base="http://mateuszbuda.com/2019/05/23/aitirads.html"><![CDATA[<h3 id="thyroid-nodules">Thyroid nodules</h3>

<p>Thyroid nodules are estimated to affect as much as 50% of the population.
Triaging them for biopsy is done based on assessment of ultrasound imaging by radiologists.
A system that quantifies the features and provides a recommendation decision proposed by the American College of Radiology (ACR) is called Thyroid Imaging Reporting and Data System (TI-RADS) [1].
ACR TI-RADS was extensively tested in multiple studies which showed its superior performance as compared to other similar risk stratification systems.
Still, it was built based on evidence in the literature and expert consensus.
We, in turn, developed an improved version using a data-driven approach based on genetic optimization methods and data for 1425 thyroid nodules.
An interactive website for our system is available at <a href="http://deckard.duhs.duke.edu/~ai-ti-rads/" target="_blank">deckard.duhs.duke.edu/~ai-ti-rads/</a>.</p>

<p style="text-align: center">
    <img src="/images/aitirads/acr-tirads.jpg" alt="ACR TI-RADS" width="98%" />
    <br />
    Figure 1: ACR TI-RADS framework introduced in [1]. (FNA = fine needle aspiration biopsy)
</p>

<h3 id="data">Data</h3>

<p>Our dataset included 1425 thyroid nodules from 1264 patients.
All nodules were assigned ground truth labels (benign or cancer) proven by either biopsy or surgery.
Each nodule was assessed for the five ACR TI-RADS feature categories (shown in Figure 1) by a single radiologist, expert in thyroid imaging.
For testing, we selected 100 cases that were additionally annotated by multiple radiologists.
The remaining 1325 cases were used for algorithm development.</p>

<h3 id="genetic-algorithm">Genetic algorithm</h3>

<p>Code repository for a genetic optimization algorithm applied in this project is available at the following link: <a href="https://github.com/mateuszbuda/AI-TI-RADS" target="_blank">github.com/mateuszbuda/AI-TI-RADS</a>.
It was implemented using Python package <a href="https://deap.readthedocs.io/en/master/">DEAP</a> for distributed evolutionary algorithms.
The main steps of the algorithm are:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1. initialize population with 100 individuals
2. for 50 generations:
    a. select individuals to create offspring population
    b. crossover randomly selected offspring individuals
    c. mutate randomly selected offspring individuals
3. return individual with the best loss function
</code></pre></div></div>

<p>An individual was represented with a vector of 19 integer variables with values in a range from 0 to 3, each corresponding to one feature in ACR TI-RADS.
Points for two features (anechoic echogenicity and extra-thyroidal extensions margin) were adapted from ACR TI-RADS since we did not have any case with these features in our dataset.
Two other features (cystic and spongiform composition) were excluded since in ACR TI-RADS these nodules receive 0 points in total without adding further points for other categories.</p>

<p>In the <strong>initial</strong> population, all individuals were representing the assignment of points as in ACR TI-RADS.</p>

<p>For <strong>selection</strong> (step 2a) we used a tournament approach of size 4.
Among 4 randomly drawn individuals, we selected one with the best fitness function.
This procedure was repeated 100 times in each generation.</p>

<p>The <strong>crossover</strong> (step 2b) was an exchange of the values between two randomly selected variables. The probability of an individual being subject to crossover with another individual was set to 50%.</p>

<p>The <strong>mutation</strong> (step 2c) assigned a new random value to a variable. The probability of mutation was set to 20% for an individual and 5% for a variable.</p>

<p>Finally, the optimized loss function used for evaluation of individuals was area under the ROC curve (AUC).
The progress of evolution is shown in Figure 2.</p>

<p style="text-align: center">
    <img src="/images/aitirads/loss.png" alt="AUC loss" width="72%" />
    <br />
    Figure 2: Mean and standard deviation for AUC of a population across evolution.
</p>

<h3 id="results">Results</h3>

<p>The optimization resulted in AI TI-RADS with new point assignments for the features as shown in Figure 3. Interactive calculator for AI TI-RADS is available online: <a href="http://deckard.duhs.duke.edu/~ai-ti-rads/" target="_blank">deckard.duhs.duke.edu/~ai-ti-rads/</a>.</p>

<p style="text-align: center">
    <img src="/images/aitirads/ai-tirads.png" alt="AI TI-RADS" width="98%" />
    <br />
    Figure 3: AI TI-RADS diagram from the Radiology article [2]. (FNA = fine needle aspiration biopsy)
</p>

<p>On the training set, the AUC for ACR TI-RADS (used for initialization) was 0.79, whereas for AI TI-RADS it was 0.82.</p>

<p>The 100 test cases were assessed for the five ACR TI-RADS feature categories by (1) eight radiologists who interpreted thyroid ultrasound in clinical practice and (2) three ACR TI-RADS committee members whose interpretations were combined into expert consensus using majority vote.
Based on these interpretations, we compared sensitivity and specificity for biopsy recommendation of ACR TI-RADS and AI TI-RADS on a boxplot shown in Figure 4.</p>

<p style="text-align: center">
    <img src="/images/aitirads/boxplot.png" alt="AI TI-RADS" width="64%" style="margin-bottom: 0.5em" />
    <br />
    Figure 4: Comparison between ACR TI-RADS and AI TI-RADS in terms of sensitivity and specificity for biopsy recommendation on the 100 test cases. Boxes represent a set of eight radiologists and blue squares represent an expert consensus.
</p>

<p>AI TI-RADS resulted in improved specificity for expert consensus from 50.6% to 54.1% (p=0.096) as well as for mean specificity of the eight radiologists from 47.7% to 55.3% (p&lt;0.001).
In terms of sensitivity, for expert consensus, it was the same for both TI-RADS (86.7%), whereas mean sensitivity of the eight radiologists slightly improved from 81.7% to 82.5% (p&gt;0.5).</p>

<h3 id="references">References</h3>

<p>[1] Tessler FN, Middleton WD, Grant EG, Hoang JK, Berland LL, Teefey SA, et al. “ACR Thyroid Imaging, Reporting and Data System (TI-RADS): White Paper of the ACR TI-RADS Committee.” Journal of the American College of Radiology, 2017.</p>

<p>[2] Wildman-Tobriner B, Buda M, Hoang JK, Middleton WD, Thayer D, Short RG, Tessler FN, Mazurowski MA “Using Artificial Intelligence to Revise ACR TI-RADS Risk Stratification of Thyroid Nodules: Diagnostic Accuracy and Utility.” Radiology, 2019.</p>

<h3 id="links">Links</h3>

<ul>
  <li>AI TI-RADS Radiology paper: <a href="https://doi.org/10.1148/radiol.2019182128" target="_blank">doi.org/10.1148/radiol.2019182128</a>.</li>
  <li>AI TI-RADS Calculator: <a href="http://deckard.duhs.duke.edu/~ai-ti-rads/" target="_blank">deckard.duhs.duke.edu/~ai-ti-rads/</a>.</li>
  <li>AI TI-RADS GitHub repository: <a href="https://github.com/mateuszbuda/AI-TI-RADS" target="_blank">github.com/mateuszbuda/AI-TI-RADS</a>.</li>
  <li>Python DEAP package: <a href="https://deap.readthedocs.io/en/master/">deap.readthedocs.io</a>.</li>
</ul>]]></content><author><name>Mateusz Buda</name></author><summary type="html"><![CDATA[Thyroid nodules are estimated to affect as much as 50% of the population. Triaging them for biopsy is done based on assessment of ultrasound imaging by radiologists. A system that quantifies ultrasound imaging features proposed by the American College of Radiology (ACR) is called Thyroid Imaging Reporting and Data System (TI-RADS). Using a genetic optimization algorithm, we developed data-driven Artificial Intelligence (AI) TI-RADS which offers significant improvement in specificity while maintaining high sensitivity for biopsy recommendation.]]></summary></entry><entry><title type="html">Python toolset for statistical comparison of machine learning models and human readers</title><link href="http://mateuszbuda.com/2019/04/30/stat.html" rel="alternate" type="text/html" title="Python toolset for statistical comparison of machine learning models and human readers" /><published>2019-04-30T00:00:00+00:00</published><updated>2019-04-30T00:00:00+00:00</updated><id>http://mateuszbuda.com/2019/04/30/stat</id><content type="html" xml:base="http://mateuszbuda.com/2019/04/30/stat.html"><![CDATA[<style>
li {
	text-align: justify
}
</style>

<h3 id="introduction">Introduction</h3>

<p>The most common statistical methods for comparing machine learning models and human readers are <a href="https://en.wikipedia.org/wiki/P-value" target="_blank">p-value</a> and <a href="https://en.wikipedia.org/wiki/Confidence_interval" target="_blank">confidence interval</a>.
Although receiving some criticism recently, p-value and confidence interval give more insight into results than a raw performance measure, if interpreted correctly, and are required by many journals.</p>

<p>This post shows an example python code utilizing <a href="https://en.wikipedia.org/wiki/Bootstrapping" target="_blank">bootstrapping</a> for computing confidence intervals and p-values comparing machine learning models and human readers.</p>

<p>I will not discuss what p-value does or does not mean, what is the right threshold for statistical significance, or how to properly interpret it.
Here are some resources that dive deeper into this topic:</p>
<ul>
  <li>Wasserstein, R.L. and Lazar, N.A., 2016. <a href="http://dx.doi.org/10.1080/00031305.2016.1154108" target="_blank">The ASA’s statement on p-values: context, process, and purpose.</a> The American Statistician, 70(2), pp.129-133.</li>
  <li>Baker, M., 2016. <a href="http://dx.doi.org/10.1038/nature.2016.19503" target="_blank">Statisticians issue warning over misuse of p-values.</a> Nature News, 531(7593), p.151.</li>
  <li>Altman, N. and Krzywinski, M., 2016. <a href="https://doi.org/10.1038/nmeth.4120" target="_blank">Points of significance: p-values and the search for significance.</a></li>
  <li>Benjamin, D.J., Berger, J.O., Johannesson, M., Nosek, B.A., Wagenmakers, E.J., Berk, R., Bollen, K.A., Brembs, B., Brown, L., Camerer, C. and Cesarini, D., 2018. <a href="https://doi.org/10.1038/s41562-017-0189-z" target="_blank">Redefine statistical significance.</a> Nature Human Behaviour, 2(1), p.6.</li>
  <li>McShane, B.B., Gal, D., Gelman, A., Robert, C. and Tackett, J.L., 2019. <a href="https://doi.org/10.1080/00031305.2018.1527253" target="_blank">Abandon statistical significance.</a> The American Statistician, 73(sup1), pp.235-245.</li>
</ul>

<h3 id="simple-statistical-toolset-for-machine-learning">Simple statistical toolset for machine learning</h3>

<p>I published a GitHub repository <a href="https://github.com/mateuszbuda/ml-stat-util" target="_blank">ml-stat-util</a> containing a set of simple functions written in Python for computing p-values and confidence intervals using bootstrapping.
I will show how to use it in different common use cases.</p>

<p>A jupyter notebook with all use cases described below is available on <a href="https://github.com/mateuszbuda/ml-stat-util/examples.ipynb" target="_blank">GitHub</a>.</p>

<h3 id="use-case-1">Use case #1</h3>

<p>Compute AUC with 95% confidence interval for a single model.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.metrics</span> <span class="kn">import</span> <span class="n">roc_auc_score</span>
<span class="kn">import</span> <span class="nn">stat_util</span>

<span class="n">score</span><span class="p">,</span> <span class="n">ci_lower</span><span class="p">,</span> <span class="n">ci_upper</span><span class="p">,</span> <span class="n">scores</span> <span class="o">=</span> <span class="n">stat_util</span><span class="p">.</span><span class="n">score_ci</span><span class="p">(</span>
    <span class="n">y_true</span><span class="p">,</span> <span class="n">y_pred</span><span class="p">,</span> <span class="n">score_fun</span><span class="o">=</span><span class="n">roc_auc_score</span>
<span class="p">)</span>
</code></pre></div></div>

<p>To get an idea of what happened, we can plot a histogram of bootstrapped scores.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>

<span class="n">bins</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">hist</span><span class="p">(</span><span class="n">scores</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">([</span><span class="n">score</span><span class="p">,</span> <span class="n">score</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">bins</span><span class="p">[</span><span class="mi">0</span><span class="p">])],</span> <span class="n">color</span><span class="o">=</span><span class="s">"tomato"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">([</span><span class="n">ci_lower</span><span class="p">,</span> <span class="n">ci_lower</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">bins</span><span class="p">[</span><span class="mi">0</span><span class="p">])],</span> <span class="n">color</span><span class="o">=</span><span class="s">"lime"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">([</span><span class="n">ci_upper</span><span class="p">,</span> <span class="n">ci_upper</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">bins</span><span class="p">[</span><span class="mi">0</span><span class="p">])],</span> <span class="n">color</span><span class="o">=</span><span class="s">"lime"</span><span class="p">)</span>
</code></pre></div></div>

<p style="text-align: center">
    <img src="/images/stat/example1.png" alt="Histogram CI" style="max-height: 250px; width: auto;" />
</p>

<h3 id="use-case-2">Use case #2</h3>

<p>Compare two models by computing p-value for a difference in their performance measured with AUC.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.metrics</span> <span class="kn">import</span> <span class="n">roc_auc_score</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="nn">stat_util</span>

<span class="n">p</span><span class="p">,</span> <span class="n">z</span> <span class="o">=</span> <span class="n">stat_util</span><span class="p">.</span><span class="n">pvalue</span><span class="p">(</span><span class="n">y_true</span><span class="p">,</span> <span class="n">y_pred1</span><span class="p">,</span> <span class="n">y_pred2</span><span class="p">,</span> <span class="n">score_fun</span><span class="o">=</span><span class="n">roc_auc_score</span><span class="p">)</span>
<span class="n">bins</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">hist</span><span class="p">(</span><span class="n">z</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">bins</span><span class="p">[</span><span class="mi">0</span><span class="p">])],</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">)</span>
</code></pre></div></div>

<p style="text-align: center">
    <img src="/images/stat/example2.png" alt="Histogram p-value" style="max-height: 250px; width: auto;" />
</p>

<h3 id="use-case-3">Use case #3</h3>

<p>Compute mean AUC with 95% confidence interval for a set of readers/models.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">from</span> <span class="nn">sklearn.metrics</span> <span class="kn">import</span> <span class="n">roc_auc_score</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="nn">stat_util</span>

<span class="n">mean_score</span><span class="p">,</span> <span class="n">ci_lower</span><span class="p">,</span> <span class="n">ci_upper</span><span class="p">,</span> <span class="n">scores</span> <span class="o">=</span> <span class="n">stat_util</span><span class="p">.</span><span class="n">score_stat_ci</span><span class="p">(</span>
    <span class="n">y_true</span><span class="p">,</span> <span class="n">y_pred_readers</span><span class="p">,</span> <span class="n">score_fun</span><span class="o">=</span><span class="n">roc_auc_score</span><span class="p">,</span> <span class="n">stat_fun</span><span class="o">=</span><span class="n">np</span><span class="p">.</span><span class="n">mean</span>
<span class="p">)</span>
<span class="n">bins</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">hist</span><span class="p">(</span><span class="n">scores</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">([</span><span class="n">mean_score</span><span class="p">,</span> <span class="n">mean_score</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">bins</span><span class="p">[</span><span class="mi">0</span><span class="p">])],</span> <span class="n">color</span><span class="o">=</span><span class="s">"tomato"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">([</span><span class="n">ci_lower</span><span class="p">,</span> <span class="n">ci_lower</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">bins</span><span class="p">[</span><span class="mi">0</span><span class="p">])],</span> <span class="n">color</span><span class="o">=</span><span class="s">"lime"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">([</span><span class="n">ci_upper</span><span class="p">,</span> <span class="n">ci_upper</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">bins</span><span class="p">[</span><span class="mi">0</span><span class="p">])],</span> <span class="n">color</span><span class="o">=</span><span class="s">"lime"</span><span class="p">)</span>
</code></pre></div></div>

<p style="text-align: center">
    <img src="/images/stat/example3.png" alt="Histogram CI mean" style="max-height: 250px; width: auto;" />
</p>

<h3 id="use-case-4">Use case #4</h3>

<p>Compare a single model to a set of readers by computing p-value for a difference in their performance measured with AUC.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">from</span> <span class="nn">sklearn.metrics</span> <span class="kn">import</span> <span class="n">roc_auc_score</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="nn">stat_util</span>

<span class="n">p</span><span class="p">,</span> <span class="n">z</span> <span class="o">=</span> <span class="n">stat_util</span><span class="p">.</span><span class="n">pvalue_stat</span><span class="p">(</span>
    <span class="n">y_true</span><span class="p">,</span> <span class="n">y_pred</span><span class="p">,</span> <span class="n">y_pred_readers</span><span class="p">,</span> <span class="n">score_fun</span><span class="o">=</span><span class="n">roc_auc_score</span><span class="p">,</span> <span class="n">stat_fun</span><span class="o">=</span><span class="n">np</span><span class="p">.</span><span class="n">mean</span>
<span class="p">)</span>
<span class="n">bins</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">hist</span><span class="p">(</span><span class="n">z</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">bins</span><span class="p">[</span><span class="mi">0</span><span class="p">])],</span> <span class="n">color</span><span class="o">=</span><span class="s">"black"</span><span class="p">)</span>
</code></pre></div></div>

<p style="text-align: center">
    <img src="/images/stat/example4.png" alt="Histogram p-value" style="max-height: 250px; width: auto;" />
</p>

<h3 id="links">Links</h3>

<ul>
  <li>Code: <a href="https://gist.github.com/mateuszbuda/ml-stat-util" target="_blank">mateuszbuda/ml-stat-util</a></li>
  <li>Notebook: <a href="https://github.com/mateuszbuda/ml-stat-util/examples.ipynb" target="_blank">mateuszbuda/ml-stat-util/examples.ipynb</a></li>
</ul>]]></content><author><name>Mateusz Buda</name></author><summary type="html"><![CDATA[The most common statistical methods for comparing machine learning models and human readers are p-value and confidence interval. Although receiving some criticism recently, p-value and confidence interval give more insight into results than a raw performance measure, if interpreted correctly, and are required by many journals. Bootstrapping is a nonparametric method to compute them. This post shows an example python code utilizing bootstrapping for computing confidence intervals and p-values comparing machine learning models and human readers.]]></summary></entry><entry><title type="html">Uploading manuscript from Overleaf (ShareLaTeX) to arXiv</title><link href="http://mateuszbuda.com/2018/10/20/arxiv.html" rel="alternate" type="text/html" title="Uploading manuscript from Overleaf (ShareLaTeX) to arXiv" /><published>2018-10-20T00:00:00+00:00</published><updated>2018-10-20T00:00:00+00:00</updated><id>http://mateuszbuda.com/2018/10/20/arxiv</id><content type="html" xml:base="http://mateuszbuda.com/2018/10/20/arxiv.html"><![CDATA[<style>
li {
    text-align: justify
}
</style>

<p><i>Updated on Nov 13, 2020</i></p>

<p><a href="https://www.overleaf.com" target="_blank">Overleaf</a> (previously ShareLaTeX) is a convenient tool to collaboratively write papers in LaTeX.
Once we have the content of a manuscript ready, it’s time for submission.
Here is a step by step guide to preparing a single zip file for uploading on <a href="https://arxiv.org" target="_blank">arXiv</a>.</p>

<h4 id="assumptions">Assumptions:</h4>

<ol>
  <li>The main file is named <code class="language-plaintext highlighter-rouge">ms.tex</code>.</li>
  <li>Used packages:
    <ul>
      <li>graphicx</li>
      <li>hyperref</li>
      <li>natbib</li>
      <li>subfiles</li>
    </ul>
  </li>
  <li>My setup on Overleaf (ShareLaTeX):
    <ul>
      <li>Main document class: <code class="language-plaintext highlighter-rouge">\documentclass[11pt]{article}</code></li>
      <li>Bibliography style: <code class="language-plaintext highlighter-rouge">\bibliographystyle{unsrtnat}</code></li>
      <li>Path to graphics: <code class="language-plaintext highlighter-rouge">\graphicspath{ {images/} }</code></li>
      <li>References from <code class="language-plaintext highlighter-rouge">references.bib</code> file added using natbib: <code class="language-plaintext highlighter-rouge">\bibliography{references}</code></li>
      <li>The first line of each subfile is: <code class="language-plaintext highlighter-rouge">\documentclass[ms.tex]{subfiles}</code></li>
    </ul>

    <div class="language-LaTeX highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">\documentclass</span><span class="na">[ms.tex]</span><span class="p">{</span>subfiles<span class="p">}</span>
    
 <span class="nt">\begin{document}</span>
 ...
 <span class="nt">\end{document}</span>
</code></pre></div>    </div>
  </li>
</ol>

<h4 id="steps">Steps:</h4>

<ol>
  <li>Download source files and unzip them.
    <ul>
      <li>Menu</li>
      <li>Download Source</li>
    </ul>
  </li>
  <li>Download the bbl file and rename it to <code class="language-plaintext highlighter-rouge">ms.bbl</code>:
    <ul>
      <li>Logs and output files</li>
      <li>Other logs &amp; files</li>
      <li>bbl file</li>
    </ul>

    <p style="text-align: center">
 <img src="/images/arxiv/bbl1.png" alt="Logs and output files" style="max-height: 400px; width: auto; border-width: 1px; border-style: solid;" />
 </p>
    <p style="text-align: center">
 <img src="/images/arxiv/bbl2.png" alt="bbl file" style="max-height: 400px; width: auto; border-width: 1px; border-style: solid;" />
 </p>
  </li>
  <li>
    <p>In the main file (<code class="language-plaintext highlighter-rouge">ms.tex</code>), below the documentclass declaration line add <code class="language-plaintext highlighter-rouge">\pdfoutput=1</code>.</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> \documentclass[11pt]{article}
 \pdfoutput=1
 ...
</code></pre></div>    </div>
  </li>
  <li>Remove <code class="language-plaintext highlighter-rouge">\documentclass[ms.tex]{subfiles}</code> statement in all subfiles.</li>
  <li>Compress (zip) all files, but not their parent folder, and upload the zip to arXiv.</li>
</ol>

<p>Note: It’s possible that this guide does not handle some (edge) cases.</p>]]></content><author><name>Mateusz Buda</name></author><summary type="html"><![CDATA[How to correctly prepare files for upload. A set of steps and a checklist for successful submission to arXiv of a manuscript written in Overleaf (ShareLaTeX).]]></summary></entry><entry><title type="html">Thresholding method for imbalanced classification</title><link href="http://mateuszbuda.com/2018/09/15/thresholding.html" rel="alternate" type="text/html" title="Thresholding method for imbalanced classification" /><published>2018-09-15T00:00:00+00:00</published><updated>2018-09-15T00:00:00+00:00</updated><id>http://mateuszbuda.com/2018/09/15/thresholding</id><content type="html" xml:base="http://mateuszbuda.com/2018/09/15/thresholding.html"><![CDATA[<style>
li {
	text-align: justify
}
</style>

<h3 id="introduction">Introduction</h3>

<p>Thresholding is a simple method that can improve the accuracy of a classifier in the case when it was trained on an imbalanced dataset.
It relies on <a href="https://en.wikipedia.org/wiki/Bayes%27_theorem" target="_blank">Bayes’ Theorem</a> and the fact that neural networks estimate posterior distribution <a href="http://cognet.mit.edu/journal/10.1162/neco.1991.3.4.461" target="_blank">(Richard &amp; Lippmann, 1991)</a>.
In practice, it means that given a datapoint $x$, the output for a neuron representing class $i$ corresponds to</p>

\[y_i(x) = p(i|x) = \frac{p(i) \cdot p(x|i)}{p(x)}\]

<p>where $p(i)$ is a prior probability for class $i$.</p>

<p>In a standard case, equal priors are assumed for all classes.
However, it is not always the case.
E.g. in medical datasets some diseases are known to have a prevalence of less than 1%.</p>

<p>A class prior can be estimated based on the number of examples in a training set unless we have a good reason to think that our training set is not reflective of the true class distribution. Otherwise, for class $i$ we have:</p>

\[p(i) = \frac{|i|}{\sum_{k}{|k|}}\]

<p>where $|i|$ denotes the number of unique examples in class $i$.</p>

<p>Finally, the adjusted network output for class $i$ can be obtained by dividing the original output by the corresponding prior.</p>

<h3 id="simple-example">Simple example</h3>

<p>Let us assume that we have already trained a classifier on a training set with the number of examples per class as following:</p>

\[[100, 400, 500]\]

<p>Then, we tested our model on a test case $x$ and it returned the vector of class probabilities:</p>

\[y = [0.2, 0.2, 0.6]\]

<p>In this case, the predicted class would be:</p>

\[argmax(y) = 2\]

<p>Now, to apply thresholding method, we have to compute the vector of priors. In this case, it will be:</p>

\[p = [100/1000, 400/1000, 500/1000] = [0.1, 0.4, 0.5]\]

<p>And adjusted predictions are obtained by dividing original predictions element-wise by the vector of priors:</p>

\[y' = y \oslash p = [\frac{0.2}{0.1}, \frac{0.2}{0.4}, \frac{0.6}{0.5}] = [2.0, 0.5, 1.2]\]

<p>The predicted class has now changed to:</p>

\[argmax(y') = 0\]

<h3 id="python-implementation">Python implementation</h3>

<p>For impatient readers, the full notebook is available as a <a href="https://gist.github.com/mateuszbuda/cb122143afcc574b3cee636e1cc58150" target="_blank">GitHub gist</a>.</p>

<p>First, let us build a simple dataset based on two Gaussian distributions.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># 20 positive and 180 negative training examples
</span><span class="n">X1_train</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">normal</span><span class="p">((</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span> <span class="mf">1.0</span><span class="p">,</span> <span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<span class="n">X0_train</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">normal</span><span class="p">((</span><span class="o">-</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span> <span class="mf">1.0</span><span class="p">,</span> <span class="p">(</span><span class="mi">180</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>

<span class="n">X_train</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">vstack</span><span class="p">((</span><span class="n">X0_train</span><span class="p">,</span> <span class="n">X1_train</span><span class="p">))</span>
<span class="n">y_train</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="mi">180</span> <span class="o">*</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mi">20</span> <span class="o">*</span> <span class="p">[</span><span class="mi">1</span><span class="p">])</span>

<span class="n">X1_test</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">normal</span><span class="p">((</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span> <span class="mf">1.0</span><span class="p">,</span> <span class="p">(</span><span class="mi">500</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<span class="n">X0_test</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">normal</span><span class="p">((</span><span class="o">-</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span> <span class="mf">1.0</span><span class="p">,</span> <span class="p">(</span><span class="mi">500</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>

<span class="n">X_test</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">vstack</span><span class="p">((</span><span class="n">X0_test</span><span class="p">,</span> <span class="n">X1_test</span><span class="p">))</span>
<span class="n">y_test</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="mi">500</span> <span class="o">*</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mi">500</span> <span class="o">*</span> <span class="p">[</span><span class="mi">1</span><span class="p">])</span>
</code></pre></div></div>

<p>The training set looks like this:</p>

<p style="text-align: center">
	<img src="/images/thresholding/trainset.png" alt="Training set" style="max-height: 250px; width: auto;" />
</p>

<p>We will use it to train a simple neural network with 2 hidden units:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">nn</span> <span class="o">=</span> <span class="n">MLPClassifier</span><span class="p">(</span><span class="n">solver</span><span class="o">=</span><span class="s">'lbfgs'</span><span class="p">,</span> <span class="n">hidden_layer_sizes</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'logistic'</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span>
<span class="n">nn</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span> <span class="n">y_train</span><span class="p">)</span>
</code></pre></div></div>

<p>The decision boundary looks like reasonably discriminating positive (blue) and negative (red) examples:</p>

<p style="text-align: center">
	<img src="/images/thresholding/decision.png" alt="Decision boundary" style="max-height: 250px; width: auto;" />
</p>

<p>The accuracy evaluated on the test set is:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">"Accuracy = {}%"</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="mi">100</span> <span class="o">*</span> <span class="n">nn</span><span class="p">.</span><span class="n">score</span><span class="p">(</span><span class="n">X_test</span><span class="p">,</span> <span class="n">y_test</span><span class="p">))</span>
</code></pre></div></div>

<p>Accuracy = 75.1%</p>

<p>We will attempt to improve it using thresholding method. To do that, we need to implement functions to estimate class priors and generate adjusted predictions.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">priors</span><span class="p">(</span><span class="n">y</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">np</span><span class="p">.</span><span class="n">unique</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">return_counts</span><span class="o">=</span><span class="bp">True</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span> <span class="o">/</span> <span class="nb">float</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">y</span><span class="p">))</span>
</code></pre></div></div>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">predict_thresholded</span><span class="p">(</span><span class="n">nn</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">p</span><span class="p">):</span>
    <span class="n">y_pred</span> <span class="o">=</span> <span class="n">nn</span><span class="p">.</span><span class="n">predict_proba</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
    <span class="n">y_pred_th</span> <span class="o">=</span> <span class="n">y_pred</span> <span class="o">/</span> <span class="n">p</span>
    <span class="k">return</span> <span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">y_pred_th</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
</code></pre></div></div>

<p>Now, we can use them and evaluate the performance again:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">p</span> <span class="o">=</span> <span class="n">priors</span><span class="p">(</span><span class="n">y_train</span><span class="p">)</span>
<span class="n">y_pred_test</span> <span class="o">=</span> <span class="n">predict_thresholded</span><span class="p">(</span><span class="n">nn</span><span class="p">,</span> <span class="n">X_test</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>
<span class="s">"Accuracy = {}%"</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="mi">100</span> <span class="o">*</span> <span class="n">accuracy_score</span><span class="p">(</span><span class="n">y_test</span><span class="p">,</span> <span class="n">y_pred_test</span><span class="p">))</span>
</code></pre></div></div>

<p>Accuracy = 84.2%</p>

<p>We were able to improve the accuracy by over 9%.
However, the thresholding method only scales the outputs by multiplying them by a constant number.
It must be noted that the discriminative power of a classifier (e.g. as measured using ROC) does not change in this case.</p>

<h3 id="links">Links</h3>

<ul>
  <li>Code: <a href="https://gist.github.com/mateuszbuda/cb122143afcc574b3cee636e1cc58150" target="_blank">GitHub gist</a></li>
  <li>Class imbalance: <a href="https://arxiv.org/abs/1710.05381" target="_blank">arXiv:1710.05381</a></li>
  <li>Extended report: <a href="http://www.diva-portal.org/smash/get/diva2:1165840/FULLTEXT01.pdf" target="_blank">diva2:1165840</a></li>
</ul>]]></content><author><name>Mateusz Buda</name></author><summary type="html"><![CDATA[Class imbalance refers to unequal number of training examples between classes in a training set. Neural networks are known to estimate Bayesian posterior distribution. The number of training examples for a class can be used to approximate its prior probability. Therefore, model output can be adjusted to reflect uneven class priors and improve the accuracy of a classifier. This post provides a simple example together with a Python implementation of the thresholding method.]]></summary></entry><entry><title type="html">Colaboratory - deep learning on a GPU for free</title><link href="http://mateuszbuda.com/2018/03/06/colab.html" rel="alternate" type="text/html" title="Colaboratory - deep learning on a GPU for free" /><published>2018-03-06T00:00:00+00:00</published><updated>2018-03-06T00:00:00+00:00</updated><id>http://mateuszbuda.com/2018/03/06/colab</id><content type="html" xml:base="http://mateuszbuda.com/2018/03/06/colab.html"><![CDATA[<h3 id="introduction">Introduction</h3>

<p>Colaboratory is a tool from Google that lets you run a Python Notebook in the cloud with GPU support.
There are some limitations on available memory and time constraints for running a continuous session yet it should be enough to train a decent scale machine learning models.
Here is an overview of the setup process together with a sample notebook that shows how to use Colaboratory to start with deep learning on Labeled Faces in the Wild dataset using Keras.</p>

<p style="text-align: center">
    <img src="/images/colab/need_a_gpu.jpg" alt="We're gonna need a GPU" width="66%" />
</p>

<h3 id="set-up">Set-up</h3>

<p>The first prerequisite is that you have a Google account and a browser other than Internet Explorer.
You probably do, so open your <a href="http://drive.google.com/">Google Drive</a>.
Here, we need to connect the Colaboratory app as shown below.</p>

<p style="text-align: center">
    <img src="/images/colab/new_connect.png" alt="New-Connect" width="66%" />
</p>

<p>Then, search for the phrase <code class="language-plaintext highlighter-rouge">colaboratory</code> and connect it with your account.</p>

<p style="text-align: center">
    <img src="/images/colab/connect.png" alt="Connect" width="80%" />
</p>
<p style="text-align: center">
    <img src="/images/colab/ok.png" alt="OK" width="60%" />
</p>

<p>At this point, you should be able to create new Colaboratory Notebook.</p>

<p style="text-align: center">
    <img src="/images/colab/new.png" alt="OK" width="66%" />
</p>

<p>To enable GPU support, you need to edit Notebook Settings.</p>

<p style="text-align: center">
    <img src="/images/colab/settings.png" alt="Settings" width="60%" />
</p>

<p>Choose the <code class="language-plaintext highlighter-rouge">GPU</code> option from the Hardware accelerator dropdown list and save the setting.</p>

<p style="text-align: center">
    <img src="/images/colab/gpu.png" alt="GPU" width="66%" />
</p>

<p>Now, you are ready to do some deep learning.</p>

<h3 id="deep-learning-starter-notebook">Deep learning starter notebook</h3>

<p>You can start by following a deep learning starter notebook that can be accessed here: <a href="https://drive.google.com/file/d/1xSIiv8iQDEsdSgjuLE6vOhxFpG-xQC0Q/view?usp=sharing">DeepLearningStarter.ipynb</a>.
It assumes some basic Python programming skills.
This notebook is a step by step guide to solve an image classification task.
It uses the <a href="http://vis-www.cs.umass.edu/lfw/">Labeled Faces in the Wild</a>, “database of face photographs designed for studying the problem of unconstrained face recognition”.
It contains images of famous people, e.g. Bill Clinton:</p>

<p style="text-align: center">
    <img src="/images/colab/clinton.png" alt="Bill Clinton" width="40%" />
</p>

<p>The model employed in this task is an all convolutional neural network implemented in <a href="https://keras.io">Keras</a>.
You should be able to achieve results similar (or even better, after tuning some training hyper-parameters) to the ones shown below.</p>

<p style="text-align: center">
    <img src="/images/colab/results.png" alt="Results" width="96%" />
</p>]]></content><author><name>Mateusz Buda</name></author><summary type="html"><![CDATA[Colaboratory is a tool from Google that lets you run a Python Notebook in the cloud with GPU support. There are some limitations on available memory and time constraints for running a continuous session yet it should be enough to train a decent scale machine learning models. Here is an overview of the setup process together with a sample notebook that shows how to use Colaboratory to start with deep learning on Labeled Faces in the Wild dataset using Keras.]]></summary></entry><entry><title type="html">An overview of deep learning methods in radiology</title><link href="http://mateuszbuda.com/2018/02/17/methods.html" rel="alternate" type="text/html" title="An overview of deep learning methods in radiology" /><published>2018-02-17T00:00:00+00:00</published><updated>2018-02-17T00:00:00+00:00</updated><id>http://mateuszbuda.com/2018/02/17/methods</id><content type="html" xml:base="http://mateuszbuda.com/2018/02/17/methods.html"><![CDATA[<p>The most straightforward way of training a convolutional neural network (CNN) is to start with a random set of weights and train it using available data specific to the problem being solved (training from scratch).
However, given the large number of parameters (weights) in a network, often above 10 million, and a limited amount of training data, a network may overfit to the available data, resulting in poor performance on test data.
Two training methods have been developed to address this issue: transfer learning [1] and off-the-shelf features (a.k.a. deep features) [2].
A diagram comparing training from scratch with transfer learning and off-the-shelf deep features is shown in Figure 1.</p>

<p style="text-align: center">
	<img src="/images/methods/methods.png" alt="Methods" width="92%" />
</p>
<p>Figure 1. An overview of deep learning methods. Comparison between training from scratch, transfer learning and deep features approaches.</p>

<p>In the transfer learning, the network is first trained using a different dataset, e.g. ImageNet.
Then, the network is “fine-tuned” through additional training with data specific to the problem to be addressed.
The idea behind this approach is that solving different visual tasks shares a certain level of processing such as recognition of edges or simple shapes.
Another way to address the issue of limited training data is the deep features approach which uses convolutional neural networks which have been trained on a different dataset to extract features from the images.
This is done by extracting activations of layers prior to the network’s final layer.
Those layers typically have hundreds or thousands of outputs.
Then, these outputs are used as inputs to “traditional” classifiers such as linear discriminant analysis, support vector machines, decision trees, etc.
This is similar to transfer learning (and is sometimes considered a part of transfer learning) with the difference being that the last layers of a CNN are replaced by a traditional classifier and other layers are not additionally trained.</p>

<h3 id="links">Links</h3>

<ul>
  <li>Journal paper: <a href="https://onlinelibrary.wiley.com/doi/full/10.1002/jmri.26534">Journal of Magnetic Resonance Imaging</a><br /></li>
  <li>arXiv paper: <a href="https://arxiv.org/abs/1802.08717">arXiv:1802.08717</a><br /></li>
</ul>

<h3 id="references">References</h3>

<p>[1] Jason Yosinski, Jeff Clune, Yoshua Bengio, and Hod Lipson. How transferable are features in deep neural networks? In <i>Advances in neural information processing systems</i>, pages 3320-3328, 2014.</p>

<p>[2] Ali Sharif Razavian, Hossein Azizpour, Josephine Sullivan, and Stefan Carlsson. CNN features off-the-shelf: an astounding baseline for recognition. In <i>Proceedings of the IEEE conference on computer vision and pattern recognition workshops</i>, pages 806–813, 2014.</p>]]></content><author><name>Mateusz Buda</name></author><summary type="html"><![CDATA[The most straightforward way of training a convolutional neural network (CNN) is to start with a random set of weights and train it using available data specific to the problem being solved (training from scratch). However, given the large number of parameters (weights) in a network, often above 10 million, and a limited amount of training data, a network may overfit to the available data, resulting in poor performance on test data. Two training methods have been developed to address this issue: transfer learning and off-the-shelf features (a.k.a. deep features).]]></summary></entry><entry><title type="html">A peer review template</title><link href="http://mateuszbuda.com/2018/01/29/review.html" rel="alternate" type="text/html" title="A peer review template" /><published>2018-01-29T00:00:00+00:00</published><updated>2018-01-29T00:00:00+00:00</updated><id>http://mateuszbuda.com/2018/01/29/review</id><content type="html" xml:base="http://mateuszbuda.com/2018/01/29/review.html"><![CDATA[<style>
li {
	text-align: justify
}
</style>

<p>It is not often taught at universities, even on graduate-level programs, how to write a peer review.
I googled around and based on different sources (links provided below) I collected a set of questions to fill each paragraph of a review.</p>

<p>Before writing a review, here is a guide <i><a href="/downloads/paper-reading.pdf">How to Read a Paper</a></i> by S. Keshav from the University of Waterloo that I follow when reading a paper (it is useful for a literature study as well).
Long story short, there are three passes of increasing level of detail.
After the first pass, which takes up to 15 minutes, you should be able to decide whether you are capable of serving as a reviewer for a given manuscript.</p>

<p>Here are the questions that I answer to fill each paragraph:</p>

<ol>
	<li>Brief summary</li>
	<ul>
		<li>
			A brief summary of the article and its contribution.
		</li>
		<li>
			State what you think the contributions are.
		</li>
	</ul>
	<li>Structure</li>
	<ul>
		<li>
			Is the article well-written and easy to understand?
		</li>
		<li>
			Could it be made clearer?
		</li>
		<li>
			Is the article well-organized?
		</li>
		<li>
			Does the article contain all of the components you would expect (Introduction, Background, Related Work, Methods, Results, Conclusions, Discussion)?
		</li>
		<li>
			Are the sections well-developed?
		</li>
		<li>
			General comments regarding layout and format, title, abstract, figures and tables.
		</li>
	</ul>
	<li>
		Novelty
	</li>
	<ul>
		<li>
			What’s new about the work?
		</li>
		<li>
			Does the author do a good job of synthesizing the literature?
		</li>
		<li>
			Is there some related work that the authors have missed?
		</li>
		<li>
			Does the related work invalidate the contribution, or (more likely) simply change its context or emphasis?
		</li>
	</ul>
	<li>
		Criticism of methodology
	</li>
	<ul>
		<li>
			Is the methodology clearly explained?
		</li>
		<li>
			Are there gaps or unaddressed issues?
		</li>
		<li>
			Are there any apparent technical flaws?
		</li>
	</ul>
	<li>
		Criticism of results
	</li>
	<ul>
		<li>
			Does the theory connect to the data?
		</li>
		<li>
			Are you convinced by the author’s results? Why or why not?
		</li>
		<li>
			Does the author answer the questions he/she sets out to answer?
		</li>
	</ul>
	<li>
		Strong points
	</li>
	<ul>
		<li>
			Was there anything you thought was really cool about the paper?
		</li>
	</ul>
	<li>
		Conclusion
	</li>
	<ul>
		<li>
			Give a brief recommendation for the paper and your reasons for it.
		</li>
	</ul>
</ol>

<h3 id="references">References</h3>

<ul>
  <li><a href="https://www.elsevier.com/reviewers-update/story/career-tips-and-advice/ten-tips-from-an-editor-on-undertaking-academic-peer-review-for-journals">10 tips from an editor on undertaking academic peer review for journals</a><br /></li>
  <li><a href="https://www.elsevier.com/reviewers/how-to-conduct-a-review">How to conduct a review</a><br /></li>
  <li><a href="http://www.phd2published.com/2012/05/09/how-to-write-a-peer-review-for-an-academic-journal-six-steps-from-start-to-finish-by-tanya-golash-boza/">How to Write a Peer Review for an Academic Journal: Six Steps from Start to Finish by Tanya Golash-Boza</a><br /></li>
</ul>]]></content><author><name>Mateusz Buda</name></author><summary type="html"><![CDATA[A set of template questions that I follow to fill each paragraph of a peer review for a technical journal.]]></summary></entry><entry><title type="html">Segmentation of brain tumor in magnetic resonance images</title><link href="http://mateuszbuda.com/2017/12/01/brainseg.html" rel="alternate" type="text/html" title="Segmentation of brain tumor in magnetic resonance images" /><published>2017-12-01T00:00:00+00:00</published><updated>2017-12-01T00:00:00+00:00</updated><id>http://mateuszbuda.com/2017/12/01/brainseg</id><content type="html" xml:base="http://mateuszbuda.com/2017/12/01/brainseg.html"><![CDATA[<p>The dataset used for development was obtained from The Cancer Imaging Archive (<a href="https://wiki.cancerimagingarchive.net/display/Public/TCGA-LGG" target="_blank">TCIA</a>) and involved 110 cases of lower-grade glioma patients.
Registers brain MR images with manual FLAIR abnormality segmentation masks are published as a Kaggle Dataset <a href="https://www.kaggle.com/mateuszbuda/lgg-mri-segmentation" target="_blank">lgg-mri-segmentation</a>.</p>

<p style="text-align: center">
    <img src="/images/brainseg/brain-mri-lgg.png" alt="Brain MRI Dataset" width="96%" />
</p>

<p>Together with the dataset, we shared a GPU enabled Python code that can be run on Kaggle: <a href="https://www.kaggle.com/mateuszbuda/brain-segmentation-pytorch" target="_blank">kaggle.com/mateuszbuda/brain-segmentation-pytorch</a>.
The script implements a data loading, preprocessing, as well as training and inference of a U-Net segmentation model.
Trained weights and results can be downloaded form Kaggle.</p>

<p>We applied U-Net architecture for the task of FLAIR abnormality segmentation in brain MRI (Figure 1).
Source code for network architecture, training, and inference implemented in PyTorch together with model weights are available on GitHub repository: <a href="https://github.com/mateuszbuda/brain-segmentation-pytorch" target="_blank">github.com/mateuszbuda/brain-segmentation-pytorch</a>.</p>

<p style="text-align: center">
	<img src="/images/brainseg/unet.png" alt="U-Net" width="96%" />
</p>
<p>Figure 1. The U-Net architecture used for segmentation.</p>

<p>To evaluate the quality of segmentation, we used Dice similarity coefficient (DSC) with 22-fold cross-validation.
The achieved performance was 83.60% mean DSC and 87.33% median DSC.
In comparison, DSC of two expert human readers for this kind of tumor is 84% with a standard deviation of 2%.
This puts our method on a par with radiologists.</p>

<p style="text-align: center">
	<img src="/images/brainseg/CS_4942.gif" alt="CS_4942" width="30%" />
	<img src="/images/brainseg/CS_5395.gif" alt="CS_5395" width="30%" />
	<img src="/images/brainseg/CS_6668.gif" alt="CS_6668" width="30%" />
</p>
<p>Figure 2. Qualitative results of segmentation.
Blue outline corresponds to ground truth and red to automatic segmentation output.
Images show FLAIR modality after preprocessing and skull stripping.</p>

<p style="text-align: center">
	<img src="/images/brainseg/DSC_distribution.png" alt="DSC distribution" width="96%" />
</p>
<p>Figure 3. Distribution of Dice similarity coefficient among cases.
Red line corresponds to mean DSC and green to median DSC.</p>

<p>Then, produced segmentations were used to extract 2D and 3D tumor shape features that are predictive of its genomic subtypes.
More detailed description of methods and results is available in our paper <i><a href="https://doi.org/10.1016/j.compbiomed.2019.05.002" target="_blank">Association of genomic subtypes of lower-grade gliomas with shape features automatically extracted by a deep learning algorithm</a></i> published in Computers in Biology and Medicine.</p>

<p style="text-align: center">
    <img src="/images/brainseg/abstract.png" alt="Graphical Abstract" width="96%" />
</p>

<h3 id="links">Links</h3>

<ul>
  <li>Full paper: <a href="https://doi.org/10.1016/j.compbiomed.2019.05.002" target="_blank">Computers in Biology and Medicine</a></li>
  <li>Code: <a href="https://github.com/mateuszbuda/brain-segmentation-pytorch" target="_blank">github.com/mateuszbuda/brain-segmentation-pytorch</a></li>
  <li>Data: <a href="https://www.kaggle.com/mateuszbuda/lgg-mri-segmentation" target="_blank">lgg-mri-segmentation</a></li>
</ul>]]></content><author><name>Mateusz Buda</name></author><summary type="html"><![CDATA[We applied U-Net architecture for the task of whole tumor segmentation in brain MRI. The dataset used for development was obtained from The Cancer Imaging Archive (TCIA) and involved 110 cases of lower-grade glioma patients. To evaluate the quality of segmentation, we used Dice similarity coefficient (DSC) with 22-fold cross-validation. The achieved performance was 83.60% mean DSC and 87.33% median DSC. In comparison, DSC of two expert human readers for this kind of tumor is 84% with a standard deviation of 2%. This puts our method on a par with radiologists.]]></summary></entry></feed>