【问题标题】:R: subset a data frame based on conditions from another data frameR:根据来自另一个数据帧的条件子集一个数据帧
【发布时间】:2013-06-14 10:42:15
【问题描述】:

这是我要解决的一个问题。比如说,我有两个数据框,如下所示:

observations <- data.frame(id = rep(rep(c(1,2,3,4), each=5), 5),
    time = c(rep(1:5,4), rep(6:10,4), rep(11:15,4), rep(16:20,4), rep(21:25,4)),
    measurement = rnorm(100,5,7))

sampletimes <- data.frame(location = letters[1:20], 
    id = rep(1:4,5),
    time1 = rep(c(2,7,12,17,22), each=4), 
    time2 = rep(c(4,9,14,19,24), each=4))

它们都包含一个名为id 的列,用于链接数据框。我想让measurements 来自observationss for whichtimeis betweentime1andtime2from thesampletimesdata frame. Additionally, I'd like to connect the appropriatelocation` 到每个测量。

我通过将sampletimes 转换为宽格式(即id 的每个条目在一行中的所有time1time2 信息)成功地做到了这一点,通过@987654333 合并两个数据框@ 变量,并使用条件语句仅在 time 位于行中至少一个时间间隔之间时获取实例,然后将 location 分配给适当的度量。

但是,我在 observations 中有大约 200 万行,这样做需要很长时间。我正在寻找一种更好的方法来保存长格式的数据。示例数据集非常简单,但实际上,我的数据包含每个id 的可变数量的间隔和位置。

对于我们的示例,我希望返回的数据框如下:

id time measurement letters[1:20]
1    3  10.5163892             a
2    3   5.5774119             b
3    3  10.5057060             c
4    3  14.1563179             d
1    8   2.2653761             e
2    8  -1.0905546             f
3    8  12.7434161             g
4    8  17.6129261             h
1   13  10.9234673             i
2   13   1.6974481             j
3   13  -0.3664951             k
4   13  13.8792198             l
1   18   6.5038847             m
2   18   1.2032935             n
3   18  15.0889469             o
4   18   0.8934357             p
1   23   3.6864527             q
2   23   0.2404074             r
3   23  11.6028766             s
4   23  20.7466908             t

【问题讨论】:

    标签: r dataframe subset


    【解决方案1】:

    这是与merge 的提案:

    # merge both data frames
    dat <- merge(observations, sampletimes, by = "id")
    # extract valid rows
    dat2 <- dat[dat$time > dat$time1 & dat$time < dat$time2, seq(4)]
    # sort
    dat2[order(dat2$time, dat2$id), ]
    

    结果:

        id time measurement location
    11   1    3    7.086246        a
    141  2    3    6.893162        b
    251  3    3   16.052627        c
    376  4    3   -6.559494        d
    47   1    8   11.506810        e
    137  2    8   10.959782        f
    267  3    8   11.079759        g
    402  4    8   11.082015        h
    83   1   13    5.584257        i
    218  2   13   -1.714845        j
    283  3   13  -11.196792        k
    418  4   13    8.887907        l
    99   1   18    1.656558        m
    234  2   18   16.573179        n
    364  3   18    6.522298        o
    454  4   18    1.005123        p
    125  1   23   -1.995719        q
    250  2   23   -6.676464        r
    360  3   23   10.514282        s
    490  4   23    3.863357        t
    

    【讨论】:

      【解决方案2】:

      效率不高,但尽职尽责:

       subset(merge(observations,sampletimes), time > time1 & time < time2)
              id time measurement location time1 time2
          11   1    3    3.180321        a     2     4
          47   1    8    6.040612        e     7     9
          83   1   13   -5.999317        i    12    14
          99   1   18    2.689414        m    17    19
          125  1   23   12.514722        q    22    24
          137  2    8    4.420679        f     7     9
          141  2    3   11.492446        b     2     4
          218  2   13    6.672506        j    12    14
          234  2   18   12.290339        n    17    19
          250  2   23   12.610828        r    22    24
          251  3    3    8.570984        c     2     4
          267  3    8   -7.112291        g     7     9
          283  3   13    6.287598        k    12    14
          360  3   23   11.941846        s    22    24
          364  3   18   -4.199001        o    17    19
          376  4    3    7.133370        d     2     4
          402  4    8   13.477790        h     7     9
          418  4   13    3.967293        l    12    14
          454  4   18   12.845535        p    17    19
          490  4   23   -1.016839        t    22    24
      

      编辑

      由于您有超过 500 万行,您应该尝试data.table 解决方案:

      library(data.table)
      OBS <- data.table(observations)
      SAM <- data.table(sampletimes)
      merge(OBS,SAM,allow.cartesian=TRUE,by='id')[time > time1 & time < time2]
      

      【讨论】:

      • 最初,此解决方案有效。但是,当我将观察数据框的大小增加到大约 500 万行时,它不起作用。我收到以下错误:Error: evaluation nested too deeply: infinite recursion / options(expressions=)?。我尝试过的所有其他命令都会产生相同的错误消息。
      • @Frank 我编辑我的解决方案以提供 data.table 解决方案。如果您遇到同样的错误,请告诉我。
      • 我的时间是 POSIXlt 格式,但它不起作用,因为 data.table 不支持 POSIXlt。一旦我将时间列转换为 POSIXct,它就起作用了。
      • @Frank 适用于 500 万行?最好使用POSIXct,它是一个数字。 POSIXlt 是一个列表,仅当您想对日期时间进行子集化时才使用它(获取小时、天、月..)
      猜你喜欢
      • 2017-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-05
      相关资源
      最近更新 更多