Пример изучения петрофизических измерений и измерений каротажа с использованием ряда графиков из Seaborn и Matplotlib

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

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

1. Первоначальное исследование выбранных скважин из набора полевых данных Volve
2. Выявление недостающих данных
3. Выявление выбросов / аномальных точек данных с помощью ручных и автоматических методов
4. Прогнозирование ключевых свойства коллектора с использованием машинного обучения

Данные

В 2018 году Equinor опубликовала все содержимое поля Volve Field в открытом доступе, чтобы способствовать исследованиям и обучению. Опубликованные данные включают:

  • Журналы скважин
  • Петрофизические интерпретации
  • Отчеты (геологические, заканчивания, петрофизические, керновые и т. Д.)
  • Основные измерения
  • Сейсмические данные
  • Геологические модели
  • и больше…

Месторождение Волве расположено примерно в 200 км к западу от Ставангера в норвежском секторе Северного моря. Углеводороды были обнаружены в формации Хугин юрского возраста в 1993 году. Добыча нефти началась в 2008 году и продолжалась 8 лет (вдвое дольше запланированного) до 2016 года, когда добыча прекратилась. Всего за время эксплуатации месторождения было добыто 63 млн баррелей в сутки, достигнув отметки 56 000 баррелей в сутки.

Более подробную информацию о месторождении Волве и весь набор данных можно найти по адресу: https://www.equinor.com/en/what-we-do/norwegian-continental-shelf-platforms/volve.html

Данные находятся под лицензией Equinor Open Data License.

Выбранные данные для анализа

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

  • 15/9-F-1 A
  • 15/9-F-1 B
  • 15/9-F-1 C
  • 15/9-F-11 A
  • 15/9-F-11 B

По этим скважинам был выбран стандартный набор ГИС (характеристик). Их названия, единицы и описания подробно описаны в таблице ниже.

Целью серии блокнотов будет прогнозирование трех обычно получаемых петрофизических измерений: пористости (PHIF), водонасыщенности (SW) и объема сланцев (VSH). Традиционно они рассчитываются с помощью ряда уравнений, выведенных эмпирическим путем.

Исследование данных

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

Я ранее рассматривал ряд процессов и графиков EDA в своих предыдущих статьях о среде:

  • Разведочный анализ данных с использованием данных каротажа
  • Визуализация покрытия скважинными данными с помощью Matplotlib
  • Как использовать обучение без учителя для кластеризации данных каротажа с помощью Python

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

В этом уроке мы рассмотрим:

  • Чтение данных из файла CSV
  • Просмотр данных на графике журнала
  • Просмотр данных на графике / графике рассеяния
  • Просмотр данных на гистограмме
  • Визуализация всех кривых каротажа на кроссплоте и гистограмме с использованием парного графика

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

Первый шаг - импортировать нужные нам библиотеки. Это pandas для загрузки и хранения данных, matplotlib и seaborn для визуализации данных.

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
import seaborn as sns

После импорта библиотек мы загрузим данные с помощью функции pandas read_csv и присвоим их переменной df.

df = pd.read_csv('data/spwla_volve_data.csv')

Pandas .describe Функция

После загрузки данные будут сохранены в структурированном объекте, похожем на таблицу, известном как фрейм данных. Мы можем проверить содержимое фрейма данных несколькими способами. Во-первых, мы можем проверить сводную статистику числовых столбцов с помощью функции .describe(). Отсюда мы можем найти информацию о количестве точек данных для каждой функции, среднем значении, стандартном отклонении, минимальных, максимальных и процентильных значениях.

Чтобы упростить чтение таблицы, мы добавим функцию .transpose(). При этом имена столбцов помещаются в строки, а статистические измерения - в столбцы.

df.describe().transpose()

Функция Pandas .info

Следующий метод, который мы можем вызвать, - это .info(). Это предоставляет список всех столбцов в кадре данных, их тип данных (например, с плавающей запятой, целое число, строка и т. Д.) И количество ненулевых значений, содержащихся в каждом столбце. Ниже мы видим, что у нас есть столбец с именем wellName, которого не было во фрейме данных, показанном выше.

df.info()

RangeIndex: 27845 entries, 0 to 27844
Data columns (total 16 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   wellName  27845 non-null  object 
 1   MD        27845 non-null  float64
 2   BS        27845 non-null  float64
 3   CALI      27845 non-null  float64
 4   DT        5493 non-null   float64
 5   DTS       5420 non-null   float64
 6   GR        27845 non-null  float64
 7   NPHI      27845 non-null  float64
 8   RACEHM    27845 non-null  float64
 9   RACELM    27845 non-null  float64
 10  RHOB      27845 non-null  float64
 11  RPCEHM    27845 non-null  float64
 12  RPCELM    27600 non-null  float64
 13  PHIF      27736 non-null  float64
 14  SW        27736 non-null  float64
 15  VSH       27844 non-null  float64
dtypes: float64(15), object(1)
memory usage: 3.4+ MB

Функции .head и .tail Pandas

Следующий полезный набор доступных нам методов - это функции head() и .tail(). Они возвращают первые / последние пять строк фрейма данных

df.head()

df.tail()

Нахождение названия скважин с помощью функции .unique

Из введения мы знаем, что в этом наборе данных должно быть 5 скважин. Мы можем проверить это, вызвав столбец wellName и используя метод .unique(). Это вернет массив, в котором перечислены все уникальные значения в этом столбце.

df['wellName'].unique()
array(['15/9-F-1 A', '15/9-F-1 B', '15/9-F-1 C', '15/9-F-11 A',
       '15/9-F-11 B'], dtype=object)

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

df['CALI']
0        8.6718
1        8.6250
2        8.6250
3        8.6250
4        8.6250
          ...  
27840    8.8750
27841    8.8510
27842    8.8040
27843    8.7260
27844    8.6720
Name: CALI, Length: 27845, dtype: float64

Визуализация данных

Графики ГИС

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

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

Эта create_plot функция принимает ряд аргументов (входов):

  • wellname: имя скважины в виде строки
  • фрейм данных: фрейм данных для выбранной лунки.
  • Curve_to_plot: список столбцов кривых каротажа / фрейма данных, которые мы хотим построить.
  • depth_curve: кривая глубины, против которой мы хотим построить график.
  • log_curves: список кривых, которые необходимо отобразить в логарифмическом масштабе.

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

grouped =df.groupby('wellName')

Когда мы вызываем функцию head() этого нового сгруппированного фрейма данных, мы получаем первые 5 строк для каждой лунки.

grouped.head()

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

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

# Create empty lists
dfs_wells = []
wellnames = []

#Split up the data by well
for well, data in grouped:
    dfs_wells.append(data)
    wellnames.append(well)

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

for i, well in enumerate(wellnames):
    print(f'Index: {i} - {well}')
Index: 0 - 15/9-F-1 A
Index: 1 - 15/9-F-1 B
Index: 2 - 15/9-F-1 C
Index: 3 - 15/9-F-11 A
Index: 4 - 15/9-F-11 B

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

curves_to_plot = ['BS', 'CALI', 'DT', 'DTS', 'GR', 
                  'NPHI', 'RACEHM', 'RACELM', 'RHOB', 
                  'RPCEHM', 'RPCELM', 'PHIF', 'SW', 'VSH']

logarithmic_curves = ['RACEHM', 'RACELM', 'RPCEHM', 'RPCELM']

Заедем в первую скважину и сделаем заговор.

Обратите внимание, что списки Python индексируются с 0, поэтому первая ячейка в списке будет в позиции 0.

well = 0
create_plot(wellnames[well], dfs_wells[well],
            curves_to_plot, dfs_wells[well]['MD'], 
            logarithmic_curves)

Когда мы выполняем этот код, мы генерируем следующий график для 15/9-F-1 A. У нас есть все наши каротажные измерения на одном графике, а кривые удельного сопротивления отображаются логарифмически, как мы и ожидали.

То же самое можно сделать и со вторым колодцем:

well = 1
create_plot(wellnames[well], dfs_wells[well], 
            curves_to_plot, dfs_wells[well]['MD'], 
            logarithmic_curves)

Стандартные кроссплоты (точечные диаграммы) с использованием Seaborn

Кросс-плоты (также известные как диаграммы рассеяния) - еще один распространенный инструмент визуализации данных, который мы используем во время петрофизического анализа. Более подробную информацию о работе с кроссплотами (диаграммами рассеяния) и данными ГИС можно найти здесь:

Подобно приведенному выше разделу графиков журналов, мы создадим простую функцию, в которой мы сможем сгенерировать несколько кроссплотов, используя простую функцию. Эта функция использует функцию FacetGrid от Seaborn и позволяет отображать графики непосредственно поверх сетки. Это намного более простой способ построения данных по сравнению с subplot2grid в matplotlib.

Аргументы (входы) этой функции:

  • x - переменная оси X в виде строки, например «НПХИ»
  • y - переменная оси Y в виде строки, например ‘RHOB’
  • c - третья переменная, используемая для применения цвета к кроссплоту, например «GR»
  • фрейм данных - сгруппированный фрейм данных, созданный с использованием .groupby('wellName')
  • columns - количество столбцов, отображаемых на рисунке.
  • xscale - масштаб по оси X
  • yscale - масштаб по оси Y
  • vmin - минимальное значение для цветовой заливки.
  • vmax - максимальное значение цветового затенения.

Оценка качества данных по нейтронной пористости и объемной плотности с помощью скважинного штангенциркуля

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

Из графика выше видно, что большинство скважин находятся в хорошем состоянии и не слишком сильно размыты, хотя в скважине 15/9-F11 B скважина немного увеличена, что показано более красными цветами.

Кросс-диаграмма между акустическим сжатием и сдвигом с окраской гамма-лучей

Следующий кросс-график, который мы рассмотрим, - это зависимость акустического сжатия (DTC) от акустического сдвига (DTS).

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

Гистограммы

гистограммы matplotlib

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

Гистограммы позволяют нам просматривать распределение, форму и диапазон числовых данных. Данные разделены на несколько интервалов, которые представлены отдельными полосами на графике.

Вы можете узнать больше о работе с гистограммами и данными ГИС в этой статье:

Создание гистограмм данных ГИС с помощью Matplotlib в Python

Мы можем вызвать простую гистограмму из нашего основного фрейма данных, просто добавив .hist(column-name) в конец объекта фрейма данных.

df.hist('GR')

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

df.hist('GR', bins=40)
plt.grid(False)

Сказанное выше приводит к мгновенному улучшению сюжета. Теперь мы можем видеть распределение данных гораздо более четко, однако все данные по-прежнему объединены.

Гистограммы Сиборна

Мы также можем обратиться к библиотеке графиков Seaborn, которая дает нам гораздо больше контроля над эстетикой сюжета. В первом примере мы можем добавить оценку плотности ядра (KDE).

Из графика выше мы видим, что метки генерируются автоматически для нас, и у нас также есть линия KDE.

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

Если мы передадим wellName для оттенка, мы сможем сгенерировать отдельные гистограммы для каждой лунки.

То же самое можно сделать и с насыпной плотностью (RHOB). Мы также можем добавить количество бункеров, которые мы хотим отобразить.

FacetGrid

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

Для FacetGrid мы указываем фрейм данных и столбцы, на которые нужно разделить данные. hue, как упоминалось в разделе кросс-плота, управляет цветом данных в каждом столбце, а col_wrap определяет максимальное количество столбцов перед переносом графика в новую строку.

KDEPlot

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

Сиборн Парный сюжет

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

Мы передаем фрейм данных вместе с переменными, которые хотим проанализировать. Вдоль диагонали парного графика у нас может быть гистограмма, но в этом примере мы будем использовать график KDE. Кроме того, мы можем указать цвета, формы и т. Д. С помощью аргумента plot_kws.

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

Резюме

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

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

Этот блокнот был первоначально опубликован для семинара по машинному обучению SPWLA на конференции SPWLA 2021 года.

Спасибо за внимание!

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

Если вы хотите связаться, вы можете найти меня в LinkedIn или на моем сайте.

Хотите узнать больше о питоне и данных каротажа скважин или о петрофизике? Следуйте за мной на Medium.

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