【问题标题】:Conditionally merging data from two data frames有条件地合并来自两个数据帧的数据
【发布时间】:2019-12-01 17:20:05
【问题描述】:

我目前正在尝试合并来自两个 dfs 眼动追踪数据的信息。在一个 df(行为)中,有与实验中的每个试验相关的开始和结束时间。在另一个 df(gaze) 中,记录了凝视的时间戳。我想检查每个凝视时间戳并评估它是否在试验的开始和结束时间内(从行为 df 中提取的信息),如果是,则将来自行为 df 的试验信息添加到试验列中凝视df。

dfs如下:

Behavioral df
   StartTime    EndTime Trial
1:         0     0.8     a
2:         1     1.8     b
3:         2     2.8     c
4:         3     3.8     d

Gaze df 
  Gaze    x   y Frame   Trial
 1: 0.00 100 200   126    NA
 2: 0.20 101 201   126    NA
 3: 0.40 102 202   127    NA
 4: 0.80 103 203   127    NA
 5: 0.60 104 204   127    NA
 6: 0.90 105 205   127    NA
 7: 1.20 106 206   128    NA
 8: 1.40 107 207   128    NA
 9: 1.60 108 208   128    NA
10: 2.02 109 209   129    NA
11: 2.50 110 210   129    NA
12: 2.90 111 211   129    NA
13: 3.10 112 212   130    NA
14: 3.79 113 213   130    NA

我想看看凝视时间戳。即,对于Gaze$Gaze[1],它是否介于 0 和 0.8 之间?是的>>>Gaze$Trial[1]=a

我试过了

for(i in Gaze$Gaze){
  if(as.numeric(Gaze$Gaze[i]) >= as.numeric(Behavior$StartTime[i])){
    if(as.numeric(Gaze$Gaze[i]) <= as.numeric(Behavior$EndTime[i])){
      Gaze$Trial[i]<-Behavior$Trial[i]
    }
  }
  else Gaze$Trial[i]<-NA

}

我得到错误:

if (as.numeric(fakegaze$Gaze[i]) >= as.numeric(fakebehavior$StartTime[i])) { 中的错误: 参数长度为零

我相信在合并信息之前我可能需要使用另一个 for 循环来分别遍历两个 dfs,但我不确定从哪里开始。谢谢!

数据:

library(data.table)
beh = setDT(structure(list(StartTime = c(0, 1, 2, 3), EndTime = c(0.8, 1.8, 2.8, 3.8
), Trial = c("a", "b", "c", "d")), row.names = c(NA, -4L), class = "data.frame"))

gaze = setDT(structure(list(Gaze = c(0, 0.2, 0.4, 0.8, 0.6, 0.9, 1.2, 1.4, 
1.6, 2.02, 2.5, 2.9, 3.1, 3.79), x = 100:113, y = 200:213, Frame = c(126L, 
126L, 127L, 127L, 127L, 127L, 128L, 128L, 128L, 129L, 129L, 129L, 
130L, 130L), Trial = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
NA, NA, NA, NA)), row.names = c(NA, -14L), class = "data.frame"))

【问题讨论】:

    标签: r dataframe for-loop merge


    【解决方案1】:

    您可以使用非 equi join 来更新凝视表中的 Trial:

    gaze[, Trial := beh[.SD, on=.(StartTime <= Gaze, EndTime >= Gaze), x.Trial]]
    
        Gaze   x   y Frame Trial
     1: 0.00 100 200   126     a
     2: 0.20 101 201   126     a
     3: 0.40 102 202   127     a
     4: 0.80 103 203   127     a
     5: 0.60 104 204   127     a
     6: 0.90 105 205   127  <NA>
     7: 1.20 106 206   128     b
     8: 1.40 107 207   128     b
     9: 1.60 108 208   128     b
    10: 2.02 109 209   129     c
    11: 2.50 110 210   129     c
    12: 2.90 111 211   129  <NA>
    13: 3.10 112 212   130     d
    14: 3.79 113 213   130     d
    

    这种方法假设beh 中没有重叠的区间(在这种情况下,正确的 Trial 可能是不明确的)。

    (OP 没有用 data.table 标记问题或包含 library(data.table) 调用,但我假设他们根据表格的打印方式使用它。)


    作为.SD is locked error bug 的解决方法,我通常按照错误消息中的建议使用copy(.SD)。但是,正如 OP 在 cmets 中指出的那样,对于大数据,这可能会很昂贵。通常等效的替代方法是翻转连接:

    # convert to correct NA type
    gaze[, Trial := rep(beh$Trial[NA_integer_], .N)] 
    # reversed update join
    gaze[beh, on=.(Gaze >= StartTime, Gaze <= EndTime), Trial := i.Trial]
    

    对于 OP 的情况,它似乎仍然产生了正确的结果。我通常avoid this kind of join 因为我发现它更难阅读并且它可能有奇怪的副作用。特别是在x[i, on=, v := i.v] 中,如果i 的多行映射到x 的同一行,则只会使用最后匹配的行(没有警告或错误)。

    【讨论】:

    • 这是完美的,谢谢!有没有办法为从 csv 文件导入的一组更大的值执行此操作?目前我正在使用 fread 导入文件,并运行相同的非 equi 语句,但出现错误:set(i, j = lc, value = newval) 中的错误:.SD 已锁定。使用 := 或 set 通过引用更新 .SD 保留供将来使用。直接在 j 中使用 := 。或者使用 copy(.SD) 作为(慢)最后的手段,直到 shallow() 被导出。你知道这其中的原因吗?再次感谢!
    • @ChanningEveridgeHambric 这是一个错误,但我不确定为什么它在某些情况下会发生而不是其他情况。我会按照错误消息中的建议使用copy(.SD) 代替.SD,除非它太慢,如果表非常大,可能会发生这种情况。我已经编辑了答案以显示另一个适用于此处的选项以及问题的链接。
    猜你喜欢
    • 1970-01-01
    • 2018-05-30
    • 2018-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    相关资源
    最近更新 更多