R:如果列中的值位于另外两列中可能的值对之间,则每组识别行号

时间:2018-05-03 19:35:03

标签: r

我有一个可能很简单的问题,但我无法理解。我的数据框的一个例子如下:

> df.corrected
   Grp Grp.ind ini.1 fin.1 ini.2 fin.2 
1    A     A.1     0     5     0     5 
2    A     A.2     5    10     5    25 
3    A     A.3    10    15    NA    NA 
4    A     A.4    15    26    NA    NA 
5    A     A.5    26    28    NA    NA 
6    A     A.6    28    30    25    30 
7    B     B.1     0    15     0    10 
8    B     B.2    NA    NA    10    20 
9    B     B.3    15    20    20    25 
10   B     B.4    20    31    25    30 
11   B     B.5    31    50    30    50 

我想在每组中查看每个观察的ini.1在可能的ini.2和fin.2值之间的行数(即ini.2 <= ini.1&lt; fin.2,对于所有人)成对的ini.2,fin.2)。我想知道行号以创建新的grp_ind id。我的愿望输出应该是这样的:

> df.corrected
   Grp Grp.ind ini.1 fin.1 ini.2 fin.2 rownum New.Grp.ind
1    A     A.1     0     5     0     5      1         A.1
2    A     A.2     5    10     5    25      2         A.2
3    A     A.3    10    15    NA    NA      2         A.2
4    A     A.4    15    26    NA    NA      2         A.2
5    A     A.5    26    28    NA    NA      6         A.6
6    A     A.6    28    30    25    30      6         A.6
7    B     B.1     0    15     0    10      1         B.1
8    B     B.2    NA    NA    10    20     NA         B.2
9    B     B.3    15    20    20    25      2         B.2
10   B     B.4    20    31    25    30      3         B.3
11   B     B.5    31    50    30    50      5         B.5

到目前为止,我试过了:

df.corrected<-df %>%
  group_by(Grp) %>%
  mutate(rownum=ifelse(!(ini.1 >=ini.2 & ini.1 < fin.2),
                   NA, row_number())) %>%
  mutate(rownum=ifelse(is.na(rownum),
                   row_number(which((ini.1 >=(ini.2%in%ini.2)) & (ini.1 < (fin.2%in%fin.2)))),rownum)) %>%
  mutate(New.Grp.ind = Grp.ind[rownum])

并且还取出第二个mutate()中的哪个()并且我没有任何成功。因为我的数据帧有超过6k的观测值,所以我想要一个灵活的解决方案而不使用na.locf。之前我尝试过该解决方案,并且在整个数据集中表现不佳。

有没有人就如何解决这个问题提供指导?

我事先感谢你们的帮助。

1 个答案:

答案 0 :(得分:1)

使用dplyr的方法是df.corrected自我加入Grp,然后应用filter来满足OP提到的规则。这将为匹配条件提供New.Grp.ind。最后,对于无法满足匹配规则的行,我们通过right_joindf.correctedGrp联接(使用Grp.ind)。

注意:我假设Grp + Grp.ind在数据中唯一地表示一行。如果没有,则应在数据中添加row number,该数据可以作为right_join的一部分使用。

library(dplyr)

df.corrected %>% inner_join((df.corrected %>% group_by(Grp) %>%
        mutate(rownum= row_number())), by="Grp") %>%
  filter(ini.1.x >=ini.2.y & ini.1.x < fin.2.y) %>%
  select( Grp, Grp.ind = Grp.ind.x, ini.1 = ini.1.x, fin.1 = fin.1.x, ini.2 = ini.2.x, 
           fin.2 = fin.2.x, rownum, New.Grp.ind = Grp.ind.y) %>%
  right_join(df.corrected, by=c("Grp","Grp.ind")) %>%
  select( Grp, Grp.ind, ini.1 = ini.1.x, fin.1 = fin.1.x, ini.2 = ini.2.x, fin.2 = fin.2.x,
         rownum, New.Grp.ind) %>%
  mutate(New.Grp.ind = coalesce(New.Grp.ind, Grp.ind))

#    Grp Grp.ind ini.1 fin.1 ini.2 fin.2 rownum New.Grp.ind
# 1    A     A.1     0     5     0     5      1         A.1
# 2    A     A.2     5    10     5    25      2         A.2
# 3    A     A.3    10    15    NA    NA      2         A.2
# 4    A     A.4    15    26    NA    NA      2         A.2
# 5    A     A.5    26    28    NA    NA      6         A.6
# 6    A     A.6    28    30    25    30      6         A.6
# 7    B     B.1     0    15     0    10      1         B.1
# 8    B     B.2    NA    NA    NA    NA     NA         B.2
# 9    B     B.3    15    20    20    25      2         B.2
# 10   B     B.4    20    31    25    30      3         B.3
# 11   B     B.5    31    50    30    50      5         B.5

数据:

df.corrected <- read.table(text = 
"Grp Grp.ind ini.1 fin.1 ini.2 fin.2 
1    A     A.1     0     5     0     5 
2    A     A.2     5    10     5    25 
3    A     A.3    10    15    NA    NA 
4    A     A.4    15    26    NA    NA 
5    A     A.5    26    28    NA    NA 
6    A     A.6    28    30    25    30 
7    B     B.1     0    15     0    10 
8    B     B.2    NA    NA    10    20 
9    B     B.3    15    20    20    25 
10   B     B.4    20    31    25    30 
11   B     B.5    31    50    30    50",
header = TRUE, stringsAsFactors = FALSE)