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))
您好,我正在寻找一种 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' 的第二种情况(根据代码不清楚正在执行哪种操作)。遍历数据行序列后,用 [[
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))