forked from fnaghetini/intro-to-geostats
-
Notifications
You must be signed in to change notification settings - Fork 0
/
5-estimacao.jl
2366 lines (1907 loc) · 92.3 KB
/
5-estimacao.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
### A Pluto.jl notebook ###
# v0.17.0
using Markdown
using InteractiveUtils
# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
macro bind(def, element)
quote
local el = $(esc(element))
global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : missing
el
end
end
# ╔═╡ f9fb89e0-36a8-11ec-3fa3-d716ca093060
begin
# carregando pacotes necessários
using GeoStats, Statistics
using CSV, DataFrames, Query
using PlutoUI, Distributions
using Plots, StatsPlots, Random
# configurações de visualização
gr(format=:png)
end;
# ╔═╡ 3e70ffa1-2a50-4dc4-a529-e4361ac6ad5f
html"""
<p style="background-color:lightgrey" xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/"><span property="dct:title">  🎯 <b>Estimação</b></span> por <span property="cc:attributionName">Franco Naghetini</span> é licenciado sob <a href="http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY 4.0<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1"></a></p>
"""
# ╔═╡ 9f8d2a06-275e-4689-8a69-b1f4dec807b3
PlutoUI.TableOfContents(aside=true, title="Sumário",
indent=true, depth=2)
# ╔═╡ 0d2c1d74-f691-4805-9aa2-e9d42da04284
md"""
![ufmg-logo](https://logodownload.org/wp-content/uploads/2015/02/ufmg-logo-2.png)
"""
# ╔═╡ 84ad4d5f-b3c3-4c21-89f2-d15396e83d05
md"""
# 🎯 Estimação
Você com certeza já ouviu falar sobre **modelagem geológica 3D**. Durante esse procedimento, o geólogo utiliza os dados disponíveis (e.g. furos de sondagem, mapa geológico) e faz algumas inferências para gerar um modelo tridimensional da subsuperfície. Após a geração desse modelo (contínuo), ele normalmente é discretizado em pequenos "tijolos" denominados blocos. Por essa razão, o modelo geológico discretizado é chamado de **modelo de blocos**.
Neste módulo, aprenderemos sobre diferentes **estimadores** (i.e. métodos de estimação) que visam atribuir um valor de teor a cada bloco do modelo de blocos. Para realizar essa tarefa, precisamos de amostras (e.g. furos de sondagem, amostras de solo) e do modelo de blocos, onde realizaremos as estimativas. O modelo de blocos, de forma genérica, pode ser chamado de **domínio de estimação** (ou grid de estimação).
Podemos pensar que a estimação consiste na interpolação de amostras com teores conhecidos para atribuir teores (estimados) a regiões que não foram amostradas.
> ⚠️ Neste módulo adotaremos uma convenção para facilitar a compreensão do conteúdo. O processo de atribuir valores de teor a unidades discretizadas será chamado de **estimação**, do inglês *estimation*. Por outro lado, os teores resultantes do processo de estimação serão chamados de **estimativas**, do inglês *estimates*. Ressalta-se que, na indústria, o termo *estimativa* é comumente utilizado para se referir tanto ao processo quanto aos valores estimados.
Este módulo é estruturado de forma a seguir o fluxo de trabalho adotado pelo [GeoStats.jl](https://github.com/JuliaEarth/GeoStats.jl):
- **Etapa 1:** Criação do domínio de estimativas;
- **Etapa 2:** Definição do problema de estimação;
- **Etapa 3:** Definição do estimador;
- **Etapa 4:** Solução do problema de estimação.
Entraremos em detalhe sobre cada uma das etapas durante o módulo.
"""
# ╔═╡ 035ef186-a067-44c0-b9a0-bdac6f4d770b
md"""
>##### 📚 Sobre
>- Você pode exportar este notebook como PDF ou HTML estático. Para isso, clique no ícone 🔺🔴, localizado no canto superior direito da pagina. Entretanto, ambos os formatos não são compatíveis com os recursos interativos do notebook.
>- Caso deseje executar alguma célula do notebook, clique no ícone ▶️, localizado no canto inferior direito da célula.
>- Algumas células encontram-se ocultadas (e.g. células que geram os plots). Você pode clicar no ícone 👁️, localizado no canto superior esquerdo da célula, para ocultá-la ou exibí-la.
>- A explicação das células que geram os plots está fora do escopo deste notebook. Entretanto, a sintaxe é bem intuitiva e pode ser facilmente compreendida!
>- Você pode ainda clicar no ícone `...`, no canto superior direito de uma célula, para excluí-la do notebook.
>- Algumas células deste notebook encontram-se encapsuladas pela expressão `md"..."` (e.g. esta célula). Essas são células de texto chamadas de *markdown*. Caso deseje aprender um pouco mais sobre a linguagem *markdown*, clique [aqui](https://docs.pipz.com/central-de-ajuda/learning-center/guia-basico-de-markdown#open).
>- No Pluto, todos os pacotes devem ser importados/baixados na primeira célula do notebook. Clique no ícone 👁️ para exibir essa célula ou consulte a seção *Pacotes utilizados* deste notebook para saber mais informações sobre os pacotes.
>- Utilize a macro ` @which` para verificar a qual pacote uma determinada função pertence.
>- Você pode utilizar este notebook da forma que quiser, basta referenciar [este link](https://github.com/fnaghetini/intro-to-geostats). Consulte a [licença] (https://creativecommons.org/licenses/by/4.0/?ref=chooser-v1) para saber mais detalhes.
>- Para mais informações acesse o [README](https://github.com/fnaghetini/intro-to-geostats/blob/main/README.md) do projeto 🚀
"""
# ╔═╡ 564423c2-6a3e-4919-a6fc-32f7d1664f86
md"""
## 1. Conceitos básicos
Nesta primeira seção, teremos uma breve introdução a três dos principais *estimadores lineares ponderados* utilizados na *estimação* de recursos minerais:
- Inverso da Potência da Distância;
- Krigagem Simples;
- Krigagem Ordinária.
"""
# ╔═╡ a069cc27-d08e-47b4-9f75-24dab178b333
md"""
### Estimadores lineares ponderados
Os três métodos listados acima compartilham a mesma equação para calcular estimativas $\hat{z}(x_o)$:
```math
\hat{z}(x_o) = \sum_{i=1}^{n} w_i \cdot z(x_i) = w_1 \cdot z(x_1) + w_2 \cdot z(x_2) + \cdots + w_n \cdot z(x_n)
```
em que $\{z(x_1), z(x_2), ..., z(x_n)\}$ são os valores das $n$ amostras que serão utilizadas na estimação da posição $x_0$, enquanto $\{w_1, w_2, ..., w_n\}$ representam os pesos atribuídos a cada $i$-ésima amostra (*Isaaks & Srivastava, 1989*).
> ⚠️ Na Estatística, é muito comum representar estimativas com o símbolo "^".
Os métodos caracterizados por essa equação são denominados **estimadores lineares ponderados** e se diferenciam entre si de acordo com a forma que os pesos $w_i$ são atribuídos a cada amostra.
"""
# ╔═╡ 9b31cfec-400a-4068-84b8-8170b3c8ab58
md"""
### Inverso da Potência da Distância (IPD)
Uma abordagem intuitiva para atribuir pesos é pensar que amostras mais distantes do ponto a ser estimado devem receber pesos menores, enquanto amostras próximas devem receber pesos maiores.
>⚠️ De acordo com a 1ª Lei da Geografia, proposta por Tobler na década de 1970: *"tudo está relacionado a tudo, mas coisas mais próximas são mais parecidas (relacionadas) entre si do que coisas mais distantes"*.
Nesse sentido, no método **Inverso da Potência da Distância (IPD)**, o peso $w_i$ de uma amostra $z(x_i)$ é inversamente proporcional a sua distância Euclidiana $d_i$ até o ponto que está sendo estimado $\hat{z}(x_o)$ (*Isaaks & Srivastava, 1989*). É comum escolhermos uma potência $p$ arbitrária associada à distância:
```math
\hat{z}(x_o) = \frac{\sum_{i=1}^{n}\frac{1}{d_i^p}z(x_i)} {\sum_{i=1}^{n}\frac{1}{d_i^p}}
```
em que $w_i = \frac{1}{d_i^p}$. O denominador da equação acima é uma **condição de fechamento** que garante que a soma dos $n$ pesos sempre totalize em 1.
>⚠️ Na Mineração, é muito comum adotar-se $p=2$. Nesse caso específico, o método pode ser chamado de **Inverso do Quadrado da Distância (IQD)**.
A Figura 01 mostra um gráfico de distância por peso para diferentes potências $p$:
"""
# ╔═╡ 951ca515-39a9-4e95-a53c-6fd7977a4cbb
begin
# geração dos dados
ds = collect(1:100)
ws = [@. 1/(ds^p) for p in 1:5]
# labels de cada gráfico
labels = ["p=$p" for p in 1:5]
# plotagem
plot(ws, label=hcat(labels...), xlabel="Distância", ylabel="Peso", lw=1.5)
end
# ╔═╡ 28acc648-ac4a-4d1c-86ce-5bb329c6a141
md"""
_**Figura 01:** Relação entre distância e peso para diferentes potências $p$._
"""
# ╔═╡ 25ddae7c-a276-417e-92c8-9fc2076db219
md"""
##### Observações
- Com o aumento da potência $p$, mais rapidamente os pesos diminuem em função do aumento da distância entre as amostras e o ponto a ser estimado.
"""
# ╔═╡ 69c94901-8d49-4fcc-97f4-bf857b04e627
md"""
### Krigagem
**Krigagem** é um termo genérico aplicado a uma família de métodos de estimação que buscam *minimizar o erro (ou resíduo) da estimação*, normalmente pela estratégia de Mínimos Quadrados (*Sinclair & Blackwell, 2006*). Alguns exemplos são: Krigagem Simples (KS), Krigagem Ordinária (KO), Krigagem Universal (KU) e Krigagem com Deriva Externa (KDE). Neste módulo, abordaremos apenas os dois primeiros.
>⚠️ Um **resíduo** (ou erro) consiste na diferença entre o valor estimado e o valor real $r = \hat{z}(x) - z(x)$ para um determinado ponto pertencente ao domínio de estimação.
Os métodos de Krigagem estão associados ao acrônimo **B.L.U.E.** (*Best Linear Unbiased Estimator*). Eles são estimadores **lineares**, pois suas estimativas são combinações lineares ponderadas das amostras disponíveis. Além disso, são **não enviesados**, já que a média dos resíduos é idealmente igual a zero. Por fim, esses métodos são **"melhores"**, pois objetivam minimizar a variância dos resíduos $\sigma_r^2$, que pode ser escrita como (*Isaaks & Srivastava, 1989*):
```math
\sigma_r^2 = \frac{1}{n} \sum_{i=1}^{n} [\hat{z}(x_i) - z(x_i)]^2 = E[\hat{z}(x_i) - z(x_i)]^2
```
A minimização de $\sigma_r^2$ é justamente o diferencial dos estimadores da família da Krigagem, já que o método IPD também é linear e não enviesado (*Isaaks & Srivastava, 1989*). A Figura 02 mostra um exemplo de duas distribuições de resíduos hipotéticas...
"""
# ╔═╡ 78866735-d01e-4c9d-abec-3ed54b8ed612
begin
# semente aleatória
Random.seed!(1234)
# N(μ=0, σ²=1)
𝒩₁ = Normal()
# N(μ=0, σ²=3)
𝒩₂ = Normal(0,3)
# geração de Z₁~ N(μ=0, σ²=1)
Z₁ = rand(𝒩₁, 2500)
# geração de Z₂ ~ N(μ=0, σ²=3)
Z₂ = rand(𝒩₂, 2500)
# histogramas
histogram(Z₂, bins=:scott, label="σ² = 3", alpha=0.7)
histogram!(Z₁, bins=:scott, alpha=0.7, label="σ² = 1",
xlabel="Resíduo", ylabel="Freq. Absoluta")
end
# ╔═╡ d5d0ef84-7c79-4d5e-af5c-52090b1dd233
md"""
_**Figura 02:** Distribuições de resíduos hipotéticas._
"""
# ╔═╡ fa6d5e16-ad13-4e68-8ee8-d846db277917
md"""
##### Observações
- Ambas as distribuições de resíduos são *não enviesadas*, já que apresentam média igual a zero;
- A distribuição azul apresenta uma maior dispersão de resíduos $\sigma_r^2$ do que a distribuição laranja;
- O diferencial dos métodos de Krigagem é justamente minimizar essa dispersão dos resíduos $\sigma_r^2$, ou seja, o erro da estimação.
"""
# ╔═╡ 956f6c67-93f1-41bf-b921-e893111bbebe
md"""
#### Krigagem Simples (KS)
Para se utilizar a **Krigagem Simples (KS)**, um estimador da família da Krigagem, deve-se ter conhecimento, à priori, da média real do depósito $\mu$. Esse seria o "maravilhoso caso em que conhecemos a média" (*Chilès & Delfiner, 2012*).
Na SK, ao minimizar a variância da estimação $\sigma_r^2$, obtemos as seguintes equações (*Sinclair & Blackwell, 2006*):
```math
\begin{bmatrix}
\gamma(x_1,x_1) & \gamma(x_1,x_2) & \cdots & \gamma(x_1,x_n) \\
\gamma(x_2,x_1) & \gamma(x_2,x_2) & \cdots & \gamma(x_2,x_n) \\
\vdots & \vdots & \ddots & \vdots \\
\gamma(x_n,x_1) & \gamma(x_n,x_2) & \cdots & \gamma(x_n,x_n) \\
\end{bmatrix}
\begin{bmatrix}
w_1 \\
w_2 \\
\vdots \\
w_n \\
\end{bmatrix}
=
\begin{bmatrix}
\gamma(x_1,x_0) \\
\gamma(x_2,x_0) \\
\vdots \\
\gamma(x_n,x_0) \\
\end{bmatrix}
```
em que $\gamma(x_1, x_j)$ representa o valor do variograma entre os pares das $n$ amostras utilizadas na estimação, $w_i$ representa os pesos que serão atribuídos às amostras e $\gamma(x_i, x_0)$ é o valor do variograma entre uma amostra e o ponto a ser estimado. O passo seguinte é realizar uma simples manipulação algébrica para isolar o vetor de pesos que, por sua vez, é a informação que desejamos obter.
Especificamente na KS, a soma dos pesos $w_i$ não totaliza em 1 e, o peso restante é atribuído ao valor da média do depósito. Chamaremos esse peso atribuído a média de $w_\mu$:
```math
w_\mu = 1 - \sum_{i=1}^{n}w_i
```
>⚠️ A demonstração de como obter o sistema linear acima foge do escopo deste material. Para mais detalhes, consulte *Isaaks & Srivastava (1989)*.
Como raramente temos acesso à média do depósito, a KS não é um método tão utilizado como a Krigagem Simples, que veremos a seguir (*Sinclair & Blackwell, 2006*).
"""
# ╔═╡ eab5920c-fd1f-4e03-a6f3-90e3ce731b6e
md"""
#### Krigagem Ordinária (KO)
Ao contrário da KS, na **Krigagem Ordinária (KO)**, a média do depósito não precisa ser conhecida. Nesse método, a minimização de $\sigma_r^2$ é realizada com uma restrição de que a soma dos pesos $w_i$ deve totalizar em 1 (*Sinclair & Blackwell, 2006*).
Essa restrição é introduzida no processo de minimização a partir da criação de uma variável artificial, o *Parâmetro de Lagrange* $\lambda$. Portanto, uma equação adicional (equivalente a zero) é introduzida no sistema linear da KO (*Sinclair & Blackwell, 2006*):
```math
\begin{bmatrix}
\gamma(x_1,x_1) & \gamma(x_1,x_2) & \cdots & \gamma(x_1,x_n) & 1 \\
\gamma(x_2,x_1) & \gamma(x_2,x_2) & \cdots & \gamma(x_2,x_n) & 1 \\
\vdots & \vdots & \ddots & \vdots & \vdots \\
\gamma(x_n,x_1) & \gamma(x_n,x_2) & \cdots & \gamma(x_n,x_n) & 1 \\
1 & 1 & \cdots & 1 & 0 \\
\end{bmatrix}
\begin{bmatrix}
w_1 \\
w_2 \\
\vdots \\
w_n \\
\lambda \\
\end{bmatrix}
=
\begin{bmatrix}
\gamma(x_1,x_0) \\
\gamma(x_2,x_0) \\
\vdots \\
\gamma(x_n,x_0) \\
1 \\
\end{bmatrix}
```
>⚠️ Note que o sistema linear da KO é muito similar àquele da KS. A única diferença é que adicionamos uma equação extra para garantir a condição de fechamento.
Como a soma dos pesos $w_i$ totaliza em 1, não é necessário atribuir um peso $w_\mu$ à média real e, consequentemente, não precisamos ter conhecimento desse parâmetro. Isso corrobora o fato de a KO ser o estimador mais utilizado na indústria.
"""
# ╔═╡ 5a9f4bbf-202f-4191-b59d-f2bed05347ae
md"""
## 2. Criação do domínio de estimação
Assim como no módulo anterior, também utilizaremos a famosa base de dados [Walker Lake](https://github.com/fnaghetini/intro-to-geostats/blob/main/data/Walker_Lake.csv). Primeiramente, vamos importar e georreferenciar esses dados. Novamente, apenas a variável `Pb` (em %) será considerada...
"""
# ╔═╡ 669d757d-dc19-43e1-b96f-8c1aa31f7579
begin
# variáveis de interesse
VARS = [:X,:Y,:Pb]
# diretório dos dados
DIR = "data/Walker_Lake.csv"
# importação dos dados
walkerlake = CSV.File(DIR, type = Float64) |> DataFrame
# seleção das variáveis de interesse e remoção dos valores faltantes
f1(dados) = select(dados, VARS)
f2(dados) = dropmissing(dados)
wl = walkerlake |> f1 |> f2 |> DataFrame
# georreferenciamento dos dados
geowl = georef(wl, (:X,:Y))
end
# ╔═╡ 207ca8d7-08df-47dd-943b-7f7846684e3b
md"""
Agora, podemos criar o nosso **domínio de estimação**, ou seja, um grid 2D onde calcularemos as estimativas. Para definirmos esse domínio, precisamos informar três parâmetros à função `CartesianGrid`:
- Coordenada do ponto de origem do domínio (vértice inferior esquerdo);
- Coordenada do ponto de término do domínio (vértice superior direito);
- Número de células em cada direção (i.e. X e Y).
Definiremos a "caixa delimitadora" do grid a partir da criação de um retângulo aderente à malha amostral, utilizando a função `boundingbox`. Dessa forma, podemos encontrar as coordenadas de origem e de término do domínio, obtendo as coordenadas mínima e máxima do retângulo, respectivamente.
Ao invés de informarmos o número de células em cada direção, é mais conveniente informarmos as dimensões que cada uma das células deve ter, ou seja, o *tamanho da célula*. Para isso, basta fazermos algumas manipulações, como veremos a seguir.
>⚠️ Aqui o termo *célula* foi adotado simplesmente por se tratar de um problema 2D. Em contextos 3D, o termo *bloco* é mais comum, como veremos no próximo módulo.
O tamanho da célula (ou bloco) é um parâmetro crucial, principalmente quando o objetivo é realizar uma *Krigagem de blocos*. Como neste módulo realizaremos uma *Krigagem de pontos*, ou seja, estimaremos o centroide de cada célula, não iremos discutir sobre esse parâmetro com tanto rigor. Definiremos o tamanho das células como ½ do espaçamento médio entre amostras vizinhas que, no nosso caso, é de `10 m x 10 m`.
>⚠️ Na estimação 3D de recursos, uma [heurística](https://en.wikipedia.org/wiki/Heuristic) comumente adotada é definir o tamanho do bloco como ¼ a ½ do espaçamento médio entre amostras vizinhas (*Abzalov, 2016*). Caso queira investigar as diferenças entre Krigagem de pontos e Krigagem de blocos, consulte *Isaaks & Srivastava (1989)*.
"""
# ╔═╡ b14c6b92-81cc-482f-9746-d9a011cff5cd
begin
# caixa delimitadora das amostras
bbox = boundingbox(geowl)
# lados da caixa delimitadora
extent = maximum(bbox) - minimum(bbox)
# Tamanho dos blocos em cada direção
blocksizes = (10., 10.)
# Número de blocos em cada direção
nblocks = ceil.(Int, extent ./ blocksizes)
# Modelo de blocos para realização de estimativas
grid = CartesianGrid(minimum(bbox), maximum(bbox), dims = Tuple(nblocks))
end
# ╔═╡ 9055d652-1c6c-4d73-9302-d58a35ffb975
md"""
A Figura 03 ilustra a distribuição espacial das amostras de Pb (%) sobre o grid de estimação definido acima. O nosso objetivo, neste módulo, é estimar valores de `Pb` para cada centroide das células.
"""
# ╔═╡ 37462572-3c3d-46e1-8e2d-266e86470b6a
begin
# plotagem do domínio de estimação
plot(grid, lw=0.5, alpha=0.5, grid=false)
# plotagem das amostras
plot!(geowl, marker=(:jet,:circle,3), markerstrokewidth=0.3,
title="Pb (%)", xlims=(0,280), ylims=(0, 300), size=(500,500))
end
# ╔═╡ 4469f1a2-6054-4ba0-b402-03892d3a90e4
md"""
_**Figura 03:** Amostras de Pb (%) plotadas sobre o domínio de estimação._
"""
# ╔═╡ 2531eee8-72c5-4056-879c-b1b65273d51a
md"""
## 3. Definição do problema de estimação
O passo seguinte é definir o **problema de estimação**. Para isso, basta informarmos três parâmetros à função `EstimationProblem`:
- Amostras georreferenciadas;
- Domínio de estimação;
- Variável que será estimado.
No nosso caso, conforme mencionado anteriormente, estamos interessados em estimar os centroides das células e, para isso, utilizaremos a função `centroid`.
> ⚠️ *Centroide* é um termo genérico para se referir ao ponto central de uma célula.
"""
# ╔═╡ 36033c09-267c-48df-b6cd-ce2ee2a5eac6
begin
# centroides das células
centroides = Collection(centroid.(grid))
# definição do problema de estimação
problema = EstimationProblem(geowl, centroides, :Pb)
end
# ╔═╡ 3a034b2e-97a2-4a4f-bc60-c6634082254a
md"""
##### Observações
- Note que a saída da célula acima fornece um resumo do nosso problema de estimação:
- `data`: amostras (469 amostras);
- `domain`: domínio de estimação (725 centroides de células);
- `variables`: variável a ser estimada (Pb).
"""
# ╔═╡ 22b5fc9a-9d08-4e36-a500-329e5036081f
function sph2cart(azi)
θ = deg2rad(azi)
sin(θ), cos(θ)
end;
# ╔═╡ 8aaca25b-8ebc-418c-ad48-344a31ba8ed9
md"""
## 4. Definição do estimador
Além de escolhermos qual estimador utilizaremos e obtermos o modelo de variograma (apenas no caso da Krigagem), devemos definir os chamados **parâmetros de vizinhança** ou, simplesmente, *vizinhança*. A vizinhança restringe o número de amostras que serão utilizadas na estimação de um ponto.
Segundo *Chilès & Delfiner (2012)*, a teoria sempre foi construída considerando todas as $n$ amostras disponíveis para calcular cada uma das estimativas. Entretanto, na prática, $n$ pode ser suficientemente grande a ponto do cálculo das estimativas não ser computacionalmente viável. Nesse sentido, uma prática comum é definir um **número mínimo e máximo de amostras** que serão utilizadas para estimar um determinado ponto. Essas informações são exemplos de parâmetros de vizinhança e são representados pelos argumentos `minneighbors` e `maxneighbors`, respectivamente.
Outro parâmetro importante é a **área de busca**, que, normalmente, é representada por uma elipse. Durante a estimação, o centroide da elipse coincide com a posição do ponto a ser estimado. Dessa forma, apenas as amostras que se situarem no interior da área de busca poderão ser utilizadas na estimativa. A elipse (ou elipsoide) de busca é representado pelo parâmetro `neighborhood`.
> ⚠️ As dimensões de uma elipse são definidas por dois eixos principais ortogonais entre si, enquanto sua orientação é definida por uma rotação em relação ao Norte (i.e. azimute). É comum utilizar a elipse de anisotropia (obtida durante a variografia) como elipse de busca, uma vez que ela nos indica até qual distância duas amostras apresentam interdependência espacial.
"""
# ╔═╡ 07175b65-bf21-49c4-9bfa-be5cf000f2ba
begin
# variância amostral (definindo o patamar)
σ² = var(geowl[:Pb])
# elipsoide de anisotropia
elp = Ellipsoid([100.0,35.0],[0], convention = GSLIB)
# modelo de variograma
γ = SphericalVariogram(nugget = 3.0,
sill = Float64(σ²),
distance = metric(elp))
end;
# ╔═╡ 045cdf16-d264-4b5d-990b-c1bd2acb5613
md"""
Considerere uma estimação em que os números mínimo e máximo de amostras são iguais a 5 e 2, respectivamente. A elipse de busca apresenta uma rotação de 45°, ou seja, seu maior eixo está alinhado ao azimute 045°. A Figura 04 mostra três situações distintas que podem ocorrer durante a estimação do centroide de um bloco. As amostras em vermelho são externas à área de busca e não podem ser utilizadas na estimação, enquanto as amostras verdes, por se situarem dentro da elipse de busca, podem.
- No **cenário A**, como existem 4 amostras no interior da elipse e o máximo permitido é de 5 amostras, todas elas serão utilizadas na estimação do centroide;
- No **cenário B**, as 2 amostras internas à área de busca serão utilizadas na estimação;
- No **cenário C**, como apenas 1 amostra está inserida dentro da elipse de busca e o mínimo de amostras é igual a 2, o centroide do bloco *não* será estimado.
![Figura_04](https://i.postimg.cc/HLgMG7Sr/elipses.jpg)
_**Figura 04:** Estimação do centroide de um bloco. (A) As quatro amostras internas à elipse de busca são utilizadas na estimação. (B) As duas amostras internas à elipse de busca são utilizadas na estimação. (C) Como não há amostras suficientes, o centroide não é estimado. Figura elaborada pelo autor._
"""
# ╔═╡ 79c812cf-849a-4eea-93d2-b08a3844d5a7
md"""
No nosso exemplo, iremos definir três estimadores distintos: IQD, KS e KO. Os números máximo e mínimo de amostras serão 4 e 8, respectivamente.
No caso dos estimadores SK e KO, utilizaremos o modelo de variograma `γ` e uma elipse de busca `elp` igual à elipse de anisotropia. A média , que deve ser informada no caso da KS, será definida como o valor da média desagrupada de Pb `μₚ`.
> ⚠️ O modelo de variograma `γ` utilizado apresenta o eixo primário alinhado N-S, com um alcance de 100 m e um eixo segundário alinhado E-W, com um alcance de 35 m. O efeito pepita considerado foi de 3.0, ou seja, cerca de 30% do valor do patamar.
"""
# ╔═╡ b2cb5618-72ba-43a3-9b04-cb2a8821bfa9
begin
# média desclusterizada
μₚ = mean(geowl, :Pb, 25.)
# IQD
IQD = IDW(:Pb => (power=2, neighbors=8))
# KS
KS = Kriging(
:Pb => (variogram=γ, mean=μₚ, neighborhood=elp,
minneighbors=4, maxneighbors=8)
)
# KO
KO = Kriging(
:Pb => (variogram=γ, neighborhood=elp,
minneighbors=4, maxneighbors=8)
)
end;
# ╔═╡ 14ba26ab-db0d-4993-9b98-56309ff23389
md"""
## 5. Solução do problema de estimação
Para gerar as de estimativas de Pb (%), resolvemos o problema definido com os três estimadores. Para isso, devemos passar o problema de estimação e o estimador como parâmetros da função `solve`. Clique na caixa abaixo para executar as estimativas...
Executar estimativas: $(@bind run CheckBox())
"""
# ╔═╡ d5977fdd-c9bc-4589-ae0e-f6cac6973fbb
if run
sol_iqd = solve(problema, IQD)
end
# ╔═╡ e570281a-39e3-438f-9c4a-395f321f12d4
if run
sol_ks = solve(problema, KS)
end
# ╔═╡ 4af2bbf9-fc03-49d0-a19f-f34356c897f7
if run
sol_ko = solve(problema, KO)
end
# ╔═╡ 73b54c21-7b69-429b-a088-fba3d0c09459
if run
md"""
Agora que os teores de Pb foram estimados, clique na caixa abaixo para visualizar o resultado (Figura 05). Em seguida, utilize a lista suspensa abaixo para selecionar a solução que deseja visualizar...
Visualizar estimativas: $(@bind viz CheckBox())
"""
end
# ╔═╡ 5f90093b-4b1e-4e0d-b84c-4232bd3c1b1a
if run && viz
md"""
Solução: $(@bind solucao Select(["IQD", "KS", "KO"], default="KO"))
"""
end
# ╔═╡ a49e5f8d-09cf-4baf-b7b4-d43858df8089
if run && viz
if solucao == "IQD"
sol = sol_iqd
elseif solucao == "KS"
sol = sol_ks
elseif solucao == "KO"
sol = sol_ko
end
end;
# ╔═╡ 60db4fd5-f06c-4821-a7ed-2f63033653ff
if run && viz
ẑ = sol |> @map({Pb = _.Pb, geometry = _.geometry}) |> GeoData
end;
# ╔═╡ 2e9b95c5-a687-4881-b69e-6567ade520cb
begin
if run && viz
# plotagem das estimativas
plot(ẑ, color=:jet, xlabel="X", ylabel="Y",
xlims=(0,280), ylims=(0, 300),clims = (0,12),
marker=(:square,10), markerstrokewidth=0.2,
title="Pb (%)", size=(500,500))
# plotagem de amostras
plot!(geowl, color=:jet, marker=(:circle,3),
markerstrokecolor=:black, markerstrokewidth=0.5,
title="Pb (%)")
end
end
# ╔═╡ 981efb6c-b1ea-4577-9c40-f3f374a23ba1
if run && viz
md"""
_**Figura 05:** Visualização das estimativas de Pb por $solucao._
"""
end
# ╔═╡ 4ce1c65d-701c-4615-90aa-9f6469e47211
if run && viz
md"""
##### Observações
- Visualmente, as estimativas geradas por KO são muito similares àquelas geradas por KS, mas distintas daquelas produzidas por IQD;
- As estimativas geradas por Krigagem são muito mais contínuas na direção N-S do que na direção E-W. Esse resultado reflete o modelo de variograma informado e é coerente com a distribuição espacial dos teores de Pb (%) que, por sua vez, são também mais contínuos na direção N-S;
- Como discutido no módulo anterior, essa base de dados foi gerada a partir do modelo digital de elevação da região de Walker Lake, nos EUA. Nessa região, há uma serra orientada na direção N-S, o que valida a nossa hipótese de que os dados são mais contínuos ao longo dessa direção;
- Como não é possível informar um modelo de variograma na estimação por IQD, esse estimador não apresentou um desempenho tão bom ao reproduzir a maior continuidade do fenômeno (i.e. mineralização de Pb) na direção N-S;
- Esse exemplo enfatiza a importância do modelo de variograma na estimação. É justamente esse parâmetro que nos permite inserir o conhecimento geológico no cálculo das estimativas!
"""
end
# ╔═╡ a2e173e6-fe66-44e6-b371-3ae194d7b0f9
md"""
## 6. Validação das estimativas
Uma etapa tão importante quanto a própria estimação é a **validação das estimativas** resultantes.
Existem diferentes abordagens de validação das estimativas, sendo a principal delas a **inspeção visual**, já realizada na seção anterior. Esse procedimento permite avaliar se as estimativas geradas fazem sentido geológico, ou seja, se elas são coerentes com as direções principais do(s) fenômeno(s) que controla(m) a mineralização (e.g. zonas de cisalhamento, estratos mineralizados). Além disso, durante essa inspeção, devemos verificar se "ilhas de altos teores" indesejadas foram geradas. Essa situação é muito comum em depósitos erráticos (e.g. Au), em função da presença de poucos valores extremamente altos no depósito que podem resultar em estimativas superotimistas.
Uma outra inspeção que deve ser realizada é a **validação global das estimativas**. Para isso, devemos comparar as estatísticas desagrupadas das amostras com as estatísticas associadas às estimativas obtidas. Segundo *Sinclair & Blackwell (2006)*, os métodos de Krigagem levam em consideração a redundância de informação ao atribuir pesos às amostras. Em outras palavras, amostras muito próximas entre si são consideradas redundantes e recebem pesos menores. Portanto, como a Krigagem realiza um desagrupamento intrínseco, é mais conveniente comparar as estatísticas das estimativas resultantes com as estatísticas desagrupadas.
A seguir compararemos quatro sumários estatísticos da variável Pb (%):
- Teores amostrais desagrupados;
- Teores estimados por IQD;
- Teores estimados por KS;
- Teores estimados por KO.
"""
# ╔═╡ e49569b3-0231-4b8e-98d9-21c68c4b1160
if run
# tamanho da janela de desagrupamento
s = 25.0
# sumário estatístico de Pb desagrupado
sum_desag = DataFrame(teor = "Pb (desagrupado)",
X̄ = mean(geowl, :Pb, s),
S² = var(geowl, :Pb, s),
q10 = quantile(geowl, :Pb, 0.1, s),
md = quantile(geowl, :Pb, 0.5, s),
q90 = quantile(geowl, :Pb, 0.9, s))
end;
# ╔═╡ 260d5fa1-b2d9-4e9d-9154-c07f2959bce5
md"""
> ⚠️ Para visualizar os sumários estatísticos, a caixa *Executar estimativas* deve estar marcada.
"""
# ╔═╡ 6b4e35a1-4f1a-4745-9370-f982762af210
function sumario_est(est, id::String)
q10 = quantile(est[:Pb], 0.1)
q90 = quantile(est[:Pb], 0.9)
df = DataFrame(teor = id,
X̄ = mean(est[:Pb]),
S² = var(est[:Pb]),
q10 = q10,
md = median(est[:Pb]),
q90 = q90)
return df
end;
# ╔═╡ b657f40a-b586-4011-ad48-aa18b0a46dc3
if run
[sum_desag
sumario_est(sol_iqd, "Pb (IQD)")
sumario_est(sol_ks, "Pb (KS)")
sumario_est(sol_ko, "Pb (KO)")]
end
# ╔═╡ b8589ac8-7305-48c1-8dff-880a7c659059
if run
md"""
##### Observações
- Vamos focar nas estatísticas `X̅` e `S²`, que representam média e variância, respectivamente;
- Os três métodos produziram estimativas cujas médias são próximas ao valor da média desagrupada;
- Os três métodos produziram estimativas suavizadas (i.e. com menores dispersões), fato evidenciado pelos valores de variância que, por sua vez, são sempre inferiores à variância desagrupada. A KS foi o estimador que gerou estimativas mais suavizadas;
- Veja como a inspeção visual é uma abordagem de validação importante. Se avaliássemos apenas os sumários estatísticos, provavelmente, chegaríamos à conclusão que o IQD era o método mais adequado, quando, na verdade, suas estimativas não representam, de forma fiel, a direção preferencial N-S da mineralização;
- A seguir, discutiremos outra abordagem de validação para avaliar (qualitativamente) o grau de suavização das estimativas obtidas.
"""
end
# ╔═╡ 466c7891-f632-4c02-990a-b5a99c1c162a
md"""
Um outro ponto que merece a nossa atenção é o **grau de suavização** das estimativas produzidas. Para isso, utilizaremos um gráfico que já conhecemos, o Q-Q Plot.
O Q-Q plot entre os teores amostrais e os teores estimados pode ser utilizado para realizar uma comparação entre ambas as distribuições. Podemos analisar visualmente o grau de suavização dos diferentes estimadores a partir desse gráfico bivariado.
A Figura 06 mostra os Q-Q plots entre os teores amostrais de Pb e os teores estimados de Pb pelos três métodos. Quanto mais distantes forem os pontos plotados da função identidade (X=Y), mais suaves são as estimativas em relação a distribuicão amostral.
> ⚠️ Para visualizar os Q-Q plots, a caixa *Executar estimativas* deve estar marcada.
"""
# ╔═╡ 03d1da66-8202-4415-a44d-8c204e740960
if run
qq_iqd = qqplot(
geowl[:Pb], sol_iqd[:Pb],
legend=:false, line=:red,
marker=(:red, :circle, 3),
xlabel="Pb amostral (%)",
ylabel="Pb estimado (%)",
title="IQD"
)
qq_ks = qqplot(
geowl[:Pb], sol_ks[:Pb],
marker=(:blue, :circle, 3),
line=:blue, legend=:false,
xlabel="Pb amostral (%)",
title="KS"
)
qq_ko = qqplot(
geowl[:Pb], sol_ko[:Pb],
line=:green, legend=:false,
marker=(:green, :circle, 3),
xlabel="Pb amostral (%)",
title="KO"
)
plot(qq_iqd, qq_ks, qq_ko, layout=(1,3), size=(700,500))
end
# ╔═╡ 5b07d44b-af44-425b-9e3e-9a5f643e840d
if run
md"""
_**Figura 06:** Q-Q plots entre os teores amostrais e estimados de Pb (%)._
"""
end
# ╔═╡ 817bf734-d8a0-43cd-9553-a7980152afe5
if run
md"""
##### Observações
- Os três métodos geraram estimativas suavizadas. Note que, pela rotação dos pontos em relação à reta X=Y, os teores de Pb estimados apresentam sempre dispersões inferiores em relação à dispersão dos teores de Pb amostrais. Esse fato é ligeiramente mais evidente no caso da KS;
- Em geral, há uma superestimação dos teores mais baixos e uma subestimação dos teores mais altos;
- Os estimadores da família da Krigagem tendem a gerar estimativas que não honram a real variabilidade do depósito (i.e. mais suavizadas). Uma alternativa seria a utilização de técnicas de **Simulação Geoestatística**. Para ter uma breve introdução a esse tópico, confira este [notebook](https://github.com/juliohm/CBMina2021/blob/main/notebook2.jl) e esta [videoaula](https://www.youtube.com/watch?v=3cLqK3lR56Y&list=PLG19vXLQHvSB-D4XKYieEku9GQMQyAzjJ) do Prof. Michael Pyrcz.
"""
end
# ╔═╡ b1b823ac-f9cf-4e5b-a622-4274f3785567
md"""
## Referências
*Abzalov, M. [Applied mining geology](https://www.google.com.br/books/edition/Applied_Mining_Geology/Oy3RDAAAQBAJ?hl=pt-BR&gbpv=0). Switzerland: Springer International Publishing, 2016*
*Chilès, J. P.; Delfiner, P. [Geostatistics: modeling spatial uncertainty](https://www.google.com.br/books/edition/Geostatistics/CUC55ZYqe84C?hl=pt-BR&gbpv=0). New Jersey: John Wiley & Sons, 2012.*
*Isaaks, E. H.; Srivastava, M. R. [Applied geostatistics](https://www.google.com.br/books/edition/Applied_Geostatistics/gUXQzQEACAAJ?hl=pt-BR). New York: Oxford University Press, 1989.*
*Sinclair, A. J.; Blackwell, G. H. [Applied mineral inventory estimation](https://www.google.com.br/books/edition/Applied_Mineral_Inventory_Estimation/oo7rCrFQJksC?hl=pt-BR&gbpv=0). New York: Cambridge University Press, 2006.*
"""
# ╔═╡ 9cd2e572-23fc-4f7a-9b91-a5d3d13a9b48
md"""
## Recursos adicionais
Abaixo, são listados alguns recursos complementares a este notebook:
> [Videoaula Krigagem - LPM/UFRGS](https://www.youtube.com/watch?v=c8GKKsbAmxU)
> [Videoaula Krigagem - University of Texas](https://www.youtube.com/watch?v=CVkmuwF8cJ8&list=PLG19vXLQHvSB-D4XKYieEku9GQMQyAzjJ)
Além dos dois recursos mencionados acima, sugere-se a leitura do Capítulo 10 do livro de *Sinclair & Blackwell (2006)* que, por sua vez, aborda uma série de discussões práticas sobre a Krigagem no contexto da estimação de recursos minerais.
"""
# ╔═╡ c8ced4cd-a74f-48bc-8cca-fb3971930390
md"""
## Pacotes utilizados
Os seguintes pacotes foram utilizados neste notebook:
| Pacote | Descrição |
|:--------------------------------------------------------:|:-----------------------:|
|[GeoStats](https://github.com/JuliaEarth/GeoStats.jl) | Rotinas geoestatísticas |
|[CSV](https://github.com/JuliaData/CSV.jl) | Arquivos CSV |
|[DataFrames](https://github.com/JuliaData/DataFrames.jl) | Manipulação de tabelas |
|[Query](https://github.com/queryverse/Query.jl) | Realização de consultas |
|[Statistics](https://docs.julialang.org/en/v1/) | Cálculo de estatísticas |
|[PlutoUI](https://github.com/fonsp/PlutoUI.jl) | Widgets interativos |
|[Distributions](https://github.com/JuliaStats/Distributions.jl) | Distribuições de probabilidade |
|[Plots](https://github.com/JuliaPlots/Plots.jl) | Visualização dos dados |
|[StatsPlots](https://github.com/JuliaPlots/StatsPlots.jl) | Visualização dos dados |
|[Random](https://docs.julialang.org/en/v1/) | Números aleatórios |
"""
# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
GeoStats = "dcc97b0b-8ce5-5539-9008-bb190f959ef6"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
Query = "1a8c2f83-1ff3-5112-b086-8aa67b057ba1"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd"
[compat]
CSV = "~0.9.9"
DataFrames = "~1.2.2"
Distributions = "~0.25.23"
GeoStats = "~0.27.0"
Plots = "~1.23.1"
PlutoUI = "~0.7.16"
Query = "~1.0.0"
StatsPlots = "~0.14.28"
"""
# ╔═╡ 00000000-0000-0000-0000-000000000002
PLUTO_MANIFEST_TOML_CONTENTS = """
# This file is machine-generated - editing it directly is not advised
[[AbstractFFTs]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "485ee0867925449198280d4af84bdb46a2a404d0"
uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c"
version = "1.0.1"
[[Adapt]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "84918055d15b3114ede17ac6a7182f68870c16f7"
uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
version = "3.3.1"
[[ArgCheck]]
git-tree-sha1 = "dedbbb2ddb876f899585c4ec4433265e3017215a"
uuid = "dce04be8-c92d-5529-be00-80e4d2c0e197"
version = "2.1.0"
[[ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
[[Arpack]]
deps = ["Arpack_jll", "Libdl", "LinearAlgebra"]
git-tree-sha1 = "2ff92b71ba1747c5fdd541f8fc87736d82f40ec9"
uuid = "7d9fca2a-8960-54d3-9f78-7d1dccf2cb97"
version = "0.4.0"
[[Arpack_jll]]
deps = ["Libdl", "OpenBLAS_jll", "Pkg"]
git-tree-sha1 = "e214a9b9bd1b4e1b4f15b22c0994862b66af7ff7"
uuid = "68821587-b530-5797-8361-c406ea357684"
version = "3.5.0+3"
[[ArrayInterface]]
deps = ["Compat", "IfElse", "LinearAlgebra", "Requires", "SparseArrays", "Static"]
git-tree-sha1 = "a8101545d6b15ff1ebc927e877e28b0ab4bc4f16"
uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
version = "3.1.36"
[[Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
[[AverageShiftedHistograms]]
deps = ["LinearAlgebra", "RecipesBase", "Statistics", "StatsBase", "UnicodePlots"]
git-tree-sha1 = "8bdad2055f64dd71a25826d752e0222726f25f20"
uuid = "77b51b56-6f8f-5c3a-9cb4-d71f9594ea6e"
version = "0.8.7"
[[AxisAlgorithms]]
deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"]
git-tree-sha1 = "66771c8d21c8ff5e3a93379480a2307ac36863f7"
uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950"
version = "1.0.1"
[[AxisArrays]]
deps = ["Dates", "IntervalSets", "IterTools", "RangeArrays"]
git-tree-sha1 = "d127d5e4d86c7680b20c35d40b503c74b9a39b5e"
uuid = "39de3d68-74b9-583c-8d2d-e117c070f3a9"
version = "0.4.4"
[[BangBang]]
deps = ["Compat", "ConstructionBase", "Future", "InitialValues", "LinearAlgebra", "Requires", "Setfield", "Tables", "ZygoteRules"]
git-tree-sha1 = "0ad226aa72d8671f20d0316e03028f0ba1624307"
uuid = "198e06fe-97b7-11e9-32a5-e1d131e6ad66"
version = "0.3.32"
[[Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
[[Baselet]]
git-tree-sha1 = "aebf55e6d7795e02ca500a689d326ac979aaf89e"
uuid = "9718e550-a3fa-408a-8086-8db961cd8217"
version = "0.1.1"
[[Bzip2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2"
uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0"
version = "1.0.8+0"
[[CSV]]
deps = ["CodecZlib", "Dates", "FilePathsBase", "InlineStrings", "Mmap", "Parsers", "PooledArrays", "SentinelArrays", "Tables", "Unicode", "WeakRefStrings"]
git-tree-sha1 = "c0a735698d1a0a388c5c7ae9c7fb3da72fd5424e"
uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
version = "0.9.9"
[[Cairo_jll]]
deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "f2202b55d816427cd385a9a4f3ffb226bee80f99"
uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a"
version = "1.16.1+0"
[[CategoricalArrays]]
deps = ["DataAPI", "Future", "Missings", "Printf", "Requires", "Statistics", "Unicode"]
git-tree-sha1 = "fbc5c413a005abdeeb50ad0e54d85d000a1ca667"
uuid = "324d7699-5711-5eae-9e2f-1d82baa6b597"
version = "0.10.1"
[[ChainRulesCore]]
deps = ["Compat", "LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "3533f5a691e60601fe60c90d8bc47a27aa2907ec"
uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
version = "1.11.0"
[[CircularArrays]]
deps = ["OffsetArrays"]
git-tree-sha1 = "0598a9ea22c65bfde7f07f21485ebf60deee3302"
uuid = "7a955b69-7140-5f4e-a0ed-f168c5e2e749"
version = "1.3.0"
[[Clustering]]
deps = ["Distances", "LinearAlgebra", "NearestNeighbors", "Printf", "SparseArrays", "Statistics", "StatsBase"]
git-tree-sha1 = "75479b7df4167267d75294d14b58244695beb2ac"
uuid = "aaaa29a8-35af-508c-8bc3-b662a17a0fe5"
version = "0.14.2"
[[CoDa]]
deps = ["AxisArrays", "Distances", "Distributions", "FillArrays", "LinearAlgebra", "Printf", "Random", "ScientificTypes", "StaticArrays", "Statistics", "StatsBase", "TableOperations", "Tables", "UnicodePlots"]
git-tree-sha1 = "110c70f633e0358ab5f71b54684d71a7e8fc3831"
uuid = "5900dafe-f573-5c72-b367-76665857777b"
version = "0.6.6"
[[CodecZlib]]
deps = ["TranscodingStreams", "Zlib_jll"]
git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da"
uuid = "944b1d66-785c-5afd-91f1-9de20f533193"
version = "0.7.0"
[[ColorSchemes]]
deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random"]
git-tree-sha1 = "a851fec56cb73cfdf43762999ec72eff5b86882a"
uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
version = "3.15.0"
[[ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.11.0"
[[Colors]]
deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40"
uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
version = "0.12.8"
[[Combinatorics]]
git-tree-sha1 = "08c8b6831dc00bfea825826be0bc8336fc369860"
uuid = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
version = "1.0.2"
[[CommonSubexpressions]]
deps = ["MacroTools", "Test"]
git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7"
uuid = "bbf7d656-a473-5ed7-a52c-81e309532950"
version = "0.3.0"
[[Compat]]
deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"]
git-tree-sha1 = "31d0151f5716b655421d9d75b7fa74cc4e744df2"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.39.0"
[[CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"
[[CompositionsBase]]
git-tree-sha1 = "455419f7e328a1a2493cabc6428d79e951349769"
uuid = "a33af91c-f02d-484b-be07-31d278c5ca2b"
version = "0.1.1"
[[ConstructionBase]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "f74e9d5388b8620b4cee35d4c5a618dd4dc547f4"
uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
version = "1.3.0"
[[Contour]]
deps = ["StaticArrays"]
git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7"
uuid = "d38c429a-6771-53c6-b99e-75d170b6e991"
version = "0.5.7"
[[CpuId]]
deps = ["Markdown"]
git-tree-sha1 = "32d125af0fb8ec3f8935896122c5e345709909e5"
uuid = "adafc99b-e345-5852-983c-f28acb93d879"
version = "0.3.0"
[[Crayons]]
git-tree-sha1 = "3f71217b538d7aaee0b69ab47d9b7724ca8afa0d"
uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f"
version = "4.0.4"
[[DataAPI]]
git-tree-sha1 = "cc70b17275652eb47bc9e5f81635981f13cea5c8"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
version = "1.9.0"
[[DataFrames]]
deps = ["Compat", "DataAPI", "Future", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrettyTables", "Printf", "REPL", "Reexport", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"]
git-tree-sha1 = "d785f42445b63fc86caa08bb9a9351008be9b765"
uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
version = "1.2.2"
[[DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
git-tree-sha1 = "7d9d316f04214f7efdbb6398d545446e246eff02"
uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
version = "0.18.10"
[[DataValueInterfaces]]
git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6"
uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464"
version = "1.0.0"