Hi Roger and Simon,

Thanks for the replies. Simon's suggestion of an isolated or missing
neighbourhood doesn't hold either.

I've attached the code below - its my attempt to solve the FELSPLINE
sausage using mrf rather than a soap smoother. Its a bit convoluted, but
should run ok. I thought this would be a good starting example to get a
GMRF running, but then hit the problem mentioned. My attempts to track the
bug suggest that there is something wierd in the knots argument that is
being supplied to smooth.construct.mrf.smooth.spec() - but haven't come so
much further than that.

Code follows.

Mark

#GMRF Example
#Solves the classic FELSPINE problem using
#GMRF in mgcv. This example is a modified version of the
#example from smooth.construct.so.smooth.spec()
#in the mgcv package

rm(list=ls())
library(mgcv)

#Extract boundary
fsb <- fs.boundary()

#Create an underlying grid and evaluate the function on it
#Based on mgcv::fs.boundary() example
dx<-0.2;dy<-0.2    #Grid steps
id.fmt <- "%i/%i"
x.vals <- seq(-1,4,by=dx)
y.vals<-seq(-1,1,by=dy)
grd <- expand.grid(x=x.vals,y=y.vals)
tru.mat <- matrix(fs.test(grd$x,grd$y),length(x.vals),length(y.vals))
grd$truth <- as.vector(tru.mat)
grd$x.idx <- as.numeric(factor(grd$x,x.vals))
grd$y.idx <- as.numeric(factor(grd$y,y.vals))
grd$xy.idx <- sprintf(id.fmt,grd$x.idx,grd$y.idx)
grd <- subset(grd,!is.na(truth))

## Simulate some fitting data, inside boundary...
n.samps<-250
x <- runif(n.samps)*5-1
y  <- runif(n.samps)*2-1
obs <- data.frame(x=x,y=y)
obs$truth <- fs.test(obs$x,obs$y,b=1)
obs$z <- obs$truth + rnorm(n.samps)*.3 ## add noise
pt.inside <- inSide(fsb,x=x,y=y) ## remove outsiders

## Associate observation with grid cell
obs$x.rnd <- round(obs$x/dx)*dx
obs$y.rnd <- round(obs$y/dy)*dy
obs$x.idx <- as.numeric(factor(obs$x.rnd,x.vals))
obs$y.idx <- as.numeric(factor(obs$y.rnd,y.vals))
obs$xy.idx <- sprintf(id.fmt,obs$x.idx,obs$y.idx)
obs$xy.idx <- factor(obs$xy.idx,levels=grd$xy.idx)

#Filter observations that are outside or don't have an associated grid cell
obs <- subset(obs,pt.inside & xy.idx %in% grd$xy.idx )

## plot boundary with truth and data locations
par(mfrow=c(1,2))
image(x.vals,y.vals,tru.mat,col=heat.colors(100),xlab="x",ylab="y")
contour(x.vals,y.vals,tru.mat,levels=seq(-5,5,by=.25),add=TRUE)
lines(fsb$x,fsb$y);
points(obs$x,obs$y,pch=3);

#Plot grid
plot(y~x,grd)
lines(fsb$x,fsb$y);

#Setup neighbourhood adjancey
nb <- grd[,c("x.idx","y.idx","xy.idx")]
nb$N <- factor(sprintf(id.fmt,nb$x.idx,nb$y.idx+1),levels=nb$xy.idx)
nb$S <- factor(sprintf(id.fmt,nb$x.idx,nb$y.idx-1),levels=nb$xy.idx)
nb$E <- factor(sprintf(id.fmt,nb$x.idx+1,nb$y.idx),levels=nb$xy.idx)
nb$W <- factor(sprintf(id.fmt,nb$x.idx-1,nb$y.idx),levels=nb$xy.idx)
nb.mat <- sapply(nb[,c("N","S","E","W")],as.numeric)
nb.l <- lapply(split(nb.mat,nb$xy.idx),function(x) x[!is.na(x)])

#Fit MRF gam
mdl <- gam(z ~ s(xy.idx,bs="mrf",xt=list(nb=nb.l)),data=obs,method="REML")










On 8 May 2014 15:15, Simon Wood <s.wood@bath.ac.uk> wrote:

> Hi Mark,
>
> I'm not sure what is happening here - there is no chance that nb.l
> contains a neighbourhood not in the levels of obs$xy.idx, I suppose? i.e. is
>
> all(names(nb.l)%in%levels(obs$xy.idx))
>
> also TRUE? Here is some code illustrating what nb should look like (and in
> response to Roger Bivand's suggestion I also tried this replacing all the
> labels with things like "x/y", but it still works).
>
>
> ## example mrf fit using polygons....
> library(mgcv)
> ## Load Columbus Ohio crime data (see ?columbus for details and credits)
> data(columb)       ## data frame
> data(columb.polys) ## district shapes list
> xt <- list(polys=columb.polys) ## neighbourhood structure info for MRF
> par(mfrow=c(2,2))
> ## First a full rank MRF...
> b0 <- gam(crime ~ s(district,bs="mrf",xt=xt),data=columb,method="REML")
>
> ## same fit based on direct neighbour spec...
> nb <- mgcv:::pol2nb(columb.polys)$nb
> xt <- list(nb=nb)
> b <- gam(crime ~ s(district,bs="mrf",xt=xt),data=columb,method="REML")
>
> best,
> Simon
>
>
>
>
> On 08/05/14 01:58, Mark Payne wrote:
>
>> Hi,
>>
>> Does anyone have an example of a Markov Random Field smoother (MRF) in
>> MGCV
>> where they have specified the neighbourhood directly, rather than
>> supplying
>> polygons? Does anyone understand how the rules should be? Based on the
>> columb example, I have setup my data set and neighbourhood like so:
>>
>>  head(nb.l)
>>>
>> $`10/10`
>> [1] 135 155 153
>>
>> $`10/2`
>> [1] 27  8  6
>>
>> $`10/3`
>> [1] 48  7 28 26
>>
>> $`10/4`
>> [1] 69 27 49 47
>>
>> $`10/5`
>> [1] 48 70 68
>>
>> $`10/7`
>> [1] 115  95  93
>>
>>  head(obs)
>>>
>>              x          y      truth x.idx y.idx xy.idx
>> 24  1.4835147  0.8026673  2.3605204    13    10  13/10
>> 26  1.0452111  0.4673685  1.8316741    11     8   11/8
>> 43  2.1514977 -0.2640058 -2.8812026    17     5   17/5
>> 46  2.8473951  0.5445714  3.6347799    20     9   20/9
>> 53 1.7983253 -0.6905912 -2.5473984 15     3   15/3
>> 86 -0.1839814 -0.7824026 -0.5776616     5     2    5/2
>>
>>>
>>>
>> but get the following error:
>>
>>  mdl <- gam(truth ~
>>>
>> s(xy.idx,bs="mrf",xt=list(nb=nb.l)),data=obs,method="REML")
>> Error in smooth.construct.mrf.smooth.spec(object, dk$data, dk$knots) :
>>    mismatch between nb/polys supplied area names and data area names
>>
>> However, there is a perfect match between the nb list names and the data
>> area names:
>>
>>> all(levels(obs$xy.idx) %in% names(nb.l))
>>>
>> [1] TRUE
>>
>>>
>>>
>> Any suggestions where to start?
>>
>> Mark
>>
>>         [[alternative HTML version deleted]]
>>
>> ______________________________________________
>> R-help@r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-help
>> PLEASE do read the posting guide http://www.R-project.org/
>> posting-guide.html
>> and provide commented, minimal, self-contained, reproducible code.
>>
>>
>
> --
> Simon Wood, Mathematical Science, University of Bath BA2 7AY UK
> +44 (0)1225 386603               http://people.bath.ac.uk/sw283
>

	[[alternative HTML version deleted]]

