Re: Adding observation covariates to an unmarkedFrameOccu object

11 views
Skip to first unread message

Jeffrey Royle

unread,
May 20, 2026, 9:13:56 AM (6 days ago) May 20
to Greg Distiller, hmecology: Hierarchical Modeling in Ecology, unma...@googlegroups.com
hi Greg,
 This is a good question for the unmarked email list, although there is a lot of overlap in the communities I think.
  At any rate , here is an example which I modified from the help file for occu (see ?occu) which I actually don't think is that helpful (sorry about that).   
 Bottom line: your observation covariates should be matrices of dimension nsites x nobs and you can include them AS A LIST in the unmarkedFrame with the "obsCovs" argument.
 So if you follow the steps shown below for your example it should work out.  
 If you have multiple covariates then the argument would look like:  obsCovs = list(obsvar1 = matrix containing the first covariate, obsvar2 = matrix containing the 2nd, obsvar3 = and so on)

data(frogs)
plot(pferUMF, panels=4)
# add some fake covariates for illustration
sC <- data.frame(sitevar1 = rnorm(numSites(pferUMF)))
nsites<- 130
nobs<- 3
obsvar1<-  matrix(rnorm(nsites*nobs),ncol=nobs)  
str(obsvar1)
pferUMF <- unmarkedFrameOccu(pfer.bin,siteCovs = sC, obsCovs = list(obsvar1=obsvar1) )
(fm <- occu(~ obsvar1 ~ 1, pferUMF))

On Wed, May 20, 2026 at 6:00 AM 'Greg Distiller' via hmecology: Hierarchical Modeling in Ecology <hmec...@googlegroups.com> wrote:

I am trying to figure out how  observation covariates are formatted within an unmarkedFrameOccu object. I know that these covariates are represented as vectors rather than with a matrix like structure as done with spOcc but am unsure how these vector are constructed. I asked AI and initially AI said that all covariate vectors in unmarked are constructed from a data frame column-wise but it is apparent that this cannot be true. The first column of a detection matrix I am using has no NA values but the first set of the elements in the one observational covariate shows “3 NA NA NA NA…”. After much iterating AI said that while the covariate values are definitely correctly associated with the detection matrix, the order of the elements inside the vectors is not predictable and that if one wants to add a covariate it should be passed to the unmarkedFrameOccu() function when constructing the unmarked object. In other words it says one should never first construct the unmarked object and then add a covariate. 

I am now passing all covariates I want when I create the unmarkedFrameOccu object but I find it difficult to believe that the unmarkedFrameOccu() function would not have a systematic way of arranging the covariate vectors and to me it looks like the vector is constructed row-wise rather than column-wise. But AI is completely adamant that unmarked would not use row-wise construction so I thought worth asking here if anyone knows how these vectors are constructed?

Many thanks

Greg

--
*** Three hierarchical modeling email lists ***
(1) unmarked: for questions specific to the R package unmarked
(2) SCR: for design and Bayesian or non-bayesian analysis of spatial capture-recapture
(3) HMecology (this list): for everything else, especially material covered in the books by Royle & Dorazio (2008), Kéry & Schaub (2012), Kéry & Royle (2016, 2021) and Schaub & Kéry (2022)
---
You received this message because you are subscribed to the Google Groups "hmecology: Hierarchical Modeling in Ecology" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hmecology+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/hmecology/8b278577-9697-4159-8da4-04fb0c64682fn%40googlegroups.com.

Ken Kellner

unread,
May 20, 2026, 10:34:40 AM (6 days ago) May 20
to unmarked
To expand a bit on Andy's answer, you can provide the observation covariates as either a named list of matrices that match the structure of the observation (occupancy) data, *or* a data frame where each column represents one covariate (but the order of the values in this column needs to be in a certain way; see below). The fact that there are two possible ways of doing things may be contributing to the confusion.

Here's an additional example of  both methods. This example will be a study with 3 sites and 2 replicate sampling occasions, and two observation covariates.

# occupancy data (note byrow = TRUE to get structure correct)
y <- matrix(c(0, 1,
              1, 1,
              0, 0), nrow=3, byrow = TRUE)

Look at the occupancy data:

> y
     [,1] [,2]
[1,]    0    1
[2,]    1    1
[3,]    0    0

# Detection-level covariates
cov1 <- matrix(c(1, 2,
                 3, 4,
                 5, 6), nrow=3, byrow = TRUE)

cov1 <- matrix(c(1, 2,
                 3, 4,
                 5, 6), nrow=3, byrow = TRUE)


Look at covariate 1:

> cov1
     [,1] [,2]
[1,]    1    2
[2,]    3    4
[3,]    5    6

Look at covariate 2:

> cov2
     [,1] [,2]
[1,]    7    8
[2,]    9   10
[3,]   11   12

The simplest way to format the observation covariates is to provide them as a list of matrices, as Andy notes.

obs_covs <- list(cov1 = cov1, cov2 = cov2)

umf <- unmarkedFrameOccu(y = y, obsCovs = obs_covs)

> umf
Data frame representation of unmarkedFrame object.
  y.1 y.2 cov1.1 cov1.2 cov2.1 cov2.2
1   0   1      1      2      7      8
2   1   1      3      4      9     10
3   0   0      5      6     11     12

However, you can also structure the observation covariates as a single data frame, where each column corresponds to one covariate. In order to do this, you need to reorganize each matrix into a column in "site-major order". So for covariate 1, the column starts with the 2 values for site 1, followed by the 2 values for site 2, followed by the 2 values for site 3. Then do the same for covariate 2, which becomes the second column. By default when converting from a matrix to a vector, R will put the values in the wrong order. You need to transpose the matrix first.

For example, this results in the wrong order:

> as.vector(cov1)
[1] 1 3 5 2 4 6

Instead we need to first transpose the matrix, then convert it to a vector:

> as.vector(t(cov1))
[1] 1 2 3 4 5 6

So the final data frame version of the obs covs is

obs_covs <- data.frame(cov1 = as.vector(t(cov1)),
                       cov2 = as.vector(t(cov2)))

> obs_covs
  cov1 cov2
1    1    7
2    2    8
3    3    9
4    4   10
5    5   11
6    6   12

Note that the first two rows of the data frame correspond to the 2 obs for site 1, rows 3 and 4 are the observations for site 2, and so on.
Here's the final unmarked frame, same as with the other method:

umf <- unmarkedFrameOccu(y = y, obsCovs = obs_covs)

> umf
Data frame representation of unmarkedFrame object.
  y.1 y.2 cov1.1 cov1.2 cov2.1 cov2.2
1   0   1      1      2      7      8
2   1   1      3      4      9     10
3   0   0      5      6     11     12

Ken
Reply all
Reply to author
Forward
0 new messages