Разделение геологической среды на основе измерений каротажа

k-ближайшие соседи (kNN) — это популярный непараметрический алгоритм машинного обучения с учителем, который можно применять как к задачам классификации, так и к задачам регрессии. Его легко реализовать на Python и легко понять, что делает его отличным алгоритмом для начала изучения, когда вы начинаете свой путь машинного обучения.

В этой статье мы расскажем, как работает алгоритм kNN и как применять его к данным каротажа скважин с использованием библиотеки Python Scikit-Learn.

Как работает алгоритм kNN?

Классификация данных — одно из основных применений машинного обучения. В результате существует множество доступных алгоритмов. Алгоритм kNN — лишь один из них.

Идея kNN довольно проста. Точки, находящиеся рядом друг с другом, считаются подобными.

Когда новая точка данных вводится в обученный набор данных, выполняются следующие шаги.

  1. Определите значение для k — количество точек, которые будут использоваться для классификации новых точек данных.
  2. Рассчитайте расстояние (евклидово или манхэттенское) между точкой данных, подлежащей классификации, и k ближайшими точками.
  3. Определите k-ближайших соседей
  4. Среди этих k-ближайших соседей мы подсчитываем количество точек данных в каждом классе.
  5. Используя голосование большинством, назначьте новую точку данных классу, который встречается чаще всего.

Простой пример ниже показывает этот процесс, где мы предполагаем, что k равно 3, а все ближайшие точки относятся к одному классу.

В случае, когда k-ближайшие соседи представляют собой смесь классов, мы можем использовать голосование по большинству, как показано ниже.

Приложения k-ближайших соседей (kNN)

  • Рекомендательные системы
  • Обнаружение шаблонов — например, обнаружение мошенничества
  • Интеллектуальный анализ текста
  • Прогнозирование климата
  • Анализ кредитного рейтинга
  • Медицинская классификация
  • Прогноз литологии

Преимущества k-ближайших соседей (kNN)

  • Просто и понятно
  • Легко реализовать на Python с помощью Sci-kit Learn.
  • Может быть быстрой для работы с небольшими наборами данных
  • Нет необходимости настраивать несколько параметров
  • Нет необходимости делать предположения о данных
  • Может применяться к бинарным и мультиклассовым задачам

Недостаткиk-ближайших соседей (kNN)

  • Классификация с большими наборами данных может быть медленной
  • Под влиянием проклятия размерности — по мере увеличения количества признаков алгоритму может быть трудно делать точные прогнозы.
  • Может быть чувствителен к масштабу данных, т. е. характеристикам, измеряемым в разных единицах измерения.
  • Влияние шума и выбросов
  • Чувствителен к несбалансированным наборам данных
  • Отсутствующие значения должны быть обработаны до использования алгоритма.

Реализация KNN с помощью Scikit-Learn для классификации фаций

Импорт необходимых библиотек

Для этого руководства нам потребуется ряд библиотек и модулей Python.

Сначала мы импортируем pandas как pd. Эта библиотека позволяет нам загружать данные из CSV-файлов и сохранять эти данные в памяти для последующего использования.

Затем у нас есть несколько модулей из научной библиотеки:

  • KNeighborsClassifer для проведения классификации kNN
  • train_test_split за разделение наших данных на наборы данных для обучения и тестирования
  • StandardScaler для стандартизации масштабов признаков
  • classification_report, confusion_matrix и accuracy_score для оценки производительности модели

Наконец, для визуализации наших данных мы будем использовать смесь matplotlib и seaborn.

import pandas as pd
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score
import seaborn as sns
import matplotlib.pyplot as plt

Импорт необходимых данных

Следующим шагом будет загрузка наших данных.

Набор данных, который мы используем для этого руководства, является подмножеством обучающего набора данных, используемого в рамках соревнования по машинному обучению, проводимого Xeek и FORCE 2020 (Bormann et al., 2020). Он выпущен под лицензией NOLD 2.0 от правительства Норвегии, подробности о которой можно найти здесь: Норвежская лицензия на открытые правительственные данные (NLOD) 2.0.

Полный набор данных доступен по следующей ссылке: https://doi.org/10.5281/zenodo.4351155.

Чтобы прочитать данные, мы можем вызвать pd.read_csv() и передать относительное расположение обучающего файла.

df = pd.read_csv('Data/Xeek_train_subset_clean.csv')

После загрузки данных мы можем вызвать метод describe() для просмотра числовых столбцов в наборе данных. Это дает нам обзор функций.

df.describe()

Подготовка данных

Работа с отсутствующими данными

Прежде чем мы приступим к алгоритму kNN, нам сначала нужно выполнить некоторую подготовку данных.

Поскольку алгоритм kNN не обрабатывает пропущенные значения, нам нужно сначала разобраться с ними. Самый простой способ сделать это — выполнить удаление по списку. Это приведет к удалению строк, если какой-либо из объектов в этой строке имеет пропущенные значения.

Настоятельно рекомендуется провести полный анализ набора данных, чтобы понять причину отсутствия данных и возможность ее исправления.

Несмотря на то, что этот метод кажется быстрым решением, он может значительно сократить ваш набор данных.

df = df.dropna()

Выбор функций обучения и тестирования

Далее нам нужно выбрать, какие функции будут использоваться для построения модели kNN и какая функция будет нашей целевой функцией.

В этом примере я использую серию каротажных измерений для построения модели и описание литологии в качестве целевого признака.

# Select inputs and target
X = df[['RDEP', 'RHOB', 'GR', 'NPHI', 'PEF', 'DTC']]
y = df['LITH']

Как и в случае любой модели машинного обучения, нам необходимо разделить наши данные на обучающий набор, который используется для обучения/построения нашей модели, и тестовый набор, который используется для проверки производительности нашей модели на невидимых данных.

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

Стандартизация значений функций

При работе с измерениями, имеющими разные масштабы и диапазоны, важно их стандартизировать. Это помогает сократить время обучения модели и уменьшить влияние на модели, основанные на расчетах на основе расстояния.

Стандартизация данных по существу включает в себя вычисление среднего значения признака, вычитание его из каждой точки данных и последующее деление на стандартное отклонение признака.

В рамках scikit-learn мы можем использовать класс StandardScaler для преобразования наших данных.

Сначала мы используем данные обучения, чтобы подогнать модель, а затем преобразуем ее с помощью функции fit_transform.

Когда дело доходит до тестовых данных, мы не хотим подгонять StandardScaler к этим данным, поскольку мы уже сделали это. Вместо этого мы просто хотим применить его. Это делается с помощью метода transform.

Важно отметить, что StandardScaler применяется после разделения тестов на поезд и только подгоняется к набору обучающих данных. После подбора модели Scaler она применяется к тестовому набору данных. Это помогает предотвратить утечку данных из тестового набора данных в модель kNN.

scaler = StandardScaler()

#Fit the StandardScaler to the training data
X_train = scaler.fit_transform(X_train)

# Apply the StandardScaler, but not fit, to the validation data
X_test = scaler.transform(X_test)

Построение классификатора kNN

При создании KNeighborsClassifier мы можем указать несколько параметров. Полную информацию о них можно найти здесь. Конечно, нам не нужно ничего указывать, и будут использоваться параметры по умолчанию.

По умолчанию количество точек, используемых для классификации новых точек данных, равно 5. Это означает, что класс 5 ближайших точек будет использоваться для классификации этой новой точки.

clf = KNeighborsClassifier()

После инициализации классификатора нам нужно обучить модель, используя наши обучающие данные (X_train и y_train). Для этого мы вызываем clf, а затем метод fit.

В методе fit мы передаем наши обучающие данные.

clf.fit(X_train, y_train)

Делаем прогнозы с помощью модели kNN

После того, как модель была обучена, мы теперь можем делать прогнозы на наших тестовых данных, вызывая метод predict из классификатора.

y_pred = clf.predict(X_test)

Оценка производительности модели

Использование точности модели

Чтобы понять, как наша модель работала на тестовых данных, мы можем использовать ряд показателей и инструментов.

Если мы хотим быстро оценить, насколько хорошо работает наша модель, мы можем обратиться к методу оценки точности. Это дает нам представление о том, сколько прогнозов было правильным по отношению к общему количеству прогнозов.

accuracy_score(y_test, y_pred)

Это возвращает значение 0,8918532439941167 и говорит нам, что наша модель правильно предсказала 89,2% наших меток.

Имейте в виду, что это значение может ввести в заблуждение, особенно если мы имеем дело с несбалансированным набором данных. Если есть класс, который доминирует, то этот класс имеет больше шансов быть правильно предсказанным по сравнению с классом меньшинства. Доминирующий класс повлияет на показатель точности, повысив его и тем самым создав ложное впечатление, что наша модель проделала хорошую работу.

Использование отчета о классификации

Мы можем продолжить нашу оценку и посмотреть на отчет о классификации. Это обеспечивает дополнительные показатели, а также показывает, насколько хорошо был предсказан каждый класс.

Дополнительными показателями являются:

  • точность: показывает, сколько значений было правильно предсказано в этом классе. Значения находятся в диапазоне от 0,0 до 1,0, где 1 — наилучшее, а 0 — наихудшее.
  • отзыв: показывает, насколько хорошо классификатор может найти все положительные случаи для этого класса.
  • f1-score: средневзвешенное гармоническое значение точности и полноты, которое генерирует значения от 1,0 (хорошо) до 0,0 (плохо).
  • support: это общее количество экземпляров этого класса в наборе данных.

Чтобы просмотреть отчет о классификации, мы можем вызвать следующий код и передать y_test и y_pred функции classification_report.

print(classification_report(y_test, y_pred))

Если мы внимательно посмотрим на результаты, то увидим, что имеем дело с несбалансированным набором данных. Мы видим, что классы Shale, Sandstone и Limestone доминируют и, как результат, имеют относительно высокие показатели точности и полноты. В то время как Halite, Tuff и Dolomite имеют относительно низкую точность и отзыв.

На этом этапе я бы подумал о том, чтобы вернуться к исходному набору данных и определить, как я мог бы справиться с этим дисбалансом. Это должно значительно улучшить производительность модели.

Матрица путаницы

Мы можем использовать другой инструмент, чтобы посмотреть, насколько хорошо работает наша модель, и это матрица путаницы. Этот инструмент предоставляет сводную информацию о том, насколько хорошо наша модель классификации работает при прогнозировании для каждого класса.

Сгенерированная матрица путаницы имеет две оси. Одна ось содержит класс, предсказанный моделью, а другая ось содержит фактическую метку класса.

Мы можем сгенерировать две версии этого в Python. Первый представляет собой простое печатное отображение матрицы путаницы, которое может быть трудно прочитать или представить другим. Вторая — версия тепловой карты, сгенерированная с помощью Seaborn.

# Simple Printed Confusion Matrix
cf_matrix = confusion_matrix(y_test, y_pred)
print(cf_matrix)

# Graphical version using seaborn and matplotlib
# Prepare the labels for the axes
labels = ['Shale', 'Sandstone', 'Sandstone/Shale', 
        'Limestone', 'Tuff', 'Marl', 'Anhydrite', 
        'Dolomite', 'Chalk', 'Coal', 'Halite']
labels.sort()

# Setup the figure
fig = plt.figure(figsize=(10,10))
ax = sns.heatmap(cf_matrix, annot=True, cmap='Reds', fmt='.0f',
                xticklabels=labels, 
                yticklabels = labels)
ax.set_title('Seaborn Confusion Matrix with labels\n\n')
ax.set_xlabel('\nPredicted Values')
ax.set_ylabel('Actual Values ');

Когда мы запускаем приведенный выше код, мы получаем следующую печатную таблицу и график.

Полученная матрица путаницы дает нам представление о том, какие классы модель предсказала правильно и неправильно. Мы можем начать выявлять любые закономерности, в которых модель может неправильно предсказывать литологию.

Например, если мы посмотрим на класс Limestone. Мы видим, что 2613 точек были предсказаны правильно, однако 185 были предсказаны как Мел и 135 как Мергель. Обе эти литологии имеют кальцитовую природу и обладают сходными свойствами с известняком. Поэтому мы могли бы вернуться и посмотреть на наши функции, чтобы определить, требуются ли другие функции или некоторые из них необходимо удалить.

Краткое содержание

Алгоритм k-ближайших соседей — это мощный, но простой для понимания алгоритм контролируемого машинного обучения, который можно применять к задачам, основанным на классификации, особенно в области наук о Земле.

В этом учебном пособии показано, как мы можем выполнить серию предварительно классифицированных измерений каротажа и сделать прогнозы относительно новых данных. Однако следует соблюдать осторожность при предварительной обработке данных и работе с несбалансированными наборами данных, что часто встречается в приложениях для недр.

Спасибо, что прочитали. Прежде чем идти, вы должны обязательно подписаться на мой контент и получать мои статьи в свой почтовый ящик. Ты можешь сделать это здесь! Кроме того, вы можете подписаться на мою рассылку новостей, чтобы бесплатно получать дополнительный контент прямо в свой почтовый ящик.

Во-вторых, вы можете получить все возможности Medium и поддержать меня и тысячи других авторов, подписавшись на членство. Это стоит всего 5 долларов в месяц, и у вас есть полный доступ ко всем потрясающим статьям на Medium, а также возможность зарабатывать деньги своим текстом. Если вы зарегистрируетесь, используя мою ссылку, вы поддержите меня напрямую частью вашего гонорара, и это не будет стоить вам больше. Если вы это сделаете, большое спасибо за вашу поддержку!