R 数据帧中重复测量的条件选择

R 数据帧中重复测量的条件选择,r,dplyr,data.table,R,Dplyr,Data.table,我有在不同时间点重复测量每个受试者(id)的数据。我想为每个主题保留两行,时间点==0和最接近4的时间点。对于两个候选时间点距离4相等的行,例如(3,5),我希望选择最低的(3) 如下图的“选择”列所示,带有“x”的行将不会保留 dat <- structure(list(id = c(172507L, 172507L, 172507L, 172525L, 172525L, 172525L, 172526L, 172526L, 172526L, 172527L, 172527L, 17

我有在不同时间点重复测量每个受试者(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))

dat像这样的东西应该可以工作:

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)
0%
筛选器(时间点==0)%>%
转换(id,时间点)
非零%
过滤器(时间点!=0)%>%
变异(差异=绝对值(时间点-4))%>%
分组依据(id)%>%
过滤器(差异==最小(差异))%>%
排列(时间点)%>%
切片(1)%>%
解组()%>%
转换(id,时间点)
df%
安排(id、时间点)

也许有一种方法可以在一个管道中完成这项工作,但我可以更轻松地想象出这种方式会发生什么。

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

库(tidyverse)
dat%>%
突变(dist=abs(4时间点))%>%
排列(id、距离、时间点)%>%
分组依据(id)%>%
筛选器(时间点%在%c中(0,第一个(时间点)))%>%
解组()%>%
安排(id、时间点)

我们可以
id
timepoint
排列
,并为每组选择
timepoint==0
时的第一次出现,以及
4-timepoint
之间的最小绝对值。由于我们已按
时间点
排列,因此.min
将首先选择值较低的
时间点
(如果是平局)

库(dplyr)
dat%>%
排列(id,时间点)%>%
分组依据(id)%>%
切片(c(哪个.max(timepoint==0),哪个.min(abs(4-timepoint)))
#id时间点
#        
#1 172507         0
#2 172507         2
#3 172525         0
#4 172525         4
#5 172526         0
#6 172526         5
#7 172527         0
#8 172527         3

以下是
数据表
解决方案。它依赖于每个ID的时间点为0的假设。否则,您应该使用
which.max(timepoint==0)
。归功于Ronak Shah的which.min方法

library(data.table)

dt <- as.data.table(dat)

dt[order(timepoint),
 .SD[c(match(TRUE, timepoint == 0), which.min(abs(4- timepoint)))],
 by = id]
编辑:更改为
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]

对于
id=172528
的单个实例,保留
timepoint=3
,但是对于
172529
的单个实例,放弃
timepoint=5
,或者对于
172530
的单个实例,放弃
timepoint=6
的逻辑是什么?我也感到困惑。为什么要放弃id=172529和id=172530的单个测量值?我相信数据现在与图像的前两列匹配,正如预期的那样。很好。有比
which.max(timepoint==0)
更干净的参数吗?@cardinal40关于
which.max(timepoint==0)
什么是“不干净的”?非常简洁的解决方案的确是+1。@您可以做
哪个(timepoint==0)[1]
,但这绝对不是一个更干净的解决方案。如果您确定每个ID都有一个时间点0,您可以将其替换为1,因为您安排了数据集<代码>切片(c(1,which.min…)
@Cole是的,非常好,但为此,我们还需要确保
时间点
列中没有负数。
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))),]) )