Шукати в цьому блозі

субота, 21 червня 2014 р.

Перевірка блокових моделей за допомогою R

Ця тема оформилась у мене цілком спонтанно. Причина написання статті у тому, що поступово зростає кількість халтури, яка прикривається гордим ім’ям "геостатистичний аналіз". Халтурять усі: геологи, які виконують первинне документування; геологи, які проектують та заповнюють бази даних; геологи, які за допомогою модних на сьогодні методів, намагаються підрахувати запаси родовищ.

Біда в тому, що більшість споживачів подібної халтури (читай - керівників та інженерних співробітників підприємств гірничодобувної промисловості) навіть не розуміє особливостей застосування подібних методик та їхніх обмежень. В результаті ми отримуємо замкнене коло - через декілька років на підприємстві стає зрозумілим, що побудована модель зовсім не відповідає реальним показникам геологічного об’єкту. Підприємство звертається за допомогою до іншого виконавця. Інший виконавець розказує - як все погано і неправильно, і в решті-решт підсовує замовнику таку-саму халтуру, тільки по іншому розфарбовану. Якщо Вам неправильно інтерпретували результати аналізу сечі або крові, і декілька років лікували від хибного діабету або гастриту - якими будуть Ваші дії? А якщо Вам неправильно інтерпретували результати опробування і Ви декілька років намагались видобувати руду там, де її взагалі немає - якими будуть Ваші дії у цьому випадку?
У цій статті ми спробуємо розібратись із декількома простими, але доволі дієвими методами "виведення на чисту воду" виконавців. Слід зауважити на тому, що деякі з виконавців навіть не можуть внятно роз’яснити - які методи обчислення вони використовували і якими методами перевіряли отримані моделі. Звіти, які вони подають замовнику - здебільшого являють собою стандартний набір не пов’язаних між собою картинок і таблиць.
Зазвичай, виконавці уповають на порівняння центральних моментів (середньої арифметичної, медіани, дисперсії)  двох вибірок: даних опробування і результатів моделювання. Але, я вважаю, не треба пояснювати читачам те, що центральні моменти можуть співпадати навіть для даних, отриманих за допомогою генератору псевдовипадкових послідовностей. Більш показовими будуть функції розподілу значень для даних опробування і результатів моделювання, але і вони не дадуть вам гарантії просторової відповідності між первинними даними і кінцевими результатами. Нам треба дослідити - як у тривимірному просторі співпадають дані опробування і результати моделювання. Наскільки зміщені показники кінцевої блокової моделі родовища або рудного покладу.
Це можна доволі швидко перевірити не витрачаючи сили та час на мудрування із інтерфейсами геоінформаційних систем. Все, що нам треба - це експортовані у формат CSV блокові моделі із обчисленими параметрами вмістів компонентів та дані просторового розташування інтервалів опробування у просторі (також у форматі CSV). До речі - коли на запитання "в якому вигляді Вам надати дані", Ви відповідаєте: "дайте Вашу блочку в форматі CSV" - на Вас починають дивитись як на чаклуна, який щойно зламав сервер прибульців та отримав доступ до потаємніших знань! Для порівняння функцій розподілу ми використаємо базові можливості R, а для дослідження просторової сумісності результатів - пакет spatstat, який не входить до базового набору. Встановлювати пакет spatstat краще за допомогою прямого завантаження з CRAN - цей пакет має доволі багато залежностей, які також не входять у базовий набір R.
Для аналізу ми використаємо результати опробування на компонент "Ікс" та результати інтерполяції вмістів компоненту у блоковій моделі. Файл з первинними даними (результати опробування) - proby.csv, файл блокової моделі - bl_model.csv.
Тож почнемо! У першу чергу перевіримо - чи співпадають функції розподілу - побудуємо графіки кумулятивних функцій розподілу:

>proby<- read.table("proby.csv", header=T, sep=";", dec=",")#завантажуємо файл із даними опробування
>bl_model<- read.table("bl_model.csv", header=T, sep=";", dec=",")#завантажуємо файл із блоковою моделлю
>summary(proby)#дивимось загальну статистику для даних опробування
      NUM               XX             YY              ZZ        
 Min.   :  1.00   Min.   :6837   Min.   :20147   Min.   :-267.77 
 1st Qu.: 37.25   1st Qu.:6846   1st Qu.:20223   1st Qu.:-169.40 
 Median : 73.50   Median :7046   Median :20298   Median :-115.06 
 Mean   : 73.50   Mean   :7023   Mean   :20302   Mean   :-118.00 
 3rd Qu.:109.75   3rd Qu.:7194   3rd Qu.:20379   3rd Qu.: -59.87 
 Max.   :146.00   Max.   :7344   Max.   :20449   Max.   :  -5.28 
      Iks         
 Min.   :0.000001 
 1st Qu.:0.013957 
 Median :0.052824 
 Mean   :0.101881 
 3rd Qu.:0.144562 
 Max.   :0.827947
>summary(bl_model)#дивимось загальну статистику для блокової моделі
      NUM            NUM_BL            XX             YY      
 Min.   :    1   Min.   :    0   Min.   :6695   Min.   :19965 
 1st Qu.: 3524   1st Qu.: 3523   1st Qu.:6815   1st Qu.:20195 
 Median : 7048   Median : 7046   Median :6935   Median :20285 
 Mean   : 7048   Mean   : 7046   Mean   :6959   Mean   :20272 
 3rd Qu.:10571   3rd Qu.:10570   3rd Qu.:7085   3rd Qu.:20365 
 Max.   :14094   Max.   :14093   Max.   :7435   Max.   :20475 
       ZZ             RAZM_X       RAZM_Y       RAZM_Z        Iks          
 Min.   :-395.0   Min.   :10   Min.   :10   Min.   :10   Min.   :0.0001564 
 1st Qu.:-205.0   1st Qu.:10   1st Qu.:10   1st Qu.:10   1st Qu.:0.0182835 
 Median :-125.0   Median :10   Median :10   Median :10   Median :0.0457895 
 Mean   :-137.7   Mean   :10   Mean   :10   Mean   :10   Mean   :0.0914940 
 3rd Qu.: -65.0   3rd Qu.:10   3rd Qu.:10   3rd Qu.:10   3rd Qu.:0.1297130 
 Max.   :  -5.0   Max.   :10   Max.   :10   Max.   :10   Max.   :0.6591007
#нас цікавлять мінімальні та максимальні значення вмістів компоненту Ікс в обох вибірках - нам треба накласти кумулятивні криві розподілу на один графік
>plot(ecdf(proby$Iks), col="red", xlim=c(0,0.85), main="Кумулятивні криві розподілу вмісту компоненту Ікс")
>plot(ecdf(bl_model$Iks), col="blue", add=T)
>legend("bottomright", legend=c("Дані опробування","Блокова модель"),pch=20, col=c("red","blue"), cex=1.2)


 
Кумулятивні криві розподілу вмісту компоненту Ікс для первинних даних опробування та блокової моделі
Як видно на рисунку - обидві вибірки характеризуються схожими функціями розподілу вмістів компоненту. Але для більш точного порівняння краще використати не власний глазомір, а який-небудь статистичний критерій. Спробуємо застосувати критерій Ансарі-Бредлі:

>ansari.test(proby$Iks, bl_model$Iks)

        Ansari-Bradley test

data:  proby$Iks and bl_model$Iks
AB = 482610.5, p-value = 0.1319
alternative hypothesis: true ratio of scales is not equal to 1


Як бачимо - досягнутий рівень значущості не дозволяє нам спростувати нульову гіпотезу, і ми погоджуємось із тезою про подібність функцій розподілу (не забувайте, що правильно звучить не "подібність", а "відсутність відмін"). До речі: критерій Смірнова (функція ks.test) показує досягнутий рівень значущості p-value=0.303, що також не дозволяє нам спростувати нульову гіпотезу.
Тепер перейдемо до аналізу просторової сумісності даних опробування та результатів обчислення якості в блоковій моделі. Для цього ми зробимо із блокової моделі вибірку найближчих до первинних проб блоків, і порівняємо значення у цих пробах та блоках. Зараз деякі "геостатистики" почнуть кидати у мене цеглинами, запевняючи що ці методи інтерполяції - "згладжувальні", і результати повинні відрізнятись від первинних даних. Звісно - вони повинні відрізнятись. Але коли вони відрізняються майже у два рази - є над чим замислитись. Для вибірки найближчих блоків ми використаємо можливості пакету spatstat і невеличкий цикл, який дозволить нам знайти позиції цих блоків у первинній таблиці. Зверніть увагу на те, що ми оперуємо координатною системою із прямокутним розташуванням осей, і всі вісі мають однаковий масштаб. У принципі - ми повинні поміняти місцями вісі X та Y, оскільки в геодезичних системах координат вони міняються. Але на даний момент це для нас не критично.

>install.packages("spatstat")#встановлюємо пакет spatstat
>library(spatstat)#завантажуємо пакет spatstat
>proby.pp3<- pp3(proby$XX, proby$YY, proby$ZZ, box3(c(6800, 7350), c(20100,20500), c(-300,0)))#будуємо тривимірний "бокс" із даними опробування
>bl_model.pp3<- pp3(bl_model$XX, bl_model$YY, bl_model$ZZ, box3(c(6650, 7500), c(19950,20500), c(-400,0)))#будуємо тривимірний "бокс" із даними блокового моделювання
>vidst<- crossdist(proby.pp3, bl_model.pp3)#обчислюємо відстані від кожної проби до кожного блоку


Результатом виконання функції crossdist є матриця, яка складається із 146 рядків (стільки у нас первинних проб, від яких ми вимірювали відстані) та 14094 стовпців (стільки блоків у нашій блоковій моделі). За допомогою функцій min, max та median можна подивитись основні параметри отриманої матриці:

>min(vidst)
[1] 0.6394529
>max(vidst)
[1] 857.6206
>median(vidst)
[1] 254.9157


Для більшої наглядності ми використаємо функцію hist, щоб відобразити графічно розподіл відстаней між блоками моделі та первинними пробами:

>hist(vidst, breaks=100, col="darkorange", main="Гістограма відстаней між первинними\nпробами та центрами мас блоків", xlab="відстані", ylab="частість")
 
Гістограма відстаней між блоками блокової моделі та первинними пробами
За бажанням - можна подивитись розташування первинних проб у просторі за допомогою команди plot(proby.pp3). В принципі - можна відобразити і просторове розташування блоків блокової моделі (точніше - їхніх центроїдів), але через надмірну концентрацію точок Ви зможете побачити лише зовнішні контури блокової моделі.

 
Тривимірне відображення розташування проб по свердловинах
Тепер нам треба знайти найближчий блок для кожної із проб. Спочатку ми приведемо програмний код, а потім пояснимо - що і для чого ми робили. Кінцевим результатом приведеного нижче коду буде таблиця найближчих до первинних проб блоків блокової моделі. За своєю структурою (кількість та назви стовпців) ця таблиця буде подібна до таблиці повного переліку блоків bl_model.

>znach<- numeric(nrow(vidst))
>stovp<- integer(nrow(vidst))
>for (i in 1:nrow(vidst)){#починаємо цикл
+ znach[i]<- vidst[i,1]
+ for (j in 1:ncol(vidst)){#починаємо вкладений цикл
+ if (vidst[i,j]<znach[i]) {znach[i]<- vidst[i,j]; stovp[i]<- j}#заносимо логічну умову для порівняння відстаней від блоків до кожної проби
+ }}#закінчуємо обидва цикли
>vidst_table<- data.frame(znach=znach, stovp=stovp)#формуємо таблицю значень відстаней і номерів блоків
>names(bl_model)#перевіряємо імена стовпців у таблиці блокової моделі
[1] "NUM"    "NUM_BL" "XX"     "YY"     "ZZ"     "RAZM_X" "RAZM_Y" "RAZM_Z"
[9] "Iks"  
>ind.bl<- match(vidst_table$stovp, bl_model$NUM)#створюємо вектор відповідності для порівняння між таблицями
>bl_poruch_pr<- bl_model[ind.bl,]#на основі вектору відповідності робемо вибірку з таблиці bl_model і заносимо її до таблиці bl_poruch_pr
>head(bl_poruch_pr)#перевіряємо результат (дивимось "шапку" таблиці)
        NUM NUM_BL   XX    YY   ZZ RAZM_X RAZM_Y RAZM_Z       Iks
4511   4511   4510 6845 20145 -205     10     10     10 0.0008770
4514   4514   4513 6845 20155 -245     10     10     10 0.2451710
4509   4509   4508 6845 20145 -225     10     10     10 0.2102884
4510   4510   4509 6845 20145 -215     10     10     10 0.0136489
9527   9527   9526 7035 20215 -155     10     10     10 0.0041822
12347 12347  12346 7195 20385  -55     10     10     10 0.4323209


Давайте тепер більш детально розпишемо послідовність наших дій. По-перше: ми створили два тимчасових вектори: znach та stovp. Вони нам знадобляться для введення в дію циклу, який буде перебирати таблицю (матрицю) vidst і вибирати з неї найближчий блок для кожної із первинних проб. Далі ми починаємо цикл, і робимо вкладений цикл з логічною умовою "якщо елемент таблиці відстаней менше за первинний елемент вектору значень, тоді записати нове значення із таблиці відстаней, а в вектор номерів стовпців записати положення цього значення - номер стовпця матриці відстаней". По закінченні цикла ми робимо зведену таблицю vidst_table значень і номерів стовпців (ці номери взяті із матриці відстаней vidst і співпадають із номерами блоків у полі таблиці bl_model$NUM).
Але, ми з Вами отримали дані номерів блоків та значення їхніх відстаней від первинних проб. А нам потрібні показники вмістів хімічних елементів та інші властивості, які містяться в цих блоках. Щоб отримати ці дані ми за допомогою функції match створюємо вектор відповідності ind.bl. У цей вектор будуть занесені номери блоків, властивості яких потрібні нам для подальшої роботи. Далі, на основі цього вектору ми "витягуємо" (з усіма полями) із таблиці bl_model лише ті блоки, які нам потрібні, і заносимо їх до таблиці bl_poruch_pr ("Блоки поруч із пробами"). Нам залишилось лише перевірити - чи перенесли ми дані в таблицю. Для цього ми використовуємо функцію head, яка виводить нам на екран заголовки полів та перші шість записів.
Отже, ми з Вами отримали таблицю, яка містить 146 блоків - найближчих до 146 первинних проб. Тепер ми можемо порівняти статистичні показники просторово суміщених даних, і подивитись - наскільки в реальності не співпадають дані моделювання із первинними значеннями (даними опробування). Ми не будемо наводити тут всі можливі варіанти порівняння даних і побудуємо лише графік кумулятивних функцій розподілу для значень вмісту компонента "Ікс" у первинних і змодельованих даних. Не забудьте перевірити граничні показники для обох таблиць, щоб задати обмеження для побудови красивого графіку:

>plot(ecdf(proby$Iks), col="red", xlim=c(0,0.85), main="Кумулятивні криві розподілу компоненту Ікс\nв пробах і найближчих блоках")
>plot(ecdf(bl_poruch_pr$Iks), col="blue", add=T)
>legend("bottomright", legend=c("Дані опробування", "Найближчі блоки"), fill=c("red", "blue"))


 
Кумулятивні криві розподілу вмісту компоненту Ікс для первинних даних опробування та найближчих до них блоків блокової моделі
Як видно з рисунку, розподіл вмістів у блоках в цілому відповідає первинним даним. Разом із тим, спостерігаються деякі невідповідності: максимальний вміст у найближчому блоці майже в два рази менший, ніж у пробі (кінцеві точки на обох функціях); на графіку значень по блоках спостерігаються "зриви" функції, і функція являє собою набір декількох відособлених ділянок. Подібні "зриви" можуть свідчити про погану (невідповідну, нерівномірну) інтерполяцію, або про ручне виправлення кінцевих даних. Але за значних розмірів блокової моделі ручне виправлення малоймовірне і ми зупиняємось на висновку про недостатню увагу моделювальників до особливостей будови рудного тіла та розподілу в ньому компонентів.

Немає коментарів:

Дописати коментар