【问题标题】:Conditional selection of repeated measures from data frame从数据框中有条件地选择重复测量
【发布时间】:2019-05-02 23:05:51
【问题描述】:

我有在可变数量的时间点对每个受试者 (id) 进行重复测量的数据。我想为每个主题保留两行,时间点 == 0 和最接近 4 的时间点。如果有两个候选时间点与 4 等距的行,例如(3, 5),我要选最低的 (3)。

如下图的“选择”列所示,带有“x”的行将不会被保留。

 dat <- structure(list(id = c(172507L, 172507L, 172507L, 172525L, 172525L, 
172525L, 172526L, 172526L, 172526L, 172527L, 172527L, 172527L, 
172527L, 172527L), timepoint = c(0L, 2L, 6L, 0L, 4L, 5L, 0L, 
5L, 2L, 2L, 3L, 5L, 6L, 0L)), class = "data.frame", row.names = c(NA, 
-14L))

【问题讨论】:

  • id = 172528的单个实例保留timepoint = 3,但为172529的单个实例丢弃timepoint = 5或@987654329的单个实例丢弃timepoint = 6的逻辑是什么@ ?
  • 我也很困惑。为什么要丢弃 id = 172529id = 172530 的单个测量值?
  • 我相信现在的数据与图像的前两列相符。

标签: r dplyr data.table


【解决方案1】:

我们可以通过idtimepointarrange,并为每个组选择timepoint == 0 时的第一次出现和4 - timepoint 之间的最小绝对值。由于我们已将其按timepoint 排列,因此which.min 将首先选择具有较低值的timepoint(以防平局)。

library(dplyr)
dat %>%
  arrange(id, timepoint) %>%
  group_by(id) %>%
  slice(c(which.max(timepoint == 0), which.min(abs(4- timepoint))))

#     id timepoint
#   <int>     <int>
#1 172507         0
#2 172507         2
#3 172525         0
#4 172525         4
#5 172526         0
#6 172526         5
#7 172527         0
#8 172527         3

【讨论】:

  • 不错的一个。有没有比which.max(timepoint == 0) 更简洁的论点?
  • @cardinal40 which.max(timepoint == 0) 有什么“不干净”的地方?确实是非常简洁的解决方案 +1。
  • @cardinal40 你可以做which(timepoint == 0)[1] 但这绝对不是更干净。
  • 如果您确定每个 ID 的时间点都是 0,则可以将其替换为 1,因为您安排了数据集。 slice(c(1, which.min...)
  • @Cole 是的,很好,但为此我们还需要确保timepoint 列中没有负数。
【解决方案2】:

你能做这样的事情吗?按距离排列,然后时间点将最小的最接近的值放在第一位。然后您可以使用first() 函数来获取第一个值或过滤时间点为零的时间。

library(tidyverse)

dat %>% 
  mutate(dist = abs(4-timepoint)) %>% 
  arrange(id, dist, timepoint) %>% 
  group_by(id) %>% 
  filter(timepoint %in% c(0, first(timepoint))) %>% 
  ungroup() %>% 
  arrange(id, timepoint)

【讨论】:

    【解决方案3】:

    这是data.table 解决方案。它依赖于每个 ID 的时间点为 0 的假设。否则,您应该使用which.max(timepoint == 0)。感谢 Ronak Shah 的 which.min 方法。

    编辑: 更改为 match(TRUE, timepoint == 0) 并修复了基本 R 方法中的问题。

    library(data.table)
    
    dt <- as.data.table(dat)
    
    dt[order(timepoint),
     .SD[c(match(TRUE, timepoint == 0), which.min(abs(4- timepoint)))],
     by = id]
    

    为了踢球,这里是基础 R:

    do.call(rbind, by(dat[order(dat$timepoint), ], dat[order(dat$timepoint), ], function(x) x[c(match(TRUE, x$timepoint == 0), which.min(abs(4-x$timepoint))),]) )
    

    【讨论】:

      【解决方案4】:

      这样的事情应该可以工作:

      zeros <- 
        dat %>% 
        filter(timepoint == 0) %>% 
        transmute(id, timepoint)
      
      nonzeros <- 
        dat %>% 
        filter(timepoint != 0) %>% 
        mutate(diff = abs(timepoint - 4)) %>% 
        group_by(id) %>% 
        filter(diff == min(diff)) %>% 
        arrange(timepoint) %>% 
        slice(1) %>% 
        ungroup() %>% 
        transmute(id, timepoint)
      
      df <-
        bind_rows(zeros, nonzeros) %>% 
        arrange(id, timepoint)
      

      可能有一种方法可以在一个管道中执行此操作,但我更容易想象这种方式发生了什么。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-24
        相关资源
        最近更新 更多