根据多个条件从后续行中查找值(不带for循环)

时间:2014-11-26 19:08:09

标签: r matching

我有一个包含以下结构的数据列的大型数据框:

    Event   Person_ID   Person_name Current_Result  
1   1       1           Greg        1               
2   1       2           John        2               
3   1       3           Tony        3               
4   2       1           Greg        3               
5   2       2           John        2               
6   2       4           Johanna     1               
7   3       1           Greg        2               
8   3       4           Johanna     1               
9   3       5           Lucy        3               
10  3       6           Mike        4               

我想要做的是在最后添加一列,我可以在下一个事件(事件+ 1)中获得结果,如果该人没有参加下一个事件,则添加NA,如下所示:

    Event   Person_ID   Person_name Current_Result  Next_Result
1   1       1           Greg        1               3
2   1       2           John        2               2
3   1       3           Tony        3               NA
4   2       1           Greg        3               2
5   2       2           John        2               NA
6   2       4           Johanna     1               1
7   3       1           Greg        2               ...
8   3       4           Johanna     1               ...
9   3       5           Lucy        3               ...
10  3       6           Mike        4               ...
...

表中的事件具有不同数量的参与者,并且未订购参与者。所以我需要某种函数来查找每一行是否在事件+ 1中有一个具有相同Person_ID的人并返回相应的Current_Result。

我已经设法使用for循环和子集,但由于表非常大,因此计算需要很长时间。我想知道是否有人知道如何更有效地做到这一点。

2 个答案:

答案 0 :(得分:0)

假设您的data.frame是根据事件订购的:

aux1 <- split(df, df[,1])[-length(unique(df$Event))]
aux2 <- split(df, df[,1])[-1]
df$Next_Rresult <- c(as.vector(mapply(function(x, y) y$Current_Result[match(x$Person_ID, y$Person_ID)], aux1, aux2)), rep(NA, lapply(split(df, df[,1]), dim)[[length(unique(df$Event))]][1]))

df
   Event Person_ID Person_name Current_Result Next_Rresult
1      1         1        Greg              1            3
2      1         2        John              2            2
3      1         3        Tony              3           NA
4      2         1        Greg              3            2
5      2         2        John              2           NA
6      2         4     Johanna              1            1
7      3         1        Greg              2           NA
8      3         4     Johanna              1           NA
9      3         5        Lucy              3           NA
10     3         6        Mike              4           NA

答案 1 :(得分:0)

我考虑扩展数据集以包含EventPerson_ID的所有组合,以便正确制作新列,从而解决了这个问题。我在最后删除了额外的行。

首先,我尝试使用expand函数,如果需要安装,该函数位于 tidyr 包(devtools::install_github("hadley/tidyr"))的开发版本中。这会扩展数据集以包括感兴趣的列的所有组合,然后您可以将其与原始数据集连接,以便为缺少的组合添加行。

我使用的其他功能,包括left_join,来自 dplyr 。对于每个Person_ID,使用mutatelead计算下一个事件的值,然后使用filter删除无关的行。

library(tidyr)
library(dplyr)
dat %>%
    expand(Event, Person_ID) %>% # expand so have all combinations of Person_ID and Event
    left_join(dat) %>% # use left join with original dataset, NA filled in
    group_by(Person_ID) %>%
    mutate(Next_Result = lead(Current_Result, order_by = Event)) %>%
    filter(!is.na(Current_Result))

Source: local data frame [10 x 5]
Groups: Person_ID

   Person_ID Person_name Event Current_Result Next_Result
1          1        Greg     1              1           3
2          2        John     1              2           2
3          3        Tony     1              3          NA
4          1        Greg     2              3           2
5          2        John     2              2          NA
6          4     Johanna     2              1           1
7          1        Greg     3              2          NA
8          4     Johanna     3              1          NA
9          5        Lucy     3              3          NA
10         6        Mike     3              4          NA

我还使用 tidyr 包中的spread添加了缺少的组合,然后重新gather将该数据集恢复为长格式。说实话,这似乎有点笨拙,但确实添加了EventPerson_ID的缺失组合。链的其余部分与以前相同。

dat %>%
    spread(Event, Current_Result) %>% # spread adds in NA if missing combinations
    gather(Event, Current_Result, 3:5) %>% # gather back to long format
    group_by(Person_ID) %>%
    mutate(Next_Result = lead(Current_Result, order_by = Event)) %>%
    filter(!is.na(Current_Result))