R / Tidyverse:面板数据在所有 waves 中找到幸存的 ID

R / Tidyverse: Panel data find surviving IDs over all waves

您好,我正在寻找一种 tidyverse 方法来查找符合以下条件的 ID(观察) 出现在每一波中。

详细说明手头的数据:
我们有多个包含 ID 和附加测量值的 waves (>20)。
出于示例目的,这里是我们手头数据的模拟:

pacman::p_load(tidyverse)
wave1 <- tibble(
  id = seq_along(1:100),
  x = runif(100, 0, 100)
)
# In wave2 some observations drop out & some new observations are added
wave2 <- tibble(
  id = seq_along(1:150),
  x = runif(150, 0, 100)
)
# Simulation of Dropout
wave2 %>%
  filter(!id %in% sample(1:150, 23)) -> wave2

# Same with Wave 3
wave3 <- tibble(
  id = c(wave2 %>% pull(id),151:200),
  x = runif(nrow(wave2) + 50, 0, 100)
)
# Simulation of Dropout
wave3 %>%
  filter(!id %in% sample(1:200, 33)) -> wave3

我正在寻找一种方便的方法来查找 Wave1 中的哪些 ID 存在于所有其他 wave 中(在示例中仅 wave2 和 3)。以及 Wave2 中有多少个 ID 存在于所有后续 wave 中(在示例中仅 wave3)。

解决方案(写了很多功夫)

inner_join

是一个简单的解决方案,需要大量的编写工作才能解决这么多波
### Solution
wave1 %>% 
  inner_join(wave2, by = "id") %>% 
  nrow() # = 83

wave1 %>% 
  inner_join(wave3, by = "id") %>% 
  nrow() # = 68

但这似乎是不必要的重复。特别是如果你有超过 20 波。 waves 始终遵循相同的命名:“wave”后跟最多 2 位数字(例如“wave16”)。 是否可以使用名称的字符向量(例如 waves <- c("wave1","wave2","wave3"))以及 for 循环和 eval 语句的组合?或者使用 data.frames 和 lapply?

的列表

解决它的进一步想法

我认为像嵌套小标题这样的结构可以帮助解决这个问题。
这样我就可以遍历行。

这是嵌套小标题的模拟

wave1 %>% write.csv(file = "wave1.csv")
wave2 %>% write.csv(file = "wave2.csv")
wave3 %>% write.csv(file = "wave3.csv")

files <- dir( pattern = "^wave\d+.csv")
data <- tibble(filename = files) %>%
  mutate(file_content = map(filename, ~ read_delim(file.path(.x)))) %>%
  mutate(df =  str_extract(filename,"wave\d+")) %>%
  relocate(df, .before = filename)
data

嵌套的 tibble 会是什么样子

但是我坚持使用 pull 和取消嵌套 data.frames,因为拉会给我列表,而 unlist 确实弄乱了结构。我也不太确定 for-loop 以 tidyverse 方法遍历行

for (i in 1:nrow(data)) {
  data[i,] %>% 
    pull(file_content)
}

我们可以循环执行此操作。使用 mget 获取 list 中感兴趣的对象的值(使用 paste 因为我们只需要 'wave2'、'wave3' 而不是 'wave1' - 或者也可以使用 ls(pattern = '^wave\d+$') 自动执行此操作,但它可能不太灵活 - 也可以使用 ls(pattern = '^wave[2-3]$'),但这可能会在 wave10 等中变得混乱..)

library(dplyr)
library(purrr)
mget(paste0('wave', 2:3)) %>% 
   map( ~ wave1 %>% 
             inner_join(.x, by = "id") %>% 
             nrow)
$wave2
[1] 85

$wave3
[1] 69

对于 'data' 的第二种情况(根据代码不清楚正在执行哪种操作)。遍历数据行序列后,用 [[

提取 'file_content' list 元素
for(i in seq_len(nrow(data))) {
    print(data$file_content[[i]])
}

通过 tidyverse 方法,我们可以使用 rowwise

访问数据
data %>%
    rowwise %>%
    mutate(out = yourfun(file_content))

或者用map

library(purrr)
data %>%
    mutate(out = map(file_content, yourfun))