如果值在范围内,则合并2个数据帧

时间:2014-05-29 13:20:34

标签: r csv

我一直在努力解决这个问题已经有一段时间没办法了,所以如果你能提供帮助,我将非常感激!我是编程新手,我的代码可能效率低下,但这是我能想到的最好的。

基本上,我有2个.csv文件(fixes.csv和zones.csv),它们包含不同的变量并且具有不同的行数和列数。第一个文件fixes.csv包含实验期间记录的眼动数据,如下所示:

Order Participant Sentence Fixation StartPosition
1       1          1         1       -6.89
2       1          1         2       -5.88
3       1          1         3       -5.33
4       1          1         4       -4.09
5       1          1         5       -5.36      

这包含在句子阅读期间进行的眼动记录。会发生的是,20名参与者中的每一个都会读取一组40个12个单词的句子,对每个句子中的不同单词进行多次修改,有时会回过头来查看以前读过的单词。 StartPosition列包含固定开始时屏幕上的位置(以视角度为单位)。值通常在-8deg和8deg之间。

第二个文件z​​ones.csv包含有关句子的信息。 40个句子中的每一个包含12个单词,每个单词形成一个感兴趣的区域。 zones.csv看起来像这样:

Sentence     Zone  ZoneStart   ZoneEnd
  1           1     -8.86      -7.49
  1           2     -7.49      -5.89
  1           3     -5.88      -4.51
  1           4     -4.51      -2.90

ZoneStart和ZoneEnd指示屏幕上每个区域的起始和结束坐标(以视角度为单位)。因为每个句子中的单词不同,所以每个区域都有一个宽度。

我想要做的是同时使用这两个文件,以便将zones.csv中的区域编号分配给fixes.csv中的注册。因此,例如,如果句子1中的第一个固定起始位置落在区域1的范围内,我希望将值1分配给它,以便结束文件看起来像这样:

Order Participant Sentence Fixation StartPosition Zone
1       1          1        1        -6.89          2
2       1          1        2        -5.88          2
3       1          1        3        -5.33          3
4       1          1        4        -4.09          3
5       1          1        5        -5.36          3   

到目前为止,我所尝试的是使用循环来自动化该过程。

zones = read.csv(file.choose(), header = TRUE, sep = ",")
fixes = read.csv(file.choose(), header = TRUE, sep = ",")

fixes$SentNo = as.factor(fixes$SentNo)
zones$Sentence = as.factor(zones$Sentence)
zones$Zone = as.factor(zones$Zone)

nfix = nrow(fixes) ## number of fixations in file fixes.csv
nsent = nlevels(fixes$Sentence) ## number of sentences in data file fixes.csv
nzs = nlevels(zones1$Zone) ## number of zones per sentence from file zones.csv
nsz = nlevels(zones$Sentence) ## number of sentences in data file zones.csv

fixes$Zone = 0

for (i in c(1:nfix)){
  for (j in c(1:nzs)){
    for (k in c(1:nsent){
      for (l in c(1:nsz)){ 
        while(fixes$Sentence[k] == zones$Sentence[l]){
          ifelse(fixes$StartPosition[i] > zones$ZoneStart[j]  
          & fixes$StratPosition[i] < zones1$ZoneEnd[j], 
          fixes$Zone[i] -> zones1$Zone[j], 0)
        return(fixes$Zone)
}
}
}
}

但这只会返回零的负载,而不是为每个注视分配区号。当它们具有不同数量的行和列时,甚至可以以这种方式使用2个单独的.csv文件吗?我尝试将它们合并为Sentence并使用大型组合文件进行合并,但这并没有帮助,因为它似乎搞乱了一个文件中的修复顺序和另一个文件中的区域顺序。

任何帮助将不胜感激!

谢谢!

4 个答案:

答案 0 :(得分:4)

Bioconductor中有一个名为IRanges的包可以满足您的需求。

首先,为您的区域形成一个IRanges对象:

zone.ranges <- with(zones, IRanges(ZoneStart, ZoneEnd))

接下来,找到重叠:

zone.ind <- findOverlaps(fixes$StartPosition, zone.ranges, select="arbitrary")

现在您有zones数据框行的索引,因此您可以合并:

fixes$Zone <- zones$Zone[zone.ind]

编辑:刚刚意识到你有浮点值,而IRanges是基于整数的。因此,鉴于您的精度,您需要将坐标乘以100。

答案 1 :(得分:3)

对于版本v1.9.8(在2016年11月25日的CRAN上),data.table已经获得了执行非equi连接范围连接的能力:< / p>

library(data.table)
setDT(fixes)[setDT(zones), 
             on = .(Sentence, StartPosition >= ZoneStart, StartPosition < ZoneEnd), 
             Zone := Zone][]
   Order Participant Sentence Fixation StartPosition Zone
1:     1           1        1        1         -6.89    2
2:     2           1        1        2         -5.88    3
3:     3           1        1        3         -5.33    3
4:     4           1        1        4         -4.09    4
5:     5           1        1        5         -5.36    3

数据

fixes <- readr::read_table(
  "Order Participant Sentence Fixation StartPosition
  1       1          1         1       -6.89
  2       1          1         2       -5.88
  3       1          1         3       -5.33
  4       1          1         4       -4.09
  5       1          1         5       -5.36"
)
zones <- readr::read_table(
  "Sentence     Zone  ZoneStart   ZoneEnd
  1           1     -8.86      -7.49
  1           2     -7.49      -5.89
  1           3     -5.88      -4.51
  1           4     -4.51      -2.90"
)

答案 2 :(得分:2)

您可以使用sqldf包:

library(sqldf)

#dummy data
fixes <- read.table(text="
Order Participant Sentence Fixation StartPosition
1       1          1         1       -6.89
2       1          1         2       -5.88
3       1          1         3       -5.33
4       1          1         4       -4.09
5       1          1         5       -5.36 
",header=TRUE)
zones <- read.table(text="
Sentence     Zone  ZoneStart   ZoneEnd
1           1     -8.86      -7.49
1           2     -7.49      -5.89
1           3     -5.88      -4.51
1           4     -4.51      -2.90
",header=TRUE)

#output merged result
res <- 
  sqldf("SELECT [Order],Participant,f.Sentence,Fixation,StartPosition,Zone
       FROM fixes f,zones z
       WHERE f.Sentence=z.Sentence AND
             f.StartPosition>=z.ZoneStart AND
             f.StartPosition<z.ZoneEnd")

答案 3 :(得分:1)

我认为最好的方法是将zones更改为更友好的格式,以便您执行以下操作:

ZoneLookUp = lapply(split(zones, zones$Sentence), function(x) c(x$ZoneStart, x$ZoneEnd[nrow(x)]))

#$`1`
#[1] -8.86 -7.49 -5.88 -4.51 -2.90

然后您可以轻松查找每个区域:

fixes$Zone = NULL
for(i in 1:nrow(fixes))
    fixes$Zone[i] = cut(fixes$StartPosition[i], ZoneLookUp[[fixes$Sentence[i]]], labels=FALSE)

如果性能问题,您可以使用bydata.table使用(仅)稍微简单的方法。