Modeling Eccentricity

As mentioned in the data exploration document, eccentricity did not seem normally distributed, and could not be effectively transformed to resemble a more Gaussian distribution. In this document, I attempted to model eccentricity using different non-linear functions such that I could extract the relevant coefficients/parameters for those function for model-based clustering.

There are different non-linear functions we can use to fit the data. I fit the data using 4 different types of non-linear functions to see which one might be the most appropriate to use

  1. Exponential function
  2. Power function
  3. Asymptotic regression
  4. Michaelis-Menten equation (rectangular hyperbola)
# ----------- Load libraries ------------

library(plyr)
library(openxlsx)

# ------------ Load data -------------
df<-read.csv("VR_Basic Scene Viewing_Summary Per Trial_Updated 11Nov2020.csv")

suj<-unique(df$subject)

ecc<-NULL
head.coef<-NULL
sacc.coef<-NULL

# definining non-linear functions
f.exp <- function(X,a,b) {a * (X^(b - 1) * b)} # exponential function
f.pwr <- function(X,a,k) {a * (exp(k * X) * k)} # power function


for (s in suj){
  # subset data frame for each participant
  sub<-subset(df, subject==s)
  # sort eccentricities from smallest to largest and create data frame
  frame<-data.frame(subject = s,
                    len = 1:nrow(sub),
                    head.ecc = sort(sub$head.ecc),
                    sacc.ecc = sort(sub$sacc.ecc)
                    )
  # bind data frame
  ecc<-rbind(ecc, frame)

  # ---------- HEAD ------------

  # EXPONENTIAL FUNCTION
  # get the starting position of a and b using a linear model
  fexp0 <- nls(log(head.ecc) ~ log(f.exp(len, a, b)), frame, start = c(a = 1, b = 1))
  # construct exponential model and extracting coefficients
  mod.exp<-nls(head.ecc ~ f.exp(len, a, b), frame, start = coef(fexp0))
  mod.exp.sum<-summary(mod.exp)

  # POWER FUNCTION
  # get the starting position
  fpwr0 <- nls(log(head.ecc) ~ log(f.pwr(len, a, k)), frame, start = c(a = 1, k = 1))
  # construct model and extracting coefficients
  mod.pwr<-nls(head.ecc ~ f.pwr(len, a, k), data=frame, start = coef(fpwr0))
  mod.pwr.sum<-summary(mod.pwr)

  # ASYMPTOTIC REGRESSION
  mod.asym<-nls(head.ecc ~ SSasymp(len, Asym, R0, lrc), data=frame)
  mod.asym.sum<-summary(mod.asym)

  # RECTANGULAR HYPERBOLA
  mod.mm<-nls(head.ecc ~ SSmicmen(len, Vm, K), data=frame)
  mod.mm.sum<-summary(mod.mm)

  h.coef<-data.frame(subject = s,
                   # exponential function coef
                   exp.int = mod.exp.sum$coefficients[1],
                   exp.rate = mod.exp.sum$coefficients[2],
                   # power function coef
                   pwr.int = mod.pwr.sum$coefficients[1],
                   pwr.rate = mod.pwr.sum$coefficients[2],
                   # asymptotic regression
                   asym.max = mod.asym.sum$coefficients[1],
                   asym.int = mod.asym.sum$coefficients[2],
                   asym.lograte = mod.asym.sum$coefficients[3],
                   # Rectangular hyperbola
                   mm.max = mod.mm.sum$coefficients[1],
                   mm.maxhalf = mod.mm.sum$coefficients[2],
                   # fit between model and data

                   exp.cor = cor(frame$head.ecc, predict(mod.exp)),
                   pwr.cor = cor(frame$head.ecc, predict(mod.pwr)),
                   asym.cor = cor(frame$head.ecc, predict(mod.asym)),
                   mm.cor = cor(frame$head.ecc, predict(mod.mm))
                   )

  head.coef<-rbind(head.coef, h.coef)

  # ---------- SACCADE ------------

  # EXPONENTIAL FUNCTION
  # get the starting position of a and b using a linear model
  fexp0 <- nls(log(sacc.ecc) ~ log(f.exp(len, a, b)), data=frame, start = c(a = 1, b = 1))
  # construct exponential model and extracting coefficients
  mod.exp<-nls(sacc.ecc ~ f.exp(len, a, b), data=frame, start = coef(fexp0))
  mod.exp.sum<-summary(mod.exp)

  # POWER FUNCTION
  # get the starting position
  fpwr0 <- nls(log(sacc.ecc) ~ log(f.pwr(len, a, k)), data=frame, start = c(a = 1, k = 1))
  # construct model and extracting coefficients
  mod.pwr<-nls(sacc.ecc ~ f.pwr(len, a, k), data=frame, start = coef(fpwr0))
  mod.pwr.sum<-summary(mod.pwr)

  # ASYMPTOTIC REGRESSION (using self-starting function)
  mod.asym<-nls(sacc.ecc ~ SSasymp(len, Asym, R0, lrc), data=frame)
  mod.asym.sum<-summary(mod.asym)

  # RECTANGULAR HYPERBOLA (using self-starting function)
  mod.mm<-nls(sacc.ecc ~ SSmicmen(len, Vm, K), data=frame)
  mod.mm.sum<-summary(mod.mm)

  s.coef<-data.frame(subject = s,
                   # exponential function coef
                   exp.int = mod.exp.sum$coefficients[1],
                   exp.rate = mod.exp.sum$coefficients[2],
                   # power function coef
                   pwr.int = mod.pwr.sum$coefficients[1],
                   pwr.rate = mod.pwr.sum$coefficients[2],
                   # asymptotic regression
                   asym.max = mod.asym.sum$coefficients[1],
                   asym.int = mod.asym.sum$coefficients[2],
                   asym.lograte = mod.asym.sum$coefficients[3],
                   # Rectangular hyperbola
                   mm.max = mod.mm.sum$coefficients[1],
                   mm.maxhalf = mod.mm.sum$coefficients[2],
                   # fit between model and data

                   exp.cor = cor(frame$sacc.ecc, predict(mod.exp)),
                   pwr.cor = cor(frame$sacc.ecc, predict(mod.pwr)),
                   asym.cor = cor(frame$sacc.ecc, predict(mod.asym)),
                   mm.cor = cor(frame$sacc.ecc, predict(mod.mm))
                   )

  sacc.coef<-rbind(sacc.coef, s.coef)
}

# datasets <- list("Saccade Paramters" = sacc.coef, "Head Movement Parameters" = head.coef)

# write.xlsx(datasets, file = "Eccentricity Parameters from Non-Linear Models.xlsx", row.names=F)

# ----------- creating summary tables ----------------

# Mean correlation between actual and model value 
head.coef.sum<-ddply(head.coef, .(), summarise,
                     exp = mean(exp.cor),
                     pwr = mean(pwr.cor),
                     asym = mean(asym.cor),
                     mm = mean(mm.cor))

# Mean correlation between actual and model value 
sacc.coef.sum<-ddply(sacc.coef, .(), summarise,
                     exp = mean(exp.cor),
                     pwr = mean(pwr.cor),
                     asym = mean(asym.cor),
                     mm = mean(mm.cor))

Below are tables examining how well the predicted values fit with actual values using the correlation function. As shown, the asymptotic regression model might fit the data best for both eye and head movement eccentricity.

Eye Movement

##         exp       pwr      asym        mm
## 1 0.9511513 0.8117374 0.9754485 0.9218623

Head Movement

##        exp       pwr      asym        mm
## 1 0.939488 0.7794861 0.9746239 0.9314913