【问题标题】:Conditional statement referencing separate rows引用单独行的条件语句
【发布时间】:2018-08-29 00:55:42
【问题描述】:
data.frame(id = rep(letters[1:2], each  = 8), examID = as.character(c(11,11:17, 21:28)), baselineExam = c(rep(c(rbind('bl',c(11,14))), each = 2), c(rep('bl', 4), 21, 21, 24, 24)), examType = c("x", "x", "fu", "fu", "y", "z", "fu", "fu", "x", "x", "y", "z", "fu", "fu", "fu", "fu"), expected_col = c("x", "x", "x", "x", "y", "z", "y", "y", "x", "x", "y", "z", "x", "x", "z", "z"))

# the first four columns are my original data frame
# the last column shows the expected output.     

    id examID baselineExam examType expected_col
1   a     11           bl        x            x
2   a     11           bl        x            x
3   a     12           11       fu            x
4   a     13           11       fu            x
5   a     14           bl        y            y
6   a     15           bl        z            z
7   a     16           14       fu            y
8   a     17           14       fu            y
9   b     21           bl        x            x
10  b     22           bl        x            x
11  b     23           bl        y            y
12  b     24           bl        z            z
13  b     25           21       fu            x
14  b     26           21       fu            x
15  b     27           24       fu            z
16  b     28           24       fu            z

每个科目 (id) 都有不同类型的纵向考试 (examType)。每项考试都有其唯一标识符 (examID)。只有基线检查包含 Examtype 的信息。 后续考试仅包含信息“fu”,但不包含正确的考试类型。但是,baselineExam 列显示了哪个是相应跟进的基线检查。我想在每一行中有一个包含正确examType 的列。 (见数据框中的expected_col

我被困住了。我不能将if(baselineExam %in% examID) 之类的东西与any 结合使用,因为没有可以根据这些组来区分这些考试的组。

一种方法是获取相应“fu”的行的索引,在“baselineExam”中查找这是哪个值,然后在“examID”中查找该数字以获取该行的examType .

我尝试了一个带有索引号的辅助列(也必须有更好的方法),我可以在这一行中获取基线检查的值 - 但我不知道如何有条件地获取值考试类型,当考试ID(基线行)==基线考试(后续行)时。

首选基本 R 解决方案或 dplyr,但对任何东西都开放


编辑

我已经更改了给定的数据,因为我之前的示例数据没有完全反映真实数据的复杂性(我过度简化了它)。不幸的是,@www 和 @akrun 的解决方案都不起作用 - 我的错,因为我没有提供足够好的样本:( 每个考试 ID 可以有多行(长数据,在我的示例中为第 1 行和第 2 行),并且在进行后续考试之前,一个接一个地进行了多个基线考试。

【问题讨论】:

  • data.table 解决方案怎么样?这种事情急需更新加入。
  • @thelatemail 我有点怀疑。我只是从未真正使用过 data.table 并且对 dplyr 更加熟悉和精通,这有点糟糕的原因......

标签: r dplyr


【解决方案1】:

使用dplyrtidyr 包的解决方案。关键是将fu替换为NA,然后使用fill函数将NA填上前一行。 mutate_if 只是将因子列转换为字符列。 dat2 是最终输出。

library(dplyr)
library(tidyr)

dat2 <- dat %>%
  mutate_if(is.factor, as.character) %>%
  mutate(type = ifelse(examType %in% "fu", NA, examType)) %>%
  fill(type)
dat2
#   id examID baselineExam examType type
# 1  a     11           bl        x    x
# 2  a     12           11       fu    x
# 3  a     13           bl        y    y
# 4  a     14           13       fu    y
# 5  b     21           bl        x    x
# 6  b     22           21       fu    x
# 7  b     23           bl        z    z
# 8  b     24           23       fu    z

更新

我们可以使用dplyr 包来实现这一点。首先,用已知的examType对数据框进行子集化,找到idexamIDexamType之间唯一组合的行,将表连接到原始数据框,并使用coalesce组合信息.

library(dplyr)

dat2 <- dat %>%
  filter(!examType %in% "fu") %>%
  distinct(id, examID, examType) %>%
  rename(Type = examType) %>%
  left_join(dat, ., by = c("id", "baselineExam" = "examID")) %>%
  mutate(Type = coalesce(Type, examType))

dat2
#    id examID baselineExam examType Type
# 1   a     11           bl        x    x
# 2   a     11           bl        x    x
# 3   a     12           11       fu    x
# 4   a     13           11       fu    x
# 5   a     14           bl        y    y
# 6   a     15           bl        z    z
# 7   a     16           14       fu    y
# 8   a     17           14       fu    y
# 9   b     21           bl        x    x
# 10  b     22           bl        x    x
# 11  b     23           bl        y    y
# 12  b     24           bl        z    z
# 13  b     25           21       fu    x
# 14  b     26           21       fu    x
# 15  b     27           24       fu    z
# 16  b     28           24       fu    z

更新示例的数据

dat <- data.frame(id = rep(letters[1:2], each  = 8), 
                  examID = as.character(c(11,11:17, 21:28)), 
                  baselineExam = c(rep(c(rbind('bl',c(11,14))), each = 2), c(rep('bl', 4), 21, 21, 24, 24)), 
                  examType = c("x", "x", "fu", "fu", "y", "z", "fu", "fu", "x", "x", "y", "z", "fu", "fu", "fu", "fu"),
                  stringsAsFactors = FALSE)

【讨论】:

  • 也许你可以更新一个 zoo:: na.locf :-) 懒得发布答案。 :-)
  • @Wen 谢谢。有时间我会更新我的帖子。
  • 谢谢!我不知道fill,这似乎很有趣。对于我的示例问题,这似乎是一个非常好的解决方案,但可能不适用于我的真实数据,因为每次考试我有很多行。我意识到我应该在问题中指定这一点。我会尝试这种方式,如果它不起作用将更新问题。
  • 我已经更新了我的问题。为误导性样本道歉:(
  • 非常感谢。我不知道coalesce。首先找到独特的组合并使用此信息非常好。
【解决方案2】:

一种选择是按“id”分组并根据“bl”的出现创建一个分组变量,将“type”创建为与“baselineExam”中的“bl”对应的“examType”

library(dplyr)
df1 %>% 
    group_by(id, grp = cumsum(baselineExam == 'bl')) %>% 
    mutate(type = examType[baselineExam == 'bl']) %>% 
    ungroup %>% 
    select(-grp)
# A tibble: 8 x 5
#  id    examID baselineExam examType type 
#  <fct> <fct>  <fct>        <fct>    <fct>
#1 a     11     bl           x        x    
#2 a     12     11           fu       x    
#3 a     13     bl           y        y    
#4 a     14     13           fu       y    
#5 b     21     bl           x        x    
#6 b     22     21           fu       x    
#7 b     23     bl           z        z    
#8 b     24     23           fu       z    

【讨论】:

  • 谢谢!这是使用cumsum 的一种超级有趣的方式,它可能是要走的路,似乎比@www 的答案更安全。然而,和以前一样,不幸的是,我的例子还不够好。这不考虑后续检查没有立即跟随基线检查的情况。我会更新我的数据。
  • @Tjebo 您的新更新示例仍然给了我预期的输出。可能是,这个例子需要改变
  • 不幸的是,它没有给出预期的输出。例如,第 7:8 行和第 13:14 行不同
猜你喜欢
  • 2013-10-09
  • 1970-01-01
  • 2016-06-03
  • 2019-10-14
  • 1970-01-01
  • 2021-10-08
  • 1970-01-01
  • 1970-01-01
  • 2019-02-05
相关资源
最近更新 更多