RE: [R] IFELSE across large array?

2004-12-05 Thread Sander Oom
Dear all,
Thanks to the help from the R mailing list we now have a script performing 
the required tasks, i.e. applying a mask and filter to a 3D array. See 
script below. Any further suggestions to simplify the code are very 
welcome. We are currently debugging the larger script of which this section 
is a small part.

The script could serve as a framework for many typical GIS neighborhood 
analyses, in this case the 'block majority'. The 'var.range' variable is 
derived from variography earlier in the main script.

Yours,
Sander and Alessandro
##INPUT SECTION1##
numRow-7
numCol-8
numReal-2
var.range-  2.1
cellsize- 0.25

##CALCULATE WINDOW SIZES BASED ON INPUT ABOVE#
#window size ...minimum is 1
numCells-round((var.range*cellsize)/2,0)
if(numCells  1) {numCells-1}
###
library(abind)
#Sim: 0=Absent; 1=Present; 10=NA
vectSim - c(1,1,0,0,1,1,10,1,0,10,1,1,1,0,1,1,1,1,1,0,0,1,0,0,10,0,0,
1,1,1,0,1,1,0,0,0,1,1,1,0,1,1,0,1,0,1,10,0,1,0,0,1,0,0,10,0,0,0,1,1,0,
0,1,0,1,0,0,1,0,0,1,1,1,1,1,10,1,10,1,0,1,0,1,0,0,1,1,0,10,10,1,1,0,1,
0,1,1,1,0,0,0,1,0,0,0,0,0,0,1,1,0,0)
#Mask: 10=NA; 1=DATA
vectMask - c(10,1,10,1,1,10,1,10,1,10,10,1,10,1,10,1,1,10,1,10,1,10,10,1,10,1,
10,1,1,10,1,10,1,10,10,1,10,1,10,1,1,10,1,10,1,10,10,1,10,1,10,1,1,10,1,10)
length(vectSim)
length(vectMask)
Sim - array(vectSim, c(numRow,numCol,numReal))
Sim[Sim==10]-NA
Sim
Mask - array(data=vectMask, c(numRow,numCol,numReal))
Mask
##expand array
junkcol-array(rep(NA,numReal*numRow),c(numRow,numCells,numReal))
#add columns borders
#cols
Sim-abind(junkcol,Sim,junkcol, along=2)
dim(Sim)[2]
junkrow-array(rep(NA,dim(Sim)[2]),c(numCells,dim(Sim)[2],numReal))
Sim-abind(junkrow,Sim,junkrow,along=1)
##DEFINE PORTION OF ARRAY ON WHICH MOVING WINDOW RUNS
##IT AVOIDS THE na BORDER
#maximum row and col indexes to consider are equal
# to num num rows and num cols in the original matrix
minr-1+numCells
maxr-dim(Sim)[1]-numCells
minc-1+numCells
maxc-dim(Sim)[2]-numCells
clean-function(a,nr,r,c) {
  rmin-row(a)[r-numCells]
  rmax-row(a)[r+numCells]
  cmin-col(a)[nr*(c-numCells)]
  cmax-col(a)[nr*(c+numCells)]
  junk-a[rmin:rmax,cmin:cmax]
  junk[numCells,numCells]-NA
  junk-as.vector(junk)
  sample(na.omit(junk),1)
}
for (n in 1:numReal)  {
  realiz-Sim[1:dim(Sim)[1],1:dim(Sim)[2],n]
  rz-realiz
  for (r in minr:maxr)  {
for (c in minc:maxc)  {
  if(is.na(realiz[r,c]) ) {
realiz[r,c]-clean(a=realiz,nr=numRow,r=r,c=c)
Sim[1:dim(Sim)[1],1:dim(Sim)[2],n]-realiz
  }#end if
}
  }
}##end overall loop
# Return to original array dimensions, removing extra NA
minr - (numCells+1)
maxr - (dim(Sim)[1]-numCells)
minc - (numCells+1)
maxc - (dim(Sim)[2]-numCells)
expSim - Sim
expSim
Sim - expSim[minr:maxr, minc:maxc, 1:dim(Sim)[3]]
Sim
# Clip simulation results using the mask
Mask
Sim[Sim==10] - NA
Mask[Mask==10] - NA
A - Sim + Mask -1
A
#

At 01:55 2004/11/24, Ray Brownrigg wrote:
 From: Liaw, Andy [EMAIL PROTECTED]
 Date: Tue, 23 Nov 2004 12:28:48 -0500

 I'll give it half a crack:

 Steps a through c can be done via nested ifelse(), treating A and M as
 vectors (as they really are).  Step d is the hard one.  I'd write a simple
 Fortran code and use .Fortran() for that.

 I don't see how any of the *apply() functions can help here, as your
 operations are element-wise, not dimension-wise.

 Andy

The original message mentions that the value 10 is actually NODATA,
and if one recodes 10 as NA, steps a) to c) become trivial, namely:
A[A == 10] - NA
M[M == 10] - NA
return(A + M - 1)
Then if step d) is performed first (i.e. appropriate values in A are
replaced by the 'most common neighbour' [perhaps using
round(mean(.., na.rm=T))] this still works, but would have to be repeated
for each replication (the third dimension).
Ray Brownrigg
  From: Sander Oom
 
  Dear all,
 
  As our previous email did not get any response, we try again with a
  reformulated question!
 
  We are trying to do something which needs an efficient loop
  over a huge
  array, possibly functions such as apply and related (tapply,
  lapply...?), but can't really understand syntax and examples in
  practice...i.e. cant' make it work.
 
  to be more specific:
  we are trying to apply a mask to a 3D array.
  By this I mean that when overlaying [i.e. comparing element
  by element]
  the mask on to the array the mask should change array
  elements according to
  the values of both array and mask elements
 
  the mask has two values: 1 and 10.
 
  the array elements have 3 values: 0, 1,  or 10
 
  sticking for the moment to the single 2d array case
 
  for example:
  [A= array]  100 10 1  10  0
1   10   1 0   0 10
 
  [ M=mask] 1  10  10 1   1  1
   101   1  1 10 10
 
  I would like the array elements to:
 
  a) IF A(ij) !=10 and  Mij = 1
leave A(ij) 

RE: [R] IFELSE across large array?

2004-11-23 Thread Liaw, Andy
I'll give it half a crack:

Steps a through c can be done via nested ifelse(), treating A and M as
vectors (as they really are).  Step d is the hard one.  I'd write a simple
Fortran code and use .Fortran() for that.

I don't see how any of the *apply() functions can help here, as your
operations are element-wise, not dimension-wise.

Andy


 From: Sander Oom
 
 Dear all,
 
 As our previous email did not get any response, we try again with a 
 reformulated question!
 
 We are trying to do something which needs an efficient loop 
 over a huge 
 array, possibly functions such as apply and related (tapply,
 lapply...?), but can't really understand syntax and examples in 
 practice...i.e. cant' make it work.
 
 to be more specific:
 we are trying to apply a mask to a 3D array.
 By this I mean that when overlaying [i.e. comparing element 
 by element] 
 the mask on to the array the mask should change array 
 elements according to 
 the values of both array and mask elements
 
 the mask has two values: 1 and 10.
 
 the array elements have 3 values: 0, 1,  or 10
 
 sticking for the moment to the single 2d array case
 
 for example:
 [A= array]  100 10 1  10  0
   1   10   1 0   0 10
 
 [ M=mask] 1  10  10 1   1  1
  101   1  1 10 10
 
 I would like the array elements to:
 
 a) IF A(ij) !=10 and  Mij = 1
   leave A(ij) unchanged
 
 b)  IF   A(ij) != 10 and M(ij) =10
 change A(ij) to M(ij) i.e mask value (10)
 
 c)IF A(ij) = 10 and M(ij) = 10
leave (Aij) unchanged
 
 d) IF A(ij) = 10 and M(ij) !=10
 replace A(ij) with the majority value in the 
 8-neighborhood
 
 (or whatever if it is an edge element) BUT ignoring 10s in this 
 neighborhood (i.e. with either 1 or 0, whichever is in majority)
 
 because the array is 3d I would like to repeat the thing with 
 all the k 
 elements (2d sub-arrays) of the array in question, using the 
 same mask for 
 al k elements
 
 Would you be able to suggest a strategy to do this?
 
 thanks very much
 
 Alessandro and Sander.
 
 __
 [EMAIL PROTECTED] mailing list
 https://stat.ethz.ch/mailman/listinfo/r-help
 PLEASE do read the posting guide! 
 http://www.R-project.org/posting-guide.html
 


__
[EMAIL PROTECTED] mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide! http://www.R-project.org/posting-guide.html


RE: [R] IFELSE across large array?

2004-11-23 Thread Marc Schwartz
On Tue, 2004-11-23 at 12:28 -0500, Liaw, Andy wrote:
 I'll give it half a crack:
 
 Steps a through c can be done via nested ifelse(), treating A and M as
 vectors (as they really are).  Step d is the hard one.  I'd write a simple
 Fortran code and use .Fortran() for that.
 
 I don't see how any of the *apply() functions can help here, as your
 operations are element-wise, not dimension-wise.
 
 Andy

I'll toss in one additional thought here in follow up to Andy's, which
is that you could feasibly use mapply() to do element-wise operations. 

In fact, this is how I compute concordant and discordant pairs in a 2D
matrix for some of the measures of association that I want to include in
the CrossTable() function in the gregmisc bundle.

I'll paste the code for the concordant() function here, to give you an
idea of the approach:

# Calculate CONcordant Pairs in a table
# cycle through x[r, c] and multiply by
# sum(x elements below and to the right of x[r, c])
# x = table
concordant - function(x)
{
  # get sum(matrix values  r AND  c)
  # for each matrix[r, c]
  mat.lr - function(r, c)
  { 
lr - x[(r.x  r)  (c.x  c)]
sum(lr)
  }

  # get row and column index for each
  # matrix element
  r.x - row(x)
  c.x - col(x)

  # return the sum of each matrix[r, c] * sums
  # using mapply to sequence thru each matrix[r, c]
  sum(x * mapply(mat.lr, r = r.x, c = c.x))
}


Presumably, you could extend the basic approach to a 3D structure, by
using a third index argument to the mapply() call and use something like
expand.grid() to create the three vectors for the indices into the 3D
array:

# Set up the index combinations for a 4 x 4 x 4 array
Index - expand.grid(1:4, 1:4, 1:4)

YourFunction - function(a, b, c)
{
   DoSomethingHere(YourArray[a, b, c])
}

YourReturnVals - mapply(YourFunction, a = Index[, 1], b = Index[, 2], 
 c = Index[, 3])


I am hoping that this approach might be applicable here, at least in
basic concept.  Also, keep in mind any scoping issues with respect to
your data structures.

HTH,

Marc Schwartz

__
[EMAIL PROTECTED] mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide! http://www.R-project.org/posting-guide.html


RE: [R] IFELSE across large array?

2004-11-23 Thread Ray Brownrigg
 From: Liaw, Andy [EMAIL PROTECTED]
 Date: Tue, 23 Nov 2004 12:28:48 -0500
 
 I'll give it half a crack:
 
 Steps a through c can be done via nested ifelse(), treating A and M as
 vectors (as they really are).  Step d is the hard one.  I'd write a simple
 Fortran code and use .Fortran() for that.
 
 I don't see how any of the *apply() functions can help here, as your
 operations are element-wise, not dimension-wise.
 
 Andy
 
The original message mentions that the value 10 is actually NODATA,
and if one recodes 10 as NA, steps a) to c) become trivial, namely:

A[A == 10] - NA
M[M == 10] - NA
return(A + M - 1)

Then if step d) is performed first (i.e. appropriate values in A are
replaced by the 'most common neighbour' [perhaps using
round(mean(.., na.rm=T))] this still works, but would have to be repeated
for each replication (the third dimension).

Ray Brownrigg

  From: Sander Oom
  
  Dear all,
  
  As our previous email did not get any response, we try again with a 
  reformulated question!
  
  We are trying to do something which needs an efficient loop 
  over a huge 
  array, possibly functions such as apply and related (tapply,
  lapply...?), but can't really understand syntax and examples in 
  practice...i.e. cant' make it work.
  
  to be more specific:
  we are trying to apply a mask to a 3D array.
  By this I mean that when overlaying [i.e. comparing element 
  by element] 
  the mask on to the array the mask should change array 
  elements according to 
  the values of both array and mask elements
  
  the mask has two values: 1 and 10.
  
  the array elements have 3 values: 0, 1,  or 10
  
  sticking for the moment to the single 2d array case
  
  for example:
  [A= array]  100 10 1  10  0
1   10   1 0   0 10
  
  [ M=mask] 1  10  10 1   1  1
   101   1  1 10 10
  
  I would like the array elements to:
  
  a) IF A(ij) !=10 and  Mij = 1
leave A(ij) unchanged
  
  b)  IF   A(ij) != 10 and M(ij) =10
  change A(ij) to M(ij) i.e mask value (10)
  
  c)IF A(ij) = 10 and M(ij) = 10
 leave (Aij) unchanged
  
  d) IF A(ij) = 10 and M(ij) !=10
  replace A(ij) with the majority value in the 
  8-neighborhood
  
  (or whatever if it is an edge element) BUT ignoring 10s in this 
  neighborhood (i.e. with either 1 or 0, whichever is in majority)
  
  because the array is 3d I would like to repeat the thing with 
  all the k 
  elements (2d sub-arrays) of the array in question, using the 
  same mask for 
  al k elements
  
  Would you be able to suggest a strategy to do this?
  
  thanks very much
  
  Alessandro and Sander.

__
[EMAIL PROTECTED] mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide! http://www.R-project.org/posting-guide.html