Short Course during the EGU General Assembly 2019 | Mon, 08 Apr, 08:30–10:15
Elisabeth Dietze is a Post Doc at AWI Potsdam, working on biomarker based fire histories and robust interpretation of sediment proxies.
Michael Dietze is a Post Doc at GFZ Potsdam, working on the seismic signals emitted by Earth surface processes.
EMMAgeo (10 min)The task (Time 5-10 min):
We will need the output of this discussion in a few moments, so do not lean back too much.
The task (Time 2 min):
EMMAgeo is the only approach to account for parametrisation uncertainties
'EMMAgeo' is one out of more than 10,000 packages available on CRAN.
install.packages("EMMAgeo")
devtools::install_github(repo = "coffeemuggler/EMMAgeo", ref = "0.9.6")
example_X, the manually mixed data setEMMA::GUI())The task (Time 5 min):
install.packages("EMMAgeo"))Install EMMAgeo 0.9.6 from Github (devtools::install_github("coffeemuggler/EMMAgeo"), maybe install package devtools in advance (install.packages("devtools")))
Alternatively: install EMMAgeo 0.9.6 from local source
read.table()),xlsx::read.xlsx()) orR.matlab::readMat())data <- read.table(file = "dataset_gsd.txt", header = TRUE, sep = "\t", dec = ".", stringsAsFactors = FALSE) X <- as.matrix(data[,-c(1, 2)]) s <- as.numeric(colnames(data))[-c(1, 2)] ID <- data[,1] depth <- data[,2]
## read an ASCII file
data <- read.table(file = "~/Desktop/X.txt",
header = TRUE,
sep = "\t",
stringsAsFactors = FALSE)
## read a MS Excel file (xlsx)
data <- xlsx::read.xlsx(file = "~/Desktop/X.xlsx",
sheetIndex = 1,
header = TRUE,
stringsAsFactors = FALSE)
## extract objects of interest (function substr() is used to remove the letter X)
X <- as.matrix(data[,-1])
s <- as.numeric(substr(x = colnames(data)[-1],
start = 2,
stop = 10))
ID <- data$ID
View(X))dim(X), range(X), rowSums(X))The task (Time: about 5 min):
library("EMMAgeo"))data(example_X)).colnames(X)) as a numeric vector.library(EMMAgeo)
## Loading required package: GPArotation
## Loading required package: limSolve
## Loading required package: caTools
## Loading required package: shiny
## Loading required package: matrixStats
data("example_X")
s <- as.numeric(colnames(X))
ID <- 1:nrow(X)
par(mfcol = c(1, 2), mar = c(4, 4, 1, 1))
gsd_col <- colorRampPalette(colors = c("darkblue", "orange", "grey"))
image(x = s, y = ID, z = t(X), log = "x", col = gsd_col(100))
plot(NA, xlim = range(s), ylim = range(X), log = "x", xlab = "Size", ylab = "Vol.-%")
for(i in 1:nrow(X)) {lines(x = s, y = X[i,], col = gsd_col(100)[i])}
EMMA(X, q, l, c, Vqn, classunits, ID, EM.ID, rotation, plot, ...)
X Data set, a numeric matrix with samples organised in rowsq Number of end-members to modell Weight transformation limit quantilec constant sum scaling factorVqn optional user-defined unscaled loadingsrotation factor rotation typeplottoggle plot outputE <- EMMA(X = X, q = 4, l = 0, c = 100, classunits = s, ID = ID, plot = TRUE, log = "x")
X = X Our example data set, 100 samples, manually mixedq = 4 Four target end-members, because we know the data setl = 0 No weight limit transformationc = 100 All classes sum to 100 %classunits = s We provide the real µm grain-size class unitsID = ID We provide the sample IDs, as wellplot = TRUE We want to see the default plot output of EMMAlog = "x" The units are in µm, so the x-axis should be in log scalestr(E)
## List of 18 ## $ loadings: num [1:4, 1:116] 0.001813 0.000891 0.000366 0.00045 0.002269 ... ## ..- attr(*, "dimnames")=List of 2 ## .. ..$ : chr [1:4] "EM1" "EM2" "EM3" "EM4" ## .. ..$ : chr [1:116] "0.04" "0.0439105" "0.0482033" "0.0529158" ... ## $ scores : num [1:100, 1:4] 0.2329 0.0748 0.507 0.2545 0.3121 ... ## ..- attr(*, "dimnames")=List of 2 ## .. ..$ : chr [1:100] "1" "2" "3" "4" ... ## .. ..$ : NULL ## $ Vqn : num [1:4, 1:116] 0.858 0.331 0.179 0.213 0.847 ... ## ..- attr(*, "dimnames")=List of 2 ## .. ..$ : chr [1:4] "EM1" "EM2" "EM3" "EM4" ## .. ..$ : NULL ## $ Vqsn : num [1:4, 1:116] 0.001813 0.000891 0.000366 0.00045 0.002269 ... ## ..- attr(*, "dimnames")=List of 2 ## .. ..$ : chr [1:4] "EM1" "EM2" "EM3" "EM4" ## .. ..$ : chr [1:116] "0.04" "0.0439105" "0.0482033" "0.0529158" ... ## $ Mqs : num [1:100, 1:4] 0.2329 0.0748 0.507 0.2545 0.3121 ... ## ..- attr(*, "dimnames")=List of 2 ## .. ..$ : chr [1:100] "1" "2" "3" "4" ... ## .. ..$ : NULL ## $ Xm : num [1:100, 1:116] 0.000978 0.000494 0.001354 0.000928 0.000984 ... ## ..- attr(*, "dimnames")=List of 2 ## .. ..$ : chr [1:100] "1" "2" "3" "4" ... ## .. ..$ : chr [1:116] "0.04" "0.0439105" "0.0482033" "0.0529158" ... ## $ modes : num [1:4] 14.3 39.8 339.9 493.6 ## $ Mqs.var : num [1:4] 23.5 18.7 30 27.8 ## $ Em : Named num [1:100] 0.0741 0.0506 0.0917 0.0782 0.0893 ... ## ..- attr(*, "names")= chr [1:100] "1" "2" "3" "4" ... ## $ En : Named num [1:100] 0.0741 0.0506 0.0917 0.0782 0.0893 ... ## ..- attr(*, "names")= chr [1:100] "1" "2" "3" "4" ... ## $ RMSEm : num 0.135 ## $ RMSEn : num 0.135 ## $ Rm : Named num [1:100] 0.982 0.998 0.961 0.984 0.977 ... ## ..- attr(*, "names")= chr [1:100] "1" "2" "3" "4" ... ## $ Rn : Named num [1:116] 0.912 0.912 0.923 0.932 0.931 ... ## ..- attr(*, "names")= chr [1:116] "0.04" "0.0439105" "0.0482033" "0.0529158" ... ## $ mRm : num 0.967 ## $ mRn : num 0.887 ## $ mRt : num 0.927 ## $ ol : num 0
loadings (Vqsn) Normalised rescaled end-member loadings.scores (Mqs) Rescaled end-member scores.Xm Modelled data.Vqn Normalised end-member loadings.modes Mode class of end-member loadings.Mqs.var Explained variance of end-membersRm, Rn Row- and col-wise explained variance.Em, En Absolute row- and col-wise model error.ol Number of overlapping end-members.The task (time about 5 minutes):
Try other parameter settings (see help for the function: ?EMMA).
If you are fast, try making new plots out of the numeric output (e.g., cumulative grain-size curves, line plots of scores, ratio plots of scores)
Question: How do you know the model you use is a proper one? How to judge meaningful end-members? Which side effects do you observe?
Or: how many end-members q do we need? And, what about l?
And we need a structured way to robustly model a data set.
l_min, in most cases zerol_max, as high as possible to still allow eigenspace calculationl sequenceq_min, as many as needed to reach R² threshold in FAq_max, first local EMMA R² maximum, fixed R², or fixed qq_min to q_max for each l)l (l_opt)So far, so good? Now let us dive into the details…
l_min will usually be zero, unless there is good reason.l_min <- 0
l_max can be up to 0.5. In reality, rescaling the data too much will violate the eigenspace calculation (eigen()). The function test.l() can be used to test if a given value is still valid. Values close to l_max yield unrealistic EMMA models. Thus, setting l_max to 95 % of the true max or lower prevents this.l_max <- test.l(X = X, l = seq(from = 0,
to = 0.5,
length.out = 20))$l.max
l_max <- 0.6 * l_max
test.l.max() approximates l_max in a loopl_max <- 0.6 * test.l.max(X = X, n = 20) print(l_max)
## [1] 0.237
l will be a sequence of values from l_minto l_max. The longer the sequence, the more models can be run (better estimate, more computation time).l <- seq(from = l_min, to = l_max, length.out = 20)
qland all possible q.q_min <- test.factors(X = X, l = l, r.min = 0.95, plot = TRUE, xlim = c(2, 10), ylim = c(0.9, 1.0))$q.min
print(q_min)
## [1] 2 3 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
q_max. Of course, for each element of l, there is a different q-max.q_maxcan be used, or a given R² value of the model.l = 0): test.parameters performs these tests for all l and q. It can run a loooong time.q_max.If you have time, try the other plot types, apart from "mRt".
See the example on the next slide, and how with increasing l also NA cases emerge.
TP <- test.parameters(X = X, q = 2:20, l = l, colour = rainbow(n = length(l)), plot = "mRt")
q_max <- TP$q.max
l, q_min and q_max at hand, these values can be fused into a parameter matrixq_min must be at least 2q_max cannot be smaller than q_minNA values are allowedq_min <- ifelse(test = q_min < 2, yes = 2, no = q_min) q_max <- ifelse(test = q_max < q_min, yes = NA, no = q_max) P <- cbind(q_min, q_max, l) P <- na.exclude(P)
X and P all possible models, in agreement with the parameter space can be evaulated to inspect the outcomes.test.robustness(). All possible end-member loadings will be plotted.EM.pot <- test.robustness(X = X, P = P, plot = TRUE)
plot(NA, xlim = c(1, length(s)), ylim = range(EM.pot$loadings))
for(i in 1:nrow(EM.pot$loadings)) {lines(EM.pot$loadings[i,], col = adjustcolor(col = 1, alpha.f = 0.1))}
hist(x = EM.pot$modes, breaks = 90)
stem(x = EM.pot$modes)
## ## The decimal point is 1 digit(s) to the right of the | ## ## 6 | 222233334444444444444444444 ## 6 | ## 7 | 2222333333333333333333333333334444 ## 7 | 5555555555555555555555555666 ## 8 | ## 8 | ## 9 | 44 ## 9 | 77777777777777777777777777777888888888888888888888888999999999999999 ## 10 | 00000000000000000000000000000000111111112222222222222222222222222222+4 ## 10 | 5555556 ## 11 | 222
limits <- cbind(c(63, 75, 98, 102),
c(64, 77, 99, 103))
robust.loadings()loadings.robust <- robust.loadings(em = EM.pot, limits = limits, plot = TRUE)
get.l.opt() can be used to identify the model with the best performance.qualitiy = "mRm", "mRn", "mRt", "mEm", "mEn" and "mEt")loadings.robust$Vqn$mean) or median (loadings.robust$Vqn$median) loadings.l_opt <- get.l.opt(X = X, l = l, quality = "mRt", Vqn = loadings.robust$Vqn$mean, plot = TRUE)
robust.scores() does this job in a Monte Carlo environment.mc_n (number om MC rounds) to a low value to increase speed.scores_robust <- robust.scores(loadings = loadings.robust, l = l_opt, mc_n = 20, plot = TRUE)
land q)l values)q values)l_minis zero (otherwise change argument min) and l_max is 95 % of the true maximum (otherwise change argument max), and that 10 values are enough (otherwise change argument n), the function get.l() creates a vector of weight transformation limits:l <- get.l(X = X, max = 0.6, n = 20) print(l)
## [1] 0.00000000 0.01247368 0.02494737 0.03742105 0.04989474 0.06236842 ## [7] 0.07484211 0.08731579 0.09978947 0.11226316 0.12473684 0.13721053 ## [13] 0.14968421 0.16215789 0.17463158 0.18710526 0.19957895 0.21205263 ## [19] 0.22452632 0.23700000 ## attr(,"class") ## [1] "EMMAgeo_l"
l vector, and following the criteria of the extended protocol for q_minand q_max, the function get.q() generates q values for each element of l:q <- get.q(X = X, l = l)
## [1] "1 cases of q_min > q_max removed: 13."
print(q)
## q_min q_max ## 0 2 6 ## 0.0124736842069489 2 6 ## 0.0249473684138978 2 5 ## 0.0374210526208467 3 5 ## 0.0498947368277956 3 5 ## 0.0623684210347445 3 5 ## 0.0748421052416934 3 5 ## 0.0873157894486423 3 5 ## 0.0997894736555912 3 5 ## 0.11226315786254 3 5 ## 0.124736842069489 3 5 ## 0.137210526276438 3 6 ## 0.149684210483387 4 2 ## 0.162157894690336 3 6 ## 0.174631578897285 3 6 ## 0.187105263104233 2 6 ## 0.199578947311182 3 6 ## 0.212052631518131 3 6 ## 0.22452631572508 3 3 ## 0.236999999932029 3 3 ## attr(,"class") ## [1] "EMMAgeo_q"
land q, all models of this parameter space are evaluated and the output is plotted.em.pot <- model.EM(X = X, q = q, l = l, plot = TRUE)
get.limits() that uses a kernel density estimate.limits <- cbind(c(63, 75, 98, 102),
c(64, 77, 99, 103))
em.rob <- robust.EM(em = em.pot, limits = limits, plot = TRUE, mc_n = 20)
## [1] "Parameter l missing! Set to 'mRt' by default"
The course materials are available at
www.micha-dietze.de/pages/r_courses.html
The EMMAgeo website with information, tutorials, news
www.micha-dietze.de/pages/emmageo.html
If you use EMMAgeo, please cite the following article
Dietze, E. & Dietze, M. (in revision). Robust grain-size distribution unmixing with the R package EMMAgeo. E&G Quaternary Science Journal.