tidyverse:根据其他行中的值从数据框中删除行
tidyverse: removing rows from data frame on basis of values in other rows
我有一堆调查数据。每行代表一次采访 "respondent." 一些受访者被采访过一次;其他人接受了多次采访。我想select,从这个tibble,只有每个受访者的最后一次采访。
这是一个最小的例子:
tmp <- tribble(
~YYYYMM, ~ID, ~DATEPR, ~IDPREV,
198001, 1, NA, NA,
198001, 2, NA, NA,
198001, 3, NA, NA,
198002, 1, 198001, 1,
198002, 2, NA, NA,
198002, 3, NA, NA,
198003, 1, 198002, 1,
198003, 2, NA, NA,
198003, 3, 198002, 3)
其中
YYYYMM
是面试日期。
DATEPR
是受访者上一次访谈的日期,如果有的话。
ID
仅在面试波中是唯一的。这意味着,例如,ID==2
和 YYYMM==198001
的受访者不必是 ID==2
和 YYYMM==198002
.
[=45= 的受访者]
IDPREV
是受访者上次采访的ID,如果有的话。
上面的标题中有九行。但是一位受访者被采访了三次,另一位受访者被采访了两次。我只想要每个受访者的最后一次采访,所以我想要一个只有六行的小标题。此代码完成工作:
for (i in 1:nrow(tmp)) {
if (!is.na(tmp$DATEPR[i])) {
ind <- which(tmp$YYYYMM == tmp$DATEPR[i] & tmp$ID == tmp$IDPREV[i])
tmp <- tmp[-ind, ]
}
}
不过好像有点难解析。是否有更清晰的方法来使用 tidyverse 函数实现相同的目的?我想到了一个两步函数:首先,获取要删除的所有行的索引;第二,删除行。但是我无法使用 map
或 dplyr
函数实现此解决方案。
如果所有之前采访过的 ID 都列在第 3 和第 4 列,您可以使用 dplyr::anti_join
对数据框进行 left anti_join ],在这里你将 DATEPR
和 IDPREV
分别与 YYYYMM
和 ID
匹配,只有来自 temp
的 YYYYMM
和 ID
的行] 没有匹配的将被保留:
anti_join(tmp, tmp, by = c("YYYYMM" = "DATEPR", "ID" = "IDPREV")) %>%
arrange(YYYYMM, ID)
# A tibble: 6 x 4
# YYYYMM ID DATEPR IDPREV
# <dbl> <dbl> <dbl> <dbl>
#1 198001 2 NA NA
#2 198001 3 NA NA
#3 198002 2 NA NA
#4 198003 1 198002 1
#5 198003 2 NA NA
#6 198003 3 198002 3
在 运行 你的代码之后:
for (i in 1:nrow(tmp)) {
if (!is.na(tmp$DATEPR[i])) {
ind <- which(tmp$YYYYMM == tmp$DATEPR[i] & tmp$ID == tmp$IDPREV[i])
tmp <- tmp[-ind, ]
}
}
tmp %>% arrange(YYYYMM, ID)
# A tibble: 6 x 4
# YYYYMM ID DATEPR IDPREV
# <dbl> <dbl> <dbl> <dbl>
#1 198001 2 NA NA
#2 198001 3 NA NA
#3 198002 2 NA NA
#4 198003 1 198002 1
#5 198003 2 NA NA
#6 198003 3 198002 3
我有一堆调查数据。每行代表一次采访 "respondent." 一些受访者被采访过一次;其他人接受了多次采访。我想select,从这个tibble,只有每个受访者的最后一次采访。
这是一个最小的例子:
tmp <- tribble(
~YYYYMM, ~ID, ~DATEPR, ~IDPREV,
198001, 1, NA, NA,
198001, 2, NA, NA,
198001, 3, NA, NA,
198002, 1, 198001, 1,
198002, 2, NA, NA,
198002, 3, NA, NA,
198003, 1, 198002, 1,
198003, 2, NA, NA,
198003, 3, 198002, 3)
其中
YYYYMM
是面试日期。DATEPR
是受访者上一次访谈的日期,如果有的话。
[=45= 的受访者]ID
仅在面试波中是唯一的。这意味着,例如,ID==2
和YYYMM==198001
的受访者不必是ID==2
和YYYMM==198002
.IDPREV
是受访者上次采访的ID,如果有的话。
上面的标题中有九行。但是一位受访者被采访了三次,另一位受访者被采访了两次。我只想要每个受访者的最后一次采访,所以我想要一个只有六行的小标题。此代码完成工作:
for (i in 1:nrow(tmp)) {
if (!is.na(tmp$DATEPR[i])) {
ind <- which(tmp$YYYYMM == tmp$DATEPR[i] & tmp$ID == tmp$IDPREV[i])
tmp <- tmp[-ind, ]
}
}
不过好像有点难解析。是否有更清晰的方法来使用 tidyverse 函数实现相同的目的?我想到了一个两步函数:首先,获取要删除的所有行的索引;第二,删除行。但是我无法使用 map
或 dplyr
函数实现此解决方案。
如果所有之前采访过的 ID 都列在第 3 和第 4 列,您可以使用 dplyr::anti_join
对数据框进行 left anti_join ],在这里你将 DATEPR
和 IDPREV
分别与 YYYYMM
和 ID
匹配,只有来自 temp
的 YYYYMM
和 ID
的行] 没有匹配的将被保留:
anti_join(tmp, tmp, by = c("YYYYMM" = "DATEPR", "ID" = "IDPREV")) %>%
arrange(YYYYMM, ID)
# A tibble: 6 x 4
# YYYYMM ID DATEPR IDPREV
# <dbl> <dbl> <dbl> <dbl>
#1 198001 2 NA NA
#2 198001 3 NA NA
#3 198002 2 NA NA
#4 198003 1 198002 1
#5 198003 2 NA NA
#6 198003 3 198002 3
在 运行 你的代码之后:
for (i in 1:nrow(tmp)) {
if (!is.na(tmp$DATEPR[i])) {
ind <- which(tmp$YYYYMM == tmp$DATEPR[i] & tmp$ID == tmp$IDPREV[i])
tmp <- tmp[-ind, ]
}
}
tmp %>% arrange(YYYYMM, ID)
# A tibble: 6 x 4
# YYYYMM ID DATEPR IDPREV
# <dbl> <dbl> <dbl> <dbl>
#1 198001 2 NA NA
#2 198001 3 NA NA
#3 198002 2 NA NA
#4 198003 1 198002 1
#5 198003 2 NA NA
#6 198003 3 198002 3