【问题标题】:Merge 2 dataframes if value within range如果值在范围内,则合并 2 个数据框
【发布时间】:2014-07-19 00:27:29
【问题描述】:

我已经为此苦苦挣扎了一段时间,找不到任何方法,所以如果您能提供帮助,我将不胜感激!我是编程新手,我的代码可能效率低下,但这是我能想到的最好的。

基本上,我有 2 个 .csv 文件(fixes.csv 和 zone.csv),它们包含不同的变量并具有不同的行数和列数。第一个文件 fixs.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 之间。

第二个文件 zone.csv 包含有关句子的信息。 40 个句子中的每一个都包含 12 个单词,每个单词形成一个兴趣区。 zone.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 表示屏幕上每个区域的起始和结束坐标(以视角度数为单位)。因为每个句子中的单词不同,所以每个区域都有一个宽度。

我想做的是同时使用这两个文件,以便将 zone.csv 中的区域编号分配给 fix.csv 中的注视点。例如,如果 Sentence 1 中的第一个注视起始位置在 Zone 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 文件吗?我尝试通过句子合并它们并从一个大的组合文件中工作,但这并没有帮助,因为它似乎弄乱了一个文件中的注视顺序和另一个文件中的区域顺序。

任何帮助将不胜感激!

谢谢!

【问题讨论】:

    标签: r csv


    【解决方案1】:

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

    首先,为您的区域创建一个 IRange 对象:

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

    接下来,找到重叠部分:

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

    现在你有了zones数据框行的索引,所以你可以合并:

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

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

    【讨论】:

      【解决方案2】:

      使用 v1.9.8 版本(2016 年 11 月 25 日在 CRAN 上),data.table 获得了执行非等值连接范围连接的能力:

      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"
      )
      

      【讨论】:

        【解决方案3】:

        你可以使用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")
        

        【讨论】:

          【解决方案4】:

          我认为最好的方法是将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 和 by。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-08-21
            • 1970-01-01
            • 1970-01-01
            • 2019-06-06
            • 1970-01-01
            • 2014-05-30
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多