"Машинное обучение"
Машинное обучение/биостатистика на клеточных изображениях для диагностики острого лимфобластного лейкоза
Если вам нравится то, что я пишу, рассмотрите возможность стать участником, используя ссылку ниже:
https://medium.com/@ashu.malgaonkar/membership
Оглавление:
I. Об этом наборе данных
II. Цитирование набора данных
III. Загрузка данных
IV. Обработка данных в Python
V. Машинное обучение
VI. Анализ показателей
VII. Заключение
I. Об этом наборе данных
Острый лимфобластный лейкоз (ОЛЛ) является наиболее распространенным типом рака у детей и составляет примерно 25% всех онкологических заболеваний у детей.
Эти клетки были выделены из микроскопических изображений и являются репрезентативными изображениями в реальном мире, потому что они содержат некоторые ошибки окрашивания и освещения, хотя эти ошибки в основном были исправлены в ходе сбора данных.
Задача идентификации незрелых лейкемических бластов из нормальных клеток под микроскопом является сложной из-за морфологического сходства, поэтому метки истинности были аннотированы опытным онкологом.
Всего имеется 15 135 изображений от 118 пациентов с двумя помеченными классами:
- Нормальная ячейка;
- Взрыв лейкемии.
II. Цитирование набора данных
Набор данных можно найти здесь:
Классификация лейкозов | Kaggle
Цитирование данных
- Гупта, А., и Гупта, Р. (2019). Набор данных ALL Challenge ISBI 2019 [Набор данных]. Архив изображений рака. https://doi.org/10.7937/tcia.2019.dc64i46r
Цитата публикации
- Анубха Гупта, Рахул Дуггал, Риту Гупта, Лалит Кумар, Нисарг Тхаккар и Девпракаш Сатпати, «GCTI-SN: нормализация химических и тканевых инвариантных пятен на основе геометрии микроскопических медицинских изображений», находится на рассмотрении.
Риту Гупта, Прамит Маллик, Рахул Дуггал, Анубха Гупта и Оджасва Шарма, «Нормализация цвета пятен и сегментация плазматических клеток в микроскопических изображениях как прелюдия к разработке автоматизированного инструмента диагностики заболеваний множественной миеломы», 16-й Международный семинар по миеломе (IMW), Индия, март 2017 г. - Рахул Дуггал, Анубха Гупта, Риту Гупта, Маня Вадхва и Чираг Ахуджа, «Сегментация перекрывающихся клеточных ядер в микроскопических изображениях с использованием сетей глубокого убеждения», Индийская конференция по компьютерному зрению, графике и обработке изображений (ICVGIP), Индия, декабрь 2016 г.
Рахул Дуггал, Анубха Гупта и Риту Гупта, «Сегментация перекрывающихся/соприкасающихся ядер лейкоцитов с использованием искусственных нейронных сетей», Серия CME по гемато-онкопатологии, Всеиндийский институт медицинских наук (AIIMS), Нью-Дели, Индия, июль 2016 г. - Рахул Дуггал, Анубха Гупта, Риту Гупта и Прамит Маллик, SD-слой: деконволюционный слой окрашивания для CNN в медицинской микроскопии, В: Деското М., Майер-Хейн Л., Франц А., Яннин П., Коллинз Д., Дюшен С. (редакторы) Вычисление медицинских изображений и вмешательство с помощью компьютера — MICCAI 2017, MICCAI 2017. Конспект лекций по информатике, часть III, LNCS 10435, стр. 435–443. Спрингер, Чам. DOI: https://doi.org/10.1007/978-3-319-66179-7_50.
III. Загрузка данных
Перейдите по этой ссылке и скачайте данные: Классификация лейкозов | Kaggle
Как только вы извлечете свою папку, вы увидите две папки, когда будете следовать по пути, который будет содержать изображения:
В папке «все» находятся изображения с раком:
В папке «Подол» находятся нераковые изображения:
IV. Обработка данных в Python
Для обработки данных нам понадобятся некоторые пакеты.
Нам понадобится skimage io для чтения изображения и получения пикселей:
from skimage import io
Затем нам нужен пакет для хранения наших данных. Для этого мы можем использовать пакет фрейма данных, такой как pandas:
import pandas as pd
Затем нам нужно, чтобы os указала нам каталог, в котором находятся наши изображения:
import os
Хорошо, теперь, когда у нас есть наши пакеты, давайте создадим переменную для двух наших путей, один для папки «все», а другой для папки «подол»:
pathforall= r'C:\...Desktop\Leukemia\archive\C-NMC_Leukemia\training_data\fold_0\all' pathforhem= r'C:\...Desktop\Leukemia\archive\C-NMC_Leukemia\training_data\fold_0\hem'
Теперь нам нужно указать Python на эти папки (переменные пути выше) и сохранить в них имена файлов в виде списка. Эти две строки дают вам два списка, один для «всех» изображений, а другой для «подол» изображений:
dir_list=os.listdir(pathforall) dir_list2=os.listdir(pathforhem)
Вот пример того, как это выглядит в обозревателе переменных редактора Spyder, который я использую для написания своего кода:
Хорошо, теперь пришло время сохранить данные из этих изображений. Позвольте мне показать вам полный код, а затем рассказать, как я это сделал:
df = pd.DataFrame() for i in dir_list[:300]: img=io.imread(pathforall + "\\" + i) my_df = pd.DataFrame(img.flatten()).transpose() my_df['Class'] = 'ALL' my_df=my_df.head(n=1) df = df.append(my_df, ignore_index=True)
Итак, давайте рассмотрим это шаг за шагом:
Первая строка в приведенном выше коде создает пустой фрейм данных. Этот фрейм данных с именем df — это то, в чем я буду хранить свои «все» данные.
df = pd.DataFrame()
Затем я инициирую цикл for, который указывает на список из папки «все». Помните, что наш список называется dir_list. Я обработал только часть изображений для своего проекта, так как все 2500 заняли у меня от получаса до часа, чтобы пройти через программу, и я не хотел ждать так долго. Вот что означает [:300], т.е. список на этом закончится:
for i in dir_list[:300]:
Теперь внутри цикла for я пишу код. Это означает, что код будет запускаться и сохранять данные для каждого изображения во фрейме данных. Давайте пройдем через это.
Строка ниже берет путь для всего текста и добавляет косую черту после него, а затем добавляет «i» из нашего цикла for. Это «i» — это имя файла первого изображения, затем второго изображения, когда цикл запускается во второй раз, затем третьего изображения и т. д., т. е. «i» перебирает имена файлов изображений в пределах папка «все»:
img=io.imread(pathforall + "\\" + i)
IMG — это n-мерный массив, состоящий из пиксельных данных изображения.
Однако нам нужно сгладить это, чтобы оно стало похоже на список. Для этого мы можем использовать img.flatten(). Затем нам нужно сохранить эти значения в виде кадра данных Pandas, чтобы мы могли хранить их и манипулировать ими позже. Однако, когда мы создаем фрейм данных из нашего списка, он будет хранить список в одном столбце. Это не полезно для нас. Мы хотим, чтобы наш список хранился горизонтально в строке, чтобы мы могли иметь наш класс «все/рак» в качестве последнего столбца, а затем использовать алгоритм машинного обучения для его классификации. Для этого нам нужно транспонировать данные. Позвольте мне сначала объяснить, что это будет делать.
Во-первых, массив, который выглядит так:
когда он сплющивается с помощью img.flatten, он будет выглядеть так:
{0,0,0,0…}
Когда это преобразовано во фрейм данных, это будет выглядеть так:
Однако нам нужно первое изображение в первой строке, второе изображение во второй строке и так далее. Так что нам придется его транспонировать. Когда вы транспонируете что-то, похожее на приведенное выше, это выглядит как строка:
Все это выравнивание, преобразование во фрейм данных и транспонирование можно выполнить с помощью этого фрагмента кода:
my_df = pd.DataFrame(img.flatten()).transpose()
Затем мы хотим, чтобы строка, которую мы только что создали, имела правильную метку. В этом случае мы перебираем раковые клетки, поэтому наша метка/класс будет «ВСЕ»:
my_df['Class'] = 'ALL'
Теперь давайте удостоверимся, что мы берем только одну строку, которую мы сделали:
my_df=my_df.head(n=1)
Теперь помните, что все, что мы делаем, является частью цикла for. Таким образом, последняя часть нашего цикла будет заключаться в том, чтобы взять пустой фрейм данных, который мы создали ранее, вне нашего цикла, и поместить в него строку, которую мы только что создали:
df = df.append(my_df, ignore_index=True)
Теперь каждый раз, когда цикл выполняется, он будет проходить через него и помещать строку внизу.
Теперь давайте сделаем то же самое для данных «кромки», повторив на пути «кромки»:
df2 = pd.DataFrame() for i in dir_list2[:300]: img2=io.imread(pathforhem + "\\" + i) my_df2 = pd.DataFrame(img2.flatten()).transpose() my_df2['Class'] = 'Not ALL' my_df2=my_df2.head(n=1) df2 = df2.append(my_df2, ignore_index=True)
Обратите внимание, что это класс «Не все».
Хорошо, теперь у нас есть два разных фрейма данных с данными о пикселях изображения в каждой строке. Один фрейм данных содержит пиксельные данные для клеток лейкемии, а другой — для клеток, не относящихся к лейкемии.
Теперь, чтобы запустить алгоритм классификации, нам сначала нужно сделать его одним набором данных. Мы можем сделать это с помощью команды concat. Команда concat по сути представляет собой «объединение» в терминах SQL. Он складывает наборы данных друг над другом:
df_stack = pd.concat([df, df2])
Когда вы запустите команду concat, как показано выше, вы заметите следующее в обозревателе переменных:
Обратите внимание на размер. Размер df и df2 равен 300 каждый. Когда вы ставите их друг на друга, получается 600. Это быстрый способ проверить свою работу.
V. Машинное обучение
Алгоритм, который я буду использовать здесь, представляет собой машину опорных векторов:
«Машины опорных векторов Часть 1 (из 3): Основные идеи!!! - YouTube"
Машины опорных векторов, часть 2: полиномиальное ядро (часть 2 из 3) — YouTube
Машины опорных векторов, часть 3: радиальное (RBF) ядро (часть 3 из 3) — YouTube
Давайте начнем с разбиения нашего набора данных на X и y. X будет функциями или столбцами, которые будут использоваться для прогнозирования целевой переменной, то есть класса, который будет храниться как y.
#Store class as y and rest of data as x X = df_stack.drop('Class', axis=1) y = df_stack['Class']
Давайте разделим набор данных на тестирование и обучение. Обучающий набор будет составлять 80%, а тестовый набор — 20%. Это означает, что алгоритм будет использовать 80% данных для обучения и построения правил, а затем использовать их для прогнозирования класса в остальных 20%.
#split data from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.20)
Теперь давайте реализуем нашу машину опорных векторов:
from sklearn.svm import SVC
Ядро, которое мы собираемся выбрать:
svclassifier = SVC(kernel='rbf')
Это ядро лучше всего работает, когда данные перекрываются, а в таких случаях, как обработка изображений, они перекрываются. Вы можете узнать больше о ядре здесь:
Машины опорных векторов, часть 3: радиальное (RBF) ядро (часть 3 из 3) — YouTube
svclassifier.fit(X_train, y_train)
А теперь сделаем некоторые прогнозы:
#make predictions y_pred = svclassifier.predict(X_test)
Давайте теперь посмотрим на метрики из прогноза:
#metrics from sklearn.metrics import classification_report, confusion_matrix print(confusion_matrix(y_test,y_pred)) print(classification_report(y_test,y_pred))
Распечатка показателей выглядит так:
VI. Анализ показателей
Посмотрите на матрицу путаницы:
[[59 5]
[16 40]]
В sklearn прогнозируемая метка находится вверху, а фактическая метка сбоку:
Это означает, что на тестовых данных алгоритм имел следующую точность:
Accuracy --> (59+40)/(59+5+16+40) = 82.5%
Чувствительность = количество истинных положительных результатов / (количество истинных положительных результатов + количество ложноотрицательных результатов)
Sensitivity --> 59 / (59 + 5) = 59/64 = 92%
Специфика = количество истинно отрицательных результатов / (количество истинно отрицательных результатов + количество ложноположительных результатов)
Specificity --> 40 / (16+40) = 40/56 = 71%
Как видите, расстройство можно предсказать с вероятностью 92% правильно, когда человек действительно болен, т.е. чувствительность этого алгоритма очень высока
VII. Вывод:
Этот тест действительно хорошо подходит для диагностики ВСЕХ случаев, когда у человека есть ВСЕ, т. е. он имеет хорошую чувствительность на уровне 92 %. Однако, когда у человека НЕТ ВСЕХ, это может иногда давать ложноположительный результат.
Другие статьи:
2 — Как создать систему определения местоположения для города | Ашутош Малгаонкар | Навстречу ИИ