在R中计算自引用变量

时间:2016-04-11 23:00:24

标签: r statistics

我正在尝试在数据框中创建一个变量,该变量将引用前一行(在正在创建的变量中)来派生一个值。我对R来说比较新,而且我来自excel,这种类型的自我引用和迭代更新功能非常简单。

mydata <- data.frame(trial = c(1,1,1,1,1,1,1,1,2,2),
fixation=c("","","aoi1","aoi1","","aoi3","aoi3","","",""),
trial.marker=c("","","","","","","",1,"",""))
mydata

trial fixation trial.marker
1                      
1                      
1     aoi1             
1     aoi1             
1                      
1     aoi3             
1     aoi3             
1                     1
2                      
2                      

详细背景:这是一个来自我有大量眼动追踪数据的数据集的样本。每行代表每隔约13毫秒记录一次的观察结果。固定变量指示主体在试验中观察该点的位置。我的目标(现在)是计算每个试验的第一次固定指示(受试者在每次试验中首先注意到什么)。我的方法是首先计算试验标记以标记每个试验的结束,然后计算第一个固定变量,该变量将扫描第一个&#34;命中的固定变量。任何一个&#34; aoi1&#34;或者&#34; aoi3,然后将这些信息一直保留下来,直到它到达试验结束时(试验标记)。然后,我将通过此试验标记索引数据框,为每个试验提取一行摘要。我需要编写各种类型的变量,我知道如何做的最好的方法是计算这些类型的自引用变量。

背景简短:我需要计算一个变量,该变量将检测每个试验中固定变量中的第一个观察结果,其中包含&#34; aoi1&#34;或者&#34; aoi3&#34;,并将此信息记录在与trial.marker变量中的1个值相同的行上。

我使用shift()函数计算trial.marker,但在引用同一变量的前一行时,这并没有正常工作。我实现它的唯一方法是使用可怕的for循环:

for (i in 1:nrow(mydata)){

if(i == 1){mydata$first.fixation[i]<- ""}

else if (mydata$trial.marker[i-1]==1){mydata$first.fixation[i]<-""}

else if (mydata$first.fixation[i-1] == ""){

  if(mydata$fixation[i] == "aoi1"){mydata$first.fixation[i] <- "aoi1"}
  else if (mydata$fixation[i] == "aoi3"){mydata$first.fixation[i] <- "aoi3"}
  else mydata$first.fixation[i] <- ""  
  }
 else mydata$first.fixation[i] <- mydata$first.fixation[i-1]
}

mydata

trial fixation trial.marker first.fixation
  1                                     
  1                                     
  1     aoi1                        aoi1
  1     aoi1                        aoi1
  1                                 aoi1
  1     aoi3                        aoi1
  1     aoi3                        aoi1
  1                     1           aoi1
  2                                     
  2     

运行此操作的数据集有120万行,运行大约需要5个小时,所以我希望有一种更有效的方法来处理它。

很抱歉,如果我的R语言很奇怪和/或我的帖子格式很糟糕。这是我的第一个堆栈溢出帖子=)希望事情足够清楚,你可以理解我在这里尝试做什么。因为我是R的新手,我确信也可能有一种完全不同的方法,但我不会想到这个......但是谁知道呢。

3 个答案:

答案 0 :(得分:0)

这是我的镜头。注意我不是R的专家(更多只是将它作为一种学习练习),所以我希望其他人可以使用或者至少批评我的代码。

我在您的数据中添加了几行,以便进行检查。它仍然循环,但这次只是试验的数量应该更快。

理想情况下,您可以避免R中的循环,因为矢量化操作几乎总是更快。

mydata <- data.frame(trial = c(1,1,1,1,1,1,1,1,2,2),
                     fixation=c("","","aoi1","aoi1","","aoi3","aoi3","","aoi3",""),
                     trial.marker=c("","","","","","","",1,"",""))
mydata
#structure shows it produces factored data (which I don't know enough about to like)
str(mydata)

#To avoid factors use stringsAsFactors = FALSE, also added blank column for first.fixation
mydata <- data.frame(trial = c(1,1,1,1,1,1,1,1,2,2,3,3),
                     fixation=c("","","aoi1","aoi1","","aoi3","aoi3","","","","aoi3",""),
                     trial.marker=c("","","","","","","",1,"",2,"",""),
                     first.fixation="",
                     stringsAsFactors = FALSE)
mydata
str(mydata)


trials<-unique(mydata$trial)

#which returns the indices that match the criteria, function not used for anything just for demonstration
which(mydata$fixation!="" & mydata$trial==1)

#loop through trials
for (i in 1:length(trials)){
  trial<-trials[i]
  #If there are no fixation it would error out so if statement
  if(length(which(mydata$fixation!="" & mydata$trial==trial))>0){
    #Find the last row with the given trial number
    rowmax <- max(which(mydata$trial==trial))
    #Find the first row with given trial number and fixation
    rowmin <- min(which(mydata$fixation!="" & mydata$trial==trial))
    #fill the data in
    mydata$first.fixation[rowmin:rowmax] = mydata$fixation[rowmin]
  }
}
mydata

答案 1 :(得分:0)

我会用data.table解决它,它通常会提供非常好的性能。虽然我没有运行量的基准。这将是解决方案。

library(data.table)
dt <- data.table(mydata)
f <- function(fixation) {
  if (length(which(fixation != "")) == 0) {
    return(rep("", length(fixation)))
  }
  min_informed <- min(which(fixation != ""))
  return(c(rep("", min_informed-1), rep(fixation[min_informed], length(fixation)-min_informed+1)))
}
dt[, fist.fixation:=f(fixation), by=list(trial)]

和输出

    trial fixation trial.marker fist.fixation
 1:     1                                    
 2:     1                                    
 3:     1     aoi1                       aoi1
 4:     1     aoi1                       aoi1
 5:     1                                aoi1
 6:     1     aoi3                       aoi1
 7:     1     aoi3                       aoi1
 8:     1                     1          aoi1
 9:     2                                    
10:     2                     2              
11:     3     aoi3                       aoi3
12:     3                                aoi3

猜测你不熟悉data.table,代码的一些解释:在dt[, fist.fixation:=f(fixation), by=list(trial)]中,第一个参数是查询,在这种情况下是所有元素,第二个参数是创建新列{{ 1}}来自函数first.fixation的结果,第三个参数是按试验分组=&gt;因此,函数f接收具有每个试验的所有注视的向量。一旦你有了这个向量,在函数f中,很容易知道哪个是第一个通知的,依此类推。

如果您决定检查它是否适用于您的大数据框架,那么如果您发布时间就会很好。我认为这应该是几分钟的时间(可能还需要几分钟)。

希望它无论如何都有帮助。

答案 2 :(得分:0)

所以我很确定我使用不同的方法解决了这个问题。打字我的问题让我清楚地知道我正在寻找一份试用摘要,所以我做了以下几点:

first.match <- function(x,y){
 match.list <- sort(match(x,y),decreasing=FALSE)
 y[match.list[1]]  
}

ff.data <-aggregate(x=exp2data$aoifixation,
by=list(exp2data$subject,exp2data$trial),
FUN=function(x) first.match(c("AOI1","AOI3"),x))

这给了我对每个试验总结的第一次固定(由每个受试者;然而,未在上面的实施例中显示)。然后我使用试验标记技术对原始数据集进行索引,然后将第一个固定向量从聚合添加到修剪后的数据集中。

ff.data <- ff.data[order(ff.data$Group.1,ff.data$Group.2),]
exp2data.trial <- exp2data[exp2data$trialmarker==1,]
exp2data.trial$ff <- ff.data[,3]

我仍在进行三重检查以确保其编码正确,但似乎很好。最好的部分是它在几秒钟内运行!我还没有尝试过,但我认为只要修改自定义函数,我就可以从试验数据中得到所有奇怪的眼动追踪变量。