我正在训练自己在R中的循环和函数(但目前处于一个非常基本的水平)。对于最近的一项研究,我需要准备如下数据:
我有一个如下所示的数据集:
dd <- read.table(text="
event.timeline.ys ID year group
1 2 800033 2008 A
2 1 800033 2009 A
3 0 800033 2010 A
4 -1 800033 2011 A
5 -2 800033 2012 A
15 0 800076 2008 B
16 -1 800076 2009 B
17 5 800100 2014 C
18 4 800100 2015 C
19 2 800100 2017 C
20 1 800100 2018 C
30 0 800125 2008 A
31 -1 800125 2009 A
32 -2 800125 2010 A", header=TRUE)
我想为每个人保留最后一行event.timeline.ys> = 0(这将是ID 800033的第3行)和第一行event.timeline.ys <0(这将是第4行ID 800033)。将删除所有其他行。因此,我的最终数据框每个ID只包含两行。
ID = 800100的人在event.timeline.ys上没有任何负值。在这种情况下,我想只保留event.timeline.ys> = 0的最后一行。
最终的数据集如下所示:
event.timeline.ys ID year group
3 0 800033 2010 A
4 -1 800033 2011 A
15 0 800076 2008 B
16 -1 800076 2009 B
20 1 800100 2018 C
30 0 800125 2008 A
31 -1 800125 2009 A
我想过使用for循环在每个ID中检查event.timeline.ys> = 0的最后一行和event.timeline.ys <0的第一行是什么。但是,R中的实际实现失败了。
有没有人有聪明的建议?我也对其他不基于for循环或类似东西的解决方案持开放态度。
这是在dplyr中使用group_by
的一个选项:
dd %>% group_by(ID, category = event.timeline.ys >= 0) %>%
filter(abs(event.timeline.ys) == min(abs(event.timeline.ys))) %>%
dplyr::select(-category) %>%
as.data.frame
category event.timeline.ys ID year group
1 TRUE 0 800033 2010 A
2 FALSE -1 800033 2011 A
3 TRUE 0 800076 2008 B
4 FALSE -1 800076 2009 B
5 TRUE 1 800100 2018 C
6 TRUE 0 800125 2008 A
7 FALSE -1 800125 2009 A
由ID
分组,以及event.timesline.ys
是否为负数。如果是负数,则选择(slice
)第一行,否则选择最后一行(即行n()
)。
library(dplyr)
dd %>%
mutate(neg = event.timeline.ys < 0) %>%
group_by(ID, neg) %>%
slice(if(neg[1]) 1 else n()) %>%
ungroup %>%
select(-neg)
# # A tibble: 7 x 4
# event.timeline.ys ID year group
# <int> <int> <int> <fct>
# 1 0 800033 2010 A
# 2 -1 800033 2011 A
# 3 0 800076 2008 B
# 4 -1 800076 2009 B
# 5 1 800100 2018 C
# 6 0 800125 2008 A
# 7 -1 800125 2009 A
这是一种使用which()
和row_number()
提取您感兴趣的行的索引的方法
library(dplyr)
dd %>%
group_by(ID) %>%
filter(row_number() == last(which(event.timeline.ys >= 0)) |
row_number() == first(which(event.timeline.ys < 0)))
我认为阅读的好处类似于你用文字描述自己的方式,所以希望这是有道理的。
这是在data.table
做到这一点的方法
library(data.table)
as.data.table(dd)[, .SD[c(last(which(event.timeline.ys >= 0)),
first(which(event.timeline.ys < 0)))],
by=ID]
ID event.timeline.ys year group
1: 800033 0 2010 A
2: 800033 -1 2011 A
3: 800076 0 2008 B
4: 800076 -1 2009 B
5: 800100 1 2018 C
6: 800125 0 2008 A
7: 800125 -1 2009 A