估计面板中随时间推移的公共集合成员的百分比
Estimating the percentage of common set members over time in a panel
我有一个时间序列面板数据集,其结构如下:有 2 只基金在每个时间段各自拥有不同的股票。
df <- data.frame(
fund_id = c(1,1,1,1,1,1,1,1, 1, 2,2,2,2),
time_Q = c(1,1,1,2,2,2,2,3, 3, 1,1,2,2),
stock_id = c("A", "B", "C", "A", "C", "D", "E", "D", "E", "A", "B", "B", "C")
)
> df
fund_id time_Q stock_id
1 1 1 A
2 1 1 B
3 1 1 C
4 1 2 A
5 1 2 C
6 1 2 D
7 1 2 E
8 1 3 D
9 1 3 E
10 2 1 A
11 2 1 B
12 2 2 B
13 2 2 C
对于每个基金,我想计算当前 time_Q 持有的股票在前一到两个季度持有的百分比。所以基本上对于每个基金和每个 time_Q,我想有 2 列过去 1 time_Q,过去 2 time_Q 显示当时持有的股票百分比也存在于每一个过去的 time_Q 年代。
结果应该是这样的:
result <- data.frame(
fund_id = c(1,1,1,2,2),
time_Q = c(1,2,3,1,2),
past_1Q = c("NA",0.5,1,"NA",0.5),
past_2Q = c("NA","NA",0,"NA","NA")
)
> result
fund_id time_Q past_1Q past_2Q
1 1 1 NA NA
2 1 2 0.5 NA
3 1 3 1 0
4 2 1 NA NA
5 2 2 0.5 NA
我目前正在考虑使用 setdiff 或 intersect 函数,但我不确定如何在面板数据集中设置格式。我正在寻找一个可扩展的 dplyr 或 data.table 解决方案,它能够涵盖多个基金、股票和时间段,并且还可以研究多达 12 个滞后时间段中的共同元素。我将不胜感激任何帮助,因为我已经在这个问题上停留了很长一段时间。
我们可以使用 dplyr
和 purrr
以编程方式建立一个滞后的所有权变量,然后 summarize()
使用 across()
跨越所有这些变量。首先,我们只需要一个所有权虚拟变量,并按基金和股票对数据进行分组。
library(dplyr)
library(purrr)
df_grouped <- df %>%
mutate(owned = TRUE) %>%
group_by(fund_id, stock_id)
然后我们可以生成每个股票的滞后所有权,基于time_Q
,将它们全部连接在一起,并且对于每个基金和time_Q
,计算所有权比例。
map(
1:2,
~df_grouped %>%
mutate(
"past_{.x}Q" := lag(owned, n = .x, order_by = time_Q)
)
) %>%
reduce(left_join, by = c("fund_id", "stock_id", "time_Q", "owned")) %>%
group_by(fund_id, time_Q) %>%
summarize(
across(
starts_with("past"),
~if (all(is.na(.x))) NA else sum(.x, na.rm = T) / n()
)
)
#> # A tibble: 5 × 4
#> fund_id time_Q past_1Q past_2Q
#> <dbl> <dbl> <dbl> <lgl>
#> 1 1 1 NA NA
#> 2 1 2 0.5 NA
#> 3 1 3 1 NA
#> 4 2 1 NA NA
#> 5 2 2 0.5 NA
这是一个 dplyr-only 解决方案:
library(dplyr)
df %>%
group_by(fund_id, time_Q) %>%
summarise(new = list(stock_id)) %>%
mutate(past_1Q = lag(new, 1),
past_2Q = lag(new, 2)) %>%
rowwise() %>%
transmute(time_Q,
across(past_1Q:past_2Q, ~ length(intersect(new, .x)) / length(new)))
输出
fund_id time_Q past_1Q past_2Q
<dbl> <dbl> <dbl> <dbl>
1 1 1 0 0
2 1 2 0.5 0
3 1 3 1 0
4 2 1 0 0
5 2 2 0.5 0
我有一个时间序列面板数据集,其结构如下:有 2 只基金在每个时间段各自拥有不同的股票。
df <- data.frame(
fund_id = c(1,1,1,1,1,1,1,1, 1, 2,2,2,2),
time_Q = c(1,1,1,2,2,2,2,3, 3, 1,1,2,2),
stock_id = c("A", "B", "C", "A", "C", "D", "E", "D", "E", "A", "B", "B", "C")
)
> df
fund_id time_Q stock_id
1 1 1 A
2 1 1 B
3 1 1 C
4 1 2 A
5 1 2 C
6 1 2 D
7 1 2 E
8 1 3 D
9 1 3 E
10 2 1 A
11 2 1 B
12 2 2 B
13 2 2 C
对于每个基金,我想计算当前 time_Q 持有的股票在前一到两个季度持有的百分比。所以基本上对于每个基金和每个 time_Q,我想有 2 列过去 1 time_Q,过去 2 time_Q 显示当时持有的股票百分比也存在于每一个过去的 time_Q 年代。 结果应该是这样的:
result <- data.frame(
fund_id = c(1,1,1,2,2),
time_Q = c(1,2,3,1,2),
past_1Q = c("NA",0.5,1,"NA",0.5),
past_2Q = c("NA","NA",0,"NA","NA")
)
> result
fund_id time_Q past_1Q past_2Q
1 1 1 NA NA
2 1 2 0.5 NA
3 1 3 1 0
4 2 1 NA NA
5 2 2 0.5 NA
我目前正在考虑使用 setdiff 或 intersect 函数,但我不确定如何在面板数据集中设置格式。我正在寻找一个可扩展的 dplyr 或 data.table 解决方案,它能够涵盖多个基金、股票和时间段,并且还可以研究多达 12 个滞后时间段中的共同元素。我将不胜感激任何帮助,因为我已经在这个问题上停留了很长一段时间。
我们可以使用 dplyr
和 purrr
以编程方式建立一个滞后的所有权变量,然后 summarize()
使用 across()
跨越所有这些变量。首先,我们只需要一个所有权虚拟变量,并按基金和股票对数据进行分组。
library(dplyr)
library(purrr)
df_grouped <- df %>%
mutate(owned = TRUE) %>%
group_by(fund_id, stock_id)
然后我们可以生成每个股票的滞后所有权,基于time_Q
,将它们全部连接在一起,并且对于每个基金和time_Q
,计算所有权比例。
map(
1:2,
~df_grouped %>%
mutate(
"past_{.x}Q" := lag(owned, n = .x, order_by = time_Q)
)
) %>%
reduce(left_join, by = c("fund_id", "stock_id", "time_Q", "owned")) %>%
group_by(fund_id, time_Q) %>%
summarize(
across(
starts_with("past"),
~if (all(is.na(.x))) NA else sum(.x, na.rm = T) / n()
)
)
#> # A tibble: 5 × 4
#> fund_id time_Q past_1Q past_2Q
#> <dbl> <dbl> <dbl> <lgl>
#> 1 1 1 NA NA
#> 2 1 2 0.5 NA
#> 3 1 3 1 NA
#> 4 2 1 NA NA
#> 5 2 2 0.5 NA
这是一个 dplyr-only 解决方案:
library(dplyr)
df %>%
group_by(fund_id, time_Q) %>%
summarise(new = list(stock_id)) %>%
mutate(past_1Q = lag(new, 1),
past_2Q = lag(new, 2)) %>%
rowwise() %>%
transmute(time_Q,
across(past_1Q:past_2Q, ~ length(intersect(new, .x)) / length(new)))
输出
fund_id time_Q past_1Q past_2Q
<dbl> <dbl> <dbl> <dbl>
1 1 1 0 0
2 1 2 0.5 0
3 1 3 1 0
4 2 1 0 0
5 2 2 0.5 0